aboutsummaryrefslogtreecommitdiffstats
path: root/worktree_status.go
diff options
context:
space:
mode:
Diffstat (limited to 'worktree_status.go')
-rw-r--r--worktree_status.go114
1 files changed, 110 insertions, 4 deletions
diff --git a/worktree_status.go b/worktree_status.go
index 373f161..6becada 100644
--- a/worktree_status.go
+++ b/worktree_status.go
@@ -2,16 +2,20 @@ package git
import (
"bytes"
+ "io"
"gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/filemode"
+ "gopkg.in/src-d/go-git.v4/plumbing/format/index"
"gopkg.in/src-d/go-git.v4/plumbing/object"
+ "gopkg.in/src-d/go-git.v4/utils/ioutil"
"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"
+ mindex "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
+// Status returns the working tree status.
func (w *Worktree) Status() (Status, error) {
ref, err := w.r.Head()
if err == plumbing.ErrReferenceNotFound {
@@ -80,7 +84,7 @@ func (w *Worktree) diffStagingWithWorktree() (merkletrie.Changes, error) {
return nil, err
}
- from := index.NewRootNode(idx)
+ from := mindex.NewRootNode(idx)
submodules, err := w.getSubmodulesStatus()
if err != nil {
return nil, err
@@ -131,7 +135,7 @@ func (w *Worktree) diffCommitWithStaging(commit plumbing.Hash, reverse bool) (me
return nil, err
}
- to := index.NewRootNode(idx)
+ to := mindex.NewRootNode(idx)
from := object.NewTreeRootNode(t)
if reverse {
@@ -159,3 +163,105 @@ func diffTreeIsEquals(a, b noder.Hasher) bool {
return bytes.Equal(hashA, hashB)
}
+
+// Add adds the file contents of a file in the worktree to the index. if the
+// file is already stagged in the index no error is returned.
+func (w *Worktree) Add(path string) (plumbing.Hash, error) {
+ s, err := w.Status()
+ if err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ h, err := w.calculateBlobHash(path)
+ if err != nil {
+ return h, err
+ }
+
+ if s.File(path).Worktree == Unmodified {
+ return h, nil
+ }
+
+ if err := w.addOrUpdateFileToIndex(path, h); err != nil {
+ return h, err
+ }
+
+ return h, err
+}
+
+func (w *Worktree) calculateBlobHash(filename string) (hash plumbing.Hash, err error) {
+ fi, err := w.fs.Stat(filename)
+ if err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ f, err := w.fs.Open(filename)
+ if err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ defer ioutil.CheckClose(f, &err)
+
+ h := plumbing.NewHasher(plumbing.BlobObject, fi.Size())
+ if _, err := io.Copy(h, f); err != nil {
+ return plumbing.ZeroHash, err
+ }
+
+ hash = h.Sum()
+ return
+}
+
+func (w *Worktree) addOrUpdateFileToIndex(filename string, h plumbing.Hash) error {
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return err
+ }
+
+ _, err = idx.Entry(filename)
+ if err == index.ErrEntryNotFound {
+ err = w.doAddFileToIndex(idx, filename)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ err = w.doUpdateFileToIndex(idx, filename, h)
+ if err != nil {
+ return err
+ }
+
+ return w.r.Storer.SetIndex(idx)
+}
+
+func (w *Worktree) doAddFileToIndex(idx *index.Index, filename string) error {
+ idx.Entries = append(idx.Entries, index.Entry{
+ Name: filename,
+ })
+
+ return nil
+}
+
+func (w *Worktree) doUpdateFileToIndex(idx *index.Index, filename string, h plumbing.Hash) error {
+ info, err := w.fs.Stat(filename)
+ if err != nil {
+ return err
+ }
+
+ for i, e := range idx.Entries {
+ if e.Name != filename {
+ continue
+ }
+
+ e.Hash = h
+ e.ModifiedAt = info.ModTime()
+ e.Mode, err = filemode.NewFromOSFileMode(info.Mode())
+ if err != nil {
+ return err
+ }
+
+ fillSystemInfo(&e, info.Sys())
+ idx.Entries[i] = e
+ }
+
+ return nil
+}