Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/form.go
T
jschoubben fba98ee80f Indexer computes fingerprints alone, over the packages a module imports
The fingerprint, named tree and package versions move from mesh-sdk into the
indexer's internal/fingerprint (ADR 0593 §2). The indexer publishes each reached
mesh Go module's package digests from the forge's listing in its new packages
state, keeps the imports a done build reports, and writes the import form only
when an input differs from the build that reported them (§4), so the form change
costs no rebuild and a package merge moves only its importers (§3). Candidates
take the same form against the group's member heads (D1-D4).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 18:25:57 +01:00

75 lines
3.4 KiB
Go

package index
import (
"strings"
"git.novox.be/novox/mesh-sdk/go/delivery"
"mesh-delivery-indexer/internal/fingerprint"
)
// form is a module's fingerprint, or why it has none, and the version of each mesh Go module of another repository
// its build is pinned to.
type form struct {
fp, none string
versions delivery.PackageVersions
}
// formOf is the module's fingerprint from its kept inputs (bases already its bases' fingerprints) and toolchains, in the
// form they call for (novox/hq ADR 0593 §2, §4):
//
// - **The import form**, for a module whose last trunk build reported its imports (kept.Imports) when every import is
// published (the packages state): the content digest of each imported package and the requirements' digest of each
// mesh Go module holding one. Its versions are each holding module's published commit (another repository's only).
// - **A change of form never rebuilds by itself** (§4): kept.ImportForm is the import-form fingerprint of the inputs
// the build that reported the imports was built from. While the import form computes to it, nothing the build was
// built from changed: the module keeps the fingerprint it holds (prev), in whatever form, and its versions.
// Otherwise the import form is written, and ImportForm moves with it.
// - **The version line** otherwise (no import set, or an import none publishes): the version of each mesh Go module its
// go.sum names, read as the indexer always read it (fingerprint.HeldVersionsOf), so its value is the one it had.
//
// It sets kept.ImportForm when it writes the import form.
func formOf(module, repository string, kept *delivery.KeptInputs2, toolchains map[string]delivery.Toolchain2, prev delivery.Module, held map[string]delivery.Module, published map[string]delivery.PublishedPackages, logf func(string, ...any)) form {
in := inputsFrom(module, *kept, toolchains)
if len(kept.Imports) > 0 {
r := fingerprint.Resolve(repository, kept.Imports, published)
if len(r.Missing) == 0 {
in.Imports, in.Requires = r.Digests, r.Requires
fp, none := fingerprint.Of(in)
switch {
case fp == "":
return form{none: none}
case kept.ImportForm == fp && prev.FP2 != "":
return form{fp: prev.FP2, versions: prev.Packages} // the build that reported the imports stands
}
kept.ImportForm = fp
return form{fp: fp, versions: r.Versions}
}
if logf != nil {
logf("%s: no published package holds %s, so its fingerprint takes the version line", module, strings.Join(r.Missing, ", "))
}
}
versions, unpublished := fingerprint.HeldVersionsOf(kept.Packages, held)
if len(unpublished) > 0 && logf != nil {
logf("%s: no module the indexer holds publishes %s, so its fingerprint takes no version of it", module, strings.Join(unpublished, ", "))
}
if len(kept.Packages) > 0 {
in.Packages = map[string]string{}
for _, p := range kept.Packages {
in.Packages[p] = versions[p]
}
}
fp, none := fingerprint.Of(in)
if fp == "" {
return form{none: none}
}
return form{fp: fp, versions: versions}
}
// inputsFrom is the fingerprint's inputs of module m from its kept inputs and the given toolchains, no package of
// either form yet.
func inputsFrom(module string, k delivery.KeptInputs2, toolchains map[string]delivery.Toolchain2) fingerprint.Inputs {
return fingerprint.Inputs{Module: module, Tree: k.Tree, Bases: k.Bases, Builder: k.Builder, Contexts: k.Contexts,
Locks: k.Locks, Toolchains: toolchains}
}