2014-12-05 20:45:49 +00:00
|
|
|
package restic
|
2014-04-21 21:25:31 +00:00
|
|
|
|
|
|
|
import (
|
2014-08-11 20:47:24 +00:00
|
|
|
"fmt"
|
2014-11-30 21:34:21 +00:00
|
|
|
"sort"
|
2014-09-18 20:41:24 +00:00
|
|
|
|
2016-09-01 20:17:37 +00:00
|
|
|
"restic/errors"
|
2016-08-21 15:46:23 +00:00
|
|
|
|
2016-02-14 14:29:28 +00:00
|
|
|
"restic/debug"
|
2014-04-21 21:25:31 +00:00
|
|
|
)
|
|
|
|
|
2016-09-01 20:08:45 +00:00
|
|
|
// Tree is an ordered list of nodes.
|
2015-01-10 22:40:10 +00:00
|
|
|
type Tree struct {
|
|
|
|
Nodes []*Node `json:"nodes"`
|
|
|
|
}
|
2014-04-21 21:25:31 +00:00
|
|
|
|
2016-09-01 20:08:45 +00:00
|
|
|
// NewTree creates a new tree object.
|
2015-01-10 22:40:10 +00:00
|
|
|
func NewTree() *Tree {
|
|
|
|
return &Tree{
|
|
|
|
Nodes: []*Node{},
|
2014-08-11 21:14:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-10 22:40:10 +00:00
|
|
|
func (t Tree) String() string {
|
2015-04-26 15:44:38 +00:00
|
|
|
return fmt.Sprintf("Tree<%d nodes>", len(t.Nodes))
|
2015-01-10 22:40:10 +00:00
|
|
|
}
|
2014-11-30 21:34:21 +00:00
|
|
|
|
2015-04-26 15:44:38 +00:00
|
|
|
// Equals returns true if t and other have exactly the same nodes.
|
|
|
|
func (t Tree) Equals(other *Tree) bool {
|
2015-01-10 22:40:10 +00:00
|
|
|
if len(t.Nodes) != len(other.Nodes) {
|
2016-09-27 20:35:08 +00:00
|
|
|
debug.Log("tree.Equals(): trees have different number of nodes")
|
2015-01-04 21:39:30 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-01-10 22:40:10 +00:00
|
|
|
for i := 0; i < len(t.Nodes); i++ {
|
|
|
|
if !t.Nodes[i].Equals(*other.Nodes[i]) {
|
2016-09-27 20:35:08 +00:00
|
|
|
debug.Log("tree.Equals(): node %d is different:", i)
|
|
|
|
debug.Log(" %#v", t.Nodes[i])
|
|
|
|
debug.Log(" %#v", other.Nodes[i])
|
2015-01-10 22:40:10 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
2014-11-30 21:34:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-01 20:08:45 +00:00
|
|
|
// Insert adds a new node at the correct place in the tree.
|
2014-11-30 21:34:21 +00:00
|
|
|
func (t *Tree) Insert(node *Node) error {
|
2015-04-30 00:59:06 +00:00
|
|
|
pos, _, err := t.binarySearch(node.Name)
|
2014-11-30 21:34:21 +00:00
|
|
|
if err == nil {
|
2016-09-01 20:08:45 +00:00
|
|
|
return errors.New("node already present")
|
2014-11-30 21:34:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 13:44:54 +00:00
|
|
|
// https://code.google.com/p/go-wiki/wiki/SliceTricks
|
2015-01-10 22:40:10 +00:00
|
|
|
t.Nodes = append(t.Nodes, &Node{})
|
|
|
|
copy(t.Nodes[pos+1:], t.Nodes[pos:])
|
|
|
|
t.Nodes[pos] = node
|
2014-11-30 21:34:21 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-30 00:59:06 +00:00
|
|
|
func (t Tree) binarySearch(name string) (int, *Node, error) {
|
2015-01-10 22:40:10 +00:00
|
|
|
pos := sort.Search(len(t.Nodes), func(i int) bool {
|
|
|
|
return t.Nodes[i].Name >= name
|
2014-11-30 21:34:21 +00:00
|
|
|
})
|
|
|
|
|
2015-01-10 22:40:10 +00:00
|
|
|
if pos < len(t.Nodes) && t.Nodes[pos].Name == name {
|
|
|
|
return pos, t.Nodes[pos], nil
|
2014-11-30 21:34:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-01 20:08:45 +00:00
|
|
|
return pos, nil, errors.New("named node not found")
|
2014-11-30 21:34:21 +00:00
|
|
|
}
|
|
|
|
|
2015-07-12 14:42:22 +00:00
|
|
|
// Subtrees returns a slice of all subtree IDs of the tree.
|
2016-08-31 18:29:54 +00:00
|
|
|
func (t Tree) Subtrees() (trees IDs) {
|
2015-07-12 14:42:22 +00:00
|
|
|
for _, node := range t.Nodes {
|
2016-09-01 19:20:03 +00:00
|
|
|
if node.Type == "dir" && node.Subtree != nil {
|
2015-07-25 15:05:45 +00:00
|
|
|
trees = append(trees, *node.Subtree)
|
2015-07-12 14:42:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return trees
|
|
|
|
}
|