Compare commits

1 Commits

Author SHA1 Message Date
Ari-43 ccb132af4f Add tip to avoid duplicate search results 2026-05-17 12:30:43 -04:00
4 changed files with 6 additions and 154 deletions
+3 -64
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"github.com/Jguer/go-alpm/v2"
"github.com/c2h5oh/datasize"
"github.com/prometheus/client_golang/prometheus"
"github.com/sethvargo/go-retry"
@@ -465,74 +464,14 @@ func (b *BuildManager) genQueue(ctx context.Context) ([]*ProtoPackage, error) {
}
}
// Cross-check against the live pacman DB: state.git lags
// reality for pkgrel-only rebuilds and arch-any moves leave
// stale x86_64 state files behind. SyncPkg was resolved by
// isAvailable above; reuse it.
if pkg.SyncPkg != nil {
// Stale extra-any state file (upstream moved from any-arch to
// a concrete arch and state.git left the old any file behind).
// Skip this iteration without writing to the DB so the sibling
// concrete-arch state file is authoritative.
if pkg.SyncPkg.Architecture() != "any" && pkg.Arch == "any" {
log.Debugf("[QG] %s->%s ignoring stale extra-any state file (upstream arch: %s)",
pkg.FullRepo, pkg.Pkgbase, pkg.SyncPkg.Architecture())
continue
}
if pkg.SyncPkg.Architecture() == "any" && pkg.Arch == "x86_64" {
// Already marked from a prior cycle: nothing to redo.
// Accept SkipReasonAnyArch too — when both extra-any and
// extra-x86_64 state files exist, isEligible's any-path
// overwrites our SkipReason on alternate iterations, and
// without this we'd re-push the no-op purge every cycle.
if pkg.DBPackage.Status == dbpackage.StatusSkipped &&
(pkg.DBPackage.SkipReason == SkipReasonAnyArchMoved ||
pkg.DBPackage.SkipReason == SkipReasonAnyArch) {
continue
}
log.Infof("[QG] %s->%s upstream moved to any-arch, dropping", pkg.FullRepo, pkg.Pkgbase)
pkg.DBPackage, err = pkg.DBPackage.Update().
SetStatus(dbpackage.StatusSkipped).
SetSkipReason(SkipReasonAnyArchMoved).
SetTagRev(state.TagRev).
SetVersion(state.PkgVer).
Save(ctx)
if err != nil {
log.Warningf("[QG] error updating dbpackage %s: %v", state.Pkgbase, err)
continue
}
buildManager.repoPurge[pkg.FullRepo] <- []*ProtoPackage{pkg}
continue
}
// Compare against the published repo version once we have one,
// so we don't loop rebuilding from main every cycle while the
// state file remains stale. Fresh packages still compare
// against state.PkgVer to catch drift on the first build.
referenceVer := state.PkgVer
if pkg.DBPackage.RepoVersion != "" {
referenceVer = pkg.DBPackage.RepoVersion
}
if alpm.VerCmp(pkg.SyncPkg.Version(), referenceVer) > 0 {
log.Infof("[QG] %s->%s upstream version drift detected (have: %s < upstream: %s), building from %s",
pkg.FullRepo, pkg.Pkgbase, referenceVer, pkg.SyncPkg.Version(), upstreamDefaultGitBranch)
pkg.UseLatest = true
}
}
if !pkg.UseLatest && pkg.DBPackage.TagRev != nil && *pkg.DBPackage.TagRev == state.TagRev {
if pkg.DBPackage.TagRev != nil && *pkg.DBPackage.TagRev == state.TagRev {
continue
}
srcRef := state.TagRev
if pkg.UseLatest {
srcRef = upstreamDefaultGitBranch
}
srcInfo, err := downloadSRCINFO(pkg.DBPackage.Pkgbase, srcRef)
// try download .SRCINFO from repo
srcInfo, err := downloadSRCINFO(pkg.DBPackage.Pkgbase, state.TagRev)
if err == nil {
pkg.Srcinfo = srcInfo
if pkg.UseLatest {
pkg.Version = constructVersion(srcInfo.Pkgver, srcInfo.Pkgrel, srcInfo.Epoch)
}
}
if !pkg.isEligible(ctx) {
+1 -32
View File
@@ -2,7 +2,6 @@ package main
import (
"context"
"github.com/Jguer/go-alpm/v2"
log "github.com/sirupsen/logrus"
"os"
"os/exec"
@@ -147,30 +146,6 @@ func housekeeping(ctx context.Context, repo, march string, wg *sync.WaitGroup) e
return err
}
}
// detect upstream version drift: Arch sometimes ships a pkgrel
// rebuild without updating state.git, so state.TagRev never
// changes and genQueue never re-queues. Compare directly against
// the pacman sync DB (always current) and force a re-queue.
// Only act on settled packages; a Queued/Building/Delayed row is
// already moving and our SetStatus(Queued) would race it.
// Compare against RepoVersion (what we actually published): the
// Version column gets rewritten to state.PkgVer by isEligible's
// "repo higher than PKGBUILD" branch on subsequent passes, so it
// would falsely report drift on every cycle for drift-built pkgs.
if pkg.DBPackage.Status == dbpackage.StatusLatest &&
pkg.DBPackage.RepoVersion != "" && pkgResolved.Version() != "" &&
alpm.VerCmp(pkgResolved.Version(), pkg.DBPackage.RepoVersion) > 0 {
log.Infof("[HK] %s->%s upstream version drift detected (repo: %s < upstream: %s), requeuing",
pkg.FullRepo, pkg.Pkgbase, pkg.DBPackage.RepoVersion, pkgResolved.Version())
pkg.DBPackage, err = pkg.DBPackage.Update().
SetStatus(dbpackage.StatusQueued).
ClearTagRev().
Save(ctx)
if err != nil {
return err
}
}
}
// check all packages from db for existence
@@ -270,13 +245,7 @@ func housekeeping(ctx context.Context, repo, march string, wg *sync.WaitGroup) e
continue
}
// Only reset when state.git has moved ahead of us. If dbPkg is
// already at-or-above state.PkgVer the mismatch is from a drift
// rebuild (built from main while state.git stayed stale) and we
// must not bounce it back to queued — that produces a build loop.
if dbPkg.TagRev != nil && state.TagRev == *dbPkg.TagRev &&
state.PkgVer != dbPkg.Version &&
alpm.VerCmp(state.PkgVer, dbPkg.Version) > 0 {
if dbPkg.TagRev != nil && state.TagRev == *dbPkg.TagRev && state.PkgVer != dbPkg.Version {
log.Infof("[HK] reseting package %s->%s with mismatched state information (%s!=%s)",
fullRepo, dbPkg.Pkgbase, state.PkgVer, dbPkg.Version)
err = dbPkg.Update().SetStatus(dbpackage.StatusQueued).ClearTagRev().Exec(ctx)
+2 -29
View File
@@ -24,14 +24,6 @@ import (
"time"
)
// Skip reasons surfaced from the build pipeline. Hoisted so the same string
// is used wherever a package is skipped for that reason.
const (
SkipReasonAnyArch = "arch = any"
SkipReasonAnyArchMoved = "arch = any (moved upstream)"
upstreamDefaultGitBranch = "main"
)
type ProtoPackage struct {
Pkgbase string
Srcinfo *srcinfo.Srcinfo
@@ -44,13 +36,6 @@ type ProtoPackage struct {
DBPackage *ent.DBPackage
Pkgbuild string
State *StateInfo
// SyncPkg is the alpm package resolved by isAvailable; cached so
// later checks (drift, arch-any-move) don't re-do FindSatisfier.
SyncPkg alpm.IPackage
// UseLatest causes SRCINFO/PKGBUILD to be fetched from
// upstreamDefaultGitBranch (main) instead of state.TagVer/state.TagRev.
// Set when upstream Arch ships a rebuild that state.git did not record.
UseLatest bool
}
var (
@@ -62,7 +47,7 @@ func (p *ProtoPackage) isEligible(ctx context.Context) bool {
switch {
case p.Arch == "any":
log.Debugf("skipped %s: any-package", p.Pkgbase)
p.DBPackage.SkipReason = SkipReasonAnyArch
p.DBPackage.SkipReason = "arch = any"
p.DBPackage.Status = dbpackage.StatusSkipped
skipping = true
case MatchGlobList(p.Pkgbase, conf.Blacklist.Packages):
@@ -380,7 +365,7 @@ func (p *ProtoPackage) setupBuildDir(ctx context.Context) (string, error) {
gr = retry.WithMaxRetries(conf.MaxCloneRetries, gr)
if err := retry.Do(ctx, gr, func(ctx context.Context) error {
cmd := exec.CommandContext(ctx, "git", "clone", "--depth", "1", "--branch", p.cloneBranch(), //nolint:gosec
cmd := exec.CommandContext(ctx, "git", "clone", "--depth", "1", "--branch", p.State.TagVer, //nolint:gosec
fmt.Sprintf("https://gitlab.archlinux.org/archlinux/packaging/packages/%s.git", gitlabPath), buildDir)
res, err := cmd.CombinedOutput()
log.Debug(string(res))
@@ -556,21 +541,9 @@ func (p *ProtoPackage) isAvailable(ctx context.Context, h *alpm.Handle) bool {
return false
}
p.SyncPkg = pkg
return true
}
// cloneBranch returns the git ref to use when cloning the upstream
// packaging repo. The default ref is the tag recorded in state.git;
// UseLatest overrides that to track the package repo's main branch
// (used when state.git lags real upstream).
func (p *ProtoPackage) cloneBranch() string {
if p.UseLatest {
return upstreamDefaultGitBranch
}
return p.State.TagVer
}
func (p *ProtoPackage) GitVersion(h *alpm.Handle) (string, error) {
if p.Pkgbase == "" {
return "", errors.New("invalid arguments")
-29
View File
@@ -96,35 +96,6 @@ package() {
# vim:set sw=2 et:
`
func TestCloneBranch(t *testing.T) { //nolint:paralleltest
for _, tc := range []struct {
name string
useLatest bool
tagVer string
want string
}{
{"state-tag-default", false, "3.3-4", "3.3-4"},
{"main-when-drift", true, "3.3-4", "main"},
{"main-ignores-empty-tag", true, "", "main"},
} {
t.Run(tc.name, func(t *testing.T) {
p := &ProtoPackage{
UseLatest: tc.useLatest,
State: &StateInfo{TagVer: tc.tagVer},
}
if got := p.cloneBranch(); got != tc.want {
t.Errorf("cloneBranch() = %q, want %q", got, tc.want)
}
})
}
}
func TestSkipReasonsDistinct(t *testing.T) { //nolint:paralleltest
if SkipReasonAnyArch == SkipReasonAnyArchMoved {
t.Fatal("any-arch skip reasons must remain distinguishable: callers and operators inspect skip_reason to tell why a package was dropped")
}
}
func TestIncreasePkgRel(t *testing.T) { //nolint:paralleltest
pkgbuild, err := os.CreateTemp(t.TempDir(), "")
if err != nil {