Files
mesh-sdk/go/delivery/series_package.go
T
jschoubben 09cf1ea6fc J4 (lead's item): the packages state's series value is a contract its readers take, not the indexer's own type
delivery.SeriesPackage and SeriesVersion, field for field as the indexer writes them (name, the ecosystem name;
package, <module>/<artifact>), with SeriesPackageKey, IsSeriesPackageKey and a checked encode and decode.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 14:54:33 +01:00

106 lines
4.6 KiB
Go

package delivery
import (
"encoding/json"
"fmt"
"regexp"
"strings"
"time"
)
// The packages state per series (design 51 *The versions*, design 32; ADR 0606 §1, ADR 0609 §1): beside the per-module
// values (PublishedPackages), the indexer keeps one key per package and series, `<name>.<series>` (SeriesPackageKey),
// holding the newest trunk version of that series the builder numbered and the newest a registry seat published. The
// indexer alone writes it; its readers (the builder, the checker, the build modules) take this value's form from here.
// A series key always holds a dot, which EscapeName never leaves in a per-module key (IsSeriesPackageKey).
// SeriesPackage is the value of a series key. Name is the package's name in its own ecosystem (a Go package's module
// path in its go.mod at the commit, an npm package's package.json name): the key is named by it, and a user's
// `packages` names it. Package is the module and artifact it is built from, `<module>/<artifact>`, by which the builder
// finds the name to number under; Series its `<major>.<minor>`. Seat is the registry seat it is published through;
// GoModule the Go module path a Go package is fetched under, empty for any other. Newest is the newest version of the
// series a seat published (what a user accepting the series builds against), Numbered the newest the builder numbered,
// published or not yet.
type SeriesPackage struct {
V int `json:"v"`
Name string `json:"name"`
Package string `json:"package,omitempty"`
Series string `json:"series"`
Seat string `json:"seat,omitempty"`
GoModule string `json:"go-module,omitempty"`
Newest *SeriesVersion `json:"newest,omitempty"`
Numbered *SeriesVersion `json:"numbered,omitempty"`
At time.Time `json:"at"`
}
// SeriesVersion is one version of a series: its number, the source commit it was built from, the digest and
// fingerprint. Contents are, for a series' newest of a Go package, its Go module's requirements' and packages' digests
// at Commit: what a user accepting the series is fingerprinted against; nil when the forge could not list it, and on a
// numbered version.
type SeriesVersion struct {
Version string `json:"version"`
Commit string `json:"commit,omitempty"`
Digest string `json:"digest,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Contents *PublishedPackages `json:"contents,omitempty"`
}
// SeriesPackageKey is the key of a package's series in the packages state: its ecosystem name as a key part and the
// series.
func SeriesPackageKey(name, series string) string { return EscapeName(name) + "." + series }
// IsSeriesPackageKey says whether a key of the packages state is a series key, not a per-module one.
func IsSeriesPackageKey(key string) bool { return strings.Contains(key, ".") }
// builtFrom says whether pkg is `<module>/<artifact>`: a module name (no slash) and an artifact named after it.
func builtFrom(pkg string) bool {
module, artifact, ok := strings.Cut(pkg, "/")
return ok && module != "" && artifact != ""
}
var seriesForm = regexp.MustCompile(`^[0-9]+\.[0-9]+$`)
func (s SeriesPackage) check() error {
switch {
case s.Name == "":
return fmt.Errorf("delivery: a series of %q names no package in its ecosystem", s.Package)
case !seriesForm.MatchString(s.Series):
return fmt.Errorf("delivery: the series %q of %s is no <major>.<minor>", s.Series, s.Name)
case s.Package != "" && !builtFrom(s.Package):
return fmt.Errorf("delivery: the series %s of %s is built from %q, which is no <module>/<artifact>", s.Series, s.Name, s.Package)
}
for which, v := range map[string]*SeriesVersion{"newest": s.Newest, "numbered": s.Numbered} {
if v != nil && v.Version == "" {
return fmt.Errorf("delivery: the %s version of %s %s names no version", which, s.Name, s.Series)
}
if v != nil && v.Contents != nil {
if err := v.Contents.check(); err != nil {
return err
}
}
}
return nil
}
// EncodeSeriesPackage is s as JSON at Version; it refuses what a reader could not take.
func EncodeSeriesPackage(s SeriesPackage) ([]byte, error) {
if err := s.check(); err != nil {
return nil, err
}
s.V = Version
return json.Marshal(s)
}
// DecodeSeriesPackage reads a series key's value; it refuses an unknown version (ErrUnknownVersion) and what
// EncodeSeriesPackage refuses.
func DecodeSeriesPackage(data []byte) (SeriesPackage, error) {
var s SeriesPackage
if err := decode(data, &s); err != nil {
return SeriesPackage{}, err
}
if err := s.check(); err != nil {
return SeriesPackage{}, err
}
return s, nil
}