The delivery repository's contracts and SDK live under modules/ as mesh-delivery-contracts and mesh-delivery-sdk, their Go module paths renamed to match the folders (the TypeScript names already did), and every importer in mesh-delivery, mesh-catalog, mesh-host, mesh-tools and mesh-sdk follows in the same group: a design as it should be, one path per module, checked by the group's check building every importer. Builds: design 47 G §427, §88 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/modules/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, ", "))
|
|
}
|