summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordwillist <dthornton@vmware.com>2021-02-14 17:23:30 -0500
committerdwillist <dthornton@vmware.com>2021-02-14 17:23:30 -0500
commitae89e3dc2ca81401d8c8ad91f83a07d4473f4c26 (patch)
tree3bd623c40e25f05b5ac504189b0d43277838646c
parent13c58c005518870f949af5d4bae160ce748c97d3 (diff)
create constructors package, move viewmodel initialization into this package
Signed-off-by: dwillist <dthornton@vmware.com>
-rw-r--r--runtime/ui/app.go24
-rw-r--r--runtime/ui/components/keybinding_primitive.go2
-rw-r--r--runtime/ui/components/visible_primitive.go29
-rw-r--r--runtime/ui/constructors/key_config.go19
-rw-r--r--runtime/ui/viewmodels/tree_view_model.go5
-rw-r--r--runtime/ui/viewmodels/tree_view_model_test.go143
6 files changed, 86 insertions, 136 deletions
diff --git a/runtime/ui/app.go b/runtime/ui/app.go
index df527fd..e9a576a 100644
--- a/runtime/ui/app.go
+++ b/runtime/ui/app.go
@@ -2,6 +2,7 @@ package ui
import (
"fmt"
+ "log"
"sync"
"github.com/gdamore/tcell/v2"
@@ -9,8 +10,8 @@ import (
"github.com/sirupsen/logrus"
"github.com/wagoodman/dive/dive/filetree"
"github.com/wagoodman/dive/dive/image"
- "github.com/wagoodman/dive/runtime/ui/constructors"
"github.com/wagoodman/dive/runtime/ui/components"
+ "github.com/wagoodman/dive/runtime/ui/constructors"
"github.com/wagoodman/dive/runtime/ui/format"
"github.com/wagoodman/dive/runtime/ui/viewmodels"
)
@@ -39,20 +40,19 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
diveApplication := components.NewDiveApplication(app)
//initialize viewmodels
- filterViewModel := viewmodels.NewFilterViewModel(nil)
+ modelConfig := constructors.ModelConfig{
+ Cache: &CacheWrapper{Cache: &cache},
+ Layers: analysis.Layers,
+ }
+ _, layersViewModel, treeViewModel, err := constructors.InitializeModels(modelConfig)
+ if err != nil {
+ log.Fatal(fmt.Errorf("unable to initialize viewmodels: %q", err))
+ }
- layerModel := viewmodels.NewLayersViewModel(analysis.Layers)
- regularLayerDetailsView := components.NewLayerDetailsView(layerModel).Setup()
+ regularLayerDetailsView := components.NewLayerDetailsView(layersViewModel).Setup()
layerDetailsBox := components.NewWrapper("Layer Details", "", regularLayerDetailsView).Setup()
layerDetailsBox.SetVisibility(components.MinHeightVisibility(10))
- //layerViewModel := viewmodels.NewLayersViewModel(analysis.Layers)
- cacheWrapper := CacheWrapper{Cache: &cache}
- treeViewModel, err := viewmodels.NewTreeViewModel(&cacheWrapper, layerModel, filterViewModel)
- if err != nil {
- panic(err)
- }
-
// initialize views
imageDetailsView := components.NewImageDetailsView(analysis).Setup()
imageDetailsBox := components.NewWrapper("Image Details", "", imageDetailsView).Setup()
@@ -155,7 +155,7 @@ func newApp(app *tview.Application, analysis *image.AnalysisResult, cache filetr
// additional setup configuration
if appConfig.GetAggregateLayerSetting() {
- err := layerModel.SwitchLayerMode()
+ err := layersViewModel.SwitchLayerMode()
if err != nil {
panic(err)
}
diff --git a/runtime/ui/components/keybinding_primitive.go b/runtime/ui/components/keybinding_primitive.go
index d26d60a..7733b45 100644
--- a/runtime/ui/components/keybinding_primitive.go
+++ b/runtime/ui/components/keybinding_primitive.go
@@ -65,7 +65,6 @@ func (t *KeyMenuView) GetKeyBindings() []helpers.KeyBindingDisplay {
func (t *KeyMenuView) Draw(screen tcell.Screen) {
t.Box.Draw(screen)
x, y, width, _ := t.Box.GetInnerRect()
- // TODO: add logic to highlight selected options
lines := []string{}
keyBindings := t.GetKeyBindings()
@@ -80,7 +79,6 @@ func (t *KeyMenuView) Draw(screen tcell.Screen) {
keyBindingFormatter = format.StatusControlSelectedBold
}
postfix := "⎹"
- //postfix := "▏"
if idx == len(keyBindings)-1 {
postfix = " "
}
diff --git a/runtime/ui/components/visible_primitive.go b/runtime/ui/components/visible_primitive.go
index 3c64025..702c953 100644
--- a/runtime/ui/components/visible_primitive.go
+++ b/runtime/ui/components/visible_primitive.go
@@ -1,36 +1,31 @@
package components
import (
- "github.com/rivo/tview"
+ "github.com/rivo/tview"
)
type Visiblility interface {
- Visible() bool
+ Visible() bool
}
type VisiblePrimitive interface {
- tview.Primitive
- Visiblility
+ tview.Primitive
+ Visiblility
}
type VisibleFunc func(tview.Primitive) bool
func Always(alwaysVal bool) VisibleFunc {
- return func (_ tview.Primitive) bool {
- return alwaysVal
- }
+ return func (_ tview.Primitive) bool {
+ return alwaysVal
+ }
}
func MinHeightVisibility(minHeight int) VisibleFunc {
- return func(p tview.Primitive) bool {
- _, _, _, height := p.GetRect()
- return height >= minHeight
- }
+ return func(p tview.Primitive) bool {
+ _, _, _, height := p.GetRect()
+ return height >= minHeight
+ }
}
-// How can we actually implement this????
-// Either we have to do one of the following
-// 1) we want to use particular and specific methods on an item
-// - we Have to make VisibleFunc methods know what their base class is ( or at least have a larger interface )
-// 2) How can we make this configurable
-// 3) make this an implementaion detail of each struct that conforms to this interface (this seems like the best idea)
+
diff --git a/runtime/ui/constructors/key_config.go b/runtime/ui/constructors/key_config.go
index 5b5ec42..735f8f8 100644
--- a/runtime/ui/constructors/key_config.go
+++ b/runtime/ui/constructors/key_config.go
@@ -9,25 +9,6 @@ import (
"gitlab.com/tslocum/cbind"
)
-// TODO move key constants out to their own file
-var DisplayNames = map[string]string{
- "keybinding.quit": "Quit",
- "keybinding.toggle-view": "Switch View",
- "keybinding.filter-files": "Find",
- "keybinding.compare-all": "Compare All",
- "keybinding.compare-layer": "Compare Layer",
- "keybinding.toggle-collapse-dir": "Collapse",
- "keybinding.toggle-collapse-all-dir": "Collapse All",
- "keybinding.toggle-filetree-attributes": "Attributes",
- "keybinding.toggle-added-files": "Added",
- "keybinding.toggle-removed-files": "Removed",
- "keybinding.toggle-modified-files": "Modified",
- "keybinding.toggle-unmodified-files": "Unmodified",
- "keybinding.page-up": "Pg Up",
- "keybinding.page-down": "Pg Down",
-}
-
-// TODO move this to a more appropriate place
type KeyConfig struct{}
type MissingConfigError struct {
diff --git a/runtime/ui/viewmodels/tree_view_model.go b/runtime/ui/viewmodels/tree_view_model.go
index 8f669bb..5294e06 100644
--- a/runtime/ui/viewmodels/tree_view_model.go
+++ b/runtime/ui/viewmodels/tree_view_model.go
@@ -84,6 +84,7 @@ func (tvm *TreeViewModel) VisibleSize() int {
func (tvm *TreeViewModel) SetFilter(filterRegex *regexp.Regexp) {
tvm.FilterModel.SetFilter(filterRegex)
if err := tvm.filterUpdate(); err != nil {
+ // TODO -Dan- handle panics
panic(err)
}
}
@@ -106,9 +107,7 @@ func (tvm *TreeViewModel) GetHiddenFileType(filetype filetree.DiffType) bool {
-// TODO: maek this method private, cant think of a reason for this to be public
func (tvm *TreeViewModel) filterUpdate() error {
- logrus.Debug("Updating filter!!!")
// keep the t selection in parity with the current DiffType selection
filter := tvm.GetFilter()
err := tvm.currentTree.VisitDepthChildFirst(func(node *filetree.FileNode) error {
@@ -127,7 +126,7 @@ func (tvm *TreeViewModel) filterUpdate() error {
if filter != nil && !node.Data.ViewInfo.Hidden { // hide nodes that do not match the current file filter regex (also don't unhide nodes that are already hidden)
match := filter.FindString(node.Path())
- node.Data.ViewInfo.Hidden = len(match) != 0
+ node.Data.ViewInfo.Hidden = len(match) == 0
}
return nil
}, nil)
diff --git a/runtime/ui/viewmodels/tree_view_model_test.go b/runtime/ui/viewmodels/tree_view_model_test.go
index 7f8314b..916393e 100644
--- a/runtime/ui/viewmodels/tree_view_model_test.go
+++ b/runtime/ui/viewmodels/tree_view_model_test.go
@@ -2,12 +2,14 @@ package viewmodels_test
import (
tar "archive/tar"
- "github.com/wagoodman/dive/dive/filetree"
- "github.com/wagoodman/dive/runtime/ui/viewmodels"
- "github.com/wagoodman/dive/runtime/ui/viewmodels/fakes"
"os"
+ "reflect"
"regexp"
"testing"
+
+ "github.com/wagoodman/dive/dive/filetree"
+ "github.com/wagoodman/dive/runtime/ui/viewmodels"
+ "github.com/wagoodman/dive/runtime/ui/viewmodels/fakes"
)
func TestTreeViewModel(t *testing.T) {
@@ -37,7 +39,7 @@ func testStringBetween(t *testing.T) {
t.Fatalf("unexpected error: %s", err)
}
- out := tvm.StringBetween(1,2,true)
+ out := tvm.StringBetween(1, 2, true)
if out != expectedString {
t.Fatalf("expected: %s got: %s", expectedString, out)
}
@@ -149,7 +151,7 @@ func testSetFilter(t *testing.T) {
lModel := &fakes.LayersModel{}
tCache := &fakes.TreeCache{}
tModel := filetree.NewFileTree()
- _,_, err := tModel.AddPath("/dirA/dirB/file", filetree.FileInfo {
+ _, _, err := tModel.AddPath("/dirA/dirB/file", filetree.FileInfo{
Path: "/dirA/dirB/file",
TypeFlag: tar.TypeReg,
Size: 100,
@@ -158,10 +160,9 @@ func testSetFilter(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
-
+ errorCheck(t, err)
- _,_,err = tModel.AddPath("/dirA/dirC/other-thing", filetree.FileInfo {
+ _, _, err = tModel.AddPath("/dirA/dirC/other-thing", filetree.FileInfo{
Path: "/dirA/dirC/other-thing",
TypeFlag: tar.TypeReg,
Size: 1000,
@@ -170,9 +171,9 @@ func testSetFilter(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
+ errorCheck(t, err)
- _,_, err = tModel.AddPath("/dirA/dirB/other-file", filetree.FileInfo {
+ _, _, err = tModel.AddPath("/dirA/dirB/other-file", filetree.FileInfo{
Path: "/dirA/dirB/other-file",
TypeFlag: tar.TypeReg,
Size: 1000,
@@ -181,7 +182,7 @@ func testSetFilter(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
+ errorCheck(t, err)
tCache.GetTreeCall.Returns.TreeModel = tModel
@@ -192,21 +193,17 @@ func testSetFilter(t *testing.T) {
hiddenNodes, err := getHiddenNodes(tModel)
errorCheck(t, err)
- if len(hiddenNodes) != 0 {
- t.Fatalf("expected no nodes to be hidden, got %d", len(hiddenNodes))
- }
+ assertEqual(t, 0, len(hiddenNodes))
r := regexp.MustCompile("other-file")
tvm.SetFilter(r)
hiddenNodes, err = getHiddenNodes(tModel)
errorCheck(t, err)
- if len(hiddenNodes) != 1 {
- t.Fatalf("expected 1 to be hidden, got %d", len(hiddenNodes))
- }
- if hiddenNodes[0].Name != "other-file" {
- t.Fatalf("expected 'other-file' to be hidden, got %s", hiddenNodes[0].Name)
- }
+ assertEqual(t, 3, len(hiddenNodes))
+ assertEqual(t, "file", hiddenNodes[0].Name)
+ assertEqual(t, "dirC", hiddenNodes[1].Name)
+ assertEqual(t, "other-thing", hiddenNodes[2].Name)
// Check if directories where all children are hidden are hidden as well
r = regexp.MustCompile("file")
@@ -214,26 +211,10 @@ func testSetFilter(t *testing.T) {
hiddenNodes, err = getHiddenNodes(tModel)
errorCheck(t, err)
- if len(hiddenNodes) != 3 {
- t.Fatalf("expected 3 nodes to be hidden, got %d", len(hiddenNodes))
- }
-
- hiddenNames := []string{}
- for _, node := range hiddenNodes {
- hiddenNames = append(hiddenNames, node.Name)
- }
-
- if !containsString("other-file", hiddenNames) {
- t.Fatalf("expected %#v to contain other-file", hiddenNames)
- }
-
- if !containsString("file", hiddenNames) {
- t.Fatalf("expected %#v to contain file", hiddenNames)
- }
+ assertEqual(t, 2, len(hiddenNodes))
- if !containsString("dirB", hiddenNames) {
- t.Fatalf("expected %#v to contain dirB", hiddenNames)
- }
+ assertEqual(t, "dirC", hiddenNodes[0].Name)
+ assertEqual(t, "other-thing", hiddenNodes[1].Name)
}
func testToggleHiddenFileType(t *testing.T) {
@@ -241,7 +222,7 @@ func testToggleHiddenFileType(t *testing.T) {
lModel := &fakes.LayersModel{}
tCache := &fakes.TreeCache{}
tModel := filetree.NewFileTree()
- _,_,err := tModel.AddPath("/dirA/file", filetree.FileInfo {
+ _, _, err := tModel.AddPath("/dirA/file", filetree.FileInfo{
Path: "/dirA/file",
TypeFlag: tar.TypeReg,
Size: 100,
@@ -250,7 +231,7 @@ func testToggleHiddenFileType(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
+ errorCheck(t, err)
tModel.Root.Children["dirA"].Children["file"].Data.DiffType = filetree.Added
tCache.GetTreeCall.Returns.TreeModel = tModel
@@ -262,30 +243,15 @@ func testToggleHiddenFileType(t *testing.T) {
hiddenNodes, err := getHiddenNodes(tModel)
errorCheck(t, err)
- if len(hiddenNodes) != 0 {
- t.Fatalf("expected no nodes to be hidden, got %d", len(hiddenNodes))
- }
+ assertEqual(t, 0, len(hiddenNodes))
tvm.ToggleHiddenFileType(filetree.Added)
hiddenNodes, err = getHiddenNodes(tModel)
errorCheck(t, err)
- if len(hiddenNodes) != 2 {
- t.Fatalf("expected 2 to be hidden, got %d", len(hiddenNodes))
- }
- hiddenNames := []string{}
- for _, node := range hiddenNodes {
- hiddenNames = append(hiddenNames, node.Name)
- }
-
- if !containsString("file", hiddenNames) {
- t.Fatalf("expected 'file' to be hidden in %#v", hiddenNames)
- }
-
- if !containsString("dirA", hiddenNames) {
- t.Fatalf("expected 'file' to be hidden in %#v", hiddenNames)
- }
-
+ assertEqual(t, 2, len(hiddenNodes))
+ assertEqual(t, "dirA", hiddenNodes[0].Name)
+ assertEqual(t, "file", hiddenNodes[1].Name)
}
func testGetHiddenFileType(t *testing.T) {
@@ -351,9 +317,7 @@ func testSetLayerIndex(t *testing.T) {
testIndex := 10
tvm.SetLayerIndex(testIndex)
- if lModel.SetLayerIndexCall.Receives.Index != testIndex {
- t.Fatalf("expected index to be %d, got %d", testIndex, lModel.SetLayerIndexCall.Receives.Index)
- }
+ assertEqual(t, testIndex, lModel.SetLayerIndexCall.Receives.Index)
}
func testSwitchLayerMode(t *testing.T) {
@@ -361,7 +325,7 @@ func testSwitchLayerMode(t *testing.T) {
lModel := &fakes.LayersModel{}
tCache := &fakes.TreeCache{}
firstTreeModel := filetree.NewFileTree()
- _, _, err := firstTreeModel.AddPath("/collapsed-dir/collapsed-file", filetree.FileInfo {
+ _, _, err := firstTreeModel.AddPath("/collapsed-dir/collapsed-file", filetree.FileInfo{
Path: "/collapsed-dir/collapsed-file",
TypeFlag: tar.TypeReg,
Size: 100,
@@ -370,14 +334,14 @@ func testSwitchLayerMode(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
+ errorCheck(t, err)
// Second tree has no collapsed or hidden values set
secondTreeModel := firstTreeModel.Copy()
firstTreeModel.Root.Children["collapsed-dir"].Data.ViewInfo.Collapsed = true
- _,_, err = secondTreeModel.AddPath("/visible/visible-file", filetree.FileInfo {
+ _, _, err = secondTreeModel.AddPath("/visible/visible-file", filetree.FileInfo{
Path: "/visible/visible-file",
TypeFlag: tar.TypeReg,
Size: 100,
@@ -386,8 +350,7 @@ func testSwitchLayerMode(t *testing.T) {
Gid: 200,
IsDir: false,
})
- errorCheck(t,err)
-
+ errorCheck(t, err)
collapsedNodes, err := getCollapsedNodes(secondTreeModel)
errorCheck(t, err)
@@ -395,10 +358,10 @@ func testSwitchLayerMode(t *testing.T) {
t.Fatalf("expected no nodes to be collapsed got %v", collapsedNodes)
}
- key := filetree.NewTreeIndexKey(1,2,3,4)
+ key := filetree.NewTreeIndexKey(1, 2, 3, 4)
tCache.GetTreeCall.Stub = func(k filetree.TreeIndexKey) (viewmodels.TreeModel, error) {
if k == key {
- return secondTreeModel,nil
+ return secondTreeModel, nil
}
return firstTreeModel, nil
@@ -409,23 +372,17 @@ func testSwitchLayerMode(t *testing.T) {
t.Fatalf("unexpected error: %s", err)
}
- lModel.GetCompareIndiciesCall.Returns.TreeIndexKey = filetree.NewTreeIndexKey(1,2,3,4)
+ lModel.GetCompareIndiciesCall.Returns.TreeIndexKey = filetree.NewTreeIndexKey(1, 2, 3, 4)
err = tvm.SwitchLayerMode()
errorCheck(t, err)
collapsedNodes, err = getCollapsedNodes(secondTreeModel)
errorCheck(t, err)
- if len(collapsedNodes) != 1 {
- t.Fatalf("expected no nodes to be collapsed got %v", collapsedNodes)
- }
+ assertEqual(t, 1, len(collapsedNodes))
- if collapsedNodes[0].Name != "collapsed-dir" {
- t.Fatalf("expected 'collapsed-dir' to be collapsed got %s", collapsedNodes[0].Name)
- }
+ assertEqual(t, "collapsed-dir", collapsedNodes[0].Name)
}
-
-
func containsString(needle string, haystack []string) bool {
for _, s := range haystack {
if s == needle {
@@ -457,15 +414,35 @@ func getCollapsedNodes(tModel *filetree.FileTree) ([]*filetree.FileNode, error)
result = append(result, node)
}
return nil
- },nil)
-
+ }, nil)
return result, err
}
-
func errorCheck(t *testing.T, err error) {
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
-} \ No newline at end of file
+}
+
+//
+// Assertion helpers
+//
+
+func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
+ t.Helper()
+ if !reflect.DeepEqual(expected, actual) {
+ t.Fatalf("Expected %#v, got %#v", expected, actual)
+ }
+}
+
+func assertSliceContains(t *testing.T, expected interface{}, container []interface{}) {
+ t.Helper()
+ for i := range container {
+ if reflect.DeepEqual(container[i], expected) {
+ return
+ }
+ }
+ t.Fatalf("Expected value %v not found", expected)
+}
+