From 9f66065237be7a80eb925e43ba9c613f7b3550ea Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 12 Jul 2024 21:22:37 +0200 Subject: [PATCH 1/4] ls: fix handling of toplevel directories in ncdu output --- cmd/restic/cmd_ls.go | 4 ++-- cmd/restic/cmd_ls_integration_test.go | 11 ++++++----- cmd/restic/cmd_ls_test.go | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index d9a3b0fb8..13bc50406 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -178,7 +178,7 @@ func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) { Warnf("JSON encode failed: %v\n", err) } p.depth++ - fmt.Fprintf(p.out, "[%d, %d, %s", NcduMajorVer, NcduMinorVer, string(snapshotBytes)) + fmt.Fprintf(p.out, "[%d, %d, %s, [{\"name\":\"\"}", NcduMajorVer, NcduMinorVer, string(snapshotBytes)) } func lsNcduNode(_ string, node *restic.Node) ([]byte, error) { @@ -246,7 +246,7 @@ func (p *ncduLsPrinter) LeaveDir(_ string) { } func (p *ncduLsPrinter) Close() { - fmt.Fprint(p.out, "\n]\n") + fmt.Fprint(p.out, "\n]\n]\n") } type textLsPrinter struct { diff --git a/cmd/restic/cmd_ls_integration_test.go b/cmd/restic/cmd_ls_integration_test.go index 2b742d1b2..f5655bdff 100644 --- a/cmd/restic/cmd_ls_integration_test.go +++ b/cmd/restic/cmd_ls_integration_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - "path/filepath" "strings" "testing" @@ -26,9 +25,10 @@ func testRunLs(t testing.TB, gopts GlobalOptions, snapshotID string) []string { func assertIsValidJSON(t *testing.T, data []byte) { // Sanity check: output must be valid JSON. - var v interface{} + var v []any err := json.Unmarshal(data, &v) rtest.OK(t, err) + rtest.Assert(t, len(v) == 4, "invalid ncdu output, expected 4 array elements, got %v", len(v)) } func TestRunLsNcdu(t *testing.T) { @@ -37,12 +37,13 @@ func TestRunLsNcdu(t *testing.T) { testSetupBackupData(t, env) opts := BackupOptions{} - testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts) + // backup such that there are multiple toplevel elements + testRunBackup(t, env.testdata+"/0", []string{"."}, opts, env.gopts) for _, paths := range [][]string{ {"latest"}, - {"latest", "/testdata"}, - {"latest", "/testdata/0", "/testdata/0/tests"}, + {"latest", "/0"}, + {"latest", "/0", "/0/9"}, } { ncdu := testRunLsWithOpts(t, env.gopts, LsOptions{Ncdu: true}, paths) assertIsValidJSON(t, ncdu) diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index 194975053..8523f702f 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -149,11 +149,12 @@ func TestLsNcdu(t *testing.T) { printer.LeaveDir("/directory") printer.Close() - rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, + rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, [{"name":""}, [ {"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800}, {"name":"data","asize":42,"dsize":512,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800} ] ] +] `, buf.String()) } From ff9238ebf16866d6a5c8bb02f605ed7daddeea9a Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 12 Jul 2024 23:46:50 +0200 Subject: [PATCH 2/4] ls: use / as top-level dir name in ncdu output --- cmd/restic/cmd_ls.go | 2 +- cmd/restic/cmd_ls_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index 13bc50406..dede03a01 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -178,7 +178,7 @@ func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) { Warnf("JSON encode failed: %v\n", err) } p.depth++ - fmt.Fprintf(p.out, "[%d, %d, %s, [{\"name\":\"\"}", NcduMajorVer, NcduMinorVer, string(snapshotBytes)) + fmt.Fprintf(p.out, "[%d, %d, %s, [{\"name\":\"/\"}", NcduMajorVer, NcduMinorVer, string(snapshotBytes)) } func lsNcduNode(_ string, node *restic.Node) ([]byte, error) { diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index 8523f702f..19b30479e 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -149,7 +149,7 @@ func TestLsNcdu(t *testing.T) { printer.LeaveDir("/directory") printer.Close() - rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, [{"name":""}, + rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, [{"name":"/"}, [ {"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800}, {"name":"data","asize":42,"dsize":512,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800} From 5671dfb481e272b48c6f7a9e5fbd76e4c7c3f1e9 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 13 Jul 2024 10:21:02 +0200 Subject: [PATCH 3/4] ls: fix ncdu output for file with timestamp before 1970 --- cmd/restic/cmd_ls.go | 4 ++++ cmd/restic/cmd_ls_test.go | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index dede03a01..76e192b6c 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -222,6 +222,10 @@ func lsNcduNode(_ string, node *restic.Node) ([]byte, error) { if node.Mode&os.ModeSticky != 0 { outNode.Mode |= 0o1000 } + if outNode.Mtime < 0 { + // ncdu does not allow negative times + outNode.Mtime = 0 + } return json.Marshal(outNode) } diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index 19b30479e..21f3d6212 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -109,11 +109,11 @@ func TestLsNodeJSON(t *testing.T) { func TestLsNcduNode(t *testing.T) { for i, expect := range []string{ - `{"name":"baz","asize":12345,"dsize":12800,"dev":0,"ino":0,"nlink":1,"notreg":false,"uid":10000000,"gid":20000000,"mode":0,"mtime":-62135596800}`, - `{"name":"empty","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":3840,"notreg":false,"uid":1001,"gid":1001,"mode":0,"mtime":-62135596800}`, - `{"name":"link","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":true,"uid":0,"gid":0,"mode":511,"mtime":-62135596800}`, + `{"name":"baz","asize":12345,"dsize":12800,"dev":0,"ino":0,"nlink":1,"notreg":false,"uid":10000000,"gid":20000000,"mode":0,"mtime":0}`, + `{"name":"empty","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":3840,"notreg":false,"uid":1001,"gid":1001,"mode":0,"mtime":0}`, + `{"name":"link","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":true,"uid":0,"gid":0,"mode":511,"mtime":0}`, `{"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":493,"mtime":1577934245}`, - `{"name":"sticky","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":4077,"mtime":-62135596800}`, + `{"name":"sticky","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":4077,"mtime":0}`, } { c := lsTestNodes[i] out, err := lsNcduNode(c.path, &c.Node) @@ -132,27 +132,30 @@ func TestLsNcdu(t *testing.T) { printer := &ncduLsPrinter{ out: &buf, } + modTime := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC) printer.Snapshot(&restic.Snapshot{ Hostname: "host", Paths: []string{"/example"}, }) printer.Node("/directory", &restic.Node{ - Type: "dir", - Name: "directory", + Type: "dir", + Name: "directory", + ModTime: modTime, }, false) printer.Node("/directory/data", &restic.Node{ - Type: "file", - Name: "data", - Size: 42, + Type: "file", + Name: "data", + Size: 42, + ModTime: modTime, }, false) printer.LeaveDir("/directory") printer.Close() rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, [{"name":"/"}, [ - {"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800}, - {"name":"data","asize":42,"dsize":512,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":-62135596800} + {"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":1577934245}, + {"name":"data","asize":42,"dsize":512,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":1577934245} ] ] ] From bdf24dc8f91157fceff483d31e510d555491f77f Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 13 Jul 2024 10:22:01 +0200 Subject: [PATCH 4/4] ls: extend test sample with a second toplevel file --- cmd/restic/cmd_ls_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index 21f3d6212..a1fcd479b 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -150,13 +150,20 @@ func TestLsNcdu(t *testing.T) { ModTime: modTime, }, false) printer.LeaveDir("/directory") + printer.Node("/file", &restic.Node{ + Type: "file", + Name: "file", + Size: 12345, + ModTime: modTime, + }, false) printer.Close() rtest.Equals(t, `[1, 2, {"time":"0001-01-01T00:00:00Z","tree":null,"paths":["/example"],"hostname":"host"}, [{"name":"/"}, [ {"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":1577934245}, {"name":"data","asize":42,"dsize":512,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":1577934245} - ] + ], + {"name":"file","asize":12345,"dsize":12800,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":0,"mtime":1577934245} ] ] `, buf.String())