Files
mesh-delivery/modules/mesh-delivery-builder/buildrun/buildseats.go
T
jschoubben 84bcdb687a BL18: build modules found through their build seats' holders on the seat list
The builder finds a build module as the indexer's seed does: the build seat whose acting rule
`build` has an `on` matching the artifact's language or kind:image, and that seat's holder, read
from the seat list's definitions and the claims of the catalog half's manifests. Task.Module, every
lane key, the unpublished modules, the toolchain sources, the ends watched, the sayer and
builder_stuck (through `<seat>.steps`) derive from it; the floor's sources are the holders of the
seats git and mesh-catalog. buildrun.GoBuildModule, NodeBuildModule, LanguageOf,
buildstep.BuildModuleOf use, build.ImageBuildModule and StuckBuildModules are gone from the builder
(the checker keeps its own names in two small files until its part reads them from the list).

Builds: design 47 G §7, §428, §704, §204, A-82
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 00:04:34 +01:00

167 lines
5.6 KiB
Go

package buildrun
import (
"fmt"
"maps"
"slices"
"strings"
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
"git.novox.be/novox/mesh-sdk/go/seatdef"
)
// **The builder names no build module** (design 47 G §7, §428, §704; A-82): a build module is the holder of the build seat
// whose acting rule `build` has an `on` matching an artifact's language or `kind:image`, found on the seat list (the seat
// definitions) and the catalog half (the manifest that claims the seat), as the indexer's seed finds it. Every task's module and
// every lane's key is that holder's name as the seat list and the catalog half give it.
// BuildModule is one build seat and the module that holds it.
type BuildModule struct {
Seat string // the seat whose acting rule builds
Module string // the module holding the seat, empty while the catalog half names none
// Toolchain is the language of the toolchain the rule's `on` names, empty for a rule on `kind:image` (no toolchain).
Toolchain string
// ByKind is whether the rule is on `kind:image`: its artifacts have no language and its nodes come from the node-engine's have.
ByKind bool
}
// AskLanguage is the language of the seat's asks (sdkstep.AskSubject): the seat is named node-build-<language>.
func (m BuildModule) AskLanguage() string { return strings.TrimPrefix(m.Seat, "node-build-") }
// BuildSeats finds the build modules from the seat definitions and the holders of seats, both read at each call.
type BuildSeats struct {
// Defs are the seat definitions of the seat list; Holder is a seat's holder on the catalog half.
defs func() map[string]seatdef.Definition
holder func(seat string) (string, bool)
}
// NewBuildSeats is the finder over defs (the seat list's definitions, nil before it is read) and holder.
func NewBuildSeats(defs func() map[string]seatdef.Definition, holder func(seat string) (string, bool)) *BuildSeats {
return &BuildSeats{defs: defs, holder: holder}
}
func (s *BuildSeats) all() []BuildModule {
if s == nil || s.defs == nil {
return nil
}
defs := s.defs()
var out []BuildModule
for _, seat := range slices.Sorted(maps.Keys(defs)) {
for _, r := range defs[seat].Acts {
if r.Step != seatdef.StepBuild || r.Acting() == seatdef.OnEvery {
continue
}
m := BuildModule{Seat: seat, ByKind: r.On == seatdef.OnKindImage}
if !m.ByKind {
m.Toolchain = r.Acting()
}
if s.holder != nil {
m.Module, _ = s.holder(seat)
}
out = append(out, m)
break
}
}
return out
}
// All are the build seats with the module holding each, by seat name; a seat no catalog entry claims has no module.
func (s *BuildSeats) All() []BuildModule { return s.all() }
// Modules are the holders of the build seats, sorted, none that is unnamed.
func (s *BuildSeats) Modules() []string {
var out []string
for _, m := range s.all() {
if m.Module != "" {
out = append(out, m.Module)
}
}
slices.Sort(out)
return slices.Compact(out)
}
// OfModule is the build seat held by module.
func (s *BuildSeats) OfModule(module string) (BuildModule, bool) {
for _, m := range s.all() {
if m.Module == module && module != "" {
return m, true
}
}
return BuildModule{}, false
}
// OfSeat is the build seat named seat.
func (s *BuildSeats) OfSeat(seat string) (BuildModule, bool) {
for _, m := range s.all() {
if m.Seat == seat {
return m, true
}
}
return BuildModule{}, false
}
// For is the build module of an artifact: the build seat whose rule's `on` is language, or `kind:image` when the artifact's
// kind is image. None, or more than one, or a seat no entry claims, is the error.
func (s *BuildSeats) For(language, kind string) (BuildModule, error) {
var found []BuildModule
for _, m := range s.all() {
if (kind == "image" && m.ByKind) || (!m.ByKind && language != "" && strings.EqualFold(m.Toolchain, strings.TrimSpace(language))) {
found = append(found, m)
}
}
switch len(found) {
case 0:
return BuildModule{}, fmt.Errorf("no seat builds an artifact of language %q and kind %q", language, kind)
case 1:
if found[0].Module == "" {
return BuildModule{}, fmt.Errorf("no module claims %s, which builds an artifact of language %q and kind %q", found[0].Seat, language, kind)
}
return found[0], nil
}
return BuildModule{}, fmt.Errorf("the seats %v each build an artifact of language %q and kind %q", seatsOf(found), language, kind)
}
func seatsOf(ms []BuildModule) []string {
var out []string
for _, m := range ms {
out = append(out, m.Seat)
}
return out
}
// LanguageOf is the language of the toolchain the build module builds with, false for a module that is no build seat's holder
// or builds with none.
func (s *BuildSeats) LanguageOf(module string) (string, bool) {
m, ok := s.OfModule(module)
return m.Toolchain, ok && m.Toolchain != ""
}
// Languages are the languages of the toolchains the build seats' rules name, sorted.
func (s *BuildSeats) Languages() []string {
var out []string
for _, m := range s.all() {
if m.Toolchain != "" {
out = append(out, m.Toolchain)
}
}
slices.Sort(out)
return slices.Compact(out)
}
// OfAskLanguage is the build module whose seat takes the asks of an ask language (go, node or image): the seat the sdk names
// for it (buildstep.BuildSeat), held by the module the catalog half names.
func (s *BuildSeats) OfAskLanguage(language string) (BuildModule, error) {
seat, err := buildstep.BuildSeat(language)
if err != nil {
return BuildModule{}, err
}
m, ok := s.OfSeat(seat)
if !ok {
return BuildModule{}, fmt.Errorf("the seat list holds no build seat %s", seat)
}
if m.Module == "" {
return BuildModule{}, fmt.Errorf("no module claims %s", seat)
}
return m, nil
}