aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/mbf/main.go
blob: 372c0acde402e31979b9727c7bdc6961d708cc4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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)
	})
}