Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/artifacts.go
T

101 lines
4.3 KiB
Go

package index
import (
"context"
"maps"
"slices"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"git.novox.be/novox/mesh-delivery/sdk/packagename"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// Each entry carries its artifacts' package names (design 47 G §676, §491, §478, §504, §412): at take-in the indexer reads
// each artifact's package name from the revision's own files at the artifact's path, the module of its go.mod for a Go
// package, the name of its package.json for an npm package, the module's and the artifact's names joined by / for an image artifact (§694), and writes it into
// the entry's artifact as package, {ecosystem, name}. The manifest validator judges §491 from these fields.
// Package ecosystems of an artifact's package (§676).
const (
EcosystemGo = "go"
EcosystemNpm = "npm"
// EcosystemImage is an image artifact's package ecosystem (§694).
EcosystemImage = "image"
)
// ArtifactRefOf is the artifact reference of a module's artifact, <module>:<artifact>.
func ArtifactRefOf(module, artifact string) string { return module + ":" + artifact }
// withArtifacts gives e its manifest's artifacts, by reference, with the package name of each package artifact (an image's is its module's name and its artifact's, §694). A
// name the forge does not answer is said and left out of the artifact, for the next entry to read again (the cache keeps only
// what was read); a manifest that does not decode leaves the entry as it is.
func (ix *Indexer) withArtifacts(ctx context.Context, e meshcatalog.CatalogEntry, m catalogue.Manifest) meshcatalog.CatalogEntry {
if m.Build == nil {
return e
}
for _, a := range m.Build.Artifacts {
art := meshcatalog.Artifact{Ref: ArtifactRefOf(e.Module, a.Name), Language: a.Language, Kind: a.Kind}
if pkg := ix.packageOf(ctx, e, a); pkg != nil {
art.Package = pkg
}
e.Artifacts = append(e.Artifacts, art)
}
slices.SortFunc(e.Artifacts, func(a, b meshcatalog.Artifact) int { return strings.Compare(a.Ref, b.Ref) })
return e
}
// packageOf is the package name of artifact a of the entry e: read through the forge at the entry's commit, kept per
// repository, commit, path and artifact so a later entry of the same commit reads nothing; nil for an artifact that names
// none (a program, an archive) or whose name cannot be read now.
func (ix *Indexer) packageOf(ctx context.Context, e meshcatalog.CatalogEntry, a catalogue.Artifact) *meshcatalog.ArtifactPackage {
switch a.Kind {
case catalogue.ArtifactPackage:
case catalogue.ArtifactImage:
// An image's package name is its module's name and its artifact's joined by `/`, read from no file (§694).
return &meshcatalog.ArtifactPackage{Ecosystem: EcosystemImage, Name: e.Module + "/" + a.Name}
default:
return nil
}
if ix.ReadFile == nil || e.Commit == "" {
return nil
}
ecosystem := EcosystemNpm
if a.Language == "go" {
ecosystem = EcosystemGo
}
key := e.Repository + "\x00" + e.Commit + "\x00" + e.Path + "\x00" + a.Name
ix.namesMu.Lock()
name, ok := ix.packageNames[key]
ix.namesMu.Unlock()
if !ok {
var err error
if name, err = packagename.Of(ctx, packagename.ReadFile(ix.ReadFile), e.Repository, e.Commit, e.Path, a); err != nil {
ix.logf("catalog graph: the package name of %s at %.12s is not read, so its entry carries none until the next entry: %v", ArtifactRefOf(e.Module, a.Name), e.Commit, err)
return nil
}
ix.namesMu.Lock()
if ix.packageNames == nil {
ix.packageNames = map[string]string{}
}
ix.packageNames[key] = name
ix.namesMu.Unlock()
}
return &meshcatalog.ArtifactPackage{Ecosystem: ecosystem, Name: name}
}
// packageEntries is the entry of each module whose manifest decodes, with its artifacts' package names as the take-in reads
// them, for the judge of §491 to read the names from.
func (ix *Indexer) packageEntries(ctx context.Context, held map[string]meshcatalog.ModulesByModuleValue, raws map[string][]byte) []meshcatalog.CatalogEntry {
var out []meshcatalog.CatalogEntry
for _, name := range slices.Sorted(maps.Keys(raws)) {
m, err := catalogue.Decode(raws[name])
if err != nil {
continue
}
cur := held[name]
out = append(out, ix.withArtifacts(ctx, meshcatalog.CatalogEntry{Module: name, Repository: cur.Repository, Path: cur.Path, Commit: cur.Commit}, m))
}
return out
}