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

116 lines
4.5 KiB
Go

package index
import (
"fmt"
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// The reasons a module has no fingerprint of the new form while the indexer writes none for any module (novox/hq
// ADR 0465 clause 2; issue 1444). Toolchains missing is delivery.ToolchainNoReport.
const (
// None2NoManifest is for a module whose directory the merged message carries no manifest of (an older bridge).
None2NoManifest = "the message carries no manifest"
// None2Builder is for a module with no artifact of a toolchain: only the builder's fingerprint is missing.
None2Builder = "builder's fingerprint not yet known"
// None2Context is for a module an artifact of which reads another repository's tree (today's form gives it none
// either, NoneContext).
None2Context = "context not pinned"
)
// lockFile is the lock file of a language's artifact that resolves packages when it is built, by name in the module's
// directory (the bridge reads these, internal/bridge LockFiles; issue 1450).
var lockFile = map[string]string{"go": "go.sum", "typescript": "package-lock.json"}
// moduleInputs is what a module's manifest and lock hashes give the indexer at a merge (issue 1450).
type moduleInputs struct {
// Kept is the new-form inputs the merge gave the module; nil when the manifest could not be read or gave none.
Kept *delivery.KeptInputs2
// Languages is the language of each artifact that has a toolchain (a bundle or a package of go or typescript), by
// artifact name. The toolchain versions are joined to them when the build modules report them (issue 1444, the
// watching half); the SDK's KeptInputs2 keeps no languages, so they are read from the manifest again then.
Languages map[string]string
// None2 is why the module has no fingerprint of the new form.
None2 string
}
// baseFP answers a base module's new-form fingerprint, or why it has none.
type baseFP func(module string) (fp, none string)
// inputsOf turns the manifest of a module (raw, as the forge answered it), the tree of its directory and the lock
// hashes of that directory (lock file name to hash) into its new-form inputs. The manifest is read by the catalogue's
// parser; a manifest it refuses, or one that is of another module, leaves Kept nil and says why.
//
// The rules are the controller's builder (mesh-controller internal/builder/builder.go): a bundle or a package of a
// language with a toolchain (go, typescript) is the artifact that has one; a package, and a bundle of those languages,
// resolves packages when it is built (wantsPackages, :1017), so it has an entry in Locks, with the hash of its
// language's lock file or an empty hash when none was carried (the fingerprint is then none, "no lock"); an archive,
// an image and an upstream resolve nothing and have no toolchain. A base is a build.on entry that names a module.
func inputsOf(module, raw, tree string, locks map[string]string, base baseFP) moduleInputs {
m, err := catalogue.ParseManifest([]byte(raw))
if err != nil {
return moduleInputs{None2: "the manifest cannot be read: " + err.Error()}
}
if m.Module != module {
return moduleInputs{None2: fmt.Sprintf("the manifest is of module %q, not %q", m.Module, module)}
}
if tree == "" {
return moduleInputs{None2: "the merge names no tree for the module's directory"}
}
kept := delivery.KeptInputs2{Tree: tree}
langs := map[string]string{}
contexts := false
var missing []string
if m.Build != nil {
for _, a := range m.Build.Artifacts {
if a.Context != nil {
contexts = true
}
if a.Kind != catalogue.ArtifactBundle && a.Kind != catalogue.ArtifactPackage {
continue
}
name, ok := lockFile[a.Language]
if !ok {
continue
}
langs[a.Name] = a.Language
if kept.Locks == nil {
kept.Locks = map[string]string{}
}
kept.Locks[a.Name] = locks[name]
}
seen := map[string]bool{}
for _, on := range m.Build.On {
if on.Module == "" || seen[on.Module] {
continue
}
seen[on.Module] = true
if fp, none := base(on.Module); fp != "" {
kept.Bases = append(kept.Bases, fp)
} else {
missing = append(missing, fmt.Sprintf("the base %s has no fingerprint (%s)", on.Module, none))
}
}
}
sort.Strings(kept.Bases)
sort.Strings(missing)
out := moduleInputs{Kept: &kept}
if len(langs) > 0 {
out.Languages = langs
}
switch {
case contexts:
out.None2 = None2Context
case len(missing) > 0:
out.None2 = strings.Join(missing, "; ")
case len(langs) > 0:
out.None2 = delivery.ToolchainNoReport
default:
out.None2 = None2Builder
}
return out
}