cmd/dist: replace dist/release.sh
All checks were successful
Test / Create distribution (push) Successful in 1m19s
Test / Sandbox (push) Successful in 3m12s
Test / Hakurei (push) Successful in 4m26s
Test / ShareFS (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m46s
Test / Hakurei (race detector) (push) Successful in 7m1s
Test / Flake checks (push) Successful in 1m29s

This is much more robust than a shell script.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-04-05 20:57:01 +09:00
parent 4cd0f57e48
commit a69273ab2a
9 changed files with 244 additions and 78 deletions

85
cmd/dist/comp/_hakurei vendored Normal file
View File

@@ -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'

232
cmd/dist/main.go vendored Normal file
View File

@@ -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)
}
}