aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-19 00:27:08 +0900
committerOphestra <cat@gensokyo.uk>2026-01-19 00:28:16 +0900
commit88e9a143d61b2416975abfca86017c3e2becfd43 (patch)
tree500f714df39e21b1f82c9c9b6e96a4f0113cee44
parent8d06c0235bf01d40d1455fac44519d9cf6983806 (diff)
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 <cat@gensokyo.uk>
-rw-r--r--internal/rosa/rosa.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index cec415aa..1aff698f 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)...,
+ )
+}