From 7925217e256e523e50932955e2f210b4d8f2a1a8 Mon Sep 17 00:00:00 2001 From: kitone Date: Tue, 14 Aug 2018 10:50:31 +0200 Subject: [PATCH 1/4] ls: Add JSON output support for restic ls cmd --- cmd/restic/cmd_ls.go | 86 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index e45ffb9d0..a6065309f 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -2,7 +2,10 @@ package main import ( "context" + "encoding/json" + "os" "strings" + "time" "github.com/spf13/cobra" @@ -59,6 +62,29 @@ func init() { flags.BoolVar(&lsOptions.Recursive, "recursive", false, "include files in subfolders of the listed directories") } +type lsSnapshot struct { + *restic.Snapshot + + ID *restic.ID `json:"id"` + ShortID string `json:"short_id"` + Nodes []lsNode `json:"nodes"` + StructType string `json:"struct_type"` // "snapshot" +} + +type lsNode struct { + Name string `json:"name"` + Type string `json:"type"` + Path string `json:"path"` + UID uint32 `json:"uid"` + GID uint32 `json:"gid"` + Size uint64 `json:"size,omitempty"` + Mode os.FileMode `json:"mode,omitempty"` + ModTime time.Time `json:"mtime,omitempty"` + AccessTime time.Time `json:"atime,omitempty"` + ChangeTime time.Time `json:"ctime,omitempty"` + StructType string `json:"struct_type"` // "node" +} + func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { if len(args) == 0 && opts.Host == "" && len(opts.Tags) == 0 && len(opts.Paths) == 0 { return errors.Fatal("Invalid arguments, either give one or more snapshot IDs or set filters.") @@ -120,8 +146,62 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { ctx, cancel := context.WithCancel(gopts.ctx) defer cancel() + + var ( + printSnapshot func(sn *restic.Snapshot) + printNode func(path string, node *restic.Node) + printFinish func() error + ) + + if gopts.JSON { + var lssnapshots []lsSnapshot + + printSnapshot = func(sn *restic.Snapshot) { + lss := lsSnapshot{ + Snapshot: sn, + ID: sn.ID(), + ShortID: sn.ID().Str(), + StructType: "Snapshot", + } + lssnapshots = append(lssnapshots, lss) + } + + printNode = func(path string, node *restic.Node) { + lsn := lsNode{ + Name: node.Name, + Type: node.Type, + Path: path, + UID: node.UID, + GID: node.GID, + Size: node.Size, + Mode: node.Mode, + ModTime: node.ModTime, + AccessTime: node.AccessTime, + ChangeTime: node.ChangeTime, + StructType: "Node", + } + s := &lssnapshots[len(lssnapshots)-1] + s.Nodes = append(s.Nodes, lsn) + } + + printFinish = func() error { + return json.NewEncoder(gopts.stdout).Encode(lssnapshots) + } + } else { + // default output methods + printSnapshot = func(sn *restic.Snapshot) { + Verbosef("snapshot %s of %v filtered by %v at %s):\n", sn.ID().Str(), sn.Paths, dirs, sn.Time) + } + printNode = func(path string, node *restic.Node) { + Printf("%s\n", formatNode(path, node, lsOptions.ListLong)) + } + printFinish = func() error { + return nil + } + } + for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args[:1]) { - Verbosef("snapshot %s of %v filtered by %v at %s):\n", sn.ID().Str(), sn.Paths, dirs, sn.Time) + printSnapshot(sn) err := walker.Walk(ctx, repo, *sn.Tree, nil, func(nodepath string, node *restic.Node, err error) (bool, error) { if err != nil { @@ -133,7 +213,7 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { if withinDir(nodepath) { // if we're within a dir, print the node - Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong)) + printNode(nodepath, node) // if recursive listing is requested, signal the walker that it // should continue walking recursively @@ -160,5 +240,5 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { return err } } - return nil + return printFinish() } From bd6e7c934c2eced6fc1488f7bffaf57195481735 Mon Sep 17 00:00:00 2001 From: kitone Date: Tue, 14 Aug 2018 10:57:45 +0200 Subject: [PATCH 2/4] add changelog entry --- changelog/unreleased/pull-1953 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/unreleased/pull-1953 diff --git a/changelog/unreleased/pull-1953 b/changelog/unreleased/pull-1953 new file mode 100644 index 000000000..b0d453a21 --- /dev/null +++ b/changelog/unreleased/pull-1953 @@ -0,0 +1,5 @@ +Enhancement: ls: Add JSON output support for restic ls cmd + +This PR enables users to get the output of `restic ls` in JSON format. + +https://github.com/restic/restic/pull/1953 From 48cc2f2188e299910ce9c302f0f8f95f4e37202d Mon Sep 17 00:00:00 2001 From: kitone Date: Tue, 14 Aug 2018 11:15:17 +0200 Subject: [PATCH 3/4] fix: switch struct_type value to lower case --- cmd/restic/cmd_ls.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index a6065309f..d6297be04 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -161,7 +161,7 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { Snapshot: sn, ID: sn.ID(), ShortID: sn.ID().Str(), - StructType: "Snapshot", + StructType: "snapshot", } lssnapshots = append(lssnapshots, lss) } @@ -178,7 +178,7 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error { ModTime: node.ModTime, AccessTime: node.AccessTime, ChangeTime: node.ChangeTime, - StructType: "Node", + StructType: "node", } s := &lssnapshots[len(lssnapshots)-1] s.Nodes = append(s.Nodes, lsn) From 46f71f4c22c58ab0bed7c35dd2b845530987bb05 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 18 Aug 2018 15:14:52 +0200 Subject: [PATCH 4/4] Improve changelog entry --- changelog/unreleased/pull-1953 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog/unreleased/pull-1953 b/changelog/unreleased/pull-1953 index b0d453a21..e22c4b22d 100644 --- a/changelog/unreleased/pull-1953 +++ b/changelog/unreleased/pull-1953 @@ -1,5 +1,7 @@ Enhancement: ls: Add JSON output support for restic ls cmd -This PR enables users to get the output of `restic ls` in JSON format. +We've implemented listing files in the repository with JSON as output, just +pass `--json` as an option to `restic ls`. This makes the output of the command +machine readable. https://github.com/restic/restic/pull/1953