remove CNB specific logic for now

Signed-off-by: dwillist <dthornton@vmware.com>
This commit is contained in:
dwillist 2021-01-18 20:51:36 -05:00
commit adbd9d793f
15 changed files with 16 additions and 241 deletions

11
=
View file

@ -1,11 +0,0 @@
package componenets
import "github.com/rivo/tview"
type Keybinded interface {
GetKeyBindings() []KeyBinding
}
type KeyMenuPrimitive struct {
*tview.TextView
}

View file

@ -13,7 +13,6 @@ ci-unit-test:
go test -cover -v -race ./...
ci-static-analysis:
grep -R 'const allowTestDataCapture = false' runtime/ui/viewmodel
go vet ./...
@! gofmt -s -l . 2>&1 | grep -vE '^\.git/' | grep -vE '^\.cache/'
golangci-lint run

View file

@ -62,13 +62,7 @@ func doAnalyzeCmd(cmd *cobra.Command, args []string) {
logrus.Error("unable to get 'ignore-errors' option:", err)
}
cnb, err := cmd.PersistentFlags().GetBool("cnb")
if err != nil {
logrus.Error("unable to get 'cnb' option:", err)
}
runtime.Run(runtime.Options{
CNB: cnb,
Ci: isCi,
Source: sourceType,
Image: imageStr,

View file

@ -56,7 +56,6 @@ func initCli() {
rootCmd.Flags().StringVarP(&exportFile, "json", "j", "", "Skip the interactive TUI and write the layer analysis statistics to a given file.")
rootCmd.Flags().StringVar(&ciConfigFile, "ci-config", ".dive-ci", "If CI=true in the environment, use the given yaml to drive validation rules.")
rootCmd.PersistentFlags().BoolP("cnb", "c", false, "show cloud native buildpack app metadata")
rootCmd.Flags().String("lowestEfficiency", "0.9", "(only valid with --ci given) lowest allowable image efficiency (as a ratio between 0-1), otherwise CI validation will fail.")
rootCmd.Flags().String("highestWastedBytes", "disabled", "(only valid with --ci given) highest allowable bytes wasted, otherwise CI validation will fail.")
rootCmd.Flags().String("highestUserWastedPercent", "0.1", "(only valid with --ci given) highest allowable percentage of bytes wasted (as a ratio between 0-1), otherwise CI validation will fail.")
@ -122,13 +121,11 @@ func initConfig() {
tcell.NewEventKey(tcell.KeyCtrlB, rune(0), tcell.ModCtrl),
))
viper.SetDefault("keybinding.toggle-added-files", components.NewKeyBinding(
"Added",
tcell.NewEventKey(tcell.KeyCtrlA, rune(0), tcell.ModCtrl),
))
viper.SetDefault("keybinding.toggle-removed-files", components.NewKeyBinding(
"Removed",
tcell.NewEventKey(tcell.KeyCtrlR, rune(0), tcell.ModCtrl),

View file

@ -1,85 +0,0 @@
package image
import (
"fmt"
"github.com/buildpacks/lifecycle"
"github.com/buildpacks/pack"
"github.com/sirupsen/logrus"
"github.com/wagoodman/dive/dive/filetree"
)
var ErrMissingCNBMetadata = fmt.Errorf("missing CNB metadata")
func (img *Image) CNBAnalyze(layerAnalysis *AnalysisResult) (*AnalysisResult, error) {
client, err := pack.NewClient()
if err != nil {
return nil, fmt.Errorf("unable to create pack client: %s", err)
}
logrus.Debugf("Inspecting image: %s", img.Name)
imageInfo, err := client.InspectImage(img.Name, true)
if err != nil {
return nil, fmt.Errorf("unable to retrieve %s image info: %s", img.Name, err)
}
empty := lifecycle.RunImageMetadata{}
if imageInfo.Base == empty {
return nil, ErrMissingCNBMetadata
}
logrus.Debugf("image info %#v", imageInfo)
newLayers := []*Layer{}
newRefTree := []*filetree.FileTree{}
if len(layerAnalysis.Layers) != len(layerAnalysis.RefTrees) {
return nil, fmt.Errorf("mismatched lengths %s vs %s", len(layerAnalysis.Layers), len(layerAnalysis.RefTrees))
}
var curLayer *Layer = nil
var curRefTree *filetree.FileTree = nil
var isStack = true
for layerIdx, layer := range layerAnalysis.Layers {
rTree := layerAnalysis.RefTrees[layerIdx]
if curLayer == nil {
curLayer = layer
curRefTree = rTree
continue
}
if isStack { // in stack still
curLayer.Size += layer.Size
_, err = curRefTree.Stack(rTree)
if err != nil {
return nil, fmt.Errorf("error to stacking trees")
}
}
if layer.Digest == imageInfo.Base.TopLayer { // end of stack
newLayers = append(newLayers, curLayer)
newRefTree = append(newRefTree, curRefTree)
isStack = false
}
if !isStack {
newLayers = append(newLayers, layer)
newRefTree = append(newRefTree, rTree)
}
}
layerAnalysis.RefTrees = newRefTree
layerAnalysis.Layers = newLayers
layerAnalysis.BOMMapping = buildBOMMapping(layerAnalysis.Layers, imageInfo)
return layerAnalysis, nil
}
func buildBOMMapping(layers []*Layer, labelMetadata *pack.ImageInfo) map[string]lifecycle.BOMEntry {
result := make(map[string]lifecycle.BOMEntry, 0)
for layerIndex, layer := range layers {
result[layer.Digest] = lifecycle.BOMEntry{
Require: lifecycle.Require{},
Buildpack: lifecycle.Buildpack{
ID: fmt.Sprintf("buildpack metadata for layer: %d", layerIndex),
Version: "1.2.3",
},
}
}
return result
}

View file

@ -5,7 +5,7 @@ import (
)
type Image struct {
Name string
Name string
Trees []*filetree.FileTree
Layers []*Layer
}
@ -28,7 +28,7 @@ func (img *Image) Analyze() (*AnalysisResult, error) {
}
return &AnalysisResult{
ImageName: img.Name,
ImageName: img.Name,
Layers: img.Layers,
RefTrees: img.Trees,
Efficiency: efficiency,

2
go.mod
View file

@ -78,4 +78,4 @@ replace github.com/golangci/lint-1 => github.com/golangci/lint-1 v0.0.0-20190420
replace mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34
replace github.com/rivo/tview => /home/deek/workspace/VMware/dwillist/tview
replace github.com/rivo/tview => github.com/dwillist/tview v0.0.0-20210114215028-5f3be7b5a4ec

2
go.sum
View file

@ -147,6 +147,8 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dwillist/tview v0.0.0-20210114215028-5f3be7b5a4ec h1:1BBnesecQR96WbK9DYDtGeFjXZw/97jl7JFNn5Xih+c=
github.com/dwillist/tview v0.0.0-20210114215028-5f3be7b5a4ec/go.mod h1:0ha5CGekam8ZV1kxkBxSlh7gfQ7YolUj2P/VruwH0QY=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=

View file

@ -7,7 +7,6 @@ import (
type Options struct {
Ci bool
CNB bool
Image string
Source dive.ImageSource
IgnoreErrors bool

View file

@ -1,7 +1,6 @@
package runtime
import (
"errors"
"fmt"
"os"
@ -52,17 +51,6 @@ func run(enableUi bool, options Options, imageResolver image.Resolver, events ev
return
}
if options.CNB {
events.message(utils.TitleFormat("Analyzing Cloud Native Buildpacks image..."))
analysis, err = img.CNBAnalyze(analysis)
if errors.Is(err, image.ErrMissingCNBMetadata) {
options.CNB = false
} else if err != nil {
events.exitWithErrorMessage("cannot analyze image", err)
return
}
}
if doExport {
events.message(utils.TitleFormat(fmt.Sprintf("Exporting image to '%s'...", options.ExportFile)))
bytes, err := export.NewExport(analysis).Marshal()
@ -115,7 +103,7 @@ func run(enableUi bool, options Options, imageResolver image.Resolver, events ev
}
if enableUi {
err = ui.Run(analysis, treeStack, options.CNB)
err = ui.Run(analysis, treeStack)
if err != nil {
zap.S().Error("run info exit: ", err.Error())
events.exitWithError(err)

View file

@ -29,7 +29,7 @@ type UI struct {
filterView tview.Primitive
}
func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetree.Comparer, isCNB bool) (*UI, error) {
func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetree.Comparer) (*UI, error) {
var err error
once.Do(func() {
config := components.NewKeyConfig()
@ -41,21 +41,11 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
//initialize viewmodels
filterViewModel := viewmodels.NewFilterViewModel(nil)
var layerModel viewmodels.LayersModel
var layerDetailsBox *components.Wrapper
// TODO extract the CNB specific logic here for now...
if isCNB {
cnbLayerViewModel := viewmodels.NewCNBLayersViewModel(analysis.Layers, analysis.BOMMapping)
cnbLayerDetailsView := components.NewCNBLayerDetailsView(cnbLayerViewModel).Setup()
layerModel = cnbLayerViewModel
layerDetailsBox = components.NewWrapper("CNB Layer Details", "", cnbLayerDetailsView).Setup()
} else {
layerViewModel := viewmodels.NewLayersViewModel(analysis.Layers)
regularLayerDetailsView := components.NewLayerDetailsView(layerViewModel).Setup()
layerModel = layerViewModel
layerDetailsBox = components.NewWrapper("Layer Details", "", regularLayerDetailsView).Setup()
}
layerModel := viewmodels.NewLayersViewModel(analysis.Layers)
regularLayerDetailsView := components.NewLayerDetailsView(layerModel).Setup()
layerDetailsBox := components.NewWrapper("Layer Details", "", regularLayerDetailsView).Setup()
layerDetailsBox.SetVisibility(components.MinHeightVisibility(10))
//layerViewModel := viewmodels.NewLayersViewModel(analysis.Layers)
@ -171,7 +161,7 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
}
// Run is the UI entrypoint.
func Run(analysis *image.AnalysisResult, treeStack filetree.Comparer, isCNB bool) error {
func Run(analysis *image.AnalysisResult, treeStack filetree.Comparer) error {
cfg := zap.NewDevelopmentConfig()
os.MkdirAll("/tmp/dive", os.ModePerm)
cfg.OutputPaths = []string{"/tmp/dive/debug.out"}
@ -186,7 +176,7 @@ func Run(analysis *image.AnalysisResult, treeStack filetree.Comparer, isCNB bool
zap.S().Info("Starting Hidden Flex Program")
app := tview.NewApplication()
_, err = newApp(app, analysis, treeStack, isCNB)
_, err = newApp(app, analysis, treeStack)
if err != nil {
return err
}

View file

@ -1,74 +0,0 @@
package components
import (
"fmt"
"strings"
"github.com/buildpacks/lifecycle"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/wagoodman/dive/dive/image"
)
type CNBLayerDetailModel interface {
GetCurrentLayer() *image.Layer
GetBOMFromDigest(layerSha string) lifecycle.BOMEntry
}
// TODO make this scrollable
type CNBLayerDetailsView struct {
*tview.TextView
layerIndex int
CNBLayerDetailModel
}
func NewCNBLayerDetailsView(model CNBLayerDetailModel) *CNBLayerDetailsView {
return &CNBLayerDetailsView{
TextView: tview.NewTextView(),
CNBLayerDetailModel: model,
}
}
func (lv *CNBLayerDetailsView) Setup() *CNBLayerDetailsView {
lv.SetTitle("Layer Details").SetTitleAlign(tview.AlignLeft)
lv.SetDynamicColors(true).SetBorder(true)
return lv
}
func (lv *CNBLayerDetailsView) Draw(screen tcell.Screen) {
curLayer := lv.CNBLayerDetailModel.GetCurrentLayer()
curBOM := lv.GetBOMFromDigest(curLayer.Digest)
displayText := layerCNBDetailsText(curLayer, curBOM)
lv.SetText(displayText)
lv.TextView.Draw(screen)
}
func (lv *CNBLayerDetailsView) GetKeyBindings() []KeyBindingDisplay {
return []KeyBindingDisplay {}
}
func layerCNBDetailsText(layer *image.Layer, bom lifecycle.BOMEntry) string {
lines := []string{}
if layer.Names != nil && len(layer.Names) > 0 {
lines = append(lines, boldString("Tags: ")+strings.Join(layer.Names, ", "))
} else {
lines = append(lines, boldString("Tags: ")+"(none)")
}
lines = append(lines, boldString("Id: ")+layer.Id)
lines = append(lines, layer.Command)
lines = append(lines, boldString("BOM: ")+fmt.Sprintf("Entry for: %s", bom.Buildpack.String()))
return strings.Join(lines, "\n")
}
func (lv *CNBLayerDetailsView) getBox() *tview.Box {
return lv.Box
}
func (lv *CNBLayerDetailsView) getDraw() drawFn {
return lv.Draw
}
func (lv *CNBLayerDetailsView) getInputWrapper() inputFn {
return lv.InputHandler
}

View file

@ -1,6 +1,8 @@
package components
import (
"fmt"
"github.com/rivo/tview"
"github.com/sirupsen/logrus"
)
@ -25,7 +27,7 @@ func (d *DiveApplication) GetKeyBindings() []KeyBindingDisplay {
result := []KeyBindingDisplay{}
for i := 0; i < len(d.bindings); i++ {
binding := d.bindings[i]
logrus.Debug("adding keybinding with name %s", binding.Display)
logrus.Debug(fmt.Sprintf("adding keybinding with name %s", binding.Display))
result = append(result, KeyBindingDisplay{KeyBinding: &binding, Selected: false})
}

View file

@ -1,26 +0,0 @@
package viewmodels
import (
"github.com/buildpacks/lifecycle"
"github.com/wagoodman/dive/dive/image"
)
type CNBLayersViewModel struct {
*LayersViewModel
bomMapping map[string]lifecycle.BOMEntry
}
func NewCNBLayersViewModel(layers []*image.Layer, bomMapping map[string]lifecycle.BOMEntry) *CNBLayersViewModel {
return &CNBLayersViewModel{
LayersViewModel: NewLayersViewModel(layers),
bomMapping: bomMapping,
}
}
func (cvm *CNBLayersViewModel) GetBOMFromDigest(layerSha string) lifecycle.BOMEntry {
result, ok := cvm.bomMapping[layerSha]
if !ok {
return lifecycle.BOMEntry{}
}
return result
}

View file

@ -58,7 +58,7 @@ func (lm *LayersViewModel) GetCompareIndicies() filetree.TreeIndexKey {
func (lm *LayersViewModel) SetLayerIndex(index int) bool {
if 0 <= index && index < len(lm.layers) {
logrus.Debug("setting index, old: %d, new: %d", lm.index, index)
logrus.Debug(fmt.Sprintf("setting index, old: %d, new: %d", lm.index, index))
lm.index = index
return true
}