diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go new file mode 100644 index 0000000..372c0ac --- /dev/null +++ b/cmd/mbf/main.go @@ -0,0 +1,113 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + "os" + "os/signal" + "path/filepath" + "runtime" + "syscall" + + "hakurei.app/command" + "hakurei.app/container" + "hakurei.app/container/check" + "hakurei.app/internal/pkg" + "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 ( + flagVerbose bool + flagCures int + flagBase string + flagTShift int + ) + c := command.New(os.Stderr, log.Printf, "mbf", func([]string) (err error) { + msg.SwapVerbose(flagVerbose) + + 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 || flagTShift > 31 { + flagTShift = 31 + } + cache.SetThreshold(1 << flagTShift) + } + return + }).Flag( + &flagVerbose, + "v", command.BoolFlag(false), + "Print cure messages to the console", + ).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(31), + "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", + ) + } + + c.MustParse(os.Args[1:], func(err error) { + if cache != nil { + cache.Close() + } + log.Fatal(err) + }) +}