64 lines
2.1 KiB
Go
64 lines
2.1 KiB
Go
package build
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// ChooseNodes picks up to want build nodes for a language (ADR 0478 clause 3): the nodes whose toolchains key reports the
|
|
// version the nodes agree on, the ones with the fewest steps the builder has running there first, a tie broken by the
|
|
// node's name. It answers the toolchain they agree on. When nothing is reported, or the nodes report different versions
|
|
// (so the indexer agreed none), it fails naming the language and why. The build module's health is not read here: a node
|
|
// whose module refuses on its toolchain refuses the step, and the build fails naming it.
|
|
func ChooseNodes(language string, entries []delivery.NodeToolchain, running map[string]int, want int) ([]string, delivery.Toolchain2, error) {
|
|
tc, none := delivery.AgreedToolchain(entries)
|
|
if none != "" {
|
|
return nil, delivery.Toolchain2{}, fmt.Errorf("no %s build node qualifies: %s", language, none)
|
|
}
|
|
nodes := make([]string, 0, len(entries))
|
|
seen := map[string]bool{}
|
|
for _, e := range entries {
|
|
if !seen[e.Node] {
|
|
seen[e.Node] = true
|
|
nodes = append(nodes, e.Node)
|
|
}
|
|
}
|
|
sort.Slice(nodes, func(i, j int) bool {
|
|
if running[nodes[i]] != running[nodes[j]] {
|
|
return running[nodes[i]] < running[nodes[j]]
|
|
}
|
|
return nodes[i] < nodes[j]
|
|
})
|
|
if len(nodes) > want {
|
|
nodes = nodes[:want]
|
|
}
|
|
return nodes, tc, nil
|
|
}
|
|
|
|
// Agree is the one digest every node built an artifact to (ADR 0478 clause 4), or an error naming each node and its
|
|
// digest when they differ. One node's digest agrees with itself.
|
|
func Agree(artifact string, byNode map[string]string) (string, error) {
|
|
nodes := make([]string, 0, len(byNode))
|
|
for n := range byNode {
|
|
nodes = append(nodes, n)
|
|
}
|
|
sort.Strings(nodes)
|
|
var first string
|
|
for i, n := range nodes {
|
|
if i == 0 {
|
|
first = byNode[n]
|
|
continue
|
|
}
|
|
if byNode[n] != first {
|
|
msg := fmt.Sprintf("the nodes built %s to different digests:", artifact)
|
|
for _, n := range nodes {
|
|
msg += fmt.Sprintf(" %s %s;", n, byNode[n])
|
|
}
|
|
return "", fmt.Errorf("%s", msg[:len(msg)-1])
|
|
}
|
|
}
|
|
return first, nil
|
|
}
|