81 lines
2.7 KiB
Go
81 lines
2.7 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 is
|
|
// written again with Src the revision; 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.
|
|
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 nil
|
|
}
|
|
repositories := slices.Sorted(maps.Keys(s.Heads))
|
|
for _, repository := range repositories {
|
|
head := s.Heads[repository]
|
|
for _, k := range ix.Builds.Modules(repository) {
|
|
key, err := delivery.ModulesKey(k.Module)
|
|
if err != nil {
|
|
ix.logf("%s: the module %q has no usable key, skipped: %v", repository, k.Module, err)
|
|
continue
|
|
}
|
|
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
|
|
}
|
|
if cur.Repository != repository || cur.Commit != head || cur.Src == rev {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|