143 lines
6.1 KiB
Go
143 lines
6.1 KiB
Go
package build
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
|
"git.novox.be/novox/mesh-delivery/sdk/trunk"
|
|
|
|
"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 meshcatalog.ModulesByModuleValue, plan Plan, tag string, done map[string]string) (versions.Numbering, error)
|
|
Built(ctx context.Context, module string, m meshcatalog.ModulesByModuleValue, plan Plan, got versions.Numbering, made []builds.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 meshcatalog.ModulesByModuleValue, plan Plan) versions.BuildClaim {
|
|
c := versions.BuildClaim{Module: module, Path: m.Path, Repository: trunk.RepositoryName(m.Repository), Fingerprint: m.Fp2,
|
|
Commit: m.Commit, Merge: uint64(m.Src)}
|
|
if uint64(m.Src) != 0 {
|
|
c.Revision = strconv.FormatUint(uint64(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 meshcatalog.ModulesByModuleValue, 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 meshcatalog.ModulesByModuleValue, plan Plan, got versions.Numbering, made []builds.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 meshcatalog.ModulesByModuleValue, 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.
|
|
// A look at a key already done builds nothing and has no start or end: a version kept there says nothing new, and is
|
|
// not logged (each later look, a first view answered or a name heard, would add one).
|
|
if b.Log != nil && !(done != nil && s.Why == versions.SaidKept) {
|
|
b.Log(builds.BuildLogEntry{Event: builds.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 := builds.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 := builds.DecodeBuilderBuild(raw)
|
|
if err != nil || cur.State != builds.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)
|
|
}
|
|
}
|