28e133c298
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 3m3s
Test / ShareFS (push) Successful in 4m14s
Test / Hakurei (push) Successful in 4m28s
Test / Sandbox (race detector) (push) Successful in 5m48s
Test / Hakurei (race detector) (push) Successful in 7m1s
Test / Flake checks (push) Successful in 1m13s
This is currently not very usable due to hakurei immutable overlay mount limitations. Signed-off-by: Ophestra <cat@gensokyo.uk>
171 lines
3.6 KiB
Go
171 lines
3.6 KiB
Go
// 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"
|
|
"errors"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"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.NewCommand(
|
|
"run", "Start the named application",
|
|
func(args []string) error {
|
|
if len(args) != 1 {
|
|
return errors.New("run requires 1 argument")
|
|
}
|
|
|
|
var config *hst.Config
|
|
f, err := os.Open(base.Append("app", args[0]).String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
config, err = parse(args[0], base, f)
|
|
if closeErr := f.Close(); err == nil {
|
|
err = closeErr
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return run(ctx, msg, config)
|
|
},
|
|
)
|
|
|
|
c.MustParse(os.Args[1:], func(err error) {
|
|
if e, ok := errors.AsType[*exec.ExitError](err); ok && e != nil {
|
|
os.Exit(e.ExitCode())
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
})
|
|
}
|