Skip to content

Commit

Permalink
worktree: Add create and push the blob objects to the storer
Browse files Browse the repository at this point in the history
Signed-off-by: Máximo Cuadros <[email protected]>
  • Loading branch information
mcuadros committed Jun 19, 2017
1 parent ad74323 commit 85a9126
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 115 deletions.
108 changes: 12 additions & 96 deletions worktree_commit.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package git

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

Expand All @@ -11,7 +9,6 @@ import (
"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/storage"
"gopkg.in/src-d/go-git.v4/utils/ioutil"

"gopkg.in/src-d/go-billy.v3"
)
Expand All @@ -34,12 +31,12 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error
return plumbing.ZeroHash, err
}

h := &commitIndexHelper{
h := &buildTreeHelper{
fs: w.fs,
s: w.r.Storer,
}

tree, err := h.buildTreeAndBlobObjects(idx)
tree, err := h.BuildTree(idx)
if err != nil {
return plumbing.ZeroHash, err
}
Expand Down Expand Up @@ -103,20 +100,20 @@ func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumb
return w.r.Storer.SetEncodedObject(obj)
}

// commitIndexHelper converts a given index.Index file into multiple git objects
// buildTreeHelper converts a given index.Index file into multiple git objects
// reading the blobs from the given filesystem and creating the trees from the
// index structure. The created objects are pushed to a given Storer.
type commitIndexHelper struct {
type buildTreeHelper struct {
fs billy.Filesystem
s storage.Storer

trees map[string]*object.Tree
entries map[string]*object.TreeEntry
}

// buildTreesAndBlobs builds the objects and push its to the storer, the hash
// BuildTree builds the tree objects and push its to the storer, the hash
// of the root tree is returned.
func (h *commitIndexHelper) buildTreeAndBlobObjects(idx *index.Index) (plumbing.Hash, error) {
func (h *buildTreeHelper) BuildTree(idx *index.Index) (plumbing.Hash, error) {
const rootNode = ""
h.trees = map[string]*object.Tree{rootNode: {}}
h.entries = map[string]*object.TreeEntry{}
Expand All @@ -130,33 +127,27 @@ func (h *commitIndexHelper) buildTreeAndBlobObjects(idx *index.Index) (plumbing.
return h.copyTreeToStorageRecursive(rootNode, h.trees[rootNode])
}

func (h *commitIndexHelper) commitIndexEntry(e *index.Entry) error {
func (h *buildTreeHelper) commitIndexEntry(e *index.Entry) error {
parts := strings.Split(e.Name, string(filepath.Separator))

var path string
for _, part := range parts {
parent := path
path = filepath.Join(path, part)

if !h.buildTree(e, parent, path) {
continue
}

if err := h.copyIndexEntryToStorage(e); err != nil {
return err
}
h.doBuildTree(e, parent, path)
}

return nil
}

func (h *commitIndexHelper) buildTree(e *index.Entry, parent, path string) bool {
func (h *buildTreeHelper) doBuildTree(e *index.Entry, parent, path string) {
if _, ok := h.trees[path]; ok {
return false
return
}

if _, ok := h.entries[path]; ok {
return false
return
}

te := object.TreeEntry{Name: filepath.Base(path)}
Expand All @@ -170,84 +161,9 @@ func (h *commitIndexHelper) buildTree(e *index.Entry, parent, path string) bool
}

h.trees[parent].Entries = append(h.trees[parent].Entries, te)
return true
}

func (h *commitIndexHelper) copyIndexEntryToStorage(e *index.Entry) error {
_, err := h.s.EncodedObject(plumbing.BlobObject, e.Hash)
if err == nil {
return nil
}

if err != plumbing.ErrObjectNotFound {
return err
}

return h.doCopyIndexEntryToStorage(e)
}

func (h *commitIndexHelper) doCopyIndexEntryToStorage(e *index.Entry) (err error) {
fi, err := h.fs.Lstat(e.Name)
if err != nil {
return err
}

if fi.Mode()&os.ModeSymlink != 0 {
return h.doCopyIndexEntryFromSymlinkToStorage(e, fi)
}

obj := h.s.NewEncodedObject()
obj.SetType(plumbing.BlobObject)
obj.SetSize(fi.Size())

reader, err := h.fs.Open(e.Name)
if err != nil {
return err
}

defer ioutil.CheckClose(reader, &err)

writer, err := obj.Writer()
if err != nil {
return err
}

defer ioutil.CheckClose(writer, &err)

if _, err := io.Copy(writer, reader); err != nil {
return err
}

_, err = h.s.SetEncodedObject(obj)
return err
}

func (h *commitIndexHelper) doCopyIndexEntryFromSymlinkToStorage(e *index.Entry, fi os.FileInfo) error {
obj := h.s.NewEncodedObject()
obj.SetType(plumbing.BlobObject)
obj.SetSize(fi.Size())

writer, err := obj.Writer()
if err != nil {
return err
}

defer ioutil.CheckClose(writer, &err)

target, err := h.fs.Readlink(e.Name)
if err != nil {
return err
}

if _, err := writer.Write([]byte(target)); err != nil {
return err
}

_, err = h.s.SetEncodedObject(obj)
return err
}

func (h *commitIndexHelper) copyTreeToStorageRecursive(parent string, t *object.Tree) (plumbing.Hash, error) {
func (h *buildTreeHelper) copyTreeToStorageRecursive(parent string, t *object.Tree) (plumbing.Hash, error) {
for i, e := range t.Entries {
if e.Mode != filemode.Dir && !e.Hash.IsZero() {
continue
Expand Down
52 changes: 33 additions & 19 deletions worktree_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (w *Worktree) Add(path string) (plumbing.Hash, error) {
return plumbing.ZeroHash, err
}

h, err := w.calculateBlobHash(path)
h, err := w.copyFileToStorage(path)
if err != nil {
return h, err
}
Expand All @@ -243,45 +243,59 @@ func (w *Worktree) Add(path string) (plumbing.Hash, error) {
return h, err
}

func (w *Worktree) calculateBlobHash(filename string) (hash plumbing.Hash, err error) {
fi, err := w.fs.Lstat(filename)
func (w *Worktree) copyFileToStorage(path string) (hash plumbing.Hash, err error) {
fi, err := w.fs.Lstat(path)
if err != nil {
return plumbing.ZeroHash, err
}

if fi.Mode()&os.ModeSymlink != 0 {
return w.calculateBlobHashFromSymlink(filename)
}
obj := w.r.Storer.NewEncodedObject()
obj.SetType(plumbing.BlobObject)
obj.SetSize(fi.Size())

f, err := w.fs.Open(filename)
writer, err := obj.Writer()
if err != nil {
return plumbing.ZeroHash, err
}

defer ioutil.CheckClose(f, &err)
defer ioutil.CheckClose(writer, &err)

if fi.Mode()&os.ModeSymlink != 0 {
err = w.fillEncodedObjectFromSymlink(writer, path, fi)
} else {
err = w.fillEncodedObjectFromFile(writer, path, fi)
}

h := plumbing.NewHasher(plumbing.BlobObject, fi.Size())
if _, err := io.Copy(h, f); err != nil {
if err != nil {
return plumbing.ZeroHash, err
}

hash = h.Sum()
return
return w.r.Storer.SetEncodedObject(obj)
}

func (w *Worktree) calculateBlobHashFromSymlink(link string) (plumbing.Hash, error) {
target, err := w.fs.Readlink(link)
func (w *Worktree) fillEncodedObjectFromFile(dst io.Writer, path string, fi os.FileInfo) (err error) {
src, err := w.fs.Open(path)
if err != nil {
return plumbing.ZeroHash, err
return err
}

h := plumbing.NewHasher(plumbing.BlobObject, int64(len(target)))
_, err = h.Write([]byte(target))
defer ioutil.CheckClose(src, &err)

if _, err := io.Copy(dst, src); err != nil {
return err
}

return err
}

func (w *Worktree) fillEncodedObjectFromSymlink(dst io.Writer, path string, fi os.FileInfo) error {
target, err := w.fs.Readlink(path)
if err != nil {
return plumbing.ZeroHash, err
return err
}

return h.Sum(), nil
_, err = dst.Write([]byte(target))
return err
}

func (w *Worktree) addOrUpdateFileToIndex(filename string, h plumbing.Hash) error {
Expand Down
11 changes: 11 additions & 0 deletions worktree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,11 @@ func (s *WorktreeSuite) TestAddUntracked(c *C) {
file := status.File("foo")
c.Assert(file.Staging, Equals, Added)
c.Assert(file.Worktree, Equals, Unmodified)

obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, hash)
c.Assert(err, IsNil)
c.Assert(obj, NotNil)
c.Assert(obj.Size(), Equals, int64(3))
}

func (s *WorktreeSuite) TestAddModified(c *C) {
Expand Down Expand Up @@ -690,6 +695,12 @@ func (s *WorktreeSuite) TestAddSymlink(c *C) {
h, err = w.Add("bar")
c.Assert(err, IsNil)
c.Assert(h, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"))

obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, h)
c.Assert(err, IsNil)
c.Assert(obj, NotNil)
c.Assert(obj.Size(), Equals, int64(3))

}

func (s *WorktreeSuite) TestRemove(c *C) {
Expand Down

0 comments on commit 85a9126

Please sign in to comment.