aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--blame/blame.go147
-rw-r--r--blame/blame_test.go478
-rw-r--r--commit.go16
-rw-r--r--commit_test.go96
-rw-r--r--common.go41
-rw-r--r--common_test.go92
-rw-r--r--diff/diff_ext_test.go65
-rw-r--r--file.go35
-rw-r--r--file_test.go133
-rw-r--r--repository.go2
-rw-r--r--repository_test.go4
-rw-r--r--revlist/revlist.go106
-rw-r--r--revlist/revlist_test.go86
-rw-r--r--tree.go6
14 files changed, 686 insertions, 621 deletions
diff --git a/blame/blame.go b/blame/blame.go
index 774362b..9475f2a 100644
--- a/blame/blame.go
+++ b/blame/blame.go
@@ -10,8 +10,8 @@ package blame
import (
"bytes"
+ "errors"
"fmt"
- "sort"
"strconv"
"strings"
"unicode/utf8"
@@ -62,52 +62,125 @@ import (
// 2. Improve how to traverse the history (example a backward
// traversal will be much more efficient)
//
-// TODO: ways to improve the functrion in general
+// TODO: ways to improve the function in general:
//
// 1. Add memoization betweenn revlist and assign.
//
// 2. It is using much more memmory than needed, see the TODOs below.
-func Blame(repo *git.Repository, commit *git.Commit, path string) ([]*git.Commit, error) {
+
+type Blame struct {
+ Repo string
+ Path string
+ Rev string
+ Lines []*line
+}
+
+func New(repo *git.Repository, path string, commit *git.Commit) (*Blame, error) {
// init the internal blame struct
b := new(blame)
b.repo = repo
b.fRev = commit
b.path = path
- // calculte the history of the file and store it in the
- // internal blame struct.
- var err error
- b.revs, err = revlist.New(b.repo, b.fRev, b.path)
+ // get all the file revisions
+ if err := b.fillRevs(); err != nil {
+ return nil, err
+ }
+
+ // calculate the line tracking graph and fill in
+ // file contents in data.
+ if err := b.fillGraphAndData(); err != nil {
+ return nil, err
+ }
+
+ file, err := b.fRev.File(b.path)
+ if err != nil {
+ return nil, err
+ }
+ finalLines := file.Lines()
+
+ lines, err := newLines(finalLines, b.sliceGraph(len(b.graph)-1))
if err != nil {
return nil, err
}
- sort.Sort(b.revs) // for forward blame, we need the history sorted by commit date
- // allocate space for the data in all the revisions of the file
- b.data = make([]string, len(b.revs))
+ return &Blame{
+ Repo: repo.URL,
+ Path: path,
+ Rev: commit.Hash.String(),
+ Lines: lines,
+ }, nil
+}
- // init the graph
- b.graph = make([][]vertex, len(b.revs))
+type line struct {
+ author string
+ text string
+}
- // for all every revision of the file, starting with the first
+func newLine(author, text string) *line {
+ return &line{
+ author: author,
+ text: text,
+ }
+}
+
+func newLines(contents []string, commits []*git.Commit) ([]*line, error) {
+ if len(contents) != len(commits) {
+ fmt.Println(len(contents))
+ fmt.Println(len(commits))
+ return nil, errors.New("contents and commits have different length")
+ }
+ result := make([]*line, 0, len(contents))
+ for i := range contents {
+ l := newLine(commits[i].Author.Email, contents[i])
+ result = append(result, l)
+ }
+ return result, nil
+}
+
+// this struct is internally used by the blame function to hold its
+// inputs, outputs and state.
+type blame struct {
+ repo *git.Repository // the repo holding the history of the file to blame
+ path string // the path of the file to blame
+ fRev *git.Commit // the commit of the final revision of the file to blame
+ revs revlist.Revs // the chain of revisions affecting the the file to blame
+ data []string // the contents of the file across all its revisions
+ graph [][]*git.Commit // the graph of the lines in the file across all the revisions TODO: not all commits are needed, only the current rev and the prev
+}
+
+// calculte the history of a file "path", from commit "from, sorted by commit date.
+func (b *blame) fillRevs() error {
+ var err error
+ b.revs, err = revlist.NewRevs(b.repo, b.fRev, b.path)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// build graph of a file from its revision history
+func (b *blame) fillGraphAndData() error {
+ b.graph = make([][]*git.Commit, len(b.revs))
+ b.data = make([]string, len(b.revs)) // file contents in all the revisions
+ // for every revision of the file, starting with the first
// one...
- var found bool
for i, rev := range b.revs {
// get the contents of the file
- b.data[i], found = git.Data(b.path, rev)
- if !found {
- continue
+ file, err := rev.File(b.path)
+ if err != nil {
+ return nil
}
- // count its lines
+ b.data[i] = file.Contents()
nLines := git.CountLines(b.data[i])
// create a node for each line
- b.graph[i] = make([]vertex, nLines)
+ b.graph[i] = make([]*git.Commit, nLines)
// assign a commit to each node
// if this is the first revision, then the node is assigned to
// this first commit.
if i == 0 {
for j := 0; j < nLines; j++ {
- b.graph[i][j] = vertex(b.revs[i])
+ b.graph[i][j] = (*git.Commit)(b.revs[i])
}
} else {
// if this is not the first commit, then assign to the old
@@ -116,31 +189,21 @@ func Blame(repo *git.Repository, commit *git.Commit, path string) ([]*git.Commit
b.assignOrigin(i, i-1)
}
}
+ return nil
+}
- // fill in the output results: copy the nodes of the last revision
- // into the result.
- fVs := b.graph[len(b.graph)-1]
+// sliceGraph returns a slice of commits (one per line) for a particular
+// revision of a file (0=first revision).
+func (b *blame) sliceGraph(i int) []*git.Commit {
+ fVs := b.graph[i]
result := make([]*git.Commit, 0, len(fVs))
for _, v := range fVs {
c := git.Commit(*v)
result = append(result, &c)
}
- return result, nil
-}
-
-// this struct is internally used by the blame function to hold its
-// intputs, outputs and state.
-type blame struct {
- repo *git.Repository // the repo holding the history of the file to blame
- path string // the path of the file to blame
- fRev *git.Commit // the commit of the final revision of the file to blame
- revs revlist.Revs // the chain of revisions affecting the the file to blame
- data []string // the contents on the file in all the revisions TODO: not all data is needed, only the current rev and the prev
- graph [][]vertex // the graph of the lines in the file across all the revisions TODO: not all vertexes are needed, only the current rev and the prev
+ return result
}
-type vertex *git.Commit // a vertex only needs to store the original commit it came from
-
// Assigns origin to vertexes in current (c) rev from data in its previous (p)
// revision
func (b *blame) assignOrigin(c, p int) {
@@ -151,7 +214,6 @@ func (b *blame) assignOrigin(c, p int) {
for h := range hunks {
hLines := git.CountLines(hunks[h].Text)
for hl := 0; hl < hLines; hl++ {
- // fmt.Printf("file=%q, rev=%d, r=%d, h=%d, hunk=%v, hunkLine=%d\n", file, rev, r, h, hunks[h], hl)
switch {
case hunks[h].Type == 0:
sl++
@@ -159,7 +221,7 @@ func (b *blame) assignOrigin(c, p int) {
b.graph[c][dl] = b.graph[p][sl]
case hunks[h].Type == 1:
dl++
- b.graph[c][dl] = vertex(b.revs[c])
+ b.graph[c][dl] = (*git.Commit)(b.revs[c])
case hunks[h].Type == -1:
sl++
default:
@@ -169,14 +231,15 @@ func (b *blame) assignOrigin(c, p int) {
}
}
-// This will print the results of a Blame as in git-blame.
+// PrettyPrint prints the results of a Blame using git-blame's style.
func (b *blame) PrettyPrint() string {
var buf bytes.Buffer
- contents, found := git.Data(b.path, b.fRev)
- if !found {
+ file, err := b.fRev.File(b.path)
+ if err != nil {
panic("PrettyPrint: internal error in repo.Data")
}
+ contents := file.Contents()
lines := strings.Split(contents, "\n")
// max line number length
diff --git a/blame/blame_test.go b/blame/blame_test.go
index 81c02f0..3c24852 100644
--- a/blame/blame_test.go
+++ b/blame/blame_test.go
@@ -2,14 +2,14 @@ package blame
import (
"bytes"
- "fmt"
"os"
"testing"
- . "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v2"
"gopkg.in/src-d/go-git.v2/core"
"gopkg.in/src-d/go-git.v2/formats/packfile"
+
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
@@ -32,59 +32,143 @@ var fixtureRepos = [...]struct {
func (s *SuiteCommon) SetUpSuite(c *C) {
s.repos = make(map[string]*git.Repository, 0)
for _, fixRepo := range fixtureRepos {
- s.repos[fixRepo.url] = git.NewPlainRepository()
+ repo := git.NewPlainRepository()
+ repo.URL = fixRepo.url
d, err := os.Open(fixRepo.packfile)
- defer func() {
- c.Assert(d.Close(), IsNil)
- }()
c.Assert(err, IsNil)
r := packfile.NewReader(d)
- r.Format = packfile.OFSDeltaFormat // TODO: how to know the format of a pack file ahead of time?
+ // TODO: how to know the format of a pack file ahead of time?
+ // Some info at:
+ // https://codewords.recurse.com/issues/three/unpacking-git-packfiles
+ r.Format = packfile.OFSDeltaFormat
- _, err = r.Read(s.repos[fixRepo.url].Storage)
+ _, err = r.Read(repo.Storage)
c.Assert(err, IsNil)
+
+ c.Assert(d.Close(), IsNil)
+
+ s.repos[fixRepo.url] = repo
}
}
-var blameTests = [...]struct {
- // input data to revlist
+type blameTest struct {
repo string
- branch string // TODO: remove this, it is no longer needed for local packfiles
- commit string
+ rev string
path string
- // expected output data form the revlist
- blames []string
-}{
+ blames []string // the commits blamed for each line
+}
+
+func (s *SuiteCommon) mockBlame(t blameTest, c *C) (blame *Blame) {
+ repo, ok := s.repos[t.repo]
+ c.Assert(ok, Equals, true)
+
+ commit, err := repo.Commit(core.NewHash(t.rev))
+ c.Assert(err, IsNil, Commentf("%v: repo=%s, rev=%s", err, repo, t.rev))
+
+ file, err := commit.File(t.path)
+ c.Assert(err, IsNil)
+ lines := file.Lines()
+ c.Assert(len(t.blames), Equals, len(lines), Commentf(
+ "repo=%s, path=%s, rev=%s: the number of lines in the file and the number of expected blames differ (len(blames)=%d, len(lines)=%d)\nblames=%#q\nlines=%#q", t.repo, t.path, t.rev, len(t.blames), len(lines), t.blames, lines))
+
+ blamedLines := make([]*line, 0, len(t.blames))
+ for i := range t.blames {
+ commit, err := repo.Commit(core.NewHash(t.blames[i]))
+ c.Assert(err, IsNil)
+ l := &line{
+ author: commit.Author.Email,
+ text: lines[i],
+ }
+ blamedLines = append(blamedLines, l)
+ }
+
+ return &Blame{
+ Repo: t.repo,
+ Path: t.path,
+ Rev: t.rev,
+ Lines: blamedLines,
+ }
+}
+
+// run a blame on all the suite's tests
+func (s *SuiteCommon) TestBlame(c *C) {
+ for i, t := range blameTests {
+ expected := s.mockBlame(t, c)
+
+ repo, ok := s.repos[t.repo]
+ c.Assert(ok, Equals, true)
+
+ commit, err := repo.Commit(core.NewHash(t.rev))
+ c.Assert(err, IsNil)
+
+ obtained, err := New(repo, t.path, commit)
+ c.Assert(err, IsNil, Commentf("subtest %d", i))
+
+ c.Assert(obtained, DeepEquals, expected, Commentf("subtest %d: %s",
+ i, sideBySide(obtained, expected)))
+ }
+}
+
+func sideBySide(output, expected *Blame) string {
+ var buf bytes.Buffer
+ buf.WriteString(output.Repo)
+ buf.WriteString(" ")
+ buf.WriteString(expected.Repo)
+ return buf.String()
+}
+
+// utility function to avoid writing so many repeated commits
+func repeat(s string, n int) []string {
+ if n < 0 {
+ panic("repeat: n < 0")
+ }
+ r := make([]string, 0, n)
+ for i := 0; i < n; i++ {
+ r = append(r, s)
+ }
+ return r
+}
+
+// utility function to concat slices
+func concat(vargs ...[]string) []string {
+ var result []string
+ for _, ss := range vargs {
+ result = append(result, ss...)
+ }
+ return result
+}
+
+var blameTests = [...]blameTest{
// use the blame2humantest.bash script to easily add more tests.
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", concat(
repeat("35e85108805c84807bc66a02d91535e1e24b38b9", 285),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", concat(
repeat("b8e471f58bcbca63b07bda20e428190409c2db47", 1),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", concat(
repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 142),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", concat(
repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 6492),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", concat(
repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 22),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", concat(
repeat("b029517f6300c2da0f4b651b8642506cd6aaf45d", 22),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", concat(
repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 259),
)},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", concat(&[]string{},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", concat(
repeat("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 7),
)},
/*
// Failed
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "InstallSpinnaker.sh", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "InstallSpinnaker.sh", concat(
repeat("ce9f123d790717599aaeb76bc62510de437761be", 2),
repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 1),
repeat("23673af3ad70b50bba7fdafadc2323302f5ba520", 1),
@@ -239,11 +323,11 @@ var blameTests = [...]struct {
repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 3),
)},
*/
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/reconfigure_spinnaker.py", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/reconfigure_spinnaker.py", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 22),
repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 7),
)},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/validate_configuration.py", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/validate_configuration.py", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 29),
repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 19),
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 15),
@@ -274,12 +358,12 @@ var blameTests = [...]struct {
repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 7),
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
)},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/run.py", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/run.py", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 185),
)},
/*
// Fail by 3
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/configurator.py", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/configurator.py", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 53),
repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 1),
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
@@ -301,62 +385,8 @@ var blameTests = [...]struct {
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 43),
)},
*/
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/fetch.py", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 140),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/yaml_util.py", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 68),
- repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 8),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("023d4fb17b76e0fe0764971df8b8538b735a1d67", 3),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 7),
- repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 12),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 33),
- repeat("bb6325e4e629fc7348a6d0e6842280d5304160ff", 40),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 7),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 4),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/spinnaker_runner.py", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 235),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 13),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 7),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 20),
- repeat("707bcdce04eabdb0549868ad1a8efa2d76b9bdf1", 7),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 21),
- repeat("2b28ea424acc8f2817d3298c143fae68bcad91a7", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 15),
- repeat("d73f9cee49a5ad27a42a6e18af7c49a8f28ad8a8", 17),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 336),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/transform_old_config.py", concat(&[]string{},
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 43),
- repeat("4584fab37e93d66fd1896d07fa3427f8056711bc", 1),
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 12),
- repeat("bb6325e4e629fc7348a6d0e6842280d5304160ff", 1),
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 16),
- repeat("0777fadf4ca6f458d7071de414f9bd5417911037", 1),
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 1),
- repeat("0777fadf4ca6f458d7071de414f9bd5417911037", 1),
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 8),
- repeat("0777fadf4ca6f458d7071de414f9bd5417911037", 1),
- repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 31),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/__init__.py", []string{}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/yaml/LICENSE", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 19),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "settings.gradle", concat(&[]string{},
- repeat("ce9f123d790717599aaeb76bc62510de437761be", 1),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/wrapper/gradle-wrapper.jar", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/__init__.py", []string{}},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/wrapper/gradle-wrapper.jar", concat(
repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1),
repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 7),
repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2),
@@ -406,15 +436,7 @@ var blameTests = [...]struct {
repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 6),
repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 55),
)},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/wrapper/gradle-wrapper.properties", concat(&[]string{},
- repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1),
- repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 4),
- repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/buildViaTravis.sh", concat(&[]string{},
- repeat("7ecc2ad58e24a5b52504985467a10c6a3bb85b9b", 24),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/settings.js", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/settings.js", concat(
repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 17),
repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1),
repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 43),
@@ -424,7 +446,7 @@ var blameTests = [...]struct {
)},
/*
// fail a few lines
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/default-spinnaker-local.yml", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/default-spinnaker-local.yml", concat(
repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9),
repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 2),
repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1),
@@ -449,36 +471,9 @@ var blameTests = [...]struct {
repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2),
)},
*/
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/igor.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 15),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/echo.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 15),
- repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 1),
- repeat("7c8d9a6081d9cb7a56c479bfe64d70540ea32795", 4),
- repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 24),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/orca.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 40),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/rosco.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9),
- repeat("24dc2d465c85cb242262ab6bc236bde3ffbb93e0", 3),
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 3),
- repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 2),
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 3),
- repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2),
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 1),
- repeat("974b775a8978b120ff710cac93a21c7387b914c9", 1),
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 2),
- repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/rush.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 18),
- )},
/*
// fail one line
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/spinnaker.yml", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/spinnaker.yml", concat(
repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 32),
repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 2),
repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 1),
@@ -500,142 +495,15 @@ var blameTests = [...]struct {
repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 15),
)},
*/
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/gate.yml", concat(&[]string{},
- repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 29),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/run_dev.sh", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 23),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/build_google_image.sh", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 16),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 18),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/refresh_source.py", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 21),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 14),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 35),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 34),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 11),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 17),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 23),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 5),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 6),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 7),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("ba10a5d5615f68eb9115cada1d639066a53ddc4d", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 7),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 9),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a80d310d9ca42c3422627f2ecca7ee1dbefa602a", 13),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 11),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 6),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 3),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("b192881117651465df2385ef89344dd5dd4810f3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 5),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 11),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 14),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("13ad4df676a16caf2ff1ca216be615d5aee37db3", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 36),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 7),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 4),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 21),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 3),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 6),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 19),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 8),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 14),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("3d3819741bada73fb950f14309c97e1f63492ec6", 2),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("e3620408a7776039f7853a21748921ea2a281953", 1),
- )},
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/install_development.sh", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/install_development.sh", concat(
repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1),
repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 71),
)},
*/
/*
// FAIL two lines interchanged
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/bootstrap_dev.sh", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/bootstrap_dev.sh", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 95),
repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1),
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10),
@@ -695,116 +563,10 @@ var blameTests = [...]struct {
repeat("838aed816872c52ed435e4876a7b64dba0bed500", 8),
)},
*/
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/build_release.sh", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 17),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/stop_dev.sh", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 23),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/build_google_image.packer", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("8fe3f13ad04ee25fde0add4ed19d29acd49a5916", 1),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2),
- repeat("8fe3f13ad04ee25fde0add4ed19d29acd49a5916", 1),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 14),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 1),
- repeat("0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 8),
- repeat("6eb5d9c5225224bfe59c401182a2939d6c27fc00", 1),
- repeat("f66196ceed7d6aeca313b0632657ab762487ced3", 1),
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3),
- )},
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/refresh_source.sh", concat(&[]string{},
- repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 17),
- )},
/*
// FAIL move?
- {"https://github.com/spinnaker/spinnaker.git", "master", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/create_google_dev_vm.sh", concat(&[]string{},
+ {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/create_google_dev_vm.sh", concat(
repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 20),
)},
*/
}
-
-// run a blame on all the suite's tests
-func (s *SuiteCommon) TestBlame(c *C) {
- for _, t := range blameTests {
- fmt.Println("Blamming", t.repo, t.branch, t.commit, t.path)
- repo, ok := s.repos[t.repo]
- c.Assert(ok, Equals, true)
-
- commit, err := repo.Commit(core.NewHash(t.commit))
- c.Assert(err, IsNil)
-
- blames, err := Blame(repo, commit, t.path)
- c.Assert(err, IsNil)
-
- c.Assert(len(blames), Equals, len(t.blames), Commentf("\nrepo=%s, branch=%s, commit=%s, path=%s",
- t.repo, t.branch, t.commit, t.path))
- c.Assert(blames, DeepEquals, s.commits(c, t.repo, t.blames...), Commentf("\nrepo=%s, branch=%s, commit=%s, path=%s, \n%s",
- t.repo, t.branch, t.commit, t.path, compareSideBySide2(t.blames, blames)))
- }
-}
-
-// TODO: duplicated from revlist/revlist_test.go
-// returns the commits from a slice of hashes
-func (s *SuiteCommon) commits(cc *C, repo string, hs ...string) []*git.Commit {
- r, ok := s.repos[repo]
- cc.Assert(ok, Equals, true)
- result := make([]*git.Commit, 0, len(hs))
- for _, h := range hs {
- c, err := r.Commit(core.NewHash(h))
- cc.Assert(err, IsNil)
- result = append(result, c)
- }
- return result
-}
-
-// TODO: duplicated from revlist/revlist_test.go
-// same length is assumed
-func compareSideBySide2(a []string, b []*git.Commit) string {
- var buf bytes.Buffer
- buf.WriteString("\t EXPECTED OBTAINED ")
- var sep string
- var obtained string
- for i := range a {
- obtained = b[i].Hash.String()
- if a[i] != obtained {
- sep = "------"
- } else {
- sep = " "
- }
- buf.WriteString(fmt.Sprintf("\n%d", i+1))
- buf.WriteString(sep)
- buf.WriteString(a[i])
- buf.WriteString(sep)
- buf.WriteString(obtained)
- }
- return buf.String()
-}
-
-// utility function to avoid writing so many repeated commits
-func repeat(s string, n int) []string {
- if n < 0 {
- panic("repeat: n < 0")
- }
- r := make([]string, 0, n)
- for i := 0; i < n; i++ {
- r = append(r, s)
- }
- return r
-}
-
-// utility function to concat slices
-func concat(dst *[]string, vargs ...[]string) []string {
- for _, ss := range vargs {
- for _, s := range ss {
- *dst = append(*dst, s)
- }
- }
- return *dst
-}
diff --git a/commit.go b/commit.go
index afd67ab..99dbf37 100644
--- a/commit.go
+++ b/commit.go
@@ -3,12 +3,16 @@ package git
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
"gopkg.in/src-d/go-git.v2/core"
)
+// New errors defined by this package.
+var ErrFileNotFound = errors.New("file not found")
+
type Hash core.Hash
// Commit points to a single tree, marking it as what the project looked like
@@ -50,6 +54,18 @@ func (c *Commit) NumParents() int {
return len(c.parents)
}
+// File returns the file with the specified "path" in the commit and a
+// nil error if the file exists. If the file does not exists, it returns
+// a nil file and the ErrFileNotFound error.
+func (c *Commit) File(path string) (file *File, err error) {
+ for file := range c.Tree().Files() {
+ if file.Name == path {
+ return file, nil
+ }
+ }
+ return nil, ErrFileNotFound
+}
+
// Decode transform an core.Object into a Blob struct
func (c *Commit) Decode(o core.Object) error {
c.Hash = o.Hash()
diff --git a/commit_test.go b/commit_test.go
index 14c2e74..67b9e77 100644
--- a/commit_test.go
+++ b/commit_test.go
@@ -1,16 +1,104 @@
package git
import (
- . "gopkg.in/check.v1"
+ "os"
+
"gopkg.in/src-d/go-git.v2/core"
+ "gopkg.in/src-d/go-git.v2/formats/packfile"
+
+ . "gopkg.in/check.v1"
)
-type CommitCommon struct{}
+type SuiteCommit struct {
+ repos map[string]*Repository
+}
+
+var _ = Suite(&SuiteCommit{})
+
+// create the repositories of the fixtures
+func (s *SuiteCommit) SetUpSuite(c *C) {
+ fixtureRepos := [...]struct {
+ url string
+ packfile string
+ }{
+ {"https://github.com/tyba/git-fixture.git", "formats/packfile/fixtures/git-fixture.ofs-delta"},
+ }
+ s.repos = make(map[string]*Repository, 0)
+ for _, fixRepo := range fixtureRepos {
+ s.repos[fixRepo.url] = NewPlainRepository()
+
+ d, err := os.Open(fixRepo.packfile)
+ c.Assert(err, IsNil)
-var _ = Suite(&CommitCommon{})
+ r := packfile.NewReader(d)
+ r.Format = packfile.OFSDeltaFormat // TODO: how to know the format of a pack file ahead of time?
-func (s *CommitCommon) TestIterClose(c *C) {
+ _, err = r.Read(s.repos[fixRepo.url].Storage)
+ c.Assert(err, IsNil)
+
+ c.Assert(d.Close(), IsNil)
+ }
+}
+
+func (s *SuiteCommit) TestIterClose(c *C) {
i := &iter{ch: make(chan core.Object, 1)}
i.Close()
i.Close()
}
+
+var fileTests = []struct {
+ repo string // the repo name as in localRepos
+ commit string // the commit to search for the file
+ path string // the path of the file to find
+ blobHash string // expected hash of the returned file
+ found bool // expected found value
+}{
+ // use git ls-tree commit to get the hash of the blobs
+ {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "not-found",
+ "", false},
+ {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", ".gitignore",
+ "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true},
+ {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "LICENSE",
+ "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true},
+
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "not-found",
+ "", false},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", ".gitignore",
+ "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg",
+ "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true},
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE",
+ "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true},
+
+ {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "binary.jpg",
+ "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true},
+ {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "binary.jpg",
+ "", false},
+
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
+ {"https://github.com/tyba/git-fixture.git", "1669dce138d9b841a518c64b10914d88f5e488ea", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
+ {"https://github.com/tyba/git-fixture.git", "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
+ {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false},
+ {"https://github.com/tyba/git-fixture.git", "b8e471f58bcbca63b07bda20e428190409c2db47", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
+ {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "CHANGELOG",
+ "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false},
+}
+
+func (s *SuiteCommit) TestFile(c *C) {
+ for i, t := range fileTests {
+ commit, err := s.repos[t.repo].Commit(core.NewHash(t.commit))
+ c.Assert(err, IsNil, Commentf("subtest %d: %v (%s)", i, err, t.commit))
+
+ file, err := commit.File(t.path)
+ found := err == nil
+ c.Assert(found, Equals, t.found, Commentf("subtest %d, path=%s, commit=%s", i, t.path, t.commit))
+ if found {
+ c.Assert(file.Hash.String(), Equals, t.blobHash, Commentf("subtest %d, commit=%s, path=%s", i, t.commit, t.path))
+ }
+ }
+}
diff --git a/common.go b/common.go
index 3e25fc7..51486b8 100644
--- a/common.go
+++ b/common.go
@@ -1,15 +1,11 @@
package git
-import (
- "bytes"
- "strings"
-)
+import "strings"
-// CountLines returns the number of lines in a string.
-// The newline character is assumed to be '\n'.
-// The empty string contains 0 lines.
-// If the last line of the string doesn't end with a newline, it will
-// still be considered a line.
+// CountLines returns the number of lines in a string à la git, this is
+// The newline character is assumed to be '\n'. The empty string
+// contains 0 lines. If the last line of the string doesn't end with a
+// newline, it will still be considered a line.
func CountLines(s string) int {
if s == "" {
return 0
@@ -20,30 +16,3 @@ func CountLines(s string) int {
}
return nEol + 1
}
-
-// FindFile searches for a path in a commit. Returns the file and true if found.
-// Returns nil and false if not found.
-// TODO: should this be a method of git.Commit instead?
-func FindFile(path string, commit *Commit) (file *File, found bool) {
- tree := commit.Tree()
- for file := range tree.Files() {
- if file.Name == path {
- return file, true
- }
- }
- return nil, false
-}
-
-// Data returns the contents of a file in a commit and true if found.
-// Returns an empty string and false if the file is not found in the
-// commit.
-// TODO: should this be a method of git.Commit instead?
-func Data(path string, commit *Commit) (contents string, found bool) {
- file, found := FindFile(path, commit)
- if !found {
- return "", found
- }
- buf := new(bytes.Buffer)
- buf.ReadFrom(file)
- return buf.String(), found
-}
diff --git a/common_test.go b/common_test.go
index 0695d5f..4c48419 100644
--- a/common_test.go
+++ b/common_test.go
@@ -5,10 +5,10 @@ import (
"os"
"testing"
- . "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v2/clients/common"
"gopkg.in/src-d/go-git.v2/core"
- "gopkg.in/src-d/go-git.v2/formats/packfile"
+
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
@@ -44,39 +44,10 @@ func (s *MockGitUploadPackService) Fetch(*common.GitUploadPackRequest) (io.ReadC
return r, nil
}
-type SuiteCommon struct {
- repos map[string]*Repository
-}
+type SuiteCommon struct{}
var _ = Suite(&SuiteCommon{})
-var fixtureRepos = [...]struct {
- url string
- packfile string
-}{
- {"https://github.com/tyba/git-fixture.git", "formats/packfile/fixtures/git-fixture.ofs-delta"},
-}
-
-// create the repositories of the fixtures
-func (s *SuiteCommon) SetUpSuite(c *C) {
- s.repos = make(map[string]*Repository, 0)
- for _, fixRepo := range fixtureRepos {
- s.repos[fixRepo.url] = NewPlainRepository()
-
- d, err := os.Open(fixRepo.packfile)
- defer func() {
- c.Assert(d.Close(), IsNil)
- }()
- c.Assert(err, IsNil)
-
- r := packfile.NewReader(d)
- r.Format = packfile.OFSDeltaFormat // TODO: how to know the format of a pack file ahead of time?
-
- _, err = r.Read(s.repos[fixRepo.url].Storage)
- c.Assert(err, IsNil)
- }
-}
-
var countLinesTests = [...]struct {
i string // the string we want to count lines from
e int // the expected number of lines in i
@@ -88,6 +59,7 @@ var countLinesTests = [...]struct {
{"a\nb\n", 2},
{"a\nb\nc", 3},
{"a\nb\nc\n", 3},
+ {"a\n\n\nb\n", 4},
{"first line\n\tsecond line\nthird line\n", 3},
}
@@ -97,59 +69,3 @@ func (s *SuiteCommon) TestCountLines(c *C) {
c.Assert(o, Equals, t.e, Commentf("subtest %d, input=%q", i, t.i))
}
}
-
-var findFileTests = []struct {
- repo string // the repo name as in localRepos
- commit string // the commit to search for the file
- path string // the path of the file to find
- blobHash string // expected hash of the returned file
- found bool // expected found value
-}{
- // use git ls-tree commit to get the hash of the blobs
- {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "not-found",
- "", false},
- {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", ".gitignore",
- "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true},
- {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "LICENSE",
- "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true},
-
- {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "not-found",
- "", false},
- {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", ".gitignore",
- "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true},
- {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg",
- "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true},
- {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE",
- "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true},
-
- {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "binary.jpg",
- "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true},
- {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "binary.jpg",
- "", false},
-
- {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
- {"https://github.com/tyba/git-fixture.git", "1669dce138d9b841a518c64b10914d88f5e488ea", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
- {"https://github.com/tyba/git-fixture.git", "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
- {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false},
- {"https://github.com/tyba/git-fixture.git", "b8e471f58bcbca63b07bda20e428190409c2db47", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true},
- {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "CHANGELOG",
- "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false},
-}
-
-func (s *SuiteCommon) TestFindFile(c *C) {
- for i, t := range findFileTests {
- commit, err := s.repos[t.repo].Commit(core.NewHash(t.commit))
- c.Assert(err, IsNil, Commentf("subtest %d: %v (%s)", i, err, t.commit))
-
- file, found := FindFile(t.path, commit)
- c.Assert(found, Equals, t.found, Commentf("subtest %d, path=%s, commit=%s", i, t.path, t.commit))
- if found {
- c.Assert(file.Hash.String(), Equals, t.blobHash, Commentf("subtest %d, commit=%s, path=%s", i, t.commit, t.path))
- }
- }
-}
diff --git a/diff/diff_ext_test.go b/diff/diff_ext_test.go
index 5ab8c7d..460cf8a 100644
--- a/diff/diff_ext_test.go
+++ b/diff/diff_ext_test.go
@@ -3,9 +3,10 @@ package diff_test
import (
"testing"
- . "gopkg.in/check.v1"
-
"gopkg.in/src-d/go-git.v2/diff"
+
+ "github.com/sergi/go-diff/diffmatchpatch"
+ . "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
@@ -39,7 +40,7 @@ var diffTests = [...]struct {
{"a\nbbbbb\n\tccc\ndd\n\tfffffffff\n", "bbbbb\n\tccc\n\tDD\n\tffff\n"},
}
-func (s *suiteCommon) TestCountLines(c *C) {
+func (s *suiteCommon) TestAll(c *C) {
for i, t := range diffTests {
diffs := diff.Do(t.src, t.dst)
src := diff.Src(diffs)
@@ -48,3 +49,61 @@ func (s *suiteCommon) TestCountLines(c *C) {
c.Assert(dst, Equals, t.dst, Commentf("subtest %d, src=%q, dst=%q, bad calculated dst", i, t.src, t.dst))
}
}
+
+var doTests = [...]struct {
+ src, dst string
+ expected []diffmatchpatch.Diff
+}{
+ {
+ src: "",
+ dst: "",
+ expected: []diffmatchpatch.Diff{},
+ },
+ {
+ src: "a",
+ dst: "a",
+ expected: []diffmatchpatch.Diff{
+ {
+ Type: 0,
+ Text: "a",
+ },
+ },
+ },
+ {
+ src: "",
+ dst: "abc\ncba",
+ expected: []diffmatchpatch.Diff{
+ {
+ Type: 1,
+ Text: "abc\ncba",
+ },
+ },
+ },
+ {
+ src: "abc\ncba",
+ dst: "",
+ expected: []diffmatchpatch.Diff{
+ {
+ Type: -1,
+ Text: "abc\ncba",
+ },
+ },
+ },
+ {
+ src: "abc\nbcd\ncde",
+ dst: "000\nabc\n111\nBCD\n",
+ expected: []diffmatchpatch.Diff{
+ {Type: 1, Text: "000\n"},
+ {Type: 0, Text: "abc\n"},
+ {Type: -1, Text: "bcd\ncde"},
+ {Type: 1, Text: "111\nBCD\n"},
+ },
+ },
+}
+
+func (s *suiteCommon) TestDo(c *C) {
+ for i, t := range doTests {
+ diffs := diff.Do(t.src, t.dst)
+ c.Assert(diffs, DeepEquals, t.expected, Commentf("subtest %d", i))
+ }
+}
diff --git a/file.go b/file.go
new file mode 100644
index 0000000..86baf7d
--- /dev/null
+++ b/file.go
@@ -0,0 +1,35 @@
+package git
+
+import (
+ "bytes"
+ "io"
+ "strings"
+
+ "gopkg.in/src-d/go-git.v2/core"
+)
+
+// File represents git file objects.
+type File struct {
+ Name string
+ io.Reader
+ Hash core.Hash
+}
+
+// Contents returns the contents of a file as a string.
+func (f *File) Contents() string {
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(f)
+ return buf.String()
+}
+
+// Lines returns a slice of lines from the contents of a file, stripping
+// all end of line characters. If the last line is empty (does not end
+// in an end of line), it is also stripped.
+func (f *File) Lines() []string {
+ splits := strings.Split(f.Contents(), "\n")
+ // remove the last line if it is empty
+ if splits[len(splits)-1] == "" {
+ return splits[:len(splits)-1]
+ }
+ return splits
+}
diff --git a/file_test.go b/file_test.go
new file mode 100644
index 0000000..8c22bb3
--- /dev/null
+++ b/file_test.go
@@ -0,0 +1,133 @@
+package git
+
+import (
+ "os"
+
+ "gopkg.in/src-d/go-git.v2/core"
+ "gopkg.in/src-d/go-git.v2/formats/packfile"
+
+ . "gopkg.in/check.v1"
+)
+
+type SuiteFile struct {
+ repos map[string]*Repository
+}
+
+var _ = Suite(&SuiteFile{})
+
+// create the repositories of the fixtures
+func (s *SuiteFile) SetUpSuite(c *C) {
+ fixtureRepos := [...]struct {
+ url string
+ packfile string
+ }{
+ {"https://github.com/tyba/git-fixture.git", "formats/packfile/fixtures/git-fixture.ofs-delta"},
+ }
+ s.repos = make(map[string]*Repository, 0)
+ for _, fixRepo := range fixtureRepos {
+ s.repos[fixRepo.url] = NewPlainRepository()
+
+ d, err := os.Open(fixRepo.packfile)
+ c.Assert(err, IsNil)
+
+ r := packfile.NewReader(d)
+ r.Format = packfile.OFSDeltaFormat
+
+ _, err = r.Read(s.repos[fixRepo.url].Storage)
+ c.Assert(err, IsNil)
+
+ c.Assert(d.Close(), IsNil)
+ }
+}
+
+var contentsTests = []struct {
+ repo string // the repo name as in localRepos
+ commit string // the commit to search for the file
+ path string // the path of the file to find
+ contents string // expected contents of the file
+}{
+ {
+ "https://github.com/tyba/git-fixture.git",
+ "b029517f6300c2da0f4b651b8642506cd6aaf45d",
+ ".gitignore",
+ `*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+`,
+ },
+ {
+ "https://github.com/tyba/git-fixture.git",
+ "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
+ "CHANGELOG",
+ `Initial changelog
+`,
+ },
+}
+
+func (s *SuiteFile) TestContents(c *C) {
+ for i, t := range contentsTests {
+ commit, err := s.repos[t.repo].Commit(core.NewHash(t.commit))
+ c.Assert(err, IsNil, Commentf("subtest %d: %v (%s)", i, err, t.commit))
+
+ file, err := commit.File(t.path)
+ c.Assert(err, IsNil)
+ c.Assert(file.Contents(), Equals, t.contents, Commentf(
+ "subtest %d: commit=%s, path=%s", i, t.commit, t.path))
+ }
+}
+
+var linesTests = []struct {
+ repo string // the repo name as in localRepos
+ commit string // the commit to search for the file
+ path string // the path of the file to find
+ lines []string // expected lines in the file
+}{
+ {
+ "https://github.com/tyba/git-fixture.git",
+ "b029517f6300c2da0f4b651b8642506cd6aaf45d",
+ ".gitignore",
+ []string{
+ "*.class",
+ "",
+ "# Mobile Tools for Java (J2ME)",
+ ".mtj.tmp/",
+ "",
+ "# Package Files #",
+ "*.jar",
+ "*.war",
+ "*.ear",
+ "",
+ "# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml",
+ "hs_err_pid*",
+ },
+ },
+ {
+ "https://github.com/tyba/git-fixture.git",
+ "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
+ "CHANGELOG",
+ []string{
+ "Initial changelog",
+ },
+ },
+}
+
+func (s *SuiteFile) TestLines(c *C) {
+ for i, t := range linesTests {
+ commit, err := s.repos[t.repo].Commit(core.NewHash(t.commit))
+ c.Assert(err, IsNil, Commentf("subtest %d: %v (%s)", i, err, t.commit))
+
+ file, err := commit.File(t.path)
+ c.Assert(err, IsNil)
+ c.Assert(file.Lines(), DeepEquals, t.lines, Commentf(
+ "subtest %d: commit=%s, path=%s", i, t.commit, t.path))
+ }
+}
diff --git a/repository.go b/repository.go
index 32a6fcf..e63869a 100644
--- a/repository.go
+++ b/repository.go
@@ -20,6 +20,7 @@ const (
type Repository struct {
Remotes map[string]*Remote
Storage *core.RAWObjectStorage
+ URL string
}
// NewRepository creates a new repository setting remote as default remote
@@ -39,6 +40,7 @@ func NewRepository(url string, auth common.AuthMethod) (*Repository, error) {
r := NewPlainRepository()
r.Remotes[DefaultRemoteName] = remote
+ r.URL = url
return r, nil
}
diff --git a/repository_test.go b/repository_test.go
index a8fe50a..20aaf0c 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -1,9 +1,10 @@
package git
import (
- . "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v2/clients/http"
"gopkg.in/src-d/go-git.v2/core"
+
+ . "gopkg.in/check.v1"
)
type SuiteRepository struct{}
@@ -14,6 +15,7 @@ func (s *SuiteRepository) TestNewRepository(c *C) {
r, err := NewRepository(RepositoryFixture, nil)
c.Assert(err, IsNil)
c.Assert(r.Remotes["origin"].Auth, IsNil)
+ c.Assert(r.URL, Equals, RepositoryFixture)
}
func (s *SuiteRepository) TestNewRepositoryWithAuth(c *C) {
diff --git a/revlist/revlist.go b/revlist/revlist.go
index f34ddb5..181e56d 100644
--- a/revlist/revlist.go
+++ b/revlist/revlist.go
@@ -12,26 +12,25 @@
// The current implementation tries to get something similar to what you
// whould get using git-revlist. See the failing tests for some
// insight about how the current implementation and git-revlist differs.
+//
+// Another way to get the revision history for a file is:
+// git log --follow -p -- file
package revlist
import (
"bytes"
- "errors"
"io"
"sort"
- "github.com/sergi/go-diff/diffmatchpatch"
-
"gopkg.in/src-d/go-git.v2"
"gopkg.in/src-d/go-git.v2/core"
"gopkg.in/src-d/go-git.v2/diff"
-)
-// New errors defined by the package.
-var ErrFileNotFound = errors.New("file not found")
+ "github.com/sergi/go-diff/diffmatchpatch"
+)
// A Revs is a list of revisions for a file (basically a list of commits).
-// It implements sort.Interface.
+// It implements sort.Interface using the commit time.
type Revs []*git.Commit
func (l Revs) Len() int {
@@ -48,7 +47,7 @@ func (l Revs) Swap(i, j int) {
}
// for debugging
-func (l Revs) String() string {
+func (l Revs) GoString() string {
var buf bytes.Buffer
for _, c := range l {
buf.WriteString(c.Hash.String()[:8])
@@ -57,16 +56,16 @@ func (l Revs) String() string {
return buf.String()
}
-// New returns a Revs pointer for the
-// file at "path", from commit "commit" backwards in time.
-// The commits are stored in arbitrary order.
+// NewRevs returns a Revs pointer for the
+// file at "path", from commit "commit".
+// The commits are sorted in commit order.
// It stops searching a branch for a file upon reaching the commit
-// were it was created.
+// were the file was created.
// Moves and copies are not currently supported.
-// Cherry-picks are not detected and therefore are added to the list
+// Cherry-picks are not detected unless there are no commits between
+// them and therefore can appear repeated in the list.
// (see git path-id for hints on how to fix this).
-// This function implements is equivalent to running go-rev-Revs.
-func New(repo *git.Repository, commit *git.Commit, path string) (Revs, error) {
+func NewRevs(repo *git.Repository, commit *git.Commit, path string) (Revs, error) {
result := make(Revs, 0)
seen := make(map[core.Hash]struct{}, 0)
err := walkGraph(&result, &seen, repo, commit, path)
@@ -74,7 +73,7 @@ func New(repo *git.Repository, commit *git.Commit, path string) (Revs, error) {
return nil, err
}
sort.Sort(result)
- result = removeComp(path, result, equivalent) // for merges of identical cherry-picks
+ result, err = removeComp(path, result, equivalent) // for merges of identical cherry-picks
if err != nil {
return nil, err
}
@@ -91,10 +90,12 @@ func walkGraph(result *Revs, seen *map[core.Hash]struct{}, repo *git.Repository,
(*seen)[current.Hash] = struct{}{}
// if the path is not in the current commit, stop searching.
- if _, found := git.FindFile(path, current); !found {
+ if _, err := current.File(path); err != nil {
return nil
}
+ // optimization: don't traverse branches that does not
+ // contain the path.
parents := parentsContainingPath(path, current)
switch len(parents) {
@@ -103,7 +104,6 @@ func walkGraph(result *Revs, seen *map[core.Hash]struct{}, repo *git.Repository,
// stop searching. This includes the case when current is the
// initial commit.
case 0:
- //fmt.Println(current.Hash.String(), ": case 0")
*result = append(*result, current)
return nil
case 1: // only one parent contains the path
@@ -113,7 +113,6 @@ func walkGraph(result *Revs, seen *map[core.Hash]struct{}, repo *git.Repository,
return err
}
if len(different) == 1 {
- //fmt.Println(current.Hash.String(), ": case 1")
*result = append(*result, current)
}
// in any case, walk the parent
@@ -144,7 +143,7 @@ func parentsContainingPath(path string, c *git.Commit) []*git.Commit {
}
panic("unreachable")
}
- if _, found := git.FindFile(path, parent); found {
+ if _, err := parent.File(path); err == nil {
result = append(result, parent)
}
}
@@ -156,7 +155,7 @@ func differentContents(path string, c *git.Commit, cs []*git.Commit) ([]*git.Com
result := make([]*git.Commit, 0, len(cs))
h, found := blobHash(path, c)
if !found {
- return nil, ErrFileNotFound
+ return nil, git.ErrFileNotFound
}
for _, cx := range cs {
if hx, found := blobHash(path, cx); found && h != hx {
@@ -168,8 +167,8 @@ func differentContents(path string, c *git.Commit, cs []*git.Commit) ([]*git.Com
// blobHash returns the hash of a path in a commit
func blobHash(path string, commit *git.Commit) (hash core.Hash, found bool) {
- file, found := git.FindFile(path, commit)
- if !found {
+ file, err := commit.File(path)
+ if err != nil {
var empty core.Hash
return empty, found
}
@@ -179,48 +178,71 @@ func blobHash(path string, commit *git.Commit) (hash core.Hash, found bool) {
// Returns a new slice of commits, with duplicates removed. Expects a
// sorted commit list. Duplication is defined according to "comp". It
// will always keep the first commit of a series of duplicated commits.
-func removeComp(path string, cs []*git.Commit, comp func(string, *git.Commit, *git.Commit) bool) []*git.Commit {
+func removeComp(path string, cs []*git.Commit, comp func(string, *git.Commit, *git.Commit) (bool, error)) ([]*git.Commit, error) {
result := make([]*git.Commit, 0, len(cs))
if len(cs) == 0 {
- return result
+ return result, nil
}
result = append(result, cs[0])
for i := 1; i < len(cs); i++ {
- if !comp(path, cs[i], cs[i-1]) {
+ equals, err := comp(path, cs[i], cs[i-1])
+ if err != nil {
+ return nil, err
+ }
+ if !equals {
result = append(result, cs[i])
}
}
- return result
+ return result, nil
}
// Equivalent commits are commits whos patch is the same.
-func equivalent(path string, a, b *git.Commit) bool {
+func equivalent(path string, a, b *git.Commit) (bool, error) {
numParentsA := a.NumParents()
numParentsB := b.NumParents()
// the first commit is not equivalent to anyone
// and "I think" merges can not be equivalent to anything
if numParentsA != 1 || numParentsB != 1 {
- return false
+ return false, nil
}
- iterA := a.Parents()
- parentA, _ := iterA.Next()
- iterB := b.Parents()
- parentB, _ := iterB.Next()
+ diffsA, err := patch(a, path)
+ if err != nil {
+ return false, err
+ }
+ diffsB, err := patch(b, path)
+ if err != nil {
+ return false, err
+ }
- dataA, _ := git.Data(path, a)
- dataParentA, _ := git.Data(path, parentA)
- dataB, _ := git.Data(path, b)
- dataParentB, _ := git.Data(path, parentB)
+ return sameDiffs(diffsA, diffsB), nil
+}
- diffsA := diff.Do(dataParentA, dataA)
- diffsB := diff.Do(dataParentB, dataB)
+func patch(c *git.Commit, path string) ([]diffmatchpatch.Diff, error) {
+ // get contents of the file in the commit
+ file, err := c.File(path)
+ if err != nil {
+ return nil, err
+ }
+ content := file.Contents()
- if sameDiffs(diffsA, diffsB) {
- return true
+ // get contents of the file in the first parent of the commit
+ var contentParent string
+ iter := c.Parents()
+ parent, err := iter.Next()
+ if err != nil {
+ return nil, err
}
- return false
+ file, err = parent.File(path)
+ if err != nil {
+ contentParent = ""
+ } else {
+ contentParent = file.Contents()
+ }
+
+ // compare the contents of parent and child
+ return diff.Do(content, contentParent), nil
}
func sameDiffs(a, b []diffmatchpatch.Diff) bool {
diff --git a/revlist/revlist_test.go b/revlist/revlist_test.go
index 7aea54c..2fe7c83 100644
--- a/revlist/revlist_test.go
+++ b/revlist/revlist_test.go
@@ -51,41 +51,40 @@ func (s *SuiteCommon) SetUpSuite(c *C) {
var revListTests = [...]struct {
// input data to revlist
repo string
- branch string // TODO: remove this, it is no longer needed for local packfiles
commit string
path string
// expected output data form the revlist
revs []string
}{
// Tyba git-fixture
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", []string{
"35e85108805c84807bc66a02d91535e1e24b38b9",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", []string{
"b8e471f58bcbca63b07bda20e428190409c2db47",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", []string{
"918c48b83bd081e863dbe1b80f8998f058cd8294",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", []string{
"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", []string{
"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", []string{
"b029517f6300c2da0f4b651b8642506cd6aaf45d",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", []string{
"918c48b83bd081e863dbe1b80f8998f058cd8294",
}},
- {"https://github.com/tyba/git-fixture.git", "master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", []string{
+ {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", []string{
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
}},
- {"https://github.com/jamesob/desk.git", "master", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "LICENSE", []string{
+ {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "LICENSE", []string{
"ffcda27c2de6768ee83f3f4a027fa4ab57d50f09",
}},
- {"https://github.com/jamesob/desk.git", "master", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "README.md", []string{
+ {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "README.md", []string{
"ffcda27c2de6768ee83f3f4a027fa4ab57d50f09",
"2e87a2dcc63a115f9a61bd969d1e85fb132a431b",
"215b0ac06225b0671bc3460d10da88c3406f796f",
@@ -111,25 +110,25 @@ var revListTests = [...]struct {
"d3f3c8faca048d11709969fbfc0cdf2901b87578",
"8777dde1abe18c805d021366643218d3f3356dd9",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/reconfigure_spinnaker.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/reconfigure_spinnaker.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/validate_configuration.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/validate_configuration.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
"1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9",
"1e3d328a2cabda5d0aaddc5dec65271343e0dc37",
"b5d999e2986e190d81767cd3cfeda0260f9f6fb8",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/fetch.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/fetch.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/yaml_util.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/yaml_util.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
"1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9",
"b5d999e2986e190d81767cd3cfeda0260f9f6fb8",
"023d4fb17b76e0fe0764971df8b8538b735a1d67",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "dev/build_release.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "dev/build_release.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
"1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9",
"f42771ba298b93a7c4f5b16c5b30ab96c15305a8",
@@ -141,10 +140,10 @@ var revListTests = [...]struct {
"5422a86a10a8c5a1ef6728f5fc8894d9a4c54cb9",
"09a4ea729b25714b6368959eea5113c99938f7b6",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "pkg_scripts/postUninstall.sh", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pkg_scripts/postUninstall.sh", []string{
"ce9f123d790717599aaeb76bc62510de437761be",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/first_google_boot.sh", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/first_google_boot.sh", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
"de25f576b888569192e6442b0202d30ca7b2d8ec",
"a596972a661d9a7deca8abd18b52ce1a39516e89",
@@ -157,13 +156,13 @@ var revListTests = [...]struct {
"a57b08a9072f6a865f760551be2a4944f72f804a",
"0777fadf4ca6f458d7071de414f9bd5417911037",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.sh", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.sh", []string{
"0d9c9cef53af38cefcb6801bb492aaed3f2c9a42",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_fake_openjdk8.sh", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_fake_openjdk8.sh", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
"37f94770d81232b1895fca447878f68d65aac652",
"46c9dcbb55ca3f4735e82ad006e8cae2fdd050d9",
@@ -174,10 +173,10 @@ var revListTests = [...]struct {
"739d8c6fe16edcb6ef9185dc74197de561b84315",
"d33c2d1e350b03fb989eefc612e8c9d5fa7cadc2",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/__init__.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/__init__.py", []string{
"a24001f6938d425d0e7504bdf5d27fc866a85c3d",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "experimental/docker-compose/docker-compose.yml", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "experimental/docker-compose/docker-compose.yml", []string{
"fda357835d889595dc39dfebc6181d863cce7d4f",
"57c59e7144354a76e1beba69ae2f85db6b1727af",
"7682dff881029c722d893a112a64fea6849a0428",
@@ -190,7 +189,7 @@ var revListTests = [...]struct {
"ddaae195b628150233b0a48f50a1674fd9d1a924",
"7119ad9cf7d4e4d8b059e5337374baae4adc7458",
}},
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/validate_configuration_test.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/validate_configuration_test.py", []string{
"1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9",
"1e3d328a2cabda5d0aaddc5dec65271343e0dc37",
}},
@@ -198,19 +197,19 @@ var revListTests = [...]struct {
// FAILS
/*
// this contains an empty move
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "google/dev/build_google_tarball.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "google/dev/build_google_tarball.py", []string{
"88e60ac93f832efc2616b3c165e99a8f2ffc3e0c",
"9e49443da49b8c862cc140b660744f84eebcfa51",
}},
*/
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/yaml_util_test.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/yaml_util_test.py", []string{
"edf909edb9319c5e615e4ce73da47bbdca388ebe",
"023d4fb17b76e0fe0764971df8b8538b735a1d67",
}},
*/
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/configurator_test.py", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/configurator_test.py", []string{
"1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9",
"edf909edb9319c5e615e4ce73da47bbdca388ebe",
"d14f793a6cd7169ef708a4fc276ad876bd3edd4e",
@@ -219,7 +218,7 @@ var revListTests = [...]struct {
*/
/*
// this contains a cherry-pick at 094d0e7d5d691 (with 3f34438d)
- {"https://github.com/jamesob/desk.git", "master", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "desk", []string{
+ {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "desk", []string{
"ffcda27c2de6768ee83f3f4a027fa4ab57d50f09",
"a0c1e853158ccbaf95574220bbf3b54509034a9f",
"decfc524570c407d6bba0f217e534c8b47dbdbee",
@@ -250,7 +249,7 @@ var revListTests = [...]struct {
}},
*/
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "InstallSpinnaker.sh", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "InstallSpinnaker.sh", []string{
"ce9f123d790717599aaeb76bc62510de437761be",
"23673af3ad70b50bba7fdafadc2323302f5ba520",
"b7015a5d36990d69a054482556127b9c7404a24a",
@@ -286,7 +285,7 @@ var revListTests = [...]struct {
}},
*/
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/default-spinnaker-local.yml", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/default-spinnaker-local.yml", []string{
"ae904e8d60228c21c47368f6a10f1cc9ca3aeebf",
"99534ecc895fe17a1d562bb3049d4168a04d0865",
"caf6d62e8285d4681514dd8027356fb019bc97ff",
@@ -303,7 +302,7 @@ var revListTests = [...]struct {
}},
*/
/*
- {"https://github.com/spinnaker/spinnaker.git", "master", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/spinnaker.yml", []string{
+ {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/spinnaker.yml", []string{
"ae904e8d60228c21c47368f6a10f1cc9ca3aeebf",
"caf6d62e8285d4681514dd8027356fb019bc97ff",
"eaf7614cad81e8ab5c813dd4821129d0c04ea449",
@@ -327,25 +326,28 @@ func (s *SuiteCommon) TestRevList(c *C) {
commit, err := repo.Commit(core.NewHash(t.commit))
c.Assert(err, IsNil)
- revs, err := New(repo, commit, t.path)
- c.Assert(err, IsNil)
+ revs, err := NewRevs(repo, commit, t.path)
+ c.Assert(err, IsNil, Commentf("\nrepo=%s, commit=%s, path=%s\n",
+ t.repo, t.commit, t.path))
- c.Assert(len(revs), Equals, len(t.revs), Commentf("\nrepo=%s, branch=%s, commit=%s, path=%s\n EXPECTED (len %d)\n%s\n OBTAINED (len %d)\n%s\n",
- t.repo, t.branch, t.commit, t.path, len(t.revs), t.revs, len(revs), revs.String()))
+ c.Assert(len(revs), Equals, len(t.revs), Commentf("\nrepo=%s, commit=%s, path=%s\n EXPECTED (len %d)\n%s\n OBTAINED (len %d)\n%s\n",
+ t.repo, t.commit, t.path, len(t.revs), t.revs, len(revs), revs.GoString()))
for i := range revs {
if revs[i].Hash.String() != t.revs[i] {
commit, err := repo.Commit(core.NewHash(t.revs[i]))
c.Assert(err, IsNil)
- if equivalent(t.path, revs[i], commit) {
+ equiv, err := equivalent(t.path, revs[i], commit)
+ c.Assert(err, IsNil)
+ if equiv {
fmt.Printf("cherry-pick detected: %s %s\n", revs[i].Hash.String(), t.revs[i])
} else {
- c.Fatalf("\nrepo=%s, branch=%s, commit=%s, path=%s, \n%s",
- t.repo, t.branch, t.commit, t.path, compareSideBySide(t.revs, revs))
+ c.Fatalf("\nrepo=%s, commit=%s, path=%s, \n%s",
+ t.repo, t.commit, t.path, compareSideBySide(t.revs, revs))
}
}
}
- fmt.Printf("OK repo=%s, branch=%s, commit=%s, path=%s\n",
- t.repo, t.branch, t.commit, t.path)
+ fmt.Printf("OK repo=%s, commit=%s, path=%s\n",
+ t.repo, t.commit, t.path)
}
}
@@ -380,7 +382,9 @@ var cherryPicks = [...][]string{
func (s *SuiteCommon) TestEquivalent(c *C) {
for _, t := range cherryPicks {
cs := s.commits(c, t[0], t[2], t[3])
- c.Assert(equivalent(t[1], cs[0], cs[1]), Equals, true, Commentf("repo=%s, file=%s, a=%s b=%s", t[0], t[1], t[2], t[3]))
+ equiv, err := equivalent(t[1], cs[0], cs[1])
+ c.Assert(err, IsNil)
+ c.Assert(equiv, Equals, true, Commentf("repo=%s, file=%s, a=%s b=%s", t[0], t[1], t[2], t[3]))
}
}
diff --git a/tree.go b/tree.go
index 5e79555..2ca084e 100644
--- a/tree.go
+++ b/tree.go
@@ -115,9 +115,3 @@ func (i *TreeIter) Next() (*Tree, error) {
tree := &Tree{r: i.r}
return tree, tree.Decode(obj)
}
-
-type File struct {
- Name string
- io.Reader
- Hash core.Hash
-}