79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
package check
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// Turns holds the gate's merge turns (novox/hq ADR 0548 §3), by repository, as a watch of the gate's turns bucket puts them
|
|
// in: the checker claims no check of a repository a turn names, except the check of a waiting delivery's own heads, so an
|
|
// approved merge goes before a check not yet started. A bucket not there is read as empty.
|
|
type Turns struct {
|
|
mu sync.Mutex
|
|
byRepo map[string]delivery.Turn
|
|
}
|
|
|
|
// Put takes a value of the turns bucket in, or its delete, and answers whether what the checker holds changed. A value that
|
|
// is not a turn is dropped as a delete would be: a turn the checker cannot read holds nothing.
|
|
func (t *Turns) Put(key string, value []byte, deleted bool) bool {
|
|
repository, err := delivery.ParseTurnsKey(key)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
if t.byRepo == nil {
|
|
t.byRepo = map[string]delivery.Turn{}
|
|
}
|
|
cur, had := t.byRepo[repository]
|
|
if !deleted {
|
|
if turn, err := delivery.DecodeTurn(value); err == nil {
|
|
t.byRepo[repository] = turn
|
|
return !had || !delivery.SameTurn(cur, turn)
|
|
}
|
|
}
|
|
delete(t.byRepo, repository)
|
|
return had
|
|
}
|
|
|
|
// Holding names the first of the repositories (by name) a turn holds off the check of the heads, and the delivery that
|
|
// waits first in it; false when none does.
|
|
func (t *Turns) Holding(repositories []string, heads string) (string, delivery.TurnWait, bool) {
|
|
if t == nil {
|
|
return "", delivery.TurnWait{}, false
|
|
}
|
|
sorted := make([]string, 0, len(repositories))
|
|
for _, r := range repositories {
|
|
sorted = append(sorted, strings.ToLower(r))
|
|
}
|
|
sort.Strings(sorted)
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
for _, r := range sorted {
|
|
turn, ok := t.byRepo[r]
|
|
if !ok || !delivery.TurnHolds(turn, heads) {
|
|
continue
|
|
}
|
|
for _, w := range turn.Waiting {
|
|
if w.Heads != heads {
|
|
return r, w, true
|
|
}
|
|
}
|
|
}
|
|
return "", delivery.TurnWait{}, false
|
|
}
|
|
|
|
// All is every turn held now, by repository (a copy).
|
|
func (t *Turns) All() map[string]delivery.Turn {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
out := make(map[string]delivery.Turn, len(t.byRepo))
|
|
for r, turn := range t.byRepo {
|
|
out[r] = turn
|
|
}
|
|
return out
|
|
}
|