added goals; refactored to filetree
This commit is contained in:
parent
2a4e6b7bfd
commit
9350984354
11
README.md
11
README.md
@ -2,4 +2,13 @@
|
|||||||
```
|
```
|
||||||
docker build -t die-test:latest .
|
docker build -t die-test:latest .
|
||||||
go run main.go
|
go run main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
|
||||||
|
[x] Extract docker layers from api
|
||||||
|
[x] Represent layers as generic tree
|
||||||
|
[x] Stack ordere tree list together as fake unionfs tree
|
||||||
|
[ ] Diff trees
|
||||||
|
[ ] Add ui for browsing layers
|
||||||
|
[ ] Add ui for diffing stack to layer
|
||||||
|
136
filetree.go
136
filetree.go
@ -1,136 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FileTree interface {
|
|
||||||
AddPath(string, interface{}) *Node
|
|
||||||
RemovePath(string) error
|
|
||||||
Visit(Visiter) error
|
|
||||||
// Diff(*Tree) error
|
|
||||||
Stack(*Tree) (Tree, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Visiter func(*Node) error
|
|
||||||
|
|
||||||
func (tree *Tree) Visit(visiter Visiter) error {
|
|
||||||
return tree.root.Visit(visiter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *Node) Visit(visiter Visiter) error {
|
|
||||||
for _, child := range node.children {
|
|
||||||
err := child.Visit(visiter)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return visiter(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *Node) IsWhiteout() bool {
|
|
||||||
return strings.HasPrefix(node.name, ".wh.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (node *Node) Path() string {
|
|
||||||
path := []string{}
|
|
||||||
curNode := node
|
|
||||||
for {
|
|
||||||
if curNode.parent == nil{
|
|
||||||
break
|
|
||||||
}
|
|
||||||
path = append([]string{curNode.name}, path...)
|
|
||||||
curNode = curNode.parent
|
|
||||||
}
|
|
||||||
return "/" + strings.Join(path, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (node *Node) WhiteoutPath() string {
|
|
||||||
path := []string{}
|
|
||||||
curNode := node
|
|
||||||
for {
|
|
||||||
if curNode.parent == nil{
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
name := curNode.name
|
|
||||||
if curNode == node {
|
|
||||||
name = strings.TrimPrefix(name, ".wh.")
|
|
||||||
}
|
|
||||||
|
|
||||||
path = append([]string{name}, path...)
|
|
||||||
curNode = curNode.parent
|
|
||||||
}
|
|
||||||
return "/" + strings.Join(path, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (tree *Tree) Stack(upper *Tree) (error) {
|
|
||||||
graft := func(node *Node) error {
|
|
||||||
if node.IsWhiteout() {
|
|
||||||
err := tree.RemovePath(node.WhiteoutPath())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Cannot remove node %s: %v", node.Path(), err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newNode, err := tree.AddPath(node.Path(), node.data)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Cannot add node %s: %v", newNode.Path(), err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return upper.Visit(graft)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tree *Tree) GetNode(path string) (*Node, error) {
|
|
||||||
nodeNames := strings.Split(path, "/")
|
|
||||||
node := tree.Root()
|
|
||||||
for _, name := range nodeNames {
|
|
||||||
if name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if node.children[name] == nil {
|
|
||||||
return nil, errors.New("Path does not exist")
|
|
||||||
}
|
|
||||||
node = node.children[name]
|
|
||||||
}
|
|
||||||
return node, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tree *Tree) AddPath(path string, data interface{}) (*Node, error) {
|
|
||||||
nodeNames := strings.Split(path, "/")
|
|
||||||
node := tree.Root()
|
|
||||||
for idx, name := range nodeNames {
|
|
||||||
if name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// find or create node
|
|
||||||
if node.children[name] != nil {
|
|
||||||
node = node.children[name]
|
|
||||||
} else {
|
|
||||||
// don't attach the payload. The payload is destined for the
|
|
||||||
// path's end node, not any intermediary node.
|
|
||||||
node = node.AddChild(name, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach payload to the last specified node
|
|
||||||
if idx == len(nodeNames)-1 {
|
|
||||||
node.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return node, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tree *Tree) RemovePath(path string) error {
|
|
||||||
node, err := tree.GetNode(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return node.Remove()
|
|
||||||
}
|
|
141
filetree_test.go
141
filetree_test.go
@ -1,141 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestAddPath(t *testing.T) {
|
|
||||||
tree := NewTree()
|
|
||||||
tree.AddPath("/etc/nginx/nginx.conf", 1)
|
|
||||||
tree.AddPath("/etc/nginx/public", 2)
|
|
||||||
tree.AddPath("/var/run/systemd", 3)
|
|
||||||
tree.AddPath("/var/run/bashful", 4)
|
|
||||||
tree.AddPath("/tmp", 5)
|
|
||||||
tree.AddPath("/tmp/nonsense", 6)
|
|
||||||
|
|
||||||
expected := `.
|
|
||||||
├── etc
|
|
||||||
│ └── nginx
|
|
||||||
│ ├── nginx.conf
|
|
||||||
│ └── public
|
|
||||||
├── tmp
|
|
||||||
│ └── nonsense
|
|
||||||
└── var
|
|
||||||
└── run
|
|
||||||
├── bashful
|
|
||||||
└── systemd
|
|
||||||
`
|
|
||||||
actual := tree.String()
|
|
||||||
|
|
||||||
if expected != actual {
|
|
||||||
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemovePath(t *testing.T) {
|
|
||||||
tree := NewTree()
|
|
||||||
tree.AddPath("/etc/nginx/nginx.conf", 1)
|
|
||||||
tree.AddPath("/etc/nginx/public", 2)
|
|
||||||
tree.AddPath("/var/run/systemd", 3)
|
|
||||||
tree.AddPath("/var/run/bashful", 4)
|
|
||||||
tree.AddPath("/tmp", 5)
|
|
||||||
tree.AddPath("/tmp/nonsense", 6)
|
|
||||||
|
|
||||||
tree.RemovePath("/var/run/bashful")
|
|
||||||
tree.RemovePath("/tmp")
|
|
||||||
|
|
||||||
expected := `.
|
|
||||||
├── etc
|
|
||||||
│ └── nginx
|
|
||||||
│ ├── nginx.conf
|
|
||||||
│ └── public
|
|
||||||
└── var
|
|
||||||
└── run
|
|
||||||
└── systemd
|
|
||||||
`
|
|
||||||
actual := tree.String()
|
|
||||||
|
|
||||||
if expected != actual {
|
|
||||||
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPath(t *testing.T) {
|
|
||||||
expected := "/etc/nginx/nginx.conf"
|
|
||||||
tree := NewTree()
|
|
||||||
node, _ := tree.AddPath(expected, nil)
|
|
||||||
|
|
||||||
actual := node.Path()
|
|
||||||
if expected != actual {
|
|
||||||
t.Errorf("Expected path '%s' got '%s'", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsWhiteout(t *testing.T) {
|
|
||||||
tree1 := NewTree()
|
|
||||||
p1, _ := tree1.AddPath("/etc/nginx/public1", 2)
|
|
||||||
p2, _ := tree1.AddPath("/etc/nginx/.wh.public2", 2)
|
|
||||||
|
|
||||||
if p1.IsWhiteout() != false {
|
|
||||||
t.Errorf("Expected path '%s' to **not** be a whiteout file", p1.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p2.IsWhiteout() != true {
|
|
||||||
t.Errorf("Expected path '%s' to be a whiteout file", p2.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func TestStack(t *testing.T) {
|
|
||||||
payloadKey := "/var/run/systemd"
|
|
||||||
payloadValue := 1263487
|
|
||||||
|
|
||||||
tree1 := NewTree()
|
|
||||||
|
|
||||||
tree1.AddPath("/etc/nginx/public", 2)
|
|
||||||
tree1.AddPath(payloadKey, 3)
|
|
||||||
tree1.AddPath("/var/run/bashful", 4)
|
|
||||||
tree1.AddPath("/tmp", 5)
|
|
||||||
tree1.AddPath("/tmp/nonsense", 6)
|
|
||||||
|
|
||||||
tree2 := NewTree()
|
|
||||||
// add new files
|
|
||||||
tree2.AddPath("/etc/nginx/nginx.conf", 1)
|
|
||||||
// modify current files
|
|
||||||
tree2.AddPath(payloadKey, payloadValue)
|
|
||||||
// whiteout the following files
|
|
||||||
tree2.AddPath("/var/run/.wh.bashful", nil)
|
|
||||||
tree2.AddPath("/.wh.tmp", nil)
|
|
||||||
|
|
||||||
err := tree1.Stack(tree2)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Could not stack trees: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := `.
|
|
||||||
├── etc
|
|
||||||
│ └── nginx
|
|
||||||
│ ├── nginx.conf
|
|
||||||
│ └── public
|
|
||||||
└── var
|
|
||||||
└── run
|
|
||||||
└── systemd
|
|
||||||
`
|
|
||||||
|
|
||||||
node, err := tree1.GetNode(payloadKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected '%s' to still exist, but it doesn't", payloadKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.data != payloadValue {
|
|
||||||
t.Errorf("Expected '%s' value to be %d but got %d", payloadKey, payloadValue, node.data.(int))
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := tree1.String()
|
|
||||||
|
|
||||||
if expected != actual {
|
|
||||||
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -28,7 +28,7 @@ func main() {
|
|||||||
tarReader := tar.NewReader(f)
|
tarReader := tar.NewReader(f)
|
||||||
targetName := "manifest.json"
|
targetName := "manifest.json"
|
||||||
var m Manifest
|
var m Manifest
|
||||||
var trees []*Tree
|
var trees []*FileTree
|
||||||
for {
|
for {
|
||||||
header, err := tarReader.Next()
|
header, err := tarReader.Next()
|
||||||
|
|
||||||
|
146
tree.go
146
tree.go
@ -2,32 +2,45 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
newLine = "\n"
|
newLine = "\n"
|
||||||
emptySpace = " "
|
emptySpace = " "
|
||||||
middleItem = "├── "
|
middleItem = "├── "
|
||||||
continueItem = "│ "
|
continueItem = "│ "
|
||||||
lastItem = "└── "
|
lastItem = "└── "
|
||||||
|
whiteoutPrefix = ".wh."
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tree struct {
|
//type FileTree interface {
|
||||||
|
// AddPath(string, interface{}) *Node
|
||||||
|
// RemovePath(string) error
|
||||||
|
// Visit(Visiter) error
|
||||||
|
// // Diff(*FileTree) error
|
||||||
|
// Stack(*FileTree) (FileTree, error)
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
type FileTree struct {
|
||||||
root *Node
|
root *Node
|
||||||
size int
|
size int
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
tree *Tree
|
tree *FileTree
|
||||||
parent *Node
|
parent *Node
|
||||||
name string
|
name string
|
||||||
data interface{}
|
data interface{}
|
||||||
children map[string]*Node
|
children map[string]*Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTree() (tree *Tree) {
|
func NewTree() (tree *FileTree) {
|
||||||
tree = new(Tree)
|
tree = new(FileTree)
|
||||||
tree.size = 0
|
tree.size = 0
|
||||||
tree.root = new(Node)
|
tree.root = new(Node)
|
||||||
tree.root.tree = tree
|
tree.root.tree = tree
|
||||||
@ -45,7 +58,7 @@ func NewNode(parent *Node, name string, data interface{}) (node *Node) {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tree *Tree) Root() *Node {
|
func (tree *FileTree) Root() *Node {
|
||||||
return tree.root
|
return tree.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +87,7 @@ func (node *Node) String() string {
|
|||||||
return node.name
|
return node.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tree *Tree) String() string {
|
func (tree *FileTree) String() string {
|
||||||
var renderLine func(string, []bool, bool) string
|
var renderLine func(string, []bool, bool) string
|
||||||
var walkTree func(*Node, []bool) string
|
var walkTree func(*Node, []bool) string
|
||||||
|
|
||||||
@ -129,7 +142,7 @@ func (node *Node) Copy() *Node {
|
|||||||
return newNode
|
return newNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tree *Tree) Copy() *Tree {
|
func (tree *FileTree) Copy() *FileTree {
|
||||||
newTree := NewTree()
|
newTree := NewTree()
|
||||||
*newTree = *tree
|
*newTree = *tree
|
||||||
newTree.root = tree.Root().Copy()
|
newTree.root = tree.Root().Copy()
|
||||||
@ -137,3 +150,112 @@ func (tree *Tree) Copy() *Tree {
|
|||||||
return newTree
|
return newTree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Visiter func(*Node) error
|
||||||
|
|
||||||
|
func (tree *FileTree) Visit(visiter Visiter) error {
|
||||||
|
return tree.root.Visit(visiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) Visit(visiter Visiter) error {
|
||||||
|
for _, child := range node.children {
|
||||||
|
err := child.Visit(visiter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visiter(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) IsWhiteout() bool {
|
||||||
|
return strings.HasPrefix(node.name, whiteoutPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node) Path() string {
|
||||||
|
path := []string{}
|
||||||
|
curNode := node
|
||||||
|
for {
|
||||||
|
if curNode.parent == nil{
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
name := curNode.name
|
||||||
|
if curNode == node {
|
||||||
|
// white out prefixes are fictitious on leaf nodes
|
||||||
|
name = strings.TrimPrefix(name, whiteoutPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
path = append([]string{name}, path...)
|
||||||
|
curNode = curNode.parent
|
||||||
|
}
|
||||||
|
return "/" + strings.Join(path, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func (tree *FileTree) Stack(upper *FileTree) (error) {
|
||||||
|
graft := func(node *Node) error {
|
||||||
|
if node.IsWhiteout() {
|
||||||
|
err := tree.RemovePath(node.Path())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot remove node %s: %v", node.Path(), err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newNode, err := tree.AddPath(node.Path(), node.data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot add node %s: %v", newNode.Path(), err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return upper.Visit(graft)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tree *FileTree) GetNode(path string) (*Node, error) {
|
||||||
|
nodeNames := strings.Split(path, "/")
|
||||||
|
node := tree.Root()
|
||||||
|
for _, name := range nodeNames {
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if node.children[name] == nil {
|
||||||
|
return nil, errors.New("Path does not exist")
|
||||||
|
}
|
||||||
|
node = node.children[name]
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tree *FileTree) AddPath(path string, data interface{}) (*Node, error) {
|
||||||
|
nodeNames := strings.Split(path, "/")
|
||||||
|
node := tree.Root()
|
||||||
|
for idx, name := range nodeNames {
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// find or create node
|
||||||
|
if node.children[name] != nil {
|
||||||
|
node = node.children[name]
|
||||||
|
} else {
|
||||||
|
// don't attach the payload. The payload is destined for the
|
||||||
|
// path's end node, not any intermediary node.
|
||||||
|
node = node.AddChild(name, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach payload to the last specified node
|
||||||
|
if idx == len(nodeNames)-1 {
|
||||||
|
node.data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tree *FileTree) RemovePath(path string) error {
|
||||||
|
node, err := tree.GetNode(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return node.Remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
139
tree_test.go
139
tree_test.go
@ -95,3 +95,142 @@ func TestPrintTree(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestAddPath(t *testing.T) {
|
||||||
|
tree := NewTree()
|
||||||
|
tree.AddPath("/etc/nginx/nginx.conf", 1)
|
||||||
|
tree.AddPath("/etc/nginx/public", 2)
|
||||||
|
tree.AddPath("/var/run/systemd", 3)
|
||||||
|
tree.AddPath("/var/run/bashful", 4)
|
||||||
|
tree.AddPath("/tmp", 5)
|
||||||
|
tree.AddPath("/tmp/nonsense", 6)
|
||||||
|
|
||||||
|
expected := `.
|
||||||
|
├── etc
|
||||||
|
│ └── nginx
|
||||||
|
│ ├── nginx.conf
|
||||||
|
│ └── public
|
||||||
|
├── tmp
|
||||||
|
│ └── nonsense
|
||||||
|
└── var
|
||||||
|
└── run
|
||||||
|
├── bashful
|
||||||
|
└── systemd
|
||||||
|
`
|
||||||
|
actual := tree.String()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemovePath(t *testing.T) {
|
||||||
|
tree := NewTree()
|
||||||
|
tree.AddPath("/etc/nginx/nginx.conf", 1)
|
||||||
|
tree.AddPath("/etc/nginx/public", 2)
|
||||||
|
tree.AddPath("/var/run/systemd", 3)
|
||||||
|
tree.AddPath("/var/run/bashful", 4)
|
||||||
|
tree.AddPath("/tmp", 5)
|
||||||
|
tree.AddPath("/tmp/nonsense", 6)
|
||||||
|
|
||||||
|
tree.RemovePath("/var/run/bashful")
|
||||||
|
tree.RemovePath("/tmp")
|
||||||
|
|
||||||
|
expected := `.
|
||||||
|
├── etc
|
||||||
|
│ └── nginx
|
||||||
|
│ ├── nginx.conf
|
||||||
|
│ └── public
|
||||||
|
└── var
|
||||||
|
└── run
|
||||||
|
└── systemd
|
||||||
|
`
|
||||||
|
actual := tree.String()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPath(t *testing.T) {
|
||||||
|
expected := "/etc/nginx/nginx.conf"
|
||||||
|
tree := NewTree()
|
||||||
|
node, _ := tree.AddPath(expected, nil)
|
||||||
|
|
||||||
|
actual := node.Path()
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("Expected path '%s' got '%s'", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsWhiteout(t *testing.T) {
|
||||||
|
tree1 := NewTree()
|
||||||
|
p1, _ := tree1.AddPath("/etc/nginx/public1", 2)
|
||||||
|
p2, _ := tree1.AddPath("/etc/nginx/.wh.public2", 2)
|
||||||
|
|
||||||
|
if p1.IsWhiteout() != false {
|
||||||
|
t.Errorf("Expected path '%s' to **not** be a whiteout file", p1.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p2.IsWhiteout() != true {
|
||||||
|
t.Errorf("Expected path '%s' to be a whiteout file", p2.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestStack(t *testing.T) {
|
||||||
|
payloadKey := "/var/run/systemd"
|
||||||
|
payloadValue := 1263487
|
||||||
|
|
||||||
|
tree1 := NewTree()
|
||||||
|
|
||||||
|
tree1.AddPath("/etc/nginx/public", 2)
|
||||||
|
tree1.AddPath(payloadKey, 3)
|
||||||
|
tree1.AddPath("/var/run/bashful", 4)
|
||||||
|
tree1.AddPath("/tmp", 5)
|
||||||
|
tree1.AddPath("/tmp/nonsense", 6)
|
||||||
|
|
||||||
|
tree2 := NewTree()
|
||||||
|
// add new files
|
||||||
|
tree2.AddPath("/etc/nginx/nginx.conf", 1)
|
||||||
|
// modify current files
|
||||||
|
tree2.AddPath(payloadKey, payloadValue)
|
||||||
|
// whiteout the following files
|
||||||
|
tree2.AddPath("/var/run/.wh.bashful", nil)
|
||||||
|
tree2.AddPath("/.wh.tmp", nil)
|
||||||
|
|
||||||
|
err := tree1.Stack(tree2)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Could not stack trees: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `.
|
||||||
|
├── etc
|
||||||
|
│ └── nginx
|
||||||
|
│ ├── nginx.conf
|
||||||
|
│ └── public
|
||||||
|
└── var
|
||||||
|
└── run
|
||||||
|
└── systemd
|
||||||
|
`
|
||||||
|
|
||||||
|
node, err := tree1.GetNode(payloadKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected '%s' to still exist, but it doesn't", payloadKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.data != payloadValue {
|
||||||
|
t.Errorf("Expected '%s' value to be %d but got %d", payloadKey, payloadValue, node.data.(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := tree1.String()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user