diff --git a/cmd/ctr/snapshot.go b/cmd/ctr/snapshot.go index bc1ceb04d..d6fe419f8 100644 --- a/cmd/ctr/snapshot.go +++ b/cmd/ctr/snapshot.go @@ -26,6 +26,7 @@ var snapshotCommand = cli.Command{ usageSnapshotCommand, removeSnapshotCommand, prepareSnapshotCommand, + treeSnapshotCommand, }, } @@ -231,3 +232,72 @@ var prepareSnapshotCommand = cli.Command{ return nil }, } + +var treeSnapshotCommand = cli.Command{ + Name: "tree", + Usage: "Display tree view of snapshot branches", + Action: func(clicontext *cli.Context) error { + ctx, cancel := appContext(clicontext) + defer cancel() + + snapshotter, err := getSnapshotter(clicontext) + if err != nil { + return err + } + + tree := make(map[string]*snapshotTreeNode) + + if err := snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error { + // Get or create node and add node details + node := getOrCreateTreeNode(info.Name, tree) + if info.Parent != "" { + node.Parent = info.Parent + p := getOrCreateTreeNode(info.Parent, tree) + p.Children = append(p.Children, info.Name) + } + + return nil + }); err != nil { + return err + } + + printTree(tree) + + return nil + }, +} + +type snapshotTreeNode struct { + Name string + Parent string + Children []string +} + +func getOrCreateTreeNode(name string, tree map[string]*snapshotTreeNode) *snapshotTreeNode { + if node, ok := tree[name]; ok { + return node + } + node := &snapshotTreeNode{ + Name: name, + } + tree[name] = node + return node +} + +func printTree(tree map[string]*snapshotTreeNode) { + for _, node := range tree { + // Print for root(parent-less) nodes only + if node.Parent == "" { + printNode(node.Name, tree, 0) + } + } +} + +func printNode(name string, tree map[string]*snapshotTreeNode, level int) { + node := tree[name] + fmt.Printf("%s\\_ %s\n", strings.Repeat(" ", level), node.Name) + level++ + for _, child := range node.Children { + printNode(child, tree, level) + } +}