The manifest invokes gitea.gitea_commit_trees. A forge that cannot say gives the module none with its words.
152 lines
6.0 KiB
Go
152 lines
6.0 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"maps"
|
|
"slices"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// applyMerged writes, for each module whose manifest the merged message carries (each directory of the merge commit that
|
|
// holds a module.json, the module its manifest names), its value at the merge commit: its directory, its manifest digest,
|
|
// its new-form inputs and why it has no new-form fingerprint yet, with the source revision that names the merge commit as
|
|
// the repository's head when the indexer has seen it (ApplySource), and Src 0 when it has not. The fingerprint itself is
|
|
// computed by Recompute (toolchains.go) once the merge is written, and again when a build module reports its toolchain.
|
|
//
|
|
// The modules are listed from the message, never from the controller's build records (novox/hq ADR 0501 clause 6, issue
|
|
// 1851), so a module added by the merge gets a value, and a fingerprint, with no build anywhere. The value of today's
|
|
// form (Module.FP, None) is no longer written: it was computed from those records (ADR 0453 clause 6). A module the
|
|
// bucket holds of another repository is left as it is and said: a move between repositories is the operator's (ADR 0420
|
|
// clause 7). Two directories naming one module write the one the bucket holds, or the first by name, and say the other.
|
|
// A value the module already holds is not written again.
|
|
func (ix *Indexer) applyMerged(ctx context.Context, f delivery.Forge) error {
|
|
digests, err := ix.keepManifests(ctx, f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
held, err := ix.heldModules(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
objects, namedErr := ix.namedObjects(ctx, f)
|
|
overlay := map[string]delivery.Module{}
|
|
dirOf := map[string]string{}
|
|
for _, dir := range slices.Sorted(maps.Keys(f.Manifests)) {
|
|
raw := f.Manifests[dir]
|
|
name := manifestModule(raw)
|
|
if name == "" {
|
|
ix.logf("%s at %s: the manifest in %q names no module, so no module is written for it", f.Repository, f.Merge, dir)
|
|
continue
|
|
}
|
|
key, err := delivery.ModulesKey(name)
|
|
if err != nil {
|
|
ix.logf("%s: the module %q has no usable key, skipped: %v", f.Repository, name, err)
|
|
continue
|
|
}
|
|
cur, has := held[key]
|
|
if has && cur.Repository != "" && !delivery.SameRepository(cur.Repository, f.Repository) {
|
|
ix.logf("%s at %s: %q names the module %s, which the indexer holds of %s; left as it is (a move between repositories is the operator's)", f.Repository, f.Merge, dir, name, cur.Repository)
|
|
continue
|
|
}
|
|
if other, dup := dirOf[name]; dup {
|
|
if !has || cur.Path != pathOf(dir) {
|
|
ix.logf("%s at %s: %q and %q both name the module %s; %q is written", f.Repository, f.Merge, other, dir, name, other)
|
|
continue
|
|
}
|
|
ix.logf("%s at %s: %q and %q both name the module %s; %q, which the indexer holds, is written", f.Repository, f.Merge, other, dir, name, dir)
|
|
}
|
|
dirOf[name] = dir
|
|
next := delivery.Module{Repository: f.Repository, Commit: f.Merge, Src: ix.srcOf(f.Repository, f.Merge), Manifest: digests[dir], Path: pathOf(dir)}
|
|
if next.Manifest == "" {
|
|
next.None2 = "the manifest cannot be read: it cannot be kept as a value"
|
|
} else {
|
|
in := inputsOfNamed(name, raw, f.Trees[dir], f.Locks[dir], objects[dir], ix.baseFP(ctx))
|
|
next.Inputs2, next.None2, next.ArtifactPaths = in.Kept, in.None2, in.ArtifactPaths
|
|
if in.Kept == nil && namedErr[dir] != "" {
|
|
next.None2 = in.None2 + ": the forge could not say them: " + namedErr[dir]
|
|
}
|
|
}
|
|
overlay[key] = next
|
|
}
|
|
// What this merge moved reaches the modules standing on it (a base's tree, build-agent's fingerprint), in the graph's order.
|
|
return ix.recomputeWith(ctx, overlay)
|
|
}
|
|
|
|
// baseFP answers the new-form fingerprint of a base module as modules.<base> holds it, or why it has none.
|
|
func (ix *Indexer) baseFP(ctx context.Context) baseFP {
|
|
return func(module string) (string, string) {
|
|
key, err := delivery.ModulesKey(module)
|
|
if err != nil {
|
|
return "", err.Error()
|
|
}
|
|
value, _, found, err := ix.Modules.Get(ctx, key)
|
|
if err != nil {
|
|
return "", "its record cannot be read: " + err.Error()
|
|
}
|
|
if !found {
|
|
return "", "the indexer holds no record of it"
|
|
}
|
|
cur, err := delivery.DecodeModule(value)
|
|
switch {
|
|
case err != nil:
|
|
return "", "its record cannot be read: " + err.Error()
|
|
case cur.FP2 != "":
|
|
return cur.FP2, ""
|
|
case cur.None2 != "":
|
|
return "", cur.None2
|
|
}
|
|
return "", "its record carries no fingerprint of the new form"
|
|
}
|
|
}
|
|
|
|
// pathOf is the module's directory as Module.Path holds it: "." for the repository's root, since empty means not known.
|
|
func pathOf(dir string) string {
|
|
if dir == "" {
|
|
return delivery.RootPath
|
|
}
|
|
return dir
|
|
}
|
|
|
|
func withV(m delivery.Module) delivery.Module { m.V = delivery.Version; return m }
|
|
|
|
// namedObjects are, by module directory, the git objects of the paths each manifest of the merge names for every artifact
|
|
// (catalogue Manifest.NamedPaths): those the message carries, else asked of the forge at the merge commit in one call
|
|
// (Named). A forge that cannot say gives, for each directory asked, its words, so the module's reason names them.
|
|
func (ix *Indexer) namedObjects(ctx context.Context, f delivery.Forge) (map[string]map[string]string, map[string]string) {
|
|
objects := map[string]map[string]string{}
|
|
need := map[string][]string{}
|
|
for dir, raw := range f.Manifests {
|
|
m, err := catalogue.ParseManifestForInputs([]byte(raw))
|
|
if err != nil {
|
|
continue // inputsOfNamed says why
|
|
}
|
|
paths, every := m.NamedPaths()
|
|
if !every {
|
|
continue
|
|
}
|
|
if carried := f.Paths[dir]; len(carried) > 0 {
|
|
objects[dir] = carried
|
|
continue
|
|
}
|
|
need[dir] = paths
|
|
}
|
|
if len(need) == 0 || ix.Named == nil {
|
|
return objects, nil
|
|
}
|
|
got, err := ix.Named(ctx, f.Repository, f.Merge, need)
|
|
if err != nil {
|
|
words := map[string]string{}
|
|
for dir := range need {
|
|
words[dir] = err.Error()
|
|
}
|
|
ix.logf("%s at %s: the objects of the named paths of %v: %v", f.Repository, f.Merge, slices.Sorted(maps.Keys(need)), err)
|
|
return objects, words
|
|
}
|
|
for dir := range need {
|
|
objects[dir] = got[dir]
|
|
}
|
|
return objects, nil
|
|
}
|