fork of go-git with some jj specific features
at main 4.4 kB view raw
1package commitgraph 2 3import ( 4 "math" 5 6 "github.com/go-git/go-git/v5/plumbing" 7 8 "github.com/emirpasic/gods/trees/binaryheap" 9) 10 11// commitNodeStackable represents a common interface between heaps and stacks 12type commitNodeStackable interface { 13 Push(c CommitNode) 14 Pop() (CommitNode, bool) 15 Peek() (CommitNode, bool) 16 Size() int 17} 18 19// commitNodeLifo is a stack implementation using an underlying slice 20type commitNodeLifo struct { 21 l []CommitNode 22} 23 24// Push pushes a new CommitNode to the stack 25func (l *commitNodeLifo) Push(c CommitNode) { 26 l.l = append(l.l, c) 27} 28 29// Pop pops the most recently added CommitNode from the stack 30func (l *commitNodeLifo) Pop() (CommitNode, bool) { 31 if len(l.l) == 0 { 32 return nil, false 33 } 34 c := l.l[len(l.l)-1] 35 l.l = l.l[:len(l.l)-1] 36 return c, true 37} 38 39// Peek returns the most recently added CommitNode from the stack without removing it 40func (l *commitNodeLifo) Peek() (CommitNode, bool) { 41 if len(l.l) == 0 { 42 return nil, false 43 } 44 return l.l[len(l.l)-1], true 45} 46 47// Size returns the number of CommitNodes in the stack 48func (l *commitNodeLifo) Size() int { 49 return len(l.l) 50} 51 52// commitNodeHeap is a stack implementation using an underlying binary heap 53type commitNodeHeap struct { 54 *binaryheap.Heap 55} 56 57// Push pushes a new CommitNode to the heap 58func (h *commitNodeHeap) Push(c CommitNode) { 59 h.Heap.Push(c) 60} 61 62// Pop removes top element on heap and returns it, or nil if heap is empty. 63// Second return parameter is true, unless the heap was empty and there was nothing to pop. 64func (h *commitNodeHeap) Pop() (CommitNode, bool) { 65 c, ok := h.Heap.Pop() 66 if !ok { 67 return nil, false 68 } 69 return c.(CommitNode), true 70} 71 72// Peek returns top element on the heap without removing it, or nil if heap is empty. 73// Second return parameter is true, unless the heap was empty and there was nothing to peek. 74func (h *commitNodeHeap) Peek() (CommitNode, bool) { 75 c, ok := h.Heap.Peek() 76 if !ok { 77 return nil, false 78 } 79 return c.(CommitNode), true 80} 81 82// Size returns number of elements within the heap. 83func (h *commitNodeHeap) Size() int { 84 return h.Heap.Size() 85} 86 87// generationAndDateOrderComparator compares two CommitNode objects based on their generation and commit time. 88// If the left CommitNode object is in a higher generation or is newer than the right one, it returns a -1. 89// If the left CommitNode object is in a lower generation or is older than the right one, it returns a 1. 90// If the two CommitNode objects have the same commit time and generation, it returns 0. 91func generationAndDateOrderComparator(left, right interface{}) int { 92 leftCommit := left.(CommitNode) 93 rightCommit := right.(CommitNode) 94 95 // if GenerationV2 is MaxUint64, then the node is not in the graph 96 if leftCommit.GenerationV2() == math.MaxUint64 { 97 if rightCommit.GenerationV2() == math.MaxUint64 { 98 switch { 99 case rightCommit.CommitTime().Before(leftCommit.CommitTime()): 100 return -1 101 case leftCommit.CommitTime().Before(rightCommit.CommitTime()): 102 return 1 103 } 104 return 0 105 } 106 // left is not in the graph, but right is, so it is newer than the right 107 return -1 108 } 109 110 if rightCommit.GenerationV2() == math.MaxInt64 { 111 // the right is not in the graph, therefore the left is before the right 112 return 1 113 } 114 115 if leftCommit.GenerationV2() == 0 || rightCommit.GenerationV2() == 0 { 116 // We need to assess generation and date 117 if leftCommit.Generation() < rightCommit.Generation() { 118 return 1 119 } 120 if leftCommit.Generation() > rightCommit.Generation() { 121 return -1 122 } 123 switch { 124 case rightCommit.CommitTime().Before(leftCommit.CommitTime()): 125 return -1 126 case leftCommit.CommitTime().Before(rightCommit.CommitTime()): 127 return 1 128 } 129 return 0 130 } 131 132 if leftCommit.GenerationV2() < rightCommit.GenerationV2() { 133 return 1 134 } 135 if leftCommit.GenerationV2() > rightCommit.GenerationV2() { 136 return -1 137 } 138 139 return 0 140} 141 142// composeIgnores composes the ignore list with the provided seenExternal list 143func composeIgnores(ignore []plumbing.Hash, seenExternal map[plumbing.Hash]bool) map[plumbing.Hash]struct{} { 144 if len(ignore) == 0 { 145 seen := make(map[plumbing.Hash]struct{}) 146 for h, ext := range seenExternal { 147 if ext { 148 seen[h] = struct{}{} 149 } 150 } 151 return seen 152 } 153 154 seen := make(map[plumbing.Hash]struct{}) 155 for _, h := range ignore { 156 seen[h] = struct{}{} 157 } 158 for h, ext := range seenExternal { 159 if ext { 160 seen[h] = struct{}{} 161 } 162 } 163 return seen 164}