Files
mesh-delivery/modules/mesh-delivery-builder/internal/versions/tools.go
T
jschoubben 260a16181c BL7: reserved by name from the catalog half's view, builder_versions calls it
The builder's tools bundle serves reserved given a package's name: it follows the catalog half's packages view itself, finds the
module from the name, answers the reserved version, or for a version no reservation holds asks the seat mesh-catalog's versions
and answers released with the release's digests; a name no entry carries, two entries carry, or a version neither reserved nor
released is answered error. builder_versions by name calls reserved through its invokes. The builder's process serves no call.

Builds: design 47 G §572, §582 (A-70)
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-11 23:12:27 +01:00

106 lines
4.2 KiB
Go

package versions
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
)
// The builder's tools of its versions (design 51 *Events of the builder*, *Tools of the builder*).
const (
VersionsTool = "builder_versions"
PublishAgainTool = "builder_publish_again"
FloorAgainTool = "builder_floor_again"
OldFormTool = "builder_old_form"
// OldFormClosedEvent is the builder's own family `version`, kept seven days,
// apart from its builds' ends, so a waiter on a build's end does not wake on them.
OldFormClosedEvent = "version.old-form-closed"
)
// Reader reads the state as the tools bundle may: every key, and one.
type Reader struct {
Keys func() ([]string, error)
Get func(key string) (json.RawMessage, bool, error)
}
// readStore is a Store over a Reader that refuses every write: the tools bundle only reads versions.
type readStore struct{ r Reader }
var errReadOnly = errors.New("the versions are written by the builder alone")
func (s readStore) Get(_ context.Context, key string) ([]byte, uint64, bool, error) {
v, ok, err := s.r.Get(key)
return v, 0, ok, err
}
func (readStore) Create(context.Context, string, []byte) (uint64, error) { return 0, errReadOnly }
func (readStore) Update(context.Context, string, []byte, uint64) (uint64, error) {
return 0, errReadOnly
}
func (s readStore) KeysOf(_ context.Context, filter string) ([]string, error) {
all, err := s.r.Keys()
if err != nil {
return nil, err
}
if filter == AllFilter {
return all, nil
}
prefix := strings.TrimSuffix(filter, "*")
var out []string
for _, k := range all {
if strings.HasPrefix(k, prefix) && !strings.Contains(k[len(prefix):], ".") {
out = append(out, k)
}
}
return out, nil
}
// VersionsAnswer is what builder_versions answers.
type VersionsAnswer struct {
Name string `json:"name"`
Versions []Entry `json:"versions"`
// Asked, Recorded and Why answer a holder's question for one version and digest (ADR 0605 §4).
Asked string `json:"asked,omitempty"`
Recorded *bool `json:"recorded,omitempty"`
Why string `json:"why,omitempty"`
// Reserved is what the seat mesh-builds' verb reserved answers for the name (and version): the reserved or released version
// with each artifact's digest, or its error (design 47 G §572, §582).
Reserved *meshbuilds.ReservedAnswer `json:"reserved,omitempty"`
}
// AnswerVersions is builder_versions: a name's versions in order, in one call; with a version (and a digest), whether
// the builder numbered it with that digest, which the holder asks before it stores (ADR 0605 §4).
func AnswerVersions(ctx context.Context, r Reader, name, version, digest string) (VersionsAnswer, error) {
name = strings.TrimSpace(name)
if name == "" {
return VersionsAnswer{}, errors.New("name is required: the package, image, bundle or archive name")
}
v := Versions{Store: readStore{r}}
all, err := v.Of(ctx, name)
if err != nil {
return VersionsAnswer{}, err
}
out := VersionsAnswer{Name: name, Versions: all}
if out.Versions == nil {
out.Versions = []Entry{}
}
if version = strings.TrimSpace(version); version != "" {
_, ok, why, err := v.Recorded(ctx, name, version, strings.TrimSpace(digest))
if err != nil {
return VersionsAnswer{}, fmt.Errorf("%s@%s: %w", name, version, err)
}
out.Asked, out.Recorded, out.Why = version, &ok, why
}
return out, nil
}
// VersionsDescription is builder_versions' description.
const VersionsDescription = "A name's versions as the builder numbered them (its state versions, design 51): every trunk and tagged " +
"version of a package, image, bundle or archive in order, each with its kind, series, fingerprint, commit, source revision, digest, " +
"seat, state (numbered, published, refused with its reason, removed with its time, reason and the event that removed it, or kept: its seat kept it whole on remove, its digest shared, with the reason and the other tags naming it, kept_with) and when. " +
"With version, and digest, it also answers recorded: whether the builder numbered that version with that digest, and why not: the " +
"question a registry seat's holder asks before it stores a publish (ADR 0605 §4). Read-only."