mirror of
https://github.com/kopia/kopia.git
synced 2026-03-12 03:06:31 -04:00
Can be disabled with `--no-error-summary`. Quick demo: https://asciinema.org/a/2rma0sx2mD6HoIPy6VL0QEFeP Also refactored fs.Directory to provide Summary optionally.
124 lines
3.0 KiB
Go
124 lines
3.0 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/kopia/kopia/fs"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/repo/object"
|
|
"github.com/kopia/kopia/snapshot/snapshotfs"
|
|
)
|
|
|
|
var (
|
|
lsCommand = app.Command("list", "List a directory stored in repository object.").Alias("ls")
|
|
|
|
lsCommandLong = lsCommand.Flag("long", "Long output").Short('l').Bool()
|
|
lsCommandRecursive = lsCommand.Flag("recursive", "Recursive output").Short('r').Bool()
|
|
lsCommandShowOID = lsCommand.Flag("show-object-id", "Show object IDs").Short('o').Bool()
|
|
lsCommandErrorSummary = lsCommand.Flag("error-summary", "Emit error summary").Default("true").Bool()
|
|
lsCommandPath = lsCommand.Arg("object-path", "Path").Required().String()
|
|
)
|
|
|
|
func runLSCommand(ctx context.Context, rep repo.Repository) error {
|
|
oid, err := parseObjectID(ctx, rep, *lsCommandPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var prefix string
|
|
if !*lsCommandLong {
|
|
prefix = *lsCommandPath
|
|
if !strings.HasSuffix(prefix, "/") {
|
|
prefix += "/"
|
|
}
|
|
}
|
|
|
|
return listDirectory(ctx, rep, prefix, oid, "")
|
|
}
|
|
|
|
func init() {
|
|
lsCommand.Action(repositoryAction(runLSCommand))
|
|
}
|
|
|
|
// nolint:gocyclo
|
|
func listDirectory(ctx context.Context, rep repo.Repository, prefix string, oid object.ID, indent string) error {
|
|
d := snapshotfs.DirectoryEntry(rep, oid, nil)
|
|
|
|
entries, err := d.Readdir(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, e := range entries {
|
|
objectID := e.(object.HasObjectID).ObjectID()
|
|
oid := objectID.String()
|
|
col := defaultColor
|
|
|
|
var (
|
|
errorSummary string
|
|
info string
|
|
)
|
|
|
|
if dws, ok := e.(fs.DirectoryWithSummary); ok && *lsCommandErrorSummary {
|
|
if ds, _ := dws.Summary(ctx); ds != nil && ds.NumFailed > 0 {
|
|
errorSummary = fmt.Sprintf(" (%v errors)", ds.NumFailed)
|
|
col = errorColor
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case *lsCommandLong:
|
|
info = fmt.Sprintf(
|
|
"%v %12d %v %-34v %v%v",
|
|
e.Mode(),
|
|
e.Size(),
|
|
formatTimestamp(e.ModTime().Local()),
|
|
oid,
|
|
nameToDisplay(prefix, e),
|
|
errorSummary,
|
|
)
|
|
case *lsCommandShowOID:
|
|
info = fmt.Sprintf("%-34v %v%v", oid, nameToDisplay(prefix, e), errorSummary)
|
|
|
|
default:
|
|
info = fmt.Sprintf("%v%v", nameToDisplay(prefix, e), errorSummary)
|
|
}
|
|
|
|
col.Println(info) //nolint:errcheck
|
|
|
|
if *lsCommandRecursive && e.Mode().IsDir() {
|
|
if listerr := listDirectory(ctx, rep, prefix+e.Name()+"/", objectID, indent+" "); listerr != nil {
|
|
return listerr
|
|
}
|
|
}
|
|
}
|
|
|
|
if dws, ok := d.(fs.DirectoryWithSummary); ok && *lsCommandErrorSummary {
|
|
if ds, _ := dws.Summary(ctx); ds != nil && ds.NumFailed > 0 {
|
|
errorColor.Fprintf(os.Stderr, "\nNOTE: Encountered %v errors while snapshotting this directory:\n\n", ds.NumFailed) //nolint:errcheck
|
|
|
|
for _, e := range ds.FailedEntries {
|
|
errorColor.Fprintf(os.Stderr, "- Error in \"%v\": %v\n", e.EntryPath, e.Error) //nolint:errcheck
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func nameToDisplay(prefix string, e fs.Entry) string {
|
|
suffix := ""
|
|
if e.IsDir() {
|
|
suffix = "/"
|
|
}
|
|
|
|
if *lsCommandLong || *lsCommandRecursive {
|
|
return prefix + e.Name() + suffix
|
|
}
|
|
|
|
return e.Name()
|
|
}
|