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 `.`; 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 / 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 (`.`), 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, ", ")) }