package git
import (
"bytes"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/utils/merkletrie"
"gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem"
"gopkg.in/src-d/go-git.v4/utils/merkletrie/index"
"gopkg.in/src-d/go-git.v4/utils/merkletrie/noder"
)
// Status returns the working tree status
func (w *Worktree) Status() (Status, error) {
ref, err := w.r.Head()
if err == plumbing.ErrReferenceNotFound {
return nil, nil
}
if err != nil {
return nil, err
}
return w.status(ref.Hash())
}
func (w *Worktree) status(commit plumbing.Hash) (Status, error) {
s := make(Status, 0)
right, err := w.diffStagingWithWorktree()
if err != nil {
return nil, err
}
for _, ch := range right {
a, err := ch.Action()
if err != nil {
return nil, err
}
switch a {
case merkletrie.Delete:
s.File(ch.From.String()).Worktree = Deleted
case merkletrie.Insert:
s.File(ch.To.String()).Worktree = Untracked
s.File(ch.To.String()).Staging = Untracked
case merkletrie.Modify:
s.File(ch.To.String()).Worktree = Modified
}
}
left, err := w.diffCommitWithStaging(commit, false)
if err != nil {
return nil, err
}
for _, ch := range left {
a, err := ch.Action()
if err != nil {
return nil, err
}
switch a {
case merkletrie.Delete:
s.File(ch.From.String()).Staging = Deleted
case merkletrie.Insert:
s.File(ch.To.String()).Staging = Added
case merkletrie.Modify:
s.File(ch.To.String()).Staging = Modified
}
}
return s, nil
}
func (w *Worktree) diffStagingWithWorktree() (merkletrie.Changes, error) {
idx, err := w.r.Storer.Index()
if err != nil {
return nil, err
}
from, err := index.NewRootNode(idx)
if err != nil {
return nil, err
}
to, err := filesystem.NewRootNode(w.fs)
if err != nil {
return nil, err
}
return merkletrie.DiffTree(from, to, IsEquals)
}
func (w *Worktree) diffCommitWithStaging(commit plumbing.Hash, reverse bool) (merkletrie.Changes, error) {
idx, err := w.r.Storer.Index()
if err != nil {
return nil, err
}
to, err := index.NewRootNode(idx)
if err != nil {
return nil, err
}
c, err := w.r.CommitObject(commit)
if err != nil {
return nil, err
}
t, err := c.Tree()
if err != nil {
return nil, err
}
from := object.NewTreeRootNode(t)
if reverse {
return merkletrie.DiffTree(to, from, IsEquals)
}
return merkletrie.DiffTree(from, to, IsEquals)
}
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())
}