The builder says wait-held for a key queued behind a package, the package as its part and on (package:<ref>), on its stream waits, and wait-ended published once the key is claimed; a toolchain wait never ends by that, and a package wait never by a toolchain's end. Files: internal/build/waits.go (Package, On, WaitPublished), internal/build/run.go (Hold at the queued result, End at the claim), cmd/mesh-delivery-builder/waits.go (Part in the body, the End rule). Builds: design 47 G A-192, §499 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
136 lines
5.1 KiB
Go
136 lines
5.1 KiB
Go
package build
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
|
sdkstep "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/buildstep"
|
|
)
|
|
|
|
// **The builder's toolchain wait** (design 47 G §672, §267, §276): the builder holds an entry while its fingerprint names a
|
|
// toolchain version of its language other than the one the agreed toolchain of that language names.
|
|
const (
|
|
// WaitsTool is builder_waits, which reads the waits; ReleaseTool is builder_release, which builds the entry with the
|
|
// running build module (§276), a hand act written in the hand-act log.
|
|
WaitsTool = "builder_waits"
|
|
ReleaseTool = "builder_release"
|
|
// WaitsState is the builder's old state section of the waits, one key <module>.<fingerprint>.
|
|
WaitsState = "waits"
|
|
WaitsBucket = builds.BuilderModule + "_" + WaitsState
|
|
// ModeRelease is the Mode of a reasks value of builder_release.
|
|
ModeRelease = "release"
|
|
// WaitRan ends a wait when a toolchain-agreed names the version; WaitReleased when builder_release ended it.
|
|
WaitRan = "ran"
|
|
// WaitPublished ends the wait of a key queued behind a package, when the key is claimed (the package is published).
|
|
WaitPublished = "published"
|
|
WaitReleased = "released"
|
|
)
|
|
|
|
// ToolchainWait is one wait: the entry's module and fingerprint, and the toolchain it waits for.
|
|
type ToolchainWait struct {
|
|
Module string `json:"module"`
|
|
Fingerprint string `json:"fingerprint"`
|
|
Language string `json:"language"`
|
|
Version string `json:"version"`
|
|
Since time.Time `json:"since"`
|
|
// Package is the package version a key queued behind it waits for, `<name>@<version>` (ADR 0603 §8; design 47 G A-192): the wait is the
|
|
// package's, not a toolchain's, and Language and Version are empty.
|
|
Package string `json:"package,omitempty"`
|
|
}
|
|
|
|
// On is what the wait waits for, as the wait's `on` says it.
|
|
func (w ToolchainWait) On() string {
|
|
if w.Package != "" {
|
|
return "package:" + w.Package
|
|
}
|
|
return "toolchain:" + w.Language + "@" + w.Version
|
|
}
|
|
|
|
// Waits keeps the builder's waits: Hold writes one in the state waits and says wait-held, once per wait; End deletes it and
|
|
// says wait-ended with how, and answers whether one was held.
|
|
type Waits interface {
|
|
Hold(ctx context.Context, w ToolchainWait)
|
|
End(ctx context.Context, module, fp, how string) bool
|
|
}
|
|
|
|
// toolchainWait is the toolchain wait of a module's fingerprint, or false when no language of its plan names a version
|
|
// other than the agreed one (a language with no agreed toolchain is not a wait of §672).
|
|
func (b *Builder) toolchainWait(module string, m meshcatalog.ModulesByModuleValue, plan Plan) (ToolchainWait, bool) {
|
|
for _, bm := range plan.Modules() {
|
|
if !plan.NeedsToolchain(bm) {
|
|
continue
|
|
}
|
|
language, _ := b.Seats.LanguageOf(bm)
|
|
ag := sdkstep.ToolchainAgreement(b.Toolchains.Entries(language))
|
|
if want, ok := m.Toolchains[language]; ag.Wait == "" && ok && want.Version != ag.Toolchain.Version {
|
|
return ToolchainWait{Module: module, Fingerprint: m.Fp2, Language: language, Version: want.Version, Since: b.now()}, true
|
|
}
|
|
}
|
|
return ToolchainWait{}, false
|
|
}
|
|
|
|
// Release builds the held entry of module at fp with the running build module, now, and ends its wait released (design 47
|
|
// G §276, §672). It answers why nothing was done, or empty.
|
|
func (b *Builder) Release(ctx context.Context, module, fp, why, by string) string {
|
|
b.init()
|
|
key, err := builds.BuilderBuildKey(module, fp)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
if b.Waits == nil {
|
|
return "this builder keeps no waits"
|
|
}
|
|
b.mu.Lock()
|
|
m, known := b.known[module]
|
|
b.mu.Unlock()
|
|
if !known || m.Fp2 != fp || m.Manifest == "" {
|
|
return fmt.Sprintf("module %s does not have the fingerprint %s now: the builder builds the module's current fingerprint", module, fp)
|
|
}
|
|
b.mu.Lock()
|
|
if b.released == nil {
|
|
b.released = map[string]bool{}
|
|
}
|
|
b.released[key] = true
|
|
b.mu.Unlock()
|
|
if !b.Waits.End(ctx, module, fp, WaitReleased) {
|
|
b.mu.Lock()
|
|
delete(b.released, key)
|
|
b.mu.Unlock()
|
|
return fmt.Sprintf("%s holds no toolchain wait: %s builds a failed key again", key, BuildAgainTool)
|
|
}
|
|
b.logf("%s: released by %s (%s): built with the running build module", key, by, why)
|
|
b.startOnce(ctx, key, module, m)
|
|
return ""
|
|
}
|
|
|
|
func (b *Builder) isReleased(key string) bool {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.released[key]
|
|
}
|
|
|
|
func (b *Builder) unrelease(key string) {
|
|
b.mu.Lock()
|
|
delete(b.released, key)
|
|
b.mu.Unlock()
|
|
}
|
|
|
|
// NewRelease is the value builder_release writes for a module's fingerprint: its key and the value.
|
|
func NewRelease(module, fp, why, by string, at time.Time) (string, []byte, error) {
|
|
key, err := builds.BuilderBuildKey(module, fp)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
if strings.TrimSpace(why) == "" {
|
|
return "", nil, errors.New("say why the entry is released (why)")
|
|
}
|
|
data, err := json.Marshal(ReAsk{V: 1, Why: strings.TrimSpace(why), By: by, At: at.UTC(), Mode: ModeRelease, Module: module, FP: fp})
|
|
return key, data, err
|
|
}
|