mesh/merge-gate head bfc64ac65ea1 merged into trunk 26de6bc62558 — pass: builds mesh-delivery-indexer, new: modules/mesh-delivery-builder → novox; no bus s…
mesh/repo-check head bfc64ac65ea1 merged into trunk 26de6bc62558 — pass: its merge-check.sh passed
mesh/delivery delivered
95 lines
3.7 KiB
Go
95 lines
3.7 KiB
Go
// Package build is the builder's logic (novox/hq ADR 0453 clause 4, ADR 0478), apart from the bus: what a manifest asks
|
|
// to be built and where, the claim of a build key, the choice of build nodes, the build modules' long steps and the run of
|
|
// one build. The bus is reached through the small interfaces here, so each part is tested with fakes.
|
|
package build
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// The build modules a task is given to, and the language whose toolchain each reports (the indexer's ToolchainModules).
|
|
const (
|
|
GoBuildModule = "mesh-build-go"
|
|
NodeBuildModule = "mesh-build-node"
|
|
)
|
|
|
|
// RefusedPrefix opens the error of a build key that is failed for a kind no builder builds yet (ADR 0478 clause 2): such
|
|
// a key is not built again as a new revision.
|
|
const RefusedPrefix = "refused kind:"
|
|
|
|
// Task is one artifact to build: its name and kind in the manifest, the build module that builds it and the language
|
|
// of the toolchain it is built with.
|
|
type Task struct {
|
|
Artifact string
|
|
Kind string
|
|
Module string
|
|
Language string
|
|
}
|
|
|
|
// Plan is what a manifest asks the builder to build, by artifact name.
|
|
type Plan struct{ Tasks []Task }
|
|
|
|
// Modules are the build modules the plan calls, sorted.
|
|
func (p Plan) Modules() []string {
|
|
seen := map[string]bool{}
|
|
var out []string
|
|
for _, t := range p.Tasks {
|
|
if !seen[t.Module] {
|
|
seen[t.Module] = true
|
|
out = append(out, t.Module)
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// NeedsToolchain is whether any task the build module builds is built with a toolchain: a bundle is, an archive is not
|
|
// (the indexer gives an archive no language, so a fingerprint names no toolchain for it; ADR 0478 clause 1).
|
|
func (p Plan) NeedsToolchain(module string) bool {
|
|
for _, t := range p.Tasks {
|
|
if t.Module == module && t.Kind != catalogue.ArtifactArchive {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Refused is the error of a plan the builder does not build: an artifact of a kind (or of a language) it has no build
|
|
// module for.
|
|
type Refused struct{ Artifact, What string }
|
|
|
|
func (r *Refused) Error() string {
|
|
return fmt.Sprintf("%s %s (artifact %s): the builder builds Go and TypeScript bundles and archives; build-agent builds it", RefusedPrefix, r.What, r.Artifact)
|
|
}
|
|
|
|
// PlanOf is the plan of a manifest (ADR 0478 clauses 1 and 2): a Go bundle and an archive are built by the Go build
|
|
// module, a TypeScript bundle by the Node one, each in the order of the artifacts' names. A manifest with an image,
|
|
// upstream or package artifact, or a bundle of another language, is refused as a whole, naming the first such artifact
|
|
// by name. A manifest with no artifact has an empty plan.
|
|
func PlanOf(m catalogue.Manifest) (Plan, error) {
|
|
if m.Build == nil {
|
|
return Plan{}, nil
|
|
}
|
|
artifacts := append([]catalogue.Artifact(nil), m.Build.Artifacts...)
|
|
sort.Slice(artifacts, func(i, j int) bool { return artifacts[i].Name < artifacts[j].Name })
|
|
var p Plan
|
|
for _, a := range artifacts {
|
|
switch {
|
|
case a.Kind == catalogue.ArtifactArchive:
|
|
p.Tasks = append(p.Tasks, Task{Artifact: a.Name, Kind: a.Kind, Module: GoBuildModule, Language: "go"})
|
|
case a.Kind == catalogue.ArtifactBundle && a.Language == "go":
|
|
p.Tasks = append(p.Tasks, Task{Artifact: a.Name, Kind: a.Kind, Module: GoBuildModule, Language: "go"})
|
|
case a.Kind == catalogue.ArtifactBundle && a.Language == "typescript":
|
|
p.Tasks = append(p.Tasks, Task{Artifact: a.Name, Kind: a.Kind, Module: NodeBuildModule, Language: "typescript"})
|
|
case a.Kind == catalogue.ArtifactBundle:
|
|
return Plan{}, &Refused{Artifact: a.Name, What: fmt.Sprintf("bundle of language %q", a.Language)}
|
|
default:
|
|
return Plan{}, &Refused{Artifact: a.Name, What: a.Kind}
|
|
}
|
|
}
|
|
return p, nil
|
|
}
|