Skip to content
quarry Artifact [edf79dc5e4]
Login

Artifact [edf79dc5e4]

Artifact edf79dc5e4b6b3c85a9d1dcdc5bb80d250cf82e0687fd028bf7b324c503e0dce:


package main

import (
	"context"
	"log"

	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/markup"
)

// closePage is how many new check-ins one read of the sweep takes; a
// larger push is walked a page at a time within the same pass.
const closePage = 50

// closeSweep closes the tickets new default-branch check-ins say they
// close (quarry#298), fossil-style: "closes #12" in a check-in comment
// does what it does in a landing's message. Runs after every fold, on
// the lease holder only.
//
// A durable watermark bounds what is new, so the history a repository
// arrives with — a mirror's, or anything folded before this sweep
// existed — is baselined at first sight, never read as a list of
// closes. A repository first seen EMPTY has no history: its watermark
// is recorded as "", the beginning, so its first push is all new. A per-check-in mark makes each close happen once across
// restarts and re-folds. A landing's own merge is left to the landing,
// whose accept closes what it named; a tracking mirror's tracker
// belongs to its upstream and is not written.
func (rg *registrar) closeSweep(name string, ix *index.Index) {
	if rg.odb == nil || rg.deps == nil || ix == nil {
		return
	}
	if rg.deps.Mirrors != nil {
		if m, ok, err := rg.deps.Mirrors.MirrorFor(name); err != nil || (ok && m.Enabled) {
			return
		}
	}
	watch, seen := rg.odb.CloseWatch(name)
	if !seen {
		tip, err := ix.CheckinsAfter("", 1)
		if err != nil {
			return
		}
		if len(tip) == 1 {
			_ = rg.odb.SetCloseWatch(name, tip[0].Hash)
		} else if rg.storeEmpty(name) {
			_ = rg.odb.SetCloseWatch(name, "")
		}
		return
	}
	// A watermark the index does not hold (a reindex part-way through)
	// would read as "only the newest check-in is new", and that one may
	// be history. Wait for the index to catch up instead.
	if watch != "" {
		if known, err := ix.BranchOf([]string{watch}); err != nil || known[watch] == "" {
			return
		}
	}
	branch := ix.DefaultBranch()
	for {
		var fresh []index.TimelineEntry
		var err error
		if watch == "" {
			fresh, err = ix.OldestCheckins(closePage)
		} else {
			fresh, err = ix.CheckinsAfter(watch, closePage)
		}
		if err != nil || len(fresh) == 0 {
			return
		}
		for _, c := range fresh {
			if c.Branch == branch {
				rg.closeFrom(name, ix, c)
			}
		}
		watch = fresh[len(fresh)-1].Hash
		if err := rg.odb.SetCloseWatch(name, watch); err != nil {
			log.Printf("close: %s: watermark: %v", name, err)
			return
		}
		if len(fresh) < closePage {
			return
		}
	}
}

// storeEmpty asks the store, not the index, whether a repository holds
// no check-in. An index that has not folded yet is empty too, and
// reading that as "created empty" would turn its whole history into
// closes on the next fold.
func (rg *registrar) storeEmpty(name string) bool {
	repo, ok := rg.deps.Repos.Get(name)
	if !ok || repo.Zit == nil {
		return false
	}
	leaves, err := repo.Zit.Leaves(context.Background())
	return err == nil && len(leaves) == 0
}

// closeFrom closes what one default-branch check-in names, once.
func (rg *registrar) closeFrom(name string, ix *index.Index, c index.TimelineEntry) {
	if len(markup.ClosingRefs(c.Comment)) == 0 {
		return
	}
	if done, err := rg.odb.CheckinClosed(name, c.Hash); err != nil || done {
		return
	}
	if merge, err := ix.IsLandingMerge(c.Hash); err != nil || merge {
		return
	}
	rg.deps.CloseFromCheckin(name, c)
	if err := rg.odb.MarkCheckinClosed(name, c.Hash); err != nil {
		log.Printf("close: %s %.12s: mark: %v", name, c.Hash, err)
	}
}