mesh/delivery merged: source.main moved to novox/mesh-delivery@b3a4b09f5b6f
mesh/check being carried to 907e092abc45 on b3a4b09f5b6f
The take-in tool's bound now says the take-in is still running and where its answer will be.
94 lines
3.5 KiB
Go
94 lines
3.5 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"maps"
|
|
"slices"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The gate's source revision (novox/hq ADR 0437 §5, ADR 0450 §1): source.main names every repository's merged head, and its
|
|
// revision in the bucket is the mesh's source revision. The indexer keeps the latest it has seen. A module is stamped
|
|
// with it (Module.Src) when the head the source names for its repository is the merge commit the module's fingerprint
|
|
// was computed at: from the modules bucket when the merge was heard first, and when the merge is heard after the source.
|
|
|
|
// sourceNow is the latest source revision seen.
|
|
type sourceNow struct {
|
|
rev uint64
|
|
heads map[string]string
|
|
}
|
|
|
|
// srcOf is the source revision that names this merge commit as the repository's head, or 0 when the latest source seen
|
|
// names another head or none has been seen.
|
|
func (ix *Indexer) srcOf(repository, merge string) uint64 {
|
|
ix.mu.Lock()
|
|
defer ix.mu.Unlock()
|
|
if ix.source.rev != 0 && merge != "" && ix.source.heads[repository] == merge {
|
|
return ix.source.rev
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ApplySource takes a revision of the gate's source.main in. An older revision than the latest seen is left. For each
|
|
// repository the source names, each module built from it whose fingerprint was computed at the head the source names, and
|
|
// that carries no Src yet, is written again with Src the revision (once: a later revision leaves it); a module computed at another commit is left (a merge heard later is stamped
|
|
// when it is written, applyMerged), and a repository none of the indexer's modules is built from writes nothing. The
|
|
// modules of a repository are those the modules bucket holds of it (ADR 0501 clause 6).
|
|
func (ix *Indexer) ApplySource(ctx context.Context, rev uint64, s delivery.Source) error {
|
|
ix.mu.Lock()
|
|
if rev < ix.source.rev {
|
|
ix.mu.Unlock()
|
|
return nil
|
|
}
|
|
ix.source = sourceNow{rev: rev, heads: maps.Clone(s.Heads)}
|
|
ix.mu.Unlock()
|
|
if ix.Modules == nil {
|
|
return ix.RecomputeCandidates(ctx)
|
|
}
|
|
// A registered module the forge could not read is read again at each new source revision (issue 1945), in the
|
|
// background: a forge that does not answer must not hold this revision. One taken in later is stamped when it is written
|
|
// (applyManifests reads srcOf).
|
|
ix.kickRetry(ctx)
|
|
held, err := ix.heldModules(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, key := range slices.Sorted(maps.Keys(held)) {
|
|
repository := ""
|
|
for r := range s.Heads {
|
|
if delivery.SameRepository(r, held[key].Repository) {
|
|
repository = r
|
|
}
|
|
}
|
|
if repository == "" {
|
|
continue
|
|
}
|
|
head := s.Heads[repository]
|
|
err = write(ctx, ix.Modules, key, func(value []byte, found bool) ([]byte, bool, error) {
|
|
if !found {
|
|
return nil, false, nil
|
|
}
|
|
cur, err := delivery.DecodeModule(value)
|
|
if err != nil {
|
|
ix.logf("modules.%s holds what is not a module, left: %v", key, err)
|
|
return nil, false, nil
|
|
}
|
|
// Stamped once, with the first revision naming the commit as the head: a later revision (a merge of another
|
|
// repository) leaves the value as it is, so no revision of the source rewrites a module that did not change.
|
|
if cur.Repository != repository || cur.Commit != head || cur.Src != 0 {
|
|
return nil, false, nil
|
|
}
|
|
cur.Src = rev
|
|
data, err := delivery.EncodeModule(cur)
|
|
return data, false, err
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("modules.%s: %w", key, err)
|
|
}
|
|
}
|
|
// A trunk that moved makes the previews made onto the old one out of date.
|
|
return ix.RecomputeCandidates(ctx)
|
|
}
|