cmd/mbf: validate build determinism
Test / Create distribution (push) Successful in 51s
Test / Sandbox (push) Successful in 2m56s
Test / ShareFS (push) Successful in 3m46s
Test / Hakurei (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 5m25s
Test / Hakurei (race detector) (push) Successful in 6m31s
Test / Flake checks (push) Successful in 1m6s
Test / Create distribution (push) Successful in 51s
Test / Sandbox (push) Successful in 2m56s
Test / ShareFS (push) Successful in 3m46s
Test / Hakurei (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 5m25s
Test / Hakurei (race detector) (push) Successful in 6m31s
Test / Flake checks (push) Successful in 1m6s
This rebuilds a package repeatedly and compares outcomes. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -27,6 +27,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@@ -897,6 +898,76 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"validate",
|
||||
"Repeatedly cure named artifact to validate determinism",
|
||||
func(args []string) error {
|
||||
if len(args) != 2 {
|
||||
return errors.New("validate requires 2 arguments")
|
||||
}
|
||||
|
||||
n, err := strconv.Atoi(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n < 2 {
|
||||
return errors.New("validate must rebuild at least twice")
|
||||
}
|
||||
|
||||
if cm.jobs < 1 {
|
||||
cm.jobs = runtime.NumCPU()/n + 1
|
||||
}
|
||||
|
||||
_, a := rosa.Native().Std().Load(rosa.ArtifactH(unique.Make(args[0])))
|
||||
if a == nil {
|
||||
return fmt.Errorf("unknown artifact %q", args[0])
|
||||
}
|
||||
|
||||
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(pkg.Encode(o.checksum.Value()))
|
||||
buf.WriteString(" (")
|
||||
buf.WriteString(o.pathname.String())
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
return errors.New(buf.String())
|
||||
}
|
||||
|
||||
for _, o := range r {
|
||||
msg.Verbosef("%s: %s", pkg.Encode(o.checksum.Value()), o.pathname)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
cleanC := c.New("clean", "Remove unused entries from the cache")
|
||||
cleanC.NewCommand(
|
||||
"fault",
|
||||
|
||||
Reference in New Issue
Block a user