diff --git a/filetree/node.go b/filetree/node.go index 979ecf1..8ba41f0 100644 --- a/filetree/node.go +++ b/filetree/node.go @@ -1,14 +1,13 @@ package filetree import ( + "archive/tar" "sort" "strings" - "github.com/fatih/color" "fmt" "github.com/phayes/permbits" "github.com/dustin/go-humanize" - "github.com/wagoodman/docker-image-explorer/_vendor-20180604210951/github.com/Microsoft/go-winio/archive/tar" ) const ( diff --git a/filetree/tree.go b/filetree/tree.go index 01e405f..5fdbcbe 100644 --- a/filetree/tree.go +++ b/filetree/tree.go @@ -217,9 +217,9 @@ func (tree *FileTree) MarkRemoved(path string) error { return node.AssignDiffType(Removed) } -func StackRange(trees []*FileTree, index int) *FileTree { +func StackRange(trees []*FileTree, start, stop int) *FileTree { tree := trees[0].Copy() - for idx := 0; idx <= index; idx++ { + for idx := start; idx <= stop; idx++ { tree.Stack(trees[idx]) } return tree diff --git a/filetree/tree_test.go b/filetree/tree_test.go index 44b8e60..429d0de 100644 --- a/filetree/tree_test.go +++ b/filetree/tree_test.go @@ -423,7 +423,7 @@ func TestStackRange(t *testing.T) { upperTree.AddPath(value, fakeData) } trees := []*FileTree{lowerTree, upperTree, tree} - StackRange(trees, 2) + StackRange(trees, 0, 2) } diff --git a/image/image.go b/image/image.go index 4934fee..6faf921 100644 --- a/image/image.go +++ b/image/image.go @@ -55,12 +55,17 @@ type Layer struct { History types.ImageHistory } -func (layer *Layer) String() string { +func (layer *Layer) Id() string { id := layer.History.ID[0:25] if len(layer.History.Tags) > 0 { id = "[" + strings.Join(layer.History.Tags, ",") + "]" } - return fmt.Sprintf(LayerFormat, id, humanize.Bytes(uint64(layer.History.Size)), layer.History.CreatedBy) + return id +} + +func (layer *Layer) String() string { + + return fmt.Sprintf(LayerFormat, layer.Id(), humanize.Bytes(uint64(layer.History.Size)), strings.TrimPrefix(layer.History.CreatedBy, "/bin/sh -c ")) } func InitializeData(imageID string) ([]*Layer, []*filetree.FileTree) { diff --git a/ui/filetreeview.go b/ui/filetreeview.go index 8b49f8e..5f95592 100644 --- a/ui/filetreeview.go +++ b/ui/filetreeview.go @@ -6,21 +6,30 @@ import ( "github.com/jroimartin/gocui" "github.com/wagoodman/docker-image-explorer/filetree" - "github.com/fatih/color" "strings" "github.com/lunixbochs/vtclean" ) +const ( + CompareLayer CompareType = iota + CompareAll +) + +type CompareType int + + type FileTreeView struct { - Name string - gui *gocui.Gui - view *gocui.View - header *gocui.View - TreeIndex int - ModelTree *filetree.FileTree - ViewTree *filetree.FileTree - RefTrees []*filetree.FileTree - HiddenDiffTypes []bool + Name string + gui *gocui.Gui + view *gocui.View + header *gocui.View + ModelTree *filetree.FileTree + ViewTree *filetree.FileTree + RefTrees []*filetree.FileTree + HiddenDiffTypes []bool + CompareMode CompareType + CompareStartIndex int + CompareStopIndex int } func NewFileTreeView(name string, gui *gocui.Gui, tree *filetree.FileTree, refTrees []*filetree.FileTree) (treeview *FileTreeView) { @@ -32,6 +41,7 @@ func NewFileTreeView(name string, gui *gocui.Gui, tree *filetree.FileTree, refTr treeview.ModelTree = tree treeview.RefTrees = refTrees treeview.HiddenDiffTypes = make([]bool, 4) + treeview.CompareMode = CompareLayer return treeview } @@ -88,8 +98,9 @@ func (view *FileTreeView) setLayer(layerIndex int) error { if layerIndex > len(view.RefTrees)-1 { return errors.New(fmt.Sprintf("Invalid layer index given: %d of %d", layerIndex, len(view.RefTrees)-1)) } - newTree := filetree.StackRange(view.RefTrees, layerIndex-1) - newTree.Compare(view.RefTrees[layerIndex]) + view.CompareStopIndex = layerIndex + newTree := filetree.StackRange(view.RefTrees, view.CompareStartIndex, view.CompareStopIndex-1) + newTree.Compare(view.RefTrees[view.CompareStopIndex]) // preserve view state on copy visitor := func(node *filetree.FileNode) error { @@ -104,11 +115,11 @@ func (view *FileTreeView) setLayer(layerIndex int) error { if debug { v, _ := view.gui.View("debug") v.Clear() - _, _ = fmt.Fprintln(v, view.RefTrees[layerIndex]) + _, _ = fmt.Fprintln(v, view.RefTrees[view.CompareStopIndex]) } view.view.SetCursor(0, 0) - view.TreeIndex = 0 + view.CompareStopIndex = 0 view.ModelTree = newTree view.updateViewTree() return view.Render() @@ -119,16 +130,16 @@ func (view *FileTreeView) CursorDown() error { // to let us know what is a valid bounds (i.e. when it hits an empty line) err := CursorDown(view.gui, view.view) if err == nil { - view.TreeIndex++ + view.CompareStopIndex++ } return view.Render() } func (view *FileTreeView) CursorUp() error { - if view.TreeIndex > 0 { + if view.CompareStopIndex > 0 { err := CursorUp(view.gui, view.view) if err == nil { - view.TreeIndex-- + view.CompareStopIndex-- } } return view.Render() @@ -140,7 +151,7 @@ func (view *FileTreeView) getAbsPositionNode() (node *filetree.FileNode) { var dfsCounter int visiter = func(curNode *filetree.FileNode) error { - if dfsCounter == view.TreeIndex { + if dfsCounter == view.CompareStopIndex { node = curNode } dfsCounter++ @@ -170,7 +181,7 @@ func (view *FileTreeView) toggleShowDiffType(diffType filetree.DiffType) error { view.HiddenDiffTypes[diffType] = !view.HiddenDiffTypes[diffType] view.view.SetCursor(0, 0) - view.TreeIndex = 0 + view.CompareStopIndex = 0 view.updateViewTree() return view.Render() } @@ -193,12 +204,11 @@ func (view *FileTreeView) updateViewTree() { } func (view *FileTreeView) KeyHelp() string { - control := color.New(color.Bold).SprintFunc() - return control("[Space]") + ": Collapse dir " + - control("[^A]") + ": Added files " + - control("[^R]") + ": Removed files " + - control("[^M]") + ": Modified files " + - control("[^U]") + ": Unmodified files" + return Formatting.Control("[Space]") + ": Collapse dir " + + Formatting.Control("[^A]") + ": Added files " + + Formatting.Control("[^R]") + ": Removed files " + + Formatting.Control("[^M]") + ": Modified files " + + Formatting.Control("[^U]") + ": Unmodified files" } func (view *FileTreeView) Render() error { @@ -207,7 +217,7 @@ func (view *FileTreeView) Render() error { view.gui.Update(func(g *gocui.Gui) error { view.view.Clear() for idx, line := range lines { - if idx == view.TreeIndex { + if idx == view.CompareStopIndex { fmt.Fprintln(view.view, Formatting.StatusBar(vtclean.Clean(line, false))) } else { fmt.Fprintln(view.view, line) diff --git a/ui/layerview.go b/ui/layerview.go index d100194..f4eefa9 100644 --- a/ui/layerview.go +++ b/ui/layerview.go @@ -51,6 +51,13 @@ func (view *LayerView) Setup(v *gocui.View, header *gocui.View) error { if err := view.gui.SetKeybinding(view.Name, gocui.KeyArrowUp, gocui.ModNone, func(*gocui.Gui, *gocui.View) error { return view.CursorUp() }); err != nil { return err } + if err := view.gui.SetKeybinding(view.Name, gocui.KeyCtrlL, gocui.ModNone, func(*gocui.Gui, *gocui.View) error { return view.setCompareMode(CompareLayer) }); err != nil { + return err + } + if err := view.gui.SetKeybinding(view.Name, gocui.KeyCtrlA, gocui.ModNone, func(*gocui.Gui, *gocui.View) error { return view.setCompareMode(CompareAll) }); err != nil { + return err + } + headerStr := fmt.Sprintf(image.LayerFormat, "Image ID", "Size", "Command") fmt.Fprintln(view.header, Formatting.Header(vtclean.Clean(headerStr, false))) @@ -58,6 +65,12 @@ func (view *LayerView) Setup(v *gocui.View, header *gocui.View) error { return view.Render() } +func (view *LayerView) setCompareMode(compareMode CompareType) error { + Views.Tree.CompareMode = compareMode + view.Render() + return Views.Tree.setLayer(Views.Tree.CompareStopIndex) +} + func (view *LayerView) Render() error { view.gui.Update(func(g *gocui.Gui) error { view.view.Clear() @@ -65,10 +78,16 @@ func (view *LayerView) Render() error { layer := view.Layers[revIdx] idx := (len(view.Layers)-1) - revIdx + layerStr := layer.String() + if idx == 0 { + // TODO: add size + layerStr = fmt.Sprintf(image.LayerFormat, layer.History.ID[0:25], "", "FROM "+layer.Id()) + } + if idx == view.LayerIndex { - fmt.Fprintln(view.view, Formatting.StatusBar(layer.String())) + fmt.Fprintln(view.view, Formatting.StatusBar(layerStr)) } else { - fmt.Fprintln(view.view, layer.String()) + fmt.Fprintln(view.view, layerStr) } } @@ -103,5 +122,6 @@ func (view *LayerView) CursorUp() error { } func (view *LayerView) KeyHelp() string { - return "blerg" + return Formatting.Control("[^L]") + ": Layer Changes " + + Formatting.Control("[^A]") + ": All Changes " } diff --git a/ui/statusview.go b/ui/statusview.go index 99cc579..a6329bc 100644 --- a/ui/statusview.go +++ b/ui/statusview.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/jroimartin/gocui" - "github.com/fatih/color" ) type StatusView struct { @@ -53,10 +52,8 @@ func (view *StatusView) CursorUp() error { } func (view *StatusView) KeyHelp() string { - control := color.New(color.Bold).SprintFunc() - return control("[^C]") + ": Quit " + - control("[^Space]") + ": Switch View " - + return Formatting.Control("[^C]") + ": Quit " + + Formatting.Control("[^Space]") + ": Switch View " } func (view *StatusView) Render() error { diff --git a/ui/ui.go b/ui/ui.go index 434adfd..8b58eb3 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -7,7 +7,7 @@ import ( "github.com/wagoodman/docker-image-explorer/filetree" "github.com/wagoodman/docker-image-explorer/image" "github.com/fatih/color" - "github.com/wagoodman/docker-image-explorer/_vendor-20180604210951/github.com/pkg/errors" + "errors" ) const debug = false @@ -15,6 +15,7 @@ const debug = false var Formatting struct { Header func(...interface{})(string) StatusBar func(...interface{})(string) + Control func(...interface{})(string) } var Views struct { @@ -168,6 +169,7 @@ func Render() { func Run(layers []*image.Layer, refTrees []*filetree.FileTree) { Formatting.StatusBar = color.New(color.ReverseVideo, color.Bold).SprintFunc() Formatting.Header = color.New(color.Bold).SprintFunc() + Formatting.Control = color.New(color.Bold).SprintFunc() g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { @@ -180,7 +182,7 @@ func Run(layers []*image.Layer, refTrees []*filetree.FileTree) { Views.Layer = NewLayerView("side", g, layers) Views.lookup[Views.Layer.Name] = Views.Layer - Views.Tree = NewFileTreeView("main", g, filetree.StackRange(refTrees, 0), refTrees) + Views.Tree = NewFileTreeView("main", g, filetree.StackRange(refTrees, 0,0), refTrees) Views.lookup[Views.Tree.Name] = Views.Tree Views.Status = NewStatusView("status", g)