ls: add missing intermediate directories to --ncdu output

This commit is contained in:
Michael Eischer 2024-07-07 13:28:56 +02:00
parent 894ec9d05d
commit 15419d603d
3 changed files with 29 additions and 16 deletions

View file

@ -71,7 +71,7 @@ func init() {
type lsPrinter interface { type lsPrinter interface {
Snapshot(sn *restic.Snapshot) Snapshot(sn *restic.Snapshot)
Node(path string, node *restic.Node) Node(path string, node *restic.Node, isPrefixDirectory bool)
LeaveDir(path string) LeaveDir(path string)
Close() Close()
} }
@ -102,7 +102,10 @@ func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) {
} }
// Print node in our custom JSON format, followed by a newline. // Print node in our custom JSON format, followed by a newline.
func (p *jsonLsPrinter) Node(path string, node *restic.Node) { func (p *jsonLsPrinter) Node(path string, node *restic.Node, isPrefixDirectory bool) {
if isPrefixDirectory {
return
}
err := lsNodeJSON(p.enc, path, node) err := lsNodeJSON(p.enc, path, node)
if err != nil { if err != nil {
Warnf("JSON encode failed: %v\n", err) Warnf("JSON encode failed: %v\n", err)
@ -217,7 +220,7 @@ func lsNcduNode(_ string, node *restic.Node) ([]byte, error) {
return json.Marshal(outNode) return json.Marshal(outNode)
} }
func (p *ncduLsPrinter) Node(path string, node *restic.Node) { func (p *ncduLsPrinter) Node(path string, node *restic.Node, _ bool) {
out, err := lsNcduNode(path, node) out, err := lsNcduNode(path, node)
if err != nil { if err != nil {
Warnf("JSON encode failed: %v\n", err) Warnf("JSON encode failed: %v\n", err)
@ -249,9 +252,11 @@ type textLsPrinter struct {
func (p *textLsPrinter) Snapshot(sn *restic.Snapshot) { func (p *textLsPrinter) Snapshot(sn *restic.Snapshot) {
Verbosef("%v filtered by %v:\n", sn, p.dirs) Verbosef("%v filtered by %v:\n", sn, p.dirs)
} }
func (p *textLsPrinter) Node(path string, node *restic.Node) { func (p *textLsPrinter) Node(path string, node *restic.Node, isPrefixDirectory bool) {
if !isPrefixDirectory {
Printf("%s\n", formatNode(path, node, p.ListLong, p.HumanReadable)) Printf("%s\n", formatNode(path, node, p.ListLong, p.HumanReadable))
} }
}
func (p *textLsPrinter) LeaveDir(_ string) {} func (p *textLsPrinter) LeaveDir(_ string) {}
func (p *textLsPrinter) Close() {} func (p *textLsPrinter) Close() {}
@ -369,8 +374,8 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
printedDir := false printedDir := false
if withinDir(nodepath) { if withinDir(nodepath) {
// if we're within a dir, print the node // if we're within a target path, print the node
printer.Node(nodepath, node) printer.Node(nodepath, node, false)
printedDir = true printedDir = true
// if recursive listing is requested, signal the walker that it // if recursive listing is requested, signal the walker that it
@ -383,12 +388,17 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
// if there's an upcoming match deeper in the tree (but we're not // if there's an upcoming match deeper in the tree (but we're not
// there yet), signal the walker to descend into any subdirs // there yet), signal the walker to descend into any subdirs
if approachingMatchingTree(nodepath) { if approachingMatchingTree(nodepath) {
// print node leading up to the target paths
if !printedDir {
printer.Node(nodepath, node, true)
}
return nil return nil
} }
// otherwise, signal the walker to not walk recursively into any // otherwise, signal the walker to not walk recursively into any
// subdirs // subdirs
if node.Type == "dir" { if node.Type == "dir" {
// immediately generate leaveDir if the directory is skipped
if printedDir { if printedDir {
printer.LeaveDir(nodepath) printer.LeaveDir(nodepath)
} }
@ -401,7 +411,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
ProcessNode: processNode, ProcessNode: processNode,
LeaveDir: func(path string) { LeaveDir: func(path string) {
// the root path `/` has no corresponding node and is thus also skipped by processNode // the root path `/` has no corresponding node and is thus also skipped by processNode
if withinDir(path) && path != "/" { if path != "/" {
printer.LeaveDir(path) printer.LeaveDir(path)
} }
}, },

View file

@ -35,13 +35,16 @@ func TestRunLsNcdu(t *testing.T) {
env, cleanup := withTestEnvironment(t) env, cleanup := withTestEnvironment(t)
defer cleanup() defer cleanup()
testRunInit(t, env.gopts) testSetupBackupData(t, env)
opts := BackupOptions{} opts := BackupOptions{}
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts) testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
ncdu := testRunLsWithOpts(t, env.gopts, LsOptions{Ncdu: true}, []string{"latest"}) for _, paths := range [][]string{
assertIsValidJSON(t, ncdu) {"latest"},
{"latest", "/testdata"},
ncdu = testRunLsWithOpts(t, env.gopts, LsOptions{Ncdu: true}, []string{"latest", "/testdata"}) {"latest", "/testdata/0", "/testdata/0/tests"},
} {
ncdu := testRunLsWithOpts(t, env.gopts, LsOptions{Ncdu: true}, paths)
assertIsValidJSON(t, ncdu) assertIsValidJSON(t, ncdu)
} }
}

View file

@ -140,12 +140,12 @@ func TestLsNcdu(t *testing.T) {
printer.Node("/directory", &restic.Node{ printer.Node("/directory", &restic.Node{
Type: "dir", Type: "dir",
Name: "directory", Name: "directory",
}) }, false)
printer.Node("/directory/data", &restic.Node{ printer.Node("/directory/data", &restic.Node{
Type: "file", Type: "file",
Name: "data", Name: "data",
Size: 42, Size: 42,
}) }, false)
printer.LeaveDir("/directory") printer.LeaveDir("/directory")
printer.Close() printer.Close()