From 88e9a143d61b2416975abfca86017c3e2becfd43 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 19 Jan 2026 00:27:08 +0900 Subject: [PATCH] internal/rosa: toolchain abstraction This provides a clean and easy to use API over toolchains. A toolchain is an opaque set of artifacts and environment fixups. Exported toolchains should be functionally indistinguishable from each other. Signed-off-by: Ophestra --- internal/rosa/rosa.go | 86 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go index cec415a..1aff698 100644 --- a/internal/rosa/rosa.go +++ b/internal/rosa/rosa.go @@ -4,6 +4,9 @@ package rosa import ( "log" "runtime" + "slices" + "strconv" + "strings" "hakurei.app/container/fhs" "hakurei.app/internal/pkg" @@ -48,3 +51,86 @@ func linuxArch() string { panic("unsupported target " + runtime.GOARCH) } } + +// Toolchain denotes the infrastructure to compile a [pkg.Artifact] on. +type Toolchain uintptr + +const ( + // toolchainBusybox denotes a busybox installation from the busyboxBin + // binary distribution. This is for decompressing unsupported formats. + toolchainBusybox Toolchain = iota +) + +// lastIndexFunc is like [strings.LastIndexFunc] but for [slices]. +func lastIndexFunc[S ~[]E, E any](s S, f func(E) bool) (i int) { + if i = slices.IndexFunc(s, f); i < 0 { + return + } + if i0 := lastIndexFunc[S](s[i+1:], f); i0 >= 0 { + i = i0 + } + return +} + +// fixupEnviron fixes up PATH, prepends extras and returns the resulting slice. +func fixupEnviron(env, extras []string, paths ...string) []string { + const pathPrefix = "PATH=" + pathVal := strings.Join(paths, ":") + + if i := lastIndexFunc(env, func(s string) bool { + return strings.HasPrefix(s, pathPrefix) + }); i < 0 { + env = append(env, pathPrefix+pathVal) + } else { + if len(env[i]) == len(pathPrefix) { + env[i] = pathPrefix + pathVal + } else { + env[i] += ":" + pathVal + } + } + + return append(extras, env...) +} + +// absCureScript is the absolute pathname [Toolchain.New] places the fixed-up +// build script under. +var absCureScript = fhs.AbsUsrBin.Append(".cure-script") + +// New returns a [pkg.Artifact] compiled on this toolchain. +func (t Toolchain) New( + name string, + extra []pkg.Artifact, + checksum *pkg.Checksum, + env []string, + script string, + + paths ...pkg.ExecPath, +) pkg.Artifact { + var ( + path = AbsSystem.Append("bin", "busybox") + args = []string{"hush", absCureScript.String()} + support []pkg.Artifact + ) + switch t { + case toolchainBusybox: + support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra) + env = fixupEnviron(env, nil, "/system/bin") + + default: + panic("unsupported toolchain " + strconv.Itoa(int(t))) + } + + return pkg.NewExec( + name, checksum, pkg.ExecTimeoutMax, + fhs.AbsRoot, env, + path, args, + + slices.Concat([]pkg.ExecPath{pkg.Path( + fhs.AbsRoot, true, + support..., + ), pkg.Path( + absCureScript, false, + pkg.NewFile(".cure-script", []byte("set -e\n"+script)), + )}, paths)..., + ) +}