mirror of https://github.com/restic/restic.git
ls: unify printer implementations
This commit is contained in:
parent
1b008c92d3
commit
a2fe337610
|
@ -69,6 +69,18 @@ func init() {
|
||||||
flags.BoolVar(&lsOptions.Ncdu, "ncdu", false, "output NCDU save format (pipe into 'ncdu -f -')")
|
flags.BoolVar(&lsOptions.Ncdu, "ncdu", false, "output NCDU save format (pipe into 'ncdu -f -')")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type lsPrinter interface {
|
||||||
|
Snapshot(sn *restic.Snapshot)
|
||||||
|
Node(path string, node *restic.Node)
|
||||||
|
LeaveDir(path string)
|
||||||
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonLsPrinter struct {
|
||||||
|
enc *json.Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) {
|
||||||
type lsSnapshot struct {
|
type lsSnapshot struct {
|
||||||
*restic.Snapshot
|
*restic.Snapshot
|
||||||
ID *restic.ID `json:"id"`
|
ID *restic.ID `json:"id"`
|
||||||
|
@ -76,7 +88,25 @@ type lsSnapshot struct {
|
||||||
StructType string `json:"struct_type"` // "snapshot"
|
StructType string `json:"struct_type"` // "snapshot"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := p.enc.Encode(lsSnapshot{
|
||||||
|
Snapshot: sn,
|
||||||
|
ID: sn.ID(),
|
||||||
|
ShortID: sn.ID().Str(),
|
||||||
|
StructType: "snapshot",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
Warnf("JSON encode failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
|
err := lsNodeJSON(p.enc, path, node)
|
||||||
|
if err != nil {
|
||||||
|
Warnf("JSON encode failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
|
func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
|
||||||
n := &struct {
|
n := &struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -118,7 +148,10 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
|
||||||
return enc.Encode(n)
|
return enc.Encode(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ncduPrinter struct {
|
func (p *jsonLsPrinter) LeaveDir(path string) {}
|
||||||
|
func (p *jsonLsPrinter) Close() {}
|
||||||
|
|
||||||
|
type ncduLsPrinter struct {
|
||||||
out io.Writer
|
out io.Writer
|
||||||
depth int
|
depth int
|
||||||
}
|
}
|
||||||
|
@ -126,7 +159,7 @@ type ncduPrinter struct {
|
||||||
// lsSnapshotNcdu prints a restic snapshot in Ncdu save format.
|
// lsSnapshotNcdu prints a restic snapshot in Ncdu save format.
|
||||||
// It opens the JSON list. Nodes are added with lsNodeNcdu and the list is closed by lsCloseNcdu.
|
// It opens the JSON list. Nodes are added with lsNodeNcdu and the list is closed by lsCloseNcdu.
|
||||||
// Format documentation: https://dev.yorhel.nl/ncdu/jsonfmt
|
// Format documentation: https://dev.yorhel.nl/ncdu/jsonfmt
|
||||||
func (p *ncduPrinter) ProcessSnapshot(sn *restic.Snapshot) {
|
func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) {
|
||||||
const NcduMajorVer = 1
|
const NcduMajorVer = 1
|
||||||
const NcduMinorVer = 2
|
const NcduMinorVer = 2
|
||||||
|
|
||||||
|
@ -138,7 +171,7 @@ func (p *ncduPrinter) ProcessSnapshot(sn *restic.Snapshot) {
|
||||||
fmt.Fprintf(p.out, "[%d, %d, %s", NcduMajorVer, NcduMinorVer, string(snapshotBytes))
|
fmt.Fprintf(p.out, "[%d, %d, %s", NcduMajorVer, NcduMinorVer, string(snapshotBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ncduPrinter) ProcessNode(path string, node *restic.Node) {
|
func (p *ncduLsPrinter) Node(path string, node *restic.Node) {
|
||||||
type NcduNode struct {
|
type NcduNode struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Asize uint64 `json:"asize"`
|
Asize uint64 `json:"asize"`
|
||||||
|
@ -180,15 +213,31 @@ func (p *ncduPrinter) ProcessNode(path string, node *restic.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ncduPrinter) LeaveDir(path string) {
|
func (p *ncduLsPrinter) LeaveDir(path string) {
|
||||||
p.depth--
|
p.depth--
|
||||||
fmt.Fprintf(p.out, "\n%s]", strings.Repeat(" ", p.depth))
|
fmt.Fprintf(p.out, "\n%s]", strings.Repeat(" ", p.depth))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ncduPrinter) Close() {
|
func (p *ncduLsPrinter) Close() {
|
||||||
fmt.Fprint(p.out, "\n]\n")
|
fmt.Fprint(p.out, "\n]\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type textLsPrinter struct {
|
||||||
|
dirs []string
|
||||||
|
ListLong bool
|
||||||
|
HumanReadable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textLsPrinter) Snapshot(sn *restic.Snapshot) {
|
||||||
|
Verbosef("%v filtered by %v:\n", sn, p.dirs)
|
||||||
|
}
|
||||||
|
func (p *textLsPrinter) Node(path string, node *restic.Node) {
|
||||||
|
Printf("%s\n", formatNode(path, node, p.ListLong, p.HumanReadable))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textLsPrinter) LeaveDir(path string) {}
|
||||||
|
func (p *textLsPrinter) Close() {}
|
||||||
|
|
||||||
func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []string) error {
|
func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return errors.Fatal("no snapshot ID specified, specify snapshot ID or use special ID 'latest'")
|
return errors.Fatal("no snapshot ID specified, specify snapshot ID or use special ID 'latest'")
|
||||||
|
@ -254,48 +303,21 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var printer lsPrinter
|
||||||
printSnapshot func(sn *restic.Snapshot)
|
|
||||||
printNode func(path string, node *restic.Node)
|
|
||||||
printLeaveNode func(path string)
|
|
||||||
printClose func()
|
|
||||||
)
|
|
||||||
|
|
||||||
if gopts.JSON {
|
if gopts.JSON {
|
||||||
enc := json.NewEncoder(globalOptions.stdout)
|
printer = &jsonLsPrinter{
|
||||||
|
enc: json.NewEncoder(globalOptions.stdout),
|
||||||
printSnapshot = func(sn *restic.Snapshot) {
|
|
||||||
err := enc.Encode(lsSnapshot{
|
|
||||||
Snapshot: sn,
|
|
||||||
ID: sn.ID(),
|
|
||||||
ShortID: sn.ID().Str(),
|
|
||||||
StructType: "snapshot",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
Warnf("JSON encode failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printNode = func(path string, node *restic.Node) {
|
|
||||||
err := lsNodeJSON(enc, path, node)
|
|
||||||
if err != nil {
|
|
||||||
Warnf("JSON encode failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if opts.Ncdu {
|
} else if opts.Ncdu {
|
||||||
ncdu := &ncduPrinter{
|
printer = &ncduLsPrinter{
|
||||||
out: globalOptions.stdout,
|
out: globalOptions.stdout,
|
||||||
}
|
}
|
||||||
printSnapshot = ncdu.ProcessSnapshot
|
|
||||||
printNode = ncdu.ProcessNode
|
|
||||||
printLeaveNode = ncdu.LeaveDir
|
|
||||||
printClose = ncdu.Close
|
|
||||||
} else {
|
} else {
|
||||||
printSnapshot = func(sn *restic.Snapshot) {
|
printer = &textLsPrinter{
|
||||||
Verbosef("%v filtered by %v:\n", sn, dirs)
|
dirs: dirs,
|
||||||
}
|
ListLong: opts.ListLong,
|
||||||
printNode = func(path string, node *restic.Node) {
|
HumanReadable: opts.HumanReadable,
|
||||||
Printf("%s\n", formatNode(path, node, opts.ListLong, opts.HumanReadable))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +335,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
printSnapshot(sn)
|
printer.Snapshot(sn)
|
||||||
|
|
||||||
processNode := func(_ restic.ID, nodepath string, node *restic.Node, err error) error {
|
processNode := func(_ restic.ID, nodepath string, node *restic.Node, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -325,7 +347,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||||
|
|
||||||
if withinDir(nodepath) {
|
if withinDir(nodepath) {
|
||||||
// if we're within a dir, print the node
|
// if we're within a dir, print the node
|
||||||
printNode(nodepath, node)
|
printer.Node(nodepath, node)
|
||||||
|
|
||||||
// if recursive listing is requested, signal the walker that it
|
// if recursive listing is requested, signal the walker that it
|
||||||
// should continue walking recursively
|
// should continue walking recursively
|
||||||
|
@ -351,8 +373,9 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||||
err = walker.Walk(ctx, repo, *sn.Tree, walker.WalkVisitor{
|
err = walker.Walk(ctx, repo, *sn.Tree, walker.WalkVisitor{
|
||||||
ProcessNode: processNode,
|
ProcessNode: processNode,
|
||||||
LeaveDir: func(path string) {
|
LeaveDir: func(path string) {
|
||||||
if printLeaveNode != nil && withinDir(path) && path != "/" {
|
// the root path `/` has no corresponding node and is thus also skipped by processNode
|
||||||
printLeaveNode(path)
|
if withinDir(path) && path != "/" {
|
||||||
|
printer.LeaveDir(path)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -361,9 +384,6 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if printClose != nil {
|
printer.Close()
|
||||||
printClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue