| package object |
| |
| import ( |
| "gopkg.in/src-d/go-git.v4/plumbing/storer" |
| "io" |
| ) |
| |
| type commitFileIter struct { |
| fileName string |
| sourceIter CommitIter |
| currentCommit *Commit |
| } |
| |
| // NewCommitFileIterFromIter returns a commit iterator which performs diffTree between |
| // successive trees returned from the commit iterator from the argument. The purpose of this is |
| // to find the commits that explain how the files that match the path came to be. |
| func NewCommitFileIterFromIter(fileName string, commitIter CommitIter) CommitIter { |
| iterator := new(commitFileIter) |
| iterator.sourceIter = commitIter |
| iterator.fileName = fileName |
| return iterator |
| } |
| |
| func (c *commitFileIter) Next() (*Commit, error) { |
| if c.currentCommit == nil { |
| var err error |
| c.currentCommit, err = c.sourceIter.Next() |
| if err != nil { |
| return nil, err |
| } |
| } |
| commit, commitErr := c.getNextFileCommit() |
| |
| // Setting current-commit to nil to prevent unwanted states when errors are raised |
| if commitErr != nil { |
| c.currentCommit = nil |
| } |
| return commit, commitErr |
| } |
| |
| func (c *commitFileIter) getNextFileCommit() (*Commit, error) { |
| for { |
| // Parent-commit can be nil if the current-commit is the initial commit |
| parentCommit, parentCommitErr := c.sourceIter.Next() |
| if parentCommitErr != nil { |
| // If the parent-commit is beyond the initial commit, keep it nil |
| if parentCommitErr != io.EOF { |
| return nil, parentCommitErr |
| } |
| parentCommit = nil |
| } |
| |
| // Fetch the trees of the current and parent commits |
| currentTree, currTreeErr := c.currentCommit.Tree() |
| if currTreeErr != nil { |
| return nil, currTreeErr |
| } |
| |
| var parentTree *Tree |
| if parentCommit != nil { |
| var parentTreeErr error |
| parentTree, parentTreeErr = parentCommit.Tree() |
| if parentTreeErr != nil { |
| return nil, parentTreeErr |
| } |
| } |
| |
| // Find diff between current and parent trees |
| changes, diffErr := DiffTree(currentTree, parentTree) |
| if diffErr != nil { |
| return nil, diffErr |
| } |
| |
| foundChangeForFile := false |
| for _, change := range changes { |
| if change.name() == c.fileName { |
| foundChangeForFile = true |
| break |
| } |
| } |
| |
| // Storing the current-commit in-case a change is found, and |
| // Updating the current-commit for the next-iteration |
| prevCommit := c.currentCommit |
| c.currentCommit = parentCommit |
| |
| if foundChangeForFile == true { |
| return prevCommit, nil |
| } |
| |
| // If not matches found and if parent-commit is beyond the initial commit, then return with EOF |
| if parentCommit == nil { |
| return nil, io.EOF |
| } |
| } |
| } |
| |
| func (c *commitFileIter) ForEach(cb func(*Commit) error) error { |
| for { |
| commit, nextErr := c.Next() |
| if nextErr != nil { |
| return nextErr |
| } |
| err := cb(commit) |
| if err == storer.ErrStop { |
| return nil |
| } else if err != nil { |
| return err |
| } |
| } |
| } |
| |
| func (c *commitFileIter) Close() { |
| c.sourceIter.Close() |
| } |