cmd/mbf: validate build determinism
Test / Create distribution (push) Successful in 3m24s
Test / Hakurei (push) Successful in 10m14s
Test / ShareFS (push) Successful in 11m4s
Test / Sandbox (push) Successful in 1m43s
Test / Sandbox (race detector) (push) Successful in 2m59s
Test / Hakurei (race detector) (push) Successful in 5m10s
Test / Flake checks (push) Successful in 2m35s

This rebuilds a package repeatedly and compares outcomes.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-07-08 16:17:11 +09:00
parent 6495118165
commit 9edb2780a4
+82
View File
@@ -27,6 +27,7 @@ import (
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"syscall"
@@ -897,6 +898,87 @@ func main() {
)
}
c.NewCommand(
"validate",
"Repeatedly cure named artifact to validate determinism",
func(args []string) error {
stage := rosa.Std
if len(args) == 3 {
switch args[0] {
case "boot":
stage -= 2
case "std":
stage -= 1
default:
return fmt.Errorf("invalid stage %q", args[0])
}
args = args[1:]
}
if len(args) != 2 {
return errors.New("validate requires 2 arguments")
}
n, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid passes %q", args[0])
}
if n < 2 {
return errors.New("validate must rebuild at least twice")
}
_, a := rosa.Native().New(stage).Load(rosa.ArtifactH(unique.Make(args[1])))
if a == nil {
return fmt.Errorf("unknown artifact %q", args[1])
}
if !a.IsExclusive() && cm.jobs < 1 {
cm.jobs = runtime.NumCPU()/n + 1
}
type res struct {
pathname *check.Absolute
checksum unique.Handle[pkg.Checksum]
}
r := make([]res, n)
if err = cm.Do(func(cache *pkg.Cache) error {
errs := make([]error, n)
var wg sync.WaitGroup
for i := range n {
wg.Go(func() {
r[i].pathname, r[i].checksum, errs[i] = cache.CureNew(a)
})
}
wg.Wait()
return errors.Join(errs...)
}); err != nil {
return err
}
for i := range n - 1 {
if r[i].checksum == r[i+1].checksum {
continue
}
var buf strings.Builder
buf.WriteString("nondeterminism:")
for _, o := range r {
buf.WriteString("\n\t")
buf.WriteString(filepath.Join(
cm.base,
"checksum",
pkg.Encode(o.checksum.Value()),
))
}
return errors.New(buf.String())
}
return nil
},
)
cleanC := c.New("clean", "Remove unused entries from the cache")
cleanC.NewCommand(
"fault",