// The app program is a proof-of-concept frontend for cmd/hakurei. // // This program is not covered by the compatibility promise. The command line // interface and configuration syntax may change at any time. package main import ( "context" "log" "os" "os/signal" "path/filepath" "syscall" "hakurei.app/check" "hakurei.app/command" "hakurei.app/fhs" "hakurei.app/hst" "hakurei.app/message" ) func main() { log.SetFlags(0) log.SetPrefix("app: ") msg := message.New(log.Default()) ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) defer stop() var ( flagVerbose bool flagBase string base, template, initial, upper, work *check.Absolute ) c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) { msg.SwapVerbose(flagVerbose) flagBase = os.ExpandEnv(flagBase) if flagBase == "" { flagBase = "state" } if flagBase, err = filepath.Abs(flagBase); err != nil { return } else if base, err = check.NewAbs(flagBase); err != nil { return } template = base.Append("template") initial = template.Append("initial") upper = template.Append("upper") work = template.Append("work") return }).Flag( &flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity", ).Flag( &flagBase, "d", command.StringFlag("$HAKUREI_APP_PATH"), "Configuration and state directory", ) { var ( flagShell string flagHome string ) c.NewCommand( "enter", "Enter mutable state template", func([]string) error { config := hst.Config{ ID: "app.hakurei.mutable", Container: &hst.ContainerConfig{ Hostname: "mutable", Filesystem: []hst.FilesystemConfigJSON{ {FilesystemConfig: &hst.FSOverlay{ Target: fhs.AbsRoot, Lower: []*check.Absolute{initial}, Upper: upper, Work: work, }}, {FilesystemConfig: &hst.FSEphemeral{ Target: fhs.AbsTmp, Write: true, Perm: 0755, }}, }, Username: "chronos", Flags: hst.FMultiarch | hst.FDevel | hst.FUserns | hst.FHostNet | hst.FTty, }, } if a, err := check.NewAbs(flagShell); err != nil { return err } else { config.Container.Shell = a config.Container.Path = a config.Container.Args = []string{ "-" + filepath.Base(flagShell), } } if a, err := check.NewAbs(flagHome); err != nil { return err } else { config.Container.Home = a } return run(ctx, msg, &config) }, ).Flag( &flagShell, "shell", command.StringFlag("/bin/zsh"), "Shell program within container", ).Flag( &flagHome, "home", command.StringFlag("/home/chronos"), "Home directory within container", ) } c.MustParse(os.Args[1:], func(err error) { if w, ok := err.(interface{ Unwrap() []error }); !ok { log.Fatal(err) } else { errs := w.Unwrap() for i, e := range errs { if i == len(errs)-1 { log.Fatal(e) } log.Println(e) } } }) }