Compare commits

..

98 Commits

Author SHA1 Message Date
cat 17383ab353 internal/rosa/package/gnu: disable flaky coreutils test
Another flaky test, once disabled but removed during an upgrade.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 10:50:53 +09:00
cat 237e793895 internal/rosa: respect preferred loadavg target
This generally improves build performance and system responsiveness.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 10:08:08 +09:00
cat 6cfd8fb934 internal/pkg: loadavg target in container environment
This exposes preferred loadavg target to the container initial process.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 09:45:43 +09:00
cat 2f1534853a internal/pkg: consolidate cache attributes
This makes the interface stable.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 09:34:27 +09:00
cat 3f8e111d1c configure Azalea language detection
This is not likely to be upstreamed anywhere, any time soon, so configure it here.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 03:13:11 +09:00
cat 9fae451dc0 internal/rosa/meson: set timeout multiplier
Current meson-based spurious test failures are generally always caused by timeouts under load, so mitigate that here.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-09 03:01:07 +09:00
cat e3666cda21 internal/rosa/make: run in hardcoded directory
This actually eliminates some of the autotools nondeterminism, as autotools is not capable of stripping build pathnames.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 21:48:47 +09:00
cat 9c51805b47 internal/rosa/package/gnu: disable flaky coreutils tests
These are huge and have incomprehensible output. Probability of failure increases under load, so disable them.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 21:31:38 +09:00
cat 3dca68fc95 cmd/mbf: validate build determinism
This rebuilds a package repeatedly and compares outcomes.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 21:28:21 +09:00
cat 6495118165 cmd/mbf: print all available handles
Useful for scripting.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 15:30:27 +09:00
cat 472849cfd6 internal/pkg: optionally force implementation entry
For validation of build determinism.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 15:26:42 +09:00
cat 3c6e9b3d05 internal/pkg: expose cure whence
Useful for cure determinism validation of KindExec.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-08 14:19:17 +09:00
cat aa5e77ef27 internal/rosa: populate mirror snapshot
This produces the same structure served by the dynamic server.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 21:14:57 +09:00
cat 76360979f9 internal/rosa: mirror response write methods
For the fs.FS implementation and static publishing.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 20:18:18 +09:00
cat 6d55ee536e test: move nix files
These are too much clutter. Move them to test directory until the test suite replacement is upstreamed.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 18:56:27 +09:00
cat c8e8651694 cmd/mbf: shallow by default
This is going to be used most of the time, with --deep only useful for fetching bootstrap artifacts.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 16:39:38 +09:00
cat aa5d38981d internal/pkg: optional shallow external cure
This saves time and is often more practical even for package maintainers.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 16:35:08 +09:00
cat b08feac26c internal/rosa/package: ipmitool
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 15:03:18 +09:00
cat 810b806a15 cmd/app: omit hidden files
This avoids vim swap files breaking scripts.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-07 13:26:58 +09:00
cat 4a42657d88 internal/rosa/package/gnu: disable sed flaky test
This is causing way too many spurious failures.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-05 23:02:02 +09:00
cat f0b6659865 internal/rosa/package/kernel: 6.18.37 to 6.18.38
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-05 18:58:28 +09:00
cat a8ffaa20e0 internal/rosa/package/hwdata: 0.408 to 0.409
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-05 18:57:40 +09:00
cat fb62ae00e4 internal/rosa/package/python: setuptools 82.0.1 to 83.0.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-05 18:57:19 +09:00
cat 512d9b95bd internal/pkg: remove status acquisition from extern helper
Doing this together just makes it awkward to query status early, having to deal with cleaning up.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-04 23:46:50 +09:00
cat 5bf87561f5 internal/pkg: move concurrent cure implementation
This is useful independent of cure and might replace the Collect hack.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-04 23:27:12 +09:00
cat dde69dde61 internal/pkg: rename inputs method
Inputs is more correct than dependencies in the current terminology.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 23:21:31 +09:00
cat 3ba6609444 internal/pkg: move outcome dereferencing
This prepares substitute computation for shallow extern replacements.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 22:52:37 +09:00
cat 6dcc2fdc17 internal/rosa/package/mesa: 26.1.3 to 26.1.4
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 22:37:31 +09:00
cat c553b74807 internal/rosa/package/libva: 2.23.0 to 2.24.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 22:35:57 +09:00
cat 8c853c3eb6 internal/rosa/package/libseccomp: 2.6.0 to 2.6.1
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 22:30:13 +09:00
cat d2f322e911 internal/rosa/package/gnutls: fix arm64-specific configure flag
Automatic prefix does not happen for the value string.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 20:58:23 +09:00
cat b538c69e01 internal/pkg: cache extern responses
This prepares substitute computation for shallow extern replacements.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-02 20:08:28 +09:00
cat c921ba4680 internal/rosa/package/qemu: set TIMEOUT_MULTIPLIER
This uses the alpine linux value for now. The default timeouts make the test suite flaky under load.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-01 21:52:56 +09:00
cat 7404bf6025 internal/rosa/package/noto: 2026.06.01 to 2026.07.01
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-01 15:42:08 +09:00
cat 3975dd3e0f internal/rosa: create /bin symlinks via helper
This centralises the workaround for surprisingly common buggy scripts with nonstandard hardcoded paths.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-01 15:03:26 +09:00
cat 3ab7116b29 internal/rosa/package/kernel: 6.12.94 to 6.18.37
Finally jumping from 6.12 to 6.18, and the patches can be dropped.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-07-01 02:32:20 +09:00
cat 9be165d6ee internal/rosa/package/qemu: 11.0.1 to 11.0.2
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:53:21 +09:00
cat 1c55e7c772 internal/rosa/package/python: vcs-versioning 2.2.0 to 2.2.2
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:51:02 +09:00
cat a981d185cf internal/rosa/package/git: 2.54.0 to 2.55.0
For some reason rust is now forced on by default without any check whatsoever. No idea why the maintainers think it was such a good idea to be so in your face.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:43:25 +09:00
cat d91951ca97 internal/rosa/package/acl: 2.3.2 to 2.4.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:16:42 +09:00
cat 09a2ffc3bc internal/rosa/package/acl: attr 2.5.2 to 2.6.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:16:09 +09:00
cat a6444658da internal/rosa/package/json-c: 0.18-20240915 to 0.19-20260627
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:06:41 +09:00
cat ed5615033c internal/rosa/package/gnu: parallel 20260522 to 20260622
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-30 19:06:13 +09:00
cat d1319a497c internal/rosa: handle nil source
Source is not always required. This improves flexibility.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-28 18:02:54 +09:00
cat cf7c34555c cmd/earlyinit: improve error messages
This improves readability, especially on a small display.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-28 18:01:51 +09:00
cat d96eecded0 internal/rosa/package/pango: 1.57.1 to 1.58.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-27 15:52:23 +09:00
cat 6863bcafd1 cmd/app: optional insecure options
These are useful for very specific cases by the maintainer. No app should ever require this.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-26 21:56:07 +09:00
cat 39f023d0e5 internal/rosa/package/glib: 2.89.0 to 2.89.1
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-26 11:33:10 +09:00
cat a8a2f692e7 internal/rosa/package/libexpat: 2.8.1 to 2.8.2
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-26 11:29:27 +09:00
cat 19f24c7206 internal/rosa/package/python: setuptools-scm 10.1.2 to 10.2.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-25 20:29:18 +09:00
cat 320432774a internal/rosa/package/python: vcs-versioning 2.1.2 to 2.2.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-25 20:28:48 +09:00
cat 0721b0fe6d internal/rosa/package/curl: 8.20.0 to 8.21.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-25 14:08:07 +09:00
cat 418e4a874d internal/rosa/package/libpsl: 0.21.5 to 0.22.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-25 14:07:38 +09:00
cat 8378e7a2c9 internal/rosa/package/vim: annotate blocked update
Releases are unreasonably frequent, and the package is never exposed to the end user and never expected to run unconfined or consume untrusted input. Additionally, upstream is accepting AI slop.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-25 14:06:03 +09:00
cat 6210c9f272 internal/rosa/package: noto
Internationalisation is required anyway, so just package the entire noto fonts.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 10:45:01 +09:00
cat c2038fa925 internal/rosa/package: rename
Useful for packaging.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 10:39:38 +09:00
cat d797cca1f2 internal/rosa/package/python: vcs-versioning 2.1.1 to 2.1.2
Another bug fix release already. Turns out upstream is using AI slop.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 09:52:59 +09:00
cat 2a51b433c8 cmd/app: exclude /tmp/ for X11 pathname socket
This would otherwise cover the pathname socket.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 08:49:16 +09:00
cat e5ce36532b internal/rosa/package/toybox: 0.8.13 to 0.8.14
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:41:56 +09:00
cat 4c647388b0 internal/rosa/package/hakurei: 0.4.4 to 0.4.5
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:28:56 +09:00
cat 3a5f4af114 release: 0.4.5
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:18:02 +09:00
cat 6195260480 internal/rosa/package/firmware: 20260519 to 20260622
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:11:20 +09:00
cat 21044d5a60 internal/rosa/package/vim: 9.2.0461 to 9.2.0707
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:10:58 +09:00
cat 025810bf0f internal/rosa/package/python: setuptools-scm 10.0.5 to 10.1.2
All in-between releases are broken. Not sure how that happened.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:10:32 +09:00
cat 20354c0411 internal/rosa/package/python: vcs-versioning 1.1.1 to 2.1.1
The environment variable changed for this package only, did not appear to affect other packages.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:09:42 +09:00
cat 9fbcd0daf2 internal/rosa/package/libarchive: 3.8.7 to 3.8.8
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-24 06:08:47 +09:00
cat 248f44a5a7 cmd/app: zero state buffer before reuse
Package internal/store expects a zero-initialised buffer.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-23 09:19:11 +09:00
cat 401dd57cbc cmd/app: display user-facing error message
This is required for useful error messages for errors originating from internal/store.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-23 09:09:55 +09:00
cat 854bcc998b cmd/app: expose scheduling configuration
Useful for the music player.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-23 06:33:27 +09:00
cat 358247be5b internal/rosa/package/x: xkeyboard-config 2.47 to 2.48
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-23 00:44:18 +09:00
cat f517a8ef07 internal/rosa/package/libffi: 3.5.2 to 3.6.0
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-23 00:43:24 +09:00
cat 973218f91f internal/rosa/package/qemu: disable netdev-socket test
This fails with ipv6 disabled.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-22 01:21:09 +09:00
cat 0ea195837b internal/rosa/package/glib: disable gio suite
This fails with ipv6 disabled.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-22 00:53:40 +09:00
cat 1348991634 internal/rosa/meson: skip specific test suites
For disabling specific broken or flaky tests.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-22 00:53:17 +09:00
cat 14b445fde5 internal/rosa/package/openssl: disable test_bio_dgram
This fails when ipv6 is disabled.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-21 21:43:46 +09:00
cat 218f7fa345 cmd/app: enforce mutable instance exclusion
This avoids invoking undefined behaviour in the underlying overlay filesystem implementation.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-21 02:09:01 +09:00
cat cd493fd95f cmd/app: centralise workdir
This makes the directory structure significantly more manageable.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-21 00:48:18 +09:00
cat 9db70c83e3 cmd/app: configure username and hostname
These no longer need to be hardcoded since this is not subject to the limitations of home-manager.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 22:15:49 +09:00
cat 4e09241e5f cmd/app: optional interactive shell
Enabling this unconditionally causes the new configuration prompt to be shown when started from a terminal, and is generally less robust than not reading zshrc unless explicitly required.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 19:08:47 +09:00
cat bd4b300ea6 internal/rosa/package/cmake: 4.3.3 to 4.3.4
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 17:56:09 +09:00
cat 6dc8214a1a internal/rosa/package/kernel: 6.12.93 to 6.12.94
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 17:55:49 +09:00
cat cada5a46ad internal/rosa/package/mesa: 26.1.2 to 26.1.3
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 17:55:08 +09:00
cat e747942829 internal/rosa/package/python: pytest 9.1.0 to 9.1.1
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 17:54:38 +09:00
cat 33b855123e internal/rosa/package/spirv: spirv-headers 1.4.350.0 to 1.4.350.1
This unfortunately does not unblock SPIRV-LLVM-Translator.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 04:43:04 +09:00
cat 58ce134718 internal/outcome: attempt nscd path-hiding if present
This avoids creating the mount point on musl setups which accomplishes nothing and can run into permission problems.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 02:42:35 +09:00
cat 2066093343 cmd/app: remove sysfs bind mounts
This should be in common instead.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:57:55 +09:00
cat 07509b3ba2 cmd/app: additional bind types
This adds optional and device mount points.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:51:57 +09:00
cat a7485d587a cmd/app: pass user-specified arguments
An extra argument is added to pad out argv0.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:44:47 +09:00
cat 4892beefc1 cmd/app: optionally override configured command
Useful for multiple applications sharing state.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:31:07 +09:00
cat 7ab54b8c94 internal/rosa: read overridden version string from source
This is more correct than the hardcoded string and is generally more robust against relative paths.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:18:12 +09:00
cat a4fab67811 internal/pkg: optionally exempt implementations from cures counter
This avoids holding up many slots with a long pipeline.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 01:03:28 +09:00
cat ed5cdd38a4 cmd/dist: build hsu separately
This program must be built with cgo disabled, and was missed when migrating build script.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 00:59:47 +09:00
cat f6318304ee hst: fix ephemeral overlay order
This is quite counterintuitive otherwise.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 00:20:31 +09:00
cat cb618093d5 hst: optionally disable file placement
This works around stubborn package managers.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-20 00:16:35 +09:00
cat b0b2471c0c cmd/app: include template name in container metadata
This helps disambiguate active mutable containers.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-19 23:36:31 +09:00
cat 344d2b8207 cmd/app: use ROSA_ prefix
This avoids awkward case-insensitive zsh completion.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-19 23:29:51 +09:00
cat 3938e8bce5 cmd/app: multiple template uppers
Having multiple environments is useful, and this was trivial to implement.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-18 03:51:49 +09:00
cat aee15b4f2a cmd/app: common configuration file
Generally useful for shared storage and environment.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-06-18 02:35:56 +09:00
125 changed files with 4840 additions and 3037 deletions
+1
View File
@@ -0,0 +1 @@
*.az linguist-language=Azalea
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
uses: actions/checkout@v4
- name: Build for release
run: nix build --print-out-paths --print-build-logs .#dist
run: nix build --print-out-paths --print-build-logs ./test#dist
- name: Release
uses: https://gitea.com/actions/release-action@main
+9 -9
View File
@@ -12,7 +12,7 @@ jobs:
uses: actions/checkout@v4
- name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.hakurei
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.hakurei
- name: Upload test output
uses: actions/upload-artifact@v3
@@ -29,7 +29,7 @@ jobs:
uses: actions/checkout@v4
- name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.race
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.race
- name: Upload test output
uses: actions/upload-artifact@v3
@@ -46,7 +46,7 @@ jobs:
uses: actions/checkout@v4
- name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox
- name: Upload test output
uses: actions/upload-artifact@v3
@@ -63,7 +63,7 @@ jobs:
uses: actions/checkout@v4
- name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox-race
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox-race
- name: Upload test output
uses: actions/upload-artifact@v3
@@ -80,7 +80,7 @@ jobs:
uses: actions/checkout@v4
- name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sharefs
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sharefs
- name: Upload test output
uses: actions/upload-artifact@v3
@@ -103,7 +103,7 @@ jobs:
uses: actions/checkout@v4
- name: Run checks
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check ./test
dist:
name: Create distribution
@@ -116,9 +116,9 @@ jobs:
id: build-test
run: >-
export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
nix build --print-out-paths --print-build-logs .#dist &&
mv package.nix.old package.nix &&
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' test/package.nix &&
nix build --print-out-paths --print-build-logs ./test#dist &&
mv test/{package.nix.old,package.nix} &&
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
- name: Upload test build
+1
View File
@@ -1,4 +1,5 @@
# produced by tools and text editors
*.swp
*.qcow2
*.test
*.out
+1 -6
View File
@@ -57,9 +57,4 @@ package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
- [fuse](https://github.com/libfuse/libfuse) to implement the filesystem.
New dependencies will generally not be added. Patches adding new dependencies
are very likely to be rejected.
## NixOS Module (deprecated)
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).
are very likely to be rejected.
+110 -20
View File
@@ -4,10 +4,12 @@ import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"hakurei.app/check"
"hakurei.app/ext"
"hakurei.app/fhs"
"hakurei.app/hst"
)
@@ -31,10 +33,19 @@ func parsePair(s string) (source, target *check.Absolute, err error) {
// parse decodes a high-level configuration stream and returns its
// corresponding [hst.Config].
func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
func parse(
id string,
base *check.Absolute,
r io.Reader,
templateP *string,
) (*hst.Config, error) {
shell := fhs.AbsRoot.Append("bin", "zsh")
home := hst.AbsPrivateTmp.Append("home")
root := hst.FSOverlay{
Target: fhs.AbsRoot,
Lower: []*check.Absolute{base.Append("initial")},
}
c := hst.Config{
ID: id,
Enablements: new(hst.Enablements),
@@ -51,13 +62,7 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
Container: &hst.ContainerConfig{
Env: make(map[string]string),
Filesystem: []hst.FilesystemConfigJSON{
{FilesystemConfig: &hst.FSOverlay{
Target: fhs.AbsRoot,
Lower: []*check.Absolute{
base.Append("template", "initial"),
},
Upper: base.Append("template", "upper"),
}},
{FilesystemConfig: &root},
{FilesystemConfig: &hst.FSBind{
Target: home,
Source: base.Append("state", id),
@@ -70,12 +75,6 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
Write: true,
Perm: 01777,
}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
},
Username: "chronos",
@@ -102,21 +101,28 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
if err := scanOnce(); err != nil {
return nil, err
}
if v, err := strconv.Atoi(s.Text()); err != nil {
if template, identity, ok := strings.Cut(s.Text(), ":"); !ok {
return nil, io.ErrUnexpectedEOF
} else if v, err := strconv.Atoi(identity); err != nil {
return nil, err
} else {
if templateP != nil {
*templateP = template
}
c.Identity = v
root.Upper = base.Append("template", template)
}
if err := scanOnce(); err != nil {
return nil, err
}
c.Container.Args = append(c.Container.Args, s.Text())
c.Container.Args = append(c.Container.Args, s.Text(), "")
var flagGPU, flagSystemBus bool
var flagInteractive, flagGPU, flagSystemBus bool
flags := map[string]*bool{
"gpu": &flagGPU,
"system_bus": &flagSystemBus,
"interactive": &flagInteractive,
"gpu": &flagGPU,
"system_bus": &flagSystemBus,
}
for s.Scan() {
@@ -176,10 +182,43 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
}
switch key {
case "username":
c.Container.Username = value
continue
case "hostname":
c.Container.Hostname = value
continue
case "group":
c.Groups = append(c.Groups, value)
continue
case "sched_policy":
if err := c.SchedPolicy.UnmarshalText([]byte(value)); err != nil {
return nil, err
}
continue
case "sched_priority":
v, err := strconv.Atoi(value)
if err != nil {
return nil, err
}
c.SchedPriority = ext.Int(v)
continue
case "insecure":
switch value {
case "pipewire":
*c.Enablements |= hst.EPipeWire
c.DirectPipeWire = true
continue
default:
return nil, fmt.Errorf("invalid insecure flag %q", value)
}
case "env":
if key, value, ok = strings.Cut(value, "="); !ok {
return nil, fmt.Errorf("invalid environment %q", key)
@@ -200,6 +239,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
)
continue
case "ro+":
source, target, err := parsePair(value)
if err != nil {
return nil, err
}
c.Container.Filesystem = append(c.Container.Filesystem,
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
Target: target,
Source: source,
Optional: true,
}},
)
continue
case "rw":
source, target, err := parsePair(value)
if err != nil {
@@ -214,6 +267,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
)
continue
case "dev":
source, target, err := parsePair(value)
if err != nil {
return nil, err
}
c.Container.Filesystem = append(c.Container.Filesystem,
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
Target: target,
Source: source,
Device: true,
}},
)
continue
case "own":
c.SessionBus.Own = append(c.SessionBus.Own, value)
continue
@@ -236,6 +303,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
return nil, err
}
if flagInteractive {
c.Container.Args[1] += "i"
}
if flagGPU {
c.Container.Filesystem = append(c.Container.Filesystem, []hst.FilesystemConfigJSON{
{FilesystemConfig: &hst.FSBind{
@@ -250,7 +321,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
c.SystemBus = nil
}
if c.Container.Flags&hst.FShareTmpdir == 0 {
if c.Container.Flags&hst.FShareTmpdir == 0 &&
(c.Enablements.Unwrap()&hst.EX11 == 0 ||
c.Container.Flags&(hst.FHostNet|hst.FHostAbstract) ==
hst.FHostNet|hst.FHostAbstract) {
c.Container.Filesystem = append(c.Container.Filesystem,
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSEphemeral{
Target: fhs.AbsTmp,
@@ -262,3 +336,19 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
return &c, nil
}
// list prints names of non-hidden entries in pathname.
func list(pathname *check.Absolute, dir bool) error {
dents, err := os.ReadDir(pathname.String())
if err != nil {
return err
}
for _, dent := range dents {
name := dent.Name()
if (dent.IsDir() != dir) || (len(name) > 0 && name[0] == '.') {
continue
}
fmt.Println(dent.Name())
}
return nil
}
+5 -9
View File
@@ -20,7 +20,7 @@ func TestParse(t *testing.T) {
want *hst.Config
err error
}{
{"com.discordapp.Discord", `8
{"com.discordapp.Discord", `nonfree:8
exec Discord --ozone-platform-hint=wayland
gpu
@@ -74,9 +74,9 @@ talk com.canonical.Unity
{FilesystemConfig: &hst.FSOverlay{
Target: fhs.AbsRoot,
Lower: []*check.Absolute{
base.Append("template", "initial"),
base.Append("initial"),
},
Upper: base.Append("template", "upper"),
Upper: base.Append("template", "nonfree"),
}},
{FilesystemConfig: &hst.FSBind{
Target: hst.AbsPrivateTmp.Append("home"),
@@ -91,12 +91,6 @@ talk com.canonical.Unity
Perm: 01777,
}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
{FilesystemConfig: &hst.FSBind{
Source: check.MustAbs("/sdcard"),
Write: true,
@@ -120,6 +114,7 @@ talk com.canonical.Unity
Args: []string{
"zsh", "-c",
"exec Discord --ozone-platform-hint=wayland",
"",
},
Flags: hst.FCoverRun | hst.FUserns | hst.FHostNet | hst.FMapRealUID |
@@ -135,6 +130,7 @@ talk com.canonical.Unity
tc.name,
base,
strings.NewReader(tc.data),
nil,
)
if !reflect.DeepEqual(err, tc.err) {
+112
View File
@@ -0,0 +1,112 @@
package main
import (
"errors"
"log"
"os"
"strconv"
"strings"
"hakurei.app/check"
"hakurei.app/fhs"
"hakurei.app/hst"
"hakurei.app/internal/env"
"hakurei.app/internal/lockedfile"
"hakurei.app/internal/outcome"
)
// MutationConflictError describes an active mutable instance.
type MutationConflictError string
func (e MutationConflictError) Error() string {
return "mutable instance active at " + string(e)
}
// informTemplate guards intention of a template or its derivatives.
func informTemplate(base *check.Absolute, name string, mutable bool) (func() error, error) {
mu := lockedfile.MutexAt(base.Append("lock", name).String())
if unlock, err := mu.Lock(); err != nil {
return nil, err
} else {
defer unlock()
}
marker := base.Append("lock", "."+name)
if p, err := os.ReadFile(marker.String()); err == nil {
if _, err = os.Stat(fhs.AbsProc.Append(string(p)).String()); err == nil {
return nil, MutationConflictError(p)
} else if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
log.Printf("removing stale marker by %s", string(p))
if err = os.Remove(marker.String()); err != nil {
return nil, err
}
} else if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
if !mutable {
return nil, nil
}
var active []hst.ID
var sc hst.Paths
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
entries, copyError := outcome.NewStore(&sc).All()
var s hst.State
for eh := range entries {
s = hst.State{}
if _, err := eh.Load(&s); err != nil {
return nil, err
}
if s.Validate(0) != nil || len(s.Container.Filesystem) < 1 {
continue
}
root, ok := s.Container.Filesystem[0].FilesystemConfig.(*hst.FSOverlay)
if !ok || root == nil {
continue
}
if !root.Target.Is(fhs.AbsRoot) ||
len(root.Lower) != 1 ||
!root.Lower[0].Is(base.Append("initial")) ||
!root.Upper.Is(base.Append("template", name)) ||
root.Work != nil {
continue
}
active = append(active, s.ID)
}
if err := copyError(); err != nil {
return nil, err
}
if len(active) != 0 {
var buf strings.Builder
buf.WriteString("derivative instances still active:")
for _, id := range active {
buf.WriteString("\n\t")
buf.WriteString(id.String())
}
return nil, errors.New(buf.String())
}
return func() error { return os.RemoveAll(marker.String()) }, os.WriteFile(
marker.String(),
[]byte(strconv.Itoa(os.Getpid())),
0400,
)
}
// acquireTemplate obtains exclusivity of a template.
func acquireTemplate(base *check.Absolute, name string) (remove func() error, err error) {
return informTemplate(base, name, true)
}
// enterTemplate checks against exclusivity of a template.
func enterTemplate(base *check.Absolute, name string) error {
_, err := informTemplate(base, name, false)
return err
}
+92 -36
View File
@@ -7,6 +7,7 @@ package main
import (
"context"
"errors"
"io"
"log"
"os"
"os/exec"
@@ -31,10 +32,11 @@ func main() {
defer stop()
var (
flagVerbose bool
flagBase string
flagVerbose bool
flagBase string
flagInsecure bool
base, template, initial, upper, work *check.Absolute
base, template, initial *check.Absolute
)
c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) {
msg.SwapVerbose(flagVerbose)
@@ -49,9 +51,7 @@ func main() {
}
template = base.Append("template")
initial = template.Append("initial")
upper = template.Append("upper")
work = template.Append("work")
initial = base.Append("initial")
return
}).Flag(
&flagVerbose,
@@ -59,8 +59,12 @@ func main() {
"Increase log verbosity",
).Flag(
&flagBase,
"d", command.StringFlag("$HAKUREI_APP_PATH"),
"d", command.StringFlag("$ROSA_APP_PATH"),
"Configuration and state directory",
).Flag(
&flagInsecure,
"insecure", command.BoolFlag(false),
"Allow use of insecure compatibility options",
)
{
@@ -70,17 +74,21 @@ func main() {
)
c.NewCommand(
"enter", "Enter mutable state template",
func([]string) error {
func(args []string) error {
if len(args) != 1 {
return list(template, true)
}
config := hst.Config{
ID: "app.hakurei.mutable",
ID: "app.hakurei.mutable." + args[0],
Container: &hst.ContainerConfig{
Hostname: "mutable",
Hostname: args[0] + "-mutable",
Filesystem: []hst.FilesystemConfigJSON{
{FilesystemConfig: &hst.FSOverlay{
Target: fhs.AbsRoot,
Lower: []*check.Absolute{initial},
Upper: upper,
Work: work,
Upper: template.Append(args[0]),
Work: base.Append("work", args[0]),
}},
{FilesystemConfig: &hst.FSEphemeral{
Target: fhs.AbsTmp,
@@ -89,7 +97,8 @@ func main() {
}},
},
Username: "chronos",
Flags: hst.FMultiarch |
Flags: hst.FNoPlace |
hst.FMultiarch |
hst.FDevel |
hst.FUserns |
hst.FHostNet |
@@ -113,7 +122,12 @@ func main() {
config.Container.Home = a
}
return run(ctx, msg, &config)
remove, err := acquireTemplate(base, args[0])
if err != nil {
return err
}
err = run(ctx, msg, false, &config)
return errors.Join(err, remove())
},
).Flag(
&flagShell,
@@ -126,29 +140,65 @@ func main() {
)
}
c.NewCommand(
"run", "Start the named application",
func(args []string) error {
if len(args) != 1 {
return errors.New("run requires 1 argument")
}
{
var (
flagCommand string
)
c.NewCommand(
"run", "Start the named application",
func(args []string) error {
if len(args) < 1 {
return list(base.Append("app"), false)
}
var config *hst.Config
f, err := os.Open(base.Append("app", args[0]).String())
if err != nil {
return err
}
config, err = parse(args[0], base, f)
if closeErr := f.Close(); err == nil {
err = closeErr
}
if err != nil {
return err
}
var config *hst.Config
var r io.Reader
f, err := os.Open(base.Append("app", args[0]).String())
if err != nil {
return err
}
r = f
return run(ctx, msg, config)
},
)
var common *os.File
if common, err = os.Open(base.Append("common").String()); err != nil {
if !errors.Is(err, os.ErrNotExist) {
_ = f.Close()
return err
}
} else {
r = io.MultiReader(f, common)
}
var name string
config, err = parse(args[0], base, r, &name)
if closeErr := f.Close(); err == nil {
err = closeErr
}
if common != nil {
if closeErr := common.Close(); err == nil {
err = closeErr
}
}
if err != nil {
return err
}
if flagCommand != "" {
config.Container.Args[2] = flagCommand
}
if err = enterTemplate(base, name); err != nil {
return err
}
return run(ctx, msg, flagInsecure, config, args[1:]...)
},
).
Flag(
&flagCommand,
"command", command.StringFlag(""),
"Override configured command",
)
}
c.MustParse(os.Args[1:], func(err error) {
if e, ok := errors.AsType[*exec.ExitError](err); ok && e != nil {
@@ -156,7 +206,13 @@ func main() {
}
if w, ok := err.(interface{ Unwrap() []error }); !ok {
log.Fatal(err)
var m string
m, ok = message.GetMessage(err)
if !ok {
log.Fatal(err)
return
}
log.Fatal(m)
} else {
errs := w.Unwrap()
for i, e := range errs {
+11 -1
View File
@@ -12,7 +12,13 @@ import (
)
// run starts a container via cmd/hakurei and returns after it terminates.
func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
func run(
ctx context.Context,
msg message.Msg,
insecure bool,
config *hst.Config,
args ...string,
) error {
c, cancel := context.WithCancel(ctx)
defer cancel()
@@ -24,7 +30,11 @@ func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
if msg.IsVerbose() {
cmd.Args = append(cmd.Args, "-v")
}
if insecure {
cmd.Args = append(cmd.Args, "--insecure")
}
cmd.Args = append(cmd.Args, "run", "3")
cmd.Args = append(cmd.Args, args...)
r, w, err := os.Pipe()
if err != nil {
+1 -1
View File
@@ -1 +1 @@
v0.4.4
v0.4.5
+24 -9
View File
@@ -35,8 +35,11 @@ func getenv(key, fallback string) string {
// mustRun runs a command with the current process's environment and panics
// on error or non-zero exit code.
func mustRun(ctx context.Context, name string, arg ...string) {
func mustRun(ctx context.Context, env []string, name string, arg ...string) {
cmd := exec.CommandContext(ctx, name, arg...)
if env != nil {
cmd.Env = append(cmd.Environ(), env...)
}
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
if err := cmd.Run(); err != nil {
panic(err)
@@ -49,6 +52,7 @@ var comp []byte
func main() {
log.SetFlags(0)
log.SetPrefix("")
log.SetOutput(os.Stdout)
verbose := os.Getenv("VERBOSE") != ""
runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
@@ -91,26 +95,37 @@ func main() {
verboseFlag = "-buildvcs=false"
}
log.Printf("Building hakurei for %s/%s.", runtime.GOOS, runtime.GOARCH)
mustRun(ctx, "go", "generate", "./...")
log.Printf("Building hakurei %s for %s/%s.", version, runtime.GOOS, runtime.GOARCH)
mustRun(ctx, nil, "go", "generate", "./...")
mustRun(
ctx, "go", "build",
ctx, nil, "go", "build",
"-trimpath",
verboseFlag, "-o", s,
"-ldflags=-s -w "+
"-buildid= -linkmode external -extldflags=-static "+
"-X hakurei.app/internal/info.buildVersion="+version+" "+
"-X hakurei.app/internal/info.hakureiPath="+prefix+"/bin/hakurei "+
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu "+
"-X main.hakureiPath="+prefix+"/bin/hakurei",
"./...",
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu",
"./cmd/hakurei",
"./cmd/sharefs",
)
log.Println()
log.Printf("Building cmd/hsu for %s/%s.", runtime.GOOS, runtime.GOARCH)
mustRun(
ctx, []string{"CGO_ENABLED=0"}, "go", "build",
"-trimpath",
verboseFlag, "-o", s,
"-ldflags=-s -w "+
"-buildid= "+
"-X main.hakureiPath="+prefix+"/bin/hakurei",
"./cmd/hsu",
)
log.Println()
if runTests {
log.Println("##### Testing Hakurei.")
mustRun(
ctx, "go", "test",
ctx, nil, "go", "test",
"-ldflags=-buildid= -linkmode external -extldflags=-static",
"./...",
)
+3 -1
View File
@@ -7,6 +7,7 @@ package main
import (
"context"
"crypto/rand"
"io"
"log"
"os"
"os/signal"
@@ -51,13 +52,14 @@ func init() {
func fatal(v ...any) {
log.Println(v...)
log.Println("unable to continue, please reboot and resolve the problem manually")
log.SetOutput(io.Discard)
select {}
}
// must calls fatal with err if it is non-nil.
func must(err error) {
if err != nil {
log.Println(err)
fatal(err)
select {}
}
}
+3 -2
View File
@@ -26,8 +26,9 @@ var _ report.RepresentableError = ModprobeError{}
func (ModprobeError) Representable() {}
func (e ModprobeError) Error() string {
return fmt.Sprintf(
"modprobe exit status %d: %s",
e.ExitCode, strings.TrimSpace(e.Stderr),
"%s (exit status %d)",
strings.TrimPrefix(strings.TrimSpace(e.Stderr), "modprobe: "),
e.ExitCode,
)
}
+5 -2
View File
@@ -64,7 +64,7 @@ func TestPrintShowInstance(t *testing.T) {
Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pipewire
Groups: video, dialout, plugdev
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
Home: /data/data/org.chromium.Chromium
Hostname: localhost
Path: /run/current-system/sw/bin/chromium
@@ -161,7 +161,7 @@ App
Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pipewire
Groups: video, dialout, plugdev
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
Home: /data/data/org.chromium.Chromium
Hostname: localhost
Path: /run/current-system/sw/bin/chromium
@@ -354,6 +354,7 @@ App
"tty": true,
"multiarch": true,
"map_real_uid": true,
"noplace": true,
"device": true,
"cover_run": true,
"share_runtime": true,
@@ -506,6 +507,7 @@ App
"tty": true,
"multiarch": true,
"map_real_uid": true,
"noplace": true,
"device": true,
"cover_run": true,
"share_runtime": true,
@@ -705,6 +707,7 @@ func TestPrintPs(t *testing.T) {
"tty": true,
"multiarch": true,
"map_real_uid": true,
"noplace": true,
"device": true,
"cover_run": true,
"share_runtime": true,
+11 -9
View File
@@ -21,13 +21,15 @@ type cache struct {
// Should generally not be used directly.
c *pkg.Cache
cures, jobs int
attr pkg.CacheAttr
// Primarily to work around missing landlock LSM.
hostAbstract bool
// Set SCHED_IDLE.
idle bool
// Unset [pkg.CSuppressInit].
verboseInit bool
// Unset [pkg.CExternShallow].
deep bool
// Loaded artifact of [rosa.QEMU].
qemu pkg.Artifact
@@ -47,15 +49,17 @@ func (cache *cache) open() (err error) {
return
}
var flags int
if cache.idle {
flags |= pkg.CSchedIdle
cache.attr.Flags |= pkg.CSchedIdle
}
if cache.hostAbstract {
flags |= pkg.CHostAbstract
cache.attr.Flags |= pkg.CHostAbstract
}
if !cache.verboseInit {
flags |= pkg.CSuppressInit
cache.attr.Flags |= pkg.CSuppressInit
}
if !cache.deep {
cache.attr.Flags |= pkg.CExternShallow
}
done := make(chan struct{})
@@ -77,10 +81,8 @@ func (cache *cache) open() (err error) {
cache.c, err = pkg.Open(
cache.ctx,
cache.msg,
flags,
cache.cures,
cache.jobs,
base,
&cache.attr,
)
if err != nil {
return
@@ -95,7 +97,7 @@ func (cache *cache) open() (err error) {
return
}
var r rosa.Remote
if r, err = rosa.NewRemote(cache.mirror, pub, http.DefaultClient); err != nil {
if r, err = rosa.NewRemote(http.DefaultClient, cache.mirror, pub); err != nil {
cache.c.Close()
return err
}
+1 -1
View File
@@ -28,8 +28,8 @@ func TestNoReply(t *testing.T) {
c, err := pkg.Open(
t.Context(),
message.New(log.New(os.Stderr, "cir: ", 0)),
0, 0, 0,
check.MustAbs(t.TempDir()),
nil,
)
if err != nil {
t.Fatalf("Open: error = %v", err)
+4 -1
View File
@@ -21,7 +21,10 @@ func commandInfo(
r *rosa.Report,
) (err error) {
if len(args) == 0 {
return errors.New("info requires at least 1 argument")
for _, h := range rosa.Native().CollectAll() {
fmt.Println(h)
}
return nil
}
// recovered by HandleAccess
+138 -4
View File
@@ -27,6 +27,7 @@ import (
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"syscall"
@@ -202,11 +203,11 @@ func main() {
"v", command.BoolFlag(false),
"Do not suppress verbose output from init",
).Flag(
&cm.cures,
&cm.attr.Cures,
"cures", command.IntFlag(0),
"Maximum number of dependencies to cure at any given time",
).Flag(
&cm.jobs,
&cm.attr.Jobs,
"jobs", command.IntFlag(0),
"Preferred number of jobs to run, when applicable",
).Flag(
@@ -217,6 +218,11 @@ func main() {
&cm.mirror,
"r", command.StringFlag("$MBF_REMOTE"),
"URL of mirror service",
).Flag(
&cm.deep,
"deep", command.BoolFlag(false),
"Cure all inputs even when the required artifact is available "+
"via the mirror service",
).Flag(
&cm.idle,
"sched-idle", command.BoolFlag(false),
@@ -539,7 +545,9 @@ func main() {
if base, err := os.OpenRoot(cm.base); err != nil {
return err
} else {
h = rosa.NewMirror(msg, base.FS(), key)
var mux http.ServeMux
rosa.NewMirror(msg, base.FS(), key).Register(&mux)
h = &mux
}
server := http.Server{Addr: args[0], Handler: h}
@@ -561,6 +569,47 @@ func main() {
},
)
c.NewCommand(
"snapshot",
"Populate an empty directory with a static mirror snapshot",
func(args []string) error {
if len(args) != 1 {
return errors.New("snapshot requires 1 argument")
}
var key ed25519.PrivateKey
if p, err := os.ReadFile(filepath.Join(cm.base, "ed25519")); err != nil {
return err
} else if len(p) != ed25519.PrivateKeySize {
return errors.New("invalid private key")
} else {
key = p
}
var m rosa.Mirror
if base, err := os.OpenRoot(cm.base); err != nil {
return err
} else {
m = rosa.NewMirror(msg, base.FS(), key)
}
retry:
root, err := os.OpenRoot(args[0])
if err != nil {
if os.IsNotExist(err) {
if err = os.MkdirAll(args[0], 0755); err != nil {
return err
}
goto retry
}
return err
}
go func() { <-ctx.Done(); _ = root.Close() }()
return m.Populate(root)
},
)
{
var (
flagGentoo string
@@ -648,6 +697,7 @@ func main() {
flagNoReply bool
flagFaults bool
flagPop bool
flagRebuild bool
flagBoot bool
flagStd bool
@@ -676,7 +726,11 @@ func main() {
default:
var pathname *check.Absolute
err := cm.Do(func(cache *pkg.Cache) (err error) {
pathname, _, err = cache.Cure(a)
if flagRebuild {
pathname, _, err = cache.CureNew(a)
} else {
pathname, _, err = cache.Cure(a)
}
return
})
if err != nil {
@@ -837,9 +891,89 @@ func main() {
&flagPop,
"pop", command.BoolFlag(false),
"Display and destroy the most recent fault entry",
).Flag(
&flagRebuild,
"rebuild", command.BoolFlag(false),
"Always enter the artifact implementation",
)
}
c.NewCommand(
"validate",
"Repeatedly cure named artifact to validate determinism",
func(args []string) error {
stage := rosa.Std
if len(args) == 3 {
switch args[0] {
case "boot":
stage -= 2
case "std":
stage -= 1
default:
return fmt.Errorf("invalid stage %q", args[0])
}
args = args[1:]
}
if len(args) != 2 {
return errors.New("validate requires 2 arguments")
}
n, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid passes %q", args[0])
}
if n < 2 {
return errors.New("validate must rebuild at least twice")
}
_, a := rosa.Native().New(stage).Load(rosa.ArtifactH(unique.Make(args[1])))
if a == nil {
return fmt.Errorf("unknown artifact %q", args[1])
}
if !a.IsExclusive() && cm.attr.Jobs < 1 {
cm.attr.Jobs = runtime.NumCPU()/n + 1
}
res := make([]unique.Handle[pkg.Checksum], n)
if err = cm.Do(func(cache *pkg.Cache) error {
errs := make([]error, n)
var wg sync.WaitGroup
for i := range n {
wg.Go(func() {
_, res[i], errs[i] = cache.CureNew(a)
})
}
wg.Wait()
return errors.Join(errs...)
}); err != nil {
return err
}
for i := range n - 1 {
if res[i] == res[i+1] {
continue
}
var buf strings.Builder
buf.WriteString("nondeterminism:")
for _, o := range res {
buf.WriteString("\n\t")
buf.WriteString(filepath.Join(
cm.base,
"checksum",
pkg.Encode(o.Value()),
))
}
return errors.New(buf.String())
}
return nil
},
)
cleanC := c.New("clean", "Remove unused entries from the cache")
cleanC.NewCommand(
"fault",
+10
View File
@@ -65,6 +65,8 @@ const (
// Some programs fail to connect to dbus session running as a different uid,
// this option works around it by mapping priv-side caller uid in container.
FMapRealUID
// FNoPlace disables placement of /etc/passwd and /etc/group.
FNoPlace
// FDevice mount /dev/ from the init mount namespace as is in the container
// mount namespace.
@@ -101,6 +103,8 @@ func (flags Flags) String() string {
return "tty"
case FMapRealUID:
return "mapuid"
case FNoPlace:
return "noplace"
case FDevice:
return "device"
case FCoverRun:
@@ -197,6 +201,8 @@ type containerConfigJSON = struct {
// Corresponds to [FMapRealUID].
MapRealUID bool `json:"map_real_uid"`
// Corresponds to [FNoPlace].
NoPlace bool `json:"noplace,omitempty"`
// Corresponds to [FDevice].
Device bool `json:"device,omitempty"`
@@ -224,6 +230,7 @@ func (c *ContainerConfig) MarshalJSON() ([]byte, error) {
Tty: c.Flags&FTty != 0,
Multiarch: c.Flags&FMultiarch != 0,
MapRealUID: c.Flags&FMapRealUID != 0,
NoPlace: c.Flags&FNoPlace != 0,
Device: c.Flags&FDevice != 0,
CoverRun: c.Flags&FCoverRun != 0,
ShareRuntime: c.Flags&FShareRuntime != 0,
@@ -266,6 +273,9 @@ func (c *ContainerConfig) UnmarshalJSON(data []byte) error {
if v.MapRealUID {
c.Flags |= FMapRealUID
}
if v.NoPlace {
c.Flags |= FNoPlace
}
if v.Device {
c.Flags |= FDevice
}
+3 -3
View File
@@ -21,8 +21,8 @@ func TestFlagsString(t *testing.T) {
}{
{"none", 0, "none"},
{"none high", hst.FAll + 1, "none"},
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -53,7 +53,7 @@ func TestContainerConfig(t *testing.T) {
{"hostnet hostabstract mapuid", &hst.ContainerConfig{Flags: hst.FHostNet | hst.FHostAbstract | hst.FMapRealUID},
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"host_net":true,"host_abstract":true,"map_real_uid":true}`},
{"all", &hst.ContainerConfig{Flags: hst.FAll},
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"noplace":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
}
for _, tc := range testCases {
+2 -2
View File
@@ -82,9 +82,9 @@ func (o *FSOverlay) Apply(z *ApplyState) {
z.Overlay(o.Target, o.Upper, o.Work, o.Lower...)
} else {
z.OverlayEphemeral(o.Target, slices.Concat(
[]*check.Absolute{o.Upper},
o.Lower,
[]*check.Absolute{o.Upper})...,
)
)...)
}
} else {
z.OverlayReadonly(o.Target, o.Lower...)
+1 -1
View File
@@ -70,7 +70,7 @@ func TestFSOverlay(t *testing.T) {
Upper: m("/tmp/upper"),
}, true, container.Ops{&container.MountOverlayOp{
Target: m("/"),
Lower: ms("/tmp/.src0", "/tmp/.src1", "/tmp/upper"),
Lower: ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
Upper: fhs.AbsRoot,
}}, m("/"), ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
"e*/:/tmp/upper:/tmp/.src0:/tmp/.src1"},
+1
View File
@@ -244,6 +244,7 @@ func TestTemplate(t *testing.T) {
"tty": true,
"multiarch": true,
"map_real_uid": true,
"noplace": true,
"device": true,
"cover_run": true,
"share_runtime": true,
+24 -4
View File
@@ -1,21 +1,29 @@
// Package env provides the [Paths] struct for efficiently building paths from the environment.
// Package env provides the [Paths] struct for efficiently building paths from
// the environment.
package env
import (
"errors"
"io/fs"
"log"
"os"
"strconv"
"hakurei.app/check"
"hakurei.app/fhs"
"hakurei.app/hst"
)
const VarRunNscd = fhs.Var + "run/nscd"
// Paths holds paths copied from the environment and is used to create [hst.Paths].
type Paths struct {
// TempDir is returned by [os.TempDir].
TempDir *check.Absolute
// RuntimePath is copied from $XDG_RUNTIME_DIR.
RuntimePath *check.Absolute
// Whether [VarRunNscd] is a directory.
HasNscd bool
}
// Copy expands [Paths] into [hst.Paths].
@@ -37,14 +45,17 @@ func (env *Paths) Copy(v *hst.Paths, userid int) {
}
// CopyPaths returns a populated [Paths].
func CopyPaths() *Paths { return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv) }
func CopyPaths() *Paths {
return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv, os.Stat)
}
// CopyPathsFunc returns a populated [Paths],
// using the provided [log.Fatalf], [os.TempDir], [os.Getenv] functions.
// CopyPathsFunc returns a populated [Paths], using the provided [log.Fatalf],
// [os.TempDir], [os.Getenv] functions.
func CopyPathsFunc(
fatalf func(format string, v ...any),
tempdir func() string,
getenv func(key string) string,
stat func(name string) (fs.FileInfo, error),
) *Paths {
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
@@ -61,5 +72,14 @@ func CopyPathsFunc(
env.RuntimePath = a
}
if fi, err := stat(VarRunNscd); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
fatalf("%v", err)
panic("unreachable")
}
} else {
env.HasNscd = fi.IsDir()
}
return &env
}
+4 -1
View File
@@ -2,6 +2,7 @@ package env_test
import (
"fmt"
"io/fs"
"reflect"
"testing"
@@ -104,7 +105,9 @@ func TestCopyPaths(t *testing.T) {
t.Fatalf("fatalf: %q, want %q", got, tc.fatal)
}
panic(stub.PanicExit)
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] })
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] }, func(name string) (fs.FileInfo, error) {
return nil, fs.ErrNotExist
})
if tc.fatal != "" {
t.Fatalf("copyPaths: expected fatal %q", tc.fatal)
+2
View File
@@ -23,6 +23,7 @@ import (
"hakurei.app/container/seccomp"
"hakurei.app/container/std"
"hakurei.app/hst"
"hakurei.app/internal/env"
"hakurei.app/internal/stub"
"hakurei.app/internal/system"
"hakurei.app/message"
@@ -174,6 +175,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
call("cmdOutput", stub.ExpectArgs{container.Nonexistent, os.Stderr, []string{}, "/"}, []byte("0"), nil),
call("tempdir", stub.ExpectArgs{}, container.Nonexistent+"/tmp", nil),
call("lookupEnv", stub.ExpectArgs{"XDG_RUNTIME_DIR"}, wantRuntimePath, nil),
call("stat", stub.ExpectArgs{env.VarRunNscd}, stubFileInfoIsDir(true), nil),
call("getuid", stub.ExpectArgs{}, 1000, nil),
call("getgid", stub.ExpectArgs{}, 100, nil),
+1 -1
View File
@@ -110,7 +110,7 @@ func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *h
Paths: env.CopyPathsFunc(k.fatalf, k.tempdir, func(key string) string {
v, _ := k.lookupEnv(key)
return v
}),
}, k.stat),
Container: config.Container,
}
+2 -8
View File
@@ -143,10 +143,6 @@ func TestOutcomeRun(t *testing.T) {
// spTmpdirOp
Bind(m("/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, std.BindWritable).
// spAccountOp
Place(m("/etc/passwd"), []byte("chronos:x:1971:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
// spWaylandOp
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0).
@@ -453,7 +449,7 @@ func TestOutcomeRun(t *testing.T) {
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FShareRuntime | hst.FShareTmpdir,
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FNoPlace | hst.FShareRuntime | hst.FShareTmpdir,
},
SystemBus: &hst.BusConfig{
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
@@ -548,8 +544,6 @@ func TestOutcomeRun(t *testing.T) {
Tmpfs(m("/run/user/"), xdgRuntimeDirSize, 0755).
Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), std.BindWritable).
Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), std.BindWritable).
Place(m("/etc/passwd"), []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
Bind(m("/run/user/1971/wayland-0"), m("/run/user/1971/wayland-0"), 0).
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), m("/run/user/1971/pipewire-0"), 0).
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), m("/run/user/1971/bus"), 0).
@@ -716,7 +710,7 @@ func (k *stubNixOS) lookupEnv(key string) (string, bool) {
func (k *stubNixOS) stat(name string) (fs.FileInfo, error) {
switch name {
case "/var/run/nscd":
return nil, nil
return stubFileInfoIsDir(true), nil
case "/run/user/1971/pulse":
return nil, nil
case "/run/user/1971/pulse/native":
-4
View File
@@ -78,10 +78,6 @@ func TestShimEntrypoint(t *testing.T) {
// spTmpdirOp
Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, std.BindWritable).
// spAccountOp
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
// spWaylandOp
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0).
+13 -10
View File
@@ -6,6 +6,7 @@ import (
"syscall"
"hakurei.app/fhs"
"hakurei.app/hst"
"hakurei.app/internal/validate"
)
@@ -41,16 +42,18 @@ func (s spAccountOp) toContainer(state *outcomeStateParams) error {
state.env["USER"] = username
state.env["SHELL"] = state.Container.Shell.String()
state.params.
Place(fhs.AbsEtc.Append("passwd"),
[]byte(username+":x:"+
state.mapuid.String()+":"+
state.mapgid.String()+
":Hakurei:"+
state.Container.Home.String()+":"+
state.Container.Shell.String()+"\n")).
Place(fhs.AbsEtc.Append("group"),
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
if state.Container.Flags&hst.FNoPlace == 0 {
state.params.
Place(fhs.AbsEtc.Append("passwd"),
[]byte(username+":x:"+
state.mapuid.String()+":"+
state.mapgid.String()+
":Hakurei:"+
state.Container.Home.String()+":"+
state.Container.Shell.String()+"\n")).
Place(fhs.AbsEtc.Append("group"),
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
}
return nil
}
+2 -3
View File
@@ -38,6 +38,7 @@ func TestSpAccountOp(t *testing.T) {
{"success fallback username", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
c := hst.Template()
c.Container.Username = ""
c.Container.Flags = hst.FMapRealUID
return c
}, nil, []stub.Call{
// this op performs basic validation and does not make calls during toSystem
@@ -60,9 +61,7 @@ func TestSpAccountOp(t *testing.T) {
// this op configures the container state and does not make calls during toContainer
}, &container.Params{
Dir: config.Container.Home,
Ops: new(container.Ops).
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
Place(m("/etc/group"), []byte("hakurei:x:100:\n")),
Ops: new(container.Ops),
}, paramsWantEnv(config, map[string]string{
"HOME": config.Container.Home.String(),
"USER": config.Container.Username,
+14 -9
View File
@@ -18,13 +18,12 @@ import (
"hakurei.app/hst"
"hakurei.app/internal/acl"
"hakurei.app/internal/dbus"
"hakurei.app/internal/env"
"hakurei.app/internal/system"
"hakurei.app/internal/validate"
"hakurei.app/message"
)
const varRunNscd = fhs.Var + "run/nscd"
func init() { gob.Register(new(spParamsOp)) }
// spParamsOp initialises unordered fields of [container.Params] and the
@@ -136,17 +135,23 @@ type spFilesystemOp struct {
}
func (s *spFilesystemOp) toSystem(state *outcomeStateSys) error {
/* retrieve paths and hide them if they're made available in the sandbox;
this feature tries to improve user experience of permissive defaults, and
to warn about issues in custom configuration; it is NOT a security feature
and should not be treated as such, ALWAYS be careful with what you bind */
// retrieve paths and hide them if they're made available in the sandbox
//
// this feature tries to improve user experience of permissive defaults, and
// to warn about issues in custom configuration; it is NOT a security feature
// and should not be treated as such, ALWAYS be careful with what you bind
hidePaths := []string{
state.sc.RuntimePath.String(),
state.sc.SharePath.String(),
}
// this causes emulated passwd database to be bypassed on some /etc/ setups
varRunNscd,
if state.Paths == nil || state.HasNscd {
hidePaths = append(hidePaths,
// this causes emulated passwd database to be bypassed on some /etc/
// setups, made optional to avoid needlessly creating it on
// non-glibc systems when invoking permissive defaults
env.VarRunNscd,
)
}
// dbus.Address does not go through syscallDispatcher
+8 -2
View File
@@ -278,6 +278,8 @@ type archiveArtifact struct {
f Artifact
}
var _ CuresExempt = archiveArtifact{}
// NewArchive returns a new [Artifact] backed by the supplied [Artifact]. The
// source [Artifact] must be a [FileArtifact] and produce a stream compatible
// with [Reader].
@@ -301,8 +303,8 @@ func init() {
})
}
// Dependencies returns a slice containing the backing file.
func (a archiveArtifact) Dependencies() []Artifact {
// Inputs returns a slice containing the backing file.
func (a archiveArtifact) Inputs() []Artifact {
return []Artifact{a.f}
}
@@ -403,3 +405,7 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
}
return
}
// CuresExempt exempts the cheap [KindArchive] implementation often found at
// the end of a [FileArtifact] pipeline.
func (archiveArtifact) CuresExempt() {}
+1 -1
View File
@@ -186,7 +186,7 @@ func TestArchiveArtifact(t *testing.T) {
cureMany(t, c, []cureStep{
{"sample", pkg.NewArchive(
pkg.NewFile("", buf.Bytes()),
), ignorePathname, expectsFS(want), nil},
), ignorePathname, expectsFS(want), pkg.WNew, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
+1 -1
View File
@@ -238,7 +238,7 @@ func TestClean(t *testing.T) {
base := makeBase(t)
msg := message.New(log.New(os.Stderr, "clean: ", 0))
msg.SwapVerbose(testing.Verbose())
c, err := pkg.Open(t.Context(), msg, 0, 0, 0, base)
c, err := pkg.Open(t.Context(), msg, base, nil)
if err != nil {
t.Fatal(err)
}
+7 -2
View File
@@ -25,6 +25,7 @@ type decompressArtifact struct {
}
var _ FileArtifact = new(decompressArtifact)
var _ CuresExempt = new(decompressArtifact)
// decompressArtifactNamed embeds decompressArtifact for a [fmt.Stringer] stream.
type decompressArtifactNamed struct {
@@ -65,8 +66,8 @@ func init() {
})
}
// Dependencies returns a slice containing the backing file.
func (a *decompressArtifact) Dependencies() []Artifact {
// Inputs returns a slice containing the backing file.
func (a *decompressArtifact) Inputs() []Artifact {
return []Artifact{a.f}
}
@@ -117,3 +118,7 @@ func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
return nil, os.ErrInvalid
}
}
// CuresExempt exempts the cheap [KindDecompress] implementation often part of
// a [FileArtifact] pipeline.
func (*decompressArtifact) CuresExempt() {}
+2 -2
View File
@@ -43,7 +43,7 @@ func TestDecompress(t *testing.T) {
&client,
"file:///testdata",
pkg.Checksum{0xfd},
), pkg.Gzip), nil, nil, &pkg.ChecksumMismatchError{
), pkg.Gzip), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
Got: testdataChecksum,
Want: pkg.Checksum{0xfd},
}},
@@ -52,7 +52,7 @@ func TestDecompress(t *testing.T) {
&client,
"file:///testdata",
testdataChecksum,
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), nil},
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), pkg.WNew, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
+22 -12
View File
@@ -30,10 +30,16 @@ import (
// AbsWork is the container pathname [TContext.GetWorkDir] is mounted on.
var AbsWork = fhs.AbsRoot.Append("work/")
// EnvJobs is the name of the environment variable holding a decimal
// representation of the preferred job count. Its value must not affect cure
// outcome.
const EnvJobs = "CURE_JOBS"
const (
// EnvJobs is the name of the environment variable holding a decimal
// representation of the preferred job count. Its value must not affect cure
// outcome.
EnvJobs = "CURE_JOBS"
// EnvLoad is the name of the environment variable holding a decimal
// representation of the preferred loadavg target. Its value must not affect
// cure outcome.
EnvLoad = "CURE_LOAD"
)
// ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make
// it available at under in the container.
@@ -407,9 +413,9 @@ func init() {
func(r *IRReader) Artifact { return readExecArtifact(r, true) })
}
// Dependencies returns a slice of all artifacts collected from caller-supplied
// Inputs returns a slice of all artifacts collected from caller-supplied
// [ExecPath].
func (a *execArtifact) Dependencies() []Artifact {
func (a *execArtifact) Inputs() []Artifact {
artifacts := make([][]Artifact, 0, len(a.paths))
for _, p := range a.paths {
artifacts = append(artifacts, p.A)
@@ -471,7 +477,7 @@ const SeccompPresets = std.PresetStrict &
func (a *execArtifact) makeContainer(
ctx context.Context,
msg message.Msg,
flags, jobs int,
flags, jobs, load int,
hostNet bool,
temp, work *check.Absolute,
getArtifact GetArtifactFunc,
@@ -508,7 +514,10 @@ func (a *execArtifact) makeContainer(
z.Quiet = flags&CSuppressInit != 0
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
z.Dir, z.Path, z.Args = a.dir, a.path, a.args
z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
z.Env = slices.Concat(a.env, []string{
EnvJobs + "=" + strconv.Itoa(jobs),
EnvLoad + "=" + strconv.Itoa(load),
})
z.Grow(len(a.paths) + 4)
if a.arch != runtime.GOARCH {
@@ -617,7 +626,7 @@ func (c *Cache) EnterExec(
return ErrNotExec
}
deps := Collect(a.Dependencies())
deps := Collect(a.Inputs())
if _, _, err = c.Cure(&deps); err == nil {
return errors.New("unreachable")
} else if !IsCollected(err) {
@@ -649,8 +658,9 @@ func (c *Cache) EnterExec(
var z *container.Container
z, err = e.makeContainer(
ctx, c.msg,
c.flags,
c.jobs,
c.attr.Flags,
c.attr.Jobs,
c.attr.Load,
hostNet,
temp, work,
func(a Artifact) (*check.Absolute, unique.Handle[Checksum]) {
@@ -693,7 +703,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
msg := f.GetMessage()
var z *container.Container
if z, err = a.makeContainer(
ctx, msg, f.cache.flags, f.GetJobs(), hostNet,
ctx, msg, f.cache.attr.Flags, f.GetJobs(), f.GetLoad(), hostNet,
f.GetTempDir(), f.GetWorkDir(),
f.GetArtifact,
f.cache.Ident,
+10 -10
View File
@@ -84,7 +84,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WNew, nil},
{"substitution", pkg.NewExec(
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
@@ -108,7 +108,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WSubstitute, nil},
{"error passthrough", pkg.NewExec(
"", "", nil, 0, false, true,
@@ -118,7 +118,7 @@ func TestExec(t *testing.T) {
[]string{"testtool"},
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
), nil, nil, &pkg.DependencyCureError{
), nil, nil, pkg.WNew, &pkg.DependencyCureError{
{
A: failingArtifact,
Err: stub.UniqueError(0xcafe),
@@ -133,7 +133,7 @@ func TestExec(t *testing.T) {
[]string{"testtool"},
pkg.ExecPath{},
), nil, nil, pkg.ErrInvalidPaths},
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths},
})
// check init failure passthrough
@@ -225,7 +225,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantNet, nil},
), ignorePathname, wantNet, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
@@ -269,7 +269,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
@@ -316,7 +316,7 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
@@ -385,7 +385,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
@@ -438,7 +438,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, nil},
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
@@ -503,7 +503,7 @@ func TestExec(t *testing.T) {
".": {Mode: fs.ModeDir | 0500},
"check": {Mode: 0400, Data: []byte("binfmt")},
}, nil},
}, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
+6 -2
View File
@@ -11,6 +11,7 @@ import (
type fileArtifact []byte
var _ KnownChecksum = new(fileArtifact)
var _ CuresExempt = new(fileArtifact)
// fileArtifactNamed embeds fileArtifact alongside a caller-supplied name.
type fileArtifactNamed struct {
@@ -62,8 +63,8 @@ func init() {
})
}
// Dependencies returns a nil slice.
func (*fileArtifact) Dependencies() []Artifact { return nil }
// Inputs returns a nil slice.
func (*fileArtifact) Inputs() []Artifact { return nil }
// IsExclusive returns false: Cure returns a prepopulated buffer.
func (*fileArtifact) IsExclusive() bool { return false }
@@ -79,3 +80,6 @@ func (a *fileArtifact) Checksum() Checksum {
func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(*a)), nil
}
// CuresExempt exempts the cheap [KindFile] implementation.
func (*fileArtifact) CuresExempt() {}
+1 -1
View File
@@ -18,7 +18,7 @@ func TestFile(t *testing.T) {
{"short", pkg.NewFile("null", []byte{0}), base.Append(
"identifier",
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
), want, nil},
), want, pkg.WNew, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
+9 -1
View File
@@ -38,7 +38,15 @@ func main() {
}
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
for _, t := range []string{
"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
} {
if s == t {
return true
}
}
return false
})
var hostNet, layers, promote bool
+22 -21
View File
@@ -90,7 +90,7 @@ type IContext struct {
// returns and must not be exposed directly.
w io.Writer
// Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with
// checksum values if non-nil.
// checksum values if non-nil. The pathname field may not be populated.
inputs map[Artifact]cureRes
}
@@ -173,7 +173,7 @@ func (i *IContext) mustWrite(p []byte) {
// WriteIdent writes the identifier of [Artifact] to the IR. The behaviour of
// WriteIdent is not defined for an [Artifact] not part of the slice returned by
// [Artifact.Dependencies].
// [Artifact.Inputs].
func (i *IContext) WriteIdent(a Artifact) {
buf := i.ic.getIdentBuf()
defer i.ic.putIdentBuf(buf)
@@ -235,13 +235,14 @@ func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
}
// encode implements Encode but replaces identifiers with their cured checksums
// for a non-nil ident. Caller must acquire Cache.identMu.
// for a non-nil ident. The pathname field is unused. Caller must acquire
// Cache.identMu.
func (ic *irCache) encode(
w io.Writer,
a Artifact,
inputs map[Artifact]cureRes,
) (err error) {
deps := a.Dependencies()
deps := a.Inputs()
idents := make([]*extIdent, len(deps))
if inputs == nil {
for i, d := range deps {
@@ -330,7 +331,7 @@ func (ic *irCache) encodeAll(
return
}
for _, d := range a.Dependencies() {
for _, d := range a.Inputs() {
if err = ic.encodeAll(w, d, encoded); err != nil {
return
}
@@ -432,9 +433,9 @@ type (
// Common buffer for word-sized reads.
buf [wordSize]byte
// Dependencies sent before params, sorted by identifier. Resliced on
// Inputs sent before params, sorted by identifier. Resliced on
// each call to Next and checked to be depleted during Finalise.
deps []*extIdent
inputs []*extIdent
// Number of values already read, -1 denotes a finalised IRReader.
count int
@@ -518,7 +519,7 @@ const (
irMaxValues = 1 << 12
// irMaxDeps is the arbitrary maximum number of direct dependencies allowed
// to be returned by [Artifact.Dependencies] and subsequently decoded by
// to be returned by [Artifact.Inputs] and subsequently decoded by
// [IRDecoder].
irMaxDeps = 1 << 10
)
@@ -603,17 +604,17 @@ func (ir *IRReader) mustReadHeader(k IRValueKind) {
// putAll returns all dependency buffers to the underlying [Cache].
func (ir *IRReader) putAll() {
for _, buf := range ir.deps {
for _, buf := range ir.inputs {
ir.d.c.putIdentBuf(buf)
}
ir.deps = nil
ir.inputs = nil
}
// DiscardAll discards all unstructured dependencies. This is useful to
// implementations that encode dependencies as [IRKindIdent] which are read back
// via ReadIdent.
func (ir *IRReader) DiscardAll() {
if ir.deps == nil {
if ir.inputs == nil {
panic("attempting to discard dependencies twice")
}
ir.putAll()
@@ -625,13 +626,13 @@ var ErrDependencyDepleted = errors.New("reading past end of dependencies")
// Next returns the next unstructured dependency.
func (ir *IRReader) Next() Artifact {
if len(ir.deps) == 0 {
if len(ir.inputs) == 0 {
panic(ErrDependencyDepleted)
}
id := unique.Make(ID(ir.deps[0][wordSize:]))
ir.d.c.putIdentBuf(ir.deps[0])
ir.deps = ir.deps[1:]
id := unique.Make(ID(ir.inputs[0][wordSize:]))
ir.d.c.putIdentBuf(ir.inputs[0])
ir.inputs = ir.inputs[1:]
if a, ok := ir.d.ident[id]; !ok {
ir.putAll()
@@ -684,8 +685,8 @@ func (ir *IRReader) Finalise() (checksum unique.Handle[Checksum], ok bool) {
}
ir.r, ir.ibw = nil, nil
if len(ir.deps) != 0 {
panic(MissedDependencyError(len(ir.deps)))
if len(ir.inputs) != 0 {
panic(MissedDependencyError(len(ir.inputs)))
}
return
@@ -778,11 +779,11 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
err = ErrIRDepend
return
}
ir.deps = make([]*extIdent, sz)
for i := range ir.deps {
ir.deps[i] = d.c.getIdentBuf()
ir.inputs = make([]*extIdent, sz)
for i := range ir.inputs {
ir.inputs[i] = d.c.getIdentBuf()
}
for _, buf := range ir.deps {
for _, buf := range ir.inputs {
ir.mustRead(buf[:])
}
+2 -2
View File
@@ -54,8 +54,8 @@ func init() {
})
}
// Dependencies returns a nil slice.
func (*httpArtifact) Dependencies() []Artifact { return nil }
// Inputs returns a nil slice.
func (*httpArtifact) Inputs() []Artifact { return nil }
// IsExclusive returns false: Cure returns as soon as a response is received.
func (*httpArtifact) IsExclusive() bool { return false }
+369 -149
View File
@@ -6,6 +6,7 @@ import (
"bytes"
"cmp"
"context"
"crypto/rand"
"crypto/sha512"
"encoding/base64"
"encoding/binary"
@@ -278,7 +279,11 @@ func (c *common) GetMessage() message.Msg { return c.cache.msg }
// GetJobs returns the preferred number of jobs to run, when applicable. Its
// value must not affect cure outcome.
func (c *common) GetJobs() int { return c.cache.jobs }
func (c *common) GetJobs() int { return c.cache.attr.Jobs }
// GetLoad returns the preferred load average target, when applicable. Its
// value must not affect cure outcome.
func (c *common) GetLoad() int { return c.cache.attr.Load }
// 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]
@@ -303,7 +308,7 @@ func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
}
var pathname *check.Absolute
if pathname, _, err = c.cache.cure(a, true); err != nil {
if pathname, _, _, err = c.cache.cure(a, true, false); err != nil {
return
}
@@ -330,8 +335,8 @@ func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
type FContext struct {
TContext
// Cured top-level dependencies looked up by Pathname.
deps map[Artifact]cureRes
// Cured top-level inputs looked up by Pathname.
inputs map[Artifact]cureRes
}
// linkSubstitute links status for substitute if populated.
@@ -356,24 +361,24 @@ func (f *FContext) linkSubstitute(ids, substitutes string) (err error) {
return
}
// InvalidLookupError is the identifier of non-dependency [Artifact] looked up
// InvalidLookupError is the identifier of non-input [Artifact] looked up
// via [FContext.GetArtifact] by a misbehaving [Artifact] implementation.
type InvalidLookupError ID
func (e InvalidLookupError) Error() string {
return "attempting to look up non-dependency artifact " + Encode(e)
return "attempting to look up non-input artifact " + Encode(e)
}
var _ error = InvalidLookupError{}
// GetArtifact returns the identifier pathname and checksum of an [Artifact].
// Calling Pathname with an [Artifact] not part of the slice returned by
// [Artifact.Dependencies] panics.
// [Artifact.Inputs] panics.
func (f *FContext) GetArtifact(a Artifact) (
pathname *check.Absolute,
checksum unique.Handle[Checksum],
) {
if res, ok := f.deps[a]; ok {
if res, ok := f.inputs[a]; ok {
return res.pathname, res.checksum
}
panic(InvalidLookupError(f.cache.Ident(a).Value()))
@@ -405,13 +410,13 @@ type Artifact interface {
// Result must remain identical across multiple invocations.
Params(ctx *IContext)
// Dependencies returns a slice of [Artifact] that the current instance
// depends on to produce its contents.
// Inputs returns a slice of [Artifact] the current instance has access to
// while producing its output.
//
// Callers must not modify the retuned slice.
//
// Result must remain identical across multiple invocations.
Dependencies() []Artifact
Inputs() []Artifact
// IsExclusive returns whether the [Artifact] is exclusive. Exclusive
// artifacts might not run in parallel with each other, and are still
@@ -485,6 +490,16 @@ type KnownChecksum interface {
Checksum() Checksum
}
// CuresExempt is optionally implemented for an artifact exempt to the
// cache-wide cures counter and limit.
type CuresExempt interface {
Artifact
// CuresExempt is a no-op function but serves to distinguish implementations
// that are cures-exempt.
CuresExempt()
}
// FileArtifact refers to an [Artifact] backed by a single file.
//
// FileArtifact does not support fine-grained cancellation. Its context is
@@ -592,7 +607,7 @@ type cureRes struct {
checksum unique.Handle[Checksum]
}
// A pendingArtifactDep is a dependency [Artifact] pending concurrent curing,
// A pendingArtifactDep is an input [Artifact] pending concurrent curing,
// subject to the cures limit. Values pointed to by result addresses are safe
// to access after the [sync.WaitGroup] associated with this pendingArtifactDep
// is done. pendingArtifactDep must not be reused or modified after it is sent
@@ -666,8 +681,12 @@ const (
// suppressed regardless of [message.Msg] state.
CSuppressInit
// CIgnoreSubstitutes disables content-based dependency substitution.
// CIgnoreSubstitutes disables content-based input substitution.
CIgnoreSubstitutes
// CExternShallow arranges for only non-flood inputs to be fetched when
// curing an [Artifact] available via the external cache.
CExternShallow
)
// toplevel holds [context.WithCancel] over caller-supplied context, where all
@@ -719,17 +738,15 @@ type Cache struct {
parent context.Context
// For deriving curing context, must not be accessed directly.
toplevel atomic.Pointer[toplevel]
// For waiting on dependency curing goroutines.
// For waiting on input curing goroutines.
wg sync.WaitGroup
// Reports new cures and passed to [Artifact].
msg message.Msg
// Directory where all [Cache] related files are placed.
base *check.Absolute
// Immutable cure options set by [Open].
flags int
// Immutable job count, when applicable.
jobs int
// Immutable [CacheAttr] populated by [Open].
attr CacheAttr
// Must not be exposed directly.
irCache
@@ -760,6 +777,8 @@ type Cache struct {
// Optional external cache implementation.
extern External
// Caches responses from extern.
externCache map[unique.Handle[ID]]unique.Handle[Checksum]
// Synchronises access to extern.
externMu sync.RWMutex
@@ -920,6 +939,7 @@ func readlinkChecksum(a *check.Absolute, buf *Checksum) error {
// SetExternal sets e as the [External] implementation of c.
func (c *Cache) SetExternal(e External) {
c.externMu.Lock()
c.externCache = make(map[unique.Handle[ID]]unique.Handle[Checksum])
c.extern = e
c.externMu.Unlock()
}
@@ -1431,7 +1451,7 @@ func (c *Cache) openFile(
ctx context.Context,
f FileArtifact,
) (r io.ReadCloser, err error) {
if kc, ok := f.(KnownChecksum); c.flags&CAssumeChecksum != 0 && ok {
if kc, ok := f.(KnownChecksum); c.attr.Flags&CAssumeChecksum != 0 && ok {
c.checksumMu.RLock()
r, err = os.Open(c.base.Append(
dirChecksum,
@@ -1616,7 +1636,47 @@ func (c *Cache) Cure(a Artifact) (
return
}
return c.cure(a, true)
pathname, checksum, _, err = c.cure(a, true, false)
return
}
// CureWhence is like Cure, but returns the whence value.
func (c *Cache) CureWhence(a Artifact) (
pathname *check.Absolute,
checksum unique.Handle[Checksum],
whence int,
err error,
) {
c.abortMu.RLock()
defer c.abortMu.RUnlock()
if err = c.toplevel.Load().ctx.Err(); err != nil {
return
}
return c.cure(a, true, false)
}
// CureNew is like Cure, but always enters the implementation.
func (c *Cache) CureNew(a Artifact) (
pathname *check.Absolute,
checksum unique.Handle[Checksum],
err error,
) {
c.abortMu.RLock()
defer c.abortMu.RUnlock()
if err = c.toplevel.Load().ctx.Err(); err != nil {
return
}
var whence int
retry:
pathname, checksum, whence, err = c.cure(a, true, true)
if err != nil || whence == WNew {
return
}
goto retry
}
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
@@ -1838,71 +1898,11 @@ func (r *RContext) NewMeasuredReader(
return r.cache.newMeasuredReader(rc, checksum)
}
// tryExtern attempts to obtain an [Artifact] outcome from extern.
func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) (
unique.Handle[Checksum],
io.ReadCloser,
error,
) {
c.externMu.RLock()
defer c.externMu.RUnlock()
if c.extern == nil {
return zeroChecksum, nil, nil
}
v, err := c.extern.Artifact(ctx, id)
if err != nil {
return zeroChecksum, nil, err
}
if v == nil {
return zeroChecksum, nil, nil
}
checksum := unique.Make(*v)
var got unique.Handle[Checksum]
if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
return checksum, nil, err
} else if got != checksum {
return zeroChecksum, nil, &ChecksumMismatchError{got.Value(), checksum.Value()}
}
var status io.ReadCloser
status, err = c.extern.Status(&RContext{common{ctx, c}}, id)
return checksum, status, err
}
// cure implements Cure without acquiring a read lock on abortMu. cure must not
// be entered during Abort.
func (c *Cache) cure(a Artifact, curesExempt bool) (
pathname *check.Absolute,
// tryChecksum dereferences a symlink to a cure outcome.
func (c *Cache) tryChecksum(pathname *check.Absolute) (
checksum unique.Handle[Checksum],
err error,
) {
id := c.Ident(a)
ids := Encode(id.Value())
pathname = c.base.Append(
dirIdentifier,
ids,
)
defer func() {
if err != nil {
pathname = nil
checksum = unique.Handle[Checksum]{}
}
}()
var (
ctx context.Context
done chan<- struct{}
)
ctx, done, checksum, err = c.loadOrStoreIdent(id)
if done == nil {
return
} else {
defer func() { c.finaliseIdent(done, id, checksum, err) }()
}
_, err = os.Lstat(pathname.String())
if err == nil {
var name string
@@ -1915,9 +1915,180 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
checksum = unique.Make(Checksum(buf[:]))
}
c.putIdentBuf(buf)
return
}
if !errors.Is(err, os.ErrNotExist) {
return
}
// tryLocal attempts to obtain an [Artifact] outcome from the filesystem.
func (c *Cache) tryLocal(id unique.Handle[ID]) (unique.Handle[Checksum], error) {
return c.tryChecksum(c.base.Append(
dirIdentifier,
Encode(id.Value()),
))
}
// tryExtern attempts to obtain an [Artifact] outcome from extern.
func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) (
unique.Handle[Checksum],
error,
) {
c.externMu.RLock()
defer c.externMu.RUnlock()
checksum, ok := c.externCache[id]
if !ok {
if c.extern == nil {
return zeroChecksum, nil
}
v, err := c.extern.Artifact(ctx, id)
if err != nil {
return zeroChecksum, err
}
if v == nil {
return zeroChecksum, nil
}
checksum = unique.Make(*v)
var got unique.Handle[Checksum]
if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
return checksum, err
} else if got != checksum {
return zeroChecksum, &ChecksumMismatchError{got.Value(), checksum.Value()}
}
}
return checksum, nil
}
// cureMany concurrently collects outcome of multiple [Artifact].
func (c *Cache) cureMany(
inputs []Artifact,
r map[Artifact]cureRes,
shallow bool,
) ([]bool, error) {
var wg sync.WaitGroup
wg.Add(len(inputs))
var mask []bool
res := make([]cureRes, len(inputs))
errs := make(DependencyCureError, 0, len(inputs))
var errsMu sync.Mutex
if shallow {
mask = make([]bool, len(inputs))
}
for i, d := range inputs {
if shallow {
if _, ok := d.(FloodArtifact); ok {
mask[i] = true
wg.Done()
continue
}
if kc, ok := d.(KnownChecksum); ok {
res[i].checksum = unique.Make(kc.Checksum())
wg.Done()
continue
}
}
pending := pendingArtifactDep{d, &res[i], &errs, &errsMu, &wg}
go pending.cure(c)
}
wg.Wait()
if len(errs) > 0 {
return mask, &errs
}
for i, p := range res {
if shallow && mask[i] {
continue
}
r[inputs[i]] = p
}
return mask, nil
}
// HangingInputError describes an input of an [Artifact] on a sparse cache
// without an outcome available locally or via [External].
type HangingInputError unique.Handle[ID]
func (e HangingInputError) Error() string {
return Encode(unique.Handle[ID](e).Value()) + " is unavailable"
}
const (
// WNew indicates a cure entering the implementation.
WNew = iota
// WCache indicates an [Artifact] present in the cache.
WCache
// WSubstitute indicates an [Artifact] hitting a content-based input
// substitution.
WSubstitute
// WExternal indicates a cure entering the external cache.
WExternal
)
// WhenceString returns a printable string for a whence value.
func WhenceString(whence int) string {
switch whence {
case WNew:
return "new"
case WCache:
return "cache"
case WSubstitute:
return "substitute"
case WExternal:
return "external"
default:
return "invalid whence " + strconv.Itoa(whence)
}
}
// cure implements Cure without acquiring a read lock on abortMu. cure must not
// be entered during Abort.
func (c *Cache) cure(a Artifact, curesExempt, rebuild bool) (
pathname *check.Absolute,
checksum unique.Handle[Checksum],
whence int,
err error,
) {
id := c.Ident(a)
if rebuild {
var v ID
_, _ = rand.Read(v[:])
id = unique.Make(v)
}
ids := Encode(id.Value())
pathname = c.base.Append(
dirIdentifier,
ids,
)
defer func() {
if err != nil {
pathname = nil
checksum = unique.Handle[Checksum]{}
}
}()
if _, ok := a.(CuresExempt); ok {
curesExempt = true
}
var (
ctx context.Context
done chan<- struct{}
)
ctx, done, checksum, err = c.loadOrStoreIdent(id)
if done == nil {
whence = WCache
return
} else {
defer func() { c.finaliseIdent(done, id, checksum, err) }()
}
checksum, err = c.tryChecksum(pathname)
if err == nil || !errors.Is(err, os.ErrNotExist) {
whence = WCache
return
}
@@ -1972,7 +2143,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
checksums,
)
if c.flags&CAssumeChecksum != 0 {
if c.attr.Flags&CAssumeChecksum != 0 {
c.checksumMu.RLock()
checksumFi, err = os.Stat(checksumPathname.String())
c.checksumMu.RUnlock()
@@ -1987,6 +2158,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
}
}
whence = WNew
if c.msg.IsVerbose() {
rn := reportName(a, id)
c.msg.Verbosef("curing %s...", rn)
@@ -2005,6 +2177,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
// cure FileArtifact outside type switch to skip TContext initialisation
if f, ok := a.(FileArtifact); ok {
if checksumFi != nil {
whence = WCache
if !checksumFi.Mode().IsRegular() {
// unreachable
err = InvalidFileModeError(checksumFi.Mode())
@@ -2039,7 +2212,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
}
r, err = f.Cure(&RContext{common{ctx, c}})
if err == nil {
if checksumPathname == nil || c.flags&CValidateKnown != 0 {
if checksumPathname == nil || c.attr.Flags&CValidateKnown != 0 {
h := sha512.New384()
hbw := c.getWriter(h)
_, err = io.Copy(w, io.TeeReader(r, hbw))
@@ -2056,7 +2229,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
if checksumPathname == nil {
checksum = unique.Make(Checksum(buf[:]))
checksums = Encode(Checksum(buf[:]))
} else if c.flags&CValidateKnown != 0 {
} else if c.attr.Flags&CValidateKnown != 0 {
if got := Checksum(buf[:]); got != checksum.Value() {
err = &ChecksumMismatchError{
Got: got,
@@ -2109,6 +2282,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
}
if checksumFi != nil {
whence = WCache
if !checksumFi.Mode().IsDir() {
// unreachable
err = InvalidFileModeError(checksumFi.Mode())
@@ -2139,30 +2313,64 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
break
case FloodArtifact:
deps := a.Dependencies()
f := FContext{t, make(map[Artifact]cureRes, len(deps))}
var wg sync.WaitGroup
wg.Add(len(deps))
res := make([]cureRes, len(deps))
errs := make(DependencyCureError, 0, len(deps))
var errsMu sync.Mutex
for i, d := range deps {
pending := pendingArtifactDep{d, &res[i], &errs, &errsMu, &wg}
go pending.cure(c)
}
wg.Wait()
if len(errs) > 0 {
err = &errs
var externChecksum unique.Handle[Checksum]
if externChecksum, err = c.tryExtern(ctx, id); err != nil {
if c.msg.IsVerbose() {
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
}
return
}
for i, p := range res {
f.deps[deps[i]] = p
extern := externChecksum != zeroChecksum
shallow := extern && c.attr.Flags&CExternShallow != 0
inputs := a.Inputs()
f := FContext{t, make(map[Artifact]cureRes, len(inputs))}
var mask []bool
if mask, err = c.cureMany(inputs, f.inputs, shallow); err != nil {
return
}
if shallow {
for i, d := range inputs {
if !mask[i] {
continue
}
if kc, ok := d.(KnownChecksum); ok {
f.inputs[d] = cureRes{checksum: unique.Make(kc.Checksum())}
continue
}
var sum unique.Handle[Checksum]
did := c.Ident(d)
sum, err = c.tryLocal(did)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return
}
sum, err = c.tryExtern(ctx, did)
if err != nil {
return
}
if sum == zeroChecksum {
if c.msg.IsVerbose() {
c.msg.Verbosef(
"input %s not available",
reportName(d, did),
)
}
err = HangingInputError(did)
return
}
}
f.inputs[d] = cureRes{checksum: sum}
}
}
sh := sha512.New384()
err = c.encode(sh, a, f.deps)
err = c.encode(sh, a, f.inputs)
if err != nil {
return
}
@@ -2177,13 +2385,14 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
substitutes,
)
if c.flags&CIgnoreSubstitutes == 0 {
if !rebuild && c.attr.Flags&CIgnoreSubstitutes == 0 {
var substituteChecksum unique.Handle[Checksum]
substituteChecksum, err = c.loadSubstitute(substitute)
if err != nil {
return
}
if substituteChecksum != zeroChecksum {
whence = WSubstitute
checksum = substituteChecksum
checksums = Encode(checksum.Value())
checksumPathname = c.base.Append(
@@ -2207,21 +2416,9 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
defer f.destroy(&err)
var (
externChecksum unique.Handle[Checksum]
externStatus io.ReadCloser
)
if externChecksum, externStatus, err = c.tryExtern(ctx, id); err != nil {
if c.msg.IsVerbose() {
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
}
return
}
if externChecksum != zeroChecksum {
if extern {
whence = WExternal
if checksum != zeroChecksum && externChecksum != checksum {
if externStatus != nil {
_ = externStatus.Close()
}
err = &ChecksumMismatchError{externChecksum.Value(), checksum.Value()}
if c.msg.IsVerbose() {
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
@@ -2229,6 +2426,14 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
return
}
var externStatus io.ReadCloser
c.externMu.RLock()
externStatus, err = c.extern.Status(&RContext{common{ctx, c}}, id)
c.externMu.RUnlock()
if err != nil {
return
}
checksum = externChecksum
checksums = Encode(checksum.Value())
checksumPathname = c.base.Append(
@@ -2245,8 +2450,10 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
return
} else if err = externStatus.Close(); err != nil {
return
} else if err = f.linkSubstitute(ids, substitutes); err != nil {
return
} else if !rebuild {
if err = f.linkSubstitute(ids, substitutes); err != nil {
return
}
}
}
return
@@ -2258,7 +2465,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
err = ca.Cure(&f)
c.exitCure(a, curesExempt)
if err == nil {
if !rebuild && err == nil {
err = f.linkSubstitute(ids, substitutes)
}
if err != nil {
@@ -2352,7 +2559,7 @@ func (pending *pendingArtifactDep) cure(c *Cache) {
defer pending.Done()
var err error
pending.resP.pathname, pending.resP.checksum, err = c.cure(pending.a, false)
pending.resP.pathname, pending.resP.checksum, _, err = c.cure(pending.a, false, false)
if err == nil {
return
}
@@ -2472,6 +2679,22 @@ var (
ErrWouldPromote = errors.New("operation would promote unextended cache")
)
// CacheAttr holds the attributes that will be applied to a new [Cache] opened
// by [Open].
type CacheAttr struct {
// Concurrent cures of a [FloodArtifact] dependency graph.
Cures int
// Options affecting [Cache] behaviour.
Flags int
// Preferred job count, when applicable.
Jobs int
// Preferred loadavg target, when applicable.
Load int
// Omit the [lockedfile] lock.
skipLock bool
}
// Open returns the address of a newly opened instance of [Cache].
//
// Concurrent cures of a [FloodArtifact] dependency graph is limited to the
@@ -2488,20 +2711,8 @@ var (
func Open(
ctx context.Context,
msg message.Msg,
flags, cures, jobs int,
base *check.Absolute,
) (*Cache, error) {
return open(ctx, msg, flags, cures, jobs, base, true)
}
// open implements Open but allows omitting the [lockedfile] lock when called
// from a test. This is used to simulate invalid states in the test suite.
func open(
ctx context.Context,
msg message.Msg,
flags, cures, jobs int,
base *check.Absolute,
lock bool,
attr *CacheAttr,
) (*Cache, error) {
openMu.Lock()
defer openMu.Unlock()
@@ -2511,11 +2722,19 @@ func open(
panic("attempting to open cache with incomplete variant setup")
}
if cures < 1 {
cures = runtime.NumCPU()
var a CacheAttr
if attr != nil {
a = *attr
}
if jobs < 1 {
jobs = runtime.NumCPU()
if a.Cures < 1 {
a.Cures = runtime.NumCPU()
}
if a.Jobs < 1 {
a.Jobs = runtime.NumCPU()
}
if a.Load < 1 {
a.Load = runtime.NumCPU() + 2
}
for _, name := range []string{
@@ -2537,9 +2756,8 @@ func open(
c := Cache{
parent: ctx,
cures: make(chan struct{}, cures),
flags: flags,
jobs: jobs,
cures: make(chan struct{}, a.Cures),
attr: a,
msg: msg,
base: base,
@@ -2556,7 +2774,7 @@ func open(
}
c.toplevel.Store(newToplevel(ctx))
if lock || !testing.Testing() {
if !a.skipLock || !testing.Testing() {
if unlock, err := lockedfile.MutexAt(
base.Append(fileLock).String(),
).Lock(); err != nil {
@@ -2617,7 +2835,7 @@ func open(
}
} else if s := string(p); s == "" {
if extension != "" {
if flags&CPromoteVariant == 0 {
if a.Flags&CPromoteVariant == 0 {
c.unlock()
return nil, ErrWouldPromote
}
@@ -2656,6 +2874,8 @@ func IsCollected(err error) bool { return errors.As(err, new(Collected)) }
// [pkg.Artifact]. It returns [Collected].
type Collect []Artifact
var _ Artifact = new(Collect)
// Cure returns [Collected].
func (*Collect) Cure(*FContext) error { return Collected{} }
@@ -2665,8 +2885,8 @@ func (*Collect) Kind() Kind { return kindCollection }
// Params is a noop: dependencies are already represented in the header.
func (*Collect) Params(*IContext) {}
// Dependencies returns [Collect] as is.
func (c *Collect) Dependencies() []Artifact { return *c }
// Inputs returns [Collect] as is.
func (c *Collect) Inputs() []Artifact { return *c }
// IsExclusive returns false: Cure is a noop.
func (*Collect) IsExclusive() bool { return false }
+231 -84
View File
@@ -35,14 +35,14 @@ import (
"hakurei.app/message"
)
//go:linkname unsafeOpen hakurei.app/internal/pkg.open
func unsafeOpen(
ctx context.Context,
msg message.Msg,
flags, cures, jobs int,
base *check.Absolute,
lock bool,
) (*pkg.Cache, error)
var skipLock = func() pkg.CacheAttr {
var attr pkg.CacheAttr
*(*bool)(unsafe.Pointer(reflect.ValueOf(&attr).
Elem().
FieldByName("skipLock").
UnsafeAddr())) = true
return attr
}()
var (
// extension is a string uniquely identifying a set of custom [Artifact]
@@ -140,11 +140,11 @@ type stubArtifact struct {
cure func(t *pkg.TContext) error
}
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
func (a *stubArtifact) Dependencies() []pkg.Artifact { return a.deps }
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
func (*stubArtifact) IsExclusive() bool { return false }
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
func (a *stubArtifact) Inputs() []pkg.Artifact { return a.deps }
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
func (*stubArtifact) IsExclusive() bool { return false }
// A stubArtifactF implements [FloodArtifact] with hardcoded behaviour.
type stubArtifactF struct {
@@ -156,11 +156,11 @@ type stubArtifactF struct {
cure func(f *pkg.FContext) error
}
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
func (a *stubArtifactF) Dependencies() []pkg.Artifact { return a.deps }
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
func (a *stubArtifactF) Inputs() []pkg.Artifact { return a.deps }
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
// A stubFile implements [FileArtifact] with hardcoded behaviour.
type stubFile struct {
@@ -339,7 +339,7 @@ func TestIdent(t *testing.T) {
var cache *pkg.Cache
if a, err := check.NewAbs(t.TempDir()); err != nil {
t.Fatal(err)
} else if cache, err = pkg.Open(t.Context(), msg, 0, 0, 0, a); err != nil {
} else if cache, err = pkg.Open(t.Context(), msg, a, nil); err != nil {
t.Fatal(err)
}
t.Cleanup(cache.Close)
@@ -519,7 +519,10 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
}
var scrubFunc func() error // scrub after hashing
if c, err := pkg.Open(t.Context(), msg, flags, 1<<4, 0, base); err != nil {
if c, err := pkg.Open(t.Context(), msg, base, &pkg.CacheAttr{
Cures: 1 << 4,
Flags: flags,
}); err != nil {
t.Fatalf("Open: error = %v", err)
} else {
t.Cleanup(c.Close)
@@ -627,6 +630,7 @@ type cureStep struct {
pathname *check.Absolute
output expectsKnown
whence int
err error
}
@@ -646,7 +650,7 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
for _, step := range steps {
t.Log("cure step:", step.name)
if pathname, checksum, err := c.Cure(step.a); !reflect.DeepEqual(err, step.err) {
if pathname, checksum, whence, err := c.CureWhence(step.a); !reflect.DeepEqual(err, step.err) {
faults, _err := c.ReadFaults(step.a)
if _err != nil {
t.Errorf("ReadFaults: error = %v", _err)
@@ -663,6 +667,8 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
t.Logf("faulting cure terminated %s ago", time.Since(faults[0].Time()))
}
t.Fatalf("Cure: error = %v, want %v", err, step.err)
} else if step.whence != whence {
t.Fatalf("Cure: whence = %s, want %s", pkg.WhenceString(whence), pkg.WhenceString(step.whence))
} else if step.pathname != ignorePathname && !pathname.Is(step.pathname) {
t.Fatalf("Cure: pathname = %q, want %q", pathname, step.pathname)
} else if step.output == nil || checksum != makeChecksumH(step.output.hash()) {
@@ -774,28 +780,28 @@ func TestCache(t *testing.T) {
identifier,
new(testdata.hash()),
testdata, nil,
), wantPathname, testdata, nil},
), wantPathname, testdata, pkg.WNew, nil},
{"identical content", newStubFile(
pkg.KindHTTPGet,
identifier0,
new(testdata.hash()),
testdata, nil,
), wantPathname0, testdata, nil},
), wantPathname0, testdata, pkg.WCache, nil},
{"existing entry", newStubFile(
pkg.KindHTTPGet,
identifier,
new(testdata.hash()),
testdata, nil,
), wantPathname, testdata, nil},
), wantPathname, testdata, pkg.WCache, nil},
{"checksum mismatch", newStubFile(
pkg.KindHTTPGet,
pkg.ID{0xff, 0},
new(pkg.Checksum),
testdata, nil,
), nil, nil, &pkg.ChecksumMismatchError{
), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
Got: testdata.hash(),
}},
@@ -816,12 +822,12 @@ func TestCache(t *testing.T) {
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
}, nil},
}, pkg.WNew, nil},
{"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{
kind: pkg.KindExec,
params: []byte("artifact overridden to be incomplete"),
}}, nil, nil, pkg.InvalidArtifactError(pkg.MustDecode(
}}, nil, nil, pkg.WNew, pkg.InvalidArtifactError(pkg.MustDecode(
"E__uZ1sLIvb84vzSm5Uezb03RogsiaeTt1nfIVv8TKnnf4LqwtSi-smdHhlkZrUJ",
))},
@@ -830,18 +836,18 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1},
nil,
nil, stub.UniqueError(0xcafe),
), nil, nil, stub.UniqueError(0xcafe)},
), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
{"error caching", newStubFile(
pkg.KindHTTPGet,
pkg.ID{0xff, 1},
nil,
nil, nil,
), nil, nil, stub.UniqueError(0xcafe)},
), nil, nil, pkg.WCache, stub.UniqueError(0xcafe)},
{"cache hit bad type", overrideChecksum{testdata.hash(), overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar,
}}}, nil, nil, pkg.InvalidFileModeError(
}}}, nil, nil, pkg.WCache, pkg.InvalidFileModeError(
0400,
)},
@@ -853,7 +859,7 @@ func TestCache(t *testing.T) {
cure: func(f *pkg.FContext) error {
panic("attempting to cure impossible artifact")
},
}, nil, nil, &pkg.DependencyCureError{
}, nil, nil, pkg.WNew, &pkg.DependencyCureError{
{
A: failingFile,
Err: struct {
@@ -864,10 +870,10 @@ func TestCache(t *testing.T) {
}},
})
if c0, err := unsafeOpen(
if c0, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, base, false,
base, &skipLock,
); err != nil {
t.Fatalf("open: error = %v", err)
} else {
@@ -875,7 +881,7 @@ func TestCache(t *testing.T) {
cureMany(t, c0, []cureStep{
{"cache hit ident", overrideIdent{
id: identifier,
}, wantPathname, testdata, nil},
}, wantPathname, testdata, pkg.WCache, nil},
{"cache miss checksum match", newStubFile(
pkg.KindHTTPGet,
@@ -886,7 +892,7 @@ func TestCache(t *testing.T) {
), base.Append(
"identifier",
pkg.Encode(testdata.hash()),
), testdata, nil},
), testdata, pkg.WNew, nil},
})
// cure after close
@@ -1016,30 +1022,30 @@ func TestCache(t *testing.T) {
{"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar,
cure: makeSample,
}}}, wantPathname, want, nil},
}}}, wantPathname, want, pkg.WNew, nil},
{"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar,
}}}, wantPathname, want, nil},
}}}, wantPathname, want, pkg.WCache, nil},
{"identical checksum", overrideIdent{id0, &stubArtifact{
kind: pkg.KindTar,
cure: makeSample,
}}, wantPathname0, want, nil},
}}, wantPathname0, want, pkg.WNew, nil},
{"cure fault", overrideIdent{pkg.ID{0xff, 0}, &stubArtifact{
kind: pkg.KindTar,
cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xcafe))
},
}}, nil, nil, stub.UniqueError(0xcafe)},
}}, nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
{"checksum mismatch", overrideChecksum{pkg.Checksum{}, overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
kind: pkg.KindTar,
cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), nil)
},
}}}, nil, nil, &pkg.ChecksumMismatchError{
}}}, nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
Got: pkg.MustDecode(
"CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT",
),
@@ -1050,7 +1056,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 2},
new(want.hash()),
testdata, nil,
), nil, nil, pkg.InvalidFileModeError(
), nil, nil, pkg.WCache, pkg.InvalidFileModeError(
fs.ModeDir | 0500,
)},
@@ -1064,7 +1070,7 @@ func TestCache(t *testing.T) {
_, err = io.ReadAll(r)
return err
},
}}, nil, nil, &os.PathError{
}}, nil, nil, pkg.WNew, &os.PathError{
Op: "read",
Path: base.Append(
"checksum",
@@ -1078,14 +1084,14 @@ func TestCache(t *testing.T) {
cure: func(t *pkg.TContext) error {
return nil
},
}}, nil, nil, pkg.NoOutputError{}},
}}, nil, nil, pkg.WNew, pkg.NoOutputError{}},
{"file output", overrideIdent{pkg.ID{0xff, 5}, &stubArtifact{
kind: pkg.KindTar,
cure: func(t *pkg.TContext) error {
return os.WriteFile(t.GetWorkDir().String(), []byte{0}, 0400)
},
}}, nil, nil, errors.New("non-file artifact produced regular file")},
}}, nil, nil, pkg.WNew, errors.New("non-file artifact produced regular file")},
{"symlink output", overrideIdent{pkg.ID{0xff, 6}, &stubArtifact{
kind: pkg.KindTar,
@@ -1095,7 +1101,7 @@ func TestCache(t *testing.T) {
t.GetWorkDir().String(),
)
},
}}, nil, nil, pkg.InvalidFileModeError(
}}, nil, nil, pkg.WNew, pkg.InvalidFileModeError(
fs.ModeSymlink | 0777,
)},
@@ -1116,7 +1122,7 @@ func TestCache(t *testing.T) {
}, base.Append(
"identifier",
"xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-",
), want, nil},
), want, pkg.WNew, nil},
{"substitutable", &stubArtifactF{
kind: pkg.KindExec,
@@ -1135,13 +1141,13 @@ func TestCache(t *testing.T) {
}, base.Append(
"identifier",
"k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f",
), want, nil},
), want, pkg.WSubstitute, nil},
})
if c0, err := unsafeOpen(
if c0, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, base, false,
base, &skipLock,
); err != nil {
t.Fatalf("open: error = %v", err)
} else {
@@ -1164,7 +1170,7 @@ func TestCache(t *testing.T) {
}, base.Append(
"identifier",
"_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_",
), want, nil},
), want, pkg.WSubstitute, nil},
})
}
@@ -1235,7 +1241,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1},
nil,
nil, stub.UniqueError(0xbad),
), nil, nil, stub.UniqueError(0xbad)},
), nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
{"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar,
@@ -1246,7 +1252,7 @@ func TestCache(t *testing.T) {
0400,
)
},
}}, nil, nil, errors.New(
}}, nil, nil, pkg.WNew, errors.New(
"non-file artifact produced regular file",
)},
})
@@ -1363,14 +1369,14 @@ func TestCache(t *testing.T) {
}}}, base.Append(
"identifier",
pkg.Encode(pkg.ID{0xff, 0}),
), want, nil},
), want, pkg.WNew, nil},
{"reject", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xfe, 1}, &stubArtifact{
kind: pkg.KindTar,
cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xbad))
},
}}}, nil, nil, stub.UniqueError(0xbad)},
}}}, nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
{"match", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
kind: pkg.KindTar,
@@ -1380,7 +1386,7 @@ func TestCache(t *testing.T) {
}}}, base.Append(
"identifier",
pkg.Encode(pkg.ID{0xff, 1}),
), want, nil},
), want, pkg.WNew, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -1408,7 +1414,7 @@ func TestCache(t *testing.T) {
), base.Append(
"identifier",
pkg.Encode(pkg.Checksum{0xfe, 0}),
), expectsChecksum{0xff, 0}, nil},
), expectsChecksum{0xff, 0}, pkg.WNew, nil},
})
for _, p := range [][]string{
@@ -1485,7 +1491,7 @@ func TestCache(t *testing.T) {
), expectsFS{
".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444},
}, nil},
}, pkg.WNew, nil},
{"substituted", substituted, base.Append(
"identifier",
@@ -1493,7 +1499,7 @@ func TestCache(t *testing.T) {
), expectsFS{
".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444},
}, nil},
}, pkg.WSubstitute, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -1586,14 +1592,14 @@ func TestCache(t *testing.T) {
{"extern", a, base.Append(
"identifier",
pkg.Encode(wantIdent.Value()),
), wantOutput, nil},
), wantOutput, pkg.WExternal, nil},
{"substitute", _a, base.Append(
"identifier",
pkg.Encode(_wantIdent.Value()),
), _wantOutput, nil},
), _wantOutput, pkg.WExternal, nil},
{"mismatch", kca, nil, nil, &pkg.ChecksumMismatchError{
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
Got: wantChecksum,
}},
})
@@ -1621,6 +1627,152 @@ func TestCache(t *testing.T) {
"work": {Mode: fs.ModeDir | 0700},
}},
{"extern shallow", pkg.CExternShallow, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
a := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("extern"),
}
wantIdent := c.Ident(a)
wantOutput := expectsFS{
".": {Mode: fs.ModeDir | 0500},
"result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
}
var wantChecksum pkg.Checksum
if err := pkg.SumFS(
&wantChecksum,
fstest.MapFS(wantOutput),
".",
); err != nil {
t.Fatal(err)
}
wantChecksumH := unique.Make(wantChecksum)
_a := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("extern substitute"),
deps: []pkg.Artifact{pkg.NewFile("", nil)},
}
_wantIdent := c.Ident(_a)
_wantOutput := expectsFS{
".": {Mode: fs.ModeDir | 0500},
}
var _wantChecksum pkg.Checksum
if err := pkg.SumFS(
&_wantChecksum,
fstest.MapFS(_wantOutput),
".",
); err != nil {
t.Fatal(err)
}
_wantChecksumH := unique.Make(_wantChecksum)
kca := pkg.NewExec(
"", "",
new(pkg.Checksum), 0, false, false,
fhs.AbsRoot, nil, fhs.AbsRoot, nil,
)
kcIdent := c.Ident(kca)
fia := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("flood input"),
deps: []pkg.Artifact{_a},
}
fiaIdent := c.Ident(fia)
flia := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("flood input local"),
deps: []pkg.Artifact{_a},
}
fliaIdent := c.Ident(flia)
h := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("hanging input"),
}
fhia := &stubArtifactF{
kind: pkg.KindExec,
params: []byte("flood input local"),
deps: []pkg.Artifact{h},
}
fhiaIdent := c.Ident(fhia)
c.SetExternal(stubExtern{
artifact: map[unique.Handle[pkg.ID]]pkg.Checksum{
wantIdent: wantChecksum,
_wantIdent: _wantChecksum,
kcIdent: wantChecksum,
fiaIdent: wantChecksum,
fliaIdent: wantChecksum,
fhiaIdent: wantChecksum,
},
checksum: map[unique.Handle[pkg.Checksum]]fstest.MapFS{
wantChecksumH: fstest.MapFS(wantOutput),
_wantChecksumH: fstest.MapFS(_wantOutput),
},
status: map[unique.Handle[pkg.ID]]string{
wantIdent: "\x00",
kcIdent: "unreachable",
},
})
cureMany(t, c, []cureStep{
{"extern", a, base.Append(
"identifier",
pkg.Encode(wantIdent.Value()),
), wantOutput, pkg.WExternal, nil},
{"flood shallow extern", fia, base.Append(
"identifier",
pkg.Encode(fiaIdent.Value()),
), wantOutput, pkg.WExternal, nil},
{"substitute", _a, base.Append(
"identifier",
pkg.Encode(_wantIdent.Value()),
), _wantOutput, pkg.WExternal, nil},
{"flood shallow local", flia, base.Append(
"identifier",
pkg.Encode(fliaIdent.Value()),
), wantOutput, pkg.WExternal, nil},
{"flood shallow hanging", fhia, nil, nil,
pkg.WNew, pkg.HangingInputError(c.Ident(h))},
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
Got: wantChecksum,
}},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
"checksum": {Mode: fs.ModeDir | 0700},
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl": {Mode: fs.ModeDir | 0500},
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/4HqRo4uTwRQjfy3d2cujMoDC_pC4iv20h4a7NYlx0UdbVuky18o5iK78TFEfPX2U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/7AZcJm58ghFyTVf_v2baSntgpsxkP5el7ti9dC77C29n8YTEqQW9jRW92KGNdYnz": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/RJbTOOIlqsEkAxGlTIsbp4mHPO0Q2IlwU7Gh_FIaTxnhgxUjAQPXXgPyP2GJWX2A": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/c4aCI00C-ZVyo_FQDQLl1OYK4U_kjzxwrLdFDiXMHnbMcZXCkXo_nxUWauScZ_4V": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/lqjQtzpJ6asInpsdxqNYVjTkRHK-gW0eUCqNCCk1KhZTuKwKAc5Z0H7tS-GWfRlg": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"status": {Mode: fs.ModeDir | 0700},
"status/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: 0400, Data: []byte("\x00")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/qOYrxy9ztKeOA96Os811_0Ox5sd8FBOxis6psJAnRJL5MLazFMaqmd4g7t7k1OHk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute/vLTXKbImP9XTTSi7P3PIuqy5L5UgX4dFQm2traX4X_pCDvg9GDraX1LmaUpgLu4w": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"substitute/yn1xEs5uSnu5EFLtkvjFSQ0C_fv50hU_w2wfDH_WBEzQhUiPJfyS3Eegy6YSclYN": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"work": {Mode: fs.ModeDir | 0700},
}},
}
checkWithCache(t, testCases)
}
@@ -1635,7 +1787,7 @@ func TestErrors(t *testing.T) {
}{
{"InvalidLookupError", pkg.InvalidLookupError{
0xff, 0xf0,
}, "attempting to look up non-dependency artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
}, "attempting to look up non-input artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
{"InvalidArtifactError", pkg.InvalidArtifactError{
0xff, 0xfd,
@@ -1883,7 +2035,7 @@ func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
func (earlyFailureF) Params(*pkg.IContext) {}
func (earlyFailureF) IsExclusive() bool { return false }
func (a earlyFailureF) Dependencies() []pkg.Artifact {
func (a earlyFailureF) Inputs() []pkg.Artifact {
deps := make([]pkg.Artifact, a)
for i := range deps {
deps[i] = a - 1
@@ -1901,7 +2053,7 @@ func (a earlyFailureF) Cure(*pkg.FContext) error {
func BenchmarkEarlyDCE(b *testing.B) {
msg := message.New(log.New(os.Stderr, "dce: ", 0))
msg.SwapVerbose(testing.Verbose())
c, err := pkg.Open(b.Context(), msg, 0, 0, 0, check.MustAbs(b.TempDir()))
c, err := pkg.Open(b.Context(), msg, check.MustAbs(b.TempDir()), nil)
if err != nil {
b.Fatal(err)
}
@@ -1950,7 +2102,8 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, check.MustAbs(container.Nonexistent),
check.MustAbs(container.Nonexistent),
nil,
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -1978,7 +2131,8 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, tempDir.Append("cache"),
tempDir.Append("cache"),
nil,
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2000,7 +2154,8 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, tempDir.Append("cache"),
tempDir.Append("cache"),
nil,
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2021,7 +2176,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
0, 0, 0, tempDir.Append("cache"),
tempDir.Append("cache"), nil,
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2074,8 +2229,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(log.Default()),
0, 0, 0,
check.MustAbs(container.Nonexistent),
nil,
); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Open: error = %v", err)
}
@@ -2113,7 +2268,7 @@ func TestExtensionRegister(t *testing.T) {
pkg.Register(pkg.KindCustomOffset, nil)
t.Cleanup(func() { opened = false })
_, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
_, _ = pkg.Open(nil, nil, nil, nil)
panic("unreachable")
})
@@ -2124,11 +2279,7 @@ func TestExtensionRegister(t *testing.T) {
base := check.MustAbs(t.TempDir())
t.Cleanup(func() { opened = false })
if c, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
); err != nil {
if c, err := pkg.Open(t.Context(), nil, base, nil); err != nil {
t.Fatal(err)
} else {
c.Close()
@@ -2156,8 +2307,7 @@ func TestExtensionRegister(t *testing.T) {
}
if _, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
base, nil,
); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("Open: error = %v, want %v", err, wantErr)
}
@@ -2178,8 +2328,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
nil,
); !reflect.DeepEqual(err, pkg.ErrWouldPromote) {
t.Fatalf("Open: error = %v", err)
}
@@ -2192,8 +2342,7 @@ func TestExtensionRegister(t *testing.T) {
if c, err := pkg.Open(
t.Context(), nil,
pkg.CPromoteVariant, 0, 0,
base,
base, &pkg.CacheAttr{Flags: pkg.CPromoteVariant},
); err != nil {
t.Fatalf("Open: error = %v", err)
} else {
@@ -2218,8 +2367,7 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
base, nil,
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
t.Fatalf("Open: error = %v", err)
}
@@ -2236,8 +2384,7 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
base, nil,
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
t.Fatalf("Open: error = %v", err)
}
+8 -2
View File
@@ -16,6 +16,8 @@ type tarArtifact struct {
f Artifact
}
var _ CuresExempt = new(tarArtifact)
// tarArtifactNamed embeds tarArtifact for a [fmt.Stringer] tarball.
type tarArtifactNamed struct {
tarArtifact
@@ -56,8 +58,8 @@ func init() {
})
}
// Dependencies returns a slice containing the backing file.
func (a *tarArtifact) Dependencies() []Artifact {
// Inputs returns a slice containing the backing file.
func (a *tarArtifact) Inputs() []Artifact {
return []Artifact{a.f}
}
@@ -211,3 +213,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
return
}
// CuresExempt exempts the cheap [KindTar] implementation often at the end of a
// [FileArtifact] pipeline.
func (*tarArtifact) CuresExempt() {}
+5 -5
View File
@@ -212,24 +212,24 @@ func checkTarHTTP(
&client,
"file:///testdata",
testdataChecksum,
), pkg.Gzip)), ignorePathname, want, nil},
), pkg.Gzip)), ignorePathname, want, pkg.WNew, nil},
{"directory", pkg.NewTar(pkg.NewDecompress(
&tarDir,
pkg.Gzip,
)), ignorePathname, want, nil},
)), ignorePathname, want, pkg.WNew, nil},
{"multiple entries", pkg.NewTar(pkg.NewDecompress(
&tarDirMulti,
pkg.Gzip,
)), nil, nil, errors.New(
)), nil, nil, pkg.WNew, errors.New(
"input directory does not contain a single regular file",
)},
{"bad type", pkg.NewTar(pkg.NewDecompress(
&tarDirType,
pkg.Gzip,
)), nil, nil, errors.New(
)), nil, nil, pkg.WNew, errors.New(
"input directory does not contain a single regular file",
)},
@@ -239,6 +239,6 @@ func checkTarHTTP(
cure: func(t *pkg.TContext) error {
return stub.UniqueError(0xcafe)
},
}), nil, nil, stub.UniqueError(0xcafe)},
}), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
})
}
+5
View File
@@ -18,6 +18,11 @@ const (
jobsLE = `"$(expr ` + jobsE + ` '*' 2)"`
// jobsLFlagE is expression for flag with double of preferred job count.
jobsLFlagE = `"-j$(expr ` + jobsE + ` '*' 2)"`
// loadE is expression for preferred loadavg target set by [pkg].
loadE = `"$` + pkg.EnvLoad + `"`
// loadFlagE is expression for flag with preferred loadavg target.
loadFlagE = `"-l$` + pkg.EnvLoad + `"`
)
// newTar wraps [pkg.NewHTTPGetTar] with a simpler function signature.
+2 -2
View File
@@ -26,8 +26,8 @@ func (a busyboxBin) Params(*pkg.IContext) {}
// IsExclusive returns false: Cure performs a trivial filesystem write.
func (busyboxBin) IsExclusive() bool { return false }
// Dependencies returns the underlying busybox [pkg.FileArtifact].
func (a busyboxBin) Dependencies() []pkg.Artifact {
// Inputs returns the underlying busybox [pkg.FileArtifact].
func (a busyboxBin) Inputs() []pkg.Artifact {
return []pkg.Artifact{a.bin}
}
+3 -3
View File
@@ -61,10 +61,10 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
}
generate := "Ninja"
test := "ninja " + jobsFlagE + " test"
test := "ninja " + jobsFlagE + " " + loadFlagE + " test"
if attr.Make {
generate = "'Unix Makefiles'"
test = "make " + jobsFlagE + " test"
test = "make " + jobsFlagE + " " + loadFlagE + " test"
}
if attr.Test != "" {
test = attr.Test
@@ -97,7 +97,7 @@ cmake -G ` + generate + ` \
}), " \\\n\t") + ` \
-DCMAKE_INSTALL_PREFIX=/system \
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
cmake --build . --parallel=` + jobsE + `
cmake --build . --parallel=` + jobsE + ` -- ` + loadFlagE + `
DESTDIR=/work cmake --install .
` + script
}
+2 -2
View File
@@ -118,8 +118,8 @@ func init() {
// IsExclusive returns false: Cure performs a few trivial filesystem writes.
func (cureEtc) IsExclusive() bool { return false }
// Dependencies returns a slice containing the backing iana-etc release.
func (a cureEtc) Dependencies() []pkg.Artifact {
// Inputs returns a slice containing the backing iana-etc release.
func (a cureEtc) Inputs() []pkg.Artifact {
if !a.minimal {
return []pkg.Artifact{ianaEtc}
}
+8 -10
View File
@@ -341,6 +341,13 @@ ln -s \
return &meta, t.NewPackage("llvm", meta.Version, source, &PackageAttr{
Flag: TExclusive,
Bin: []string{
"chmod",
"mkdir",
"rm",
"tr",
"awk",
},
}, &CMakeHelper{
Append: []string{"llvm"},
@@ -358,16 +365,7 @@ ln -s clang++ /work/system/bin/c++
// on 3-stage determinism to test later stages.
SkipTest: t.stage.isStage0(),
Test: `
chmod +w /bin && ln -s \
../system/bin/chmod \
../system/bin/mkdir \
../system/bin/rm \
../system/bin/tr \
../system/bin/awk \
/bin
ninja ` + jobsFlagE + ` check-all
`,
Test: "ninja " + jobsFlagE + " " + loadFlagE + " check-all",
},
_python,
_perl,
+4 -2
View File
@@ -89,7 +89,7 @@ func (attr *MakeHelper) wantsDir() (string, bool) {
if attr != nil && attr.InPlace {
return helperInPlace, false
}
return `"$(mktemp -d)"`, false
return "/cure/", true
}
// script generates the cure script.
@@ -160,7 +160,8 @@ func (attr *MakeHelper) script(t Toolchain, name string) string {
scriptMake := `
make \
` + jobsFlagE
` + jobsFlagE + ` \
` + loadFlagE
if len(attr.Make) > 0 {
scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t")
}
@@ -170,6 +171,7 @@ make \
(!attr.SkipCheckEarly || !t.stage.isStage0()) {
scriptMake += attr.ScriptCheckEarly + `make \
` + jobsFlagE + ` \
` + loadFlagE + ` \
`
if len(attr.Check) > 0 {
scriptMake += strings.Join(attr.Check, " \\\n\t")
+6
View File
@@ -18,6 +18,8 @@ type MesonHelper struct {
// Flags passed to the setup command.
Setup []KV
// Test suites to skip.
SkipTests []string
// Whether to skip meson test.
SkipTest bool
// Run tests with interactive input/output.
@@ -56,11 +58,15 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
scriptTest = `
meson test \
-t 10 \
--print-errorlogs`
if attr.InteractiveTest {
scriptTest += ` \
--interactive`
}
for _, suite := range attr.SkipTests {
scriptTest += " \\\n\t--no-suite='" + suite + "'"
}
}
return `
+256 -113
View File
@@ -14,6 +14,7 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"unique"
"hakurei.app/internal/pkg"
@@ -30,8 +31,8 @@ type Remote struct {
c *http.Client
}
// NewRemote returns a populated [Remote]
func NewRemote(base string, pub ed25519.PublicKey, c *http.Client) (Remote, error) {
// NewRemote returns a populated [Remote].
func NewRemote(c *http.Client, base string, pub ed25519.PublicKey) (Remote, error) {
u, err := url.Parse(base)
return Remote{u, pub, c}, err
}
@@ -201,14 +202,261 @@ func (r Remote) Status(
), nil
}
// NewMirror returns an [http.Handler] for servicing mirror requests.
// Mirror services requests made by [Remote].
type Mirror struct {
// Cache on-filesystem format.
fsys fs.FS
// Signs payloads.
key ed25519.PrivateKey
// Verbose output.
msg message.Msg
}
// Populate fills an empty root with a static mirror snapshot.
func (m Mirror) Populate(root *os.Root) error {
if dents, err := fs.ReadDir(root.FS(), "."); err != nil {
return err
} else if len(dents) > 0 {
return syscall.ENOTEMPTY
}
for _, name := range []string{
dirArtifact,
dirOutcome,
dirStatus,
} {
if err := root.Mkdir(name, 0755); err != nil {
return err
}
}
var w *os.File
if dents, err := fs.ReadDir(m.fsys, "identifier"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf [2 * len(pkg.Checksum{})]byte
if err = pkg.Decode(
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
name,
); err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirArtifact, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
err = m.writeArtifact(&buf, w, nil)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
if dents, err := fs.ReadDir(m.fsys, "checksum"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf pkg.Checksum
if err = pkg.Decode(&buf, name); err != nil {
return err
}
var fsys fs.FS
fsys, err = fs.Sub(m.fsys, filepath.Join("checksum", name))
if err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirOutcome, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
m.msg.Verbosef("exporting outcome %s", name)
err = pkg.Write(fsys, ".", w)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
if dents, err := fs.ReadDir(m.fsys, "status"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf [2 * len(pkg.Checksum{})]byte
if err = pkg.Decode(
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
name,
); err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirStatus, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
err = m.writeStatus(&buf, w, nil)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
return nil
}
// NewMirror returns a populated [Mirror] for servicing mirror requests.
func NewMirror(
msg message.Msg,
fsys fs.FS,
key ed25519.PrivateKey,
) http.Handler {
) Mirror {
return Mirror{fsys, key, msg}
}
// writeArtifact writes a signed dirArtifact response.
func (m Mirror) writeArtifact(
buf *[2 * len(pkg.Checksum{})]byte,
w io.Writer,
header http.Header,
) error {
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
if linkname, err := fs.ReadLink(m.fsys, filepath.Join(
"identifier",
ids,
)); err != nil {
return err
} else if err = pkg.Decode(
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
filepath.Base(linkname),
); err != nil {
return err
}
m.msg.Verbosef("serving artifact %s", ids)
if header != nil {
header.Set(
"Content-Length",
strconv.Itoa(ed25519.SignatureSize+len(buf)),
)
}
_, err := w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...))
return err
}
// writeOutcome writes a dirOutcome response.
func (m Mirror) writeOutcome(
buf *pkg.Checksum,
w io.Writer,
header http.Header,
) error {
checksums := pkg.Encode(*buf)
rel := filepath.Join("checksum", checksums)
if _, err := fs.Lstat(m.fsys, rel); err != nil {
return err
}
m.msg.Verbosef("serving outcome %s", checksums)
_fsys, err := fs.Sub(m.fsys, rel)
if err != nil {
return err
}
var gw *gzip.Writer
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
return err
}
if header != nil {
header.Set("Content-Encoding", "gzip")
}
if err = pkg.Write(_fsys, ".", gw); err != nil {
_ = gw.Close()
return err
}
return gw.Close()
}
// writeStatus writes a signed dirStatus response.
func (m Mirror) writeStatus(
buf *[2 * len(pkg.Checksum{})]byte,
w io.Writer,
_ http.Header,
) error {
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
f, err := m.fsys.Open(filepath.Join(
"status",
ids,
))
if err != nil {
return err
}
s, ok := f.(io.Seeker)
if !ok {
return &fs.PathError{Op: "seek", Path: ids, Err: fs.ErrInvalid}
}
m.msg.Verbosef("serving status %s", ids)
h := sha512.New384()
if _, err = io.Copy(h, f); err != nil {
_ = f.Close()
return err
}
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
if _, err = w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...)); err != nil {
_ = f.Close()
return err
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
_ = f.Close()
return err
} else if _, err = io.Copy(w, f); err != nil {
_ = f.Close()
return err
}
return f.Close()
}
// writeF is a helper for writing a mirror response with error handling.
func writeF[B any](
m Mirror,
w http.ResponseWriter,
buf B,
f func(
buf B,
w io.Writer,
header http.Header,
) error,
) {
err := f(buf, w, w.Header())
if err == nil {
return
}
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(http.StatusNotFound)
return
}
m.msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
}
// Register configures an [http.ServeMux] for servicing mirror requests.
func (m Mirror) Register(mux *http.ServeMux) {
const identName = "ident"
var mux http.ServeMux
mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func(
w http.ResponseWriter,
@@ -222,38 +470,7 @@ func NewMirror(
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
if linkname, err := fs.ReadLink(fsys, filepath.Join(
"identifier",
ids,
)); err != nil {
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(http.StatusNotFound)
return
}
msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
} else if err = pkg.Decode(
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
filepath.Base(linkname),
); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
msg.Verbosef("serving artifact %s", ids)
w.Header().Set(
"Content-Length",
strconv.Itoa(ed25519.SignatureSize+len(buf)),
)
if _, err := w.Write(append(
ed25519.Sign(key, buf[:]),
buf[:]...,
)); err != nil {
msg.Verbose(err)
}
writeF(m, w, &buf, m.writeArtifact)
})
mux.HandleFunc("/"+dirOutcome+"/{"+identName+"}", func(
@@ -273,40 +490,7 @@ func NewMirror(
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
checksums := pkg.Encode(buf)
rel := filepath.Join("checksum", checksums)
if _, err := fs.Lstat(fsys, rel); err != nil {
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(http.StatusNotFound)
return
}
msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
msg.Verbosef("serving outcome %s", pkg.Encode(buf))
_fsys, err := fs.Sub(fsys, rel)
if err != nil {
msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var gw *gzip.Writer
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Encoding", "gzip")
if err = pkg.Write(_fsys, ".", gw); err != nil {
msg.Verbose(err)
}
if err = gw.Close(); err != nil {
msg.GetLogger().Println(err)
}
writeF(m, w, &buf, m.writeOutcome)
})
mux.HandleFunc("/"+dirStatus+"/{"+identName+"}", func(
@@ -321,47 +505,6 @@ func NewMirror(
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
f, err := fsys.Open(filepath.Join(
"status",
ids,
))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(http.StatusNotFound)
return
}
msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
s, ok := f.(io.Seeker)
if !ok {
msg.GetLogger().Println("backing filesystem does not support seek")
w.WriteHeader(http.StatusInternalServerError)
return
}
msg.Verbosef("serving status %s", ids)
h := sha512.New384()
if _, err = io.Copy(h, f); err != nil {
_ = f.Close()
msg.Verbose(err)
w.WriteHeader(http.StatusInternalServerError)
}
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
if _, err = w.Write(append(ed25519.Sign(key, buf[:]), buf[:]...)); err != nil {
msg.Verbose(err)
return
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
msg.GetLogger().Println(err)
return
} else if _, err = io.Copy(w, f); err != nil {
msg.Verbose(err)
return
}
writeF(m, w, &buf, m.writeStatus)
})
return &mux
}
+7 -4
View File
@@ -4,6 +4,7 @@ import (
"crypto/ed25519"
"io/fs"
"log"
"net/http"
"net/http/httptest"
"os"
"testing"
@@ -30,7 +31,7 @@ func TestMirror(t *testing.T) {
msg.SwapVerbose(testing.Verbose())
var c *pkg.Cache
c, err = pkg.Open(t.Context(), msg, 0, 0, 0, base)
c, err = pkg.Open(t.Context(), msg, base, nil)
if err != nil {
t.Fatal(err)
}
@@ -52,14 +53,16 @@ func TestMirror(t *testing.T) {
}
wantChecksums := pkg.Encode(wantChecksum)
server := httptest.NewServer(rosa.NewMirror(msg, fstest.MapFS{
var mux http.ServeMux
rosa.NewMirror(msg, fstest.MapFS{
"identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)},
"checksum/" + wantChecksums: {Mode: os.ModeDir | 0500},
}, priv))
}, priv).Register(&mux)
server := httptest.NewServer(&mux)
t.Cleanup(server.Close)
var extern pkg.External
extern, err = rosa.NewRemote("http://example.com:80", pub, server.Client())
extern, err = rosa.NewRemote(server.Client(), "http://example.com:80", pub)
if err != nil {
t.Fatal(err)
}
@@ -1,26 +0,0 @@
From 8a80d895dfd779373363c3a4b62ecce5a549efb2 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Sat, 30 Mar 2024 10:17:10 +0100
Subject: tools/attr.c: Add missing libgen.h include for basename(3)
Fixes compilation issue with musl and modern C99 compilers.
See: https://bugs.gentoo.org/926294
---
tools/attr.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/attr.c b/tools/attr.c
index f12e4af..6a3c1e9 100644
--- a/tools/attr.c
+++ b/tools/attr.c
@@ -28,6 +28,7 @@
#include <errno.h>
#include <string.h>
#include <locale.h>
+#include <libgen.h>
#include <attr/attributes.h>
--
cgit v1.1
+4 -4
View File
@@ -1,7 +1,7 @@
diff --git a/test/attr.test b/test/attr.test
index 6ce2f9b..e9bde92 100644
--- a/test/attr.test
+++ b/test/attr.test
diff --git a/test/attr.run b/test/attr.run
index 27d17f6..a4d60c0 100644
--- a/test/attr.run
+++ b/test/attr.run
@@ -11,7 +11,7 @@ Try various valid and invalid names
$ touch f
+13 -13
View File
@@ -3,25 +3,25 @@ package attr {
website = "https://savannah.nongnu.org/projects/attr";
anitya = 137;
version# = "2.5.2";
version# = "2.6.0";
source = remoteTar {
url = "https://download.savannah.nongnu.org/releases/attr/"+
"attr-"+version+".tar.gz";
checksum = "YWEphrz6vg1sUMmHHVr1CRo53pFXRhq_pjN-AlG8UgwZK1y6m7zuDhxqJhD0SV0l";
checksum = "pp-NvD1cMIwZycNwZGW2ez-PbTEpHxrRnVH27csj9QdN4oEBkEbJOZX1IIvKnTWS";
compress = gzip;
};
patches = [
"libgen-basename.patch",
"musl-errno.patch",
];
early = `
ln -s ../../system/bin/perl /usr/bin
`;
patches = [ "musl-errno.patch" ];
bin = [ "perl" ];
populateUsrBin = true;
exec = make {};
inputs = [ perl ];
inputs = [
perl,
kernel-headers,
];
}
package acl {
@@ -29,11 +29,11 @@ package acl {
website = "https://savannah.nongnu.org/projects/acl";
anitya = 16;
version# = "2.3.2";
version# = "2.4.0";
source = remoteTar {
url = "https://download.savannah.nongnu.org/releases/acl/"+
"acl-"+version+".tar.gz";
checksum = "-fY5nwH4K8ZHBCRXrzLdguPkqjKI6WIiGu4dBtrZ1o0t6AIU73w8wwJz_UyjIS0P";
checksum = "U2eaAsWrhhzEfhyprwHQQG55bFPZxtsHk1Usnd9Jb_g-H__pJod4H3RTrL4ipXDw";
compress = gzip;
};
@@ -42,6 +42,6 @@ package acl {
skipCheck = true;
};
inputs = [ attr ];
inputs = [ attr, kernel-headers ];
runtime = [ attr ];
}
+2 -2
View File
@@ -3,12 +3,12 @@ package cmake {
website = "https://cmake.org";
anitya = 306;
version# = "4.3.3";
version# = "4.3.4";
source = remoteGitHubRelease {
suffix = "Kitware/CMake";
tag = "v"+version;
name = "cmake-"+version+".tar.gz";
checksum = "VS-b6cN4S9hfNv3JOUAbAfI9nh3EeuVwY_IVgUdgq6VKwvfchhXwvvFAUcpZG6Ez";
checksum = "6A50pqarKDXKOCv7ffKMvWJWmNTVp_ep8KoaWwNdg-RYQRddgKbxayHveTo6jZ_7";
compress = gzip;
};
patches = [
+2 -2
View File
@@ -3,10 +3,10 @@ package curl {
website = "https://curl.se";
anitya = 381;
version# = "8.20.0";
version# = "8.21.0";
source = remoteTar {
url = "https://curl.se/download/curl-"+version+".tar.bz2";
checksum = "xyHXwrngIRGMasuzhn-I5MSCOhktwINbsWt1f_LuR-5jRVvyx_g6U1EQfDLEbr9r";
checksum = "lJSm8bVjS0OmsarEdbvejdQdvXsb7yGarlr6oMtA9FW1EXOga8zZxa1LPtfaq_qX";
compress = bzip2;
};
+3 -3
View File
@@ -3,12 +3,12 @@ package firmware {
website = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git";
anitya = 141464;
version# = "20260519";
version# = "20260622";
source = remoteGitLab {
domain = "gitlab.com";
suffix = "kernel-firmware/linux-firmware";
ref = version;
checksum = "l-wBRTWclYnJsgV4qtUV1-UL5Y4nknAPre8CMe0dH7PxtAqbaeudEIM_Fnuj0TCV";
checksum = "gpytkDM58EVjaUuryOekcekh_rWsfuv3S7LQxopHlNlVGmMsuqNwfug4BjgTgizE";
};
// dedup creates temporary file
@@ -34,7 +34,7 @@ package firmware {
// requires pre-commit
skipCheck = true;
install = "make " + jobsFlagE + " DESTDIR=/work/system dedup";
install = "make " + jobsFlagE + " " + loadFlagE + " DESTDIR=/work/system dedup";
};
inputs = [
+7 -4
View File
@@ -3,24 +3,25 @@ package git {
website = "https://www.git-scm.com";
anitya = 5350;
version# = "2.54.0";
version# = "2.55.0";
source = remoteTar {
url = "https://www.kernel.org/pub/software/scm/git/"+
"git-"+version+".tar.gz";
checksum = "7vGKtFOJGqY8DO4e8UMRax7dLgImXKQz5MMalec6MlgYrsarffSJjgOughwRFpSH";
checksum = "lOer6jb8vZQk6Nd1rLZIgsYys8whLvjJq8XbmCdTATcPFAYuQcK1Rgj1Jj6a00W8";
compress = gzip;
};
early = `
ln -s ../../system/bin/perl /usr/bin/ || true
# test suite assumes apache
rm -f /system/bin/httpd
`;
// uses source tree as scratch space
enterSource = true;
env = [ "NO_RUST=YesPlease" ];
bin = [ "perl" ];
populateUsrBin = true;
exec = make {
inPlace = true;
generate = "make configure";
@@ -69,6 +70,7 @@ disable_test t5515-fetch-merge-logic
install = `make \
` + jobsFlagE + ` \
` + loadFlagE + ` \
DESTDIR=/work \
NO_INSTALL_HARDLINKS=1 \
install`;
@@ -85,6 +87,7 @@ disable_test t5515-fetch-merge-logic
zlib,
curl,
libexpat,
kernel-headers,
];
runtime = [
+4 -2
View File
@@ -3,11 +3,11 @@ package glib {
website = "https://developer.gnome.org/glib";
anitya = 10024;
version# = "2.89.0";
version# = "2.89.1";
source = remoteGit {
url = "https://gitlab.gnome.org/GNOME/glib.git";
tag = version;
checksum = "4FXKhdS3pC98LevYa_h7piRylG86cZ_c9zAtGr78oHodU1ob8rBxGU0hoIZ4nzcA";
checksum = "9_6Eew2KIwa1AHopjU7CqC13_nur5FPJMu-iGUd7sD_1gAM1pa_HVUuAtqExJoYU";
};
files = {
@@ -19,6 +19,8 @@ package glib {
setup = {
"Ddefault_library": "both";
};
// fails with ipv6 disabled
skipTests = [ "gio" ];
};
inputs = [
+13 -6
View File
@@ -155,6 +155,13 @@ package sed {
compress = gzip;
};
writable = true;
early = `
test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
test_disable '#!/bin/sh' testsuite/read-error-stale-errno.sh
`;
exec = make {};
inputs = [
@@ -363,6 +370,9 @@ test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
test_disable '#!/bin/sh' gnulib-tests/test-c32ispunct.sh
test_disable '#!/bin/sh' tests/ls/hyperlink.sh
test_disable '#!/bin/sh' tests/misc/user.sh
test_disable '#!/bin/sh' tests/split/line-bytes.sh
test_disable '#!/bin/sh' tests/ls/stat-vs-dirent.sh
test_disable '#!/bin/sh' tests/dd/sparse.sh
test_disable 'int main(){return 0;}' gnulib-tests/test-chown.c
test_disable 'int main(){return 0;}' gnulib-tests/test-fchownat.c
test_disable 'int main(){return 0;}' gnulib-tests/test-lchown.c
@@ -504,17 +514,14 @@ package parallel {
website = "https://www.gnu.org/software/parallel";
anitya = 5448;
version# = "20260522";
version# = "20260622";
source = remoteTar {
url = "https://ftpmirror.gnu.org/gnu/parallel/parallel-"+version+".tar.bz2";
checksum = "ezg3NZMlY-q-478YXmjWmDrDlaL55T7aBCuv3B7Z3DkAlfZRQEKO8eumqbcxTIy6";
checksum = "pEkZ_J18AvKCMoPfxEprC0Smw7zP6qXASmC1uFf_HVD_jc95H06LvzGi40-mtCUo";
compress = bzip2;
};
early = `
ln -s ../system/bin/bash /bin/
`;
bin = [ "bash" ];
exec = make {};
inputs = [
+2 -1
View File
@@ -34,7 +34,8 @@ echo 'int main(){return 0;}' > tests/mini-dtls-fragments.c
"with-zstd": "link";
"": arch {
arm64 = "disable-hardware-acceleration";
// miscompilation on arm64
arm64 = "--disable-hardware-acceleration";
};
};
};
+8 -3
View File
@@ -2,11 +2,11 @@ package hakurei-source {
description = "hakurei source tree";
exclude = true;
version# = "0.4.4";
version# = "0.4.5";
output = remoteTar {
url = "https://git.gensokyo.uk/rosa/hakurei/archive/"+
"v"+version+".tar.gz";
checksum = "BCIKpRiVv2tDg8lyX1bG_VgTBBMFCByv726x6DfJ0LiRg5ma4T5fcxYUaQl8JMVB";
checksum = "5bvbuIRcDIrtijogwqXn3y8h5f3rVS4ZSVhOig6Galfzt3g-O3Ufb-tHL1kQCQWK";
compress = gzip;
};
}
@@ -48,8 +48,13 @@ go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
-X hakurei.app/internal/info.buildVersion=$(cat cmd/dist/VERSION)
-X hakurei.app/internal/info.hakureiPath=/system/bin/hakurei
-X hakurei.app/internal/info.hsuPath=/system/bin/hsu
" ./cmd/hakurei ./cmd/sharefs
echo "Building hsu for $(go env GOOS)/$(go env GOARCH)."
CGO_ENABLED=0 go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
-buildid=
-X main.hakureiPath=/system/bin/hakurei
" ./...
" ./cmd/hsu
echo`;
check = `
echo '##### Testing hakurei.'
+2 -2
View File
@@ -3,11 +3,11 @@ package hwdata {
website = "https://github.com/vcrhonek/hwdata";
anitya = 5387;
version# = "0.408";
version# = "0.409";
source = remoteGitHub {
suffix = "vcrhonek/hwdata";
tag = "v"+version;
checksum = "1Rm52ovBb8sZRlA578EKgKSIea9QGgDVSBDETU872BisZTVosQy-OTKkWpzU_ddB";
checksum = "p2qr1_Y9dpjMNnK8OPNcuHSNwZldwb6mtiJ9Nd5HgU8z3L9fixLthnixywU8dd65";
};
writable = true;
-1
View File
@@ -25,7 +25,6 @@ package system-image {
version = unversioned;
exclude = true;
source = earlyinit;
extra = [
musl,
mksh,
+40
View File
@@ -0,0 +1,40 @@
package iana-enterprise-numbers {
description = "IANA Enterprise Numbers";
website = "https://www.iana.org/assignments/enterprise-numbers.txt";
exclude = true;
version# = "20250113140800";
output = remoteFile {
url = "https://web.archive.org/web/"+version+"id_/"+
"https://www.iana.org/assignments/enterprise-numbers.txt";
checksum = "IplVyf7P4PDhhDovWCzL6jPGmF0T75InOCv2IOTMoR7khHUcRfki1pY93kobuXHF";
};
}
package ipmitool {
description = "an open-source tool for controlling IPMI-enabled systems";
website = "https://codeberg.org/IPMITool/ipmitool";
anitya = 1390;
version# = "1_8_19";
source = remoteTar {
url = "https://codeberg.org/IPMITool/ipmitool/archive/"+
"IPMITOOL_"+version+".tar.gz";
checksum = "oxY5S_C2Dl4NhVWtE0BMJtAAxCUgjAwvZm7gzqEzDf0Ina6auYNKztVdM3tclfgT";
compress = gzip;
};
extra = [ iana-enterprise-numbers ];
early = "cp ../extra/iana-enterprise-numbers enterprise-numbers\n";
exec = make {
generate = "./bootstrap";
};
inputs = [
automake,
libtool,
readline,
];
runtime = [ readline ];
}
+2 -2
View File
@@ -3,11 +3,11 @@ package json-c {
website = "https://json-c.github.io/json-c";
anitya = 390279;
version# = "0.18-20240915";
version# = "0.19-20260627";
source = remoteGitHub {
suffix = "json-c/json-c";
tag = "json-c-"+version;
checksum = "LXY6AqXtavysCqcWrniSkgV8fv54iDowsrQ7RXM-upH-ZoJr2R34ff7coFRvOr-k";
checksum = "_yfWLtcd185xgLJaWC63pByFpROncoX7z1kHA02sCqYv2EEKG4YhJqc-8zdgtZ0c";
};
exec = cmake {
@@ -1,493 +0,0 @@
From 6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f Mon Sep 17 00:00:00 2001
From: Nathan Chancellor <nathan@kernel.org>
Date: Sat, 13 Dec 2025 19:58:11 +0900
Subject: drm/amd/display: Reduce number of arguments of dcn30's
CalculateWatermarksAndDRAMSpeedChangeSupport()
CalculateWatermarksAndDRAMSpeedChangeSupport() has a large number of
parameters, which must be passed on the stack. Most of the parameters
between the two callsites are the same, so they can be accessed through
the existing mode_lib pointer, instead of being passed as explicit
arguments. Doing this reduces the stack size of
dml30_ModeSupportAndSystemConfigurationFull() from 1912 bytes to 1840
bytes building for x86_64 with clang-22, helping stay under the 2048
byte limit for display_mode_vba_30.c.
Additionally, now that there is a pointer to mode_lib->vba available,
use 'v' consistently throughout the entire function.
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 563dfbefdf633c8d958398ddfa3955f9f40e47d9)
---
.../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 287 +++++----------------
1 file changed, 66 insertions(+), 221 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
index 2d19bb8de59c84..1df3412be3465d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
@@ -265,62 +265,23 @@ static void CalculateDynamicMetadataParameters(
static void CalculateWatermarksAndDRAMSpeedChangeSupport(
struct display_mode_lib *mode_lib,
unsigned int PrefetchMode,
- unsigned int NumberOfActivePlanes,
- unsigned int MaxLineBufferLines,
- unsigned int LineBufferSize,
- unsigned int DPPOutputBufferPixels,
- unsigned int DETBufferSizeInKByte,
- unsigned int WritebackInterfaceBufferSize,
double DCFCLK,
double ReturnBW,
- bool GPUVMEnable,
- unsigned int dpte_group_bytes[],
- unsigned int MetaChunkSize,
double UrgentLatency,
double ExtraLatency,
- double WritebackLatency,
- double WritebackChunkSize,
double SOCCLK,
- double DRAMClockChangeLatency,
- double SRExitTime,
- double SREnterPlusExitTime,
double DCFCLKDeepSleep,
unsigned int DPPPerPlane[],
- bool DCCEnable[],
double DPPCLK[],
unsigned int DETBufferSizeY[],
unsigned int DETBufferSizeC[],
unsigned int SwathHeightY[],
unsigned int SwathHeightC[],
- unsigned int LBBitPerPixel[],
double SwathWidthY[],
double SwathWidthC[],
- double HRatio[],
- double HRatioChroma[],
- unsigned int vtaps[],
- unsigned int VTAPsChroma[],
- double VRatio[],
- double VRatioChroma[],
- unsigned int HTotal[],
- double PixelClock[],
- unsigned int BlendingAndTiming[],
double BytePerPixelDETY[],
double BytePerPixelDETC[],
- double DSTXAfterScaler[],
- double DSTYAfterScaler[],
- bool WritebackEnable[],
- enum source_format_class WritebackPixelFormat[],
- double WritebackDestinationWidth[],
- double WritebackDestinationHeight[],
- double WritebackSourceHeight[],
- enum clock_change_support *DRAMClockChangeSupport,
- double *UrgentWatermark,
- double *WritebackUrgentWatermark,
- double *DRAMClockChangeWatermark,
- double *WritebackDRAMClockChangeWatermark,
- double *StutterExitWatermark,
- double *StutterEnterPlusExitWatermark,
- double *MinActiveDRAMClockChangeLatencySupported);
+ enum clock_change_support *DRAMClockChangeSupport);
static void CalculateDCFCLKDeepSleep(
struct display_mode_lib *mode_lib,
unsigned int NumberOfActivePlanes,
@@ -2646,62 +2607,23 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
CalculateWatermarksAndDRAMSpeedChangeSupport(
mode_lib,
PrefetchMode,
- v->NumberOfActivePlanes,
- v->MaxLineBufferLines,
- v->LineBufferSize,
- v->DPPOutputBufferPixels,
- v->DETBufferSizeInKByte[0],
- v->WritebackInterfaceBufferSize,
v->DCFCLK,
v->ReturnBW,
- v->GPUVMEnable,
- v->dpte_group_bytes,
- v->MetaChunkSize,
v->UrgentLatency,
v->UrgentExtraLatency,
- v->WritebackLatency,
- v->WritebackChunkSize,
v->SOCCLK,
- v->FinalDRAMClockChangeLatency,
- v->SRExitTime,
- v->SREnterPlusExitTime,
v->DCFCLKDeepSleep,
v->DPPPerPlane,
- v->DCCEnable,
v->DPPCLK,
v->DETBufferSizeY,
v->DETBufferSizeC,
v->SwathHeightY,
v->SwathHeightC,
- v->LBBitPerPixel,
v->SwathWidthY,
v->SwathWidthC,
- v->HRatio,
- v->HRatioChroma,
- v->vtaps,
- v->VTAPsChroma,
- v->VRatio,
- v->VRatioChroma,
- v->HTotal,
- v->PixelClock,
- v->BlendingAndTiming,
v->BytePerPixelDETY,
v->BytePerPixelDETC,
- v->DSTXAfterScaler,
- v->DSTYAfterScaler,
- v->WritebackEnable,
- v->WritebackPixelFormat,
- v->WritebackDestinationWidth,
- v->WritebackDestinationHeight,
- v->WritebackSourceHeight,
- &DRAMClockChangeSupport,
- &v->UrgentWatermark,
- &v->WritebackUrgentWatermark,
- &v->DRAMClockChangeWatermark,
- &v->WritebackDRAMClockChangeWatermark,
- &v->StutterExitWatermark,
- &v->StutterEnterPlusExitWatermark,
- &v->MinActiveDRAMClockChangeLatencySupported);
+ &DRAMClockChangeSupport);
for (k = 0; k < v->NumberOfActivePlanes; ++k) {
if (v->WritebackEnable[k] == true) {
@@ -4895,62 +4817,23 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
CalculateWatermarksAndDRAMSpeedChangeSupport(
mode_lib,
v->PrefetchModePerState[i][j],
- v->NumberOfActivePlanes,
- v->MaxLineBufferLines,
- v->LineBufferSize,
- v->DPPOutputBufferPixels,
- v->DETBufferSizeInKByte[0],
- v->WritebackInterfaceBufferSize,
v->DCFCLKState[i][j],
v->ReturnBWPerState[i][j],
- v->GPUVMEnable,
- v->dpte_group_bytes,
- v->MetaChunkSize,
v->UrgLatency[i],
v->ExtraLatency,
- v->WritebackLatency,
- v->WritebackChunkSize,
v->SOCCLKPerState[i],
- v->FinalDRAMClockChangeLatency,
- v->SRExitTime,
- v->SREnterPlusExitTime,
v->ProjectedDCFCLKDeepSleep[i][j],
v->NoOfDPPThisState,
- v->DCCEnable,
v->RequiredDPPCLKThisState,
v->DETBufferSizeYThisState,
v->DETBufferSizeCThisState,
v->SwathHeightYThisState,
v->SwathHeightCThisState,
- v->LBBitPerPixel,
v->SwathWidthYThisState,
v->SwathWidthCThisState,
- v->HRatio,
- v->HRatioChroma,
- v->vtaps,
- v->VTAPsChroma,
- v->VRatio,
- v->VRatioChroma,
- v->HTotal,
- v->PixelClock,
- v->BlendingAndTiming,
v->BytePerPixelInDETY,
v->BytePerPixelInDETC,
- v->DSTXAfterScaler,
- v->DSTYAfterScaler,
- v->WritebackEnable,
- v->WritebackPixelFormat,
- v->WritebackDestinationWidth,
- v->WritebackDestinationHeight,
- v->WritebackSourceHeight,
- &v->DRAMClockChangeSupport[i][j],
- &v->UrgentWatermark,
- &v->WritebackUrgentWatermark,
- &v->DRAMClockChangeWatermark,
- &v->WritebackDRAMClockChangeWatermark,
- &v->StutterExitWatermark,
- &v->StutterEnterPlusExitWatermark,
- &v->MinActiveDRAMClockChangeLatencySupported);
+ &v->DRAMClockChangeSupport[i][j]);
}
}
@@ -5067,63 +4950,25 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
static void CalculateWatermarksAndDRAMSpeedChangeSupport(
struct display_mode_lib *mode_lib,
unsigned int PrefetchMode,
- unsigned int NumberOfActivePlanes,
- unsigned int MaxLineBufferLines,
- unsigned int LineBufferSize,
- unsigned int DPPOutputBufferPixels,
- unsigned int DETBufferSizeInKByte,
- unsigned int WritebackInterfaceBufferSize,
double DCFCLK,
double ReturnBW,
- bool GPUVMEnable,
- unsigned int dpte_group_bytes[],
- unsigned int MetaChunkSize,
double UrgentLatency,
double ExtraLatency,
- double WritebackLatency,
- double WritebackChunkSize,
double SOCCLK,
- double DRAMClockChangeLatency,
- double SRExitTime,
- double SREnterPlusExitTime,
double DCFCLKDeepSleep,
unsigned int DPPPerPlane[],
- bool DCCEnable[],
double DPPCLK[],
unsigned int DETBufferSizeY[],
unsigned int DETBufferSizeC[],
unsigned int SwathHeightY[],
unsigned int SwathHeightC[],
- unsigned int LBBitPerPixel[],
double SwathWidthY[],
double SwathWidthC[],
- double HRatio[],
- double HRatioChroma[],
- unsigned int vtaps[],
- unsigned int VTAPsChroma[],
- double VRatio[],
- double VRatioChroma[],
- unsigned int HTotal[],
- double PixelClock[],
- unsigned int BlendingAndTiming[],
double BytePerPixelDETY[],
double BytePerPixelDETC[],
- double DSTXAfterScaler[],
- double DSTYAfterScaler[],
- bool WritebackEnable[],
- enum source_format_class WritebackPixelFormat[],
- double WritebackDestinationWidth[],
- double WritebackDestinationHeight[],
- double WritebackSourceHeight[],
- enum clock_change_support *DRAMClockChangeSupport,
- double *UrgentWatermark,
- double *WritebackUrgentWatermark,
- double *DRAMClockChangeWatermark,
- double *WritebackDRAMClockChangeWatermark,
- double *StutterExitWatermark,
- double *StutterEnterPlusExitWatermark,
- double *MinActiveDRAMClockChangeLatencySupported)
+ enum clock_change_support *DRAMClockChangeSupport)
{
+ struct vba_vars_st *v = &mode_lib->vba;
double EffectiveLBLatencyHidingY = 0;
double EffectiveLBLatencyHidingC = 0;
double LinesInDETY[DC__NUM_DPP__MAX] = { 0 };
@@ -5142,101 +4987,101 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
double WritebackDRAMClockChangeLatencyHiding = 0;
unsigned int k, j;
- mode_lib->vba.TotalActiveDPP = 0;
- mode_lib->vba.TotalDCCActiveDPP = 0;
- for (k = 0; k < NumberOfActivePlanes; ++k) {
- mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP + DPPPerPlane[k];
- if (DCCEnable[k] == true) {
- mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP + DPPPerPlane[k];
+ v->TotalActiveDPP = 0;
+ v->TotalDCCActiveDPP = 0;
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ v->TotalActiveDPP = v->TotalActiveDPP + DPPPerPlane[k];
+ if (v->DCCEnable[k] == true) {
+ v->TotalDCCActiveDPP = v->TotalDCCActiveDPP + DPPPerPlane[k];
}
}
- *UrgentWatermark = UrgentLatency + ExtraLatency;
+ v->UrgentWatermark = UrgentLatency + ExtraLatency;
- *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark;
+ v->DRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->UrgentWatermark;
- mode_lib->vba.TotalActiveWriteback = 0;
- for (k = 0; k < NumberOfActivePlanes; ++k) {
- if (WritebackEnable[k] == true) {
- mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1;
+ v->TotalActiveWriteback = 0;
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ if (v->WritebackEnable[k] == true) {
+ v->TotalActiveWriteback = v->TotalActiveWriteback + 1;
}
}
- if (mode_lib->vba.TotalActiveWriteback <= 1) {
- *WritebackUrgentWatermark = WritebackLatency;
+ if (v->TotalActiveWriteback <= 1) {
+ v->WritebackUrgentWatermark = v->WritebackLatency;
} else {
- *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+ v->WritebackUrgentWatermark = v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
}
- if (mode_lib->vba.TotalActiveWriteback <= 1) {
- *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency;
+ if (v->TotalActiveWriteback <= 1) {
+ v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency;
} else {
- *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
+ v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
}
- for (k = 0; k < NumberOfActivePlanes; ++k) {
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
- mode_lib->vba.LBLatencyHidingSourceLinesY = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1);
+ v->LBLatencyHidingSourceLinesY = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1);
- mode_lib->vba.LBLatencyHidingSourceLinesC = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1);
+ v->LBLatencyHidingSourceLinesC = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1);
- EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]);
+ EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]);
- EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]);
+ EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]);
LinesInDETY[k] = (double) DETBufferSizeY[k] / BytePerPixelDETY[k] / SwathWidthY[k];
LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]);
- FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k];
+ FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
if (BytePerPixelDETC[k] > 0) {
- LinesInDETC = mode_lib->vba.DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
+ LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]);
- FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k];
+ FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (v->HTotal[k] / v->PixelClock[k]) / v->VRatioChroma[k];
} else {
LinesInDETC = 0;
FullDETBufferingTimeC = 999999;
}
- ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark;
+ ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark;
- if (NumberOfActivePlanes > 1) {
- ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k];
+ if (v->NumberOfActivePlanes > 1) {
+ ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightY[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatio[k];
}
if (BytePerPixelDETC[k] > 0) {
- ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark;
+ ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark;
- if (NumberOfActivePlanes > 1) {
- ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k];
+ if (v->NumberOfActivePlanes > 1) {
+ ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightC[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatioChroma[k];
}
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC);
+ v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC);
} else {
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY;
+ v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY;
}
- if (WritebackEnable[k] == true) {
+ if (v->WritebackEnable[k] == true) {
- WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024 / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4);
- if (WritebackPixelFormat[k] == dm_444_64) {
+ WritebackDRAMClockChangeLatencyHiding = v->WritebackInterfaceBufferSize * 1024 / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4);
+ if (v->WritebackPixelFormat[k] == dm_444_64) {
WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2;
}
- if (mode_lib->vba.WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) {
+ if (v->WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) {
WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding * 2;
}
- WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - mode_lib->vba.WritebackDRAMClockChangeWatermark;
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin);
+ WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark;
+ v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(v->ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin);
}
}
- mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999;
+ v->MinActiveDRAMClockChangeMargin = 999999;
PlaneWithMinActiveDRAMClockChangeMargin = 0;
- for (k = 0; k < NumberOfActivePlanes; ++k) {
- if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < mode_lib->vba.MinActiveDRAMClockChangeMargin) {
- mode_lib->vba.MinActiveDRAMClockChangeMargin = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k];
- if (BlendingAndTiming[k] == k) {
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) {
+ v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k];
+ if (v->BlendingAndTiming[k] == k) {
PlaneWithMinActiveDRAMClockChangeMargin = k;
} else {
- for (j = 0; j < NumberOfActivePlanes; ++j) {
- if (BlendingAndTiming[k] == j) {
+ for (j = 0; j < v->NumberOfActivePlanes; ++j) {
+ if (v->BlendingAndTiming[k] == j) {
PlaneWithMinActiveDRAMClockChangeMargin = j;
}
}
@@ -5244,40 +5089,40 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
}
}
- *MinActiveDRAMClockChangeLatencySupported = mode_lib->vba.MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency;
+ v->MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + v->FinalDRAMClockChangeLatency;
SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999;
- for (k = 0; k < NumberOfActivePlanes; ++k) {
- if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) {
- SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k];
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (v->BlendingAndTiming[k] == k)) && !(v->BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) {
+ SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k];
}
}
- mode_lib->vba.TotalNumberOfActiveOTG = 0;
- for (k = 0; k < NumberOfActivePlanes; ++k) {
- if (BlendingAndTiming[k] == k) {
- mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG + 1;
+ v->TotalNumberOfActiveOTG = 0;
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ if (v->BlendingAndTiming[k] == k) {
+ v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1;
}
}
- if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) {
+ if (v->MinActiveDRAMClockChangeMargin > 0) {
*DRAMClockChangeSupport = dm_dram_clock_change_vactive;
- } else if (((mode_lib->vba.SynchronizedVBlank == true || mode_lib->vba.TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) {
+ } else if (((v->SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) {
*DRAMClockChangeSupport = dm_dram_clock_change_vblank;
} else {
*DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
}
FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[0];
- for (k = 0; k < NumberOfActivePlanes; ++k) {
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
if (FullDETBufferingTimeY[k] <= FullDETBufferingTimeYStutterCriticalPlane) {
FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[k];
- TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (HTotal[k] / PixelClock[k]) / VRatio[k];
+ TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
}
}
- *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
- *StutterEnterPlusExitWatermark = dml_max(SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane);
+ v->StutterExitWatermark = v->SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
+ v->StutterEnterPlusExitWatermark = dml_max(v->SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane);
}
--
cgit 1.2.3-korg
@@ -1,606 +0,0 @@
From f54a91f5337cd918eb86cf600320d25b6cfd8209 Mon Sep 17 00:00:00 2001
From: Nathan Chancellor <nathan@kernel.org>
Date: Sat, 13 Dec 2025 19:58:10 +0900
Subject: drm/amd/display: Reduce number of arguments of dcn30's
CalculatePrefetchSchedule()
After an innocuous optimization change in clang-22,
dml30_ModeSupportAndSystemConfigurationFull() is over the 2048 byte
stack limit for display_mode_vba_30.c.
drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (2096) exceeds limit (2048) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than]
3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
| ^
With clang-21, this function was already close to the limit:
drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (1912) exceeds limit (1586) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than]
3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
| ^
CalculatePrefetchSchedule() has a large number of parameters, which must
be passed on the stack. Most of the parameters between the two callsites
are the same, so they can be accessed through the existing mode_lib
pointer, instead of being passed as explicit arguments. Doing this
reduces the stack size of dml30_ModeSupportAndSystemConfigurationFull()
from 2096 bytes to 1912 bytes with clang-22.
Closes: https://github.com/ClangBuiltLinux/linux/issues/2117
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit b20b3fc4210f83089f835cdb91deec4b0778761a)
---
.../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 258 ++++++---------------
1 file changed, 73 insertions(+), 185 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
index abe51cf3aab2..a244504cc1f2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
@@ -77,32 +77,14 @@ static unsigned int dscceComputeDelay(
static unsigned int dscComputeDelay(
enum output_format_class pixelFormat,
enum output_encoder_class Output);
-// Super monster function with some 45 argument
static bool CalculatePrefetchSchedule(
struct display_mode_lib *mode_lib,
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
+ unsigned int k,
Pipe *myPipe,
unsigned int DSCDelay,
- double DPPCLKDelaySubtotalPlusCNVCFormater,
- double DPPCLKDelaySCL,
- double DPPCLKDelaySCLLBOnly,
- double DPPCLKDelayCNVCCursor,
- double DISPCLKDelaySubtotal,
unsigned int DPP_RECOUT_WIDTH,
- enum output_format_class OutputFormat,
- unsigned int MaxInterDCNTileRepeaters,
unsigned int VStartup,
unsigned int MaxVStartup,
- unsigned int GPUVMPageTableLevels,
- bool GPUVMEnable,
- bool HostVMEnable,
- unsigned int HostVMMaxNonCachedPageTableLevels,
- double HostVMMinPageSize,
- bool DynamicMetadataEnable,
- bool DynamicMetadataVMEnabled,
- int DynamicMetadataLinesBeforeActiveRequired,
- unsigned int DynamicMetadataTransmittedBytes,
double UrgentLatency,
double UrgentExtraLatency,
double TCalc,
@@ -116,7 +98,6 @@ static bool CalculatePrefetchSchedule(
unsigned int MaxNumSwathY,
double PrefetchSourceLinesC,
unsigned int SwathWidthC,
- int BytePerPixelC,
double VInitPreFillC,
unsigned int MaxNumSwathC,
long swath_width_luma_ub,
@@ -124,9 +105,6 @@ static bool CalculatePrefetchSchedule(
unsigned int SwathHeightY,
unsigned int SwathHeightC,
double TWait,
- bool ProgressiveToInterlaceUnitInOPP,
- double *DSTXAfterScaler,
- double *DSTYAfterScaler,
double *DestinationLinesForPrefetch,
double *PrefetchBandwidth,
double *DestinationLinesToRequestVMInVBlank,
@@ -135,14 +113,7 @@ static bool CalculatePrefetchSchedule(
double *VRatioPrefetchC,
double *RequiredPrefetchPixDataBWLuma,
double *RequiredPrefetchPixDataBWChroma,
- bool *NotEnoughTimeForDynamicMetadata,
- double *Tno_bw,
- double *prefetch_vmrow_bw,
- double *Tdmdl_vm,
- double *Tdmdl,
- unsigned int *VUpdateOffsetPix,
- double *VUpdateWidthPix,
- double *VReadyOffsetPix);
+ bool *NotEnoughTimeForDynamicMetadata);
static double RoundToDFSGranularityUp(double Clock, double VCOSpeed);
static double RoundToDFSGranularityDown(double Clock, double VCOSpeed);
static void CalculateDCCConfiguration(
@@ -810,29 +781,12 @@ static unsigned int dscComputeDelay(enum output_format_class pixelFormat, enum o
static bool CalculatePrefetchSchedule(
struct display_mode_lib *mode_lib,
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
+ unsigned int k,
Pipe *myPipe,
unsigned int DSCDelay,
- double DPPCLKDelaySubtotalPlusCNVCFormater,
- double DPPCLKDelaySCL,
- double DPPCLKDelaySCLLBOnly,
- double DPPCLKDelayCNVCCursor,
- double DISPCLKDelaySubtotal,
unsigned int DPP_RECOUT_WIDTH,
- enum output_format_class OutputFormat,
- unsigned int MaxInterDCNTileRepeaters,
unsigned int VStartup,
unsigned int MaxVStartup,
- unsigned int GPUVMPageTableLevels,
- bool GPUVMEnable,
- bool HostVMEnable,
- unsigned int HostVMMaxNonCachedPageTableLevels,
- double HostVMMinPageSize,
- bool DynamicMetadataEnable,
- bool DynamicMetadataVMEnabled,
- int DynamicMetadataLinesBeforeActiveRequired,
- unsigned int DynamicMetadataTransmittedBytes,
double UrgentLatency,
double UrgentExtraLatency,
double TCalc,
@@ -846,7 +800,6 @@ static bool CalculatePrefetchSchedule(
unsigned int MaxNumSwathY,
double PrefetchSourceLinesC,
unsigned int SwathWidthC,
- int BytePerPixelC,
double VInitPreFillC,
unsigned int MaxNumSwathC,
long swath_width_luma_ub,
@@ -854,9 +807,6 @@ static bool CalculatePrefetchSchedule(
unsigned int SwathHeightY,
unsigned int SwathHeightC,
double TWait,
- bool ProgressiveToInterlaceUnitInOPP,
- double *DSTXAfterScaler,
- double *DSTYAfterScaler,
double *DestinationLinesForPrefetch,
double *PrefetchBandwidth,
double *DestinationLinesToRequestVMInVBlank,
@@ -865,15 +815,10 @@ static bool CalculatePrefetchSchedule(
double *VRatioPrefetchC,
double *RequiredPrefetchPixDataBWLuma,
double *RequiredPrefetchPixDataBWChroma,
- bool *NotEnoughTimeForDynamicMetadata,
- double *Tno_bw,
- double *prefetch_vmrow_bw,
- double *Tdmdl_vm,
- double *Tdmdl,
- unsigned int *VUpdateOffsetPix,
- double *VUpdateWidthPix,
- double *VReadyOffsetPix)
+ bool *NotEnoughTimeForDynamicMetadata)
{
+ struct vba_vars_st *v = &mode_lib->vba;
+ double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater;
bool MyError = false;
unsigned int DPPCycles = 0, DISPCLKCycles = 0;
double DSTTotalPixelsAfterScaler = 0;
@@ -905,26 +850,26 @@ static bool CalculatePrefetchSchedule(
double Tdmec = 0;
double Tdmsks = 0;
- if (GPUVMEnable == true && HostVMEnable == true) {
- HostVMInefficiencyFactor = PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly;
- HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels;
+ if (v->GPUVMEnable == true && v->HostVMEnable == true) {
+ HostVMInefficiencyFactor = v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly;
+ HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels;
} else {
HostVMInefficiencyFactor = 1;
HostVMDynamicLevelsTrips = 0;
}
CalculateDynamicMetadataParameters(
- MaxInterDCNTileRepeaters,
+ v->MaxInterDCNTileRepeaters,
myPipe->DPPCLK,
myPipe->DISPCLK,
myPipe->DCFCLKDeepSleep,
myPipe->PixelClock,
myPipe->HTotal,
myPipe->VBlank,
- DynamicMetadataTransmittedBytes,
- DynamicMetadataLinesBeforeActiveRequired,
+ v->DynamicMetadataTransmittedBytes[k],
+ v->DynamicMetadataLinesBeforeActiveRequired[k],
myPipe->InterlaceEnable,
- ProgressiveToInterlaceUnitInOPP,
+ v->ProgressiveToInterlaceUnitInOPP,
&Tsetup,
&Tdmbf,
&Tdmec,
@@ -932,16 +877,16 @@ static bool CalculatePrefetchSchedule(
LineTime = myPipe->HTotal / myPipe->PixelClock;
trip_to_mem = UrgentLatency;
- Tvm_trips = UrgentExtraLatency + trip_to_mem * (GPUVMPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1);
+ Tvm_trips = UrgentExtraLatency + trip_to_mem * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1);
- if (DynamicMetadataVMEnabled == true && GPUVMEnable == true) {
- *Tdmdl = TWait + Tvm_trips + trip_to_mem;
+ if (v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true) {
+ v->Tdmdl[k] = TWait + Tvm_trips + trip_to_mem;
} else {
- *Tdmdl = TWait + UrgentExtraLatency;
+ v->Tdmdl[k] = TWait + UrgentExtraLatency;
}
- if (DynamicMetadataEnable == true) {
- if (VStartup * LineTime < Tsetup + *Tdmdl + Tdmbf + Tdmec + Tdmsks) {
+ if (v->DynamicMetadataEnable[k] == true) {
+ if (VStartup * LineTime < Tsetup + v->Tdmdl[k] + Tdmbf + Tdmec + Tdmsks) {
*NotEnoughTimeForDynamicMetadata = true;
} else {
*NotEnoughTimeForDynamicMetadata = false;
@@ -949,39 +894,39 @@ static bool CalculatePrefetchSchedule(
dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf);
dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec);
dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks);
- dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl);
+ dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]);
}
} else {
*NotEnoughTimeForDynamicMetadata = false;
}
- *Tdmdl_vm = (DynamicMetadataEnable == true && DynamicMetadataVMEnabled == true && GPUVMEnable == true ? TWait + Tvm_trips : 0);
+ v->Tdmdl_vm[k] = (v->DynamicMetadataEnable[k] == true && v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true ? TWait + Tvm_trips : 0);
if (myPipe->ScalerEnabled)
- DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCL;
+ DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCL;
else
- DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCLLBOnly;
+ DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCLLBOnly;
- DPPCycles = DPPCycles + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor;
+ DPPCycles = DPPCycles + myPipe->NumberOfCursors * v->DPPCLKDelayCNVCCursor;
- DISPCLKCycles = DISPCLKDelaySubtotal;
+ DISPCLKCycles = v->DISPCLKDelaySubtotal;
if (myPipe->DPPCLK == 0.0 || myPipe->DISPCLK == 0.0)
return true;
- *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK
+ v->DSTXAfterScaler[k] = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK
+ DSCDelay;
- *DSTXAfterScaler = *DSTXAfterScaler + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH;
+ v->DSTXAfterScaler[k] = v->DSTXAfterScaler[k] + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH;
- if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && ProgressiveToInterlaceUnitInOPP))
- *DSTYAfterScaler = 1;
+ if (v->OutputFormat[k] == dm_420 || (myPipe->InterlaceEnable && v->ProgressiveToInterlaceUnitInOPP))
+ v->DSTYAfterScaler[k] = 1;
else
- *DSTYAfterScaler = 0;
+ v->DSTYAfterScaler[k] = 0;
- DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler;
- *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
- *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal));
+ DSTTotalPixelsAfterScaler = v->DSTYAfterScaler[k] * myPipe->HTotal + v->DSTXAfterScaler[k];
+ v->DSTYAfterScaler[k] = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
+ v->DSTXAfterScaler[k] = DSTTotalPixelsAfterScaler - ((double) (v->DSTYAfterScaler[k] * myPipe->HTotal));
MyError = false;
@@ -990,32 +935,32 @@ static bool CalculatePrefetchSchedule(
Tvm_trips_rounded = dml_ceil(4.0 * Tvm_trips / LineTime, 1) / 4 * LineTime;
Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1) / 4 * LineTime;
- if (GPUVMEnable) {
- if (GPUVMPageTableLevels >= 3) {
- *Tno_bw = UrgentExtraLatency + trip_to_mem * ((GPUVMPageTableLevels - 2) - 1);
+ if (v->GPUVMEnable) {
+ if (v->GPUVMMaxPageTableLevels >= 3) {
+ v->Tno_bw[k] = UrgentExtraLatency + trip_to_mem * ((v->GPUVMMaxPageTableLevels - 2) - 1);
} else
- *Tno_bw = 0;
+ v->Tno_bw[k] = 0;
} else if (!myPipe->DCCEnable)
- *Tno_bw = LineTime;
+ v->Tno_bw[k] = LineTime;
else
- *Tno_bw = LineTime / 4;
+ v->Tno_bw[k] = LineTime / 4;
- dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime
- - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal);
+ dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, v->Tdmdl[k])) / LineTime
+ - (v->DSTYAfterScaler[k] + v->DSTXAfterScaler[k] / myPipe->HTotal);
Lsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC);
Tsw_oto = Lsw_oto * LineTime;
- prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC) / Tsw_oto;
+ prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k]) / Tsw_oto;
- if (GPUVMEnable == true) {
- Tvm_oto = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto,
+ if (v->GPUVMEnable == true) {
+ Tvm_oto = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto,
Tvm_trips,
LineTime / 4.0);
} else
Tvm_oto = LineTime / 4.0;
- if ((GPUVMEnable == true || myPipe->DCCEnable == true)) {
+ if ((v->GPUVMEnable == true || myPipe->DCCEnable == true)) {
Tr0_oto = dml_max3(
(MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto,
LineTime - Tvm_oto, LineTime / 4);
@@ -1041,10 +986,10 @@ static bool CalculatePrefetchSchedule(
dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf);
dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec);
dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks);
- dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", *Tdmdl_vm);
- dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl);
- dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", *DSTXAfterScaler);
- dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)*DSTYAfterScaler);
+ dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", v->Tdmdl_vm[k]);
+ dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]);
+ dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", v->DSTXAfterScaler[k]);
+ dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)v->DSTYAfterScaler[k]);
*PrefetchBandwidth = 0;
*DestinationLinesToRequestVMInVBlank = 0;
@@ -1058,26 +1003,26 @@ static bool CalculatePrefetchSchedule(
double PrefetchBandwidth3 = 0;
double PrefetchBandwidth4 = 0;
- if (Tpre_rounded - *Tno_bw > 0)
+ if (Tpre_rounded - v->Tno_bw[k] > 0)
PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte
+ 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor
+ PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY
- + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC)
- / (Tpre_rounded - *Tno_bw);
+ + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k])
+ / (Tpre_rounded - v->Tno_bw[k]);
else
PrefetchBandwidth1 = 0;
- if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw) > 0) {
- PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw);
+ if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]) > 0) {
+ PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]);
}
- if (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded > 0)
+ if (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded > 0)
PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame *
HostVMInefficiencyFactor + PrefetchSourceLinesY *
swath_width_luma_ub * BytePerPixelY +
PrefetchSourceLinesC * swath_width_chroma_ub *
- BytePerPixelC) /
- (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded);
+ v->BytePerPixelC[k]) /
+ (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded);
else
PrefetchBandwidth2 = 0;
@@ -1085,7 +1030,7 @@ static bool CalculatePrefetchSchedule(
PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow *
HostVMInefficiencyFactor + PrefetchSourceLinesY *
swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC *
- swath_width_chroma_ub * BytePerPixelC) / (Tpre_rounded -
+ swath_width_chroma_ub * v->BytePerPixelC[k]) / (Tpre_rounded -
Tvm_trips_rounded);
else
PrefetchBandwidth3 = 0;
@@ -1095,7 +1040,7 @@ static bool CalculatePrefetchSchedule(
}
if (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded > 0)
- PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC)
+ PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k])
/ (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded);
else
PrefetchBandwidth4 = 0;
@@ -1106,7 +1051,7 @@ static bool CalculatePrefetchSchedule(
bool Case3OK;
if (PrefetchBandwidth1 > 0) {
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1
>= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth1 >= Tr0_trips_rounded) {
Case1OK = true;
} else {
@@ -1117,7 +1062,7 @@ static bool CalculatePrefetchSchedule(
}
if (PrefetchBandwidth2 > 0) {
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2
>= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth2 < Tr0_trips_rounded) {
Case2OK = true;
} else {
@@ -1128,7 +1073,7 @@ static bool CalculatePrefetchSchedule(
}
if (PrefetchBandwidth3 > 0) {
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3
< Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth3 >= Tr0_trips_rounded) {
Case3OK = true;
} else {
@@ -1151,13 +1096,13 @@ static bool CalculatePrefetchSchedule(
dml_print("DML: prefetch_bw_equ: %f\n", prefetch_bw_equ);
if (prefetch_bw_equ > 0) {
- if (GPUVMEnable) {
- Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4);
+ if (v->GPUVMEnable) {
+ Tvm_equ = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4);
} else {
Tvm_equ = LineTime / 4;
}
- if ((GPUVMEnable || myPipe->DCCEnable)) {
+ if ((v->GPUVMEnable || myPipe->DCCEnable)) {
Tr0_equ = dml_max4(
(MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_equ,
Tr0_trips,
@@ -1226,7 +1171,7 @@ static bool CalculatePrefetchSchedule(
}
*RequiredPrefetchPixDataBWLuma = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData * BytePerPixelY * swath_width_luma_ub / LineTime;
- *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * BytePerPixelC * swath_width_chroma_ub / LineTime;
+ *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * v->BytePerPixelC[k] * swath_width_chroma_ub / LineTime;
} else {
MyError = true;
dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__);
@@ -1242,9 +1187,9 @@ static bool CalculatePrefetchSchedule(
dml_print("DML: Tr0: %fus - time to fetch first row of data pagetables and first row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank);
dml_print("DML: Tr1: %fus - time to fetch second row of data pagetables and second row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank);
dml_print("DML: Tsw: %fus = time to fetch enough pixel data and cursor data to feed the scalers init position and detile\n", (double)LinesToRequestPrefetchPixelData * LineTime);
- dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime);
+ dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime);
dml_print("DML: Tvstartup - Tsetup - Tcalc - Twait - Tpre - To > 0\n");
- dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup);
+ dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup);
dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n", PixelPTEBytesPerRow);
} else {
@@ -1275,7 +1220,7 @@ static bool CalculatePrefetchSchedule(
dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__);
}
- *prefetch_vmrow_bw = dml_max(prefetch_vm_bw, prefetch_row_bw);
+ v->prefetch_vmrow_bw[k] = dml_max(prefetch_vm_bw, prefetch_row_bw);
}
if (MyError) {
@@ -2448,30 +2393,12 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->ErrorResult[k] = CalculatePrefetchSchedule(
mode_lib,
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
+ k,
&myPipe,
v->DSCDelay[k],
- v->DPPCLKDelaySubtotal
- + v->DPPCLKDelayCNVCFormater,
- v->DPPCLKDelaySCL,
- v->DPPCLKDelaySCLLBOnly,
- v->DPPCLKDelayCNVCCursor,
- v->DISPCLKDelaySubtotal,
(unsigned int) (v->SwathWidthY[k] / v->HRatio[k]),
- v->OutputFormat[k],
- v->MaxInterDCNTileRepeaters,
dml_min(v->VStartupLines, v->MaxVStartupLines[k]),
v->MaxVStartupLines[k],
- v->GPUVMMaxPageTableLevels,
- v->GPUVMEnable,
- v->HostVMEnable,
- v->HostVMMaxNonCachedPageTableLevels,
- v->HostVMMinPageSize,
- v->DynamicMetadataEnable[k],
- v->DynamicMetadataVMEnabled,
- v->DynamicMetadataLinesBeforeActiveRequired[k],
- v->DynamicMetadataTransmittedBytes[k],
v->UrgentLatency,
v->UrgentExtraLatency,
v->TCalc,
@@ -2485,7 +2412,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->MaxNumSwathY[k],
v->PrefetchSourceLinesC[k],
v->SwathWidthC[k],
- v->BytePerPixelC[k],
v->VInitPreFillC[k],
v->MaxNumSwathC[k],
v->swath_width_luma_ub[k],
@@ -2493,9 +2419,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->SwathHeightY[k],
v->SwathHeightC[k],
TWait,
- v->ProgressiveToInterlaceUnitInOPP,
- &v->DSTXAfterScaler[k],
- &v->DSTYAfterScaler[k],
&v->DestinationLinesForPrefetch[k],
&v->PrefetchBandwidth[k],
&v->DestinationLinesToRequestVMInVBlank[k],
@@ -2504,14 +2427,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
&v->VRatioPrefetchC[k],
&v->RequiredPrefetchPixDataBWLuma[k],
&v->RequiredPrefetchPixDataBWChroma[k],
- &v->NotEnoughTimeForDynamicMetadata[k],
- &v->Tno_bw[k],
- &v->prefetch_vmrow_bw[k],
- &v->Tdmdl_vm[k],
- &v->Tdmdl[k],
- &v->VUpdateOffsetPix[k],
- &v->VUpdateWidthPix[k],
- &v->VReadyOffsetPix[k]);
+ &v->NotEnoughTimeForDynamicMetadata[k]);
if (v->BlendingAndTiming[k] == k) {
double TotalRepeaterDelayTime = v->MaxInterDCNTileRepeaters * (2 / v->DPPCLK[k] + 3 / v->DISPCLK);
v->VUpdateWidthPix[k] = (14 / v->DCFCLKDeepSleep + 12 / v->DPPCLK[k] + TotalRepeaterDelayTime) * v->PixelClock[k];
@@ -4781,29 +4697,12 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->NoTimeForPrefetch[i][j][k] = CalculatePrefetchSchedule(
mode_lib,
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
+ k,
&myPipe,
v->DSCDelayPerState[i][k],
- v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater,
- v->DPPCLKDelaySCL,
- v->DPPCLKDelaySCLLBOnly,
- v->DPPCLKDelayCNVCCursor,
- v->DISPCLKDelaySubtotal,
v->SwathWidthYThisState[k] / v->HRatio[k],
- v->OutputFormat[k],
- v->MaxInterDCNTileRepeaters,
dml_min(v->MaxVStartup, v->MaximumVStartup[i][j][k]),
v->MaximumVStartup[i][j][k],
- v->GPUVMMaxPageTableLevels,
- v->GPUVMEnable,
- v->HostVMEnable,
- v->HostVMMaxNonCachedPageTableLevels,
- v->HostVMMinPageSize,
- v->DynamicMetadataEnable[k],
- v->DynamicMetadataVMEnabled,
- v->DynamicMetadataLinesBeforeActiveRequired[k],
- v->DynamicMetadataTransmittedBytes[k],
v->UrgLatency[i],
v->ExtraLatency,
v->TimeCalc,
@@ -4817,7 +4716,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->MaxNumSwY[k],
v->PrefetchLinesC[i][j][k],
v->SwathWidthCThisState[k],
- v->BytePerPixelC[k],
v->PrefillC[k],
v->MaxNumSwC[k],
v->swath_width_luma_ub_this_state[k],
@@ -4825,9 +4723,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
v->SwathHeightYThisState[k],
v->SwathHeightCThisState[k],
v->TWait,
- v->ProgressiveToInterlaceUnitInOPP,
- &v->DSTXAfterScaler[k],
- &v->DSTYAfterScaler[k],
&v->LineTimesForPrefetch[k],
&v->PrefetchBW[k],
&v->LinesForMetaPTE[k],
@@ -4836,14 +4731,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
&v->VRatioPreC[i][j][k],
&v->RequiredPrefetchPixelDataBWLuma[i][j][k],
&v->RequiredPrefetchPixelDataBWChroma[i][j][k],
- &v->NoTimeForDynamicMetadata[i][j][k],
- &v->Tno_bw[k],
- &v->prefetch_vmrow_bw[k],
- &v->Tdmdl_vm[k],
- &v->Tdmdl[k],
- &v->VUpdateOffsetPix[k],
- &v->VUpdateWidthPix[k],
- &v->VReadyOffsetPix[k]);
+ &v->NoTimeForDynamicMetadata[i][j][k]);
}
for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) {
--
cgit 1.2.3-korg
+11 -13
View File
@@ -3,11 +3,11 @@ package kernel-source {
website = "https://kernel.org";
exclude = true;
version# = "6.12.93";
version# = "6.18.38";
output = remoteTar {
url = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
"snapshot/linux-"+version+".tar.gz";
checksum = "cGFcgR-h4Vwv2BU78jV4HmU-3yU_ER8l8LyKF0MibEsB-kUbbrIgqxMedXZ1j8Xw";
checksum = "y_c897Efibj3TxgJQfpfTOWHTEoBPqu-XLwl2c40THwfgiNAop3qusrGvQkThXtI";
compress = gzip;
};
}
@@ -45,9 +45,9 @@ cat \
checksum = arch {
default = "";
amd64 = "Oy3soh5GNJr4JU7lk85J49LgNw-44SGpNB6NVlPp_mFUaXxvIGt1KLPnlpU3JYcB";
arm64 = "GKHHQepUpwQjsSiq47-HV1G_aRR12oasaO5dV2bjc3D-4UzE9-Mb92ptplQQhSEc";
riscv64 = "YwNZiSwm6EnTyCmKe-RMLhFHD7VuJoVjD6XnqywaB3e-Vk0rEWxsAxoNkCvxbXz9";
amd64 = "UscduTw49AOk4CL6gLS6yORPFiHO79h1kFZKXKDaUI9j0x5CySi7P2Ywf29gYBsM";
arm64 = "FM5-YFUbkOiux1KMxU29pecCoq6kPUfSL_4JlfqRHe4ZxIiT1AELGt7liD6df3-K";
riscv64 = "Z1jR7S3nnGYOJtOR3sOMznfmkD_TirHP7-f3tVcgkVzWzHvMXS7ElHLT1NExqcqa";
};
inputs = [ rsync ];
}
@@ -55,18 +55,14 @@ cat \
package kernel {
description = "the generic Rosa OS linux kernel";
website = "https://kernel.org";
anitya = 375621;
anitya = 389470;
source = kernel-source;
patches = [
"f54a91f5337cd918eb86cf600320d25b6cfd8209.patch",
"6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f.patch",
];
files = {
".config": arch {
amd64 = "kernel_amd64.config";
arm64 = "kernel_arm64.config";
riscv64 = "kernel_riscv64.config";
amd64 = "amd64.config";
arm64 = "arm64.config";
riscv64 = "riscv64.config";
};
".installkernel": "installkernel";
@@ -115,6 +111,7 @@ install -Dm0500 \
make \
` + jobsFlagE + ` \
` + loadFlagE + ` \
-f /usr/src/kernel/Makefile \
O=/tmp/kbuild \
LLVM=1 \
@@ -138,6 +135,7 @@ rm -v "/work/system/lib/modules/$(make -f /usr/src/kernel/Makefile kernelversion
gawk,
coreutils,
diffutils,
bash,
python,
xz,
+3 -3
View File
@@ -1,5 +1,5 @@
#define LINUX_VERSION_CODE 396378
#define LINUX_VERSION_CODE 397861
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
#define LINUX_VERSION_MAJOR 6
#define LINUX_VERSION_PATCHLEVEL 12
#define LINUX_VERSION_SUBLEVEL 90
#define LINUX_VERSION_PATCHLEVEL 18
#define LINUX_VERSION_SUBLEVEL 37
+2 -2
View File
@@ -3,11 +3,11 @@ package libarchive {
website = "https://www.libarchive.org";
anitya = 1558;
version# = "3.8.7";
version# = "3.8.8";
source = remoteGitHub {
suffix = "libarchive/libarchive";
tag = "v"+version;
checksum = "CUJK4MDQmZmATClgQBH2Wt-7Ts4iiSUlg1J_TVb6-5IK3rVUgVLIMc5k-bnWB9w3";
checksum = "MYlQdlxHX14rFL_zEYvDArKgGVIueTPzSEDgCzaZkmi0_N7WsaEpogGO3qnHpfTc";
};
files = { "CTestCustom.cmake"; };
+2 -2
View File
@@ -12,6 +12,7 @@ package libcap {
};
// uses source tree as scratch space
enterSource = true;
writable = true;
chmod = true;
@@ -20,8 +21,7 @@ package libcap {
"lib=lib",
];
early = "\nln -s ../system/bin/bash /bin/\n";
bin = [ "bash" ];
exec = make {
skipConfigure = true;
inPlace = true;
+2 -2
View File
@@ -3,7 +3,7 @@ package libexpat {
website = "https://libexpat.github.io";
anitya = 770;
version# = "2.8.1";
version# = "2.8.2";
source = remoteGitHubRelease {
suffix = "libexpat/libexpat";
tag = "R_"+replace {
@@ -12,7 +12,7 @@ package libexpat {
new = "_";
};
name = "expat-"+version+".tar.bz2";
checksum = "iMEtbOJhQfGof2GxSlxffQSI1va_NDDQ9VIuqcPbNZ0291Dr8wttD5QecYyjIQap";
checksum = "98Pdyj5QtO7QRtNFXTWsCNCixQDx701ZGql2B-JIrTDkw49J5WXXUwnS4AdMlM4L";
compress = bzip2;
};
+2 -2
View File
@@ -3,12 +3,12 @@ package libffi {
website = "https://sourceware.org/libffi";
anitya = 1611;
version# = "3.5.2";
version# = "3.6.0";
source = remoteGitHubRelease {
suffix = "libffi/libffi";
tag = "v"+version;
name = "libffi-"+version+".tar.gz";
checksum = "2_Q-ZNBBbVhltfL5zEr0wljxPegUimTK4VeMSiwJEGksls3n4gj3lV0Ly3vviSFH";
checksum = "y3H_jP_eoByznlztjvni3wDfGA4CIJoOh3eRnzjnE3G3Ms3AWk53oOZxkbruvLxM";
compress = gzip;
};
+1 -2
View File
@@ -11,8 +11,7 @@ package libinput {
checksum = "GxBGPN6YybQxrD2MDsIL8gdDYImXn4NAJi6EvTx_Hb_1jcbjwCrjeyjY2upUyTMi";
};
early = "ln -sf ../system/bin/bash /bin/\n";
bin = [ "bash" ];
exec = meson {
setup = {
"Dmtdev": "false";
+6 -3
View File
@@ -3,12 +3,12 @@ package libpsl {
website = "https://rockdaboot.github.io/libpsl";
anitya = 7305;
version# = "0.21.5";
version# = "0.22.0";
source = remoteGitHubRelease {
suffix = "rockdaboot/libpsl";
tag = version;
name = "libpsl-"+version+".tar.gz";
checksum = "XjfxSzh7peG2Vg4vJlL8z4JZJLcXqbuP6pLWkrGCmRxlnYUFTKNBqWGHCxEOlCad";
checksum = "sYrq75kNAJvU5gA2gv2tFYIFbFFit6PuYuW1tYSgcsJsIUzwMJTodofsaEGq3iGf";
compress = gzip;
};
@@ -21,5 +21,8 @@ test_disable 'int main(){return 0;}' tests/test-is-public-builtin.c
exec = make {};
inputs = [ python ];
inputs = [
pkg-config,
python,
];
}
@@ -3,18 +3,16 @@ package libseccomp {
website = "https://github.com/seccomp/libseccomp";
anitya = 13823;
version# = "2.6.0";
version# = "2.6.1";
source = remoteGitHubRelease {
suffix = "seccomp/libseccomp";
tag = "v"+version;
name = "libseccomp-"+version+".tar.gz";
checksum = "mMu-iR71guPjFbb31u-YexBaanKE_nYPjPux-vuBiPfS_0kbwJdfCGlkofaUm-EY";
checksum = "YiiUqaQA9EUDSeC3CifYJLJHT9DwkqQtW21ek0H3HzEG7_I9Yn5-pLt5ybQqpEEt";
compress = gzip;
};
patches = [ "fix-export-oob-read.patch" ];
early = "\nln -s ../system/bin/bash /bin/\n";
bin = [ "bash" ];
exec = make {};
inputs = [
@@ -1,13 +0,0 @@
diff --git a/src/api.c b/src/api.c
index adccef3..65a277a 100644
--- a/src/api.c
+++ b/src/api.c
@@ -786,7 +786,7 @@ API int seccomp_export_bpf_mem(const scmp_filter_ctx ctx, void *buf,
if (BPF_PGM_SIZE(program) > *len)
rc = _rc_filter(-ERANGE);
else
- memcpy(buf, program->blks, *len);
+ memcpy(buf, program->blks, BPF_PGM_SIZE(program));
}
*len = BPF_PGM_SIZE(program);
+2 -2
View File
@@ -3,11 +3,11 @@ package libva {
website = "https://01.org/vaapi";
anitya = 1752;
version# = "2.23.0";
version# = "2.24.0";
source = remoteGitHub {
suffix = "intel/libva";
tag = version;
checksum = "UmF5tPyWIG_w5kiR3KFpoYbF7UUcaak5tyc-RhOheNTwQlLkPlifreFYCM9FQxbq";
checksum = "Jb5bdeHXLPPTWFlmauKDZlfAjFiXiILs17Pp7F8kAiyctFiDItpzYY0prIlnW7mu";
};
exec = meson {
+2 -6
View File
@@ -14,12 +14,8 @@ package lm_sensors {
chmod = true;
enterSource = true;
early = `
ln -s \
../../system/bin/perl \
/usr/bin/
`;
bin = [ "perl" ];
populateUsrBin = true;
exec = make {
inPlace = true;
skipConfigure = true;
+2 -2
View File
@@ -4,12 +4,12 @@ package mesa {
anitya = 1970;
latest = anityaFallback;
version# = "26.1.2";
version# = "26.1.4";
source = remoteGitLab {
domain = "gitlab.freedesktop.org";
suffix = "mesa/mesa";
ref = "mesa-"+version;
checksum = "EcY_vsm4rjUzVj7jQraWb9i3y0I2F0oH3Tav01QszQMxNzjLbSWHrQYR1mPRU-J4";
checksum = "E13xE-PmYKdhuh2f_7lExKSamVCnXm7qKmzZVBzMuzaMA-EGi7ZDdf2UwZrrUpK_";
};
exec = meson {
+1 -1
View File
@@ -81,13 +81,13 @@ sed -i \
extensions/libebt_snat.txlate
`;
bin = [ "bash" ];
exec = make {
generate = "./autogen.sh";
configure = {
"enable-static";
};
preCheck = `
ln -s ../system/bin/bash /bin/
chmod +w /etc/ && ln -s ../usr/src/iptables/etc/ethertypes /etc/
`;
};
+4 -5
View File
@@ -15,6 +15,7 @@ package ninja {
"CFLAGS=-std=c++17",
];
bin = [ "echo" ];
exec = generic {
build = `
python3 /usr/src/ninja/configure.py \
@@ -22,12 +23,10 @@ python3 /usr/src/ninja/configure.py \
--bootstrap
python3 /usr/src/ninja/configure.py \
--gtest-source-dir=/usr/src/extra/googletest
./ninja ` + jobsFlagE + ` all`;
./ninja ` + jobsFlagE + ` ` + loadFlagE + ` all
`;
check = `
chmod +w /bin/
ln -s ../system/bin/echo /bin/
./ninja_test`;
check = "./ninja_test";
install = `
mkdir -p /work/system/bin/
+32
View File
@@ -0,0 +1,32 @@
package noto {
description = "a typeface for the world";
website = "https://fonts.google.com/noto";
anitya = 10671;
version# = "2026.07.01";
source = remoteGitHub {
suffix = "notofonts/notofonts.github.io";
tag = "noto-monthly-release-"+version;
checksum = "4DdHW0aUDkcT-b3KNSNmPl_A2n4lrIeVmqjitDgUm4blGmGQjnMOtI4J9EjjYc06";
};
enterSource = true;
exec = generic {
inPlace = true;
install = `
DEST=/work/system/share/fonts/noto
for font in $(ls -d fonts/*/); do
if [[ -d "$font"unhinted/variable-ttf ]]; then
install -m444 -vDt "$DEST" "$font"unhinted/variable-ttf/*.ttf
elif [[ -d "$font"unhinted/otf ]]; then
install -m444 -vDt "$DEST" "$font"unhinted/otf/*.otf
else
install -m444 -vDt "$DEST" "$font"unhinted/ttf/*.ttf
fi
done
rename -v 's/\[.*\]//' $DEST/*
`;
};
inputs = [ rename ];
}
+1
View File
@@ -33,6 +33,7 @@ package openssl {
check = [
"HARNESS_JOBS=" + jobsE,
"TESTS='-test_bio_dgram'",
"test",
];
};
+2 -2
View File
@@ -3,12 +3,12 @@ package pango {
website = "https://www.pango.org";
anitya = 11783;
version# = "1.57.1";
version# = "1.58.0";
source = remoteGitLab {
domain = "gitlab.gnome.org";
suffix = "GNOME/pango";
ref = version;
checksum = "BzfdEym2eIyL5ownJ1LfqQwZkY3yH71YAsQF5R-sRV2pIOmc_CULAcfqVQki_Ose";
checksum = "k-Jcw7ys4-Q5gS0Y3WCb1MzIWauweIdknf61hRXJmQFfszw7sM7v0dItOoHMZLQJ";
};
exec = meson {
+2 -5
View File
@@ -12,11 +12,8 @@ package pcre2 {
compress = bzip2;
};
early = `
# RunGrepTest expects /bin/echo
ln -s ../system/bin/toybox /bin/echo
`;
// RunGrepTest expects /bin/echo
bin = [ "echo" ];
exec = make {
configure = {
"enable-jit";
+9 -9
View File
@@ -78,11 +78,11 @@ package python-setuptools {
website = "https://pypi.org/project/setuptools";
anitya = 4021;
version# = "82.0.1";
version# = "83.0.0";
source = remoteGitHub {
suffix = "pypa/setuptools";
tag = "v"+version;
checksum = "nznP46Tj539yqswtOrIM4nQgwLA1h-ApKX7z7ghazROCpyF5swtQGwsZoI93wkhc";
checksum = "WqYSqCAvwpcIG6yXV8vVzRMNWl2CrcPOUPwlYrLV70ykHSpKxW1-XYQ4Z4n0ebAt";
};
exec = pip {
@@ -124,15 +124,15 @@ package python-vcs-versioning {
website = "https://setuptools-scm.readthedocs.io/en/latest";
anitya = 389421;
version# = "1.1.1";
version# = "2.2.2";
source = remoteGitHub {
suffix = "pypa/setuptools-scm";
tag = "vcs-versioning-v"+version;
checksum = "rXZixTsZcRcIoUC1LvWrjySsiXSv5uhW6ng2P-yXZrbdj7FrSrDeJLCfC2b-ladV";
checksum = "dqKZGEjxWZ5xo4BjcpFOHxlEZfqrVWM79cRWa8OhGZY7VDSdOxrg7QVIhA6jsPcB";
};
env = [
"SETUPTOOLS_SCM_PRETEND_VERSION=" + version,
"VCS_VERSIONING_PRETEND_VERSION=" + version,
];
exec = pip {
@@ -158,11 +158,11 @@ package python-setuptools-scm {
website = "https://setuptools-scm.readthedocs.io/en/latest";
anitya = 7874;
version# = "10.0.5";
version# = "10.2.0";
source = remoteGitHub {
suffix = "pypa/setuptools-scm";
tag = "setuptools-scm-v"+version;
checksum = "vTN_TPd-b4Wbsw5WmAcsWjrs-FNXXznOeVTDnb54NtXve9Oy-eb2HPy-RG3FzNqp";
checksum = "vbZMqPbhScSE5gQXHIvG3pPNw7Iqsi9sEpI13wPdTNQQYOI2skfCvwSTXLq9Ncq8";
};
env = [
@@ -382,11 +382,11 @@ package python-pytest {
website = "https://pytest.org";
anitya = 3765;
version# = "9.1.0";
version# = "9.1.1";
source = remoteGitHub {
suffix = "pytest-dev/pytest";
tag = version;
checksum = "UNd_5ArXTfdGROVW5a0Z22FE4uOLfCMW4NeAnAp9SKHLGja9Db2Xc3BF48x7Hr_l";
checksum = "PnsF2mxJDF1d1MeYfMmlrSa_OlI92F8OPlSVA-lqsh4ggRZiAHjbTdO_jfNox065";
};
env = [
@@ -0,0 +1,20 @@
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index be4fa627b5..d6af6a036b 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -29,7 +29,6 @@ qtests_generic = [
'test-hmp',
'qos-test',
'readconfig-test',
- 'netdev-socket',
]
if enable_modules
qtests_generic += [ 'modules-test' ]
@@ -402,7 +401,6 @@ qtests = {
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
'virtio-net-failover': test_migration_files,
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
- 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
}
if vnc.found()
+11 -3
View File
@@ -3,13 +3,17 @@ package qemu {
website = "https://www.qemu.org";
anitya = 13607;
version# = "11.0.1";
version# = "11.0.2";
source = remoteTar {
url = "https://download.qemu.org/qemu-"+version+".tar.bz2";
checksum = "J3j3uNpiqxEoIEngBX2objV_1tzGfEgEphp5Ph86AJQvA_XMwYUakyvRH7YKEkwV";
checksum = "FcVvKLivqRuFg7bGJlgJxx6-MWLORgJcliHwBw_1WssI-R7epGT75JawvSYy8Ltq";
compress = bzip2;
};
patches = [ "disable-mcast-test.patch" ];
patches = [
"disable-mcast-test.patch",
// fails with ipv6 disabled
"disable-netdev-socket.patch",
];
// configure script uses source as scratch space
writable = true;
@@ -49,6 +53,10 @@ EOF
sep = ",";
};
};
check = [
"TIMEOUT_MULTIPLIER=5",
];
};
inputs = [

Some files were not shown because too many files have changed in this diff Show More