The indexer's packages state is read through its read tool's first view and its views family (ADR 0615 §1), as the other four states the builder follows, not by its bucket: the manifest drops the read, invokes indexer_read_packages and consumes views.packages. A package built unnumbered because its name was not known at its claim was numbered only at its module's next claim. Now a series key heard naming a name looks at its module again (Builder.PackageNamed), and a look at a done trunk build numbers what it left unnumbered with the done key's digests (BuildClaim.Done), so version.numbered carries the digest for the build module's late publish. Woken by the views family, never a timer. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
139 lines
5.6 KiB
Go
139 lines
5.6 KiB
Go
package build
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
|
|
"mesh-delivery-builder/internal/versions"
|
|
)
|
|
|
|
// Numbers numbers a trunk build at its claim (novox/hq design 51 *The versions*, ADR 0606, ADR 0617 §1) and records the
|
|
// digests it was built with. Nil numbers nothing.
|
|
type Numbers interface {
|
|
// tag is a check's build's tag (TagOf), empty for a trunk build; done the digests of its key when it is done already
|
|
// (versions.BuildClaim.Done), nil otherwise.
|
|
Number(ctx context.Context, module string, m delivery.Module, plan Plan, tag string, done map[string]string) (versions.Numbering, error)
|
|
Built(ctx context.Context, module string, m delivery.Module, plan Plan, got versions.Numbering, made []delivery.BuiltArtifact) error
|
|
}
|
|
|
|
// VersionNumbers is Numbers over the builder's state versions.
|
|
type VersionNumbers struct {
|
|
N *versions.Numberer
|
|
// TagNumbered is told the versions a check's build of a tag ask's head was numbered (the ask is then marked numbered
|
|
// in tag-asks, design 51 *Tagged versions*); nil tells nobody.
|
|
TagNumbered func(ctx context.Context, c versions.BuildClaim, got versions.Numbering)
|
|
}
|
|
|
|
// ClaimOf is the claim a module value's trunk build is numbered by: a package per source revision (Src), the rest per
|
|
// fingerprint, in merge order (Src).
|
|
func ClaimOf(module string, m delivery.Module, plan Plan) versions.BuildClaim {
|
|
c := versions.BuildClaim{Module: module, Path: m.Path, Repository: delivery.RepositoryName(m.Repository), Fingerprint: m.FP2,
|
|
Commit: m.Commit, Merge: m.Src}
|
|
if m.Src != 0 {
|
|
c.Revision = strconv.FormatUint(m.Src, 10)
|
|
}
|
|
for _, t := range plan.Tasks {
|
|
c.Artifacts = append(c.Artifacts, versions.ClaimArtifact{Artifact: t.Artifact, Kind: t.Kind, Language: t.Language})
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (v VersionNumbers) Number(ctx context.Context, module string, m delivery.Module, plan Plan, tag string, done map[string]string) (versions.Numbering, error) {
|
|
c := ClaimOf(module, m, plan)
|
|
c.Done = done
|
|
if tag != "" {
|
|
// A check's build of a head a tag ask names: its packages tagged, below the next version (design 51 *Tagged versions*).
|
|
c.Tag, c.Head, c.Revision, c.Merge = tag, m.Commit, "", 0
|
|
}
|
|
got, err := v.N.Number(ctx, c)
|
|
if err == nil && tag != "" && len(got.Versions) > 0 && v.TagNumbered != nil {
|
|
v.TagNumbered(ctx, c, got)
|
|
}
|
|
return got, err
|
|
}
|
|
|
|
func (v VersionNumbers) Built(ctx context.Context, module string, m delivery.Module, plan Plan, got versions.Numbering, made []delivery.BuiltArtifact) error {
|
|
digests := map[string]string{}
|
|
for _, a := range made {
|
|
digests[a.Name] = a.Digest
|
|
}
|
|
return v.N.Built(ctx, ClaimOf(module, m, plan), got, digests)
|
|
}
|
|
|
|
// TagOf answers the cleaned tag a kept tag ask names for a repository's head (the builder's state tag-asks, design 51
|
|
// *Tagged versions*): a check's build of that head numbers its packages tagged at its claim.
|
|
type TagOf func(ctx context.Context, repository, head string) (tag string, ok bool)
|
|
|
|
// number numbers a build before its claim, a trunk build's artifacts or a check's build's packages under its tag: false
|
|
// when it waits for its floor (a package, design 51 *The floor*), and then nothing is claimed; the floor's wake looks at
|
|
// the module again.
|
|
func (b *Builder) number(ctx context.Context, module string, m delivery.Module, plan Plan, tag string) (versions.Numbering, bool) {
|
|
if b.Numbers == nil {
|
|
return versions.Numbering{}, true
|
|
}
|
|
var done map[string]string
|
|
if tag == "" {
|
|
done = b.doneDigests(ctx, module, m.FP2)
|
|
}
|
|
got, err := b.Numbers.Number(ctx, module, m, plan, tag, done)
|
|
for _, s := range got.Said {
|
|
b.logf("%s at %s: %s", module, m.FP2, s.Line)
|
|
// And in the build log (design 51 *The versions*: it says a version was kept, and why), between the build's start and end.
|
|
if b.Log != nil {
|
|
b.Log(delivery.BuildLogEntry{Event: delivery.BuildSaidEvent, Module: module, FP: m.FP2, Commit: m.Commit, Node: b.Node,
|
|
At: time.Now().UTC(), Line: s.Line, Why: s.Why})
|
|
}
|
|
}
|
|
if err != nil {
|
|
// Said, and built as before: an unnumbered build is published by its digest (ADR 0617 §1), numbered at its next look.
|
|
b.logf("%s at %s: %v", module, m.FP2, fmt.Errorf("not numbered, the versions cannot be used: %w", err))
|
|
return versions.Numbering{}, true
|
|
}
|
|
if got.Wait != "" {
|
|
b.logf("%s at %s is not built yet: %s", module, m.FP2, got.Wait)
|
|
return got, false
|
|
}
|
|
return got, true
|
|
}
|
|
|
|
// doneDigests are the digests of a trunk build's key by artifact when the key is done, nil otherwise or when it cannot be
|
|
// read: a look at a done build numbers what it left unnumbered with them (versions.BuildClaim.Done).
|
|
func (b *Builder) doneDigests(ctx context.Context, module, fp string) map[string]string {
|
|
key, err := delivery.BuilderBuildKey(module, fp)
|
|
if err != nil || b.Claimer.Store == nil {
|
|
return nil
|
|
}
|
|
raw, _, found, err := b.Claimer.Store.Get(ctx, key)
|
|
if err != nil || !found {
|
|
return nil
|
|
}
|
|
cur, err := delivery.DecodeBuilderBuild(raw)
|
|
if err != nil || cur.State != delivery.BuildDone {
|
|
return nil
|
|
}
|
|
out := map[string]string{}
|
|
for _, a := range cur.Artifacts {
|
|
if a.Digest != "" {
|
|
out[a.Name] = a.Digest
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// PackageNamed looks at a module again when the indexer's packages state names a name for one of its packages
|
|
// (versions.NamedModule): a done trunk build that left the package unnumbered, its name not known at its claim, is
|
|
// numbered then with the done build's digests, and version.numbered says them for its build module's late publish.
|
|
func (b *Builder) PackageNamed(ctx context.Context, module string) {
|
|
b.init()
|
|
b.mu.Lock()
|
|
m, ok := b.known[module]
|
|
b.mu.Unlock()
|
|
if ok {
|
|
b.consider(ctx, module, m)
|
|
}
|
|
}
|