Skip to content

Commit

Permalink
Do not omit shadowed entries in ls output
Browse files Browse the repository at this point in the history
Fixes gopasspw#2338

RELEASE_NOTES=[BUGFIX] Do not shadow entries behind folders.

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
  • Loading branch information
dominikschulz committed Sep 13, 2022
1 parent fd11327 commit 88afcc2
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 24 deletions.
4 changes: 4 additions & 0 deletions internal/store/root/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/gopasspw/gopass/internal/out"
"github.com/gopasspw/gopass/internal/store"
"github.com/gopasspw/gopass/internal/tree"
"github.com/gopasspw/gopass/pkg/debug"
)

// List will return a flattened list of all tree entries.
Expand Down Expand Up @@ -61,7 +62,9 @@ func (r *Store) Tree(ctx context.Context) (*tree.Root, error) {
return nil, err
}

debug.Log("[root] adding files: %q", sf)
addFileFunc(sf...)
debug.Log("[root] Tree: %s", root.Format(-1))
addTplFunc(r.store.ListTemplates(ctx, "")...)

mps := r.MountPoints()
Expand All @@ -82,6 +85,7 @@ func (r *Store) Tree(ctx context.Context) (*tree.Root, error) {
return nil, fmt.Errorf("failed to add file: %w", err)
}

debug.Log("[%s] adding files: %q", alias, sf)
addFileFunc(sf...)
addTplFunc(substore.ListTemplates(ctx, alias)...)
}
Expand Down
47 changes: 39 additions & 8 deletions internal/tree/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package tree

import (
"bytes"

"github.com/gopasspw/gopass/pkg/debug"
)

// Node is a tree node.
type Node struct {
Name string
Type string
Leaf bool
Template bool
Mount bool
Path string
Expand Down Expand Up @@ -40,7 +42,7 @@ func (n Node) Equals(other Node) bool {
return false
}

if n.Type != other.Type {
if n.Leaf != other.Leaf {
return false
}

Expand All @@ -59,6 +61,35 @@ func (n Node) Equals(other Node) bool {
return true
}

func (n Node) Merge(other Node) *Node {
r := Node{
Name: n.Name,
Leaf: n.Leaf,
Template: n.Template,
Mount: n.Mount,
Path: n.Path,
Subtree: n.Subtree,
}

// can't change name
if other.Leaf {
r.Leaf = true
}
if other.Template {
r.Template = true
}
if other.Mount {
r.Mount = true
}
// can't change path
if r.Subtree == nil && other.Subtree != nil {
r.Subtree = other.Subtree
}
debug.Log("merged %+v and %+v into %+v", n, other, r)

return &r
}

// format returns a pretty printed string of all nodes in and below
// this node, e.g. `├── baz`.
func (n *Node) format(prefix string, last bool, maxDepth, curDepth int) string {
Expand Down Expand Up @@ -86,7 +117,7 @@ func (n *Node) format(prefix string, last bool, maxDepth, curDepth int) string {
switch {
case n.Mount:
_, _ = out.WriteString(colMount(n.Name + " (" + n.Path + ")"))
case n.Type == "dir":
case n.Subtree != nil:
_, _ = out.WriteString(colDir(n.Name + sep))
default:
_, _ = out.WriteString(n.Name)
Expand All @@ -113,7 +144,7 @@ func (n *Node) format(prefix string, last bool, maxDepth, curDepth int) string {

// Len returns the length of this subtree.
func (n *Node) Len() int {
if n.Type == "file" {
if n.Subtree == nil {
return 1
}

Expand All @@ -137,17 +168,17 @@ func (n *Node) list(prefix string, maxDepth, curDepth int, files bool) []string

prefix += n.Name

out := make([]string, 0, n.Len())
// if it's a file and we are looking for files
if n.Type == "file" && files {
if n.Leaf && files {
// we return the file
return []string{prefix}
} else if curDepth == maxDepth && n.Type != "file" {
out = append(out, prefix)
} else if curDepth == maxDepth && n.Subtree != nil {
// otherwise if we are "at the bottom" and it's not a file
// we return the directory name with a separator at the end
return []string{prefix + sep}
}

out := make([]string, 0, n.Len())
// if we don't have subitems, then it's a leaf and we return
// (notice that this is what ends the recursion when maxDepth is set to -1)
if n.Subtree == nil {
Expand Down
17 changes: 11 additions & 6 deletions internal/tree/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/fatih/color"
"github.com/gopasspw/gopass/pkg/debug"
)

const (
Expand Down Expand Up @@ -59,18 +60,18 @@ func (r *Root) AddTemplate(path string) error {
func (r *Root) insert(path string, template bool, mountPath string) error {
t := r.Subtree

debug.Log("adding: %s [tpl: %t, mp: %q]", path, template, mountPath)
// split the path into its components, iterate over them and create
// the tree structure. Everything but the last element is a folder.
p := strings.Split(path, "/")
for i, e := range p {
n := &Node{
Name: e,
Type: "dir",
Subtree: NewTree(),
}
// this is the final element (a leaf)
if i == len(p)-1 {
n.Type = "file"
n.Leaf = true
n.Subtree = nil
n.Template = template

Expand All @@ -80,11 +81,15 @@ func (r *Root) insert(path string, template bool, mountPath string) error {
}
}

node, _ := t.Insert(n)
debug.Log("[%d] %s -> Node: %+v", i, e, n)

node := t.Insert(n)
debug.Log("node after insert: %+v", node)

// do we need to extend an existing subtree?
if i < len(p)-1 && node.Subtree == nil {
node.Subtree = NewTree()
node.Type = "dir"
// node.Type = "dir"
}

// re-root t to the new subtree
Expand Down Expand Up @@ -147,8 +152,8 @@ func (r *Root) FindFolder(path string) (*Root, error) {
prefix := ""

for _, e := range p {
_, node := t.find(e)
if node == nil || node.Type == "file" || node.Subtree == nil {
_, node := t.findPositionFor(e)
if node == nil || node.Subtree == nil {
return nil, ErrNotFound
}

Expand Down
21 changes: 11 additions & 10 deletions internal/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package tree
import (
"fmt"
"sort"

"github.com/gopasspw/gopass/pkg/debug"
)

// ErrNodePresent is returned when a node with the same name is already present.
Expand Down Expand Up @@ -44,28 +46,27 @@ func (t *Tree) Equals(other *Tree) bool {
}

// Insert adds a new node at the right position.
func (t *Tree) Insert(node *Node) (*Node, error) {
pos, found := t.find(node.Name)
func (t *Tree) Insert(node *Node) *Node {
pos, found := t.findPositionFor(node.Name)
if found != nil {
if node.Mount {
t.Nodes[pos] = node

return node, nil
}
debug.Log("merging node (%+v) with existing one (%+v)", found, node)
m := found.Merge(*node)
t.Nodes[pos] = m

return t.Nodes[pos], fmt.Errorf("error at %q: %w", node.Name, ErrNodePresent)
return m
}

debug.Log("extending subtree for %s", node.Name)
// insert at the right position, see
// https://code.google.com/p/go-wiki/wiki/SliceTricks
t.Nodes = append(t.Nodes, &Node{})
copy(t.Nodes[pos+1:], t.Nodes[pos:])
t.Nodes[pos] = node

return node, nil
return node
}

func (t *Tree) find(name string) (int, *Node) {
func (t *Tree) findPositionFor(name string) (int, *Node) {
pos := sort.Search(len(t.Nodes), func(i int) bool {
return t.Nodes[i].Name >= name
})
Expand Down

0 comments on commit 88afcc2

Please sign in to comment.