diff options
-rw-r--r-- | _examples/log/main.go | 5 | ||||
-rw-r--r-- | options.go | 9 | ||||
-rw-r--r-- | plumbing/object/commit_walker_limit.go | 65 | ||||
-rw-r--r-- | repository.go | 9 | ||||
-rw-r--r-- | repository_test.go | 132 |
5 files changed, 218 insertions, 2 deletions
diff --git a/_examples/log/main.go b/_examples/log/main.go index ba0597a..5807515 100644 --- a/_examples/log/main.go +++ b/_examples/log/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" "gopkg.in/src-d/go-git.v4" . "gopkg.in/src-d/go-git.v4/_examples" @@ -31,7 +32,9 @@ func main() { CheckIfError(err) // ... retrieves the commit history - cIter, err := r.Log(&git.LogOptions{From: ref.Hash()}) + since := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) + until := time.Date(2019, 7, 30, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&git.LogOptions{From: ref.Hash(), Since: &since, Until: &until}) CheckIfError(err) // ... just iterates over the commits, printing it @@ -4,6 +4,7 @@ import ( "errors" "regexp" "strings" + "time" "golang.org/x/crypto/openpgp" "gopkg.in/src-d/go-git.v4/config" @@ -348,6 +349,14 @@ type LogOptions struct { // It is equivalent to running `git log --all`. // If set on true, the From option will be ignored. All bool + + // Show commits more recent than a specific date. + // It is equivalent to running `git log --since <date>` or `git log --after <date>`. + Since *time.Time + + // Show commits older than a specific date. + // It is equivalent to running `git log --until <date>` or `git log --before <date>`. + Until *time.Time } var ( diff --git a/plumbing/object/commit_walker_limit.go b/plumbing/object/commit_walker_limit.go new file mode 100644 index 0000000..ee56e50 --- /dev/null +++ b/plumbing/object/commit_walker_limit.go @@ -0,0 +1,65 @@ +package object + +import ( + "io" + "time" + + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type commitLimitIter struct { + sourceIter CommitIter + limitOptions LogLimitOptions +} + +type LogLimitOptions struct { + Since *time.Time + Until *time.Time +} + +func NewCommitLimitIterFromIter(commitIter CommitIter, limitOptions LogLimitOptions) CommitIter { + iterator := new(commitLimitIter) + iterator.sourceIter = commitIter + iterator.limitOptions = limitOptions + return iterator +} + +func (c *commitLimitIter) Next() (*Commit, error) { + for { + commit, err := c.sourceIter.Next() + if err != nil { + return nil, err + } + + if c.limitOptions.Since != nil && commit.Committer.When.Before(*c.limitOptions.Since) { + continue + } + if c.limitOptions.Until != nil && commit.Committer.When.After(*c.limitOptions.Until) { + continue + } + return commit, nil + } +} + +func (c *commitLimitIter) ForEach(cb func(*Commit) error) error { + for { + commit, nextErr := c.Next() + if nextErr == io.EOF { + break + } + if nextErr != nil { + return nextErr + } + err := cb(commit) + if err == storer.ErrStop { + return nil + } else if err != nil { + return err + } + } + return nil +} + +func (c *commitLimitIter) Close() { + c.sourceIter.Close() +} diff --git a/repository.go b/repository.go index 2251d6c..11269ef 100644 --- a/repository.go +++ b/repository.go @@ -1068,6 +1068,11 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) { it = r.logWithFile(*o.FileName, it, o.All) } + if o.Since != nil || o.Until != nil { + limitOptions := object.LogLimitOptions{Since: o.Since, Until: o.Until} + it = r.logWithLimit(it, limitOptions) + } + return it, nil } @@ -1097,6 +1102,10 @@ func (*Repository) logWithFile(fileName string, commitIter object.CommitIter, ch return object.NewCommitFileIterFromIter(fileName, commitIter, checkParent) } +func (*Repository) logWithLimit(commitIter object.CommitIter, limitOptions object.LogLimitOptions) object.CommitIter { + return object.NewCommitLimitIterFromIter(commitIter, limitOptions) +} + func commitIterFunc(order LogOrder) func(c *object.Commit) object.CommitIter { switch order { case LogOrderDefault: diff --git a/repository_test.go b/repository_test.go index 5fc6aeb..e85311f 100644 --- a/repository_test.go +++ b/repository_test.go @@ -14,6 +14,8 @@ import ( "testing" "time" + fixtures "gopkg.in/src-d/go-git-fixtures.v3" + "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/armor" openpgperr "golang.org/x/crypto/openpgp/errors" @@ -32,7 +34,6 @@ import ( "gopkg.in/src-d/go-billy.v4/memfs" "gopkg.in/src-d/go-billy.v4/osfs" "gopkg.in/src-d/go-billy.v4/util" - "gopkg.in/src-d/go-git-fixtures.v3" ) type RepositorySuite struct { @@ -1675,6 +1676,135 @@ func (s *RepositorySuite) TestLogFileWithError(c *C) { c.Assert(err, NotNil) } +func (s *RepositorySuite) TestLogLimitNext(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since}) + + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogLimitForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since, Until: &until}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + } + + expectedIndex := 0 + err = cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogAllLimitForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{Since: &since, Until: &until, All: true}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + } + + expectedIndex := 0 + err = cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(expectedIndex, Equals, 2) +} + +func (s *RepositorySuite) TestLogLimitWithOtherParamsFail(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + Since: &since, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + defer cIter.Close() + + _, iterErr := cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogLimitWithOtherParamsPass(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + until := time.Date(2015, 3, 31, 11, 43, 0, 0, time.UTC) + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + Until: &until, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + defer cIter.Close() + + commitVal, iterErr := cIter.Next() + c.Assert(iterErr, Equals, nil) + c.Assert(commitVal.Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") + + _, iterErr = cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + func (s *RepositorySuite) TestCommit(c *C) { r, _ := Init(memory.NewStorage(), nil) err := r.clone(context.Background(), &CloneOptions{ |