cmd/ctr: stablize output of snapshot tree

Preserves the order of the tree output between each execution. Slightly
refactored the behavior to be more "object oriented".

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2017-12-12 14:42:38 -08:00
parent 03bc5e974d
commit 9aeeefae55
No known key found for this signature in database
GPG Key ID: 67B3DED84EDC823F

View File

@ -287,18 +287,12 @@ var treeCommand = cli.Command{
defer cancel() defer cancel()
var ( var (
snapshotter = client.SnapshotService(context.GlobalString("snapshotter")) snapshotter = client.SnapshotService(context.GlobalString("snapshotter"))
tree = make(map[string]*snapshotTreeNode) tree = newSnapshotTree()
) )
if err := snapshotter.Walk(ctx, func(ctx gocontext.Context, info snapshots.Info) error { if err := snapshotter.Walk(ctx, func(ctx gocontext.Context, info snapshots.Info) error {
// Get or create node and add node details // Get or create node and add node details
node := getOrCreateTreeNode(info.Name, tree) tree.add(info)
if info.Parent != "" {
node.Parent = info.Parent
p := getOrCreateTreeNode(info.Parent, tree)
p.Children = append(p.Children, info.Name)
}
return nil return nil
}); err != nil { }); err != nil {
return err return err
@ -429,37 +423,68 @@ var unpackCommand = cli.Command{
}, },
} }
type snapshotTree struct {
nodes []*snapshotTreeNode
index map[string]*snapshotTreeNode
}
func newSnapshotTree() *snapshotTree {
return &snapshotTree{
index: make(map[string]*snapshotTreeNode),
}
}
type snapshotTreeNode struct { type snapshotTreeNode struct {
Name string info snapshots.Info
Parent string children []string
Children []string
} }
func getOrCreateTreeNode(name string, tree map[string]*snapshotTreeNode) *snapshotTreeNode { func (st *snapshotTree) add(info snapshots.Info) *snapshotTreeNode {
if node, ok := tree[name]; ok { entry, ok := st.index[info.Name]
return node if !ok {
entry = &snapshotTreeNode{info: info}
st.nodes = append(st.nodes, entry)
st.index[info.Name] = entry
} else {
entry.info = info // update info if we created placeholder
} }
node := &snapshotTreeNode{
Name: name, if info.Parent != "" {
pn := st.get(info.Parent)
if pn == nil {
// create a placeholder
pn = st.add(snapshots.Info{Name: info.Parent})
}
pn.children = append(pn.children, info.Name)
} }
tree[name] = node return entry
return node
} }
func printTree(tree map[string]*snapshotTreeNode) { func (st *snapshotTree) get(name string) *snapshotTreeNode {
for _, node := range tree { return st.index[name]
}
func printTree(st *snapshotTree) {
for _, node := range st.nodes {
// Print for root(parent-less) nodes only // Print for root(parent-less) nodes only
if node.Parent == "" { if node.info.Parent == "" {
printNode(node.Name, tree, 0) printNode(node.info.Name, st, 0)
} }
} }
} }
func printNode(name string, tree map[string]*snapshotTreeNode, level int) { func printNode(name string, tree *snapshotTree, level int) {
node := tree[name] node := tree.index[name]
fmt.Printf("%s\\_ %s\n", strings.Repeat(" ", level), node.Name) prefix := strings.Repeat(" ", level)
if level > 0 {
prefix += "\\_"
}
fmt.Printf(prefix+" %s\n", node.info.Name)
level++ level++
for _, child := range node.Children { for _, child := range node.children {
printNode(child, tree, level) printNode(child, tree, level)
} }
} }