mirror of
https://github.com/go-gitea/gitea
synced 2024-09-19 18:26:04 +00:00
106 lines
2.3 KiB
Go
106 lines
2.3 KiB
Go
|
package commitgraph
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
|
||
|
"github.com/emirpasic/gods/trees/binaryheap"
|
||
|
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/storer"
|
||
|
)
|
||
|
|
||
|
type commitNodeIteratorByCTime struct {
|
||
|
heap *binaryheap.Heap
|
||
|
seenExternal map[plumbing.Hash]bool
|
||
|
seen map[plumbing.Hash]bool
|
||
|
}
|
||
|
|
||
|
// NewCommitNodeIterCTime returns a CommitNodeIter that walks the commit history,
|
||
|
// starting at the given commit and visiting its parents while preserving Committer Time order.
|
||
|
// this appears to be the closest order to `git log`
|
||
|
// The given callback will be called for each visited commit. Each commit will
|
||
|
// be visited only once. If the callback returns an error, walking will stop
|
||
|
// and will return the error. Other errors might be returned if the history
|
||
|
// cannot be traversed (e.g. missing objects). Ignore allows to skip some
|
||
|
// commits from being iterated.
|
||
|
func NewCommitNodeIterCTime(
|
||
|
c CommitNode,
|
||
|
seenExternal map[plumbing.Hash]bool,
|
||
|
ignore []plumbing.Hash,
|
||
|
) CommitNodeIter {
|
||
|
seen := make(map[plumbing.Hash]bool)
|
||
|
for _, h := range ignore {
|
||
|
seen[h] = true
|
||
|
}
|
||
|
|
||
|
heap := binaryheap.NewWith(func(a, b interface{}) int {
|
||
|
if a.(CommitNode).CommitTime().Before(b.(CommitNode).CommitTime()) {
|
||
|
return 1
|
||
|
}
|
||
|
return -1
|
||
|
})
|
||
|
|
||
|
heap.Push(c)
|
||
|
|
||
|
return &commitNodeIteratorByCTime{
|
||
|
heap: heap,
|
||
|
seenExternal: seenExternal,
|
||
|
seen: seen,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (w *commitNodeIteratorByCTime) Next() (CommitNode, error) {
|
||
|
var c CommitNode
|
||
|
for {
|
||
|
cIn, ok := w.heap.Pop()
|
||
|
if !ok {
|
||
|
return nil, io.EOF
|
||
|
}
|
||
|
c = cIn.(CommitNode)
|
||
|
cID := c.ID()
|
||
|
|
||
|
if w.seen[cID] || w.seenExternal[cID] {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
w.seen[cID] = true
|
||
|
|
||
|
for i, h := range c.ParentHashes() {
|
||
|
if w.seen[h] || w.seenExternal[h] {
|
||
|
continue
|
||
|
}
|
||
|
pc, err := c.ParentNode(i)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
w.heap.Push(pc)
|
||
|
}
|
||
|
|
||
|
return c, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (w *commitNodeIteratorByCTime) ForEach(cb func(CommitNode) error) error {
|
||
|
for {
|
||
|
c, err := w.Next()
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
}
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = cb(c)
|
||
|
if err == storer.ErrStop {
|
||
|
break
|
||
|
}
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (w *commitNodeIteratorByCTime) Close() {}
|