diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-04-05 20:57:01 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-04-05 23:58:08 +0900 |
| commit | a69273ab2a7040ba906876e6d7888b4edeb74ebc (patch) | |
| tree | 0379e49590110d6f4505e0de1671506a46da47b7 /cmd/dist | |
| parent | 4cd0f57e48c94e7f628446d050027165fdd9e315 (diff) | |
cmd/dist: replace dist/release.sh
This is much more robust than a shell script.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/dist')
| -rw-r--r-- | cmd/dist/comp/_hakurei | 85 | ||||
| -rw-r--r-- | cmd/dist/main.go | 232 |
2 files changed, 317 insertions, 0 deletions
diff --git a/cmd/dist/comp/_hakurei b/cmd/dist/comp/_hakurei new file mode 100644 index 00000000..11424612 --- /dev/null +++ b/cmd/dist/comp/_hakurei @@ -0,0 +1,85 @@ +#compdef hakurei + +_hakurei_run() { + __hakurei_files + return $? +} + +_hakurei_exec() { + _arguments \ + '--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \ + '-a[Application identity]: :_numbers' \ + '-g[Groups inherited by all container processes]: :_groups' \ + '-d[Container home directory]: :_files -/' \ + '-u[Passwd user name within sandbox]: :_users' \ + '--private-runtime[Do not share XDG_RUNTIME_DIR between containers under the same identity]' \ + '--private-tmpdir[Do not share TMPDIR between containers under the same identity]' \ + '--wayland[Enable connection to Wayland via security-context-v1]' \ + '-X[Enable direct connection to X11]' \ + '--dbus[Enable proxied connection to D-Bus]' \ + '--pipewire[Enable connection to PipeWire via SecurityContext]' \ + '--pulse[Enable PulseAudio compatibility daemon]' \ + '--dbus-config[Path to session bus proxy config file]: :_files -g "*.json"' \ + '--dbus-system[Path to system bus proxy config file]: :_files -g "*.json"' \ + '--mpris[Allow owning MPRIS D-Bus path]' \ + '--dbus-log[Force buffered logging in the D-Bus proxy]' +} + +_hakurei_ps() { + _arguments \ + '--short[List instances only]' +} + +_hakurei_show() { + _alternative \ + 'instances:domains:__hakurei_instances' \ + 'files:files:__hakurei_files' +} + +__hakurei_files() { + _files -g "*.(json|hakurei)" + return $? +} + +__hakurei_instances() { + local -a out + shift -p + out=( ${(f)"$(_call_program commands hakurei ps --short 2>&1)"} ) + if (( $#out == 0 )); then + _message "No active instances" + else + _describe "active instances" out + fi + return $? +} + +(( $+functions[_hakurei_commands] )) || _hakurei_commands() +{ + local -a _hakurei_cmds + _hakurei_cmds=( + "run:Load and start container from configuration file" + "exec:Configure and start a permissive container" + "show:Show live or local instance configuration" + "ps:List active instances" + "version:Display version information" + "license:Show full license text" + "template:Produce a config template" + "help:Show help message" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'action' _hakurei_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_hakurei_cmds[(r)$words[1]:*]%%:*}}" + if (( $+functions[_hakurei_$cmd] )); then + _hakurei_$cmd + else + _message "no more options" + fi + fi +} + +_arguments -C \ + '-v[Increase log verbosity]' \ + '--json[Serialise output in JSON when applicable]' \ + '*::hakurei command:_hakurei_commands'
\ No newline at end of file diff --git a/cmd/dist/main.go b/cmd/dist/main.go new file mode 100644 index 00000000..d3555e86 --- /dev/null +++ b/cmd/dist/main.go @@ -0,0 +1,232 @@ +//go:build dist + +package main + +import ( + "archive/tar" + "compress/gzip" + "context" + "crypto/sha512" + _ "embed" + "encoding/hex" + "fmt" + "io" + "io/fs" + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "runtime" +) + +// getenv looks up an environment variable, and returns fallback if it is unset. +func getenv(key, fallback string) string { + if v, ok := os.LookupEnv(key); ok { + return v + } + return fallback +} + +// mustRun runs a command with the current process's environment and panics +// on error or non-zero exit code. +func mustRun(ctx context.Context, name string, arg ...string) { + cmd := exec.CommandContext(ctx, name, arg...) + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + if err := cmd.Run(); err != nil { + panic(err) + } +} + +//go:embed comp/_hakurei +var comp []byte + +func main() { + fmt.Println() + log.SetFlags(0) + log.SetPrefix("# ") + + version := getenv("HAKUREI_VERSION", "untagged") + prefix := getenv("PREFIX", "/usr") + destdir := getenv("DESTDIR", "dist") + + if err := os.MkdirAll(destdir, 0755); err != nil { + log.Fatal(err) + } + s, err := os.MkdirTemp(destdir, ".dist.*") + if err != nil { + log.Fatal(err) + } + defer func() { + var code int + + if err = os.RemoveAll(s); err != nil { + code = 1 + log.Println(err) + } + + if r := recover(); r != nil { + code = 1 + log.Println(r) + } + + os.Exit(code) + }() + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + + log.Println("Building hakurei.") + mustRun(ctx, "go", "generate", "./...") + mustRun( + ctx, "go", "build", + "-trimpath", + "-v", "-o", s, + "-ldflags=-s -w "+ + "-buildid= -linkmode external -extldflags=-static "+ + "-X hakurei.app/internal/info.buildVersion="+version+" "+ + "-X hakurei.app/internal/info.hakureiPath="+prefix+"/bin/hakurei "+ + "-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu "+ + "-X main.hakureiPath="+prefix+"/bin/hakurei", + "./...", + ) + fmt.Println() + + log.Println("Testing Hakurei.") + mustRun( + ctx, "go", "test", + "-ldflags=-buildid= -linkmode external -extldflags=-static", + "./...", + ) + fmt.Println() + + log.Println("Creating distribution.") + const suffix = ".tar.gz" + distName := "hakurei-" + version + "-" + runtime.GOARCH + var f *os.File + if f, err = os.OpenFile( + filepath.Join(s, distName+suffix), + os.O_CREATE|os.O_EXCL|os.O_WRONLY, + 0644, + ); err != nil { + panic(err) + } + defer func() { + if f == nil { + return + } + if err = f.Close(); err != nil { + log.Println(err) + } + }() + + h := sha512.New() + gw := gzip.NewWriter(io.MultiWriter(f, h)) + tw := tar.NewWriter(gw) + + mustWriteHeader := func(name string, size int64, mode os.FileMode) { + header := tar.Header{ + Name: filepath.Join(distName, name), + Size: size, + Mode: int64(mode), + Uname: "root", + Gname: "root", + } + + if mode&os.ModeDir != 0 { + header.Typeflag = tar.TypeDir + fmt.Printf("%s %s\n", mode, name) + } else { + header.Typeflag = tar.TypeReg + fmt.Printf("%s %s (%d bytes)\n", mode, name, size) + } + + if err = tw.WriteHeader(&header); err != nil { + panic(err) + } + } + + mustWriteFile := func(name string, data []byte, mode os.FileMode) { + mustWriteHeader(name, int64(len(data)), mode) + if mode&os.ModeDir != 0 { + return + } + if _, err = tw.Write(data); err != nil { + panic(err) + } + } + + mustWriteFromPath := func(dst, src string) { + var r *os.File + if r, err = os.Open(src); err != nil { + panic(err) + } + + var fi os.FileInfo + if fi, err = r.Stat(); err != nil { + _ = r.Close() + panic(err) + } + + mustWriteHeader(dst, fi.Size(), fi.Mode()) + if _, err = io.Copy(tw, r); err != nil { + _ = r.Close() + panic(err) + } else if err = r.Close(); err != nil { + panic(err) + } + } + + mustWriteFile(".", nil, fs.ModeDir|0755) + mustWriteFile("comp/", nil, os.ModeDir|0755) + mustWriteFile("comp/_hakurei", comp, 0644) + mustWriteFile("install.sh", []byte(`#!/bin/sh -e +cd "$(dirname -- "$0")" || exit 1 + +install -vDm0755 "bin/hakurei" "${DESTDIR}`+prefix+`/bin/hakurei" +install -vDm0755 "bin/sharefs" "${DESTDIR}`+prefix+`/bin/sharefs" + +install -vDm4511 "bin/hsu" "${DESTDIR}`+prefix+`/bin/hsu" +if [ ! -f "${DESTDIR}/etc/hsurc" ]; then + install -vDm0400 "hsurc.default" "${DESTDIR}/etc/hsurc" +fi + +install -vDm0644 "comp/_hakurei" "${DESTDIR}`+prefix+`/share/zsh/site-functions/_hakurei" +`), 0755) + + mustWriteFromPath("README.md", "README.md") + mustWriteFile("hsurc.default", []byte("1000 0"), 0400) + for _, name := range []string{ + "hsu", + "hakurei", + "sharefs", + } { + mustWriteFromPath( + filepath.Join("bin", name), + filepath.Join(s, name), + ) + } + + if err = tw.Close(); err != nil { + panic(err) + } else if err = gw.Close(); err != nil { + panic(err) + } else if err = f.Close(); err != nil { + panic(err) + } + f = nil + + if err = os.WriteFile( + filepath.Join(destdir, distName+suffix+".sha512"), + append(hex.AppendEncode(nil, h.Sum(nil)), " "+distName+suffix+"\n"...), + 0644, + ); err != nil { + panic(err) + } + if err = os.Rename( + filepath.Join(s, distName+suffix), + filepath.Join(destdir, distName+suffix), + ); err != nil { + panic(err) + } +} |
