All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m53s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 3m10s
This removes the bootstrap dependency on Gentoo stage3 tarball. Signed-off-by: Ophestra <cat@gensokyo.uk>
251 lines
5.1 KiB
Go
251 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"runtime"
|
|
"syscall"
|
|
"unique"
|
|
|
|
"hakurei.app/command"
|
|
"hakurei.app/container"
|
|
"hakurei.app/container/check"
|
|
"hakurei.app/internal/pkg"
|
|
"hakurei.app/internal/rosa"
|
|
"hakurei.app/message"
|
|
)
|
|
|
|
func main() {
|
|
container.TryArgv0(nil)
|
|
|
|
log.SetFlags(0)
|
|
log.SetPrefix("mbf: ")
|
|
msg := message.New(log.Default())
|
|
|
|
if os.Geteuid() == 0 {
|
|
log.Fatal("this program must not run as root")
|
|
}
|
|
|
|
var cache *pkg.Cache
|
|
ctx, stop := signal.NotifyContext(context.Background(),
|
|
syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
|
defer stop()
|
|
defer func() {
|
|
if cache != nil {
|
|
cache.Close()
|
|
}
|
|
|
|
if r := recover(); r != nil {
|
|
fmt.Println(r)
|
|
log.Fatal("consider scrubbing the on-disk cache")
|
|
}
|
|
}()
|
|
|
|
var (
|
|
flagQuiet bool
|
|
flagCures int
|
|
flagBase string
|
|
flagTShift int
|
|
)
|
|
c := command.New(os.Stderr, log.Printf, "mbf", func([]string) (err error) {
|
|
msg.SwapVerbose(!flagQuiet)
|
|
|
|
var base *check.Absolute
|
|
if flagBase, err = filepath.Abs(flagBase); err != nil {
|
|
return
|
|
} else if base, err = check.NewAbs(flagBase); err != nil {
|
|
return
|
|
}
|
|
if cache, err = pkg.Open(ctx, msg, flagCures, base); err == nil {
|
|
if flagTShift < 0 {
|
|
cache.SetThreshold(0)
|
|
} else if flagTShift > 31 {
|
|
cache.SetThreshold(1 << 31)
|
|
} else {
|
|
cache.SetThreshold(1 << flagTShift)
|
|
}
|
|
}
|
|
return
|
|
}).Flag(
|
|
&flagQuiet,
|
|
"q", command.BoolFlag(false),
|
|
"Do not print cure messages",
|
|
).Flag(
|
|
&flagCures,
|
|
"cures", command.IntFlag(0),
|
|
"Maximum number of dependencies to cure at any given time",
|
|
).Flag(
|
|
&flagBase,
|
|
"d", command.StringFlag("cache"),
|
|
"Directory to store cured artifacts",
|
|
).Flag(
|
|
&flagTShift,
|
|
"tshift", command.IntFlag(-1),
|
|
"Dependency graph size exponent, to the power of 2",
|
|
)
|
|
|
|
{
|
|
var flagShifts int
|
|
c.NewCommand(
|
|
"scrub", "Examine the on-disk cache for errors",
|
|
func(args []string) error {
|
|
if len(args) > 0 {
|
|
return errors.New("scrub expects no arguments")
|
|
}
|
|
if flagShifts < 0 || flagShifts > 31 {
|
|
flagShifts = 12
|
|
}
|
|
return cache.Scrub(runtime.NumCPU() << flagShifts)
|
|
},
|
|
).Flag(
|
|
&flagShifts,
|
|
"shift", command.IntFlag(12),
|
|
"Scrub parallelism size exponent, to the power of 2",
|
|
)
|
|
}
|
|
|
|
{
|
|
var (
|
|
flagGentoo string
|
|
flagChecksum string
|
|
|
|
flagStage0 bool
|
|
)
|
|
c.NewCommand(
|
|
"stage3",
|
|
"Check for toolchain 3-stage non-determinism",
|
|
func(args []string) (err error) {
|
|
std := rosa.Std
|
|
if flagGentoo != "" {
|
|
std -= 3 // magic number to discourage misuse
|
|
|
|
var checksum pkg.Checksum
|
|
if len(flagChecksum) != 0 {
|
|
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
|
|
return
|
|
}
|
|
}
|
|
rosa.SetGentooStage3(flagGentoo, checksum)
|
|
}
|
|
|
|
_, _, _, stage1 := (std - 2).NewLLVM()
|
|
_, _, _, stage2 := (std - 1).NewLLVM()
|
|
_, _, _, stage3 := std.NewLLVM()
|
|
var (
|
|
pathname *check.Absolute
|
|
checksum [2]unique.Handle[pkg.Checksum]
|
|
)
|
|
|
|
if pathname, _, err = cache.Cure(stage1); err != nil {
|
|
return err
|
|
}
|
|
log.Println("stage1:", pathname)
|
|
|
|
if pathname, checksum[0], err = cache.Cure(stage2); err != nil {
|
|
return err
|
|
}
|
|
log.Println("stage2:", pathname)
|
|
if pathname, checksum[1], err = cache.Cure(stage3); err != nil {
|
|
return err
|
|
}
|
|
log.Println("stage3:", pathname)
|
|
|
|
if checksum[0] != checksum[1] {
|
|
err = &pkg.ChecksumMismatchError{
|
|
Got: checksum[0].Value(),
|
|
Want: checksum[1].Value(),
|
|
}
|
|
} else {
|
|
log.Println(
|
|
"stage2 is identical to stage3",
|
|
"("+pkg.Encode(checksum[0].Value())+")",
|
|
)
|
|
}
|
|
|
|
if flagStage0 {
|
|
if pathname, _, err = cache.Cure(
|
|
std.Load(rosa.Stage0),
|
|
); err != nil {
|
|
return err
|
|
}
|
|
log.Println(pathname)
|
|
}
|
|
|
|
return
|
|
},
|
|
).
|
|
Flag(
|
|
&flagGentoo,
|
|
"gentoo", command.StringFlag(""),
|
|
"Bootstrap from a Gentoo stage3 tarball",
|
|
).
|
|
Flag(
|
|
&flagChecksum,
|
|
"checksum", command.StringFlag(""),
|
|
"Checksum of Gentoo stage3 tarball",
|
|
).
|
|
Flag(
|
|
&flagStage0,
|
|
"stage0", command.BoolFlag(false),
|
|
"Create bootstrap stage0 tarball",
|
|
)
|
|
}
|
|
|
|
{
|
|
var (
|
|
flagDump string
|
|
)
|
|
c.NewCommand(
|
|
"cure",
|
|
"Cure the named artifact and show its path",
|
|
func(args []string) error {
|
|
if len(args) != 1 {
|
|
return errors.New("cure requires 1 argument")
|
|
}
|
|
if p, ok := rosa.ResolveName(args[0]); !ok {
|
|
return fmt.Errorf("unsupported artifact %q", args[0])
|
|
} else if flagDump == "" {
|
|
pathname, _, err := cache.Cure(rosa.Std.Load(p))
|
|
if err == nil {
|
|
log.Println(pathname)
|
|
}
|
|
return err
|
|
} else {
|
|
f, err := os.OpenFile(
|
|
flagDump,
|
|
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
|
|
0644,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = cache.EncodeAll(f, rosa.Std.Load(p)); err != nil {
|
|
_ = f.Close()
|
|
return err
|
|
}
|
|
|
|
return f.Close()
|
|
}
|
|
},
|
|
).
|
|
Flag(
|
|
&flagDump,
|
|
"dump", command.StringFlag(""),
|
|
"Write IR to specified pathname and terminate",
|
|
)
|
|
}
|
|
|
|
c.MustParse(os.Args[1:], func(err error) {
|
|
if cache != nil {
|
|
cache.Close()
|
|
}
|
|
log.Fatal(err)
|
|
})
|
|
}
|