aboutsummaryrefslogblamecommitdiffstats
path: root/utils/merkletrie/filesystem/node.go
blob: 847d71ef5cbb3065e605af457e4397a31f718ce1 (plain) (tree)































































































































                                                                       
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
}