From 5bc7337b0448b329c15f15576b2e4caa1e6bb6ce Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 22 Oct 2018 17:48:43 -0400 Subject: [PATCH] truncate inefficiencies report (fixes #27) --- cmd/analyze.go | 4 ++-- cmd/build.go | 4 ++-- image/image.go | 13 ++++++++----- ui/detailsview.go | 29 +++++++++++++++++------------ ui/ui.go | 30 +++++++----------------------- 5 files changed, 36 insertions(+), 44 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 077e99c..6a99bba 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -18,6 +18,6 @@ func analyze(cmd *cobra.Command, args []string) { os.Exit(1) } color.New(color.Bold).Println("Analyzing Image") - manifest, refTrees := image.InitializeData(userImage) - ui.Run(manifest, refTrees) + manifest, refTrees, efficiency, inefficiencies := image.InitializeData(userImage) + ui.Run(manifest, refTrees, efficiency, inefficiencies) } diff --git a/cmd/build.go b/cmd/build.go index 49c41b2..309d1ee 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -41,6 +41,6 @@ func doBuild(cmd *cobra.Command, args []string) { log.Fatal(err) } - manifest, refTrees := image.InitializeData(string(imageId)) - ui.Run(manifest, refTrees) + manifest, refTrees, efficiency, inefficiencies := image.InitializeData(string(imageId)) + ui.Run(manifest, refTrees, efficiency, inefficiencies) } diff --git a/image/image.go b/image/image.go index 43f8000..6442e77 100644 --- a/image/image.go +++ b/image/image.go @@ -193,7 +193,7 @@ func processLayerTar(line *jotframe.Line, layerMap map[string]*filetree.FileTree line.Close() } -func InitializeData(imageID string) ([]*Layer, []*filetree.FileTree) { +func InitializeData(imageID string) ([]*Layer, []*filetree.FileTree, float64, filetree.EfficiencySlice) { var manifest ImageManifest var layerMap = make(map[string]*filetree.FileTree) var trees = make([]*filetree.FileTree, 0) @@ -212,11 +212,11 @@ func InitializeData(imageID string) ([]*Layer, []*filetree.FileTree) { } // save this image to disk temporarily to get the content info - imageTarPath, tmpDir := saveImage(imageID) + // imageTarPath, tmpDir := saveImage(imageID) // fmt.Println(imageTarPath) // fmt.Println(tmpDir) - // imageTarPath := "/tmp/dive446223287/image.tar" - defer os.RemoveAll(tmpDir) + imageTarPath := "/home/wagoodman/Downloads/image/image.tar" + // defer os.RemoveAll(tmpDir) // read through the image contents and build a tree tarFile, err := os.Open(imageTarPath) @@ -325,7 +325,10 @@ func InitializeData(imageID string) ([]*Layer, []*filetree.FileTree) { layerIdx-- } - return layers, trees + fmt.Println(" Analyzing layers...") + efficiency, inefficiencies := filetree.Efficiency(trees) + + return layers, trees, efficiency, inefficiencies } func saveImage(imageID string) (string, string) { diff --git a/ui/detailsview.go b/ui/detailsview.go index 663859d..51fcd07 100644 --- a/ui/detailsview.go +++ b/ui/detailsview.go @@ -22,12 +22,14 @@ type DetailsView struct { } // NewDetailsView creates a new view object attached the the global [gocui] screen object. -func NewDetailsView(name string, gui *gocui.Gui) (detailsView *DetailsView) { +func NewDetailsView(name string, gui *gocui.Gui, efficiency float64, inefficiencies filetree.EfficiencySlice) (detailsView *DetailsView) { detailsView = new(DetailsView) // populate main fields detailsView.Name = name detailsView.gui = gui + detailsView.efficiency = efficiency + detailsView.inefficiencies = inefficiencies return detailsView } @@ -76,10 +78,8 @@ func (view *DetailsView) CursorUp() error { return CursorUp(view.gui, view.view) } -// Update refreshes the state objects for future rendering. Note: we only need to update this view upon the initial tree load +// Update refreshes the state objects for future rendering. func (view *DetailsView) Update() error { - layerTrees := Views.Tree.RefTrees - view.efficiency, view.inefficiencies = filetree.Efficiency(layerTrees) return nil } @@ -94,16 +94,21 @@ func (view *DetailsView) Render() error { var wastedSpace int64 template := "%5s %12s %-s\n" - var trueInefficiencies int inefficiencyReport := fmt.Sprintf(Formatting.Header(template), "Count", "Total Space", "Path") - for idx := len(view.inefficiencies) - 1; idx >= 0; idx-- { - data := view.inefficiencies[idx] - trueInefficiencies++ - wastedSpace += data.CumulativeSize - inefficiencyReport += fmt.Sprintf(template, strconv.Itoa(len(data.Nodes)), humanize.Bytes(uint64(data.CumulativeSize)), data.Path) + + height := 100 + if view.view != nil { + _, height = view.view.Size() } - if trueInefficiencies == 0 { - inefficiencyReport = "" + + for idx := 0; idx < len(view.inefficiencies); idx++ { + data := view.inefficiencies[len(view.inefficiencies)-1-idx] + wastedSpace += data.CumulativeSize + + // todo: make this report scrollable and exportable + if idx < height { + inefficiencyReport += fmt.Sprintf(template, strconv.Itoa(len(data.Nodes)), humanize.Bytes(uint64(data.CumulativeSize)), data.Path) + } } effStr := fmt.Sprintf("\n%s %d %%", Formatting.Header("Image efficiency score:"), int(100.0*view.efficiency)) diff --git a/ui/ui.go b/ui/ui.go index 3f918e7..80c6d48 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -3,22 +3,16 @@ package ui import ( "errors" "fmt" - "log" - "github.com/fatih/color" "github.com/jroimartin/gocui" "github.com/wagoodman/dive/filetree" "github.com/wagoodman/dive/image" - "os" - "runtime" - "runtime/pprof" + "log" ) const debug = false -const profile = false -var cpuProfilePath *os.File -var memoryProfilePath *os.File +// var profileObj = profile.Start(profile.CPUProfile, profile.ProfilePath("."), profile.NoShutdownHook) // debugPrint writes the given string to the debug pane (if the debug pane is enabled) func debugPrint(s string) { @@ -138,13 +132,9 @@ func CursorUp(g *gocui.Gui, v *gocui.View) error { // quit is the gocui callback invoked when the user hits Ctrl+C func quit(g *gocui.Gui, v *gocui.View) error { - if profile { - pprof.StopCPUProfile() - runtime.GC() // get up-to-date statistics - pprof.WriteHeapProfile(memoryProfilePath) - memoryProfilePath.Close() - cpuProfilePath.Close() - } + + // profileObj.Stop() + return gocui.ErrQuit } @@ -288,7 +278,7 @@ func renderStatusOption(control, title string, selected bool) string { } // Run is the UI entrypoint. -func Run(layers []*image.Layer, refTrees []*filetree.FileTree) { +func Run(layers []*image.Layer, refTrees []*filetree.FileTree, efficiency float64, inefficiencies filetree.EfficiencySlice) { Formatting.Selected = color.New(color.ReverseVideo, color.Bold).SprintFunc() Formatting.Header = color.New(color.Bold).SprintFunc() @@ -319,7 +309,7 @@ func Run(layers []*image.Layer, refTrees []*filetree.FileTree) { Views.Filter = NewFilterView("command", g) Views.lookup[Views.Filter.Name] = Views.Filter - Views.Details = NewDetailsView("details", g) + Views.Details = NewDetailsView("details", g, efficiency, inefficiencies) Views.lookup[Views.Details.Name] = Views.Details g.Cursor = false @@ -337,12 +327,6 @@ func Run(layers []*image.Layer, refTrees []*filetree.FileTree) { log.Panicln(err) } - if profile { - os.Create("cpu.pprof") - os.Create("mem.pprof") - pprof.StartCPUProfile(cpuProfilePath) - } - if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { log.Panicln(err) }