diff --git a/cmd/travelgrunt/main.go b/cmd/travelgrunt/main.go index 1525735..57767ef 100644 --- a/cmd/travelgrunt/main.go +++ b/cmd/travelgrunt/main.go @@ -46,14 +46,14 @@ func buildMenuFromTree(t tree.Tree) string { var selected string var parentID string - for c := -1; c < t.LevelCount(); c++ { - if !t.HasChildren(c, parentID) { - selected = parentID - - break + for idx := -1; idx < t.LevelCount(); idx++ { + if len(parentID) > 0 { + if !t.GetNode(parentID).HasChildren() { + return parentID + } } - selected, err := menu.Build(t.ChildNames(c, parentID), terminal.Height(), parentID) + selected, err := menu.Build(t.LevelChildNames(idx, parentID), terminal.Height(), parentID) if err != nil { if err.Error() == "^C" { @@ -63,7 +63,11 @@ func buildMenuFromTree(t tree.Tree) string { log.Fatalf("failed to build menu: %s", err.Error()) } - parentID = t.ChildItems(c, parentID)[selected] + if selected == "." { + return parentID + } + + parentID = t.LevelChildItems(idx, parentID)[selected] } return selected diff --git a/pkg/directory/tree/node/node.go b/pkg/directory/tree/node/node.go index 0c449f8..3867b97 100644 --- a/pkg/directory/tree/node/node.go +++ b/pkg/directory/tree/node/node.go @@ -1,6 +1,6 @@ package node -// Node is an element Tree gets composed from (a path with hierarchical and connection metadata) +// Node is an element Tree gets composed from (a path enriched with hierarchical and connection metadata) type Node struct { name string path string @@ -32,7 +32,7 @@ func (n Node) HasChildren() bool { return len(n.children) > 0 } -// IsTerminal tells us if that node has can be a Tree exit point +// IsTerminal tells us if that node has can be used as a tree exit point func (n Node) IsTerminal() bool { return n.terminal } diff --git a/pkg/directory/tree/tree.go b/pkg/directory/tree/tree.go index 8a602b1..de954f9 100644 --- a/pkg/directory/tree/tree.go +++ b/pkg/directory/tree/tree.go @@ -135,8 +135,13 @@ func (t Tree) levelItems(idx int) (items map[string]string) { return items } -// ChildItems gives us a list of child items for the [parent] node located on the given level ID and the given path -func (t Tree) ChildItems(idx int, parentPath string) (items map[string]string) { +// GetNode returns a node record for the given path +func (t Tree) GetNode(path string) node.Node { + return t.nodes[path] +} + +// LevelChildItems gives us a list of child items for the [parent] node located on the given level ID and on the given path +func (t Tree) LevelChildItems(idx int, parentPath string) (items map[string]string) { if len(t.levels) < idx+1 { return nil } @@ -152,8 +157,8 @@ func (t Tree) ChildItems(idx int, parentPath string) (items map[string]string) { items = make(map[string]string, len(t.levels[idx+1])) for path, name := range t.levels[idx+1] { - currentNode := t.nodes[path] - parentNode := t.nodes[parentPath] + currentNode := t.GetNode(path) + parentNode := t.GetNode(parentPath) if currentNode.IsAChildOf(parentNode) { items[name] = path @@ -167,18 +172,7 @@ func (t Tree) ChildItems(idx int, parentPath string) (items map[string]string) { return items } -// ChildNames gives us a list of child names for the [parent] node located on the given level ID and the given path -func (t Tree) ChildNames(idx int, parentPath string) []string { - return sortedKeys(t.ChildItems(idx, parentPath)) -} - -// HasChildren tells us if a node on the given level ID and the given path has child nodes (if node is a parent itself) -func (t Tree) HasChildren(idx int, parentPath string) bool { - return len(t.ChildItems(idx, parentPath)) > 0 -} - -func (t Tree) nodeExists(path string) bool { - _, defined := t.nodes[path] - - return defined +// LevelChildNames gives us a list of child names for the [parent] node located on the given level ID and on the given path +func (t Tree) LevelChildNames(idx int, parentPath string) []string { + return sortedKeys(t.LevelChildItems(idx, parentPath)) } diff --git a/pkg/directory/tree/tree_test.go b/pkg/directory/tree/tree_test.go index a199e19..e3e7f42 100644 --- a/pkg/directory/tree/tree_test.go +++ b/pkg/directory/tree/tree_test.go @@ -64,14 +64,14 @@ func TestLevelItems(t *testing.T) { assert.Equal("terragrunt", items["terragrunt"]) } -func TestChildItems(t *testing.T) { +func TestLevelChildItems(t *testing.T) { assert := assert.New(t) - assert.Nil(mock.ChildItems(10, "whatever")) - assert.Equal(map[string]string{}, mock.ChildItems(4, "terragrunt/prod/region-1/k8s/foo")) - assert.Equal(mock.levelItems(0), mock.ChildItems(-1, "ignored-if-minus-one-passed")) + assert.Nil(mock.LevelChildItems(10, "whatever")) + assert.Equal(map[string]string{}, mock.LevelChildItems(4, "terragrunt/prod/region-1/k8s/foo")) + assert.Equal(mock.levelItems(0), mock.LevelChildItems(-1, "ignored-if-minus-one-passed")) - items := mock.ChildItems(0, "terragrunt") + items := mock.LevelChildItems(0, "terragrunt") expected := map[string]string{"dev": "terragrunt/dev", "prod": "terragrunt/prod"} assert.NotNil(items) @@ -79,10 +79,10 @@ func TestChildItems(t *testing.T) { assert.Equal(expected, items) } -func TestChildItemsTerminalAndWithChildren(t *testing.T) { +func TestLevelChildItemsTerminalAndWithChildren(t *testing.T) { assert := assert.New(t) - items := mock.ChildItems(3, "terragrunt/dev/region-1/rds") + items := mock.LevelChildItems(3, "terragrunt/dev/region-1/rds") expected := map[string]string{ ".": "terragrunt/dev/region-1/rds", "bar": "terragrunt/dev/region-1/rds/bar", @@ -95,32 +95,13 @@ func TestChildItemsTerminalAndWithChildren(t *testing.T) { assert.Equal(expected, items) } -func TestChildNames(t *testing.T) { +func TestLevelChildNames(t *testing.T) { assert := assert.New(t) - items := mock.ChildNames(0, "terragrunt") + items := mock.LevelChildNames(0, "terragrunt") expected := []string{"dev", "prod"} assert.NotNil(items) assert.Equal(2, len(items)) assert.Equal(expected, items) } - -func TestHasChildren(t *testing.T) { - assert := assert.New(t) - - assert.True(mock.HasChildren(-1, "")) - assert.True(mock.HasChildren(-1, "whatever")) - - assert.True(mock.nodeExists("terragrunt")) - assert.True(mock.HasChildren(0, "terragrunt")) - - assert.True(mock.nodeExists("terragrunt/prod/region-1/k8s")) - assert.True(mock.HasChildren(3, "terragrunt/prod/region-1/k8s")) - - assert.False(mock.nodeExists("i-do-not-exist")) - assert.False(mock.HasChildren(0, "i-do-not-exist")) - - assert.True(mock.nodeExists("terragrunt/prod/region-1/k8s/foo")) - assert.False(mock.HasChildren(4, "terragrunt/prod/region-1/k8s/foo")) -} diff --git a/pkg/menu/menu.go b/pkg/menu/menu.go index 260a473..9074d0e 100644 --- a/pkg/menu/menu.go +++ b/pkg/menu/menu.go @@ -28,13 +28,15 @@ func getSize(itemCount int, size int) int { } // Build creates an interactive menu to chose destination directory from -func Build(items []string, maxSize int, previous string) (selected string, err error) { +func Build(items []string, size int, parentID string) (selected string, err error) { + var extension string + if len(items) == 0 { return "", fmt.Errorf("no items") } - if len(previous) > 0 { - fmt.Printf("=> %s\n", previous) + if len(parentID) > 0 { + extension = fmt.Sprintf(" [from \"%s\"]", parentID) } if len(items) == 1 { @@ -50,9 +52,9 @@ func Build(items []string, maxSize int, previous string) (selected string, err e } prompt := promptui.Select{ - Label: label, + Label: label + extension, Items: items, - Size: getSize(len(items), maxSize-Overhead), + Size: getSize(len(items), size-Overhead), Searcher: searcher, }