-
Notifications
You must be signed in to change notification settings - Fork 0
/
tree.go
120 lines (104 loc) · 2.67 KB
/
tree.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Content managed by Project Forge, see [projectforge.md] for details.
package filesystem
import (
"path"
"github.com/samber/lo"
"golang.org/x/exp/slices"
"admini.dev/admini/app/util"
)
type Node struct {
Name string `json:"name"`
Dir bool `json:"dir,omitempty"`
Size int `json:"size,omitempty"`
Children Nodes `json:"children,omitempty"`
Tags []string `json:"tags,omitempty"`
}
func (n *Node) Get(pth ...string) *Node {
if len(pth) == 0 {
return n
}
return n.Children.Get(pth...)
}
func (n *Node) Flatten(curr string) []string {
x := path.Join(curr, n.Name)
ret := n.Children.Flatten(x)
if !n.Dir {
ret = append(ret, x)
}
return ret
}
type Nodes []*Node
func (n Nodes) Flatten(curr string) []string {
ret := make([]string, 0, len(n))
for _, node := range n {
ret = append(ret, node.Flatten(curr)...)
}
return ret
}
func (n Nodes) Sort() Nodes {
slices.SortFunc(n, func(l *Node, r *Node) bool {
return l.Name < r.Name
})
return n
}
func (n Nodes) Get(pth ...string) *Node {
if len(pth) == 0 {
return nil
}
for _, x := range n {
if x.Name == pth[0] {
return x.Get(pth[1:]...)
}
}
return nil
}
func (n Nodes) Merge(x Nodes) Nodes {
ret := slices.Clone(n)
for _, xn := range x {
if curr := ret.Get(xn.Name); curr != nil {
curr.Tags = lo.Uniq(append(slices.Clone(curr.Tags), xn.Tags...))
if len(curr.Children) == 0 && len(xn.Children) > 0 {
curr.Children = xn.Children
} else {
curr.Children = curr.Children.Merge(xn.Children)
}
} else {
ret = append(ret, xn)
}
}
return ret
}
type Tree struct {
Nodes Nodes `json:"nodes,omitempty"`
Config util.ValueMap `json:"config,omitempty"`
}
func (t Tree) Flatten() []string {
return t.Nodes.Flatten("")
}
func (t Tree) Merge(x *Tree) *Tree {
return &Tree{Nodes: t.Nodes.Merge(x.Nodes), Config: t.Config.Merge(x.Config)}
}
func (f *FileSystem) listNodes(pth string, ign []string, logger util.Logger, tags ...string) (Nodes, error) {
files := f.ListFiles(pth, ign, logger)
nodes := make(Nodes, 0, len(files))
for _, de := range files {
x := path.Join(pth, de.Name())
if de.IsDir() {
kids, err := f.listNodes(x, ign, logger)
if err != nil {
return nil, err
}
nodes = append(nodes, &Node{Name: de.Name(), Dir: true, Children: kids, Tags: tags})
} else {
nodes = append(nodes, &Node{Name: de.Name(), Tags: tags, Size: f.Size(x)})
}
}
return nodes.Sort(), nil
}
func (f *FileSystem) ListTree(cfg util.ValueMap, pth string, ign []string, logger util.Logger, tags ...string) (*Tree, error) {
nodes, err := f.listNodes(pth, ign, logger, tags...)
if err != nil {
return nil, err
}
return &Tree{Config: cfg, Nodes: nodes}, nil
}