The builder adopts meshcatalogclient's branch follower on its views reader (A-5, A-15): the modules, their manifests (kept from the entry that holds them, by its digest), their packages and each package's name in its ecosystem are read from the catalog half's entries, never the indexer's modules, manifests, candidates and packages views; an entry of a branch other than the module's first builds its fingerprint and supersedes only its own branch's older one; the start's sweep runs once every followed half's first view is in; the builder's tools bundle reads package names through the same follower. A run's candidate is no input of the builder (A-84): its read of the indexer's candidates view goes, and the entry point for a run's build ask is not built (no line gives the ask's form). The seats' events the builder's own handler takes are named per seat so the follower's events have one taker. Builds: design 47 G §348, §479, §614, A-5, A-15, A-84 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
145 lines
5.0 KiB
Go
145 lines
5.0 KiB
Go
package versions
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
|
)
|
|
|
|
// PackagesState is the indexer's packages state as the builder reads it (its manifest's reads grant): its keys, and one
|
|
// key's value (found false when it holds none).
|
|
type PackagesState interface {
|
|
Keys(ctx context.Context) ([]string, error)
|
|
Get(ctx context.Context, key string) (value []byte, found bool, err error)
|
|
}
|
|
|
|
// NamesIn are a package's names in its ecosystem as the indexer's packages state holds them (design 32): the name of the
|
|
// series key that names module and artifact as what it is built from. A series key is named `<name>.<series>`; a key
|
|
// with no dot is a mesh Go module's published packages, not a series. A value that does not decode is passed over.
|
|
func NamesIn(s PackagesState) PackageNames {
|
|
return func(ctx context.Context, module, artifact string) (string, bool, error) {
|
|
keys, err := s.Keys(ctx)
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
sort.Strings(keys)
|
|
built := NameOf(module, artifact)
|
|
for _, key := range keys {
|
|
if !isSeriesKey(key) {
|
|
continue
|
|
}
|
|
value, found, err := s.Get(ctx, key)
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
if !found {
|
|
continue
|
|
}
|
|
v, err := meshcatalog.DecodePackagesByPackageSeriesValue(value) // the indexer's value of a series key (mesh-sdk's contract, J4)
|
|
if err != nil || v.Package != built {
|
|
continue
|
|
}
|
|
return v.Name, true, nil
|
|
}
|
|
return "", false, nil
|
|
}
|
|
}
|
|
|
|
// NamedModule is the module a value of the indexer's packages state names a package's name for (design 32), and that
|
|
// name: a series key whose value names a name and the <module>/<artifact> it is built from. The builder looks at that module again when
|
|
// the value is heard, so a done build that left the package unnumbered (its name not known at its claim) is numbered then.
|
|
func NamedModule(key string, value []byte) (module, name string, ok bool) {
|
|
if !isSeriesKey(key) {
|
|
return "", "", false
|
|
}
|
|
v, err := meshcatalog.DecodePackagesByPackageSeriesValue(value)
|
|
if err != nil || v.Name == "" {
|
|
return "", "", false
|
|
}
|
|
module, artifact, cut := strings.Cut(v.Package, "/")
|
|
if !cut || module == "" || artifact == "" {
|
|
return "", "", false
|
|
}
|
|
return module, v.Name, true
|
|
}
|
|
|
|
// isSeriesKey says whether a key of the indexer's packages state is a series key (`<package>.<series>`), not a per-module one.
|
|
func isSeriesKey(key string) bool {
|
|
_, _, ok := meshcatalog.ParsePackagesByPackageSeriesKey(key)
|
|
return ok
|
|
}
|
|
|
|
// Built is a module's artifact, which a package's name is the name of.
|
|
type Built struct{ Module, Artifact string }
|
|
|
|
// Carriers are the module artifacts a package's name in its ecosystem is the name of, as the catalog half's packages view
|
|
// holds them (the inverse of NamesIn; design 47 G §572, §478): each distinct module and artifact of a series key whose value
|
|
// names that name, sorted. A name no entry carries answers none.
|
|
func Carriers(s PackagesState) func(ctx context.Context, name string) ([]Built, error) {
|
|
return func(ctx context.Context, name string) ([]Built, error) {
|
|
keys, err := s.Keys(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(keys)
|
|
seen := map[Built]bool{}
|
|
var out []Built
|
|
for _, key := range keys {
|
|
if !isSeriesKey(key) {
|
|
continue
|
|
}
|
|
value, found, err := s.Get(ctx, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found {
|
|
continue
|
|
}
|
|
v, err := meshcatalog.DecodePackagesByPackageSeriesValue(value)
|
|
if err != nil || v.Name != name {
|
|
continue
|
|
}
|
|
if module, artifact, cut := strings.Cut(v.Package, "/"); cut && module != "" && artifact != "" && !seen[Built{module, artifact}] {
|
|
seen[Built{module, artifact}] = true
|
|
out = append(out, Built{module, artifact})
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
}
|
|
|
|
// ModuleOf is the module and artifact a package's name is built from (Carriers), found false for a name no entry carries; more
|
|
// than one entry carrying it is an error naming them.
|
|
func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
|
|
return moduleOfCarriers(Carriers(s))
|
|
}
|
|
|
|
// moduleOfCarriers is ModuleOf over one way of finding the carriers.
|
|
func moduleOfCarriers(carriers func(ctx context.Context, name string) ([]Built, error)) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
|
|
return func(ctx context.Context, name string) (string, string, bool, error) {
|
|
got, err := carriers(ctx, name)
|
|
switch {
|
|
case err != nil:
|
|
return "", "", false, err
|
|
case len(got) == 0:
|
|
return "", "", false, nil
|
|
case len(got) > 1:
|
|
return "", "", false, errors.New(MoreThanOne(name, got))
|
|
}
|
|
return got[0].Module, got[0].Artifact, true, nil
|
|
}
|
|
}
|
|
|
|
// MoreThanOne is the words of a name that more than one entry carries.
|
|
func MoreThanOne(name string, got []Built) string {
|
|
var refs []string
|
|
for _, b := range got {
|
|
refs = append(refs, b.Module+"/"+b.Artifact)
|
|
}
|
|
return fmt.Sprintf("the name %s is carried by more than one entry: %s", name, strings.Join(refs, ", "))
|
|
}
|