aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-07-25 14:14:34 +0900
committerOphestra <cat@gensokyo.uk>2026-07-25 14:14:34 +0900
commit0d3efeb456117b87f256e3bfaabd5abbace67ab4 (patch)
tree7405be7a58e634f2d6d1fa00b34b3e054e35666c
parent35147f6dfb0b81d2fe21f69b3800162b0cd7060f (diff)
internal/rosa: remove xz utils hack
This replaces all xz invocations with the native decompressor. This also significantly cleans up the Gentoo stage3 bootstrap path. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/rosa/busybox.go124
-rw-r--r--internal/rosa/gentoo.go104
-rw-r--r--internal/rosa/llvm_test.go2
-rw-r--r--internal/rosa/package/gnu.az6
-rw-r--r--internal/rosa/rosa.go56
-rw-r--r--internal/rosa/state.go15
6 files changed, 131 insertions, 176 deletions
diff --git a/internal/rosa/busybox.go b/internal/rosa/busybox.go
deleted file mode 100644
index ae900a04..00000000
--- a/internal/rosa/busybox.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package rosa
-
-import (
- "fmt"
- "io"
- "net/http"
- "os"
- "time"
-
- "hakurei.app/fhs"
- "hakurei.app/internal/pkg"
-)
-
-// busyboxBin is a busybox binary distribution installed under bin/busybox.
-type busyboxBin struct {
- // Underlying busybox binary.
- bin pkg.FileArtifact
-}
-
-// Kind returns the hardcoded [pkg.Kind] value.
-func (a busyboxBin) Kind() pkg.Kind { return kindBusyboxBin }
-
-// Params is a noop.
-func (a busyboxBin) Params(*pkg.IContext) {}
-
-// IsExclusive returns false: Cure performs a trivial filesystem write.
-func (busyboxBin) IsExclusive() bool { return false }
-
-// Inputs returns the underlying busybox [pkg.FileArtifact].
-func (a busyboxBin) Inputs() []pkg.Artifact {
- return []pkg.Artifact{a.bin}
-}
-
-func init() {
- pkg.Register(kindBusyboxBin, func(r *pkg.IRReader) pkg.Artifact {
- a := busyboxBin{r.Next().(pkg.FileArtifact)}
- if _, ok := r.Finalise(); ok {
- panic(pkg.ErrUnexpectedChecksum)
- }
- return a
- })
-}
-
-// String returns the reporting name of the underlying file prefixed with expand.
-func (a busyboxBin) String() string {
- return "expand-" + a.bin.(fmt.Stringer).String()
-}
-
-// Cure installs the underlying busybox [pkg.File] to bin/busybox.
-func (a busyboxBin) Cure(t *pkg.TContext) (err error) {
- var r io.ReadCloser
- if r, err = t.Open(a.bin); err != nil {
- return
- }
- defer func() {
- closeErr := r.Close()
- if err == nil {
- err = closeErr
- }
- }()
-
- binDir := t.GetWorkDir().Append("bin")
- if err = os.MkdirAll(binDir.String(), 0700); err != nil {
- return
- }
-
- var w *os.File
- if w, err = os.OpenFile(
- binDir.Append("busybox").String(),
- os.O_WRONLY|os.O_CREATE|os.O_EXCL,
- 0500,
- ); err != nil {
- return
- }
- defer func() {
- closeErr := w.Close()
- if err == nil {
- err = closeErr
- }
- }()
-
- _, err = io.Copy(w, r)
- return
-}
-
-// newBusyboxBin returns a [pkg.Artifact] containing a busybox installation from
-// the https://busybox.net/downloads/binaries/ binary release.
-func (s *S) newBusyboxBin() pkg.Artifact {
- var version, url, checksum string
- switch s.arch {
- case "amd64":
- version = "1.35.0"
- url = "https://busybox.net/downloads/binaries/" +
- version + "-" + s.linuxArch() + "-linux-musl/busybox"
- checksum = "L7OBIsPu9enNHn7FqpBT1kOg_mCLNmetSeNMA3i4Y60Z5jTgnlX3qX3zcQtLx5AB"
- case "arm64":
- version = "1.31.0"
- url = "https://busybox.net/downloads/binaries/" +
- version + "-defconfig-multiarch-musl/busybox-armv8l"
- checksum = "npJjBO7iwhjW6Kx2aXeSxf8kXhVgTCDChOZTTsI8ZfFfa3tbsklxRiidZQdrVERg"
-
- default:
- panic("unsupported target " + s.arch)
- }
-
- return pkg.NewExec(
- "busybox-bin-"+version, s.arch, nil, pkg.ExecTimeoutMax, false, false,
- fhs.AbsRoot, []string{
- "PATH=/system/bin",
- },
- AbsSystem.Append("bin", "busybox"),
- []string{"hush", "-c", "" +
- "busybox mkdir -p /work/system/bin/ && " +
- "busybox cp /system/bin/busybox /work/system/bin/ && " +
- "busybox --install -s /work/system/bin/"},
- pkg.Path(AbsSystem, true, busyboxBin{pkg.NewHTTPGet(
- &http.Client{Transport: &http.Transport{
- // busybox website is really slow to respond
- TLSHandshakeTimeout: 2 * time.Minute,
- }}, url,
- mustDecode(checksum),
- )}),
- )
-}
diff --git a/internal/rosa/gentoo.go b/internal/rosa/gentoo.go
new file mode 100644
index 00000000..a0a8e525
--- /dev/null
+++ b/internal/rosa/gentoo.go
@@ -0,0 +1,104 @@
+package rosa
+
+import (
+ "errors"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "hakurei.app/internal/pkg"
+)
+
+// gentooOverlay are symlinks on top of a Gentoo LLVM stage3 tarball for
+// compatibility with the Rosa OS stage0 distribution.
+type gentooOverlay struct{ stage3 pkg.Artifact }
+
+// Kind returns the hardcoded [pkg.Kind] value.
+func (a gentooOverlay) Kind() pkg.Kind { return kindGentooOverlay }
+
+// Params is a noop.
+func (a gentooOverlay) Params(*pkg.IContext) {}
+
+// IsExclusive returns false: Cure performs a trivial filesystem write.
+func (gentooOverlay) IsExclusive() bool { return false }
+
+// Inputs returns the underlying Gentoo stage3.
+func (a gentooOverlay) Inputs() []pkg.Artifact {
+ return []pkg.Artifact{a.stage3}
+}
+
+func init() {
+ pkg.Register(kindGentooOverlay, func(r *pkg.IRReader) pkg.Artifact {
+ a := gentooOverlay{r.Next()}
+ if _, ok := r.Finalise(); ok {
+ panic(pkg.ErrUnexpectedChecksum)
+ }
+ return a
+ })
+}
+
+// String returns a hardcoded name.
+func (a gentooOverlay) String() string { return "gentoo-overlay" }
+
+// Revision returns a hardcoded value incremented on layout changes.
+func (a gentooOverlay) Revision() uint64 { return 0 }
+
+// Cure installs the overlay.
+func (a gentooOverlay) Cure(f *pkg.FContext) (err error) {
+ pathname, _ := f.GetArtifact(a.stage3)
+ var stage3 *os.Root
+ if stage3, err = os.OpenRoot(pathname.String()); err != nil {
+ return err
+ }
+ defer func() {
+ closeErr := stage3.Close()
+ if err == nil {
+ err = closeErr
+ }
+ }()
+ fsys := stage3.FS()
+
+ system := f.GetWorkDir().Append("system")
+ bin := system.Append("bin")
+ if err = os.MkdirAll(bin.String(), 0700); err != nil {
+ return
+ }
+
+ linknames := []string{
+ "../../bin/sh",
+ }
+
+ var dents []os.DirEntry
+
+ const llvm = "usr/lib/llvm"
+ dents, err = fs.ReadDir(fsys, llvm)
+ if err != nil {
+ return
+ }
+ if len(dents) != 1 {
+ return errors.New("stage3 /" + llvm + " contains more than one entry")
+ }
+
+ llvmBin := filepath.Join(llvm, dents[0].Name(), "bin")
+ dents, err = fs.ReadDir(fsys, llvmBin)
+ if err != nil {
+ return
+ }
+ for _, dent := range dents {
+ linknames = append(linknames, filepath.Join(
+ "../..",
+ llvmBin,
+ dent.Name(),
+ ))
+ }
+
+ for _, linkname := range linknames {
+ if err = os.Symlink(
+ linkname,
+ bin.Append(filepath.Base(linkname)).String(),
+ ); err != nil {
+ return
+ }
+ }
+ return
+}
diff --git a/internal/rosa/llvm_test.go b/internal/rosa/llvm_test.go
index af5f6530..2b1d2e7d 100644
--- a/internal/rosa/llvm_test.go
+++ b/internal/rosa/llvm_test.go
@@ -8,7 +8,7 @@ import (
)
func TestLLVMInputs(t *testing.T) {
- const wantInputCount = 473
+ const wantInputCount = 470
_, llvm := rosa.Native().Std().MustLoad(rosa.H("llvm"))
var n int
diff --git a/internal/rosa/package/gnu.az b/internal/rosa/package/gnu.az
index d1da6b8a..7cfcc726 100644
--- a/internal/rosa/package/gnu.az
+++ b/internal/rosa/package/gnu.az
@@ -292,11 +292,14 @@ package findutils {
anitya = 812;
version# = "4.11.0";
- source = remoteFile {
+ source = remoteTar {
url = "https://ftpmirror.gnu.org/gnu/findutils/findutils-"+version+".tar.xz";
+ compress = xz;
checksum = "X-qsv9aUoBL583q-4iZcBI3_7Ufd3fSIqFmNLXWdEpUihlRfMpGGyAUt8SAvDKae";
};
+ writable = true;
+ chmod = true;
early = `
echo '#!/bin/sh' > gnulib-tests/test-c32ispunct.sh
echo 'int main(){return 0;}' > gnulib-tests/test-fstatat.c
@@ -307,7 +310,6 @@ echo 'int main(){return 0;}' > tests/xargs/test-sigusr.c
inputs = [
diffutils,
- xz,
sed,
];
}
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index de4229ea..456f82e7 100644
--- a/internal/rosa/rosa.go
+++ b/internal/rosa/rosa.go
@@ -26,8 +26,8 @@ const (
// kindEtc is the kind of [pkg.Artifact] of cureEtc.
kindEtc = iota + pkg.KindCustomOffset
- // kindBusyboxBin is the kind of [pkg.Artifact] of busyboxBin.
- kindBusyboxBin
+ // kindGentooOverlay is the kind of [pkg.Artifact] of gentooOverlay.
+ kindGentooOverlay
)
// mustDecode is like [pkg.MustDecode], but replaces the zero value and prints
@@ -97,15 +97,9 @@ func (s *S) earlyLDFLAGS(static bool) string {
}
const (
- // _stageBusybox denotes a busybox installation from the busyboxBin
- // binary distribution. This is defined as a [Stage] to make use of the
- // toolchain abstractions to preprocess stageGentoo and is not a real,
- // functioning toolchain. It does not contain any compilers.
- _stageBusybox Stage = iota
-
// stageGentoo denotes the toolchain in a Gentoo stage3 tarball. Special
// care must be taken to compile correctly against this stage.
- stageGentoo
+ stageGentoo Stage = iota
// stageIntermediateGentoo is like stageIntermediate, but compiled against
// stageGentoo.
@@ -239,11 +233,6 @@ func (t Toolchain) New(
var support []pkg.Artifact
switch t.stage {
- case _stageBusybox:
- name += "-early"
- support = slices.Concat([]pkg.Artifact{t.newBusyboxBin()}, extra)
- env = fixupEnviron(env, nil, "/system/bin")
-
case stageGentoo, stageEarly:
name += "-boot"
support = append(support, extra...)
@@ -251,22 +240,17 @@ func (t Toolchain) New(
if t.stage == stageEarly {
_, a := t.MustLoad(_stage0Dist)
support = append(support, a)
+ } else if t.gentooStage3 == nil {
+ panic(os.ErrInvalid)
} else {
- support = append(support, t.S.New(_stageBusybox).New("gentoo", 0, nil, nil, nil, `
-tar -C /work -xf /usr/src/stage3.tar.xz
-rm -rf /work/dev/ /work/proc/
-ln -vs ../usr/bin /work/bin
-mkdir -vp /work/system/bin
-(cd /work/system/bin && ln -vs \
- ../../bin/sh \
- ../../usr/lib/llvm/*/bin/* \
- .)
-`, pkg.Path(AbsUsrSrc.Append("stage3.tar.xz"), false,
- pkg.NewHTTPGet(
- nil, t.gentooStage3,
- t.gentooStage3Checksum,
- ),
- )))
+ support = append(support,
+ t.gentooStage3,
+ gentooOverlay{t.gentooStage3},
+ )
+ env = append(env,
+ "CC=clang",
+ "CXX=clang++",
+ )
}
env = fixupEnviron(env, []string{
EnvTriple + "=" + t.triple(),
@@ -516,20 +500,6 @@ func (t Toolchain) NewPackage(
sourceSuffix string
)
- if _, ok := source.(pkg.FileArtifact); ok {
- if attr.Writable || attr.Chmod ||
- wantsChmod || wantsWrite ||
- len(attr.Patches) > 0 {
- panic("source processing requested on a xz-compressed tarball")
- }
-
- sourceSuffix = ".tar.xz"
- scriptEarly += `
-tar -C /usr/src/ -xf '/usr/src/` + name + `.tar.xz'
-mv '/usr/src/` + rn + `' '/usr/src/` + name + `'
-`
- }
-
dir, create := helper.wantsDir()
helperScriptEarly := helper.scriptEarly()
if attr.EnterSource ||
diff --git a/internal/rosa/state.go b/internal/rosa/state.go
index 36fe9451..516efd81 100644
--- a/internal/rosa/state.go
+++ b/internal/rosa/state.go
@@ -213,10 +213,8 @@ type S struct {
// Cached [pkg.Artifact].
c [_stageEnd]sync.Map
- // URL of a Gentoo stage3 tarball.
- gentooStage3 string
- // Expected checksum of gentooStage3.
- gentooStage3Checksum pkg.Checksum
+ // Unpacked Gentoo LLVM stage3.
+ gentooStage3 pkg.Artifact
}
// Clone returns a copy of s.
@@ -485,6 +483,7 @@ func (s *S) getFrame() azalea.Frame {
k("gzip"): pkg.Gzip + compressOffset,
k("bzip2"): pkg.Bzip2 + compressOffset,
k("zstd"): pkg.Zstd + compressOffset,
+ k("xz"): pkg.XZ + compressOffset,
}
s.frame.Val = map[unique.Handle[azalea.Ident]]any{
@@ -803,6 +802,7 @@ func (s *S) getFrame() azalea.Frame {
k("gzip"): uint32(pkg.Gzip),
k("bzip2"): uint32(pkg.Bzip2),
k("zstd"): uint32(pkg.Zstd),
+ k("xz"): uint32(pkg.XZ),
}},
// high-level helpers
@@ -1372,12 +1372,15 @@ func (s *S) SetSource(fsys fs.FS) error {
// SetGentooStage3 sets the Gentoo stage3 tarball url and checksum. It panics
// if given zero values or if these values have already been set.
func (s *S) SetGentooStage3(url string, checksum pkg.Checksum) {
- if s.gentooStage3 != "" {
+ if s.gentooStage3 != nil {
panic(errors.New("attempting to set Gentoo stage3 url twice"))
}
if url == "" {
panic(errors.New("attempting to set Gentoo stage3 url to the zero value"))
}
- s.gentooStage3, s.gentooStage3Checksum = url, checksum
+ s.gentooStage3 = pkg.NewTar(pkg.NewDecompress(
+ pkg.NewHTTPGet(nil, url, checksum),
+ pkg.XZ,
+ ))
s.DropCaches(s.Arch(), s.Flags())
}