diff --git a/.gitignore b/.gitignore index ed10d54f..fe160921 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,7 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib -*.pkg -/hakurei - -# Test binary, built with `go test -c` +# produced by tools and text editors +*.qcow2 *.test - -# Output of the go coverage tool, specifically when used with LiteIDE *.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work -go.work.sum - -# env file -.env .idea .vscode @@ -30,8 +10,5 @@ go.work.sum /internal/pkg/testdata/testtool /internal/rosa/hakurei_current.tar.gz -# release -/dist/hakurei-* - -# interactive nixos vm -nixos.qcow2 \ No newline at end of file +# cmd/dist default destination +/dist diff --git a/all.sh b/all.sh new file mode 100755 index 00000000..17b6b862 --- /dev/null +++ b/all.sh @@ -0,0 +1,6 @@ +#!/bin/sh -e + +TOOLCHAIN_VERSION="$(go version)" +cd "$(dirname -- "$0")/" +echo "# Building cmd/dist using ${TOOLCHAIN_VERSION}." +go run -v --tags=dist ./cmd/dist diff --git a/dist/comp/_hakurei b/cmd/dist/comp/_hakurei similarity index 100% rename from dist/comp/_hakurei rename to cmd/dist/comp/_hakurei diff --git a/cmd/dist/main.go b/cmd/dist/main.go new file mode 100644 index 00000000..af01777b --- /dev/null +++ b/cmd/dist/main.go @@ -0,0 +1,228 @@ +//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("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) { + if err = tw.WriteHeader(&tar.Header{ + Name: filepath.Join(distName, name), + Size: size, + Mode: int64(mode), + Uname: "root", + Gname: "root", + }); err != nil { + panic(err) + } + + if mode&os.ModeDir != 0 { + fmt.Printf("%s %s\n", mode, name) + } else { + fmt.Printf("%s %s (%d bytes)\n", mode, name, size) + } + } + + 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) + } +} diff --git a/dist/hsurc.default b/dist/hsurc.default deleted file mode 100644 index f770d5ef..00000000 --- a/dist/hsurc.default +++ /dev/null @@ -1 +0,0 @@ -1000 0 \ No newline at end of file diff --git a/dist/install.sh b/dist/install.sh deleted file mode 100755 index a4352288..00000000 --- a/dist/install.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -cd "$(dirname -- "$0")" || exit 1 - -install -vDm0755 "bin/hakurei" "${DESTDIR}/usr/bin/hakurei" -install -vDm0755 "bin/sharefs" "${DESTDIR}/usr/bin/sharefs" - -install -vDm4511 "bin/hsu" "${DESTDIR}/usr/bin/hsu" -if [ ! -f "${DESTDIR}/etc/hsurc" ]; then - install -vDm0400 "hsurc.default" "${DESTDIR}/etc/hsurc" -fi - -install -vDm0644 "comp/_hakurei" "${DESTDIR}/usr/share/zsh/site-functions/_hakurei" \ No newline at end of file diff --git a/dist/release.sh b/dist/release.sh deleted file mode 100755 index 1cfcc721..00000000 --- a/dist/release.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -e -cd "$(dirname -- "$0")/.." -VERSION="${HAKUREI_VERSION:-untagged}" -prefix="${PREFIX:-/usr}" -pname="hakurei-${VERSION}-$(go env GOARCH)" -out="${DESTDIR:-dist}/${pname}" - -destroy_workdir() { - rm -rf "${out}" -} -trap destroy_workdir EXIT - -echo '# Preparing distribution files.' -mkdir -p "${out}" -cp -v "README.md" "dist/hsurc.default" "dist/install.sh" "${out}" -cp -rv "dist/comp" "${out}" -echo - -echo '# Building hakurei.' -go generate ./... -go build -trimpath -v -o "${out}/bin/" -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" ./... -echo - -echo '# Testing hakurei.' -go test -ldflags='-buildid= -linkmode external -extldflags=-static' ./... -echo - -echo '# Creating distribution.' -rm -f "${out}.tar.gz" && tar -C "${out}/.." -vczf "${out}.tar.gz" "${pname}" -(cd "${out}/.." && sha512sum "${pname}.tar.gz" > "${pname}.tar.gz.sha512") -echo diff --git a/flake.nix b/flake.nix index 48cf3421..3cca5975 100644 --- a/flake.nix +++ b/flake.nix @@ -141,7 +141,7 @@ PATH="${pkgs.pkgsStatic.musl.bin}/bin:$PATH" \ DESTDIR="$out" \ HAKUREI_VERSION="v${hakurei.version}" \ - ./dist/release.sh + ./all.sh ''; } );