1package object 2 3import ( 4 "io" 5 6 "github.com/emirpasic/gods/trees/binaryheap" 7 8 "github.com/jesseduffield/go-git/v5/plumbing" 9 "github.com/jesseduffield/go-git/v5/plumbing/storer" 10) 11 12type commitIteratorByCTime struct { 13 seenExternal map[plumbing.Hash]bool 14 seen map[plumbing.Hash]bool 15 heap *binaryheap.Heap 16} 17 18// NewCommitIterCTime returns a CommitIter that walks the commit history, 19// starting at the given commit and visiting its parents while preserving Committer Time order. 20// this appears to be the closest order to `git log` 21// The given callback will be called for each visited commit. Each commit will 22// be visited only once. If the callback returns an error, walking will stop 23// and will return the error. Other errors might be returned if the history 24// cannot be traversed (e.g. missing objects). Ignore allows to skip some 25// commits from being iterated. 26func NewCommitIterCTime( 27 c *Commit, 28 seenExternal map[plumbing.Hash]bool, 29 ignore []plumbing.Hash, 30) CommitIter { 31 seen := make(map[plumbing.Hash]bool) 32 for _, h := range ignore { 33 seen[h] = true 34 } 35 36 heap := binaryheap.NewWith(func(a, b interface{}) int { 37 if a.(*Commit).Committer.When.Before(b.(*Commit).Committer.When) { 38 return 1 39 } 40 return -1 41 }) 42 heap.Push(c) 43 44 return &commitIteratorByCTime{ 45 seenExternal: seenExternal, 46 seen: seen, 47 heap: heap, 48 } 49} 50 51func (w *commitIteratorByCTime) Next() (*Commit, error) { 52 var c *Commit 53 for { 54 cIn, ok := w.heap.Pop() 55 if !ok { 56 return nil, io.EOF 57 } 58 c = cIn.(*Commit) 59 60 if w.seen[c.Hash] || w.seenExternal[c.Hash] { 61 continue 62 } 63 64 w.seen[c.Hash] = true 65 66 for _, h := range c.ParentHashes { 67 if w.seen[h] || w.seenExternal[h] { 68 continue 69 } 70 pc, err := GetCommit(c.s, h) 71 if err != nil { 72 return nil, err 73 } 74 w.heap.Push(pc) 75 } 76 77 return c, nil 78 } 79} 80 81func (w *commitIteratorByCTime) ForEach(cb func(*Commit) error) error { 82 for { 83 c, err := w.Next() 84 if err == io.EOF { 85 break 86 } 87 if err != nil { 88 return err 89 } 90 91 err = cb(c) 92 if err == storer.ErrStop { 93 break 94 } 95 if err != nil { 96 return err 97 } 98 } 99 100 return nil 101} 102 103func (w *commitIteratorByCTime) Close() {} 104