aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2016-08-30 15:29:31 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2016-08-30 15:29:31 +0200
commit60636dd029a1e356bab8698b798504302fe645cb (patch)
tree49cfa335c09bb727d1954132075960562951a2aa
parent2c527d02ceac3879f82ab53645b6c7c03c0e5d71 (diff)
downloadgo-git-60636dd029a1e356bab8698b798504302fe645cb.tar.gz
DiffTree based on TreeWalker
-rw-r--r--cshared/tree_cshared.go14
-rw-r--r--file.go5
-rw-r--r--tree.go2
-rw-r--r--tree_diff.go100
-rw-r--r--tree_diff_test.go146
5 files changed, 190 insertions, 77 deletions
diff --git a/cshared/tree_cshared.go b/cshared/tree_cshared.go
index 3884817..ddaf0f1 100644
--- a/cshared/tree_cshared.go
+++ b/cshared/tree_cshared.go
@@ -106,20 +106,18 @@ func c_NewTreeWalker(r uint64, t uint64) uint64 {
}
//export c_TreeWalker_Next
-func c_TreeWalker_Next(tw uint64) (*C.char, *C.char, uint32, *C.char,
- uint64, int, *C.char) {
+func c_TreeWalker_Next(tw uint64) (*C.char, *C.char, uint32, *C.char, int, *C.char) {
obj, ok := GetObject(Handle(tw))
if !ok {
- return nil, nil, 0, nil, IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ return nil, nil, 0, nil, ErrorCodeNotFound, C.CString(MessageNotFound)
}
walker := obj.(*git.TreeWalker)
- name, entry, object, err := walker.Next()
+ name, entry, err := walker.Next()
if err != nil {
- return nil, nil, 0, nil, IH, ErrorCodeInternal, C.CString(err.Error())
+ return nil, nil, 0, nil, ErrorCodeInternal, C.CString(err.Error())
}
return C.CString(name), C.CString(entry.Name), uint32(entry.Mode),
- CBytes(entry.Hash[:]), uint64(RegisterObject(&object)),
- ErrorCodeSuccess, nil
+ CBytes(entry.Hash[:]), ErrorCodeSuccess, nil
}
//export c_TreeWalker_Tree
@@ -140,4 +138,4 @@ func c_TreeWalker_Close(tw uint64) {
}
walker := obj.(*git.TreeWalker)
walker.Close()
-} \ No newline at end of file
+}
diff --git a/file.go b/file.go
index e18caaf..9180528 100644
--- a/file.go
+++ b/file.go
@@ -16,7 +16,8 @@ type File struct {
Blob
}
-func newFile(name string, m os.FileMode, b *Blob) *File {
+// NewFile returns a File based on the given blob object
+func NewFile(name string, m os.FileMode, b *Blob) *File {
return &File{Name: name, Mode: m, Blob: *b}
}
@@ -77,7 +78,7 @@ func (iter *FileIter) Next() (*File, error) {
return nil, err
}
- return newFile(name, entry.Mode, blob), nil
+ return NewFile(name, entry.Mode, blob), nil
}
}
diff --git a/tree.go b/tree.go
index eaa0c15..462589d 100644
--- a/tree.go
+++ b/tree.go
@@ -62,7 +62,7 @@ func (t *Tree) File(path string) (*File, error) {
blob := &Blob{}
blob.Decode(obj)
- return newFile(path, e.Mode, blob), nil
+ return NewFile(path, e.Mode, blob), nil
}
func (t *Tree) findEntry(path string) (*TreeEntry, error) {
diff --git a/tree_diff.go b/tree_diff.go
index bad2230..1c613bd 100644
--- a/tree_diff.go
+++ b/tree_diff.go
@@ -33,12 +33,54 @@ const (
type Change struct {
Action
- Name string
- Files [2]*File
+ From ChangeEntry
+ To ChangeEntry
+}
+
+type ChangeEntry struct {
+ Name string
+ Tree *Tree
+ TreeEntry TreeEntry
+}
+
+func (c *Change) Files() (from *File, to *File, err error) {
+ if c.Action == Insert || c.Action == Modify {
+ to, err = newFileFromTreeEntry(c.To.Tree, &c.To.TreeEntry)
+ if err != nil {
+ return
+ }
+
+ }
+
+ if c.Action == Delete || c.Action == Modify {
+ from, err = newFileFromTreeEntry(c.From.Tree, &c.From.TreeEntry)
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func newFileFromTreeEntry(t *Tree, e *TreeEntry) (*File, error) {
+ blob, err := t.r.Blob(e.Hash)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFile(e.Name, e.Mode, blob), nil
}
func (c *Change) String() string {
- return fmt.Sprintf("<Action: %s, Path: %s>", c.Action, c.Name)
+ return fmt.Sprintf("<Action: %s, Path: %s>", c.Action, c.name())
+}
+
+func (c *Change) name() string {
+ if c.From.Name != "" {
+ return c.From.Name
+ }
+
+ return c.To.Name
}
type Changes []*Change
@@ -68,7 +110,7 @@ func (c Changes) Swap(i, j int) {
}
func (c Changes) Less(i, j int) bool {
- return strings.Compare(c[i].Name, c[j].Name) < 0
+ return strings.Compare(c[i].name(), c[j].name()) < 0
}
func (c Changes) String() string {
@@ -98,29 +140,34 @@ func newWithEmpty(a, b *Tree) (Changes, error) {
tree = a
}
- iter := tree.Files()
- defer iter.Close()
+ w := NewTreeWalker(tree.r, tree)
+ defer w.Close()
for {
- file, err := iter.Next()
+ path, entry, err := w.Next()
if err == io.EOF {
break
} else if err != nil {
return nil, fmt.Errorf("cannot get next file: %s", err)
}
- var files [2]*File
+ if entry.Mode.IsDir() {
+ continue
+ }
+
+ c := &Change{Action: action}
+
if action == Insert {
- files[1] = file
+ c.To.Name = path
+ c.To.TreeEntry = entry
+ c.To.Tree = tree
} else {
- files[0] = file
+ c.From.Name = path
+ c.From.TreeEntry = entry
+ c.From.Tree = tree
}
- changes = append(changes, &Change{
- Action: action,
- Name: file.Name,
- Files: files,
- })
+ changes = append(changes, c)
}
return changes, nil
@@ -146,19 +193,16 @@ func newDiffTree(a, b *Tree) ([]*Change, error) {
sort.Sort(bChanges)
for len(aChanges) > 0 && len(bChanges) > 0 {
- switch comp := strings.Compare(aChanges[0].Name, bChanges[0].Name); {
+ switch comp := strings.Compare(aChanges[0].name(), bChanges[0].name()); {
case comp == 0: // append as "Modify" or ignore if not changed
- modified, err := hasChange(a, b, aChanges[0].Name)
+ modified, err := hasChange(a, b, aChanges[0].name())
if err != nil {
return nil, err
}
if modified {
- result = append(result, &Change{
- Action: Modify,
- Name: aChanges[0].Name,
- Files: [2]*File{aChanges[0].Files[0], bChanges[0].Files[1]},
- })
+ c := mergeInsertAndDeleteIntoModify(aChanges[0], bChanges[0])
+ result = append(result, c)
}
aChanges = aChanges[1:]
@@ -180,6 +224,18 @@ func newDiffTree(a, b *Tree) ([]*Change, error) {
return result, nil
}
+func mergeInsertAndDeleteIntoModify(a, b *Change) *Change {
+ c := &Change{Action: Modify}
+ c.From.Name = a.From.Name
+ c.From.Tree = a.From.Tree
+ c.From.TreeEntry = a.From.TreeEntry
+ c.To.Name = b.To.Name
+ c.To.Tree = b.To.Tree
+ c.To.TreeEntry = b.To.TreeEntry
+
+ return c
+}
+
func hasChange(a, b *Tree, path string) (bool, error) {
ha, err := hash(a, path)
if err != nil {
diff --git a/tree_diff_test.go b/tree_diff_test.go
index 7733c90..b7efaa1 100644
--- a/tree_diff_test.go
+++ b/tree_diff_test.go
@@ -11,12 +11,16 @@ import (
)
type DiffTreeSuite struct {
+ BaseSuite
+
repos map[string]*Repository
}
var _ = Suite(&DiffTreeSuite{})
func (s *DiffTreeSuite) SetUpSuite(c *C) {
+ s.BaseSuite.SetUpSuite(c)
+
fixtureRepos := [...]struct {
url string
packfile string
@@ -74,12 +78,58 @@ func (s *DiffTreeSuite) TestActionString(c *C) {
PanicMatches, "unsupported action: 37")
}
+func (s *DiffTreeSuite) TestChangeFilesInsert(c *C) {
+ tree, err := s.Repository.Tree(core.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c"))
+ c.Assert(err, IsNil)
+
+ change := &Change{Action: Insert}
+ change.To.Name = "json/long.json"
+ change.To.Tree = tree
+ change.To.TreeEntry.Hash = core.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9")
+
+ from, to, err := change.Files()
+ c.Assert(err, IsNil)
+ c.Assert(from, IsNil)
+ c.Assert(to.ID(), Equals, change.To.TreeEntry.Hash)
+}
+
+func (s *DiffTreeSuite) TestChangeFilesDelete(c *C) {
+ tree, err := s.Repository.Tree(core.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c"))
+ c.Assert(err, IsNil)
+
+ change := &Change{Action: Delete}
+ change.From.Name = "json/long.json"
+ change.From.Tree = tree
+ change.From.TreeEntry.Hash = core.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9")
+
+ from, to, err := change.Files()
+ c.Assert(err, IsNil)
+ c.Assert(to, IsNil)
+ c.Assert(from.ID(), Equals, change.From.TreeEntry.Hash)
+}
+
+func (s *DiffTreeSuite) TestChangeFilesModify(c *C) {
+ tree, err := s.Repository.Tree(core.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c"))
+ c.Assert(err, IsNil)
+
+ change := &Change{Action: Modify}
+ change.To.Name = "json/long.json"
+ change.To.Tree = tree
+ change.To.TreeEntry.Hash = core.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9")
+ change.From.Name = "json/long.json"
+ change.From.Tree = tree
+ change.From.TreeEntry.Hash = core.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492")
+
+ from, to, err := change.Files()
+ c.Assert(err, IsNil)
+ c.Assert(to.ID(), Equals, change.To.TreeEntry.Hash)
+ c.Assert(from.ID(), Equals, change.From.TreeEntry.Hash)
+}
+
func (s *DiffTreeSuite) TestChangeString(c *C) {
expected := "<Action: Insert, Path: foo>"
- change := &Change{
- Action: Insert,
- Name: "foo",
- }
+ change := &Change{Action: Insert}
+ change.From.Name = "foo"
obtained := change.String()
c.Assert(obtained, Equals, expected)
@@ -93,42 +143,51 @@ func (s *DiffTreeSuite) TestChangesString(c *C) {
expected = "[<Action: Modify, Path: bla>]"
changes = make([]*Change, 1)
- changes[0] = &Change{Action: Modify, Name: "bla"}
+ changes[0] = &Change{Action: Modify}
+ changes[0].From.Name = "bla"
+
obtained = changes.String()
c.Assert(obtained, Equals, expected)
expected = "[<Action: Modify, Path: bla>, <Action: Insert, Path: foo/bar>]"
changes = make([]*Change, 2)
- changes[0] = &Change{Action: Modify, Name: "bla"}
- changes[1] = &Change{Action: Insert, Name: "foo/bar"}
+ changes[0] = &Change{Action: Modify}
+ changes[0].From.Name = "bla"
+ changes[1] = &Change{Action: Insert}
+ changes[1].From.Name = "foo/bar"
obtained = changes.String()
c.Assert(obtained, Equals, expected)
}
+type expectChange struct {
+ Action Action
+ Name string
+}
+
func (s *DiffTreeSuite) TestDiffTree(c *C) {
for i, t := range []struct {
- repo string // the repo name as in localRepos
- commit1 string // the commit of the first tree
- commit2 string // the commit of the second tree
- expected Changes // the expected list of changes
+ repo string // the repo name as in localRepos
+ commit1 string // the commit of the first tree
+ commit2 string // the commit of the second tree
+ expected []expectChange // the expected list of []changeExpect
}{
{
"git://github.com/dezfowler/LiteMock.git",
"",
"",
- Changes{},
+ []expectChange{},
},
{
"git://github.com/dezfowler/LiteMock.git",
"b7965eaa2c4f245d07191fe0bcfe86da032d672a",
"b7965eaa2c4f245d07191fe0bcfe86da032d672a",
- Changes{},
+ []expectChange{},
},
{
"git://github.com/dezfowler/LiteMock.git",
"",
"b7965eaa2c4f245d07191fe0bcfe86da032d672a",
- Changes{
+ []expectChange{
{Action: Insert, Name: "README"},
},
},
@@ -136,7 +195,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/dezfowler/LiteMock.git",
"b7965eaa2c4f245d07191fe0bcfe86da032d672a",
"",
- Changes{
+ []expectChange{
{Action: Delete, Name: "README"},
},
},
@@ -144,7 +203,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/githubtraining/example-branches.git",
"",
"f0eb272cc8f77803478c6748103a1450aa1abd37",
- Changes{
+ []expectChange{
{Action: Insert, Name: "README.md"},
},
},
@@ -152,7 +211,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/githubtraining/example-branches.git",
"f0eb272cc8f77803478c6748103a1450aa1abd37",
"",
- Changes{
+ []expectChange{
{Action: Delete, Name: "README.md"},
},
},
@@ -160,13 +219,13 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/githubtraining/example-branches.git",
"f0eb272cc8f77803478c6748103a1450aa1abd37",
"f0eb272cc8f77803478c6748103a1450aa1abd37",
- Changes{},
+ []expectChange{},
},
{
"git://github.com/github/gem-builder.git",
"",
"9608eed92b3839b06ebf72d5043da547de10ce85",
- Changes{
+ []expectChange{
{Action: Insert, Name: "README"},
{Action: Insert, Name: "gem_builder.rb"},
{Action: Insert, Name: "gem_eval.rb"},
@@ -176,7 +235,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"9608eed92b3839b06ebf72d5043da547de10ce85",
"",
- Changes{
+ []expectChange{
{Action: Delete, Name: "README"},
{Action: Delete, Name: "gem_builder.rb"},
{Action: Delete, Name: "gem_eval.rb"},
@@ -186,17 +245,17 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"9608eed92b3839b06ebf72d5043da547de10ce85",
"9608eed92b3839b06ebf72d5043da547de10ce85",
- Changes{},
+ []expectChange{},
},
{
"git://github.com/toqueteos/ts3.git",
"",
"764e914b75d6d6df1fc5d832aa9840f590abf1bb",
- Changes{
+ []expectChange{
+ {Action: Insert, Name: "README.markdown"},
{Action: Insert, Name: "examples/bot.go"},
{Action: Insert, Name: "examples/raw_shell.go"},
{Action: Insert, Name: "helpers.go"},
- {Action: Insert, Name: "README.markdown"},
{Action: Insert, Name: "ts3.go"},
},
},
@@ -204,11 +263,11 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/toqueteos/ts3.git",
"764e914b75d6d6df1fc5d832aa9840f590abf1bb",
"",
- Changes{
+ []expectChange{
+ {Action: Delete, Name: "README.markdown"},
{Action: Delete, Name: "examples/bot.go"},
{Action: Delete, Name: "examples/raw_shell.go"},
{Action: Delete, Name: "helpers.go"},
- {Action: Delete, Name: "README.markdown"},
{Action: Delete, Name: "ts3.go"},
},
},
@@ -216,13 +275,13 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/toqueteos/ts3.git",
"764e914b75d6d6df1fc5d832aa9840f590abf1bb",
"764e914b75d6d6df1fc5d832aa9840f590abf1bb",
- Changes{},
+ []expectChange{},
},
{
"git://github.com/github/gem-builder.git",
"9608eed92b3839b06ebf72d5043da547de10ce85",
"6c41e05a17e19805879689414026eb4e279f7de0",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
},
},
@@ -230,7 +289,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"6c41e05a17e19805879689414026eb4e279f7de0",
"89be3aac2f178719c12953cc9eaa23441f8d9371",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
{Action: Insert, Name: "gem_eval_test.rb"},
{Action: Insert, Name: "security.rb"},
@@ -241,7 +300,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"89be3aac2f178719c12953cc9eaa23441f8d9371",
"597240b7da22d03ad555328f15abc480b820acc0",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
},
},
@@ -249,7 +308,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"597240b7da22d03ad555328f15abc480b820acc0",
"0260380e375d2dd0e1a8fcab15f91ce56dbe778e",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
{Action: Modify, Name: "gem_eval_test.rb"},
{Action: Insert, Name: "lazy_dir.rb"},
@@ -262,7 +321,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"0260380e375d2dd0e1a8fcab15f91ce56dbe778e",
"597240b7da22d03ad555328f15abc480b820acc0",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
{Action: Modify, Name: "gem_eval_test.rb"},
{Action: Delete, Name: "lazy_dir.rb"},
@@ -275,7 +334,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"0260380e375d2dd0e1a8fcab15f91ce56dbe778e",
"ca9fd470bacb6262eb4ca23ee48bb2f43711c1ff",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
{Action: Modify, Name: "security.rb"},
{Action: Modify, Name: "security_test.rb"},
@@ -285,7 +344,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/github/gem-builder.git",
"fe3c86745f887c23a0d38c85cfd87ca957312f86",
"b7e3f636febf7a0cd3ab473b6d30081786d2c5b6",
- Changes{
+ []expectChange{
{Action: Modify, Name: "gem_eval.rb"},
{Action: Modify, Name: "gem_eval_test.rb"},
{Action: Insert, Name: "git_mock"},
@@ -298,7 +357,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/rumpkernel/rumprun-xen.git",
"1831e47b0c6db750714cd0e4be97b5af17fb1eb0",
"51d8515578ea0c88cc8fc1a057903675cf1fc16c",
- Changes{
+ []expectChange{
{Action: Modify, Name: "Makefile"},
{Action: Modify, Name: "netbsd_init.c"},
{Action: Modify, Name: "rumphyper_stubs.c"},
@@ -309,7 +368,7 @@ func (s *DiffTreeSuite) TestDiffTree(c *C) {
"git://github.com/rumpkernel/rumprun-xen.git",
"1831e47b0c6db750714cd0e4be97b5af17fb1eb0",
"e13e678f7ee9badd01b120889e0ec5fdc8ae3802",
- Changes{
+ []expectChange{
{Action: Modify, Name: "app-tools/rumprun"},
},
},
@@ -346,19 +405,19 @@ func assertChanges(a Changes, c *C) {
for _, changes := range a {
switch changes.Action {
case Insert:
- c.Assert(changes.Files[0], IsNil)
- c.Assert(changes.Files[1], NotNil)
+ c.Assert(changes.From.Tree, IsNil)
+ c.Assert(changes.To.Tree, NotNil)
case Delete:
- c.Assert(changes.Files[0], NotNil)
- c.Assert(changes.Files[1], IsNil)
+ c.Assert(changes.From.Tree, NotNil)
+ c.Assert(changes.To.Tree, IsNil)
case Modify:
- c.Assert(changes.Files[0], NotNil)
- c.Assert(changes.Files[1], NotNil)
+ c.Assert(changes.From.Tree, NotNil)
+ c.Assert(changes.To.Tree, NotNil)
}
}
}
-func equalChanges(a, b Changes) bool {
+func equalChanges(a Changes, b []expectChange) bool {
if a == nil && b == nil {
return true
}
@@ -372,11 +431,10 @@ func equalChanges(a, b Changes) bool {
}
sort.Sort(a)
- sort.Sort(b)
for i, va := range a {
vb := b[i]
- if va.Action != vb.Action || va.Name != vb.Name {
+ if va.Action != vb.Action || va.name() != vb.Name {
return false
}
}