123 lines
4.6 KiB
Go
123 lines
4.6 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The reasons a module has no fingerprint (ADR 0437 §5; issue 1209's decision).
|
|
const (
|
|
// NoneNarrow is for a module whose image compiles a Go program from a context: the context is the hash of the build
|
|
// source the builder handed it, not a git tree.
|
|
NoneNarrow = "an artifact compiles a Go program from a build source that git trees do not pin: no fingerprint before release 4"
|
|
// NoneContext is for a context that is a repository's root tree.
|
|
NoneContext = "an artifact reads the root tree of a repository the indexer does not know the tree of before release 4"
|
|
// NoneNoBuild is for a module no successful trunk build recorded the inputs of.
|
|
NoneNoBuild = "no successful trunk build recorded its inputs"
|
|
)
|
|
|
|
// fingerprintOf is the module's fingerprint at the merge, or none and why: its directory's tree from the merged
|
|
// message and the bases, contexts and toolchains its newest successful trunk build recorded.
|
|
func fingerprintOf(k Known, trees map[string]string) (fp, none string) {
|
|
if k.Trunk == nil {
|
|
return "", NoneNoBuild
|
|
}
|
|
in := *k.Trunk.SourceInputs
|
|
artifacts := make([]string, 0, len(in.Contexts))
|
|
for a := range in.Contexts {
|
|
artifacts = append(artifacts, a)
|
|
}
|
|
sort.Strings(artifacts)
|
|
for _, a := range artifacts {
|
|
if strings.HasPrefix(in.Contexts[a], "narrow:") {
|
|
return "", NoneNarrow
|
|
}
|
|
}
|
|
if len(artifacts) > 0 {
|
|
return "", NoneContext
|
|
}
|
|
in.Tree = trees[k.Path] // the directory "" is the repository's root
|
|
return delivery.SourceFingerprint(in)
|
|
}
|
|
|
|
// applyMerged writes, for each module built from the merged repository, its fingerprint at the merge commit (or none and
|
|
// why), 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. A module of another repository is not written. A value the module already
|
|
// holds is not written again. From the manifests and lock hashes the message carries (the forge bridge, issue 1448) it
|
|
// also writes the module's manifest digest, its new-form inputs and why it has no new-form fingerprint (issues 1444, 1449,
|
|
// 1450); this release writes no fingerprint of the new form for any module.
|
|
func (ix *Indexer) applyMerged(ctx context.Context, f delivery.Forge) error {
|
|
digests, err := ix.keepManifests(ctx, f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, k := range ix.Builds.Modules(f.Repository) {
|
|
key, err := delivery.ModulesKey(k.Module)
|
|
if err != nil {
|
|
ix.logf("%s: the module %q has no usable key, skipped: %v", f.Repository, k.Module, err)
|
|
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]}
|
|
// 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]
|
|
switch {
|
|
case !has:
|
|
next.None2 = None2NoManifest
|
|
case next.Manifest == "":
|
|
next.None2 = "the manifest cannot be read: it cannot be kept as a value"
|
|
default:
|
|
in := inputsOf(k.Module, raw, f.Trees[k.Path], f.Locks[k.Path], ix.baseFP(ctx))
|
|
next.Inputs2, next.None2 = in.Kept, in.None2
|
|
}
|
|
err = write(ctx, ix.Modules, key, func(value []byte, found bool) ([]byte, bool, error) {
|
|
if found {
|
|
if cur, err := delivery.DecodeModule(value); err == nil && reflect.DeepEqual(cur, withV(next)) {
|
|
return nil, false, nil
|
|
}
|
|
}
|
|
data, err := delivery.EncodeModule(next)
|
|
return data, false, err
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("modules.%s: %w", key, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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"
|
|
}
|
|
}
|
|
|
|
func withV(m delivery.Module) delivery.Module { m.V = delivery.Version; return m }
|