119 lines
3.7 KiB
Go
119 lines
3.7 KiB
Go
package buildstep
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// The states `pauses` of the build seats, whose three seats hold the same layouts (the part `build-step`): a node's
|
|
// pause under `paused.<node>`, its capacity under `capacity.<node>`.
|
|
|
|
// PausesState is the name of the state.
|
|
const PausesState = "pauses"
|
|
|
|
// PauseKey is the key of a node's pause.
|
|
func PauseKey(node string) (string, error) {
|
|
if err := checkNode(node); err != nil {
|
|
return "", err
|
|
}
|
|
return "paused." + node, nil
|
|
}
|
|
|
|
// CapacityKey is the key of a node's capacity.
|
|
func CapacityKey(node string) (string, error) {
|
|
if err := checkNode(node); err != nil {
|
|
return "", err
|
|
}
|
|
return "capacity." + node, nil
|
|
}
|
|
|
|
// Pause is whether a node takes no new ask, and who said so.
|
|
type Pause struct {
|
|
V int `json:"v"`
|
|
Paused bool `json:"paused"`
|
|
By string `json:"by,omitempty"`
|
|
At time.Time `json:"at,omitzero"`
|
|
}
|
|
|
|
// EncodePause is p as a pauses value.
|
|
func EncodePause(p Pause) ([]byte, error) {
|
|
p.V = Version
|
|
p.At = p.At.UTC()
|
|
return json.Marshal(p)
|
|
}
|
|
|
|
// DecodePause reads a pause, refusing another version.
|
|
func DecodePause(data []byte) (Pause, error) {
|
|
var p Pause
|
|
if err := decodeVersioned(data, &p, func() int { return p.V }); err != nil {
|
|
return Pause{}, err
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// Capacity is how many steps a node runs at once, and why.
|
|
type Capacity struct {
|
|
V int `json:"v"`
|
|
Effective int `json:"effective"`
|
|
Configured int `json:"configured"`
|
|
ConfiguredFrom string `json:"configured-from,omitempty"`
|
|
QuotaCores float64 `json:"quota-cores,omitempty"`
|
|
QuotaFrom string `json:"quota-from"`
|
|
CoresPerStep float64 `json:"cores-per-step"`
|
|
ByCPU int `json:"by-cpu,omitempty"`
|
|
BuildHours string `json:"build-hours,omitempty"`
|
|
OutsideHours bool `json:"outside-hours,omitempty"`
|
|
BuildHoursFault string `json:"build-hours-fault,omitempty"`
|
|
Ineligible string `json:"ineligible,omitempty"`
|
|
Why string `json:"why"`
|
|
At time.Time `json:"at,omitzero"`
|
|
}
|
|
|
|
// EncodeCapacity is c as a pauses value.
|
|
func EncodeCapacity(c Capacity) ([]byte, error) {
|
|
c.V = Version
|
|
c.At = c.At.UTC()
|
|
return json.Marshal(c)
|
|
}
|
|
|
|
// DecodeCapacity reads a capacity, refusing another version.
|
|
func DecodeCapacity(data []byte) (Capacity, error) {
|
|
var c Capacity
|
|
if err := decodeVersioned(data, &c, func() int { return c.V }); err != nil {
|
|
return Capacity{}, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func decodeVersioned(data []byte, into any, version func() int) error {
|
|
if err := json.Unmarshal(data, into); err != nil {
|
|
return fmt.Errorf("buildstep: value does not fit its shape: %w", err)
|
|
}
|
|
if v := version(); v != Version {
|
|
return fmt.Errorf("%w: a value of version %d, this reader reads %d", ErrUnknownVersion, v, Version)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ComposerKey is the key a composer build is kept under: the fetched commit, the directory, the package and the
|
|
// toolchain it ran with. The mesh package versions the ask names are an input of the build, so they are in the key,
|
|
// sorted, when there are any; an ask that names none gets the key it always had (issue 1921).
|
|
func ComposerKey(repository, commit, dir, pkg string, toolchain ToolchainUsed, versions PackageVersions) string {
|
|
parts := []string{repository, commit, dir, pkg, toolchain.Version, toolchain.Recipe}
|
|
pkgs := make([]string, 0, len(versions))
|
|
for p := range versions {
|
|
pkgs = append(pkgs, p)
|
|
}
|
|
sort.Strings(pkgs)
|
|
for _, p := range pkgs {
|
|
parts = append(parts, p+"="+versions[p])
|
|
}
|
|
sum := sha256.Sum256([]byte(strings.Join(parts, "\n")))
|
|
return "composer-" + hex.EncodeToString(sum[:8])
|
|
}
|