The indexer writes '.' for a root module's path and the toolchains each fingerprint was computed with (issue 1615)
This commit is contained in:
@@ -63,7 +63,7 @@ func (ix *Indexer) applyMerged(ctx context.Context, f delivery.Forge) error {
|
||||
continue
|
||||
}
|
||||
fp, none := fingerprintOf(k, f.Trees)
|
||||
next := delivery.Module{Repository: f.Repository, Commit: f.Merge, FP: fp, None: none, Src: ix.srcOf(f.Repository, f.Merge), Manifest: digests[k.Path], Path: k.Path}
|
||||
next := delivery.Module{Repository: f.Repository, Commit: f.Merge, FP: fp, None: none, Src: ix.srcOf(f.Repository, f.Merge), Manifest: digests[k.Path], Path: pathOf(k.Path)}
|
||||
// The new form (issue 1444, R4c-2): no module has a fingerprint of it yet, so each has the reason it has none, which
|
||||
// names what is missing, from its manifest and lock hashes (inputs.go).
|
||||
raw, has := f.Manifests[k.Path]
|
||||
@@ -109,4 +109,12 @@ func (ix *Indexer) baseFP(ctx context.Context) baseFP {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 }
|
||||
|
||||
@@ -234,7 +234,7 @@ func TestAMergeWritesTheModulesDirectoryAndKeepsItThroughSourceAndRecompute(t *t
|
||||
if err := ix.Apply(ctx, mergedMsg("novox/mesh-delivery", map[string]string{"modules/a": "newtree", "": "roottree"})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for module, want := range map[string]string{"a": "modules/a", "r": ""} {
|
||||
for module, want := range map[string]string{"a": "modules/a", "r": delivery.RootPath} {
|
||||
if m, ok := moduleOf(t, mods, module); !ok || m.Path != want {
|
||||
t.Errorf("after the merge %s = %+v (%v), want path %q", module, m, ok, want)
|
||||
}
|
||||
@@ -252,7 +252,14 @@ func TestAMergeWritesTheModulesDirectoryAndKeepsItThroughSourceAndRecompute(t *t
|
||||
if !strings.Contains(raw, `"path":"modules/a"`) {
|
||||
t.Errorf("the stored value %s has no path", raw)
|
||||
}
|
||||
if strings.Contains(string(mods.vals["r"]), `"path"`) {
|
||||
t.Errorf("the root module's value %s names a path", mods.vals["r"])
|
||||
}
|
||||
|
||||
func TestARootModuleHasTheDirectoryDot(t *testing.T) { // 1615/AC3: empty means not known, a root module is "."
|
||||
ix, mods := modulesIndexer(t, rec(t, "build-1", "r", "novox/mesh-sdk", "", "main", "", "2026-10-19T09:00:00Z", strings.Replace(aInputs, `"Module":"a"`, `"Module":"r"`, 1)))
|
||||
if err := ix.Apply(context.Background(), mergedMsg("novox/mesh-sdk", map[string]string{"": "roottree"})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m, ok := moduleOf(t, mods, "r"); !ok || m.Path != delivery.RootPath {
|
||||
t.Errorf("module = %+v (%v), want path %q", m, ok, delivery.RootPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package index
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
@@ -32,7 +33,7 @@ func TestASourceRevisionStampsTheModulesOfTheRepositoriesHeadItNames(t *testing.
|
||||
m, ok := moduleOf(t, mods, "a")
|
||||
want := before
|
||||
want.Src = 7
|
||||
if !ok || m != want {
|
||||
if !ok || !reflect.DeepEqual(m, want) {
|
||||
t.Errorf("module a = %+v (%v), want %+v: the fingerprint and the commit as the merge wrote them, with Src 7", m, ok, want)
|
||||
}
|
||||
if c, ok := moduleOf(t, mods, "c"); ok {
|
||||
|
||||
@@ -179,7 +179,10 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
all[key] = &known{key: key, cur: cur, languages: languagesOf(m), bases: basesOf(m), contexts: hasContext(m)}
|
||||
}
|
||||
tools := ix.agreed()
|
||||
type result struct{ fp, none string }
|
||||
type result struct {
|
||||
fp, none string
|
||||
tcs map[string]delivery.ToolchainUsed // by language, when there is a fingerprint
|
||||
}
|
||||
done := map[string]result{}
|
||||
visiting := map[string]bool{}
|
||||
var of func(module string, chain []string) result
|
||||
@@ -192,16 +195,16 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
cur, has := held[module]
|
||||
switch {
|
||||
case !has:
|
||||
return result{"", "the indexer holds no record of it"}
|
||||
return result{fp: "", none: "the indexer holds no record of it"}
|
||||
case cur.FP2 != "":
|
||||
return result{cur.FP2, ""}
|
||||
return result{fp: cur.FP2, none: ""}
|
||||
case cur.None2 != "":
|
||||
return result{"", cur.None2}
|
||||
return result{fp: "", none: cur.None2}
|
||||
}
|
||||
return result{"", "its record carries no fingerprint of the new form"}
|
||||
return result{fp: "", none: "its record carries no fingerprint of the new form"}
|
||||
}
|
||||
if visiting[module] {
|
||||
return result{"", "a cycle of bases: " + strings.Join(append(chain, module), " -> ")}
|
||||
return result{fp: "", none: "a cycle of bases: " + strings.Join(append(chain, module), " -> ")}
|
||||
}
|
||||
visiting[module] = true
|
||||
defer delete(visiting, module)
|
||||
@@ -258,6 +261,9 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
r.none = noBuilder
|
||||
default:
|
||||
r.fp, r.none = delivery.SourceFingerprint2(kept.With(module, toolchains))
|
||||
if r.fp != "" {
|
||||
r.tcs = toolchainsUsed(toolchains)
|
||||
}
|
||||
}
|
||||
done[module] = r
|
||||
k.cur.Inputs2 = &kept
|
||||
@@ -269,7 +275,7 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
r := of(key, nil)
|
||||
if _, merged := overlay[key]; merged {
|
||||
final := overlay[key]
|
||||
final.FP2, final.None2, final.Inputs2 = r.fp, r.none, k.cur.Inputs2
|
||||
final.FP2, final.None2, final.Inputs2, final.Toolchains = r.fp, r.none, k.cur.Inputs2, r.tcs
|
||||
// What the bases and the builder gave is kept as it was while the value it gave does not change, so a merge
|
||||
// that moves nothing for the module writes nothing (as Recompute does).
|
||||
if value, _, found, err := ix.Modules.Get(ctx, key); err == nil && found {
|
||||
@@ -282,7 +288,7 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
finals[key] = final
|
||||
continue
|
||||
}
|
||||
if k.cur.FP2 == r.fp && k.cur.None2 == r.none {
|
||||
if k.cur.FP2 == r.fp && k.cur.None2 == r.none && reflect.DeepEqual(k.cur.Toolchains, r.tcs) {
|
||||
continue
|
||||
}
|
||||
digest, inputs := k.cur.Manifest, k.cur.Inputs2
|
||||
@@ -294,10 +300,10 @@ func (ix *Indexer) recomputeWith(ctx context.Context, overlay map[string]deliver
|
||||
if err != nil || cur.Manifest != digest || cur.Inputs2 == nil {
|
||||
return nil, false, nil // a merge changed it meanwhile; its own recompute follows
|
||||
}
|
||||
if cur.FP2 == r.fp && cur.None2 == r.none {
|
||||
if cur.FP2 == r.fp && cur.None2 == r.none && reflect.DeepEqual(cur.Toolchains, r.tcs) {
|
||||
return nil, false, nil
|
||||
}
|
||||
cur.FP2, cur.None2 = r.fp, r.none
|
||||
cur.FP2, cur.None2, cur.Toolchains = r.fp, r.none, r.tcs
|
||||
cur.Inputs2 = inputs
|
||||
data, err := delivery.EncodeModule(cur)
|
||||
return data, false, err
|
||||
@@ -365,3 +371,15 @@ func hasContext(m catalogue.Manifest) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// toolchainsUsed are the toolchains a fingerprint was computed with, by language (an artifact's toolchain is its language's).
|
||||
func toolchainsUsed(by map[string]delivery.Toolchain2) map[string]delivery.ToolchainUsed {
|
||||
if len(by) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := map[string]delivery.ToolchainUsed{}
|
||||
for _, t := range by {
|
||||
out[t.Language] = delivery.ToolchainUsed{Version: t.Version, Recipe: t.Recipe}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package index
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -238,3 +239,30 @@ func TestAMergeKeepsAFingerprintTheModuleStillHas(t *testing.T) { // 1444 (revie
|
||||
t.Errorf("fp2 = %q (was %q), writes %d more", after.FP2, before.FP2, mods.writes-w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAModuleKeepsTheToolchainsItsFingerprintWasComputedWith(t *testing.T) { // 1615/AC3
|
||||
ix, mods := newFormIndexer(t, builderModules(t)...)
|
||||
if m, _ := moduleOf(t, mods, "avahi"); m.Toolchains != nil {
|
||||
t.Fatalf("before a toolchain is reported: toolchains = %+v, want none", m.Toolchains)
|
||||
}
|
||||
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.1")
|
||||
m, _ := moduleOf(t, mods, "avahi")
|
||||
want := map[string]delivery.ToolchainUsed{"go": {Version: "go1.27.1", Recipe: "1"}}
|
||||
if m.FP2 == "" || !reflect.DeepEqual(m.Toolchains, want) {
|
||||
t.Fatalf("avahi: fp2 %q toolchains %+v, want %+v", m.FP2, m.Toolchains, want)
|
||||
}
|
||||
if o, _ := moduleOf(t, mods, "other"); o.FP2 != "" || o.Toolchains != nil {
|
||||
t.Errorf("a module with no fingerprint carries toolchains %+v", o.Toolchains)
|
||||
}
|
||||
// An upgrade moves the fingerprint and the toolchains together, with no merge.
|
||||
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.2")
|
||||
n, _ := moduleOf(t, mods, "avahi")
|
||||
if n.FP2 == m.FP2 || n.Toolchains["go"].Version != "go1.27.2" {
|
||||
t.Errorf("after the upgrade: fp2 %q (was %q) toolchains %+v, want the new version with the new fingerprint", n.FP2, m.FP2, n.Toolchains)
|
||||
}
|
||||
// Nodes that disagree leave no fingerprint and no toolchains.
|
||||
reportToolchain(t, ix, "mesh-build-go", "ace", "go", "go1.26.0")
|
||||
if d, _ := moduleOf(t, mods, "avahi"); d.FP2 != "" || d.Toolchains != nil {
|
||||
t.Errorf("disagreeing nodes: fp2 %q toolchains %+v, want neither", d.FP2, d.Toolchains)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user