69 Commits

Author SHA1 Message Date
42c93a57a4 internal/rosa: fix patches
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m51s
Test / Hakurei (push) Successful in 3m58s
Test / ShareFS (push) Successful in 4m5s
Test / Hpkg (push) Successful in 4m35s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m59s
Test / Flake checks (push) Successful in 1m53s
Turns out alacritty clobbers output. It turns tabs into spaces and also removes whitespace-only lines for some reason.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-23 02:12:09 +09:00
b1b14810ac internal/rosa/kernel: increase audio powersave timeout
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 3m45s
Test / ShareFS (push) Successful in 4m0s
Test / Hpkg (push) Successful in 4m28s
Test / Sandbox (race detector) (push) Successful in 5m8s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m38s
This feature is incredibly annoying as some amplifiers take time to wake up, and causes a non-insignificant amount of audio to be dropped.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-22 21:28:39 +09:00
de117ef365 internal/rosa: ncurses artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 3m55s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m40s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Flake checks (push) Successful in 1m46s
For running menuconfig.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-22 18:07:24 +09:00
5e4bf23e0c internal/rosa/musl: migrate to make helper
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m44s
Test / Hakurei (push) Successful in 3m57s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m38s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m12s
Test / Flake checks (push) Successful in 1m40s
This is much cleaner and eliminates the early ugliness.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-22 15:53:41 +09:00
d4519e2075 internal/rosa/make: expose --host
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m51s
Test / Hakurei (push) Successful in 4m26s
Test / ShareFS (push) Successful in 4m43s
Test / Hpkg (push) Successful in 5m18s
Test / Hakurei (race detector) (push) Successful in 6m37s
Test / Sandbox (race detector) (push) Successful in 2m30s
Test / Flake checks (push) Successful in 1m54s
This should be set alongside --build.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-22 15:14:09 +09:00
7f1e4cf43c internal/rosa: kernel artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m38s
Test / Hakurei (push) Successful in 3m58s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m38s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m37s
The configuration still wants some cleanup, but this works fine as a generic kernel for now.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 23:19:16 +09:00
d021621fba internal/rosa: install kernel headers out-of-tree
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 4m5s
Test / ShareFS (push) Successful in 4m8s
Test / Hpkg (push) Successful in 4m37s
Test / Sandbox (race detector) (push) Successful in 5m2s
Test / Hakurei (race detector) (push) Successful in 6m19s
Test / Flake checks (push) Successful in 1m45s
This is somewhat cheaper than the implementation with extra artifact and is more friendly to the make helper.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 19:16:10 +09:00
56567307ec internal/rosa: gnu tar artifact
All checks were successful
Test / Create distribution (push) Successful in 2m21s
Test / Sandbox (push) Successful in 5m17s
Test / Hakurei (push) Successful in 10m39s
Test / ShareFS (push) Successful in 12m32s
Test / Hakurei (race detector) (push) Successful in 3m28s
Test / Hpkg (push) Successful in 5m42s
Test / Sandbox (race detector) (push) Successful in 2m20s
Test / Flake checks (push) Successful in 1m44s
Initially, libarchive was going to be used, but its test suite simply does not want to work under musl, not even with libiconv. The ticket last discussing this ceased any activity in 2020.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 18:09:51 +09:00
0264a1ef09 internal/rosa: libiconv artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m48s
Test / Hakurei (push) Successful in 4m3s
Test / ShareFS (push) Successful in 3m56s
Test / Hpkg (push) Successful in 4m25s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 6m18s
Test / Flake checks (push) Successful in 1m45s
For software that assumes glibc.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 14:35:32 +09:00
0123bbee3d internal/rosa: bc artifact
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m32s
Test / Hakurei (push) Successful in 3m44s
Test / ShareFS (push) Successful in 3m57s
Test / Hpkg (push) Successful in 4m28s
Test / Sandbox (race detector) (push) Successful in 4m59s
Test / Hakurei (race detector) (push) Successful in 6m10s
Test / Flake checks (push) Successful in 1m41s
Required by the kernel.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 00:30:40 +09:00
771adad603 internal/rosa: texinfo artifact
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 4m5s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m34s
Test / Sandbox (race detector) (push) Successful in 5m6s
Test / Hakurei (race detector) (push) Successful in 6m16s
Test / Flake checks (push) Successful in 1m51s
Yet another wheel reinvented by GNU. Required to shut some GNU programs up.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-21 00:28:21 +09:00
178305cb22 internal/rosa: elfutils artifact
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 3m56s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m37s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m40s
Required by the kernel.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-20 21:51:07 +09:00
c2456e252c internal/rosa: musl-obstack artifact
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m45s
Test / Hakurei (push) Successful in 3m57s
Test / ShareFS (push) Successful in 4m5s
Test / Hpkg (push) Successful in 4m42s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 6m2s
Test / Flake checks (push) Successful in 1m38s
Yet another nonstandard glibc extension used by elfutils.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-20 21:34:59 +09:00
273068b90c internal/rosa: musl-fts artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m38s
Test / Hakurei (push) Successful in 3m55s
Test / ShareFS (push) Successful in 3m56s
Test / Hpkg (push) Successful in 4m24s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 3m24s
Test / Flake checks (push) Successful in 1m54s
Another nonstandard glibc extension used by elfutils.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-20 21:29:09 +09:00
16b20e1d34 internal/rosa: argp-standalone artifact
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m44s
Test / Hakurei (push) Successful in 3m56s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m48s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Flake checks (push) Successful in 1m43s
Nonstandard glibc extension used by elfutils.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-20 21:19:34 +09:00
b983917a6e internal/rosa: expose kernel source
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m52s
Test / Hakurei (push) Successful in 4m7s
Test / ShareFS (push) Successful in 4m8s
Test / Hpkg (push) Successful in 4m36s
Test / Sandbox (race detector) (push) Successful in 5m11s
Test / Hakurei (race detector) (push) Successful in 6m44s
Test / Flake checks (push) Successful in 3m12s
This also removes the unused kernel helper.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-20 18:45:42 +09:00
e1b8f40add cmd/mbf: cache dir via environment
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 3m3s
Test / Hakurei (push) Successful in 4m5s
Test / ShareFS (push) Successful in 4m12s
Test / Hpkg (push) Successful in 4m41s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m38s
This is much less cumbersome than dragging the flag around all the time.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 15:32:25 +09:00
6df0d37c5a cmd/mbf: Rosa OS container helper
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 3m51s
Test / ShareFS (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m32s
Test / Sandbox (race detector) (push) Successful in 4m58s
Test / Hakurei (race detector) (push) Successful in 6m13s
Test / Flake checks (push) Successful in 1m43s
This sets up a Rosa OS container with its shell as the initial process.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 15:12:16 +09:00
1619b06541 internal/pkg: export layer promotion
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m48s
Test / Hakurei (push) Successful in 3m45s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m29s
Test / Sandbox (race detector) (push) Successful in 5m2s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m58s
This is a useful helper for external tooling.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 15:06:10 +09:00
e335d99c6b internal/pkg: export seccomp presets
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m38s
Test / Hakurei (push) Successful in 3m48s
Test / ShareFS (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m25s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m11s
Test / Flake checks (push) Successful in 1m41s
This is useful for external tooling providing an execArtifact-like environment.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 14:30:31 +09:00
d888d09b6d cmd/mbf: explicit help command
All checks were successful
Test / Create distribution (push) Successful in 1m4s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m57s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m38s
Test / Sandbox (race detector) (push) Successful in 5m20s
Test / Hakurei (race detector) (push) Successful in 6m1s
Test / Flake checks (push) Successful in 1m41s
Not having this command is counterintuitive.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 13:55:05 +09:00
54176e7315 internal/rosa: use LTS kernel
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m36s
Test / Hakurei (push) Successful in 3m55s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m28s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m7s
Test / Flake checks (push) Successful in 1m34s
For out-of-tree modules.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-19 01:22:08 +09:00
3bfe99d3d8 internal/lockedfile: keep objects alive while stopping cleanups
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m38s
Test / Hakurei (push) Successful in 3m49s
Test / ShareFS (push) Successful in 3m59s
Test / Hpkg (push) Successful in 4m23s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 5m54s
Test / Flake checks (push) Successful in 1m43s
Fixes https://go.dev/issues/74780.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-18 20:00:32 +09:00
149dfbb6af internal/rosa: tamago toolchain artifact
All checks were successful
Test / Create distribution (push) Successful in 1m20s
Test / Sandbox (push) Successful in 3m12s
Test / Hakurei (push) Successful in 4m27s
Test / ShareFS (push) Successful in 4m36s
Test / Hpkg (push) Successful in 5m7s
Test / Sandbox (race detector) (push) Successful in 5m29s
Test / Hakurei (race detector) (push) Successful in 6m38s
Test / Flake checks (push) Successful in 1m41s
Currently used by the (wip) bootloader, might not make it into the final OS.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-18 19:26:42 +09:00
58801b44d4 internal/rosa: util-linux artifact
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m40s
Test / Hakurei (push) Successful in 3m51s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m35s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m12s
Test / Flake checks (push) Successful in 1m34s
This stuff will likely be implemented natively in the final system. For now, it is useful for debugging.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-18 14:21:59 +09:00
e065bbf792 internal/rosa: procps artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m46s
Test / Hakurei (push) Successful in 3m45s
Test / ShareFS (push) Successful in 3m59s
Test / Hpkg (push) Successful in 4m29s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m43s
Generally pretty useful, and required by util-linux test suite.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-18 14:07:36 +09:00
a883e57e7d internal/rosa: qemu artifact
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 3m58s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 4m59s
Test / Hakurei (race detector) (push) Successful in 5m53s
Test / Flake checks (push) Successful in 1m42s
This is still a quite minimal build. More features will be enabled as dependencies become available. The powerpc failure will be investigated if it is ever needed.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 17:34:25 +09:00
ef9bd8ecbf internal/rosa/go: 1.25.7 to 1.26.0
All checks were successful
Test / Create distribution (push) Successful in 1m7s
Test / Sandbox (push) Successful in 2m51s
Test / Hakurei (push) Successful in 4m11s
Test / ShareFS (push) Successful in 4m15s
Test / Hpkg (push) Successful in 4m54s
Test / Sandbox (race detector) (push) Successful in 5m6s
Test / Hakurei (race detector) (push) Successful in 6m5s
Test / Flake checks (push) Successful in 1m41s
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 14:40:24 +09:00
a40527dcb2 internal/pkg/ir: document reason for avoiding ident cache
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 1m49s
Test / ShareFS (push) Successful in 2m55s
Test / Hakurei (push) Successful in 3m7s
Test / Hpkg (push) Successful in 3m36s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 6m19s
Test / Flake checks (push) Successful in 1m41s
This got brought up earlier today as a potential optimisation. This change documents why it is not viable, and hopefully clears up some performance implications of using IRDecoder, namely that its decoding costs do not amortise.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 14:38:42 +09:00
88d9a6163e container/initplace: return nil for createTemp error injection
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m35s
Test / Hakurei (push) Successful in 3m50s
Test / ShareFS (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m11s
Test / Flake checks (push) Successful in 1m37s
This matches os package behaviour, and avoids adding the cleanup.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 14:16:54 +09:00
47860b0387 internal/rosa/python: enable bzip2 and xz
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m47s
Test / Hakurei (push) Successful in 7m7s
Test / Sandbox (race detector) (push) Successful in 8m43s
Test / Hpkg (push) Successful in 8m51s
Test / ShareFS (push) Successful in 8m52s
Test / Hakurei (race detector) (push) Successful in 10m58s
Test / Flake checks (push) Successful in 1m49s
This is required by qemu test suite.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 02:39:11 +09:00
50c9da8b6d internal/rosa/python: enable openssl
All checks were successful
Test / Create distribution (push) Successful in 2m27s
Test / Sandbox (push) Successful in 5m47s
Test / ShareFS (push) Successful in 7m28s
Test / Sandbox (race detector) (push) Successful in 7m46s
Test / Hpkg (push) Successful in 8m1s
Test / Hakurei (race detector) (push) Successful in 8m57s
Test / Hakurei (push) Successful in 2m39s
Test / Flake checks (push) Successful in 1m41s
This is required by qemu test suite.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 02:01:57 +09:00
16966043c7 internal/rosa: dtc artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m57s
Test / Hakurei (push) Successful in 4m11s
Test / ShareFS (push) Successful in 4m21s
Test / Hpkg (push) Successful in 4m55s
Test / Sandbox (race detector) (push) Successful in 5m16s
Test / Hakurei (race detector) (push) Successful in 6m15s
Test / Flake checks (push) Successful in 1m36s
Required by qemu.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 00:54:34 +09:00
a3515a6ef5 internal/rosa: bison artifact
All checks were successful
Test / Create distribution (push) Successful in 1m5s
Test / Sandbox (push) Successful in 2m53s
Test / Hakurei (push) Successful in 3m58s
Test / ShareFS (push) Successful in 4m7s
Test / Hpkg (push) Successful in 4m32s
Test / Sandbox (race detector) (push) Successful in 5m9s
Test / Hakurei (race detector) (push) Successful in 6m4s
Test / Flake checks (push) Successful in 1m47s
Required by dtc, which is required by qemu.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-17 00:32:04 +09:00
7f05baab28 internal/rosa: flex artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 4m2s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m32s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 6m13s
Test / Flake checks (push) Successful in 1m58s
Required by dtc, which is required by qemu.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 23:55:36 +09:00
d4d5e631ae internal/rosa: glib artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m46s
Test / Hakurei (push) Successful in 3m50s
Test / ShareFS (push) Successful in 4m0s
Test / Hpkg (push) Successful in 4m29s
Test / Sandbox (race detector) (push) Successful in 4m57s
Test / Hakurei (race detector) (push) Successful in 5m56s
Test / Flake checks (push) Successful in 1m45s
Unfortunately required by many programs, even non-gtk ones.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 19:01:02 +09:00
1df3bcc3b9 nix: mount tmpfs on /tmp
All checks were successful
Test / ShareFS (push) Successful in 36s
Test / Sandbox (race detector) (push) Successful in 46s
Test / Sandbox (push) Successful in 47s
Test / Hpkg (push) Successful in 47s
Test / Create distribution (push) Successful in 1m1s
Test / Hakurei (push) Successful in 3m4s
Test / Hakurei (race detector) (push) Successful in 3m30s
Test / Flake checks (push) Successful in 1m38s
This hopefully eliminates spurious test failures caused by /tmp running out of space.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 18:22:29 +09:00
1809b53e52 internal/rosa/wayland: build-only tests patch
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m44s
Test / Hakurei (push) Successful in 3m56s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m41s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 3m13s
Test / Flake checks (push) Successful in 1m41s
This patch last had any discussion eight months ago and is still not merged.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 13:55:34 +09:00
67b2914c94 internal/rosa: meson helper
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m34s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m0s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m9s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 2m0s
This is used by quite a few projects.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 13:49:13 +09:00
74dee11822 internal/rosa/cmake: optional variant string
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m35s
Test / Hakurei (push) Successful in 3m55s
Test / ShareFS (push) Successful in 4m11s
Test / Hpkg (push) Successful in 4m39s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 6m1s
Test / Flake checks (push) Successful in 1m44s
This improves consistency with other helpers and removes the usually unnecessary variant suffix.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 12:44:40 +09:00
a58c9258cc internal/rosa/pcre2: downgrade to 10.43
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m39s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m29s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 5m55s
Test / Hakurei (push) Successful in 2m33s
Test / Flake checks (push) Successful in 1m34s
Latest release breaks assumptions made by GLib.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 01:51:38 +09:00
710b164c91 internal/pkg: allow devel syscalls
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m47s
Test / Hakurei (push) Successful in 4m0s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 5m9s
Test / Hakurei (race detector) (push) Successful in 6m12s
Test / Flake checks (push) Successful in 1m58s
This is required by the GLib test suite, and possibly others.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 01:46:28 +09:00
93911d6015 internal/rosa: pcre2 artifact
All checks were successful
Test / Create distribution (push) Successful in 1m12s
Test / Sandbox (push) Successful in 3m32s
Test / Hakurei (push) Successful in 5m12s
Test / ShareFS (push) Successful in 5m24s
Test / Sandbox (race detector) (push) Successful in 5m51s
Test / Hpkg (push) Successful in 5m50s
Test / Hakurei (race detector) (push) Successful in 7m6s
Test / Flake checks (push) Successful in 1m47s
Required by GLib.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-16 01:20:52 +09:00
bb097536d4 internal/rosa: remove libcxxabi hack
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 3m59s
Test / ShareFS (push) Successful in 4m0s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 4m58s
Test / Hakurei (race detector) (push) Successful in 6m12s
Test / Flake checks (push) Successful in 1m39s
This was caused by stack overflow which was resolved many commits ago.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-15 21:59:09 +09:00
49b6526a38 internal/rosa: remove redundant meson flags
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m33s
Test / Sandbox (race detector) (push) Successful in 4m59s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Flake checks (push) Successful in 1m42s
These have no effect.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-15 20:18:34 +09:00
f9c31df94d internal/rosa: fixed-size toolchain enum
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m36s
Test / Hakurei (push) Successful in 3m50s
Test / ShareFS (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m34s
Test / Sandbox (race detector) (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 6m14s
Test / Flake checks (push) Successful in 1m37s
This fits in an inlined uint32 IR value.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-15 00:58:14 +09:00
4f570cc5c9 internal/pkg: expose extra methods to file
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m38s
Test / Hakurei (push) Successful in 3m56s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m33s
Test / Sandbox (race detector) (push) Successful in 5m8s
Test / Hakurei (race detector) (push) Successful in 5m56s
Test / Flake checks (push) Successful in 1m45s
This is useful for FileArtifact processing another stream.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-15 00:45:37 +09:00
5828631e79 internal/pkg: split off context common
All checks were successful
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 2m49s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m37s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 48s
Test / Flake checks (push) Successful in 1m53s
For making these methods available to RContext.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-15 00:39:24 +09:00
4f9f4875d7 internal/rosa/openssl: scale jobs based on cpu count
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m41s
Test / ShareFS (push) Successful in 3m57s
Test / Hpkg (push) Successful in 4m41s
Test / Sandbox (race detector) (push) Successful in 5m2s
Test / Hakurei (race detector) (push) Successful in 5m51s
Test / Hakurei (push) Successful in 2m37s
Test / Flake checks (push) Successful in 1m33s
The hardcoded value of 256 causes test failures due to excessive load on some machines. Twice the cpu count appears to almost saturate all cpus without causing spurious failures.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-13 03:34:08 +09:00
d49e654482 internal/rosa: kmod artifact
All checks were successful
Test / Create distribution (push) Successful in 1m7s
Test / Sandbox (push) Successful in 2m51s
Test / Hakurei (push) Successful in 4m18s
Test / ShareFS (push) Successful in 4m21s
Test / Hpkg (push) Successful in 4m50s
Test / Sandbox (race detector) (push) Successful in 5m15s
Test / Hakurei (race detector) (push) Successful in 3m8s
Test / Flake checks (push) Successful in 1m34s
Required by the kernel.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-13 03:15:27 +09:00
b746e352e5 internal/rosa/zstd: fix libdir
All checks were successful
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 2m49s
Test / Hakurei (push) Successful in 4m3s
Test / ShareFS (push) Successful in 4m10s
Test / Hpkg (push) Successful in 4m49s
Test / Sandbox (race detector) (push) Successful in 5m8s
Test / Hakurei (race detector) (push) Successful in 6m5s
Test / Flake checks (push) Successful in 1m44s
CMake implicitly changes it to lib64 which is not supported.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-13 03:14:30 +09:00
c620d88dce update README document
All checks were successful
Test / Create distribution (push) Successful in 30s
Test / ShareFS (push) Successful in 37s
Test / Sandbox (push) Successful in 44s
Test / Sandbox (race detector) (push) Successful in 43s
Test / Hpkg (push) Successful in 45s
Test / Hakurei (push) Successful in 50s
Test / Hakurei (race detector) (push) Successful in 3m15s
Test / Flake checks (push) Successful in 1m39s
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-13 01:38:50 +09:00
7cd14b8865 internal/rosa: squashfs-tools artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m34s
Test / Hakurei (push) Successful in 3m47s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m26s
Test / Sandbox (race detector) (push) Successful in 5m9s
Test / Hakurei (race detector) (push) Successful in 6m15s
Test / Flake checks (push) Successful in 1m46s
The Makefile is very poorly written, so had to be configured through the environment.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-12 02:33:33 +09:00
3e18a4b397 internal/rosa: zstd artifact
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 3m55s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m34s
Test / Sandbox (race detector) (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 6m14s
Test / Flake checks (push) Successful in 1m45s
Optional dependency of many programs, and generally useful to have around.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-12 01:48:21 +09:00
1791b604b5 internal/rosa/make: configurable configure and install
Some checks failed
Test / Create distribution (push) Successful in 29s
Test / ShareFS (push) Successful in 36s
Test / Sandbox (race detector) (push) Successful in 43s
Test / Sandbox (push) Successful in 44s
Test / Hakurei (race detector) (push) Successful in 49s
Test / Hpkg (push) Successful in 46s
Test / Hakurei (push) Failing after 2m34s
Test / Flake checks (push) Has been skipped
This makes the helper useful for non-autotools build systems.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-12 01:19:40 +09:00
59ff6db7ec internal/rosa: toolchain type methods
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m39s
Test / Hakurei (push) Successful in 3m49s
Test / ShareFS (push) Successful in 4m4s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 5m56s
Test / Flake checks (push) Successful in 1m44s
This improves readability for toolchain-specific checks.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 18:18:11 +09:00
430e099556 internal/rosa/stage0: add arm64 tarball
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m37s
Test / Hakurei (push) Successful in 3m59s
Test / ShareFS (push) Successful in 4m0s
Test / Hpkg (push) Successful in 4m33s
Test / Sandbox (race detector) (push) Successful in 5m12s
Test / Hakurei (race detector) (push) Successful in 5m56s
Test / Flake checks (push) Successful in 1m38s
This took far longer to complete because the aarch64 development machine is much slower.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 17:57:54 +09:00
17b64bb42c internal/pkg: skip resolved cure errors
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m44s
Test / Hakurei (push) Successful in 4m2s
Test / ShareFS (push) Successful in 4m2s
Test / Hpkg (push) Successful in 4m30s
Test / Sandbox (race detector) (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 6m5s
Test / Flake checks (push) Successful in 1m35s
This significantly improves error resolution performance.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 17:50:18 +09:00
dbb89dfb0f internal/pkg: buffer tar reader
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m48s
Test / Hakurei (push) Successful in 4m0s
Test / ShareFS (push) Successful in 4m10s
Test / Hpkg (push) Successful in 4m44s
Test / Sandbox (race detector) (push) Successful in 5m34s
Test / Hakurei (race detector) (push) Successful in 8m7s
Test / Flake checks (push) Successful in 1m49s
This significantly improves performance and is a good assumption since the primary use case of FileArtifact is over the network.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 02:08:44 +09:00
de06ea2be4 internal/pkg: read buffer free list
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m53s
Test / Hakurei (push) Successful in 4m30s
Test / ShareFS (push) Successful in 4m28s
Test / Hpkg (push) Successful in 5m6s
Test / Sandbox (race detector) (push) Successful in 5m18s
Test / Hakurei (race detector) (push) Successful in 6m35s
Test / Flake checks (push) Successful in 2m3s
Reader has a non-insignificant buffer that is worth saving as well.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 02:02:46 +09:00
1ef7bedfb5 internal/rosa/toybox: do not assume bash location
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m36s
Test / Hakurei (push) Successful in 3m52s
Test / ShareFS (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m27s
Test / Sandbox (race detector) (push) Successful in 5m7s
Test / Hakurei (race detector) (push) Successful in 5m54s
Test / Flake checks (push) Successful in 1m43s
For compatibility with Gentoo stage3 as bootstrap seed.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 01:36:41 +09:00
05a828c474 internal/pkg: validate tar pathnames
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m35s
Test / ShareFS (push) Successful in 3m59s
Test / Hpkg (push) Successful in 4m46s
Test / Sandbox (race detector) (push) Successful in 5m2s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Hakurei (push) Successful in 4m24s
Test / Flake checks (push) Successful in 1m50s
TContext no longer validates FileArtifact ahead of time, validation outcome is instead determined after consuming the reader to EOF. All data must therefore be treated as untrusted input until the reader is closed.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-11 00:40:54 +09:00
0061d11f93 internal/rosa: use self-hosted stage0
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m53s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 3m10s
This removes the bootstrap dependency on Gentoo stage3 tarball.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-10 22:31:08 +09:00
fb101a02f2 internal/rosa: self-host stage0 tarball
All checks were successful
Test / Create distribution (push) Successful in 2m26s
Test / Sandbox (push) Successful in 5m22s
Test / Hakurei (push) Successful in 6m37s
Test / ShareFS (push) Successful in 6m39s
Test / Hpkg (push) Successful in 7m10s
Test / Sandbox (race detector) (push) Successful in 7m15s
Test / Hakurei (race detector) (push) Successful in 8m15s
Test / Flake checks (push) Successful in 1m51s
This replaces gentoo stage3 tarballs.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-10 21:22:46 +09:00
3dbd67d113 internal/rosa: consistent stage0 paths
All checks were successful
Test / Create distribution (push) Successful in 2m2s
Test / Hakurei (push) Successful in 6m35s
Test / ShareFS (push) Successful in 6m33s
Test / Sandbox (race detector) (push) Successful in 6m52s
Test / Hpkg (push) Successful in 7m20s
Test / Hakurei (race detector) (push) Successful in 7m46s
Test / Sandbox (push) Successful in 1m37s
Test / Flake checks (push) Successful in 1m50s
This makes using the gentoo stage3 as our stage0 compatible with Rosa OS stage0 tarballs.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-10 19:28:47 +09:00
f511f0a9e9 internal/rosa: bzip2 artifact
All checks were successful
Test / Create distribution (push) Successful in 30s
Test / Sandbox (push) Successful in 45s
Test / ShareFS (push) Successful in 2m44s
Test / Hakurei (push) Successful in 3m1s
Test / Hpkg (push) Successful in 3m31s
Test / Sandbox (race detector) (push) Successful in 5m10s
Test / Hakurei (race detector) (push) Successful in 3m13s
Test / Flake checks (push) Successful in 1m48s
For creating the stage0 tarball. Might be replaced by a custom artifact at some point.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-09 02:26:52 +09:00
47995137b3 internal/rosa/perl: skip installing manpages
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m48s
Test / Hakurei (push) Successful in 4m13s
Test / ShareFS (push) Successful in 4m10s
Test / Hpkg (push) Successful in 4m48s
Test / Sandbox (race detector) (push) Successful in 5m5s
Test / Hakurei (race detector) (push) Successful in 7m0s
Test / Flake checks (push) Successful in 1m48s
Perl manpages ignore prefix and gets installed to /. This change does not use the configure script because it is completely broken and specifying either "none" or a single space character (undocumented) has no effect.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-09 01:50:52 +09:00
e1b8607101 internal/rosa: rename stage0 toolchain
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 1m48s
Test / Sandbox (race detector) (push) Successful in 2m52s
Test / Hakurei (push) Successful in 3m1s
Test / ShareFS (push) Successful in 3m16s
Test / Hakurei (race detector) (push) Successful in 3m58s
Test / Hpkg (push) Successful in 3m57s
Test / Flake checks (push) Successful in 1m48s
This is stage0 relative to Rosa OS, and stage3 relative to the toolchain it is compiled on (Gentoo in this case). Referring to the toolchain itself as stage3 is counterintuitive and misleading.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-09 00:55:07 +09:00
3d3bd45b95 internal/rosa/hakurei: 0.3.4 to 0.3.5
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m37s
Test / ShareFS (push) Successful in 3m59s
Test / Hpkg (push) Successful in 4m33s
Test / Sandbox (race detector) (push) Successful in 5m0s
Test / Hakurei (race detector) (push) Successful in 6m16s
Test / Hakurei (push) Successful in 3m0s
Test / Flake checks (push) Successful in 2m7s
This removes all backport patches.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-09 00:27:45 +09:00
53 changed files with 14532 additions and 888 deletions

181
README.md
View File

@@ -15,164 +15,51 @@
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
</p>
Hakurei is a tool for running sandboxed graphical applications as dedicated subordinate users on the Linux kernel.
It implements the application container of [planterette (WIP)](https://git.gensokyo.uk/security/planterette),
a self-contained Android-like package manager with modern security features.
Hakurei is a tool for running sandboxed desktop applications as dedicated
subordinate users on the Linux kernel. It implements the application container
of [planterette (WIP)](https://git.gensokyo.uk/security/planterette), a
self-contained Android-like package manager with modern security features.
## NixOS Module usage
Interaction with hakurei happens entirely through structures described by
package [hst](https://pkg.go.dev/hakurei.app/hst). No native API is available
due to internal details of uid isolation.
The NixOS module currently requires home-manager to configure subordinate users. Full module documentation can be found [here](options.md).
## Notable Packages
To use the module, import it into your configuration with
Package [container](https://pkg.go.dev/hakurei.app/container) is general purpose
container tooling. It is used by the hakurei shim process running as the target
subordinate user to set up the application container. It has a single dependency,
[libseccomp](https://github.com/seccomp/libseccomp), to create BPF programs
for the [system call filter](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html).
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
Package [internal/pkg](https://pkg.go.dev/hakurei.app/internal/pkg) provides
infrastructure for hermetic builds. This replaces the legacy nix-based testing
framework and serves as the build system of Rosa OS, currently developed under
package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
hakurei = {
url = "git+https://git.gensokyo.uk/security/hakurei";
## Dependencies
# Optional but recommended to limit the size of your system closure.
inputs.nixpkgs.follows = "nixpkgs";
};
};
`container` depends on:
outputs = { self, nixpkgs, hakurei, ... }:
{
nixosConfigurations.hakurei = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
hakurei.nixosModules.hakurei
];
};
};
}
```
- [libseccomp](https://github.com/seccomp/libseccomp) to generate BPF programs.
This adds the `environment.hakurei` option:
`cmd/hakurei` depends on:
```nix
{ pkgs, ... }:
- [acl](https://savannah.nongnu.org/projects/acl/) to export sockets to
subordinate users.
- [wayland](https://gitlab.freedesktop.org/wayland/wayland) to set up
[security-context-v1](https://wayland.app/protocols/security-context-v1).
- [xcb](https://xcb.freedesktop.org/) to grant and revoke subordinate users
access to the X server.
{
environment.hakurei = {
enable = true;
stateDir = "/var/lib/hakurei";
users = {
alice = 0;
nixos = 10;
};
`cmd/sharefs` depends on:
commonPaths = [
{
src = "/sdcard";
write = true;
}
];
- [fuse](https://github.com/libfuse/libfuse) to implement the filesystem.
extraHomeConfig = {
home.stateVersion = "23.05";
};
New dependencies will generally not be added. Patches adding new dependencies
are very likely to be rejected.
apps = {
"org.chromium.Chromium" = {
name = "chromium";
identity = 1;
packages = [ pkgs.chromium ];
userns = true;
mapRealUid = true;
dbus = {
system = {
filter = true;
talk = [
"org.bluez"
"org.freedesktop.Avahi"
"org.freedesktop.UPower"
];
};
session =
f:
f {
talk = [
"org.freedesktop.FileManager1"
"org.freedesktop.Notifications"
"org.freedesktop.ScreenSaver"
"org.freedesktop.secrets"
"org.kde.kwalletd5"
"org.kde.kwalletd6"
];
own = [
"org.chromium.Chromium.*"
"org.mpris.MediaPlayer2.org.chromium.Chromium.*"
"org.mpris.MediaPlayer2.chromium.*"
];
call = { };
broadcast = { };
};
};
};
## NixOS Module (deprecated)
"org.claws_mail.Claws-Mail" = {
name = "claws-mail";
identity = 2;
packages = [ pkgs.claws-mail ];
gpu = false;
capability.pulse = false;
};
"org.weechat" = {
name = "weechat";
identity = 3;
shareUid = true;
packages = [ pkgs.weechat ];
capability = {
wayland = false;
x11 = false;
dbus = true;
pulse = false;
};
};
"dev.vencord.Vesktop" = {
name = "discord";
identity = 3;
shareUid = true;
packages = [ pkgs.vesktop ];
share = pkgs.vesktop;
command = "vesktop --ozone-platform-hint=wayland";
userns = true;
mapRealUid = true;
capability.x11 = true;
dbus = {
session =
f:
f {
talk = [ "org.kde.StatusNotifierWatcher" ];
own = [ ];
call = { };
broadcast = { };
};
system.filter = true;
};
};
"io.looking-glass" = {
name = "looking-glass-client";
identity = 4;
useCommonPaths = false;
groups = [ "plugdev" ];
extraPaths = [
{
src = "/dev/shm/looking-glass";
write = true;
}
];
extraConfig = {
programs.looking-glass-client.enable = true;
};
};
};
};
}
```
The NixOS module is in maintenance mode and will be removed once planterette is
feature-complete. Full module documentation can be found [here](options.md).

View File

@@ -10,11 +10,15 @@ import (
"path/filepath"
"runtime"
"syscall"
"time"
"unique"
"hakurei.app/command"
"hakurei.app/container"
"hakurei.app/container/check"
"hakurei.app/container/fhs"
"hakurei.app/container/seccomp"
"hakurei.app/container/std"
"hakurei.app/internal/pkg"
"hakurei.app/internal/rosa"
"hakurei.app/message"
@@ -55,6 +59,11 @@ func main() {
c := command.New(os.Stderr, log.Printf, "mbf", func([]string) (err error) {
msg.SwapVerbose(!flagQuiet)
flagBase = os.ExpandEnv(flagBase)
if flagBase == "" {
flagBase = "cache"
}
var base *check.Absolute
if flagBase, err = filepath.Abs(flagBase); err != nil {
return
@@ -81,7 +90,7 @@ func main() {
"Maximum number of dependencies to cure at any given time",
).Flag(
&flagBase,
"d", command.StringFlag("cache"),
"d", command.StringFlag("$MBF_CACHE_DIR"),
"Directory to store cured artifacts",
).Flag(
&flagTShift,
@@ -109,46 +118,92 @@ func main() {
)
}
c.NewCommand(
"stage3",
"Check for toolchain 3-stage non-determinism",
func(args []string) (err error) {
_, _, _, stage1 := (rosa.Std - 2).NewLLVM()
_, _, _, stage2 := (rosa.Std - 1).NewLLVM()
_, _, _, stage3 := rosa.Std.NewLLVM()
var (
pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum]
)
{
var (
flagGentoo string
flagChecksum string
if pathname, _, err = cache.Cure(stage1); err != nil {
return err
}
log.Println("stage1:", pathname)
flagStage0 bool
)
c.NewCommand(
"stage3",
"Check for toolchain 3-stage non-determinism",
func(args []string) (err error) {
t := rosa.Std
if flagGentoo != "" {
t -= 3 // magic number to discourage misuse
if pathname, checksum[0], err = cache.Cure(stage2); err != nil {
return err
}
log.Println("stage2:", pathname)
if pathname, checksum[1], err = cache.Cure(stage3); err != nil {
return err
}
log.Println("stage3:", pathname)
if checksum[0] != checksum[1] {
err = &pkg.ChecksumMismatchError{
Got: checksum[0].Value(),
Want: checksum[1].Value(),
var checksum pkg.Checksum
if len(flagChecksum) != 0 {
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
return
}
}
rosa.SetGentooStage3(flagGentoo, checksum)
}
} else {
log.Println(
"stage2 is identical to stage3",
"("+pkg.Encode(checksum[0].Value())+")",
_, _, _, stage1 := (t - 2).NewLLVM()
_, _, _, stage2 := (t - 1).NewLLVM()
_, _, _, stage3 := t.NewLLVM()
var (
pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum]
)
}
return
},
)
if pathname, _, err = cache.Cure(stage1); err != nil {
return err
}
log.Println("stage1:", pathname)
if pathname, checksum[0], err = cache.Cure(stage2); err != nil {
return err
}
log.Println("stage2:", pathname)
if pathname, checksum[1], err = cache.Cure(stage3); err != nil {
return err
}
log.Println("stage3:", pathname)
if checksum[0] != checksum[1] {
err = &pkg.ChecksumMismatchError{
Got: checksum[0].Value(),
Want: checksum[1].Value(),
}
} else {
log.Println(
"stage2 is identical to stage3",
"("+pkg.Encode(checksum[0].Value())+")",
)
}
if flagStage0 {
if pathname, _, err = cache.Cure(
t.Load(rosa.Stage0),
); err != nil {
return err
}
log.Println(pathname)
}
return
},
).
Flag(
&flagGentoo,
"gentoo", command.StringFlag(""),
"Bootstrap from a Gentoo stage3 tarball",
).
Flag(
&flagChecksum,
"checksum", command.StringFlag(""),
"Checksum of Gentoo stage3 tarball",
).
Flag(
&flagStage0,
"stage0", command.BoolFlag(false),
"Create bootstrap stage0 tarball",
)
}
{
var (
@@ -162,7 +217,7 @@ func main() {
return errors.New("cure requires 1 argument")
}
if p, ok := rosa.ResolveName(args[0]); !ok {
return fmt.Errorf("unsupported artifact %q", args[0])
return fmt.Errorf("unknown artifact %q", args[0])
} else if flagDump == "" {
pathname, _, err := cache.Cure(rosa.Std.Load(p))
if err == nil {
@@ -195,6 +250,142 @@ func main() {
)
}
{
var (
flagNet bool
flagSession bool
flagWithToolchain bool
)
c.NewCommand(
"shell",
"Interactive shell in the specified Rosa OS environment",
func(args []string) error {
root := make([]pkg.Artifact, 0, 6+len(args))
for _, arg := range args {
p, ok := rosa.ResolveName(arg)
if !ok {
return fmt.Errorf("unknown artifact %q", arg)
}
root = append(root, rosa.Std.Load(p))
}
musl, compilerRT, runtimes, clang := rosa.Std.NewLLVM()
root = append(root, musl)
if flagWithToolchain {
root = append(root, compilerRT, runtimes, clang)
}
root = append(root,
rosa.Std.Load(rosa.Mksh),
rosa.Std.Load(rosa.Toybox),
)
type cureRes struct {
pathname *check.Absolute
checksum unique.Handle[pkg.Checksum]
}
cured := make(map[pkg.Artifact]cureRes)
for _, a := range root {
pathname, checksum, err := cache.Cure(a)
if err != nil {
return err
}
cured[a] = cureRes{pathname, checksum}
}
layers := pkg.PromoteLayers(root, func(a pkg.Artifact) (
*check.Absolute,
unique.Handle[pkg.Checksum],
) {
res := cured[a]
return res.pathname, res.checksum
}, func(i int, d pkg.Artifact) {
r := pkg.Encode(cache.Ident(d).Value())
if s, ok := d.(fmt.Stringer); ok {
if name := s.String(); name != "" {
r += "-" + name
}
}
msg.Verbosef("promoted layer %d as %s", i, r)
})
z := container.New(ctx, msg)
z.WaitDelay = 3 * time.Second
z.SeccompPresets = pkg.SeccompPresets
z.SeccompFlags |= seccomp.AllowMultiarch
z.ParentPerm = 0700
z.HostNet = flagNet
z.RetainSession = flagSession
z.Hostname = "localhost"
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
var tempdir *check.Absolute
if s, err := filepath.Abs(os.TempDir()); err != nil {
return err
} else if tempdir, err = check.NewAbs(s); err != nil {
return err
}
z.Dir = fhs.AbsRoot
z.Env = []string{
"SHELL=/system/bin/mksh",
"PATH=/system/bin",
"HOME=/",
}
z.Path = rosa.AbsSystem.Append("bin", "mksh")
z.Args = []string{"mksh"}
z.
OverlayEphemeral(fhs.AbsRoot, layers...).
Place(
fhs.AbsEtc.Append("hosts"),
[]byte("127.0.0.1 localhost\n"),
).
Place(
fhs.AbsEtc.Append("passwd"),
[]byte("media_rw:x:1023:1023::/:/system/bin/sh\n"+
"nobody:x:65534:65534::/proc/nonexistent:/system/bin/false\n"),
).
Place(
fhs.AbsEtc.Append("group"),
[]byte("media_rw:x:1023:\nnobody:x:65534:\n"),
).
Bind(tempdir, fhs.AbsTmp, std.BindWritable).
Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
if err := z.Start(); err != nil {
return err
}
if err := z.Serve(); err != nil {
return err
}
return z.Wait()
},
).
Flag(
&flagNet,
"net", command.BoolFlag(false),
"Share host net namespace",
).
Flag(
&flagSession,
"session", command.BoolFlag(false),
"Retain session",
).
Flag(
&flagWithToolchain,
"with-toolchain", command.BoolFlag(false),
"Include the stage3 LLVM toolchain",
)
}
c.Command(
"help",
"Show this help message",
func([]string) error { c.PrintHelp(); return nil },
)
c.MustParse(os.Args[1:], func(err error) {
if cache != nil {
cache.Close()

View File

@@ -238,8 +238,11 @@ func sliceAddr[S any](s []S) *[]S { return &s }
func newCheckedFile(t *testing.T, name, wantData string, closeErr error) osFile {
f := &checkedOsFile{t: t, name: name, want: wantData, closeErr: closeErr}
// check happens in Close, and cleanup is not guaranteed to run, so relying on it for sloppy implementations will cause sporadic test results
f.cleanup = runtime.AddCleanup(f, func(name string) { f.t.Fatalf("checkedOsFile %s became unreachable without a call to Close", name) }, f.name)
// check happens in Close, and cleanup is not guaranteed to run, so relying
// on it for sloppy implementations will cause sporadic test results
f.cleanup = runtime.AddCleanup(f, func(name string) {
panic("checkedOsFile " + name + " became unreachable without a call to Close")
}, name)
return f
}

View File

@@ -21,7 +21,7 @@ func TestTmpfileOp(t *testing.T) {
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), stub.UniqueError(5)),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, (*checkedOsFile)(nil), stub.UniqueError(5)),
}, stub.UniqueError(5)},
{"Write", &Params{ParentPerm: 0700}, &TmpfileOp{
@@ -35,14 +35,14 @@ func TestTmpfileOp(t *testing.T) {
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, stub.UniqueError(3)), nil),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.Close", sampleDataString, stub.UniqueError(3)), nil),
}, stub.UniqueError(3)},
{"ensureFile", &Params{ParentPerm: 0700}, &TmpfileOp{
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.ensureFile", sampleDataString, nil), nil),
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, stub.UniqueError(2)),
}, stub.UniqueError(2)},
@@ -50,29 +50,29 @@ func TestTmpfileOp(t *testing.T) {
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.bindMount", sampleDataString, nil), nil),
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, stub.UniqueError(1)),
call("bindMount", stub.ExpectArgs{"tmp.bindMount", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, stub.UniqueError(1)),
}, stub.UniqueError(1)},
{"remove", &Params{ParentPerm: 0700}, &TmpfileOp{
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.remove", sampleDataString, nil), nil),
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
call("remove", stub.ExpectArgs{"tmp.32768"}, nil, stub.UniqueError(0)),
call("bindMount", stub.ExpectArgs{"tmp.remove", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
call("remove", stub.ExpectArgs{"tmp.remove"}, nil, stub.UniqueError(0)),
}, stub.UniqueError(0)},
{"success", &Params{ParentPerm: 0700}, &TmpfileOp{
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.success", sampleDataString, nil), nil),
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
call("remove", stub.ExpectArgs{"tmp.32768"}, nil, nil),
call("bindMount", stub.ExpectArgs{"tmp.success", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
call("remove", stub.ExpectArgs{"tmp.success"}, nil, nil),
}, nil},
})

View File

@@ -8,7 +8,6 @@
package filelock
import (
"errors"
"io/fs"
)
@@ -74,10 +73,3 @@ func (lt lockType) String() string {
return "Unlock"
}
}
// IsNotSupported returns a boolean indicating whether the error is known to
// report that a function is not supported (possibly for a specific input).
// It is satisfied by errors.ErrUnsupported as well as some syscall errors.
func IsNotSupported(err error) bool {
return errors.Is(err, errors.ErrUnsupported)
}

View File

@@ -94,6 +94,11 @@ func (f *File) Close() error {
err := closeFile(f.osFile.File)
f.cleanup.Stop()
// f may be dead at the moment after we access f.cleanup,
// so the cleanup can fire before Stop completes. Keep f
// alive while we call Stop. See the documentation for
// runtime.Cleanup.Stop.
runtime.KeepAlive(f)
return err
}

View File

@@ -39,22 +39,20 @@ type ExecPath struct {
W bool
}
// layers returns pathnames collected from A deduplicated by checksum.
func (p *ExecPath) layers(f *FContext) []*check.Absolute {
msg := f.GetMessage()
layers := make([]*check.Absolute, 0, len(p.A))
checksums := make(map[unique.Handle[Checksum]]struct{}, len(p.A))
for i := range p.A {
d := p.A[len(p.A)-1-i]
pathname, checksum := f.GetArtifact(d)
// PromoteLayers returns artifacts with identical-by-content layers promoted to
// the highest priority instance, as if mounted via [ExecPath].
func PromoteLayers(
artifacts []Artifact,
getArtifact func(Artifact) (*check.Absolute, unique.Handle[Checksum]),
report func(i int, d Artifact),
) []*check.Absolute {
layers := make([]*check.Absolute, 0, len(artifacts))
checksums := make(map[unique.Handle[Checksum]]struct{}, len(artifacts))
for i := range artifacts {
d := artifacts[len(artifacts)-1-i]
pathname, checksum := getArtifact(d)
if _, ok := checksums[checksum]; ok {
if msg.IsVerbose() {
msg.Verbosef(
"promoted layer %d as %s",
len(p.A)-1-i, reportName(d, f.cache.Ident(d)),
)
}
report(len(artifacts)-1-i, d)
continue
}
checksums[checksum] = struct{}{}
@@ -64,6 +62,19 @@ func (p *ExecPath) layers(f *FContext) []*check.Absolute {
return layers
}
// layers returns pathnames collected from A deduplicated via [PromoteLayers].
func (p *ExecPath) layers(f *FContext) []*check.Absolute {
msg := f.GetMessage()
return PromoteLayers(p.A, f.GetArtifact, func(i int, d Artifact) {
if msg.IsVerbose() {
msg.Verbosef(
"promoted layer %d as %s",
i, reportName(d, f.cache.Ident(d)),
)
}
})
}
// Path returns a populated [ExecPath].
func Path(pathname *check.Absolute, writable bool, a ...Artifact) ExecPath {
return ExecPath{pathname, a, writable}
@@ -365,6 +376,10 @@ func scanVerbose(
}
}
// SeccompPresets is the [seccomp] presets used by exec artifacts.
const SeccompPresets = std.PresetStrict &
^(std.PresetDenyNS | std.PresetDenyDevel)
// cure is like Cure but allows optional host net namespace. This is used for
// the [KnownChecksum] variant where networking is allowed.
func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
@@ -388,7 +403,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
z := container.New(ctx, f.GetMessage())
z.WaitDelay = execWaitDelay
z.SeccompPresets |= std.PresetStrict & ^std.PresetDenyNS
z.SeccompPresets = SeccompPresets
z.SeccompFlags |= seccomp.AllowMultiarch
z.ParentPerm = 0700
z.HostNet = hostNet

View File

@@ -310,6 +310,13 @@ type (
// verbose logging is enabled. Artifacts may only depend on artifacts
// previously described in the IR stream.
//
// IRDecoder rejects an IR stream on the first decoding error, it does not
// check against nonzero reserved ancillary data or incorrectly ordered or
// redundant unstructured dependencies. An invalid IR stream as such will
// yield [Artifact] values with identifiers disagreeing with those computed
// by IRDecoder. For this reason, IRDecoder does not access the ident cache
// to avoid putting [Cache] into an inconsistent state.
//
// Methods of IRDecoder are not safe for concurrent use.
IRDecoder struct {
// Address of underlying [Cache], must not be exposed directly.

View File

@@ -65,18 +65,23 @@ func MustDecode(s string) (checksum Checksum) {
return
}
// common holds elements and receives methods shared between different contexts.
type common struct {
// Address of underlying [Cache], should be zeroed or made unusable after
// Cure returns and must not be exposed directly.
cache *Cache
}
// TContext is passed to [TrivialArtifact.Cure] and provides information and
// methods required for curing the [TrivialArtifact].
//
// Methods of TContext are safe for concurrent use. TContext is valid
// until [TrivialArtifact.Cure] returns.
type TContext struct {
// Address of underlying [Cache], should be zeroed or made unusable after
// [TrivialArtifact.Cure] returns and must not be exposed directly.
cache *Cache
// Populated during [Cache.Cure].
work, temp *check.Absolute
common
}
// destroy destroys the temporary directory and joins its errors with the error
@@ -104,10 +109,10 @@ func (t *TContext) destroy(errP *error) {
}
// Unwrap returns the underlying [context.Context].
func (t *TContext) Unwrap() context.Context { return t.cache.ctx }
func (c *common) Unwrap() context.Context { return c.cache.ctx }
// GetMessage returns [message.Msg] held by the underlying [Cache].
func (t *TContext) GetMessage() message.Msg { return t.cache.msg }
func (c *common) GetMessage() message.Msg { return c.cache.msg }
// GetWorkDir returns a pathname to a directory which [Artifact] is expected to
// write its output to. This is not the final resting place of the [Artifact]
@@ -126,13 +131,13 @@ func (t *TContext) GetTempDir() *check.Absolute { return t.temp }
// If err is nil, the caller must close the resulting [io.ReadCloser] and return
// its error, if any. Failure to read r to EOF may result in a spurious
// [ChecksumMismatchError], or the underlying implementation may block on Close.
func (t *TContext) Open(a Artifact) (r io.ReadCloser, err error) {
func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
if f, ok := a.(FileArtifact); ok {
return t.cache.openFile(f)
return c.cache.openFile(f)
}
var pathname *check.Absolute
if pathname, _, err = t.cache.Cure(a); err != nil {
if pathname, _, err = c.cache.Cure(a); err != nil {
return
}
@@ -191,14 +196,7 @@ func (f *FContext) GetArtifact(a Artifact) (
//
// Methods of RContext are safe for concurrent use. RContext is valid
// until [FileArtifact.Cure] returns.
type RContext struct {
// Address of underlying [Cache], should be zeroed or made unusable after
// [FileArtifact.Cure] returns and must not be exposed directly.
cache *Cache
}
// Unwrap returns the underlying [context.Context].
func (r *RContext) Unwrap() context.Context { return r.cache.ctx }
type RContext struct{ common }
// An Artifact is a read-only reference to a piece of data that may be created
// deterministically but might not currently be available in memory or on the
@@ -466,7 +464,7 @@ type Cache struct {
// Synchronises entry into exclusive artifacts for the cure method.
exclMu sync.Mutex
// Buffered I/O free list, must not be accessed directly.
bufioPool sync.Pool
brPool, bwPool sync.Pool
// Unlocks the on-filesystem cache. Must only be called from Close.
unlock func()
@@ -548,6 +546,26 @@ func (c *Cache) unsafeIdent(a Artifact, encodeKind bool) (
return
}
// getReader is like [bufio.NewReader] but for brPool.
func (c *Cache) getReader(r io.Reader) *bufio.Reader {
br := c.brPool.Get().(*bufio.Reader)
br.Reset(r)
return br
}
// putReader adds br to brPool.
func (c *Cache) putReader(br *bufio.Reader) { c.brPool.Put(br) }
// getWriter is like [bufio.NewWriter] but for bwPool.
func (c *Cache) getWriter(w io.Writer) *bufio.Writer {
bw := c.bwPool.Get().(*bufio.Writer)
bw.Reset(w)
return bw
}
// putWriter adds bw to bwPool.
func (c *Cache) putWriter(bw *bufio.Writer) { c.bwPool.Put(bw) }
// A ChecksumMismatchError describes an [Artifact] with unexpected content.
type ChecksumMismatchError struct {
// Actual and expected checksums.
@@ -927,14 +945,14 @@ func (c *Cache) openFile(f FileArtifact) (r io.ReadCloser, err error) {
}
if c.msg.IsVerbose() {
rn := reportName(f, c.Ident(f))
c.msg.Verbosef("curing %s to memory...", rn)
c.msg.Verbosef("curing %s in memory...", rn)
defer func() {
if err == nil {
c.msg.Verbosef("cured %s to memory", rn)
c.msg.Verbosef("opened %s for reading", rn)
}
}()
}
return f.Cure(&RContext{c})
return f.Cure(&RContext{common{c}})
}
return
}
@@ -1131,6 +1149,9 @@ type DependencyCureError []*CureError
// unwrapM recursively expands underlying errors into a caller-supplied map.
func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
for _, err := range *e {
if _, ok := me[err.Ident]; ok {
continue
}
if _e, ok := err.Err.(*DependencyCureError); ok {
_e.unwrapM(me)
continue
@@ -1214,13 +1235,6 @@ func (c *Cache) exitCure(a Artifact, curesExempt bool) {
<-c.cures
}
// getWriter is like [bufio.NewWriter] but for bufioPool.
func (c *Cache) getWriter(w io.Writer) *bufio.Writer {
bw := c.bufioPool.Get().(*bufio.Writer)
bw.Reset(w)
return bw
}
// measuredReader implements [io.ReadCloser] and measures the checksum during
// Close. If the underlying reader is not read to EOF, Close blocks until all
// remaining data is consumed and validated.
@@ -1303,9 +1317,6 @@ func (r *RContext) NewMeasuredReader(
return r.cache.newMeasuredReader(rc, checksum)
}
// putWriter adds bw to bufioPool.
func (c *Cache) putWriter(bw *bufio.Writer) { c.bufioPool.Put(bw) }
// cure implements Cure without checking the full dependency graph.
func (c *Cache) cure(a Artifact, curesExempt bool) (
pathname *check.Absolute,
@@ -1437,7 +1448,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
if err = c.enterCure(a, curesExempt); err != nil {
return
}
r, err = f.Cure(&RContext{c})
r, err = f.Cure(&RContext{common{c}})
if err == nil {
if checksumPathname == nil || c.IsStrict() {
h := sha512.New384()
@@ -1513,7 +1524,11 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
return
}
t := TContext{c, c.base.Append(dirWork, ids), c.base.Append(dirTemp, ids)}
t := TContext{
c.base.Append(dirWork, ids),
c.base.Append(dirTemp, ids),
common{c},
}
switch ca := a.(type) {
case TrivialArtifact:
defer t.destroy(&err)
@@ -1713,13 +1728,16 @@ func open(
msg: msg,
base: base,
identPool: sync.Pool{New: func() any { return new(extIdent) }},
ident: make(map[unique.Handle[ID]]unique.Handle[Checksum]),
identErr: make(map[unique.Handle[ID]]error),
identPending: make(map[unique.Handle[ID]]<-chan struct{}),
brPool: sync.Pool{New: func() any { return new(bufio.Reader) }},
bwPool: sync.Pool{New: func() any { return new(bufio.Writer) }},
}
c.ctx, c.cancel = context.WithCancel(ctx)
c.identPool.New = func() any { return new(extIdent) }
c.bufioPool.New = func() any { return new(bufio.Writer) }
if lock || !testing.Testing() {
if unlock, err := lockedfile.MutexAt(

View File

@@ -10,8 +10,7 @@ import (
"io/fs"
"net/http"
"os"
"hakurei.app/container/check"
"path"
)
const (
@@ -100,7 +99,6 @@ func (e DisallowedTypeflagError) Error() string {
// Cure cures the [Artifact], producing a directory located at work.
func (a *tarArtifact) Cure(t *TContext) (err error) {
temp := t.GetTempDir()
var tr io.ReadCloser
if tr, err = t.Open(a.f); err != nil {
return
@@ -116,7 +114,9 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
err = closeErr
}
}(tr)
tr = io.NopCloser(tr)
br := t.cache.getReader(tr)
defer t.cache.putReader(br)
tr = io.NopCloser(br)
switch a.compression {
case TarUncompressed:
@@ -137,14 +137,24 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
type dirTargetPerm struct {
path *check.Absolute
path string
mode fs.FileMode
}
var madeDirectories []dirTargetPerm
if err = os.MkdirAll(temp.String(), 0700); err != nil {
if err = os.MkdirAll(t.GetTempDir().String(), 0700); err != nil {
return
}
var root *os.Root
if root, err = os.OpenRoot(t.GetTempDir().String()); err != nil {
return
}
defer func() {
closeErr := root.Close()
if err == nil {
err = closeErr
}
}()
var header *tar.Header
r := tar.NewReader(tr)
@@ -158,9 +168,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
}
pathname := temp.Append(header.Name)
if typeflag >= '0' && typeflag <= '9' && typeflag != tar.TypeDir {
if err = os.MkdirAll(pathname.Dir().String(), 0700); err != nil {
if err = root.MkdirAll(path.Dir(header.Name), 0700); err != nil {
return
}
}
@@ -168,8 +177,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
switch typeflag {
case tar.TypeReg:
var f *os.File
if f, err = os.OpenFile(
pathname.String(),
if f, err = root.OpenFile(
header.Name,
os.O_CREATE|os.O_EXCL|os.O_WRONLY,
header.FileInfo().Mode()&0500,
); err != nil {
@@ -184,26 +193,29 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
break
case tar.TypeLink:
if err = os.Link(
temp.Append(header.Linkname).String(),
pathname.String(),
if err = root.Link(
header.Linkname,
header.Name,
); err != nil {
return
}
break
case tar.TypeSymlink:
if err = os.Symlink(header.Linkname, pathname.String()); err != nil {
if err = root.Symlink(
header.Linkname,
header.Name,
); err != nil {
return
}
break
case tar.TypeDir:
madeDirectories = append(madeDirectories, dirTargetPerm{
path: pathname,
path: header.Name,
mode: header.FileInfo().Mode(),
})
if err = os.MkdirAll(pathname.String(), 0700); err != nil {
if err = root.MkdirAll(header.Name, 0700); err != nil {
return
}
break
@@ -220,7 +232,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
if err == nil {
for _, e := range madeDirectories {
if err = os.Chmod(e.path.String(), e.mode&0500); err != nil {
if err = root.Chmod(e.path, e.mode&0500); err != nil {
return
}
}
@@ -228,6 +240,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
return
}
temp := t.GetTempDir()
if err = os.Chmod(temp.String(), 0700); err != nil {
return
}

View File

@@ -43,14 +43,14 @@ index 6ce2f9b..e9bde92 100644
--- a/test/attr.test
+++ b/test/attr.test
@@ -11,7 +11,7 @@ Try various valid and invalid names
$ touch f
$ setfattr -n user -v value f
- > setfattr: f: Operation not supported
+ > setfattr: f: Not supported
$ setfattr -n user. -v value f
> setfattr: f: Invalid argument
$ touch f
$ setfattr -n user -v value f
- > setfattr: f: Operation not supported
+ > setfattr: f: Not supported
$ setfattr -n user. -v value f
> setfattr: f: Invalid argument
`},
), &MakeAttr{
ScriptEarly: `

View File

@@ -11,19 +11,27 @@ type PArtifact int
const (
ACL PArtifact = iota
ArgpStandalone
Attr
Autoconf
Automake
BC
Bash
Binutils
Bison
Bzip2
CMake
Coreutils
Curl
DTC
Diffutils
Elfutils
Findutils
Flex
Fuse
Gawk
GMP
GLib
Gawk
Gettext
Git
Go
@@ -33,9 +41,13 @@ const (
Hakurei
HakureiDist
IniConfig
Kernel
KernelHeaders
KernelSource
Kmod
LibXau
Libexpat
Libiconv
Libpsl
Libffi
Libgd
@@ -49,25 +61,35 @@ const (
Make
Meson
Mksh
MuslFts
MuslObstack
NSS
NSSCACert
Ncurses
Ninja
OpenSSL
PCRE2
Packaging
Patch
Perl
PkgConfig
Pluggy
Procps
PyTest
Pygments
Python
QEMU
Rsync
Sed
Setuptools
SquashfsTools
TamaGo
Tar
Texinfo
Toybox
toyboxEarly
Unzip
utilMacros
UtilLinux
Wayland
WaylandProtocols
XCB
@@ -75,13 +97,19 @@ const (
Xproto
XZ
Zlib
Zstd
buildcatrust
utilMacros
// gcc is a hacked-to-pieces GCC toolchain meant for use in intermediate
// stages only. This preset and its direct output must never be exposed.
gcc
// Stage0 is a tarball containing all compile-time dependencies of artifacts
// part of the [Std] toolchain.
Stage0
// _presetEnd is the total number of presets and does not denote a preset.
_presetEnd
)
@@ -108,19 +136,27 @@ func (t Toolchain) Load(p PArtifact) pkg.Artifact {
func ResolveName(name string) (p PArtifact, ok bool) {
p, ok = map[string]PArtifact{
"acl": ACL,
"argp-standalone": ArgpStandalone,
"attr": Attr,
"autoconf": Autoconf,
"automake": Automake,
"bc": BC,
"bash": Bash,
"binutils": Binutils,
"bison": Bison,
"bzip2": Bzip2,
"cmake": CMake,
"coreutils": Coreutils,
"curl": Curl,
"dtc": DTC,
"diffutils": Diffutils,
"elfutils": Elfutils,
"findutils": Findutils,
"flex": Flex,
"fuse": Fuse,
"gawk": Gawk,
"gmp": GMP,
"glib": GLib,
"gawk": Gawk,
"gettext": Gettext,
"git": Git,
"go": Go,
@@ -130,9 +166,13 @@ func ResolveName(name string) (p PArtifact, ok bool) {
"hakurei": Hakurei,
"hakurei-dist": HakureiDist,
"iniconfig": IniConfig,
"kernel": Kernel,
"kernel-headers": KernelHeaders,
"kernel-source": KernelSource,
"kmod": Kmod,
"libXau": LibXau,
"libexpat": Libexpat,
"libiconv": Libiconv,
"libpsl": Libpsl,
"libseccomp": Libseccomp,
"libucontext": Libucontext,
@@ -146,23 +186,34 @@ func ResolveName(name string) (p PArtifact, ok bool) {
"make": Make,
"meson": Meson,
"mksh": Mksh,
"musl-fts": MuslFts,
"musl-obstack": MuslObstack,
"nss": NSS,
"nss-cacert": NSSCACert,
"ncurses": Ncurses,
"ninja": Ninja,
"openssl": OpenSSL,
"pcre2": PCRE2,
"packaging": Packaging,
"patch": Patch,
"perl": Perl,
"pkg-config": PkgConfig,
"pluggy": Pluggy,
"procps": Procps,
"pytest": PyTest,
"pygments": Pygments,
"python": Python,
"qemu": QEMU,
"rsync": Rsync,
"sed": Sed,
"setuptools": Setuptools,
"squashfs-tools": SquashfsTools,
"tamago": TamaGo,
"tar": Tar,
"texinfo": Texinfo,
"toybox": Toybox,
"unzip": Unzip,
"util-linux": UtilLinux,
"wayland": Wayland,
"wayland-protocols": WaylandProtocols,
"xcb": XCB,
@@ -170,6 +221,7 @@ func ResolveName(name string) (p PArtifact, ok bool) {
"xproto": Xproto,
"xz": XZ,
"zlib": Zlib,
"zstd": Zstd,
}[name]
return
}

View File

@@ -0,0 +1,27 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newArgpStandalone() pkg.Artifact {
const (
version = "1.3"
checksum = "vtW0VyO2pJ-hPyYmDI2zwSLS8QL0sPAUKC1t3zNYbwN2TmsaE-fADhaVtNd3eNFl"
)
return t.NewViaMake("argp-standalone", version, pkg.NewHTTPGetTar(
nil, "http://www.lysator.liu.se/~nisse/misc/"+
"argp-standalone-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
Env: []string{
"CC=cc -std=gnu89 -fPIC",
},
ScriptInstall: `
install -D -m644 /usr/src/argp-standalone/argp.h /work/system/include/argp.h
install -D -m755 libargp.a /work/system/lib/libargp.a
`,
},
t.Load(Diffutils),
)
}
func init() { artifactsF[ArgpStandalone] = Toolchain.newArgpStandalone }

27
internal/rosa/bzip2.go Normal file
View File

@@ -0,0 +1,27 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newBzip2() pkg.Artifact {
const (
version = "1.0.8"
checksum = "cTLykcco7boom-s05H1JVsQi1AtChYL84nXkg_92Dm1Xt94Ob_qlMg_-NSguIK-c"
)
return t.NewViaMake("bzip2", version, pkg.NewHTTPGetTar(
nil, "https://sourceware.org/pub/bzip2/bzip2-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
Writable: true,
SkipConfigure: true,
SkipCheck: true,
InPlace: true,
ScriptEarly: "cd /usr/src/bzip2",
Make: []string{
"CC=cc",
},
ScriptInstall: "make PREFIX=/work/system install",
})
}
func init() { artifactsF[Bzip2] = Toolchain.newBzip2 }

View File

@@ -13,19 +13,7 @@ func (t Toolchain) newCMake() pkg.Artifact {
version = "4.2.1"
checksum = "Y3OdbMsob6Xk2y1DCME6z4Fryb5_TkFD7knRT8dTNIRtSqbiCJyyDN9AxggN_I75"
)
return t.New("cmake-"+version, 0, []pkg.Artifact{
t.Load(Make),
t.Load(KernelHeaders),
}, nil, nil, `
cd "$(mktemp -d)"
/usr/src/cmake/bootstrap \
--prefix=/system \
--parallel="$(nproc)" \
-- \
-DCMAKE_USE_OPENSSL=OFF
make "-j$(nproc)"
make DESTDIR=/work install
`, pkg.Path(AbsUsrSrc.Append("cmake"), true, t.NewPatchedSource(
return t.NewViaMake("cmake", version, t.NewPatchedSource(
// expected to be writable in the copy made during bootstrap
"cmake", version, pkg.NewHTTPGetTar(
nil, "https://github.com/Kitware/CMake/releases/download/"+
@@ -33,13 +21,30 @@ make DESTDIR=/work install
mustDecode(checksum),
pkg.TarGzip,
), false,
)))
), &MakeAttr{
OmitDefaults: true,
SkipConfigure: true,
ScriptConfigured: `
/usr/src/cmake/bootstrap \
--prefix=/system \
--parallel="$(nproc)" \
-- \
-DCMAKE_USE_OPENSSL=OFF
`,
SkipCheck: true,
},
t.Load(KernelHeaders),
)
}
func init() { artifactsF[CMake] = Toolchain.newCMake }
// CMakeAttr holds the project-specific attributes that will be applied to a new
// [pkg.Artifact] compiled via [CMake].
type CMakeAttr struct {
// Joined with name with a dash if non-empty.
Variant string
// Path elements joined with source.
Append []string
// Use source tree as scratch space.
@@ -67,12 +72,12 @@ type CMakeAttr struct {
// NewViaCMake returns a [pkg.Artifact] for compiling and installing via [CMake].
func (t Toolchain) NewViaCMake(
name, version, variant string,
name, version string,
source pkg.Artifact,
attr *CMakeAttr,
extra ...pkg.Artifact,
) pkg.Artifact {
if name == "" || version == "" || variant == "" {
if name == "" || version == "" {
panic("names must be non-empty")
}
if attr == nil {
@@ -96,8 +101,13 @@ func (t Toolchain) NewViaCMake(
prefix = AbsSystem
}
rname := name
if attr.Variant != "" {
rname += "-" + attr.Variant
}
sourcePath := AbsUsrSrc.Append(name)
return t.New(name+"-"+variant+"-"+version, attr.Flag, stage3Concat(t, extra,
return t.New(rname+"-"+version, attr.Flag, stage0Concat(t, extra,
t.Load(CMake),
t.Load(Ninja),
), nil, slices.Concat([]string{

34
internal/rosa/dtc.go Normal file
View File

@@ -0,0 +1,34 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newDTC() pkg.Artifact {
const (
version = "1.7.2"
checksum = "vUoiRynPyYRexTpS6USweT5p4SVHvvVJs8uqFkkVD-YnFjwf6v3elQ0-Etrh00Dt"
)
return t.NewViaMeson("dtc", version, t.NewPatchedSource(
"dtc", version, pkg.NewHTTPGetTar(
nil, "https://git.kernel.org/pub/scm/utils/dtc/dtc.git/snapshot/"+
"dtc-v"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false,
), &MesonAttr{
// works around buggy test:
// fdtdump-runtest.sh /usr/src/dtc/tests/fdtdump.dts
Writable: true,
Configure: [][2]string{
{"Dyaml", "disabled"},
{"Dstatic-build", "true"},
},
},
t.Load(Flex),
t.Load(Bison),
t.Load(M4),
t.Load(Coreutils),
t.Load(Diffutils),
)
}
func init() { artifactsF[DTC] = Toolchain.newDTC }

41
internal/rosa/elfutils.go Normal file
View File

@@ -0,0 +1,41 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newElfutils() pkg.Artifact {
const (
version = "0.194"
checksum = "Q3XUygUPv9vR1TkWucwUsQ8Kb1_F6gzk-KMPELr3cC_4AcTrprhVPMvN0CKkiYRa"
)
return t.NewViaMake("elfutils", version, pkg.NewHTTPGetTar(
nil, "https://sourceware.org/elfutils/ftp/"+
version+"/elfutils-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), &MakeAttr{
Env: []string{
"CC=cc" +
// nonstandard glibc extension
" -DFNM_EXTMATCH=0",
},
// nonstandard glibc extension
SkipCheck: true,
Configure: [][2]string{
{"enable-deterministic-archives"},
},
},
t.Load(M4),
t.Load(PkgConfig),
t.Load(Zlib),
t.Load(Bzip2),
t.Load(Zstd),
t.Load(ArgpStandalone),
t.Load(MuslFts),
t.Load(MuslObstack),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[Elfutils] = Toolchain.newElfutils }

21
internal/rosa/flex.go Normal file
View File

@@ -0,0 +1,21 @@
package rosa
import (
"hakurei.app/internal/pkg"
)
func (t Toolchain) newFlex() pkg.Artifact {
const (
version = "2.6.4"
checksum = "p9POjQU7VhgOf3x5iFro8fjhy0NOanvA7CTeuWS_veSNgCixIJshTrWVkc5XLZkB"
)
return t.NewViaMake("flex", version, pkg.NewHTTPGetTar(
nil, "https://github.com/westes/flex/releases/download/"+
"v"+version+"/flex-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), nil,
t.Load(M4),
)
}
func init() { artifactsF[Flex] = Toolchain.newFlex }

View File

@@ -7,11 +7,23 @@ func (t Toolchain) newFuse() pkg.Artifact {
version = "3.18.1"
checksum = "COb-BgJRWXLbt9XUkNeuiroQizpMifXqxgieE1SlkMXhs_WGSyJStrmyewAw2hd6"
)
return t.New("fuse-"+version, 0, []pkg.Artifact{
t.Load(Python),
t.Load(Meson),
t.Load(Ninja),
return t.NewViaMeson("fuse", version, pkg.NewHTTPGetTar(
nil, "https://github.com/libfuse/libfuse/releases/download/"+
"fuse-"+version+"/fuse-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MesonAttr{
Configure: [][2]string{
{"Ddefault_library", "both"},
{"Dtests", "true"},
{"Duseroot", "false"},
{"Dinitscriptdir", "/system/init.d"},
},
ScriptCompiled: "python3 -m pytest test/",
// this project uses pytest
SkipCheck: true,
},
t.Load(IniConfig),
t.Load(Packaging),
t.Load(Pluggy),
@@ -19,27 +31,6 @@ func (t Toolchain) newFuse() pkg.Artifact {
t.Load(PyTest),
t.Load(KernelHeaders),
}, nil, nil, `
cd "$(mktemp -d)"
meson setup \
--reconfigure \
--buildtype=release \
--prefix=/system \
--prefer-static \
-Dtests=true \
-Duseroot=false \
-Dinitscriptdir=/system/init.d \
-Ddefault_library=both \
. /usr/src/fuse
meson compile
python3 -m pytest test/
meson install \
--destdir=/work
`, pkg.Path(AbsUsrSrc.Append("fuse"), false, pkg.NewHTTPGetTar(
nil, "https://github.com/libfuse/libfuse/releases/download/"+
"fuse-"+version+"/fuse-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
)))
)
}
func init() { artifactsF[Fuse] = Toolchain.newFuse }

View File

@@ -23,6 +23,23 @@ chmod +w tests/test-c32ispunct.sh && echo '#!/bin/sh' > tests/test-c32ispunct.sh
}
func init() { artifactsF[M4] = Toolchain.newM4 }
func (t Toolchain) newBison() pkg.Artifact {
const (
version = "3.8.2"
checksum = "BhRM6K7URj1LNOkIDCFDctSErLS-Xo5d9ba9seg10o6ACrgC1uNhED7CQPgIY29Y"
)
return t.NewViaMake("bison", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), nil,
t.Load(M4),
t.Load(Diffutils),
t.Load(Sed),
)
}
func init() { artifactsF[Bison] = Toolchain.newBison }
func (t Toolchain) newSed() pkg.Artifact {
const (
version = "4.9"
@@ -266,6 +283,24 @@ test_disable 'int main(){return 0;}' gnulib-tests/test-lchown.c
}
func init() { artifactsF[Coreutils] = Toolchain.newCoreutils }
func (t Toolchain) newTexinfo() pkg.Artifact {
const (
version = "7.2"
checksum = "9EelM5b7QGMAY5DKrAm_El8lofBGuFWlaBPSBhh7l_VQE8054MBmC0KBvGrABqjv"
)
return t.NewViaMake("texinfo", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/texinfo/texinfo-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
// nonstandard glibc extension
SkipCheck: true,
},
t.Load(Perl),
)
}
func init() { artifactsF[Texinfo] = Toolchain.newTexinfo }
func (t Toolchain) newGperf() pkg.Artifact {
const (
version = "3.3"
@@ -351,6 +386,71 @@ echo 'int main(){return 0;}' > tests/xargs/test-sigusr.c
}
func init() { artifactsF[Findutils] = Toolchain.newFindutils }
func (t Toolchain) newBC() pkg.Artifact {
const (
version = "1.08.2"
checksum = "8h6f3hjV80XiFs6v9HOPF2KEyg1kuOgn5eeFdVspV05ODBVQss-ey5glc8AmneLy"
)
return t.NewViaMake("bc", version, t.NewPatchedSource(
"bc", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/bc/bc-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false,
), &MakeAttr{
Writable: true,
},
t.Load(Perl),
t.Load(Texinfo),
)
}
func init() { artifactsF[BC] = Toolchain.newBC }
func (t Toolchain) newLibiconv() pkg.Artifact {
const (
version = "1.18"
checksum = "iV5q3VxP5VPdJ-X7O5OQI4fGm8VjeYb5viLd1L3eAHg26bbHb2_Qn63XPF3ucVZr"
)
return t.NewViaMake("libiconv", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/libiconv/libiconv-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), nil)
}
func init() { artifactsF[Libiconv] = Toolchain.newLibiconv }
func (t Toolchain) newTar() pkg.Artifact {
const (
version = "1.35"
checksum = "zSaoSlVUDW0dSfm4sbL4FrXLFR8U40Fh3zY5DWhR5NCIJ6GjU6Kc4VZo2-ZqpBRA"
)
return t.NewViaMake("tar", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/tar/tar-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
Env: []string{
// very expensive
"TARTEST_SKIP_LARGE_FILES=1",
},
Configure: [][2]string{
{"disable-acl"},
{"without-posix-acls"},
{"without-xattrs"},
},
Make: []string{
`TESTSUITEFLAGS="-j$(nproc)"`,
},
},
t.Load(Diffutils),
t.Load(Gzip),
t.Load(Bzip2),
t.Load(Zstd),
)
}
func init() { artifactsF[Tar] = Toolchain.newTar }
func (t Toolchain) newBinutils() pkg.Artifact {
const (
version = "2.45"

View File

@@ -143,7 +143,7 @@ sed -i \
go125 := t.newGo(
"1.25.7",
"fyylHdBVRUobnBjYj3NKBaYPUw3kGmo2mEELiZonOYurPfbarNU1x77B99Fjut7Q",
finalEnv, `
[]string{"CGO_ENABLED=0"}, `
sed -i \
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
cmd/link/internal/`+runtime.GOARCH+`/obj.go
@@ -153,6 +153,17 @@ rm \
`, go123,
)
return go125
return t.newGo(
"1.26.0",
"uHLcrgBc0NMcyTMDLRNAZIcOx0RyQlyekSl9xbWSwj3esEFWJysYLfLa3S8p39Nh",
finalEnv, `
sed -i \
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
cmd/link/internal/`+runtime.GOARCH+`/obj.go
rm \
os/root_unix_test.go
`, go125,
)
}
func init() { artifactsF[Go] = Toolchain.newGoLatest }

55
internal/rosa/gtk.go Normal file
View File

@@ -0,0 +1,55 @@
package rosa
import (
"strings"
"hakurei.app/container/fhs"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newGLib() pkg.Artifact {
const (
version = "2.86.4"
checksum = "AfTjBrrxtXXPL6dFa1LfTe40PyPSth62CoIkM5m_VJTUngGLOFHw6I4XE7RGQE8G"
)
return t.NewViaMeson("glib", version, pkg.NewHTTPGet(
nil, "https://download.gnome.org/sources/glib/"+
strings.Join(strings.SplitN(version, ".", 3)[:2], ".")+
"/glib-"+version+".tar.xz",
mustDecode(checksum),
), &MesonAttr{
SourceSuffix: ".tar.xz",
ScriptEarly: `
cd /usr/src/
tar xf glib.tar.xz
mv glib-` + version + ` glib
`,
Configure: [][2]string{
{"Ddefault_library", "both"},
},
Paths: []pkg.ExecPath{
pkg.Path(fhs.AbsEtc.Append(
"machine-id",
), false, pkg.NewFile(
"glib-machine-id",
[]byte("ffffffffffffffffffffffffffffffff\n"),
)),
pkg.Path(AbsSystem.Append(
"var/lib/dbus/machine-id",
), false, pkg.NewFile(
"glib-machine-id",
[]byte("fefefefefefefefefefefefefefefefe\n"),
)),
},
},
t.Load(XZ),
t.Load(Packaging),
t.Load(Bash),
t.Load(PCRE2),
t.Load(Libffi),
t.Load(Zlib),
)
}
func init() { artifactsF[GLib] = Toolchain.newGLib }

View File

@@ -6,8 +6,8 @@ import (
func (t Toolchain) newHakurei(suffix, script string) pkg.Artifact {
const (
version = "0.3.4"
checksum = "wVwSLo75a2OnH5tgxNWXR_YhiOJUFnYM_9-sJtxAEOKhcPE0BJafs6PU8o5JzyCT"
version = "0.3.5"
checksum = "6Tn38NLezRD2d3aGdFg5qFfqn8_KvC6HwMKwJMPvaHmVw8xRgxn8B0PObswl2mOk"
)
return t.New("hakurei"+suffix+"-"+version, 0, []pkg.Artifact{
t.Load(Go),
@@ -44,213 +44,45 @@ chmod -R +w /usr/src/hakurei
cd /usr/src/hakurei
HAKUREI_VERSION='v`+version+`'
`+script, pkg.Path(AbsUsrSrc.Append("hakurei"), true, t.NewPatchedSource("hakurei", version, pkg.NewHTTPGetTar(
nil, "https://git.gensokyo.uk/security/hakurei/archive/"+
"v"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), true, [2]string{"dist-00-tests", `From 67e453f5c4de915de23ecbe5980e595758f0f2fb Mon Sep 17 00:00:00 2001
From: Ophestra <cat@gensokyo.uk>
Date: Tue, 27 Jan 2026 06:49:48 +0900
Subject: [PATCH] dist: run tests
`+script, pkg.Path(AbsUsrSrc.Append("hakurei"), true, t.NewPatchedSource(
"hakurei", version, pkg.NewHTTPGetTar(
nil, "https://git.gensokyo.uk/security/hakurei/archive/"+
"v"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), true, [2]string{"createTemp-error-injection", `diff --git a/container/dispatcher_test.go b/container/dispatcher_test.go
index 5de37fc..fe0c4db 100644
--- a/container/dispatcher_test.go
+++ b/container/dispatcher_test.go
@@ -238,8 +238,11 @@ func sliceAddr[S any](s []S) *[]S { return &s }
This used to be impossible due to nix jank which has been addressed.
func newCheckedFile(t *testing.T, name, wantData string, closeErr error) osFile {
f := &checkedOsFile{t: t, name: name, want: wantData, closeErr: closeErr}
- // check happens in Close, and cleanup is not guaranteed to run, so relying on it for sloppy implementations will cause sporadic test results
- f.cleanup = runtime.AddCleanup(f, func(name string) { f.t.Fatalf("checkedOsFile %s became unreachable without a call to Close", name) }, f.name)
+ // check happens in Close, and cleanup is not guaranteed to run, so relying
+ // on it for sloppy implementations will cause sporadic test results
+ f.cleanup = runtime.AddCleanup(f, func(name string) {
+ panic("checkedOsFile " + name + " became unreachable without a call to Close")
+ }, name)
return f
}
Signed-off-by: Ophestra <cat@gensokyo.uk>
---
dist/release.sh | 21 ++++++++++++++++-----
flake.nix | 32 ++++++++++++++++++++------------
internal/acl/acl_test.go | 2 +-
package.nix | 2 +-
4 files changed, 38 insertions(+), 19 deletions(-)
diff --git a/container/initplace_test.go b/container/initplace_test.go
index afeddbe..1c2f20b 100644
--- a/container/initplace_test.go
+++ b/container/initplace_test.go
@@ -21,7 +21,7 @@ func TestTmpfileOp(t *testing.T) {
Path: samplePath,
Data: sampleData,
}, nil, nil, []stub.Call{
- call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), stub.UniqueError(5)),
+ call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, (*checkedOsFile)(nil), stub.UniqueError(5)),
}, stub.UniqueError(5)},
diff --git a/dist/release.sh b/dist/release.sh
index 4dcb278..0ba9104 100755
--- a/dist/release.sh
+++ b/dist/release.sh
@@ -2,19 +2,30 @@
cd "$(dirname -- "$0")/.."
VERSION="${HAKUREI_VERSION:-untagged}"
pname="hakurei-${VERSION}"
-out="dist/${pname}"
+out="${DESTDIR:-dist}/${pname}"
+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= -extldflags '-static'
+go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w
+ -buildid= -extldflags '-static'
-X hakurei.app/internal/info.buildVersion=${VERSION}
-X hakurei.app/internal/info.hakureiPath=/usr/bin/hakurei
-X hakurei.app/internal/info.hsuPath=/usr/bin/hsu
-X main.hakureiPath=/usr/bin/hakurei" ./...
+echo
-rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"
-rm -rf "./${out}"
-(cd dist && sha512sum "${pname}.tar.gz" > "${pname}.tar.gz.sha512")
+echo '# Testing hakurei.'
+go test -ldflags='-buildid= -extldflags=-static' ./...
+echo
+
+echo '# Creating distribution.'
+rm -f "${out}.tar.gz" && tar -C "${out}/.." -vczf "${out}.tar.gz" "${pname}"
+rm -rf "${out}"
+(cd "${out}/.." && sha512sum "${pname}.tar.gz" > "${pname}.tar.gz.sha512")
+echo
diff --git a/flake.nix b/flake.nix
index 9e09c61..2340b92 100644
--- a/flake.nix
+++ b/flake.nix
@@ -143,19 +143,27 @@
"bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs";
};
- dist = pkgs.runCommand "${hakurei.name}-dist" { buildInputs = hakurei.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
- # go requires XDG_CACHE_HOME for the build cache
- export XDG_CACHE_HOME="$(mktemp -d)"
+ dist =
+ pkgs.runCommand "${hakurei.name}-dist"
+ {
+ buildInputs = hakurei.targetPkgs ++ [
+ pkgs.pkgsStatic.musl
+ ];
+ }
+ ''
+ cd $(mktemp -d) \
+ && cp -r ${hakurei.src}/. . \
+ && chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
+ && chmod -R +w .
- # get a different workdir as go does not like /build
- cd $(mktemp -d) \
- && cp -r ${hakurei.src}/. . \
- && chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
- && chmod -R +w .
-
- export HAKUREI_VERSION="v${hakurei.version}"
- CC="clang -O3 -Werror" ./dist/release.sh && mkdir $out && cp -v "dist/hakurei-$HAKUREI_VERSION.tar.gz"* $out
- '';
+ CC="musl-clang -O3 -Werror -Qunused-arguments" \
+ GOCACHE="$(mktemp -d)" \
+ HAKUREI_TEST_SKIP_ACL=1 \
+ PATH="${pkgs.pkgsStatic.musl.bin}/bin:$PATH" \
+ DESTDIR="$out" \
+ HAKUREI_VERSION="v${hakurei.version}" \
+ ./dist/release.sh
+ '';
}
);
diff --git a/internal/acl/acl_test.go b/internal/acl/acl_test.go
index af6da55..19ce45a 100644
--- a/internal/acl/acl_test.go
+++ b/internal/acl/acl_test.go
@@ -24,7 +24,7 @@ var (
)
func TestUpdate(t *testing.T) {
- if os.Getenv("GO_TEST_SKIP_ACL") == "1" {
+ if os.Getenv("HAKUREI_TEST_SKIP_ACL") == "1" {
t.Skip("acl test skipped")
}
diff --git a/package.nix b/package.nix
index 00c4401..2eaa2ec 100644
--- a/package.nix
+++ b/package.nix
@@ -89,7 +89,7 @@ buildGoModule rec {
CC = "clang -O3 -Werror";
# nix build environment does not allow acls
- GO_TEST_SKIP_ACL = 1;
+ HAKUREI_TEST_SKIP_ACL = 1;
};
buildInputs = [`}, [2]string{"container-tests", `From bf14a412e47344fff2681f4b24d1ecc7415bfcb0 Mon Sep 17 00:00:00 2001
From: Ophestra <cat@gensokyo.uk>
Date: Sat, 31 Jan 2026 10:59:56 +0900
Subject: [PATCH] container: fix host-dependent test cases
These are not fully controlled by hakurei and may change depending on host configuration.
Signed-off-by: Ophestra <cat@gensokyo.uk>
---
container/container_test.go | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/container/container_test.go b/container/container_test.go
index d737a18..98713cb 100644
--- a/container/container_test.go
+++ b/container/container_test.go
@@ -275,12 +275,12 @@ var containerTestCases = []struct {
),
earlyMnt(
ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore),
- ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/random", "/dev/random", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/urandom", "/dev/urandom", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
+ ent("/null", "/dev/null", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/zero", "/dev/zero", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/full", "/dev/full", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/random", "/dev/random", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/urandom", "/dev/urandom", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/tty", "/dev/tty", ignore, "devtmpfs", "devtmpfs", ignore),
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
@@ -293,12 +293,12 @@ var containerTestCases = []struct {
),
earlyMnt(
ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore),
- ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/random", "/dev/random", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/urandom", "/dev/urandom", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
- ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
+ ent("/null", "/dev/null", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/zero", "/dev/zero", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/full", "/dev/full", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/random", "/dev/random", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/urandom", "/dev/urandom", ignore, "devtmpfs", "devtmpfs", ignore),
+ ent("/tty", "/dev/tty", ignore, "devtmpfs", "devtmpfs", ignore),
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
),
@@ -696,6 +696,9 @@ func init() {
mnt[i].VfsOptstr = strings.TrimSuffix(mnt[i].VfsOptstr, ",relatime")
mnt[i].VfsOptstr = strings.TrimSuffix(mnt[i].VfsOptstr, ",noatime")
+ cur.FsOptstr = strings.Replace(cur.FsOptstr, ",seclabel", "", 1)
+ mnt[i].FsOptstr = strings.Replace(mnt[i].FsOptstr, ",seclabel", "", 1)
+
if !cur.EqualWithIgnore(mnt[i], "\x00") {
fail = true
log.Printf("[FAIL] %s", cur)`}, [2]string{"dist-01-tarball-name", `diff --git a/dist/release.sh b/dist/release.sh
index 0ba9104..2990ee1 100755
--- a/dist/release.sh
+++ b/dist/release.sh
@@ -1,7 +1,7 @@
#!/bin/sh -e
cd "$(dirname -- "$0")/.."
VERSION="${HAKUREI_VERSION:-untagged}"
-pname="hakurei-${VERSION}"
+pname="hakurei-${VERSION}-$(go env GOARCH)"
out="${DESTDIR:-dist}/${pname}"
echo '# Preparing distribution files.'
`}),
), pkg.Path(AbsUsrSrc.Append("hostname", "main.go"), false, pkg.NewFile(
{"Write", &Params{ParentPerm: 0700}, &TmpfileOp{
`},
)), pkg.Path(AbsUsrSrc.Append("hostname", "main.go"), false, pkg.NewFile(
"hostname.go",
[]byte(`
package main

View File

@@ -1,44 +1,123 @@
package rosa
import (
"slices"
import "hakurei.app/internal/pkg"
"hakurei.app/internal/pkg"
const kernelVersion = "6.12.73"
var kernelSource = pkg.NewHTTPGetTar(
nil, "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
"snapshot/linux-"+kernelVersion+".tar.gz",
mustDecode("29oUBJKF1ULIv1-XQLpEUUc3LgjUSmyvOSskG37MYUcBlBjMk7RcbCTLrD7UfSM6"),
pkg.TarGzip,
)
// newKernel is a helper for interacting with Kbuild.
func (t Toolchain) newKernel(
flag int,
patches [][2]string,
script string,
extra ...pkg.Artifact,
) pkg.Artifact {
const (
version = "6.18.5"
checksum = "-V1e1WWl7HuePkmm84sSKF7nLuHfUs494uNMzMqXEyxcNE_PUE0FICL0oGWn44mM"
)
return t.New("kernel-"+version, flag, slices.Concat([]pkg.Artifact{
t.Load(Make),
}, extra), nil, nil, `
export LLVM=1
export HOSTLDFLAGS="${LDFLAGS}"
cd /usr/src/linux
`+script, pkg.Path(AbsUsrSrc.Append("linux"), true, t.NewPatchedSource(
"kernel", version, pkg.NewHTTPGetTar(
nil,
"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
"snapshot/linux-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false, patches...,
)))
func (t Toolchain) newKernelSource() pkg.Artifact {
return t.New("kernel-"+kernelVersion+"-src", 0, nil, nil, nil, `
mkdir -p /work/usr/src/
cp -r /usr/src/linux /work/usr/src/
chmod -R +w /work/usr/src/linux/
`, pkg.Path(AbsUsrSrc.Append("linux"), false, kernelSource))
}
func init() { artifactsF[KernelSource] = Toolchain.newKernelSource }
func (t Toolchain) newKernelHeaders() pkg.Artifact {
return t.newKernel(TEarly, nil, `
make "-j$(nproc)" \
INSTALL_HDR_PATH=/work/system \
headers_install
`, t.Load(Rsync))
return t.NewViaMake("kernel-headers", kernelVersion, kernelSource, &MakeAttr{
SkipConfigure: true,
SkipCheck: true,
Make: []string{
"-f /usr/src/kernel-headers/Makefile",
"O=/tmp/kbuild",
"LLVM=1",
`HOSTLDFLAGS="${LDFLAGS}"`,
"INSTALL_HDR_PATH=/work/system",
"headers_install",
},
ScriptInstall: "\n",
Flag: TEarly,
},
t.Load(Rsync),
)
}
func init() { artifactsF[KernelHeaders] = Toolchain.newKernelHeaders }
func (t Toolchain) newKernel() pkg.Artifact {
return t.NewViaMake("kernel", kernelVersion, kernelSource, &MakeAttr{
OmitDefaults: true,
SkipConfigure: true,
// Build, install, and boot kernel before running kselftest on it.
SkipCheck: true,
Env: []string{
"PATH=/system/sbin",
},
ScriptEarly: `
install -Dm0400 \
/usr/src/.config \
/tmp/kbuild/.config
install -Dm0500 \
/usr/src/.installkernel \
/sbin/installkernel
`,
Make: []string{
"-f /usr/src/kernel/Makefile",
"O=/tmp/kbuild",
"LLVM=1",
"KBUILD_BUILD_VERSION='1-Rosa'",
"KBUILD_BUILD_TIMESTAMP='2106-02-07 06:28:15 UTC'",
"KBUILD_BUILD_USER=kbuild",
"KBUILD_BUILD_HOST=localhost",
"all",
},
ScriptInstall: `
make \
"-j$(nproc)" \
-f /usr/src/kernel/Makefile \
O=/tmp/kbuild \
LLVM=1 \
INSTALL_PATH=/work \
install \
INSTALL_MOD_PATH=/work \
modules_install
rm -v /work/lib/modules/` + kernelVersion + `/build
`,
Paths: []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append(
".config",
), false, pkg.NewFile(".config", kernelConfig)),
pkg.Path(AbsUsrSrc.Append(
".installkernel",
), false, pkg.NewFile("installkernel", []byte(`#!/bin/sh -e
echo "Installing linux $1..."
cp -av "$2" "$4"
cp -av "$3" "$4"
`))),
},
},
t.Load(Flex),
t.Load(Bison),
t.Load(M4),
t.Load(Tar),
t.Load(Perl),
t.Load(BC),
t.Load(Sed),
t.Load(Gawk),
t.Load(Coreutils),
t.Load(Diffutils),
t.Load(XZ),
t.Load(Zlib),
t.Load(Gzip),
t.Load(Bzip2),
t.Load(Zstd),
t.Load(Kmod),
t.Load(Elfutils),
t.Load(OpenSSL),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[Kernel] = Toolchain.newKernel }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package rosa
import _ "embed"
//go:embed kernel_amd64.config
var kernelConfig []byte

33
internal/rosa/kmod.go Normal file
View File

@@ -0,0 +1,33 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newKmod() pkg.Artifact {
const (
version = "34.2"
checksum = "0K7POeTKxMhExsaTsnKAC6LUNsRSfe6sSZxWONPbOu-GI_pXOw3toU_BIoqfBhJV"
)
return t.NewViaMeson("kmod", version, pkg.NewHTTPGetTar(
nil, "https://www.kernel.org/pub/linux/utils/kernel/"+
"kmod/kmod-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MesonAttr{
Configure: [][2]string{
{"Dsysconfdir", "/system/etc"},
{"Dbashcompletiondir", "no"},
{"Dfishcompletiondir", "no"},
{"Dxz", "disabled"},
{"Dmanpages", "false"},
},
// makes assumptions about the running kernel
SkipCheck: true,
},
t.Load(Zlib),
t.Load(Zstd),
t.Load(OpenSSL),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[Kmod] = Toolchain.newKmod }

View File

@@ -7,34 +7,24 @@ func (t Toolchain) newLibucontext() pkg.Artifact {
version = "1.5"
checksum = "Ggk7FMmDNBdCx1Z9PcNWWW6LSpjGYssn2vU0GK5BLXJYw7ZxZbA2m_eSgT9TFnIG"
)
return t.New("libucontext", 0, []pkg.Artifact{
t.Load(Make),
}, nil, []string{
"ARCH=" + linuxArch(),
}, `
cd /usr/src/libucontext
make check
make DESTDIR=/work install
`, pkg.Path(AbsUsrSrc.Append("libucontext"), true,
t.NewPatchedSource("libucontext", version, pkg.NewHTTPGetTar(
return t.NewViaMake("libucontext", version, t.NewPatchedSource(
"libucontext", version, pkg.NewHTTPGetTar(
nil, "https://github.com/kaniini/libucontext/archive/refs/tags/"+
"libucontext-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), true, [2]string{"rosa-prefix", `diff --git a/Makefile b/Makefile
index c80e574..4a8c1d3 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ ifeq ($(ARCH),$(filter $(ARCH),arm64))
override ARCH = aarch64
endif
), false,
), &MakeAttr{
Writable: true,
OmitDefaults: true,
SkipConfigure: true,
InPlace: true,
-prefix = /usr
+prefix = /system
libdir = ${prefix}/lib
shared_libdir = ${libdir}
static_libdir = ${libdir}
`}),
))
ScriptEarly: "cd /usr/src/libucontext",
Make: []string{
"ARCH=" + linuxArch(),
},
ScriptInstall: "make prefix=/system DESTDIR=/work install",
})
}
func init() { artifactsF[Libucontext] = Toolchain.newLibucontext }

View File

@@ -159,15 +159,6 @@ ln -s ld.lld /work/system/bin/ld
[2]string{"LIBCXX_HAS_MUSL_LIBC", "ON"},
[2]string{"LIBCXX_USE_COMPILER_RT", "ON"},
)
if t > toolchainStage3 {
// libcxxabi fails to compile if c++ headers not prefixed in /usr
// is found by the compiler, and doing this is easier than
// overriding CXXFLAGS; not using mv here to avoid chown failures
scriptEarly += `
cp -r /system/include /usr/include && rm -rf /system/include
`
}
}
if attr.flags&llvmRuntimeLibcxxABI != 0 {
cache = append(cache,
@@ -176,7 +167,7 @@ cp -r /system/include /usr/include && rm -rf /system/include
)
}
return t.NewViaCMake("llvm", version, variant, t.NewPatchedSource(
return t.NewViaCMake("llvm", version, t.NewPatchedSource(
"llvmorg", version, pkg.NewHTTPGetTar(
nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+
"llvmorg-"+version+".tar.gz",
@@ -184,6 +175,8 @@ cp -r /system/include /usr/include && rm -rf /system/include
pkg.TarGzip,
), true, attr.patches...,
), &CMakeAttr{
Variant: variant,
Cache: slices.Concat(cache, attr.cmake),
Append: cmakeAppend,
Prefix: attr.prefix,
@@ -199,7 +192,7 @@ cp -r /system/include /usr/include && rm -rf /system/include
Paths: attr.paths,
Flag: TExclusive,
}, stage3Concat(t, attr.extra,
}, stage0Concat(t, attr.extra,
t.Load(Libffi),
t.Load(Python),
t.Load(Perl),
@@ -233,7 +226,7 @@ func (t Toolchain) newLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) {
}
compilerRT = t.newLLVMVariant("compiler-rt", &llvmAttr{
env: stage3ExclConcat(t, []string{},
env: stage0ExclConcat(t, []string{},
"LDFLAGS="+earlyLDFLAGS(false),
),
cmake: [][2]string{
@@ -253,11 +246,8 @@ func (t Toolchain) newLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) {
{"COMPILER_RT_BUILD_XRAY", "OFF"},
},
append: []string{"compiler-rt"},
extra: []pkg.Artifact{t.NewMusl(&MuslAttr{
Headers: true,
Env: []string{
"CC=clang",
},
extra: []pkg.Artifact{t.newMusl(true, []string{
"CC=clang",
})},
script: `
mkdir -p "${ROSA_INSTALL_PREFIX}/lib/clang/21/lib/"
@@ -274,21 +264,18 @@ ln -s \
`,
})
musl = t.NewMusl(&MuslAttr{
Extra: []pkg.Artifact{compilerRT},
Env: stage3ExclConcat(t, []string{
"CC=clang",
"LIBCC=/system/lib/clang/21/lib/" +
triplet() + "/libclang_rt.builtins.a",
"AR=ar",
"RANLIB=ranlib",
},
"LDFLAGS="+earlyLDFLAGS(false),
),
})
musl = t.newMusl(false, stage0ExclConcat(t, []string{
"CC=clang",
"LIBCC=/system/lib/clang/21/lib/" +
triplet() + "/libclang_rt.builtins.a",
"AR=ar",
"RANLIB=ranlib",
},
"LDFLAGS="+earlyLDFLAGS(false),
), compilerRT)
runtimes = t.newLLVMVariant("runtimes", &llvmAttr{
env: stage3ExclConcat(t, []string{},
env: stage0ExclConcat(t, []string{},
"LDFLAGS="+earlyLDFLAGS(false),
),
flags: llvmRuntimeLibunwind | llvmRuntimeLibcxx | llvmRuntimeLibcxxABI,
@@ -308,7 +295,7 @@ ln -s \
clang = t.newLLVMVariant("clang", &llvmAttr{
flags: llvmProjectClang | llvmProjectLld,
env: stage3ExclConcat(t, []string{},
env: stage0ExclConcat(t, []string{},
"CFLAGS="+earlyCFLAGS,
"CXXFLAGS="+earlyCXXFLAGS(),
"LDFLAGS="+earlyLDFLAGS(false),
@@ -336,7 +323,7 @@ index 657f4230379e..12c305756184 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -185,6 +185,7 @@ public:
Apple,
PC,
+ Rosa,
@@ -362,7 +349,7 @@ index 0584c941d2e6..e4d6ef963cc7 100644
+ .Case("rosa", Triple::Rosa)
.Default(Triple::UnknownVendor);
}
`},
{"xfail-broken-tests", `diff --git a/clang/test/Modules/timestamps.c b/clang/test/Modules/timestamps.c
@@ -374,14 +361,14 @@ index 50fdce630255..4b4465a75617 100644
+
/// Verify timestamps that gets embedded in the module
#include <c-header.h>
`},
{"path-system-include", `diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index cdbf21fb9026..dd052858700d 100644
index 8ac8d4eb9181..e46b04a898ca 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -773,6 +773,12 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -671,6 +671,12 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(
DriverArgs, CC1Args,
concat(SysRoot, "/usr/include", MultiarchIncludeDir));
@@ -391,15 +378,15 @@ index cdbf21fb9026..dd052858700d 100644
+ DriverArgs, CC1Args,
+ concat(SysRoot, "/system/include", MultiarchIncludeDir));
+
if (getTriple().getOS() == llvm::Triple::RTEMS)
return;
@@ -783,6 +789,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
@@ -681,6 +687,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include"));
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));
+ addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/system/include"));
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
`},
@@ -413,13 +400,13 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
const bool IsRISCV = Triple.isRISCV();
const bool IsCSKY = Triple.isCSKY();
+ const bool IsRosa = Triple.getVendor() == llvm::Triple::Rosa;
if (IsCSKY && !SelectedMultilibs.empty())
SysRoot = SysRoot + SelectedMultilibs.back().osSuffix();
@@ -318,12 +319,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
const std::string OSLibDir = std::string(getOSLibDir(Triple, Args));
const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
+ if (IsRosa) {
+ ExtraOpts.push_back("-rpath");
+ ExtraOpts.push_back("/system/lib");
@@ -441,11 +428,11 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
+ }
}
Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);
@@ -341,18 +353,30 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
Paths);
}
- addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);
- addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);
+ if (!IsRosa) {
@@ -464,9 +451,9 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
+ else
+ addPathIfExists(D, concat(SysRoot, "/system", OSLibDir, ABIName), Paths);
}
Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);
- addPathIfExists(D, concat(SysRoot, "/lib"), Paths);
- addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);
+ if (!IsRosa) {
@@ -476,7 +463,7 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
+ addPathIfExists(D, concat(SysRoot, "/system/lib"), Paths);
+ }
}
ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
@@ -457,6 +481,9 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
@@ -487,20 +474,20 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
+
std::string ArchName;
bool IsArm = false;
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index 64324a3f8b01..15ce70b68217 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -515,7 +515,7 @@ bool Options::processFrontendOptions(InputArgList &Args) {
FEOpts.FwkPaths = std::move(FrameworkPaths);
// Add default framework/library paths.
- PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
+ PathSeq DefaultLibraryPaths = {"/usr/lib", "/system/lib", "/usr/local/lib"};
PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
"/System/Library/Frameworks"};
`},
},
})

View File

@@ -36,8 +36,8 @@ type MakeAttr struct {
// Do not include default extras.
OmitDefaults bool
// Dependencies not provided by stage3.
NonStage3 []pkg.Artifact
// Dependencies not provided by stage0.
NonStage0 []pkg.Artifact
// Additional environment variables.
Env []string
@@ -51,20 +51,28 @@ type MakeAttr struct {
// Remain in working directory set up during ScriptEarly.
InPlace bool
// Whether to skip running the configure script.
SkipConfigure bool
// Flags passed to the configure script.
Configure [][2]string
// Extra make targets.
Make []string
// Host target triple, zero value is equivalent to the Rosa OS triple.
Host string
// Target triple, zero value is equivalent to the Rosa OS triple.
Build string
// Whether to skip the check target.
SkipCheck bool
// Name of the check target, zero value is equivalent to "check".
CheckName string
// Replaces the default install command.
ScriptInstall string
// Suffix appended to the source pathname.
SourceSuffix string
// Passed through to [Toolchain.New], before source.
Paths []pkg.ExecPath
// Passed through to [Toolchain.New].
Flag int
}
@@ -82,39 +90,53 @@ func (t Toolchain) NewViaMake(
if attr == nil {
attr = new(MakeAttr)
}
host := `"${ROSA_TRIPLE}"`
if attr.Host != "" {
host = attr.Host
}
build := `"${ROSA_TRIPLE}"`
if attr.Build != "" {
build = attr.Build
}
var configureFlags string
if len(attr.Configure) > 0 {
const sep = " \\\n\t"
configureFlags += sep + strings.Join(
slices.Collect(func(yield func(string) bool) {
for _, v := range attr.Configure {
s := v[0]
if v[1] == "" || (v[0] != "" &&
v[0][0] >= 'a' &&
v[0][0] <= 'z') {
s = "--" + s
}
if v[1] != "" {
s += "=" + v[1]
}
if !yield(s) {
return
}
}
}),
sep,
)
}
var configure string
if !attr.SkipConfigure {
configure += `
/usr/src/` + name + `/configure \
--prefix=/system`
var buildFlag string
if attr.Build != `""` {
buildFlag = ` \
if attr.Host != `""` {
configure += ` \
--host=` + host
}
if attr.Build != `""` {
configure += ` \
--build=` + build
}
if len(attr.Configure) > 0 {
const sep = " \\\n\t"
configure += sep + strings.Join(
slices.Collect(func(yield func(string) bool) {
for _, v := range attr.Configure {
s := v[0]
if v[1] == "" || (v[0] != "" &&
v[0][0] >= 'a' &&
v[0][0] <= 'z') {
s = "--" + s
}
if v[1] != "" {
s += "=" + v[1]
}
if !yield(s) {
return
}
}
}),
sep,
)
}
}
makeTargets := make([]string, 1, 2+len(attr.Make))
@@ -148,15 +170,20 @@ func (t Toolchain) NewViaMake(
panic("cannot remain in root")
}
return t.New(name+"-"+version, attr.Flag, stage3Concat(t,
attr.NonStage3,
scriptInstall := attr.ScriptInstall
if scriptInstall == "" {
scriptInstall = "make DESTDIR=/work install"
}
scriptInstall += "\n"
return t.New(name+"-"+version, attr.Flag, stage0Concat(t,
attr.NonStage0,
finalExtra...,
), nil, attr.Env, scriptEarly+`
/usr/src/`+name+`/configure \
--prefix=/system`+buildFlag+configureFlags+attr.ScriptConfigured+`
), nil, attr.Env, scriptEarly+configure+attr.ScriptConfigured+`
make "-j$(nproc)"`+strings.Join(makeTargets, " ")+`
make DESTDIR=/work install
`+attr.Script, pkg.Path(AbsUsrSrc.Append(
name+attr.SourceSuffix,
), attr.Writable, source))
`+scriptInstall+attr.Script, slices.Concat(attr.Paths, []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append(
name+attr.SourceSuffix,
), attr.Writable, source),
})...)
}

View File

@@ -1,6 +1,11 @@
package rosa
import "hakurei.app/internal/pkg"
import (
"slices"
"strings"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newMeson() pkg.Artifact {
const (
@@ -25,3 +30,96 @@ python3 setup.py \
)))
}
func init() { artifactsF[Meson] = Toolchain.newMeson }
// MesonAttr holds the project-specific attributes that will be applied to a new
// [pkg.Artifact] compiled via [Meson].
type MesonAttr struct {
// Mount the source tree writable.
Writable bool
// Additional environment variables.
Env []string
// Runs before setup.
ScriptEarly string
// Runs after configure.
ScriptCompiled string
// Runs after install.
Script string
// Flags passed to the setup command.
Configure [][2]string
// Whether to skip meson test.
SkipCheck bool
// Appended after the test command.
AppendTest string
// Suffix appended to the source pathname.
SourceSuffix string
// Passed through to [Toolchain.New], before source.
Paths []pkg.ExecPath
// Passed through to [Toolchain.New].
Flag int
}
// NewViaMeson returns a [pkg.Artifact] for compiling and installing via [Meson].
func (t Toolchain) NewViaMeson(
name, version string,
source pkg.Artifact,
attr *MesonAttr,
extra ...pkg.Artifact,
) pkg.Artifact {
if name == "" || version == "" {
panic("names must be non-empty")
}
if attr == nil {
attr = new(MesonAttr)
}
scriptCompiled := attr.ScriptCompiled
if len(scriptCompiled) > 0 && scriptCompiled[0] != '\n' {
scriptCompiled = "\n" + scriptCompiled
}
var check string
if !attr.SkipCheck {
check = "\nmeson test \\\n\t--print-errorlogs" + attr.AppendTest
}
return t.New(name+"-"+version, attr.Flag, slices.Concat([]pkg.Artifact{
t.Load(Python),
t.Load(Meson),
t.Load(Ninja),
t.Load(PkgConfig),
t.Load(CMake),
}, extra), nil, attr.Env, attr.ScriptEarly+`
cd "$(mktemp -d)"
meson setup \
`+strings.Join(slices.Collect(func(yield func(string) bool) {
for _, v := range append([][2]string{
{"prefix", "/system"},
{"buildtype", "release"},
}, attr.Configure...) {
s := "-" + v[0]
if len(v[0]) > 0 && v[0][0] != 'D' {
s = "-" + s
}
if v[1] != "" {
s += "=" + v[1]
}
if !yield(s) {
return
}
}
}), " \\\n\t")+` \
. /usr/src/`+name+`
meson compile`+scriptCompiled+check+`
meson install \
--destdir=/work
`+attr.Script, slices.Concat(attr.Paths, []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append(
name+attr.SourceSuffix,
), attr.Writable, source),
})...)
}

View File

@@ -7,7 +7,7 @@ func (t Toolchain) newMksh() pkg.Artifact {
version = "59c"
checksum = "0Zj-k4nXEu3IuJY4lvwD2OrC2t27GdZj8SPy4DoaeuBRH1padWb7oREpYgwY8JNq"
)
return t.New("mksh-"+version, 0, stage3Concat(t, []pkg.Artifact{},
return t.New("mksh-"+version, 0, stage0Concat(t, []pkg.Artifact{},
t.Load(Perl),
t.Load(Coreutils),
), nil, []string{

33
internal/rosa/musl-fts.go Normal file
View File

@@ -0,0 +1,33 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newMuslFts() pkg.Artifact {
const (
version = "1.2.7"
checksum = "N_p_ZApX3eHt7xoDCw1hLf6XdJOw7ZSx7xPvpvAP0knG2zgU0zeN5w8tt5Pg60XJ"
)
return t.NewViaMake("musl-fts", version, pkg.NewHTTPGetTar(
nil, "https://github.com/void-linux/musl-fts/archive/refs/tags/"+
"v"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
Writable: true,
Env: []string{
"CC=cc -fPIC",
},
ScriptEarly: `
cd /usr/src/musl-fts
./bootstrap.sh
`,
},
t.Load(M4),
t.Load(Perl),
t.Load(Autoconf),
t.Load(Automake),
t.Load(Libtool),
t.Load(PkgConfig),
)
}
func init() { artifactsF[MuslFts] = Toolchain.newMuslFts }

View File

@@ -0,0 +1,33 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newMuslObstack() pkg.Artifact {
const (
version = "1.2.3"
checksum = "tVRY_KjIlkkMszcaRlkKdBVQHIXTT_T_TiMxbwErlILXrOBosocg8KklppZhNdCG"
)
return t.NewViaMake("musl-obstack", version, pkg.NewHTTPGetTar(
nil, "https://github.com/void-linux/musl-obstack/archive/refs/tags/"+
"v"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
Writable: true,
Env: []string{
"CC=cc -fPIC",
},
ScriptEarly: `
cd /usr/src/musl-obstack
./bootstrap.sh
`,
},
t.Load(M4),
t.Load(Perl),
t.Load(Autoconf),
t.Load(Automake),
t.Load(Libtool),
t.Load(PkgConfig),
)
}
func init() { artifactsF[MuslObstack] = Toolchain.newMuslObstack }

View File

@@ -1,34 +1,24 @@
package rosa
import (
"slices"
import "hakurei.app/internal/pkg"
"hakurei.app/internal/pkg"
)
// MuslAttr holds the attributes that will be applied to musl.
type MuslAttr struct {
// Install headers only.
Headers bool
// Environment variables concatenated with defaults.
Env []string
// Dependencies concatenated with defaults.
Extra []pkg.Artifact
}
// NewMusl returns a [pkg.Artifact] containing an installation of musl libc.
func (t Toolchain) NewMusl(attr *MuslAttr) pkg.Artifact {
func (t Toolchain) newMusl(
headers bool,
env []string,
extra ...pkg.Artifact,
) pkg.Artifact {
const (
version = "1.2.5"
checksum = "y6USdIeSdHER_Fw2eT2CNjqShEye85oEg2jnOur96D073ukmIpIqDOLmECQroyDb"
)
if attr == nil {
attr = new(MuslAttr)
}
name := "musl"
attr := MakeAttr{
OmitDefaults: true,
SkipCheck: true,
target := "install"
script := `
Env: env,
Script: `
mkdir -p /work/system/bin
COMPAT_LINKER_NAME="ld-musl-` + linuxArch() + `.so.1"
ln -vs ../lib/libc.so /work/system/bin/linker
@@ -36,29 +26,23 @@ ln -vs ../lib/libc.so /work/system/bin/ldd
ln -vs libc.so "/work/system/lib/${COMPAT_LINKER_NAME}"
rm -v "/work/lib/${COMPAT_LINKER_NAME}"
rmdir -v /work/lib
`
if attr.Headers {
target = "install-headers"
script = ""
`,
}
return t.New("musl-"+version, 0, stage3Concat(t, attr.Extra,
t.Load(Make),
t.Load(Coreutils),
), nil, slices.Concat([]string{
"ROSA_MUSL_TARGET=" + target,
}, attr.Env), `
cd "$(mktemp -d)"
/usr/src/musl/configure \
--prefix=/system \
--target="${ROSA_TRIPLE}"
make "-j$(nproc)" DESTDIR=/work "${ROSA_MUSL_TARGET}"
`+script, pkg.Path(AbsUsrSrc.Append("musl"), false, t.NewPatchedSource(
if headers {
name += "-headers"
attr.ScriptInstall = "make DESTDIR=/work install-headers"
attr.Script = ""
}
return t.NewViaMake(name, version, t.NewPatchedSource(
// expected to be writable in copies
"musl", version, pkg.NewHTTPGetTar(
nil, "https://musl.libc.org/releases/musl-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false,
)))
), &attr, stage0Concat(t, extra,
t.Load(Coreutils),
)...)
}

26
internal/rosa/ncurses.go Normal file
View File

@@ -0,0 +1,26 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newNcurses() pkg.Artifact {
const (
version = "6.6"
checksum = "XvWp4xi6hR_hH8XUoGY26L_pqBSDapJYulhzZqPuR0KNklqypqNc1yNXU-nOjf5w"
)
return t.NewViaMake("ncurses", version, pkg.NewHTTPGetTar(
nil, "https://ftpmirror.gnu.org/gnu/ncurses/ncurses-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
// "tests" are actual demo programs, not a test suite.
SkipCheck: true,
Configure: [][2]string{
{"with-pkg-config"},
{"enable-pc-files"},
},
},
t.Load(PkgConfig),
)
}
func init() { artifactsF[Ncurses] = Toolchain.newNcurses }

View File

@@ -7,30 +7,33 @@ func (t Toolchain) newOpenSSL() pkg.Artifact {
version = "3.5.5"
checksum = "I2Hp1LxcTR8j4G6LFEQMVy6EJH-Na1byI9Ti-ThBot6EMLNRnjGXGq-WXrim3Fkz"
)
return t.New("openssl-"+version, 0, []pkg.Artifact{
t.Load(Perl),
t.Load(Make),
t.Load(Zlib),
t.Load(KernelHeaders),
}, nil, []string{
"CC=cc",
}, `
cd "$(mktemp -d)"
/usr/src/openssl/Configure \
--prefix=/system \
--libdir=lib \
--openssldir=etc/ssl
make \
"-j$(nproc)" \
HARNESS_JOBS=256 \
test
make DESTDIR=/work install
`, pkg.Path(AbsUsrSrc.Append("openssl"), false, pkg.NewHTTPGetTar(
return t.NewViaMake("openssl", version, pkg.NewHTTPGetTar(
nil, "https://github.com/openssl/openssl/releases/download/"+
"openssl-"+version+"/openssl-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
)))
), &MakeAttr{
OmitDefaults: true,
SkipConfigure: true,
Env: []string{
"CC=cc",
},
ScriptConfigured: `
/usr/src/openssl/Configure \
--prefix=/system \
--libdir=lib \
--openssldir=etc/ssl
`,
CheckName: "test",
Make: []string{
`HARNESS_JOBS="$(expr "$(nproc)" '*' 2)"`,
},
},
t.Load(Perl),
t.Load(Zlib),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[OpenSSL] = Toolchain.newOpenSSL }

33
internal/rosa/pcre2.go Normal file
View File

@@ -0,0 +1,33 @@
package rosa
import (
"hakurei.app/internal/pkg"
)
func (t Toolchain) newPCRE2() pkg.Artifact {
const (
version = "10.43"
checksum = "iyNw-POPSJwiZVJfUK5qACA6q2uMzP-84WieimN_CskaEkuw5fRnRTZhEv6ry2Yo"
)
return t.NewViaMake("pcre2", version, pkg.NewHTTPGetTar(
nil, "https://github.com/PCRE2Project/pcre2/releases/download/"+
"pcre2-"+version+"/pcre2-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), &MakeAttr{
ScriptEarly: `
# RunGrepTest expects /bin/echo
ln -s ../system/bin/toybox /bin/echo
`,
Configure: [][2]string{
{"enable-jit"},
{"enable-pcre2-8"},
{"enable-pcre2-16"},
{"enable-pcre2-32"},
},
},
t.Load(Diffutils),
)
}
func init() { artifactsF[PCRE2] = Toolchain.newPCRE2 }

View File

@@ -27,7 +27,7 @@ make \
"-j$(nproc)" \
TEST_JOBS=256 \
test_harness
make DESTDIR=/work install
./perl -Ilib -I. installperl --destdir=/work
`, pkg.Path(AbsUsrSrc.Append("perl"), true, t.NewPatchedSource(
"perl", version, pkg.NewHTTPGetTar(
nil, "https://www.cpan.org/src/5.0/perl-"+version+".tar.gz",

37
internal/rosa/procps.go Normal file
View File

@@ -0,0 +1,37 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newProcps() pkg.Artifact {
const (
version = "4.0.6"
checksum = "pl_fZLvDlv6iZTkm8l_tHFpzTDVFGCiSJEs3eu0zAX6u36AV36P_En8K7JPScRWM"
)
return t.NewViaMake("procps", version, t.NewPatchedSource(
"procps", version, pkg.NewHTTPGetTar(
nil, "https://gitlab.com/procps-ng/procps/-/archive/"+
"v"+version+"/procps-v"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), false,
), &MakeAttr{
Writable: true,
ScriptEarly: `
cd /usr/src/procps
./autogen.sh
`,
Configure: [][2]string{
{"without-ncurses"},
},
},
t.Load(M4),
t.Load(Perl),
t.Load(Autoconf),
t.Load(Automake),
t.Load(Gettext),
t.Load(Libtool),
t.Load(Gzip),
t.Load(PkgConfig),
)
}
func init() { artifactsF[Procps] = Toolchain.newProcps }

View File

@@ -57,6 +57,11 @@ export HOME="$(mktemp -d)"
},
t.Load(Zlib),
t.Load(Libffi),
t.Load(PkgConfig),
t.Load(OpenSSL),
t.Load(Bzip2),
t.Load(XZ),
)
}
func init() { artifactsF[Python] = Toolchain.newPython }

102
internal/rosa/qemu.go Normal file
View File

@@ -0,0 +1,102 @@
package rosa
import (
"hakurei.app/internal/pkg"
)
func (t Toolchain) newQEMU() pkg.Artifact {
const (
version = "10.2.1"
checksum = "rjLTSgHJd3X3Vgpxrsus_ZZiaYLiNix1YhcHaGbLd_odYixwZjCcAIt8CVQPJGdZ"
)
return t.NewViaMake("qemu", version, t.NewPatchedSource(
"qemu", version, pkg.NewHTTPGetTar(
nil, "https://download.qemu.org/qemu-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), false, [2]string{"disable-mcast-test", `diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
index b731af0ad9..b5cbed4801 100644
--- a/tests/qtest/netdev-socket.c
+++ b/tests/qtest/netdev-socket.c
@@ -401,7 +401,7 @@ static void test_dgram_inet(void)
qtest_quit(qts0);
}
-#if !defined(_WIN32) && !defined(CONFIG_DARWIN)
+#if 0
static void test_dgram_mcast(void)
{
QTestState *qts;
@@ -513,7 +513,7 @@ int main(int argc, char **argv)
if (has_ipv4) {
qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4);
qtest_add_func("/netdev/dgram/inet", test_dgram_inet);
-#if !defined(_WIN32) && !defined(CONFIG_DARWIN)
+#if 0
qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
#endif
}
`},
), &MakeAttr{
// configure script uses source as scratch space
Writable: true,
ScriptEarly: `
# tests expect /var/tmp/ to be available
mkdir -p /var/tmp/
# https://gitlab.com/qemu-project/qemu/-/issues/3145
(cd /usr/src/qemu && sed -i \
's,Input/output error,I/O error,g' \
tests/qemu-iotests/[0-9][0-9][0-9]* \
tests/qemu-iotests/tests/copy-before-write \
tests/qemu-iotests/tests/file-io-error.out &&
cat << EOF > tests/qemu-iotests/150
#!/bin/sh
_notrun 'appears to spuriously fail on zfs'
EOF
)
`,
Configure: [][2]string{
{"disable-download"},
{"disable-docs"},
{"target-list-exclude", "" +
// fails to load firmware
"ppc-linux-user," +
"ppc64-linux-user," +
"ppc64le-linux-user," +
"ppc-softmmu," +
"ppc64-softmmu"},
},
ScriptConfigured: `
make "-j$(nproc)"
`,
},
t.Load(Bash),
t.Load(Python),
t.Load(Ninja),
t.Load(Bzip2),
t.Load(PkgConfig),
t.Load(Diffutils),
t.Load(OpenSSL),
t.Load(Bzip2),
t.Load(XZ),
t.Load(Flex),
t.Load(Bison),
t.Load(M4),
t.Load(PCRE2),
t.Load(Libffi),
t.Load(Zlib),
t.Load(GLib),
t.Load(Zstd),
t.Load(DTC),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[QEMU] = Toolchain.newQEMU }

View File

@@ -2,6 +2,7 @@
package rosa
import (
"errors"
"log"
"runtime"
"slices"
@@ -82,11 +83,11 @@ func earlyLDFLAGS(static bool) string {
return s
}
// earlyCFLAGS is reference CFLAGS for the stage3 toolchain.
// earlyCFLAGS is reference CFLAGS for the stage0 toolchain.
const earlyCFLAGS = "-Qunused-arguments " +
"-isystem/system/include"
// earlyCXXFLAGS returns reference CXXFLAGS for the stage3 toolchain
// earlyCXXFLAGS returns reference CXXFLAGS for the stage0 toolchain
// corresponding to [runtime.GOARCH].
func earlyCXXFLAGS() string {
return "--start-no-unused-arguments " +
@@ -98,19 +99,33 @@ func earlyCXXFLAGS() string {
}
// Toolchain denotes the infrastructure to compile a [pkg.Artifact] on.
type Toolchain uintptr
type Toolchain uint32
const (
// toolchainBusybox denotes a busybox installation from the busyboxBin
// binary distribution. This is for decompressing unsupported formats.
toolchainBusybox Toolchain = iota
// _toolchainBusybox denotes a busybox installation from the busyboxBin
// binary distribution. This is defined as a toolchain to make use of the
// toolchain abstractions to preprocess toolchainGentoo and is not a real,
// functioning toolchain. It does not contain any compilers.
_toolchainBusybox Toolchain = iota
// toolchainStage3 denotes the Gentoo stage3 toolchain. Special care must be
// taken to compile correctly against this toolchain.
toolchainStage3
// toolchainGentoo denotes the toolchain in a Gentoo stage3 tarball. Special
// care must be taken to compile correctly against this toolchain.
toolchainGentoo
// toolchainIntermediateGentoo is like to toolchainIntermediate, but
// compiled against toolchainGentoo.
toolchainIntermediateGentoo
// toolchainStdGentoo is like Std, but bootstrapped from toolchainGentoo.
// This toolchain creates the first [Stage0] distribution.
toolchainStdGentoo
// toolchainStage0 denotes the stage0 toolchain. Special care must be taken
// to compile correctly against this toolchain.
toolchainStage0
// toolchainIntermediate denotes the intermediate toolchain compiled against
// toolchainStage3. This toolchain should be functionally identical to [Std]
// toolchainStage0. This toolchain should be functionally identical to [Std]
// and is used to bootstrap [Std].
toolchainIntermediate
@@ -122,19 +137,49 @@ const (
_toolchainEnd
)
// stage3Concat concatenates s and values. If the current toolchain is
// toolchainStage3, stage3Concat returns s as is.
func stage3Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t == toolchainStage3 {
// isStage0 returns whether t is a stage0 toolchain.
func (t Toolchain) isStage0() bool {
switch t {
case toolchainGentoo, toolchainStage0:
return true
default:
return false
}
}
// isIntermediate returns whether t is an intermediate toolchain.
func (t Toolchain) isIntermediate() bool {
switch t {
case toolchainIntermediateGentoo, toolchainIntermediate:
return true
default:
return false
}
}
// isStd returns whether t is considered functionally equivalent to [Std].
func (t Toolchain) isStd() bool {
switch t {
case toolchainStdGentoo, Std:
return true
default:
return false
}
}
// stage0Concat concatenates s and values. If the current toolchain is
// toolchainStage0, stage0Concat returns s as is.
func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t.isStage0() {
return s
}
return slices.Concat(s, values)
}
// stage3ExclConcat concatenates s and values. If the current toolchain is not
// toolchainStage3, stage3ExclConcat returns s as is.
func stage3ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t == toolchainStage3 {
// stage0ExclConcat concatenates s and values. If the current toolchain is not
// toolchainStage0, stage0ExclConcat returns s as is.
func stage0ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t.isStage0() {
return slices.Concat(s, values)
}
return s
@@ -173,7 +218,7 @@ func fixupEnviron(env, extras []string, paths ...string) []string {
// absCureScript is the absolute pathname [Toolchain.New] places the fixed-up
// build script under.
var absCureScript = fhs.AbsUsrBin.Append(".cure-script")
var absCureScript = AbsSystem.Append("bin", ".cure-script")
const (
// TExclusive denotes an exclusive [pkg.Artifact].
@@ -182,12 +227,31 @@ const (
TEarly
)
var (
// gentooStage3 is the url of a Gentoo stage3 tarball.
gentooStage3 string
// gentooStage3Checksum is the expected checksum of gentooStage3.
gentooStage3Checksum pkg.Checksum
)
// SetGentooStage3 sets the Gentoo stage3 tarball url and checksum. It panics
// if given zero values or if these values have already been set.
func SetGentooStage3(url string, checksum pkg.Checksum) {
if gentooStage3 != "" {
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"))
}
gentooStage3, gentooStage3Checksum = url, checksum
}
// New returns a [pkg.Artifact] compiled on this toolchain.
func (t Toolchain) New(
name string,
flag int,
extra []pkg.Artifact,
checksum *pkg.Checksum,
knownChecksum *pkg.Checksum,
env []string,
script string,
@@ -195,57 +259,47 @@ func (t Toolchain) New(
) pkg.Artifact {
const lcMessages = "LC_MESSAGES=C.UTF-8"
var (
path = AbsSystem.Append("bin", "sh")
args = []string{"sh", absCureScript.String()}
support []pkg.Artifact
)
var support []pkg.Artifact
switch t {
case toolchainBusybox:
case _toolchainBusybox:
name += "-early"
support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra)
path = AbsSystem.Append("bin", "busybox")
args[0] = "hush"
env = fixupEnviron(env, nil, "/system/bin")
case toolchainStage3:
case toolchainGentoo, toolchainStage0:
name += "-boot"
var seed string
switch runtime.GOARCH {
case "amd64":
seed = "c5_FwMnRN8RZpTdBLGYkL4RR8ampdaZN2JbkgrFLe8-QHQAVQy08APVvIL6eT7KW"
case "arm64":
seed = "79uRbRI44PyknQQ9RlFUQrwqplup7vImiIk6klefL8TN-fT42TXMS_v4XszwexCb"
default:
panic("unsupported target " + runtime.GOARCH)
}
path = fhs.AbsRoot.Append("bin", "bash")
args[0] = "bash"
support = slices.Concat([]pkg.Artifact{
cureEtc{},
toolchainBusybox.New("stage3", 0, nil, nil, nil, `
support = append(support, cureEtc{})
if t == toolchainStage0 {
support = append(support, NewStage0())
} else {
support = append(support, _toolchainBusybox.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, "https://basement.gensokyo.uk/seed/"+seed,
mustDecode(seed),
nil, gentooStage3,
gentooStage3Checksum,
),
)),
}, extra)
)))
}
support = slices.Concat(support, extra)
env = fixupEnviron(env, []string{
EnvTriplet + "=" + triplet(),
lcMessages,
"LDFLAGS=" + earlyLDFLAGS(true),
}, "/system/bin",
"/usr/bin",
"/usr/lib/llvm/21/bin",
)
case toolchainIntermediate, Std:
if t < Std {
case toolchainIntermediateGentoo, toolchainStdGentoo,
toolchainIntermediate, Std:
if t.isIntermediate() {
name += "-std"
}
@@ -279,9 +333,10 @@ ln -vs ../usr/bin /work/bin
}
return pkg.NewExec(
name, checksum, pkg.ExecTimeoutMax, flag&TExclusive != 0,
name, knownChecksum, pkg.ExecTimeoutMax, flag&TExclusive != 0,
fhs.AbsRoot, env,
path, args,
AbsSystem.Append("bin", "sh"),
[]string{"sh", absCureScript.String()},
slices.Concat([]pkg.ExecPath{pkg.Path(
fhs.AbsRoot, true,
@@ -328,7 +383,7 @@ cat /usr/src/` + name + `-patches/* | \
`
aname += "-patched"
}
return t.New(aname, 0, stage3Concat(t, []pkg.Artifact{},
return t.New(aname, 0, stage0Concat(t, []pkg.Artifact{},
t.Load(Patch),
), nil, nil, script, paths...)
}

41
internal/rosa/squashfs.go Normal file
View File

@@ -0,0 +1,41 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newSquashfsTools() pkg.Artifact {
const (
version = "4.7.4"
checksum = "pG0E_wkRJFS6bvPYF-hTKZT-cWnvo5BbIzCDZrJZVQDgJOx2Vc3ZfNSEV7Di7cSW"
)
return t.NewViaMake("squashfs-tools", version, t.NewPatchedSource(
"squashfs-tools", version, pkg.NewHTTPGetTar(
nil, "https://github.com/plougher/squashfs-tools/releases/"+
"download/"+version+"/squashfs-tools-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false,
), &MakeAttr{
Writable: true,
SkipConfigure: true,
InPlace: true,
Env: []string{
"CONFIG=1",
"XZ_SUPPORT=0",
"LZO_SUPPORT=0",
"LZ4_SUPPORT=0",
"COMP_DEFAULT=zstd",
"USE_PREBUILT_MANPAGES=y",
},
ScriptEarly: "cd /usr/src/squashfs-tools/squashfs-tools",
SkipCheck: true,
ScriptInstall: "make INSTALL_PREFIX=/work/system install",
},
t.Load(Sed),
t.Load(Zstd),
t.Load(Gzip),
t.Load(Zlib),
)
}
func init() { artifactsF[SquashfsTools] = Toolchain.newSquashfsTools }

View File

@@ -12,45 +12,57 @@ func (t Toolchain) newNSS() pkg.Artifact {
version0 = "4_38_2"
checksum0 = "25x2uJeQnOHIiq_zj17b4sYqKgeoU8-IsySUptoPcdHZ52PohFZfGuIisBreWzx0"
)
return t.New("nss-"+version, 0, []pkg.Artifact{
t.Load(Perl),
t.Load(Python),
t.Load(Unzip),
t.Load(Make),
t.Load(Gawk),
t.Load(Coreutils),
t.Load(Zlib),
t.Load(KernelHeaders),
}, nil, nil, `
unzip /usr/src/nspr.zip -d /usr/src
mv '/usr/src/nspr-NSPR_`+version0+`_RTM' /usr/src/nspr
cd /usr/src/nss
make \
"-j$(nproc)" \
CCC="clang++" \
NSDISTMODE=copy \
BUILD_OPT=1 \
USE_64=1 \
nss_build_all
mkdir -p /work/system/nss
cp -r \
/usr/src/dist/. \
lib/ckfw/builtins/certdata.txt \
/work/system/nss
`, pkg.Path(AbsUsrSrc.Append("nss"), true, t.NewPatchedSource(
return t.NewViaMake("nss", version, t.NewPatchedSource(
"nss", version, pkg.NewHTTPGetTar(
nil, "https://github.com/nss-dev/nss/archive/refs/tags/"+
"NSS_"+version+"_RTM.tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), false,
)), pkg.Path(AbsUsrSrc.Append("nspr.zip"), false, pkg.NewHTTPGet(
nil, "https://hg-edge.mozilla.org/projects/nspr/archive/"+
"NSPR_"+version0+"_RTM.zip",
mustDecode(checksum0),
)))
), &MakeAttr{
Paths: []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append("nspr.zip"), false, pkg.NewHTTPGet(
nil, "https://hg-edge.mozilla.org/projects/nspr/archive/"+
"NSPR_"+version0+"_RTM.zip",
mustDecode(checksum0),
)),
},
Writable: true,
OmitDefaults: true,
SkipConfigure: true,
InPlace: true,
ScriptEarly: `
unzip /usr/src/nspr.zip -d /usr/src
mv '/usr/src/nspr-NSPR_` + version0 + `_RTM' /usr/src/nspr
cd /usr/src/nss
`,
SkipCheck: true,
Make: []string{
"CCC=clang++",
"NSDISTMODE=copy",
"BUILD_OPT=1",
"USE_64=1",
"nss_build_all",
},
ScriptInstall: `
mkdir -p /work/system/nss
cp -r \
/usr/src/dist/. \
lib/ckfw/builtins/certdata.txt \
/work/system/nss
`,
},
t.Load(Perl),
t.Load(Python),
t.Load(Unzip),
t.Load(Gawk),
t.Load(Coreutils),
t.Load(Zlib),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[NSS] = Toolchain.newNSS }

75
internal/rosa/stage0.go Normal file
View File

@@ -0,0 +1,75 @@
package rosa
import (
"runtime"
"sync"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newStage0() pkg.Artifact {
musl, compilerRT, runtimes, clang := t.NewLLVM()
return t.New("rosa-stage0", 0, []pkg.Artifact{
musl,
compilerRT,
runtimes,
clang,
t.Load(Bzip2),
t.Load(Patch),
t.Load(Make),
t.Load(CMake),
t.Load(Ninja),
t.Load(Libffi),
t.Load(Python),
t.Load(Perl),
t.Load(Diffutils),
t.Load(Bash),
t.Load(Gawk),
t.Load(Coreutils),
t.Load(Findutils),
t.Load(KernelHeaders),
}, nil, nil, `
umask 377
tar \
-vjc \
-C / \
-f /work/stage0-`+triplet()+`.tar.bz2 \
system bin usr/bin/env
`)
}
func init() { artifactsF[Stage0] = Toolchain.newStage0 }
var (
// stage0 stores the tarball unpack artifact.
stage0 pkg.Artifact
// stage0Once is for lazy initialisation of stage0.
stage0Once sync.Once
)
// NewStage0 returns a stage0 distribution created from curing [Stage0].
func NewStage0() pkg.Artifact {
stage0Once.Do(func() {
var seed string
switch runtime.GOARCH {
case "amd64":
seed = "tqM1Li15BJ-uFG8zU-XjgFxoN_kuzh1VxrSDVUVa0vGmo-NeWapSftH739sY8EAg"
case "arm64":
seed = "CJj3ZSnRyLmFHlWIQtTPQD9oikOZY4cD_mI3v_-LIYc2hhg-cq_CZFBLzQBAkFIn"
default:
panic("unsupported target " + runtime.GOARCH)
}
stage0 = pkg.NewHTTPGetTar(
nil, "https://hakurei.app/seed/20260210/"+
"stage0-"+triplet()+".tar.bz2",
mustDecode(seed),
pkg.TarBzip2,
)
})
return stage0
}

40
internal/rosa/tamago.go Normal file
View File

@@ -0,0 +1,40 @@
package rosa
import (
"runtime"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newTamaGo() pkg.Artifact {
const (
version = "1.26.0"
checksum = "5XkfbpTpSdPJfwtTfUegfdu4LUy8nuZ7sCondiRIxTJI9eQONi8z_O_dq9yDkjw8"
)
return t.New("tamago-go"+version, 0, []pkg.Artifact{
t.Load(Bash),
t.Load(Go),
}, nil, []string{
"CC=cc",
"GOCACHE=/tmp/gocache",
}, `
mkdir /work/system # "${TMPDIR}"
cp -r /usr/src/tamago /work/system
cd /work/system/tamago/src
chmod -R +w ..
sed -i \
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
cmd/link/internal/`+runtime.GOARCH+`/obj.go
rm \
os/root_unix_test.go
./all.bash
`, pkg.Path(AbsUsrSrc.Append("tamago"), false, pkg.NewHTTPGetTar(
nil, "https://github.com/usbarmory/tamago-go/archive/refs/tags/"+
"tamago-go"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
)))
}
func init() { artifactsF[TamaGo] = Toolchain.newTamaGo }

View File

@@ -7,16 +7,18 @@ func (t Toolchain) newToybox(suffix, script string) pkg.Artifact {
version = "0.8.13"
checksum = "rZ1V1ATDte2WeQZanxLVoiRGdfPXhMlEo5-exX-e-ml8cGn9qOv0ABEUVZpX3wTI"
)
return t.New("toybox-"+version+suffix, TEarly, stage3Concat(t, []pkg.Artifact{},
return t.New("toybox-"+version+suffix, TEarly, stage0Concat(t, []pkg.Artifact{},
t.Load(Make),
t.Load(Bash),
t.Load(Gzip),
t.Load(KernelHeaders),
), nil, stage3Concat(t, []string{},
), nil, stage0Concat(t, []string{},
"ROSA_CHECK=make USER=cure tests",
), `
ln -s ../system/bin/bash /bin/ || true
chmod +w /bin/
ln -rs "$(which bash)" /bin/ || true
cd /usr/src/toybox
chmod +w kconfig tests
rm \

View File

@@ -0,0 +1,49 @@
package rosa
import (
"strings"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newUtilLinux() pkg.Artifact {
const (
version = "2.41.3"
checksum = "gPTd5JJ2ho_Rd0qainuogcLiiWwKSXEZPXN3yCCRl0m0KBgMaqwFuMjYgu9z8zCH"
)
return t.NewViaMake("util-linux", version, pkg.NewHTTPGetTar(
nil, "https://www.kernel.org/pub/linux/utils/util-linux/"+
"v"+strings.Join(strings.SplitN(version, ".", 3)[:2], ".")+
"/util-linux-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &MakeAttr{
ScriptEarly: `
ln -s ../system/bin/bash /bin/
`,
Configure: [][2]string{
{"disable-use-tty-group"},
{"disable-makeinstall-setuid"},
{"disable-makeinstall-chown"},
{"enable-fs-paths-default", "" +
"/system/sbin:" +
"/system/sbin/fs.d:" +
"/system/sbin/fs"},
{"disable-su"},
{"disable-liblastlog2"},
{"disable-pam-lastlog2"},
},
// check script claims:
// For development purpose only.
// Don't execute on production system!
SkipCheck: true,
},
t.Load(Bash),
t.Load(KernelHeaders),
)
}
func init() { artifactsF[UtilLinux] = Toolchain.newUtilLinux }

View File

@@ -7,43 +7,31 @@ func (t Toolchain) newWayland() pkg.Artifact {
version = "1.24.0"
checksum = "JxgLiFRRGw2D3uhVw8ZeDbs3V7K_d4z_ypDog2LBqiA_5y2vVbUAk5NT6D5ozm0m"
)
return t.New("wayland-"+version, 0, []pkg.Artifact{
t.Load(Python),
t.Load(Meson),
t.Load(PkgConfig),
t.Load(CMake),
t.Load(Ninja),
return t.NewViaMeson("wayland", version, pkg.NewHTTPGetTar(
nil, "https://gitlab.freedesktop.org/wayland/wayland/"+
"-/archive/"+version+"/wayland-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), &MesonAttr{
Writable: true,
ScriptEarly: `
cd /usr/src/wayland
chmod +w tests tests/sanity-test.c
echo 'int main(){}' > tests/sanity-test.c
`,
Configure: [][2]string{
{"Ddefault_library", "both"},
{"Ddocumentation", "false"},
{"Dtests", "true"},
},
},
t.Load(Gawk),
t.Load(Diffutils),
t.Load(Libffi),
t.Load(Libexpat),
t.Load(Libxml2),
}, nil, nil, `
cd /usr/src/wayland
chmod +w tests tests/sanity-test.c
echo 'int main(){}' > tests/sanity-test.c
cd "$(mktemp -d)"
meson setup \
--reconfigure \
--buildtype=release \
--prefix=/system \
--prefer-static \
-Ddocumentation=false \
-Dtests=true \
-Ddefault_library=both \
. /usr/src/wayland
meson compile
meson test
meson install \
--destdir=/work
`, pkg.Path(AbsUsrSrc.Append("wayland"), true, pkg.NewHTTPGetTar(
nil, "https://gitlab.freedesktop.org/wayland/wayland/"+
"-/archive/"+version+"/wayland-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
)))
)
}
func init() { artifactsF[Wayland] = Toolchain.newWayland }
@@ -52,33 +40,68 @@ func (t Toolchain) newWaylandProtocols() pkg.Artifact {
version = "1.47"
checksum = "B_NodZ7AQfCstcx7kgbaVjpkYOzbAQq0a4NOk-SA8bQixAE20FY3p1-6gsbPgHn9"
)
return t.New("wayland-protocols-"+version, 0, []pkg.Artifact{
t.Load(Python),
t.Load(Meson),
t.Load(PkgConfig),
t.Load(CMake),
t.Load(Ninja),
return t.NewViaMeson("wayland-protocols", version, t.NewPatchedSource(
"wayland-protocols", version, pkg.NewHTTPGetTar(
nil, "https://gitlab.freedesktop.org/wayland/wayland-protocols/"+
"-/archive/"+version+"/wayland-protocols-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
), false, [2]string{"build-only", `From 8b4c76275fa1b6e0a99a53494151d9a2c907144d Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Fri, 8 Nov 2024 11:27:25 -0600
Subject: [PATCH] tests: Make build-only tests actually build-only
The goal behind the pedantic compiler tests are to ensure that the code
that wayland-scanner is generating can be compiled in pedantic mode by
the system C compiler.
Trying to execute the built tests may fail because of undefined symbols.
This affects certain platforms more than others; Linux/musl and Darwin
are examples of platforms that cannot execute binaries with undefined
symbols. This meant tests needlessly failed on these platforms.
Signed-off-by: A. Wilcox <AWilcox@Wilcox-Tech.com>
Closes: #48, #228
---
tests/meson.build | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/meson.build b/tests/meson.build
index aa216ec2..5a93bb36 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,4 +1,5 @@
prog_scan_sh = find_program('scan.sh')
+prog_true = find_program('true')
libwayland = [
dependency('wayland-client'),
@@ -100,7 +101,7 @@ foreach protocol_file : protocol_files
test_source,
client_header,
server_header,
- code
+ code,
],
link_args: extra_linker_flags,
dependencies: libwayland,
@@ -111,7 +112,7 @@ foreach protocol_file : protocol_files
'-Werror' ],
install: false,
)
- test(test_name, pedantic_test_executable)
+ test(test_name, prog_true, depends : [pedantic_test_executable])
# Check that the header
if not protocol_file.contains('xdg-foreign-unstable-v1')
--
GitLab
`},
), nil,
t.Load(Wayland),
t.Load(Libffi),
t.Load(Libexpat),
t.Load(Libxml2),
}, nil, nil, `
cd "$(mktemp -d)"
meson setup \
--reconfigure \
--buildtype=release \
--prefix=/system \
--prefer-static \
. /usr/src/wayland-protocols
meson compile
meson install \
--destdir=/work
`, pkg.Path(AbsUsrSrc.Append("wayland-protocols"), false, pkg.NewHTTPGetTar(
nil, "https://gitlab.freedesktop.org/wayland/wayland-protocols/"+
"-/archive/"+version+"/wayland-protocols-"+version+".tar.bz2",
mustDecode(checksum),
pkg.TarBzip2,
)))
)
}
func init() { artifactsF[WaylandProtocols] = Toolchain.newWaylandProtocols }

View File

@@ -16,6 +16,7 @@ func (t Toolchain) newZlib() pkg.Artifact {
Env: []string{
"CC=clang -fPIC",
},
Host: `""`,
Build: `""`,
})
}

23
internal/rosa/zstd.go Normal file
View File

@@ -0,0 +1,23 @@
package rosa
import "hakurei.app/internal/pkg"
func (t Toolchain) newZstd() pkg.Artifact {
const (
version = "1.5.7"
checksum = "4XhfR7DwVkwo1R-TmYDAJOcx9YXv9WSFhcFUe3hWEAMmdMLPhFaznCqYIA19_xxV"
)
return t.NewViaCMake("zstd", version, pkg.NewHTTPGetTar(
nil, "https://github.com/facebook/zstd/releases/download/"+
"v"+version+"/zstd-"+version+".tar.gz",
mustDecode(checksum),
pkg.TarGzip,
), &CMakeAttr{
Append: []string{"build", "cmake"},
Cache: [][2]string{
{"CMAKE_BUILD_TYPE", "Release"},
{"CMAKE_INSTALL_LIBDIR", "lib"},
},
})
}
func init() { artifactsF[Zstd] = Toolchain.newZstd }

View File

@@ -95,6 +95,9 @@
];
};
# Disk image is too small for some tests:
boot.tmp.useTmpfs = true;
environment.hakurei = {
enable = true;
stateDir = "/var/lib/hakurei";