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. 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) } 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 } 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) } } // A trunk that moved makes the previews made onto the old one out of date. return ix.RecomputeCandidates(ctx) }