aboutsummaryrefslogtreecommitdiffstats
path: root/utils/merkletrie/filesystem/node.go
blob: 847d71ef5cbb3065e605af457e4397a31f718ce1 (plain) (blame)
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
121
122
123
124
125
126
127
128
package filesystem

import (
	"bytes"
	"io"
	"os"
	"path/filepath"

	"gopkg.in/src-d/go-billy.v2"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/filemode"
	"gopkg.in/src-d/go-git.v4/utils/merkletrie/noder"
)

var ignore = map[string]bool{
	".git": true,
}

func IsEquals(a, b noder.Hasher) bool {
	pathA := a.(noder.Path)
	pathB := b.(noder.Path)
	if pathA[len(pathA)-1].IsDir() || pathB[len(pathB)-1].IsDir() {
		return false
	}

	return bytes.Equal(a.Hash(), b.Hash())
}

type Node struct {
	parent string
	name   string
	isDir  bool
	info   billy.FileInfo
	fs     billy.Filesystem
}

func NewRootNode(fs billy.Filesystem) (*Node, error) {
	info, err := fs.Stat("/")
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	return &Node{fs: fs, info: info, isDir: true, name: ""}, nil
}

func (n *Node) String() string {
	return filepath.Join(n.parent, n.name)
}

func (n *Node) Hash() []byte {
	if n.IsDir() {
		return nil
	}

	f, err := n.fs.Open(n.fullpath())
	if err != nil {
		panic(err)
	}

	h := plumbing.NewHasher(plumbing.BlobObject, n.info.Size())
	if _, err := io.Copy(h, f); err != nil {
		panic(err)
	}

	hash := h.Sum()
	mode, err := filemode.NewFromOSFileMode(n.info.Mode())
	if err != nil {
		panic(err)
	}

	return append(hash[:], mode.Bytes()...)
}

func (n *Node) Name() string {
	return n.name
}

func (n *Node) IsDir() bool {
	return n.isDir
}

func (n *Node) Children() ([]noder.Noder, error) {
	files, err := n.readDir()

	if err != nil {
		return nil, err
	}

	path := n.fullpath()
	var c []noder.Noder
	for _, file := range files {
		if _, ok := ignore[file.Name()]; ok {
			continue
		}

		c = append(c, &Node{
			fs:     n.fs,
			parent: path,
			info:   file,
			name:   file.Name(),
			isDir:  file.IsDir(),
		})
	}

	return c, nil
}

func (n *Node) NumChildren() (int, error) {
	files, err := n.readDir()
	return len(files), err
}

func (n *Node) fullpath() string {
	return filepath.Join(n.parent, n.name)
}

func (n *Node) readDir() ([]billy.FileInfo, error) {
	if !n.IsDir() {
		return nil, nil
	}

	l, err := n.fs.ReadDir(n.fullpath())
	if err != nil && os.IsNotExist(err) {
		return l, nil
	}

	return l, err
}