Print indexing statistics

pull/6/head
Mickaël Menu 3 years ago
parent 58cfec5c80
commit 9876bcec00
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -1,6 +1,7 @@
package cmd
import (
"fmt"
"os"
"time"
@ -15,6 +16,7 @@ import (
type Index struct {
Directory string `arg optional type:"path" default:"." help:"Directory containing the notes to index"`
Force bool `help:"Force indexing all the notes" short:"f"`
Quiet bool `help:"Do not print statistics nor progress" short:"q"`
}
func (cmd *Index) Run(container *Container) error {
@ -33,29 +35,42 @@ func (cmd *Index) Run(container *Container) error {
return err
}
bar := progressbar.NewOptions(-1,
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionThrottle(100*time.Millisecond),
progressbar.OptionSpinnerType(14),
)
var bar *progressbar.ProgressBar
if !cmd.Quiet {
bar = progressbar.NewOptions(-1,
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionThrottle(100*time.Millisecond),
progressbar.OptionSpinnerType(14),
)
}
var stats note.IndexingStats
err = db.WithTransaction(func(tx sqlite.Transaction) error {
notes := sqlite.NewNoteDAO(tx, container.Logger)
return note.Index(
stats, err = note.Index(
*dir,
cmd.Force,
container.Parser(),
notes,
container.Logger,
func(change paths.DiffChange) {
bar.Add(1)
bar.Describe(change.String())
if bar != nil {
bar.Add(1)
bar.Describe(change.String())
}
},
)
return err
})
bar.Clear()
if bar != nil {
bar.Clear()
}
if err == nil && !cmd.Quiet {
fmt.Println(stats)
}
return err
}

@ -12,6 +12,7 @@ import (
"github.com/mickael-menu/zk/util"
"github.com/mickael-menu/zk/util/errors"
"github.com/mickael-menu/zk/util/paths"
strutil "github.com/mickael-menu/zk/util/strings"
"gopkg.in/djherbis/times.v1"
)
@ -28,6 +29,28 @@ type Metadata struct {
Checksum string
}
// IndexingStats holds metrics about an indexing process.
type IndexingStats struct {
SourceCount int
AddedCount int
ModifiedCount int
RemovedCount int
Duration time.Duration
}
// String implements Stringer
func (s IndexingStats) String() string {
return fmt.Sprintf(`Indexed %d %v in %v
+ %d added
~ %d modified
- %d removed`,
s.SourceCount,
strutil.Pluralize("note", s.SourceCount),
s.Duration.Round(500*time.Millisecond),
s.AddedCount, s.ModifiedCount, s.RemovedCount,
)
}
// Indexer persists the notes index.
type Indexer interface {
// Indexed returns the list of indexed note file metadata.
@ -41,20 +64,24 @@ type Indexer interface {
}
// Index indexes the content of the notes in the given directory.
func Index(dir zk.Dir, force bool, parser Parser, indexer Indexer, logger util.Logger, callback func(change paths.DiffChange)) error {
func Index(dir zk.Dir, force bool, parser Parser, indexer Indexer, logger util.Logger, callback func(change paths.DiffChange)) (IndexingStats, error) {
wrap := errors.Wrapper("indexing failed")
stats := IndexingStats{}
startTime := time.Now()
source := paths.Walk(dir.Path, dir.Config.Extension, logger)
target, err := indexer.Indexed()
if err != nil {
return wrap(err)
return stats, wrap(err)
}
err = paths.Diff(source, target, force, func(change paths.DiffChange) error {
count, err := paths.Diff(source, target, force, func(change paths.DiffChange) error {
callback(change)
switch change.Kind {
case paths.DiffAdded:
stats.AddedCount += 1
metadata, err := metadata(change.Path, dir.Path, parser)
if err == nil {
err = indexer.Add(metadata)
@ -62,6 +89,7 @@ func Index(dir zk.Dir, force bool, parser Parser, indexer Indexer, logger util.L
logger.Err(err)
case paths.DiffModified:
stats.ModifiedCount += 1
metadata, err := metadata(change.Path, dir.Path, parser)
if err == nil {
err = indexer.Update(metadata)
@ -69,13 +97,17 @@ func Index(dir zk.Dir, force bool, parser Parser, indexer Indexer, logger util.L
logger.Err(err)
case paths.DiffRemoved:
stats.RemovedCount += 1
err := indexer.Remove(change.Path)
logger.Err(err)
}
return nil
})
return wrap(err)
stats.SourceCount = count
stats.Duration = time.Since(startTime)
return stats, wrap(err)
}
// metadata retrieves note metadata for the given file.

@ -39,18 +39,22 @@ func (k DiffKind) String() string {
// Diff compares two sources of Metadata and report the file changes, using the
// file modification date.
//
// Returns the number of files in the source.
//
// Warning: The Metadata have to be sorted by their Path for the diffing to
// work properly.
func Diff(source, target <-chan Metadata, forceModified bool, callback func(DiffChange) error) error {
func Diff(source, target <-chan Metadata, forceModified bool, callback func(DiffChange) error) (int, error) {
var err error
var sourceFile, targetFile Metadata
var sourceOpened, targetOpened bool = true, true
sourceCount := 0
pair := diffPair{}
for err == nil && (sourceOpened || targetOpened) {
if pair.source == nil {
sourceFile, sourceOpened = <-source
if sourceOpened {
sourceCount += 1
pair.source = &sourceFile
}
}
@ -66,7 +70,7 @@ func Diff(source, target <-chan Metadata, forceModified bool, callback func(Diff
}
}
return err
return sourceCount, err
}
// diffPair holds the current two files to be diffed.

@ -266,7 +266,7 @@ func TestDiffCancellation(t *testing.T) {
target := []Metadata{}
received := make([]DiffChange, 0)
err := Diff(toChannel(source), toChannel(target), false, func(change DiffChange) error {
_, err := Diff(toChannel(source), toChannel(target), false, func(change DiffChange) error {
received = append(received, change)
if len(received) == 1 {
@ -286,12 +286,14 @@ func TestDiffCancellation(t *testing.T) {
}
func test(t *testing.T, source, target []Metadata, forceModified bool, expected []DiffChange) {
expectedCount := len(source)
received := make([]DiffChange, 0)
err := Diff(toChannel(source), toChannel(target), forceModified, func(change DiffChange) error {
actualCount, err := Diff(toChannel(source), toChannel(target), forceModified, func(change DiffChange) error {
received = append(received, change)
return nil
})
assert.Nil(t, err)
assert.Equal(t, actualCount, expectedCount)
assert.Equal(t, received, expected)
}

Loading…
Cancel
Save