2 Commits
Author SHA1 Message Date
cat bfd922fde3 internal/rosa/package/kernel: 6.12.94 to 6.18.37
Test / Create distribution (push) Successful in 2m51s
Test / Sandbox (push) Successful in 7m38s
Test / ShareFS (push) Successful in 8m59s
Test / Hakurei (push) Successful in 9m6s
Test / Sandbox (race detector) (push) Successful in 9m53s
Test / Hakurei (race detector) (push) Successful in 11m7s
Test / Flake checks (push) Successful in 1m16s
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:00:31 +09:00
cat b121f74b4e 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 01:59:18 +09:00
313 changed files with 2110 additions and 21003 deletions
-1
View File
@@ -1 +0,0 @@
*.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 ./test#dist
run: nix build --print-out-paths --print-build-logs .#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 ./test#checks.x86_64-linux.hakurei
run: nix build --out-link "result" --print-out-paths --print-build-logs .#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 ./test#checks.x86_64-linux.race
run: nix build --out-link "result" --print-out-paths --print-build-logs .#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 ./test#checks.x86_64-linux.sandbox
run: nix build --out-link "result" --print-out-paths --print-build-logs .#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 ./test#checks.x86_64-linux.sandbox-race
run: nix build --out-link "result" --print-out-paths --print-build-logs .#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 ./test#checks.x86_64-linux.sharefs
run: nix build --out-link "result" --print-out-paths --print-build-logs .#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 ./test
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check
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 = /' test/package.nix &&
nix build --print-out-paths --print-build-logs ./test#dist &&
mv test/{package.nix.old,package.nix} &&
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 &&
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
- name: Upload test build
-1
View File
@@ -1,5 +1,4 @@
# produced by tools and text editors
*.swp
*.qcow2
*.test
*.out
+6 -1
View File
@@ -11,7 +11,7 @@
<a href="https://git.gensokyo.uk/rosa/hakurei/actions"><img src="https://git.gensokyo.uk/rosa/hakurei/actions/workflows/test.yml/badge.svg?branch=staging&style=flat-square" alt="Gitea Workflow Status" /></a>
<br/>
<a href="https://git.gensokyo.uk/rosa/hakurei/releases"><img src="https://img.shields.io/gitea/v/release/rosa/hakurei?gitea_url=https%3A%2F%2Fgit.gensokyo.uk&color=purple" alt="Release" /></a>
<a href="https://git.gensokyo.uk/rosa/hakurei/src/branch/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-pink" alt="MIT License" /></a>
<a href="https://goreportcard.com/report/hakurei.app"><img src="https://goreportcard.com/badge/hakurei.app" alt="Go Report Card" /></a>
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
</p>
@@ -58,3 +58,8 @@ package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
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).
-17
View File
@@ -4,7 +4,6 @@ import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
@@ -336,19 +335,3 @@ func parse(
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
}
+23 -2
View File
@@ -7,6 +7,7 @@ package main
import (
"context"
"errors"
"fmt"
"io"
"log"
"os"
@@ -76,7 +77,17 @@ func main() {
"enter", "Enter mutable state template",
func(args []string) error {
if len(args) != 1 {
return list(template, true)
dents, err := os.ReadDir(template.String())
if err != nil {
return err
}
for _, dent := range dents {
if !dent.IsDir() {
continue
}
fmt.Println(dent.Name())
}
return nil
}
config := hst.Config{
@@ -148,7 +159,17 @@ func main() {
"run", "Start the named application",
func(args []string) error {
if len(args) < 1 {
return list(base.Append("app"), false)
dents, err := os.ReadDir(base.Append("app").String())
if err != nil {
return err
}
for _, dent := range dents {
if dent.IsDir() {
continue
}
fmt.Println(dent.Name())
}
return nil
}
var config *hst.Config
+1 -1
View File
@@ -1 +1 @@
v0.4.7
v0.4.5
-6
View File
@@ -36,11 +36,6 @@ _hakurei_show() {
'files:files:__hakurei_files'
}
_hakurei_kill() {
_alternative \
'instances:domains:__hakurei_instances'
}
__hakurei_files() {
_files -g "*.(json|hakurei)"
return $?
@@ -65,7 +60,6 @@ __hakurei_instances() {
"run:Load and start container from configuration file"
"exec:Configure and start a permissive container"
"show:Show live or local instance configuration"
"kill:Terminate an active instance"
"ps:List active instances"
"version:Display version information"
"license:Show full license text"
+3 -3
View File
@@ -57,7 +57,7 @@ func main() {
verbose := os.Getenv("VERBOSE") != ""
runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
version = getenv("HAKUREI_VERSION", strings.TrimSpace(version))
prefix := getenv("PREFIX", "/usr/local")
prefix := getenv("PREFIX", "/usr")
destdir := getenv("DESTDIR", "dist")
if verbose {
@@ -217,7 +217,7 @@ func main() {
mustWriteFile("comp/", nil, os.ModeDir|0755)
mustWriteFile("comp/_hakurei", comp, 0644)
mustWriteFile("install.sh", []byte(`#!/bin/sh -e
cd "$(dirname -- "$0")"
cd "$(dirname -- "$0")" || exit 1
install -vDm0755 "bin/hakurei" "${DESTDIR}`+prefix+`/bin/hakurei"
install -vDm0755 "bin/sharefs" "${DESTDIR}`+prefix+`/bin/sharefs"
@@ -230,7 +230,7 @@ fi
install -vDm0644 "comp/_hakurei" "${DESTDIR}`+prefix+`/share/zsh/site-functions/_hakurei"
`), 0755)
mustWriteFromPath("LICENSE", "LICENSE", 0)
mustWriteFromPath("README.md", "README.md", 0)
mustWriteFile("hsurc.default", []byte("1000 0"), 0400)
mustWriteFromPath("bin/hsu", filepath.Join(s, "hsu"), 04511)
for _, name := range []string{
-18
View File
@@ -11,7 +11,6 @@ import (
"os/user"
"strconv"
"sync"
"syscall"
"time"
"hakurei.app/check"
@@ -373,23 +372,6 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
Flag(&flagNoStore, "no-store", command.BoolFlag(false), "Do not attempt to match from active instances")
}
c.NewCommand("kill", "Terminate an active instance", func(args []string) error {
if len(args) != 1 {
log.Fatal("kill requires 1 argument")
}
var sc hst.Paths
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
entry := tryIdentifier(msg, args[0], outcome.NewStore(&sc))
if entry == nil {
log.Fatalf("%q does not match any active instance", args[0])
}
if err := syscall.Kill(entry.PID, syscall.SIGTERM); err != nil {
log.Fatalf("cannot terminate %s: %v", entry.ID.String(), err)
}
return errSuccess
})
{
var flagShort bool
c.NewCommand("ps", "List active instances", func(args []string) error {
+6 -10
View File
@@ -19,13 +19,13 @@ func TestHelp(t *testing.T) {
want string
}{
{
"main", []string{}, `usage: hakurei [-h | --help] [-v] [--insecure] [--json] <command> [<args>]
"main", []string{}, `
Usage: hakurei [-h | --help] [-v] [--insecure] [--json] COMMAND [OPTIONS]
commands:
Commands:
run Load and start container from configuration file
exec Configure and start a permissive container
show Show live or local instance configuration
kill Terminate an active instance
ps List active instances
version Display version information
license Show full license text
@@ -35,14 +35,10 @@ commands:
`,
},
{
"exec", []string{"exec", "-h"}, `usage: hakurei exec [-h | --help] [--dbus-config <value>]
[--dbus-system <value>] [--mpris] [--dbus-log]
[--id <value>] [-a <int>] [-g <value>] [-d <value>]
[-u <value>] [--policy <value>] [--priority <int>]
[--private-runtime] [--private-tmpdir] [--wayland] [-X]
[--dbus] [--pipewire] [--pulse] <command> [<args>]
"exec", []string{"exec", "-h"}, `
Usage: hakurei exec [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--policy <value>] [--priority <int>] [--private-runtime] [--private-tmpdir] [--wayland] [-X] [--dbus] [--pipewire] [--pulse] COMMAND [OPTIONS]
flags:
Flags:
-X Enable direct connection to X11
-a int
Application identity
+1 -1
View File
@@ -66,7 +66,7 @@ func TestEncodeJSON(t *testing.T) {
want string
}{
{"marshaler", errorJSONMarshaler{},
`cannot encode json for *main.errorJSONMarshaler: unique error 3735928559 injected by the test suite`},
`cannot encode json for main.errorJSONMarshaler: unique error 3735928559 injected by the test suite`},
{"default", func() {},
`cannot write json: json: unsupported type: func()`},
}
+1 -1
View File
@@ -8,7 +8,7 @@ buildGoModule {
pname = "${hakurei.pname}-hsu";
inherit (hakurei) version;
src = ../cmd/hsu;
src = ./.;
inherit (hakurei) vendorHash;
env.CGO_ENABLED = 0;
+9 -65
View File
@@ -5,7 +5,6 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"testing"
"hakurei.app/check"
@@ -22,66 +21,41 @@ type cache struct {
// Should generally not be used directly.
c *pkg.Cache
attr pkg.CacheAttr
cures, jobs int
// Primarily to work around missing landlock LSM.
hostAbstract bool
// Set SCHED_IDLE.
idle bool
// Unset [pkg.CSuppressInit].
verboseInit bool
// Whether to enable output colours.
color bool
// Unset [pkg.CExternShallow].
deep bool
// Loaded artifact of [rosa.QEMU].
qemu pkg.Artifact
base, mirror string
}
// writeTitle sets title of the terminal connected to [message.Msg].
func writeTitle(msg message.Msg, s string) {
msg.Suspend()
w := msg.GetLogger().Writer()
_, _ = w.Write([]byte("\x1b]0;" + s + "\a"))
msg.Resume()
}
// open opens the underlying [pkg.Cache].
func (cache *cache) open() (err error) {
if cache.c != nil {
return os.ErrInvalid
}
var hostname string
if hostname, err = os.Hostname(); err != nil {
return
}
var base *check.Absolute
if cache.base, err = filepath.Abs(cache.base); err != nil {
return
} else if base, err = check.NewAbs(cache.base); err != nil {
return
}
var notify chan bool
var flags int
if cache.idle {
cache.attr.Flags |= pkg.CSchedIdle
flags |= pkg.CSchedIdle
}
if cache.hostAbstract {
cache.attr.Flags |= pkg.CHostAbstract
flags |= pkg.CHostAbstract
}
if !cache.verboseInit {
cache.attr.Flags |= pkg.CSuppressInit
}
if !cache.deep {
cache.attr.Flags |= pkg.CExternShallow
}
if cache.color {
cache.attr.Flags |= pkg.CColourOutput
notify = make(chan bool, 1<<12)
cache.attr.Notify = notify
flags |= pkg.CSuppressInit
}
done := make(chan struct{})
@@ -103,8 +77,10 @@ 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
@@ -119,40 +95,13 @@ func (cache *cache) open() (err error) {
return
}
var r rosa.Remote
if r, err = rosa.NewRemote(http.DefaultClient, cache.mirror, pub); err != nil {
if r, err = rosa.NewRemote(cache.mirror, pub, http.DefaultClient); err != nil {
cache.c.Close()
return err
}
cache.c.SetExternal(r)
}
if cache.attr.Notify != nil {
cache.msg.Suspend()
_, _ = cache.msg.GetLogger().Writer().Write([]byte("\x1b[22;0t"))
cache.msg.Resume()
prefix := hostname + ": mbf "
go func() {
var n, nc uint64
for enter := range notify {
if enter {
nc++
} else {
nc--
n++
}
if nc == 0 {
writeTitle(cache.msg, prefix[:len(prefix)-1])
continue
}
writeTitle(cache.msg, prefix+
"("+strconv.FormatUint(nc, 10)+
" running, "+strconv.FormatUint(n, 10)+" complete)")
}
}()
}
if cache.qemu != nil {
var pathname *check.Absolute
pathname, _, err = cache.c.Cure(cache.qemu)
@@ -173,11 +122,6 @@ func (cache *cache) open() (err error) {
func (cache *cache) Close() {
if cache.c != nil {
cache.c.Close()
if cache.attr.Notify != nil {
cache.msg.Suspend()
_, _ = cache.msg.GetLogger().Writer().Write([]byte("\x1b[23;0t"))
cache.msg.Resume()
}
}
}
+5 -5
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)
@@ -63,7 +63,7 @@ func TestNoReply(t *testing.T) {
}
<-done
wantIdent := pkg.MustDecode("bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32")
wantIdent := pkg.MustDecode("fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG")
if gotIdent := c.Ident(a).Value(); gotIdent != wantIdent {
t.Errorf(
"cureFromIR: %s, want %s",
@@ -124,7 +124,7 @@ func TestDaemon(t *testing.T) {
cancel()
<-done
const want = "bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32"
const want = "fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG"
if got := filepath.Base(p.String()); got != want {
t.Errorf("cureRemote: %s, want %s", got, want)
}
@@ -132,8 +132,8 @@ func TestDaemon(t *testing.T) {
wantLog := []string{
"",
"daemon: aborting all pending cures",
"daemon: attempting to cancel invalid artifact 58Vy_5beLZCvZX__KzRKyIE6vATleaZP1ZBxbqoWnekz9aZ1zkxNgcIUFI5V1_Jf",
"daemon: fulfilled artifact " + want,
"daemon: attempting to cancel invalid artifact kQm9fmnCmXST1-MMmxzcau2oKZCXXrlZydo4PkeV5hO_2PKfeC8t98hrbV_ZZx_j",
"daemon: fulfilled artifact fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG",
}
gotLog := strings.Split(buf.String(), "\n")
slices.Sort(gotLog)
+1 -4
View File
@@ -21,10 +21,7 @@ func commandInfo(
r *rosa.Report,
) (err error) {
if len(args) == 0 {
for _, h := range rosa.Native().CollectAll() {
fmt.Println(h)
}
return nil
return errors.New("info requires at least 1 argument")
}
// recovered by HandleAccess
+39 -213
View File
@@ -27,7 +27,6 @@ import (
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"syscall"
@@ -92,11 +91,6 @@ func main() {
var cm cache
defer func() { cm.Close() }()
if cm.color = ext.Isatty(syscall.Stderr) &&
os.Getenv("NO_COLOR") == "" &&
os.Getenv("TERM") != "dumb"; cm.color {
log.SetPrefix("\x1b[2mmbf: \x1b[0m")
}
var (
flagQuiet bool
@@ -208,17 +202,13 @@ func main() {
"v", command.BoolFlag(false),
"Do not suppress verbose output from init",
).Flag(
&cm.attr.Cures,
&cm.cures,
"cures", command.IntFlag(0),
"Maximum number of dependencies to cure at any given time",
).Flag(
&cm.attr.Jobs,
&cm.jobs,
"jobs", command.IntFlag(0),
"Preferred number of jobs to run, when applicable",
).Flag(
&cm.attr.Load,
"load-average", command.IntFlag(0),
"Preferred load average number, when applicable",
).Flag(
&cm.base,
"d", command.StringFlag("$MBF_CACHE_DIR"),
@@ -227,11 +217,6 @@ 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),
@@ -283,7 +268,7 @@ func main() {
if _, err := io.Copy(h, os.Stdin); err != nil {
return err
}
fmt.Println(pkg.Encode(pkg.Checksum(h.Sum(nil))))
log.Println(pkg.Encode(pkg.Checksum(h.Sum(nil))))
return nil
},
)
@@ -554,9 +539,7 @@ func main() {
if base, err := os.OpenRoot(cm.base); err != nil {
return err
} else {
var mux http.ServeMux
rosa.NewMirror(msg, base.FS(), key).Register(&mux)
h = &mux
h = rosa.NewMirror(msg, base.FS(), key)
}
server := http.Server{Addr: args[0], Handler: h}
@@ -578,52 +561,28 @@ 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
flagChecksum string
)
c.NewCommand(
"stage4",
"stage3",
"Check for toolchain 3-stage non-determinism",
func(args []string) (err error) {
s := rosa.Std
if flagGentoo != "" {
s -= 3 // magic number to discourage misuse
var checksum pkg.Checksum
if len(flagChecksum) != 0 {
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
return
}
}
rosa.Native().SetGentooStage3(flagGentoo, checksum)
}
var (
pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum]
@@ -631,7 +590,7 @@ func main() {
_llvm := rosa.H("llvm")
if err = cm.Do(func(cache *pkg.Cache) (err error) {
_, llvm := rosa.Native().New(rosa.Std - 2).Load(_llvm)
_, llvm := rosa.Native().New(s - 2).Load(_llvm)
pathname, _, err = cache.Cure(llvm)
return
}); err != nil {
@@ -640,31 +599,21 @@ func main() {
log.Println("stage1:", pathname)
if err = cm.Do(func(cache *pkg.Cache) (err error) {
_, llvm := rosa.Native().New(rosa.Std - 1).Load(_llvm)
pathname, _, err = cache.Cure(llvm)
return
}); err != nil {
return
}
log.Println("stage2:", pathname)
if err = cm.Do(func(cache *pkg.Cache) (err error) {
_, llvm := rosa.Native().New(rosa.Std).Load(_llvm)
_, llvm := rosa.Native().New(s - 1).Load(_llvm)
pathname, checksum[0], err = cache.Cure(llvm)
return
}); err != nil {
return
}
log.Println("stage3:", pathname)
log.Println("stage2:", pathname)
if err = cm.Do(func(cache *pkg.Cache) (err error) {
_, llvm := rosa.Native().New(rosa.Stage3).Load(_llvm)
_, llvm := rosa.Native().New(s).Load(_llvm)
pathname, checksum[1], err = cache.Cure(llvm)
return
}); err != nil {
return
}
log.Println("stage4:", pathname)
log.Println("stage3:", pathname)
if checksum[0] != checksum[1] {
err = &pkg.ChecksumMismatchError{
@@ -673,34 +622,23 @@ func main() {
}
} else {
log.Println(
"stage3 is identical to stage4",
"stage2 is identical to stage3",
"("+pkg.Encode(checksum[0].Value())+")",
)
}
return
},
).Flag(
&flagGentoo,
"gentoo", command.StringFlag(""),
"Bootstrap from a Gentoo stage3 tarball",
).Flag(
&flagChecksum,
"checksum", command.StringFlag(""),
"Checksum of Gentoo stage3 tarball",
)
}
c.NewCommand(
"all",
command.UsageInternal,
func([]string) error {
all := rosa.Native().CollectAll()
a := make(pkg.Collect, len(all))
for i, h := range all {
_, a[i] = rosa.Native().Std().Load(h)
}
return cm.Do(func(cache *pkg.Cache) (err error) {
_, _, err = cache.Cure(&a)
if pkg.IsCollected(err) {
err = nil
}
return
})
},
)
{
var (
flagDump string
@@ -710,13 +648,9 @@ func main() {
flagNoReply bool
flagFaults bool
flagPop bool
flagRebuild bool
flagBoot bool
flagStd bool
flagGentoo string
flagChecksum string
)
c.NewCommand(
"cure",
@@ -733,18 +667,6 @@ func main() {
t -= 1
}
if flagGentoo != "" {
var checksum pkg.Checksum
if len(flagChecksum) != 0 {
if err := pkg.Decode(&checksum, flagChecksum); err != nil {
return err
}
}
rosa.Native().SetGentooStage3(flagGentoo, checksum)
t -= 3 // magic number to discourage misuse
}
_, a := rosa.Native().New(t).Load(rosa.ArtifactH(unique.Make(args[0])))
if a == nil {
return fmt.Errorf("unknown artifact %q", args[0])
@@ -754,17 +676,13 @@ func main() {
default:
var pathname *check.Absolute
err := cm.Do(func(cache *pkg.Cache) (err error) {
if flagRebuild {
pathname, _, err = cache.CureNew(a)
} else {
pathname, _, err = cache.Cure(a)
}
return
})
if err != nil {
return err
}
fmt.Println(pathname)
log.Println(pathname)
if flagExport != "" {
msg.Verbosef("exporting %s to %s...", args[0], flagExport)
@@ -813,7 +731,7 @@ func main() {
ctx,
a,
"", true, os.Stdin, os.Stdout, os.Stderr,
rosa.AbsSystem.Append("bin", "sh"),
rosa.AbsSystem.Append("bin", "mksh"),
"sh",
)
})
@@ -825,7 +743,7 @@ func main() {
}
pathname, err := cureRemote(ctx, &addr, a, flags)
if !flagNoReply && err == nil {
fmt.Println(pathname)
log.Println(pathname)
}
if errors.Is(err, context.Canceled) {
@@ -919,97 +837,9 @@ 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",
).Flag(
&flagGentoo,
"gentoo", command.StringFlag(""),
"Bootstrap from a Gentoo stage3 tarball",
).Flag(
&flagChecksum,
"checksum", command.StringFlag(""),
"Checksum of Gentoo stage3 tarball",
)
}
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",
@@ -1196,10 +1026,6 @@ func main() {
if w, ok := err.(interface{ Unwrap() []error }); !ok {
log.Fatal(err)
} else {
if _, ok = w.(pkg.InputError); ok {
log.Fatal(w)
}
errs := w.Unwrap()
for i, e := range errs {
if i == len(errs)-1 {
+2 -3
View File
@@ -13,7 +13,6 @@ func New(output io.Writer, logf LogFunc, name string, early HandlerFunc) Command
return c
}
// newNode initialises a subcommand tree and returns its address.
func newNode(output io.Writer, logf LogFunc, name, usage string) *node {
n := &node{
name: name, usage: usage,
@@ -23,8 +22,8 @@ func newNode(output io.Writer, logf LogFunc, name, usage string) *node {
n.set.SetOutput(output)
n.set.Usage = func() {
_ = n.writeHelp()
if len(n.suffix) > 0 {
_, _ = fmt.Fprintln(output, "flags:")
if n.suffix.Len() > 0 {
_, _ = fmt.Fprintln(output, "Flags:")
n.set.PrintDefaults()
_, _ = fmt.Fprintln(output)
}
+4 -16
View File
@@ -18,14 +18,8 @@ func TestBuild(t *testing.T) {
t.Run("direct zero length", func(t *testing.T) {
wantPanic := "invalid subcommand"
t.Run("zero length name", func(t *testing.T) {
defer checkRecover(t, "Command", wantPanic)
c.Command("", "usage", stubHandler)
})
t.Run("zero length usage", func(t *testing.T) {
defer checkRecover(t, "Command", wantPanic)
c.Command("name", "", stubHandler)
})
t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("", "usage", stubHandler) })
t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("name", "", stubHandler) })
})
t.Run("direct adopt unique names", func(t *testing.T) {
@@ -40,14 +34,8 @@ func TestBuild(t *testing.T) {
t.Run("zero length", func(t *testing.T) {
wantPanic := "invalid subcommand tree"
t.Run("zero length name", func(t *testing.T) {
defer checkRecover(t, "New", wantPanic)
c.New("", "usage")
})
t.Run("zero length usage", func(t *testing.T) {
defer checkRecover(t, "New", wantPanic)
c.New("name", "")
})
t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("", "usage") })
t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("name", "") })
})
t.Run("direct adopt unique names", func(t *testing.T) {
+6 -26
View File
@@ -6,43 +6,36 @@ import (
"strings"
)
// UsageInternal is a special usage string that hides the command from the
// generated help message.
const UsageInternal = "\x00"
// UsageInternal causes the command to be hidden from help text when set as the usage string.
const UsageInternal = "internal"
type (
// HandlerFunc is called when matching a directly handled subcommand tree.
HandlerFunc = func(args []string) error
// LogFunc is the function signature of a printf function. The zero value
// implies [log.Printf].
// LogFunc is the function signature of a printf function.
LogFunc = func(format string, a ...any)
// FlagDefiner is a deferred flag definer value, usually encapsulating the
// default value.
// FlagDefiner is a deferred flag definer value, usually encapsulating the default value.
FlagDefiner interface {
// Define defines the flag in set.
Define(b *strings.Builder, set *flag.FlagSet, p any, name, usage string)
}
// A Flag is satisfied by command objects capable of receiving flags.
Flag[T any] interface {
// Flag defines a generic flag type in Node's flag set.
Flag(p any, name string, value FlagDefiner, usage string) T
}
// A Command is the root of a command tree.
Command interface {
Parse(arguments []string) error
// MustParse determines exit outcomes for Parse errors and calls
// handleError if [HandlerFunc] returns a non-nil error.
// MustParse determines exit outcomes for Parse errors
// and calls handleError if [HandlerFunc] returns a non-nil error.
MustParse(arguments []string, handleError func(error))
baseNode[Command]
}
// A Node is a subcommand under a [Command].
Node baseNode[Node]
baseNode[T any] interface {
@@ -60,16 +53,3 @@ type (
Flag[T]
}
)
// rootNode satisfies baseNode for [Command].
type rootNode struct{ *node }
func (r rootNode) Command(name, usage string, f HandlerFunc) Command {
r.node.Command(name, usage, f)
return r
}
func (r rootNode) Flag(p any, name string, value FlagDefiner, usage string) Command {
r.node.Flag(p, name, value, usage)
return r
}
+1 -7
View File
@@ -16,13 +16,7 @@ func (e FlagError) Is(target error) bool {
}
func (n *node) Flag(p any, name string, value FlagDefiner, usage string) Node {
var buf strings.Builder
value.Define(&buf, n.set, p, name, usage)
s := buf.String()
if len(s) > 0 && s[0] == ' ' {
s = s[1:]
}
n.suffix = append(n.suffix, s)
value.Define(&n.suffix, n.set, p, name, usage)
return n
}
+3 -21
View File
@@ -1,7 +1,6 @@
package command
import (
"bytes"
"errors"
"fmt"
"io"
@@ -14,31 +13,14 @@ var ErrHelp = errors.New("help requested")
func (n *node) PrintHelp() { _ = n.writeHelp() }
func (n *node) writeHelp() error {
prefix := strings.Join(append(n.prefix, n.name), " ")
var buf strings.Builder
offset := 7 + len(prefix)
line := offset + 14
w := bytes.Repeat([]byte{' '}, offset+1)
w[0] = '\n'
for _, flag := range n.suffix {
line += len(flag) + 1
if line >= 80 {
line = offset + len(flag) + 1
buf.Write(w)
}
buf.WriteByte(' ')
buf.WriteString(flag)
}
if _, err := fmt.Fprintf(n.out,
"usage: %s [-h | --help]%s <command> [<args>]\n",
prefix, &buf,
"\nUsage:\t%s [-h | --help]%s COMMAND [OPTIONS]\n",
strings.Join(append(n.prefix, n.name), " "), &n.suffix,
); err != nil {
return err
}
if n.child != nil {
if _, err := fmt.Fprint(n.out, "\ncommands:\n"); err != nil {
if _, err := fmt.Fprint(n.out, "\nCommands:\n"); err != nil {
return err
}
}
+2 -6
View File
@@ -3,9 +3,9 @@ package command
import (
"flag"
"io"
"strings"
)
// A node represents a command.
type node struct {
child, next *node
name, usage string
@@ -13,16 +13,13 @@ type node struct {
out io.Writer
logf LogFunc
// Names of commands preceding node.
prefix []string
// Short user-facing representations of flags received by node.
suffix []string
suffix strings.Builder
f HandlerFunc
set *flag.FlagSet
}
// adopt adds v as the last child of n.
func (n *node) adopt(v *node) bool {
if n.child != nil {
return n.child.append(v)
@@ -31,7 +28,6 @@ func (n *node) adopt(v *node) bool {
return true
}
// append adds v as the last sibling of n.
func (n *node) append(v *node) bool {
if n.name == v.name {
return false
+22 -18
View File
@@ -70,7 +70,7 @@ func TestParse(t *testing.T) {
"d=0 out of order string flag",
buildTestCommand,
[]string{"string", "--string", "64d3b4b7b21788585845060e2199a78f"},
"flag provided but not defined: -string\nusage: test string [-h | --help] <command> [<args>]\n\n", "",
"flag provided but not defined: -string\n\nUsage:\ttest string [-h | --help] COMMAND [OPTIONS]\n\n", "",
errors.New("flag provided but not defined: -string"),
},
{
@@ -120,7 +120,7 @@ func TestParse(t *testing.T) {
"d=1 empty sub help",
buildTestCommand,
[]string{"empty", "-h"},
"usage: test empty [-h | --help] <command> [<args>]\n\n", "", flag.ErrHelp,
"\nUsage:\ttest empty [-h | --help] COMMAND [OPTIONS]\n\n", "", flag.ErrHelp,
},
{
"d=1 no match",
@@ -151,10 +151,10 @@ func TestParse(t *testing.T) {
"d=0 help",
buildTestCommand,
[]string{},
`usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>]
[--repeat <value>] <command> [<args>]
`
Usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
commands:
Commands:
error return an error
print wraps Fprint
string print string passed by flag
@@ -171,10 +171,10 @@ commands:
"d=0 help flag",
buildTestCommand,
[]string{"-h"},
`usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>]
[--repeat <value>] <command> [<args>]
`
Usage: test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
commands:
Commands:
error return an error
print wraps Fprint
string print string passed by flag
@@ -185,7 +185,7 @@ commands:
succeed this command succeeds
deep top level of command tree with various levels
flags:
Flags:
-fail
fail early
-int int
@@ -203,9 +203,10 @@ flags:
"d=1 help",
buildTestCommand,
[]string{"join"},
`usage: test join [-h | --help] <command> [<args>]
`
Usage: test join [-h | --help] COMMAND [OPTIONS]
commands:
Commands:
out write result to wout
log log result to wlog
@@ -215,9 +216,10 @@ commands:
"d=1 help flag",
buildTestCommand,
[]string{"join", "-h"},
`usage: test join [-h | --help] <command> [<args>]
`
Usage: test join [-h | --help] COMMAND [OPTIONS]
commands:
Commands:
out write result to wout
log log result to wlog
@@ -228,9 +230,10 @@ commands:
"d=2 help",
buildTestCommand,
[]string{"deep", "d=2"},
`usage: test deep d=2 [-h | --help] <command> [<args>]
`
Usage: test deep d=2 [-h | --help] COMMAND [OPTIONS]
commands:
Commands:
d=3 relative third level
`, "", command.ErrHelp,
@@ -239,9 +242,10 @@ commands:
"d=2 help flag",
buildTestCommand,
[]string{"deep", "d=2", "-h"},
`usage: test deep d=2 [-h | --help] <command> [<args>]
`
Usage: test deep d=2 [-h | --help] COMMAND [OPTIONS]
commands:
Commands:
d=3 relative third level
`, "", flag.ErrHelp,
@@ -257,7 +261,7 @@ commands:
t.Errorf("Parse: error = %v; wantErr %v", err, tc.wantErr)
}
if got := wout.String(); got != tc.want {
t.Errorf("Parse:\n%s\nwant\n%s", got, tc.want)
t.Errorf("Parse: %s want %s", got, tc.want)
}
if gotLog := wlog.String(); gotLog != tc.wantLog {
t.Errorf("Parse: log = %s wantLog %s", gotLog, tc.wantLog)
+14
View File
@@ -0,0 +1,14 @@
package command
// the top level node wants [Command] returned for its builder methods
type rootNode struct{ *node }
func (r rootNode) Command(name, usage string, f HandlerFunc) Command {
r.node.Command(name, usage, f)
return r
}
func (r rootNode) Flag(p any, name string, value FlagDefiner, usage string) Command {
r.node.Flag(p, name, value, usage)
return r
}
+6 -6
View File
@@ -7,11 +7,11 @@
]
},
"locked": {
"lastModified": 1787146702,
"narHash": "sha256-YbRcLdU/yK4gWsQg7V8WTKZHfXL33g8+wSFUX3wyevs=",
"lastModified": 1780361225,
"narHash": "sha256-wnV9ttf4fPWNonBIQmvlrSlNpQYgx5HgWWd007mwIFA=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "173b7e8d40fdc8c296a9c99854314f17a3a1704c",
"rev": "e28654b71096e08c019d4861ca26acb646f583d8",
"type": "github"
},
"original": {
@@ -23,11 +23,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1787101114,
"narHash": "sha256-gwrPcFf/rDjHPaVflbDZ040ZDmBTRj/7+s8ZmE2SaIM=",
"lastModified": 1780453794,
"narHash": "sha256-bXMRa9VTsHSPXL4Cw8R6JJLQeY3Y/IP4+YJCYVmQ7FY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b18a4b905f8d028dc4476412e6d6891728695379",
"rev": "6b316287bae2ee04c9b93c8c858d930fd07d7338",
"type": "github"
},
"original": {
+13 -13
View File
@@ -43,19 +43,19 @@
;
in
{
hakurei = callPackage ./. { inherit system self; };
race = callPackage ./. {
hakurei = callPackage ./test { inherit system self; };
race = callPackage ./test {
inherit system self;
withRace = true;
};
sandbox = callPackage ./sandbox { inherit self; };
sandbox-race = callPackage ./sandbox {
sandbox = callPackage ./test/sandbox { inherit self; };
sandbox-race = callPackage ./test/sandbox {
inherit self;
withRace = true;
};
sharefs = callPackage ./sharefs { inherit system self; };
sharefs = callPackage ./cmd/sharefs/test { inherit system self; };
formatting = runCommandLocal "check-formatting" { nativeBuildInputs = [ nixfmt ]; } ''
cd ${./.}
@@ -99,7 +99,7 @@
hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
inherit (pkgs)
# passthru.buildInputs
go_1_27
go_1_26
clang
# nativeBuildInputs
@@ -116,7 +116,7 @@
nettools
;
};
hsu = pkgs.callPackage ./hsu.nix { inherit (self.packages.${system}) hakurei; };
hsu = pkgs.callPackage ./cmd/hsu/package.nix { inherit (self.packages.${system}) hakurei; };
sharefs = pkgs.linkFarm "sharefs" {
"bin/sharefs" = "${hakurei}/libexec/sharefs";
"bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs";
@@ -180,7 +180,7 @@
let
# this is used for interactive vm testing during development, where tests might be broken
package = self.packages.${pkgs.stdenv.hostPlatform.system}.hakurei.override {
buildGo127Module = previousArgs: pkgs.pkgsStatic.buildGo127Module (previousArgs // { doCheck = false; });
buildGo126Module = previousArgs: pkgs.pkgsStatic.buildGo126Module (previousArgs // { doCheck = false; });
};
in
{
@@ -190,11 +190,11 @@
};
}
./interactive/configuration.nix
./interactive/vm.nix
./interactive/hakurei.nix
./interactive/trace.nix
./interactive/raceattr.nix
./test/interactive/configuration.nix
./test/interactive/vm.nix
./test/interactive/hakurei.nix
./test/interactive/trace.nix
./test/interactive/raceattr.nix
self.nixosModules.hakurei
home-manager.nixosModules.home-manager
+1 -1
View File
@@ -1,3 +1,3 @@
module hakurei.app
go 1.27
go 1.26
+2 -2
View File
@@ -303,8 +303,8 @@ func init() {
})
}
// Inputs returns a slice containing the backing file.
func (a archiveArtifact) Inputs() []Artifact {
// Dependencies returns a slice containing the backing file.
func (a archiveArtifact) Dependencies() []Artifact {
return []Artifact{a.f}
}
+2 -2
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), pkg.WNew, nil},
), ignorePathname, expectsFS(want), nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -202,7 +202,7 @@ func TestArchiveArtifact(t *testing.T) {
"checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/-zXKfphyWM2Ko7VMVURaEMSuixNokFSe0xFbnwR2RtRtvMrcPGWalV0LIn45PXTY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")},
"identifier/3oYyAbRJ_we7AgWo1BRcRcnxXFk3mAQ0Qui2nGQMi8GIJNJQtvUC6P2IeoA5mbjD": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")},
"substitute": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
+3 -12
View File
@@ -73,10 +73,7 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
continue
}
c.msg.Verbosef(
"arranging for destruction of %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
c.msg.Verbosef("arranging for destruction of %s...", name)
idents = append(idents, identPair{id, name})
}
@@ -105,10 +102,7 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
if err = c.parent.Err(); err != nil {
return destroyedIdents, destroyedChecksums, err
}
c.msg.Verbosef(
"destroying checksum %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
c.msg.Verbosef("destroying checksum %s...", name)
if !dry {
if err = errors.Join(removeAll(c.base.Append(
dirChecksum,
@@ -136,10 +130,7 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
continue
}
c.msg.Verbosef(
"destroying substitute %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
c.msg.Verbosef("destroying substitute %s...", name)
if !dry {
if err = os.Remove(c.base.Append(
dirStatus,
+12 -12
View File
@@ -48,7 +48,7 @@ func TestClean(t *testing.T) {
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/h6qx7m0vsyhO6oLEJgY2rKa1c6RZuIZ4QXxZSh__NZJ9VU0MIj5bFB-KuaPcsfpE": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/pPRjw2XYgjB5k8dYedwxTBMgHh4_v2JM_G2Vd-skQbAGOOgPsl3CGSUbEF7om_MO": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"lock": {Mode: 0644},
"variant": {Mode: 0400},
@@ -69,7 +69,7 @@ func TestClean(t *testing.T) {
"checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk": {Mode: 0400, Data: []byte("\xfd")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/tkrOYhQfTRaArk4nNYNjTmHQUmuJMVIoDeAKIQBm3I4uuMimBKXKMIY2gGZqwQg4": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk")},
"identifier/FMwSBYw22KqM8jZryfY2ChHXpLuVDdWYyNOYdHvIVYk8ujY6UnGRm5brr2sTTfpD": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk")},
"lock": {Mode: 0644},
"variant": {Mode: 0400},
@@ -122,16 +122,16 @@ func TestClean(t *testing.T) {
"checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE/result": {Mode: 0444},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
"identifier/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
"identifier/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"lock": {Mode: 0644},
"variant": {Mode: 0400},
"status": {Mode: fs.ModeDir | 0700},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"substitute/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"substitute/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"fault": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
@@ -199,18 +199,18 @@ func TestClean(t *testing.T) {
"checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv": {Mode: 0400, Data: []byte("kept")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
"identifier/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
"identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
"identifier/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
"lock": {Mode: 0644},
"variant": {Mode: 0400},
"status": {Mode: fs.ModeDir | 0700},
"status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0400, Data: []byte(statusHeader + "kept")},
"status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0400, Data: []byte(statusHeader + "kept")},
"status/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: 0400, Data: []byte(statusHeader + "kept")},
"status/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: 0400, Data: []byte(statusHeader + "kept")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
"substitute/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
"fault": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
@@ -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, base, nil)
c, err := pkg.Open(t.Context(), msg, 0, 0, 0, base)
if err != nil {
t.Fatal(err)
}
+2 -29
View File
@@ -6,9 +6,6 @@ import (
"fmt"
"io"
"os"
"hakurei.app/internal/xz"
"hakurei.app/internal/zstd"
)
const (
@@ -16,10 +13,6 @@ const (
Gzip = iota
// Bzip2 denotes a stream compressed via [bzip2].
Bzip2
// Zstd denotes a stream compressed via [zstd].
Zstd
// XZ denotes a stream compressed via [xz].
XZ
)
// A decompressArtifact is a [FileArtifact] decompressing a backing
@@ -73,8 +66,8 @@ func init() {
})
}
// Inputs returns a slice containing the backing file.
func (a *decompressArtifact) Inputs() []Artifact {
// Dependencies returns a slice containing the backing file.
func (a *decompressArtifact) Dependencies() []Artifact {
return []Artifact{a.f}
}
@@ -98,9 +91,6 @@ func (c compoundCloser) Close() error {
return err
}
// IsExecutable returns false.
func (*decompressArtifact) IsExecutable() bool { return false }
// Cure returns a decompressor [io.ReadCloser].
func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
sr, err := r.Open(a.f)
@@ -124,23 +114,6 @@ func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
io.Closer
}{bzip2.NewReader(br), br}, nil
case Zstd:
return struct {
io.Reader
io.Closer
}{zstd.NewReader(br), br}, nil
case XZ:
var _dr io.Reader
if _dr, err = xz.NewReader(br, 0); err != nil {
_ = br.Close()
return nil, err
}
return struct {
io.Reader
io.Closer
}{_dr, br}, nil
default:
return nil, os.ErrInvalid
}
+7 -9
View File
@@ -36,12 +36,6 @@ func TestDecompress(t *testing.T) {
return (pkg.Checksum)(h.Sum(nil))
}()
gh := pkg.NewDecompress(pkg.NewHTTPGet(
&client,
"file:///testdata",
testdataChecksum,
), pkg.Gzip)
checkWithCache(t, []cacheTestCase{
{"decompress", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
cureMany(t, c, []cureStep{
@@ -49,12 +43,16 @@ func TestDecompress(t *testing.T) {
&client,
"file:///testdata",
pkg.Checksum{0xfd},
), pkg.Gzip), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
), pkg.Gzip), nil, nil, &pkg.ChecksumMismatchError{
Got: testdataChecksum,
Want: pkg.Checksum{0xfd},
}},
{"gzip", gh, ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), pkg.WNew, nil},
{"gzip", pkg.NewDecompress(pkg.NewHTTPGet(
&client,
"file:///testdata",
testdataChecksum,
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -63,7 +61,7 @@ func TestDecompress(t *testing.T) {
"checksum/" + pkg.Encode(sha512.Sum384([]byte{0})): {Mode: 0400, Data: []byte{0}},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + pkg.Encode(pkg.NewIR().Ident(gh).Value()): {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
"identifier/QpjkahDrz7pz-tv0eAGNXR6x9NAtTjWCK5Hr7G1cIZj9rT7bLYJWUQeLD4wamAlF": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
"substitute": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
+13 -34
View File
@@ -30,16 +30,10 @@ import (
// AbsWork is the container pathname [TContext.GetWorkDir] is mounted on.
var AbsWork = fhs.AbsRoot.Append("work/")
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"
)
const EnvJobs = "CURE_JOBS"
// ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make
// it available at under in the container.
@@ -413,9 +407,9 @@ func init() {
func(r *IRReader) Artifact { return readExecArtifact(r, true) })
}
// Inputs returns a slice of all artifacts collected from caller-supplied
// Dependencies returns a slice of all artifacts collected from caller-supplied
// [ExecPath].
func (a *execArtifact) Inputs() []Artifact {
func (a *execArtifact) Dependencies() []Artifact {
artifacts := make([][]Artifact, 0, len(a.paths))
for _, p := range a.paths {
artifacts = append(artifacts, p.A)
@@ -444,7 +438,7 @@ func scanVerbose(
msg message.Msg,
cancel context.CancelFunc,
done chan<- struct{},
prefix, suffix string,
prefix string,
r io.Reader,
) {
defer close(done)
@@ -454,7 +448,7 @@ func scanVerbose(
bufio.MaxScanTokenSize<<12,
)
for s.Scan() {
msg.Verbose(prefix, s.Text()+suffix)
msg.Verbose(prefix, s.Text())
}
if err := s.Err(); err != nil && !errors.Is(err, os.ErrClosed) {
cancel()
@@ -477,7 +471,7 @@ const SeccompPresets = std.PresetStrict &
func (a *execArtifact) makeContainer(
ctx context.Context,
msg message.Msg,
flags, jobs, load int,
flags, jobs int,
hostNet bool,
temp, work *check.Absolute,
getArtifact GetArtifactFunc,
@@ -514,10 +508,7 @@ 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),
EnvLoad + "=" + strconv.Itoa(load),
})
z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
z.Grow(len(a.paths) + 4)
if a.arch != runtime.GOARCH {
@@ -626,7 +617,7 @@ func (c *Cache) EnterExec(
return ErrNotExec
}
deps := Collect(a.Inputs())
deps := Collect(a.Dependencies())
if _, _, err = c.Cure(&deps); err == nil {
return errors.New("unreachable")
} else if !IsCollected(err) {
@@ -658,9 +649,8 @@ func (c *Cache) EnterExec(
var z *container.Container
z, err = e.makeContainer(
ctx, c.msg,
c.attr.Flags,
c.attr.Jobs,
c.attr.Load,
c.flags,
c.jobs,
hostNet,
temp, work,
func(a Artifact) (*check.Absolute, unique.Handle[Checksum]) {
@@ -703,7 +693,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.attr.Flags, f.GetJobs(), f.GetLoad(), hostNet,
ctx, msg, f.cache.flags, f.GetJobs(), hostNet,
f.GetTempDir(), f.GetWorkDir(),
f.GetArtifact,
f.cache.Ident,
@@ -728,25 +718,14 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
brStdout, brStderr := f.cache.getReader(stdout), f.cache.getReader(stderr)
stdoutDone, stderrDone := make(chan struct{}), make(chan struct{})
var suffix, prefixO, prefixE string
if f.cache.attr.Flags&CColourOutput != 0 {
suffix = "\x1b[0m"
prefixO = "\x1b[1;37m(" + a.name + ")\x1b[0m"
prefixE = "\x1b[1;97m(" + a.name + ")\x1b[0m"
} else {
prefixO = "(" + a.name + ":1)"
prefixE = "(" + a.name + ":2)"
}
go scanVerbose(
msg, cancel, stdoutDone,
prefixO, suffix,
"("+a.name+":1)",
io.TeeReader(brStdout, status),
)
go scanVerbose(
msg, cancel, stderrDone,
prefixE, suffix,
"("+a.name+":2)",
io.TeeReader(brStderr, status),
)
defer func() {
+25 -22
View File
@@ -84,7 +84,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil},
), ignorePathname, wantOffline, 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, pkg.WSubstitute, nil},
), ignorePathname, wantOffline, nil},
{"error passthrough", pkg.NewExec(
"", "", nil, 0, false, true,
@@ -118,8 +118,11 @@ func TestExec(t *testing.T) {
[]string{"testtool"},
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
), nil, nil, pkg.WNew, pkg.InputError{
failingArtifact: stub.UniqueError(0xcafe),
), nil, nil, &pkg.DependencyCureError{
{
A: failingArtifact,
Err: stub.UniqueError(0xcafe),
},
}},
{"invalid paths", pkg.NewExec(
@@ -130,7 +133,7 @@ func TestExec(t *testing.T) {
[]string{"testtool"},
pkg.ExecPath{},
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths},
), nil, nil, pkg.ErrInvalidPaths},
})
// check init failure passthrough
@@ -180,11 +183,11 @@ func TestExec(t *testing.T) {
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/QwS7SmiatdqryQYgESdGw7Yw2PcpNf0vNfpvUA0t92BTlKiUjfCrXyMW17G2X77X": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/" + expected.Offline: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/" + expected.OfflineS: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/_OHzj_xdmfpaWfFN-_D9JpGpPlIjh84873E3Ui9xwv9PPPIt0BlzvH-cnPNeRsTl": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -222,7 +225,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantNet, pkg.WNew, nil},
), ignorePathname, wantNet, nil},
})
destroyStatus(t, base, 2, 0)
@@ -239,7 +242,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.Net: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")},
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -266,7 +269,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil},
), ignorePathname, wantOffline, nil},
})
destroyStatus(t, base, 2, 0)
@@ -281,7 +284,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.OvlRoot: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -313,7 +316,7 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil},
), ignorePathname, wantOffline, nil},
})
destroyStatus(t, base, 2, 0)
@@ -328,7 +331,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.Work: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -382,7 +385,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil},
), ignorePathname, wantOffline, nil},
})
destroyStatus(t, base, 2, 0)
@@ -400,9 +403,9 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/2uIvmnqtzAx4Ed4PWV8xjZCWeJCwfE2IcCc0evM-Nd8mDUlgSU6nLtPLcpPUcMlG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
"identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
"identifier/" + expected.Layers: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -435,7 +438,7 @@ func TestExec(t *testing.T) {
},
}),
pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil},
), ignorePathname, wantOffline, nil},
})
destroyStatus(t, base, 2, 0)
@@ -449,8 +452,8 @@ func TestExec(t *testing.T) {
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/Vzj9qaSVBtNyBQv_PW6uojFOWTwraHoaC0C6xdaGG1q_HTvSh4KLVxRcEQU1jd2Y": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -500,7 +503,7 @@ func TestExec(t *testing.T) {
".": {Mode: fs.ModeDir | 0500},
"check": {Mode: 0400, Data: []byte("binfmt")},
}, pkg.WNew, nil},
}, nil},
})
destroyStatus(t, base, 2, 0)
@@ -516,9 +519,9 @@ func TestExec(t *testing.T) {
"checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3/check": {Mode: 0400, Data: []byte("binfmt")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/c-HodmoEG0f_WGdst9aN-duLMH7QDDXOUi7UcyArXMeM1fc9lYKKQlTCW8ktaK8X": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3")},
"identifier/6VQTJ1lI5BmVuI1YFYJ8ClO3MRORvTTrcWFDcUU-l5Ga8EofxCxGlSTYN-u8dKj_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3")},
"identifier/_v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV")},
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute": {Mode: fs.ModeDir | 0700},
+2 -17
View File
@@ -12,7 +12,6 @@ type fileArtifact []byte
var _ KnownChecksum = new(fileArtifact)
var _ CuresExempt = new(fileArtifact)
var _ RevisionArtifact = new(fileArtifact)
// fileArtifactNamed embeds fileArtifact alongside a caller-supplied name.
type fileArtifactNamed struct {
@@ -64,8 +63,8 @@ func init() {
})
}
// Inputs returns a nil slice.
func (*fileArtifact) Inputs() []Artifact { return nil }
// Dependencies returns a nil slice.
func (*fileArtifact) Dependencies() []Artifact { return nil }
// IsExclusive returns false: Cure returns a prepopulated buffer.
func (*fileArtifact) IsExclusive() bool { return false }
@@ -77,20 +76,6 @@ func (a *fileArtifact) Checksum() Checksum {
return Checksum(h.Sum(nil))
}
// Revision satisfies [RevisionArtifact] for incompatible IsExecutable behaviour.
func (*fileArtifact) Revision() uint64 { return 0 }
// IsExecutable returns whether the contents begin with shebang or the ELF
// magic number.
func (a *fileArtifact) IsExecutable() bool {
return a != nil &&
(bytes.HasPrefix(
*a, []byte{'#', '!'},
) || bytes.HasPrefix(
*a, []byte{0x7f, 'E', 'L', 'F'},
))
}
// Cure returns the caller-supplied data.
func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(*a)), nil
+5 -24
View File
@@ -12,41 +12,22 @@ func TestFile(t *testing.T) {
t.Parallel()
want := expectsFile{0}
const ident = "N7M6W8-e55Wky_1q1a6qRKFVDw1S5XtPdB4HE2YZObG8OFum8HittyJgZUG5Ru2u"
wantShebang := expectsFile("#!/bin/sh\n")
const identShebang = "oKTGZb_TRtJf5G1iGGj4SOx1WUbI6YhmsUeEsCNvmK9tZYRwdwQf-DLFUxRPx5qm"
wantELF := expectsFile("\x7fELF\xde\xad\xbe\xef")
const identELF = "LjeHmIJgD1SiXIH8ewpGRed2_LU84NLapstnOAa_0hxLd8YY7x4KM0aApsj-RwCh"
checkWithCache(t, []cacheTestCase{
{"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
cureMany(t, c, []cureStep{
{"short", pkg.NewFile("null", want), base.Append(
{"short", pkg.NewFile("null", []byte{0}), base.Append(
"identifier",
ident,
), want, pkg.WNew, nil},
{"shebang", pkg.NewFile("shebang", wantShebang), base.Append(
"identifier",
identShebang,
), wantShebang, pkg.WNew, nil},
{"elf", pkg.NewFile("ELF", wantELF), base.Append(
"identifier",
identELF,
), wantELF, pkg.WNew, nil},
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
), want, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
"checksum": {Mode: fs.ModeDir | 0700},
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: want},
"checksum/" + pkg.Encode(wantShebang.hash()): {Mode: 0500, Data: wantShebang},
"checksum/" + pkg.Encode(wantELF.hash()): {Mode: 0500, Data: wantELF},
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: []byte{0}},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + ident: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(want.hash()))},
"identifier/" + identShebang: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(wantShebang.hash()))},
"identifier/" + identELF: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(wantELF.hash()))},
"identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -1,11 +1,11 @@
package expected
const (
Offline = "IKmVhALejtYA3JhN1PCfjKF-Dio1XVcOeMWDHhfSHCbb4iBNhGjFy2UspZveZvb8"
OfflineS = "6ZubjSyCnz4-TKgQZi_BbY-JUwsStYCtD_f-BTDOOotfEbqkm47W20AazHRaLviz"
OvlRoot = "Yox7WpG8B_OqIXWF4HWFZkUfsEl7DGzpFyZM0qtd9T8nQ-7SAkEUurlAe6_DJ6Iu"
Layers = "aAwfxDB-efVo379FNl178jK7HEKU3LEjHbZdaVVjk7GnXGZGEANNsXnB3SCUxM9A"
Net = "IU3GwU2jTBd7HjotvFo2wsDWBQGVGpamwiSKdc2G1EnhM-ZaacxAuK6q0wbTVxra"
Promote = "rOjetGHzT_jPErrBR24IAZKDj8Q9dLLqxFQqloMgjsULss0VXDI--n6LxuMBHvmZ"
Work = "7f9XDeREfvJIjCe0qesND0s0tasExAIcc-OH33-eq9tsrQPUXhJp4KEkpsYH4hCD"
Offline = "q5ktDTq0miP-VvB2blxqXQeaRXCUWgP_KbC18KNtUDtyoaI_h5mHmGuPMArVEBDs"
OfflineS = "IY91PCtOpCYy21AaIK0c9f8-Z6fb2_2ewoHWkt4dxoLf0GOrWqS8yAGFLV84b1Dw"
OvlRoot = "NacZGXwuRkTvcHaG08a22ujJ8qCWN0RSoFlRSR5FSt0ZcBbJ28FRvkYsHEtX7G8i"
Layers = "WBJDrATtX6rIE5yAu8ePX3WmDF0Tt9kFiue0m3cRnyRoVx1my8a67fh3CAW486oP"
Net = "CmYtj2sNB3LHtqiDuck_Lz3MjLLIiwyP8N4NDitQ1Icvv__LVP9p8tm-sHeQaKKp"
Promote = "TX3eCloaQFkV-SZIH6Jg6E5WKH--rcXY1P0jnZKmLFKWrNqnOzd4G9eIBh6i5ywN"
Work = "OuNiLSC68pZhAOr1YQ4WbV1tzASA0nxLEBcK7lO7MqxDY_j8dmP_C612RTuF23Lu"
)
@@ -1,11 +1,11 @@
package expected
const (
Offline = "MTgCSzwPrzGigp9phvDPRwUTNGLm1KM2EsEtbz-l2cNieqjaGtnzm65CDXlSxXrl"
OfflineS = "p89bQg7_jR4nwaSbpEd08ne1jHOEw7Wlnlyv5FHq7ba1Kml3HSBZwEKRzu0gCqEb"
OvlRoot = "9ifwO6MAaV9kTqRR2O5PJzm8XhfXbr50mFLWyEHQm8OHHcJtAEUgXZzJYoZt9YVV"
Layers = "INuGActFPwJtS7mAR9Bkt7FD4yoHlXHSJ9CaSAQJrpkUBL_k815Cs_jvRfxy5-a7"
Net = "kJvy24uk4ePvHoxSKf4vMOhR4NxLbmyWlA9bTS7d3z3fE9WF1Tvpao9g-QuYU4vm"
Promote = "lYqyYrfjPawIbld5Qz0NbKvd_bmI3nJC1eEnlIQWzsjWE9uA1HuKPAaClnDeyG6L"
Work = "V6k4FqOBMRCmHiqchs5-joVGZ_MhNWZyXm3gdbU0S7S5eMze7G4SwYMTf66ojKQL"
Offline = "WapqyoPxbWSnq07dWHt71mHaJXq99pAjJfFlELlJljSiZMhTFqqlzU1_mN86shSj"
OfflineS = "ibQZHcdXgNQ1OiMX1FrburBbGPVvKEHvPilbQCkm_0oV0BQCHomyyTbYNrFMGIwl"
OvlRoot = "V9anFOiRvjGfAeBhLl14AL8TKdWZyD0WTPYe4fS9mOBw8iW5Lmarvt6TG6MV8uWm"
Layers = "tKx7JNRoSBdK_7MdzI-nwTNV2wmiPzwYdcd17oLmXKL_iLmUzUiA79qTqdrTasrv"
Net = "aXyDLzBCJ9XltXZIfetEVsEkrqHfcXuD5XE_FcUnYbN3emwL55N6P8LlHzNfGnM5"
Promote = "3k4V16n96Lq04gjFSKmm4sFjyQ883FFBNXgTy9s_DjeTwxT3pg_iacEh8yMb_S4m"
Work = "6Q49MhFWRE3Ne6MycwAotgl1GtoU5WCHqJNWG2byYZCY-zX-IxPrWiKk7bKkNzhE"
)
@@ -1,11 +1,11 @@
package expected
const (
Offline = "LlieSHVDe1lnKvfI8t4oGRg_2hPxwyy1drmaqc-EKCOENuS9C2YHrp2VY5pSyhbg"
OfflineS = "qccjM8oYjUuEYPKFFzAxDFVzMerSUKUZc18NdVQoiPWf-70XOsNK8NaUQqjTgTAD"
OvlRoot = "lpV2bb_KGYFHPiOn-jtGop8K_ew0y1p3BezRp0ebM93_a-T9J-vkqGD5uokda1aN"
Layers = "sM3DJm210CHPGHkAquIbrXhspB81FpVC60ApQrvJGD5El2i7cSONj7LWf7EWqKpT"
Net = "JihQUwsVETRYjb2-yIXLYZ6WVsaFebwl8btSYAsNQ2QapS5MZVaI-dYwrVoySycR"
Promote = "lGqwR4W2OjylSVitMQP1lc6wApOBkbMjsmIqkxQbfEZ3DHEQBbJr84ErW6Xb54zo"
Work = "aZgtyv6aMtoHFkHAaJr6nLaA7N_SHjShgWPyQ5UdzaIqYSiVqvCrZqSokGTCcTii"
Offline = "Z6yXE5gOJScL3srmnVMWgCXccDiUNZ5snSrf6RkXuU1_U0rX_kGVwsfHUgNG_awd"
OfflineS = "zN16xv6LKRJRipUJwupyxg2rZcvf-qpsMn_qCxUmgxlTSuNwYI70ZEb7dHW5k0gO"
OvlRoot = "zYXJHFRLuxvUhuisZEXgGgVvdQd6piMfp5jmtT6jdVjvC2gICXquOq-UTwlrSD5I"
Layers = "_F8EDazHbcLeT0sVSQXRN_kn9IjduqJcDYgzXpsT-hpKU4EBcZ0PISN2zchpqMbm"
Net = "CA_FAaSIYJgapBEHV40doxpH23PdUEy_6s1TZc7wfSPN0XYqwGpMceXXDSabGveO"
Promote = "_3LPrLp--4h9k4GsNNApu9hHtAafq-GUhfU6d4hJKBDKT3bz_szOsvkXxc5sK53d"
Work = "FEgHeiCD_WT4wsfB-9kDH5n6cRWCEYtJmXdKZgmUUukAOoXumH_hLlosXREC-tqq"
)
+1 -9
View File
@@ -38,15 +38,7 @@ func main() {
}
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
for _, t := range []string{
"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
} {
if s == t {
return true
}
}
return false
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
})
var hostNet, layers, promote bool
+26 -44
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. The pathname field may not be populated.
// checksum values if non-nil.
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.Inputs].
// [Artifact.Dependencies].
func (i *IContext) WriteIdent(a Artifact) {
buf := i.ic.getIdentBuf()
defer i.ic.putIdentBuf(buf)
@@ -235,14 +235,13 @@ 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. The pathname field is unused. Caller must acquire
// Cache.identMu.
// for a non-nil ident. Caller must acquire Cache.identMu.
func (ic *irCache) encode(
w io.Writer,
a Artifact,
inputs map[Artifact]cureRes,
) (err error) {
deps := a.Inputs()
deps := a.Dependencies()
idents := make([]*extIdent, len(deps))
if inputs == nil {
for i, d := range deps {
@@ -278,11 +277,10 @@ func (ic *irCache) encode(
return *a == *b
})
// kind uint64 | rev uint64 | deps_sz uint64
var buf [wordSize * 3]byte
// kind uint64 | deps_sz uint64
var buf [wordSize * 2]byte
binary.LittleEndian.PutUint64(buf[:], uint64(a.Kind()))
binary.LittleEndian.PutUint64(buf[wordSize:], GetRevision(a))
binary.LittleEndian.PutUint64(buf[wordSize*2:], uint64(len(idents)))
binary.LittleEndian.PutUint64(buf[wordSize:], uint64(len(idents)))
if _, err = w.Write(buf[:]); err != nil {
return
}
@@ -332,7 +330,7 @@ func (ic *irCache) encodeAll(
return
}
for _, d := range a.Inputs() {
for _, d := range a.Dependencies() {
if err = ic.encodeAll(w, d, encoded); err != nil {
return
}
@@ -434,9 +432,9 @@ type (
// Common buffer for word-sized reads.
buf [wordSize]byte
// Inputs sent before params, sorted by identifier. Resliced on
// Dependencies sent before params, sorted by identifier. Resliced on
// each call to Next and checked to be depleted during Finalise.
inputs []*extIdent
deps []*extIdent
// Number of values already read, -1 denotes a finalised IRReader.
count int
@@ -520,7 +518,7 @@ const (
irMaxValues = 1 << 12
// irMaxDeps is the arbitrary maximum number of direct dependencies allowed
// to be returned by [Artifact.Inputs] and subsequently decoded by
// to be returned by [Artifact.Dependencies] and subsequently decoded by
// [IRDecoder].
irMaxDeps = 1 << 10
)
@@ -605,17 +603,17 @@ func (ir *IRReader) mustReadHeader(k IRValueKind) {
// putAll returns all dependency buffers to the underlying [Cache].
func (ir *IRReader) putAll() {
for _, buf := range ir.inputs {
for _, buf := range ir.deps {
ir.d.c.putIdentBuf(buf)
}
ir.inputs = nil
ir.deps = 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.inputs == nil {
if ir.deps == nil {
panic("attempting to discard dependencies twice")
}
ir.putAll()
@@ -627,13 +625,13 @@ var ErrDependencyDepleted = errors.New("reading past end of dependencies")
// Next returns the next unstructured dependency.
func (ir *IRReader) Next() Artifact {
if len(ir.inputs) == 0 {
if len(ir.deps) == 0 {
panic(ErrDependencyDepleted)
}
id := unique.Make(ID(ir.inputs[0][wordSize:]))
ir.d.c.putIdentBuf(ir.inputs[0])
ir.inputs = ir.inputs[1:]
id := unique.Make(ID(ir.deps[0][wordSize:]))
ir.d.c.putIdentBuf(ir.deps[0])
ir.deps = ir.deps[1:]
if a, ok := ir.d.ident[id]; !ok {
ir.putAll()
@@ -686,8 +684,8 @@ func (ir *IRReader) Finalise() (checksum unique.Handle[Checksum], ok bool) {
}
ir.r, ir.ibw = nil, nil
if len(ir.inputs) != 0 {
panic(MissedDependencyError(len(ir.inputs)))
if len(ir.deps) != 0 {
panic(MissedDependencyError(len(ir.deps)))
}
return
@@ -741,15 +739,6 @@ func (ir *IRReader) ReadString() string {
return unsafe.String(unsafe.SliceData(p), len(p))
}
// A RevisionError describes the first [Artifact] in an IR stream claiming a
// revision not supported by the registered implementation.
type RevisionError [2]uint64
func (e RevisionError) Error() string {
return "claimed revision " + strconv.FormatUint(e[0], 10) +
" differs from implementation value " + strconv.FormatUint(e[1], 10)
}
// decode decodes the next [Artifact] in the IR stream and returns any buffer
// originating from [Cache] before returning. decode returns [io.EOF] if and
// only if the underlying [io.Reader] is already read to EOF.
@@ -782,9 +771,6 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
return
}
ir.mustRead(ir.buf[:])
rev := binary.LittleEndian.Uint64(ir.buf[:])
defer ir.putAll()
ir.mustRead(ir.buf[:])
sz := binary.LittleEndian.Uint64(ir.buf[:])
@@ -792,11 +778,11 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
err = ErrIRDepend
return
}
ir.inputs = make([]*extIdent, sz)
for i := range ir.inputs {
ir.inputs[i] = d.c.getIdentBuf()
ir.deps = make([]*extIdent, sz)
for i := range ir.deps {
ir.deps[i] = d.c.getIdentBuf()
}
for _, buf := range ir.inputs {
for _, buf := range ir.deps {
ir.mustRead(buf[:])
}
@@ -805,10 +791,6 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
err = syscall.ENOTRECOVERABLE
return
}
if _rev := GetRevision(a); _rev != rev {
err = RevisionError{rev, _rev}
return
}
if ir.count != -1 {
err = ErrRemainingIR
@@ -823,8 +805,8 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
d.ident[id] = a
} else {
d.c.msg.Verbosef(
"artifact %s%s%s appeared more than once in IR stream",
d.c.sgrIdent, Encode(id.Value()), d.c.sgrRes,
"artifact %s appeared more than once in IR stream",
Encode(id.Value()),
)
}
-33
View File
@@ -135,36 +135,3 @@ func TestIRRoundtrip(t *testing.T) {
}
checkWithCache(t, testCasesCache)
}
func TestRevision(t *testing.T) {
checkWithCache(t, []cacheTestCase{{"revision", 0, nil,
func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
a := pkg.NewFile("", nil)
var buf bytes.Buffer
if err := c.EncodeAll(&buf, a); err != nil {
t.Fatal(err)
}
if _, err := c.NewDecoder(
bytes.NewReader(buf.Bytes()),
).Decode(); err != nil {
t.Fatalf("Decode: error = %v", err)
}
p := buf.Bytes()
p[8] = 0xfd
wantErr := pkg.RevisionError{0xfd, 0}
if _, err := c.NewDecoder(
bytes.NewReader(p),
).Decode(); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("Decode: error = %v, want %v", err, wantErr)
}
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
"checksum": {Mode: fs.ModeDir | 0700},
"identifier": {Mode: fs.ModeDir | 0700},
"substitute": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
},
}})
}
+2 -5
View File
@@ -54,8 +54,8 @@ func init() {
})
}
// Inputs returns a nil slice.
func (*httpArtifact) Inputs() []Artifact { return nil }
// Dependencies returns a nil slice.
func (*httpArtifact) Dependencies() []Artifact { return nil }
// IsExclusive returns false: Cure returns as soon as a response is received.
func (*httpArtifact) IsExclusive() bool { return false }
@@ -74,9 +74,6 @@ func (e ResponseStatusError) Error() string {
return "the requested URL returned non-OK status: " + http.StatusText(int(e))
}
// IsExecutable returns false.
func (*httpArtifact) IsExecutable() bool { return false }
// Cure sends the http request and returns the resulting response body reader
// wrapped to perform checksum validation. It is valid but not encouraged to
// close the resulting [io.ReadCloser] before it is read to EOF, as that causes
+2 -2
View File
@@ -104,7 +104,7 @@ func TestHTTPGet(t *testing.T) {
)
wantPathname := base.Append(
"identifier",
"COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue",
"oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_",
)
if pathname, checksum, err := c.Cure(f); err != nil {
t.Fatalf("Cure: error = %v", err)
@@ -158,7 +158,7 @@ func TestHTTPGet(t *testing.T) {
"checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU": {Mode: 0400, Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
"identifier/oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
"substitute": {Mode: fs.ModeDir | 0700},
+210 -471
View File
File diff suppressed because it is too large Load Diff
+148 -280
View File
@@ -35,14 +35,14 @@ import (
"hakurei.app/message"
)
var skipLock = func() pkg.CacheAttr {
var attr pkg.CacheAttr
*(*bool)(unsafe.Pointer(reflect.ValueOf(&attr).
Elem().
FieldByName("skipLock").
UnsafeAddr())) = true
return attr
}()
//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 (
// extension is a string uniquely identifying a set of custom [Artifact]
@@ -142,7 +142,7 @@ type stubArtifact struct {
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) Dependencies() []pkg.Artifact { return a.deps }
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
func (*stubArtifact) IsExclusive() bool { return false }
@@ -158,7 +158,7 @@ type stubArtifactF struct {
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) 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 }
@@ -170,8 +170,6 @@ type stubFile struct {
stubArtifact
}
func (*stubFile) IsExecutable() bool { return false }
func (a *stubFile) Cure(*pkg.RContext) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(a.data)), a.err
}
@@ -332,7 +330,7 @@ func TestIdent(t *testing.T) {
},
nil,
}, unique.Make[pkg.ID](pkg.MustDecode(
"fkmge-H56Ph2LzNNbEUjTypes8LfOxrF_CEXg07kq6ho_nbTNvzQde9-bjB7gyB_",
"97Y85QewssfPbNIN9cyNhzD4e6dLHcDTU8rb2c34k-aCrZfBNXFUc0duPiLFFcw_",
))},
}
@@ -341,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, a, nil); err != nil {
} else if cache, err = pkg.Open(t.Context(), msg, 0, 0, 0, a); err != nil {
t.Fatal(err)
}
t.Cleanup(cache.Close)
@@ -521,10 +519,7 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
}
var scrubFunc func() error // scrub after hashing
if c, err := pkg.Open(t.Context(), msg, base, &pkg.CacheAttr{
Cures: 1 << 4,
Flags: flags,
}); err != nil {
if c, err := pkg.Open(t.Context(), msg, flags, 1<<4, 0, base); err != nil {
t.Fatalf("Open: error = %v", err)
} else {
t.Cleanup(c.Close)
@@ -632,7 +627,6 @@ type cureStep struct {
pathname *check.Absolute
output expectsKnown
whence int
err error
}
@@ -652,7 +646,7 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
for _, step := range steps {
t.Log("cure step:", step.name)
if pathname, checksum, whence, err := c.CureWhence(step.a); !reflect.DeepEqual(err, step.err) {
if pathname, checksum, err := c.Cure(step.a); !reflect.DeepEqual(err, step.err) {
faults, _err := c.ReadFaults(step.a)
if _err != nil {
t.Errorf("ReadFaults: error = %v", _err)
@@ -669,8 +663,6 @@ 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()) {
@@ -782,28 +774,28 @@ func TestCache(t *testing.T) {
identifier,
new(testdata.hash()),
testdata, nil,
), wantPathname, testdata, pkg.WNew, nil},
), wantPathname, testdata, nil},
{"identical content", newStubFile(
pkg.KindHTTPGet,
identifier0,
new(testdata.hash()),
testdata, nil,
), wantPathname0, testdata, pkg.WCache, nil},
), wantPathname0, testdata, nil},
{"existing entry", newStubFile(
pkg.KindHTTPGet,
identifier,
new(testdata.hash()),
testdata, nil,
), wantPathname, testdata, pkg.WCache, nil},
), wantPathname, testdata, nil},
{"checksum mismatch", newStubFile(
pkg.KindHTTPGet,
pkg.ID{0xff, 0},
new(pkg.Checksum),
testdata, nil,
), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
), nil, nil, &pkg.ChecksumMismatchError{
Got: testdata.hash(),
}},
@@ -824,13 +816,13 @@ func TestCache(t *testing.T) {
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
}, pkg.WNew, nil},
}, nil},
{"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{
kind: pkg.KindExec,
params: []byte("artifact overridden to be incomplete"),
}}, nil, nil, pkg.WNew, pkg.InvalidArtifactError(pkg.MustDecode(
"poVrv3zNINbHd-WUJihwgWQwJpbHURFHfpY7Zux-ztto_bQhhS5PdpbNMjdkXv-V",
}}, nil, nil, pkg.InvalidArtifactError(pkg.MustDecode(
"E__uZ1sLIvb84vzSm5Uezb03RogsiaeTt1nfIVv8TKnnf4LqwtSi-smdHhlkZrUJ",
))},
{"error passthrough", newStubFile(
@@ -838,18 +830,18 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1},
nil,
nil, stub.UniqueError(0xcafe),
), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
), nil, nil, stub.UniqueError(0xcafe)},
{"error caching", newStubFile(
pkg.KindHTTPGet,
pkg.ID{0xff, 1},
nil,
nil, nil,
), nil, nil, pkg.WCache, stub.UniqueError(0xcafe)},
), nil, nil, stub.UniqueError(0xcafe)},
{"cache hit bad type", overrideChecksum{testdata.hash(), overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar,
}}}, nil, nil, pkg.WCache, pkg.InvalidFileModeError(
}}}, nil, nil, pkg.InvalidFileModeError(
0400,
)},
@@ -861,18 +853,21 @@ func TestCache(t *testing.T) {
cure: func(f *pkg.FContext) error {
panic("attempting to cure impossible artifact")
},
}, nil, nil, pkg.WNew, pkg.InputError{
failingFile: struct {
}, nil, nil, &pkg.DependencyCureError{
{
A: failingFile,
Err: struct {
_ []byte
stub.UniqueError
}{UniqueError: 0xbad},
},
}},
})
if c0, err := pkg.Open(
if c0, err := unsafeOpen(
t.Context(),
message.New(nil),
base, &skipLock,
0, 0, 0, base, false,
); err != nil {
t.Fatalf("open: error = %v", err)
} else {
@@ -880,7 +875,7 @@ func TestCache(t *testing.T) {
cureMany(t, c0, []cureStep{
{"cache hit ident", overrideIdent{
id: identifier,
}, wantPathname, testdata, pkg.WCache, nil},
}, wantPathname, testdata, nil},
{"cache miss checksum match", newStubFile(
pkg.KindHTTPGet,
@@ -891,7 +886,7 @@ func TestCache(t *testing.T) {
), base.Append(
"identifier",
pkg.Encode(testdata.hash()),
), testdata, pkg.WNew, nil},
), testdata, nil},
})
// cure after close
@@ -1021,30 +1016,30 @@ func TestCache(t *testing.T) {
{"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar,
cure: makeSample,
}}}, wantPathname, want, pkg.WNew, nil},
}}}, wantPathname, want, nil},
{"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar,
}}}, wantPathname, want, pkg.WCache, nil},
}}}, wantPathname, want, nil},
{"identical checksum", overrideIdent{id0, &stubArtifact{
kind: pkg.KindTar,
cure: makeSample,
}}, wantPathname0, want, pkg.WNew, nil},
}}, wantPathname0, want, 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, pkg.WNew, stub.UniqueError(0xcafe)},
}}, nil, nil, 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.WNew, &pkg.ChecksumMismatchError{
}}}, nil, nil, &pkg.ChecksumMismatchError{
Got: pkg.MustDecode(
"CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT",
),
@@ -1055,7 +1050,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 2},
new(want.hash()),
testdata, nil,
), nil, nil, pkg.WCache, pkg.InvalidFileModeError(
), nil, nil, pkg.InvalidFileModeError(
fs.ModeDir | 0500,
)},
@@ -1069,7 +1064,7 @@ func TestCache(t *testing.T) {
_, err = io.ReadAll(r)
return err
},
}}, nil, nil, pkg.WNew, &os.PathError{
}}, nil, nil, &os.PathError{
Op: "read",
Path: base.Append(
"checksum",
@@ -1083,14 +1078,14 @@ func TestCache(t *testing.T) {
cure: func(t *pkg.TContext) error {
return nil
},
}}, nil, nil, pkg.WNew, pkg.NoOutputError{}},
}}, nil, nil, 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, pkg.WNew, errors.New("non-file artifact produced regular file")},
}}, nil, nil, errors.New("non-file artifact produced regular file")},
{"symlink output", overrideIdent{pkg.ID{0xff, 6}, &stubArtifact{
kind: pkg.KindTar,
@@ -1100,7 +1095,7 @@ func TestCache(t *testing.T) {
t.GetWorkDir().String(),
)
},
}}, nil, nil, pkg.WNew, pkg.InvalidFileModeError(
}}, nil, nil, pkg.InvalidFileModeError(
fs.ModeSymlink | 0777,
)},
@@ -1120,8 +1115,8 @@ func TestCache(t *testing.T) {
},
}, base.Append(
"identifier",
"gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9",
), want, pkg.WNew, nil},
"xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-",
), want, nil},
{"substitutable", &stubArtifactF{
kind: pkg.KindExec,
@@ -1139,14 +1134,14 @@ func TestCache(t *testing.T) {
},
}, base.Append(
"identifier",
"VGjpp7NVw3OYLpgOQumfM0KcJgY3suz6torykUczcg4bGT24ySkPn5hy-4dNqqkR",
), want, pkg.WSubstitute, nil},
"k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f",
), want, nil},
})
if c0, err := pkg.Open(
if c0, err := unsafeOpen(
t.Context(),
message.New(nil),
base, &skipLock,
0, 0, 0, base, false,
); err != nil {
t.Fatalf("open: error = %v", err)
} else {
@@ -1168,8 +1163,8 @@ func TestCache(t *testing.T) {
},
}, base.Append(
"identifier",
"zeZ4JEZ0atAKl6Am67cBID6-KR18nZGgeYfU4qTuYaWhQC4eAn0dyTXdIBH9Bos8",
), want, pkg.WSubstitute, nil},
"_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_",
), want, nil},
})
}
@@ -1193,15 +1188,15 @@ func TestCache(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/zeZ4JEZ0atAKl6Am67cBID6-KR18nZGgeYfU4qTuYaWhQC4eAn0dyTXdIBH9Bos8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/___9_QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
"identifier/_wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
"identifier/_woAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
"identifier/VGjpp7NVw3OYLpgOQumfM0KcJgY3suz6torykUczcg4bGT24ySkPn5hy-4dNqqkR": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/nWPg893oqn_YNN8kgfZrs_LVLwP90e0mKxqU8UwoazQh-yBPwhoviD7of6YALx-M": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"substitute/OyBGorh72Z9kVw35JUa8FbqDbpR4DqT-MX1jic0uKN5PdYmUBiAF38BRsIRnBigf": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"work": {Mode: fs.ModeDir | 0700},
}},
@@ -1240,7 +1235,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1},
nil,
nil, stub.UniqueError(0xbad),
), nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
), nil, nil, stub.UniqueError(0xbad)},
{"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar,
@@ -1251,7 +1246,7 @@ func TestCache(t *testing.T) {
0400,
)
},
}}, nil, nil, pkg.WNew, errors.New(
}}, nil, nil, errors.New(
"non-file artifact produced regular file",
)},
})
@@ -1368,14 +1363,14 @@ func TestCache(t *testing.T) {
}}}, base.Append(
"identifier",
pkg.Encode(pkg.ID{0xff, 0}),
), want, pkg.WNew, nil},
), want, 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, pkg.WNew, stub.UniqueError(0xbad)},
}}}, nil, nil, stub.UniqueError(0xbad)},
{"match", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
kind: pkg.KindTar,
@@ -1385,7 +1380,7 @@ func TestCache(t *testing.T) {
}}}, base.Append(
"identifier",
pkg.Encode(pkg.ID{0xff, 1}),
), want, pkg.WNew, nil},
), want, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -1413,7 +1408,7 @@ func TestCache(t *testing.T) {
), base.Append(
"identifier",
pkg.Encode(pkg.Checksum{0xfe, 0}),
), expectsChecksum{0xff, 0}, pkg.WNew, nil},
), expectsChecksum{0xff, 0}, nil},
})
for _, p := range [][]string{
@@ -1490,7 +1485,7 @@ func TestCache(t *testing.T) {
), expectsFS{
".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444},
}, pkg.WNew, nil},
}, nil},
{"substituted", substituted, base.Append(
"identifier",
@@ -1498,7 +1493,7 @@ func TestCache(t *testing.T) {
), expectsFS{
".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444},
}, pkg.WSubstitute, nil},
}, nil},
})
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -1509,18 +1504,18 @@ func TestCache(t *testing.T) {
"checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV": {Mode: 0400, Data: []byte("destroyed")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/CLyyxJWn1yUGFs_0KnJ4ZSU2hH4-elvGFRB36x14LrNrKBJPxvORhL9O4Rc7oeYU": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"identifier/arv8a6z4i0x6pUb5Z2T-3iE4ETvyZj-uReHGKsS7uiBgMgKNEOzTGG3LIZb8vp0L": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"identifier/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/L-A8SK4ZX631eyealbJVH08u5pAVEf2NMk8RmLlxl7BVADkU4hNjWD6pi5H7uL1F": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"identifier/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/aSMwvPAwdsIF9e1spuLyRNEc8aTFA4HRVasoNqGjxdm1laSMs2h2teGsoSzLp_pR": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"status": {Mode: fs.ModeDir | 0700},
"status/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x")},
"status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"status/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM")},
"status/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"status/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"substitute/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"work": {Mode: fs.ModeDir | 0700},
}},
@@ -1591,14 +1586,14 @@ func TestCache(t *testing.T) {
{"extern", a, base.Append(
"identifier",
pkg.Encode(wantIdent.Value()),
), wantOutput, pkg.WExternal, nil},
), wantOutput, nil},
{"substitute", _a, base.Append(
"identifier",
pkg.Encode(_wantIdent.Value()),
), _wantOutput, pkg.WExternal, nil},
), _wantOutput, nil},
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
{"mismatch", kca, nil, nil, &pkg.ChecksumMismatchError{
Got: wantChecksum,
}},
})
@@ -1612,163 +1607,17 @@ func TestCache(t *testing.T) {
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/ofaXbB5gIza_7W4Rzo5XDe_8FwlCPKWn3TBcmGgFAkkTWMl5GXGmOzX89Jd2Mk2A": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"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/c4aCI00C-ZVyo_FQDQLl1OYK4U_kjzxwrLdFDiXMHnbMcZXCkXo_nxUWauScZ_4V": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/cNoG77frXGRCJa7fUi1INKUEQg7L4qrX5acsSv-wqZdGZT7dQwM93rD3at6kSFFF": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
"identifier/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"status": {Mode: fs.ModeDir | 0700},
"status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")},
"status/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: 0400, Data: []byte("\x00")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"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/3fYJjSiWhklt7TK9MPVLGk5_8AIU8ostTcFPXULJf_qeAVG6pmC-Cqqu4ZhEXRxn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/mXlNz_v77nW7jstn_rJn4RL7dCQlkakM0y-HjO6tkDubtzaj-wCmW1hIr2Gk64_O": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"status": {Mode: fs.ModeDir | 0700},
"status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute/MccYezQ4pshkeBV4w_aAEIwvZdKHL3OAgAkR3ouZ43EF94Ur1HBHaN7njPfJAj50": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"substitute/VV5W0_DiA1iylaqbKFThp1ZpV_y1ccVS1XyqDnDaXoHQ-EEyPI4XFrQHcHOF2hWG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"substitute/qOYrxy9ztKeOA96Os811_0Ox5sd8FBOxis6psJAnRJL5MLazFMaqmd4g7t7k1OHk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"work": {Mode: fs.ModeDir | 0700},
}},
@@ -1786,7 +1635,7 @@ func TestErrors(t *testing.T) {
}{
{"InvalidLookupError", pkg.InvalidLookupError{
0xff, 0xf0,
}, "attempting to look up non-input artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
}, "attempting to look up non-dependency artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
{"InvalidArtifactError", pkg.InvalidArtifactError{
0xff, 0xfd,
@@ -1946,7 +1795,7 @@ errors during scrub:
}
}
func TestInputError(t *testing.T) {
func TestDependencyCureError(t *testing.T) {
t.Parallel()
makeIdent := func(ident ...byte) pkg.Artifact {
@@ -1959,40 +1808,56 @@ func TestInputError(t *testing.T) {
testCases := []struct {
name string
err pkg.InputError
err pkg.DependencyCureError
want string
unwrap []error
}{
{"simple", pkg.InputError{
makeIdent(0xff, 9): stub.UniqueError(0xbad09),
makeIdent(0xff, 0): stub.UniqueError(0xbad00),
makeIdent(0xff, 0xf): stub.UniqueError(0xbad0f),
makeIdent(0xff, 1): stub.UniqueError(0xbad01),
}, `errors curing inputs:
{"simple", pkg.DependencyCureError{
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
}, `errors curing dependencies:
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
stub.UniqueError(0xbad00),
stub.UniqueError(0xbad01),
stub.UniqueError(0xbad09),
stub.UniqueError(0xbad0f),
&pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
&pkg.CureError{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
&pkg.CureError{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
&pkg.CureError{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
}},
{"dedup", pkg.InputError{
makeIdent(0xff, 9): stub.UniqueError(0xbad09),
makeIdent(0xff, 9): stub.UniqueError(0xbad09),
makeIdent(0xff, 9): stub.UniqueError(0xbad09),
makeIdent(0xff, 0): stub.UniqueError(0xbad00),
makeIdent(0xff, 0): stub.UniqueError(0xbad00),
makeIdent(0xff, 1): stub.UniqueError(0xbad01),
}, `errors curing inputs:
{"dedup", pkg.DependencyCureError{
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
{A: makeIdent(0xff, 0xfd), Err: &pkg.DependencyCureError{
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
{A: makeIdent(0xff, 0xc), Err: &pkg.DependencyCureError{
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
}},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
}},
{A: makeIdent(0xff, 0xff), Err: &pkg.DependencyCureError{
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
{A: makeIdent(0xff, 0xc), Err: &pkg.DependencyCureError{
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
}},
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
}},
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
}, `errors curing dependencies:
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite`, []error{
stub.UniqueError(0xbad00),
stub.UniqueError(0xbad01),
stub.UniqueError(0xbad09),
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
&pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
&pkg.CureError{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
&pkg.CureError{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
&pkg.CureError{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
}},
}
for _, tc := range testCases {
@@ -2018,7 +1883,7 @@ func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
func (earlyFailureF) Params(*pkg.IContext) {}
func (earlyFailureF) IsExclusive() bool { return false }
func (a earlyFailureF) Inputs() []pkg.Artifact {
func (a earlyFailureF) Dependencies() []pkg.Artifact {
deps := make([]pkg.Artifact, a)
for i := range deps {
deps[i] = a - 1
@@ -2036,21 +1901,19 @@ 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())
for b.Loop() {
b.StopTimer()
c, err := pkg.Open(b.Context(), msg, check.MustAbs(b.TempDir()), nil)
c, err := pkg.Open(b.Context(), msg, 0, 0, 0, check.MustAbs(b.TempDir()))
if err != nil {
b.Fatal(err)
}
b.StartTimer()
_, _, err = c.Cure(earlyFailureF(8))
b.StopTimer()
if !errors.Is(err, stub.UniqueError(0xcafe)) {
b.Fatalf("Cure: error = %v", err)
}
c.Close()
b.StartTimer()
dce := err.(*pkg.DependencyCureError)
for b.Loop() {
dce.Unwrap()
}
}
@@ -2087,8 +1950,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
check.MustAbs(container.Nonexistent),
nil,
0, 0, 0, check.MustAbs(container.Nonexistent),
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2116,8 +1978,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
tempDir.Append("cache"),
nil,
0, 0, 0, tempDir.Append("cache"),
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2139,8 +2000,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
tempDir.Append("cache"),
nil,
0, 0, 0, tempDir.Append("cache"),
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2161,7 +2021,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open(
t.Context(),
message.New(nil),
tempDir.Append("cache"), nil,
0, 0, 0, tempDir.Append("cache"),
); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
}
@@ -2214,8 +2074,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)
}
@@ -2253,7 +2113,7 @@ func TestExtensionRegister(t *testing.T) {
pkg.Register(pkg.KindCustomOffset, nil)
t.Cleanup(func() { opened = false })
_, _ = pkg.Open(nil, nil, nil, nil)
_, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
panic("unreachable")
})
@@ -2264,7 +2124,11 @@ func TestExtensionRegister(t *testing.T) {
base := check.MustAbs(t.TempDir())
t.Cleanup(func() { opened = false })
if c, err := pkg.Open(t.Context(), nil, base, nil); err != nil {
if c, err := pkg.Open(
t.Context(), nil,
0, 0, 0,
base,
); err != nil {
t.Fatal(err)
} else {
c.Close()
@@ -2292,7 +2156,8 @@ func TestExtensionRegister(t *testing.T) {
}
if _, err := pkg.Open(
t.Context(), nil,
base, nil,
0, 0, 0,
base,
); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("Open: error = %v, want %v", err, wantErr)
}
@@ -2313,8 +2178,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)
}
@@ -2327,7 +2192,8 @@ func TestExtensionRegister(t *testing.T) {
if c, err := pkg.Open(
t.Context(), nil,
base, &pkg.CacheAttr{Flags: pkg.CPromoteVariant},
pkg.CPromoteVariant, 0, 0,
base,
); err != nil {
t.Fatalf("Open: error = %v", err)
} else {
@@ -2352,7 +2218,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(), nil,
base, nil,
0, 0, 0,
base,
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
t.Fatalf("Open: error = %v", err)
}
@@ -2369,7 +2236,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open(
t.Context(), nil,
base, nil,
0, 0, 0,
base,
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
t.Fatalf("Open: error = %v", err)
}
+2 -9
View File
@@ -58,8 +58,8 @@ func init() {
})
}
// Inputs returns a slice containing the backing file.
func (a *tarArtifact) Inputs() []Artifact {
// Dependencies returns a slice containing the backing file.
func (a *tarArtifact) Dependencies() []Artifact {
return []Artifact{a.f}
}
@@ -172,13 +172,6 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
break
case tar.TypeChar:
t.GetMessage().Verbosef(
"%sskipping character device %d, %d %q%s",
t.cache.sgrWarn, header.Devmajor, header.Devminor, header.Name, t.cache.sgrRes,
)
continue
case tar.TypeXGlobalHeader:
continue // ignore
+30 -11
View File
@@ -3,6 +3,7 @@ package pkg_test
import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/sha512"
"errors"
"io/fs"
@@ -79,8 +80,8 @@ func TestTar(t *testing.T) {
"checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"identifier/v9DUj2R4YK_3ae0m9VuUYI-HJysDDCENu1k10thxioycRzFH1Qejw5bBGukm4IdL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"identifier/T68YqeEW5moiwVe4J0wPvjERgyMUd4k_cKKxTcQx6AXqZaQAuuryu-Iv-qxDV6-T": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -103,8 +104,8 @@ func TestTar(t *testing.T) {
"checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
"identifier": {Mode: fs.ModeDir | 0700},
"identifier/1SuvgGltcsgqps9tWqjULG8RCdpx_6KVWXdsMd5xPKvdtysOxqpE-3bLu4j0WpGk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
"identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
"identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
"identifier/e3BECw_x_vDyTvj2P48MJVgwpgALeXQ90Ye2Y8gr6SwIPtMup6SR2LVcCTDRGpVi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -131,7 +132,16 @@ func checkTarHTTP(
if err := w.Close(); err != nil {
t.Fatalf("Close: error = %v", err)
}
testdata = buf.String()
var zbuf bytes.Buffer
gw := gzip.NewWriter(&zbuf)
if _, err := gw.Write(buf.Bytes()); err != nil {
t.Fatalf("Write: error = %v", err)
}
if err := gw.Close(); err != nil {
t.Fatalf("Close: error = %v", err)
}
testdata = zbuf.String()
}
testdataChecksum := func() pkg.Checksum {
@@ -198,19 +208,28 @@ func checkTarHTTP(
defer newDestroyArtifactFunc(&tarDirType)(t, base, c)
cureMany(t, c, []cureStep{
{"file", pkg.NewTar(pkg.NewHTTPGet(
{"file", pkg.NewTar(pkg.NewDecompress(pkg.NewHTTPGet(
&client,
"file:///testdata",
testdataChecksum,
)), ignorePathname, want, pkg.WNew, nil},
), pkg.Gzip)), ignorePathname, want, nil},
{"directory", pkg.NewTar(&tarDir), ignorePathname, want, pkg.WNew, nil},
{"directory", pkg.NewTar(pkg.NewDecompress(
&tarDir,
pkg.Gzip,
)), ignorePathname, want, nil},
{"multiple entries", pkg.NewTar(&tarDirMulti), nil, nil, pkg.WNew, errors.New(
{"multiple entries", pkg.NewTar(pkg.NewDecompress(
&tarDirMulti,
pkg.Gzip,
)), nil, nil, errors.New(
"input directory does not contain a single regular file",
)},
{"bad type", pkg.NewTar(&tarDirType), nil, nil, pkg.WNew, errors.New(
{"bad type", pkg.NewTar(pkg.NewDecompress(
&tarDirType,
pkg.Gzip,
)), nil, nil, errors.New(
"input directory does not contain a single regular file",
)},
@@ -220,6 +239,6 @@ func checkTarHTTP(
cure: func(t *pkg.TContext) error {
return stub.UniqueError(0xcafe)
},
}), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
}), nil, nil, stub.UniqueError(0xcafe)},
})
}
+1 -1
View File
@@ -55,7 +55,7 @@ func TestDispatch(t *testing.T) {
}),
},
}, true, []string{`{"kind":"fatal","message":"rejecting coldboot loop","error":"unique error 51966 injected by the test suite"}
`, `{"kind":"inconsistent","message":"processed inconsistent uevent","error":{"fault":1,"event":{"action":"add","devpath":"\u0000","env":{"V":"` + "\ufffd" + `"},"seqnum":2,"subsystem":""},"object":{"state":1,"devpath":"\u0000","subsystem":"","env":{"V":"` + "\ufffd" + `"}}}}
`, `{"kind":"inconsistent","message":"processed inconsistent uevent","error":{"fault":1,"event":{"action":"add","devpath":"\u0000","env":{"V":"\ufffd"},"seqnum":2,"subsystem":""},"object":{"state":1,"devpath":"\u0000","subsystem":"","env":{"V":"\ufffd"}}}}
`}, `dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite
dispatch: processed inconsistent uevent: duplicate add event on devpath "\x00"
`, nil},
+6 -59
View File
@@ -12,7 +12,7 @@ import (
// Value are types supported by the language.
type Value interface {
bool | int64 | string | []string | []int64 | [][2]string | Nil
bool | int64 | string | []string | []int64 | [][2]string
}
type (
@@ -33,29 +33,6 @@ type (
F func(args FArgs) (v any, set bool, err error)
V map[unique.Handle[Ident]]any
}
// Nil represents an untyped nil.
Nil struct{}
// AString represents an argument string that may be nil.
AString struct {
V string
Nil bool
}
)
// NilError is returned for an invalid nil assignment.
type NilError struct{ reflect.Type }
func (e NilError) Error() string {
return fmt.Sprintf("attempting to assign nil to %s", e.Type)
}
var (
// nilStringV is the [reflect.Value] of an Azalea nil assigned to an [AString].
nilStringV = reflect.ValueOf(AString{Nil: true})
// nilStringT is the [reflect.Type] of nilStringV.
nilStringT = nilStringV.Type()
)
// Apply applies named arguments and rejects unused arguments.
@@ -73,8 +50,8 @@ func (args FArgs) Apply(v map[unique.Handle[Ident]]any) error {
}
return UndefinedError(arg.K.Value())
}
if err := storeE(r, arg.V); err != nil {
err := storeE(r, arg.V)
if err != nil {
return err
}
}
@@ -138,38 +115,11 @@ func (e TypeError) Is(err error) bool {
}
// storeE is a convenience function to set the value of a result pointer.
func storeE(rp, r any) error {
func storeE(rp any, r any) error {
pv := reflect.ValueOf(rp).Elem()
pt := pv.Type()
as := nilStringT.AssignableTo(pt)
if r == (Nil{}) {
switch kind := pt.Kind(); kind {
case reflect.Bool, reflect.String:
return NilError{pt}
default:
if rv, ok := rp.(*any); ok && !reflect.ValueOf(*rv).IsValid() {
*rv = Nil{}
} else if as {
pv.Set(nilStringV)
} else {
pv.SetZero()
}
return nil
}
}
v := reflect.ValueOf(r)
if vt := v.Type(); !vt.AssignableTo(pt) {
if as {
var asv AString
if err := storeE(&asv.V, r); err != nil {
return err
}
pv.Set(reflect.ValueOf(asv))
return nil
}
pt, vt := pv.Type(), v.Type()
if !vt.AssignableTo(pt) {
return TypeError{vt, pt}
}
pv.Set(v)
@@ -276,9 +226,6 @@ func evaluateAny(d PF, s []Frame, expr, rp any) bool {
case "false":
store(rp, false)
return true
case "nil":
store(rp, Nil{})
return true
default:
return evaluateAny(d, s, v, rp)
}
+5 -69
View File
@@ -100,79 +100,15 @@ func TestEvaluate(t *testing.T) {
Err: UndefinedError("f"),
}},
{"error wrap deep", `f { v = nonexistent; }`, makeStackCheck(func(
{"error wrap deep", `f { v = nil; }`, makeStackCheck(func(
FArgs,
) (any, error) {
panic("unreachable")
}), "", EvaluationError{
Expr: Ident("nonexistent"),
Err: UndefinedError("nonexistent"),
Expr: Ident("nil"),
Err: UndefinedError("nil"),
}},
{"nil", `f { v = nil; }`, checkArgs(FArgs{
{K: unique.Make(Ident("v")), V: Nil{}},
}), "\xfd", nil},
{"apply nil string", `f { v = nil; }`, makeStackCheck(func(
args FArgs,
) (v any, err error) {
var s string
err = args.Apply(map[unique.Handle[Ident]]any{
unique.Make(Ident("v")): &s,
})
v = s
return
}), "", EvaluationError{
Expr: Func{
Ident: Ident("f"),
Args: []Arg{
{K: []Ident{"v"}, V: Val{Ident("nil")}},
},
},
Err: NilError{Type: reflect.TypeFor[string]()},
}},
{"apply nil AString", `f { v = nil; }`, makeStackCheck(func(
args FArgs,
) (v any, err error) {
s := AString{}
err = args.Apply(map[unique.Handle[Ident]]any{
unique.Make(Ident("v")): &s,
})
v = s.V
if !s.Nil {
err = fmt.Errorf("got non-nil string %q", s.V)
}
return
}), "", nil},
{"apply AString", `f { v = "\xfd"; }`, makeStackCheck(func(
args FArgs,
) (v any, err error) {
s := AString{}
err = args.Apply(map[unique.Handle[Ident]]any{
unique.Make(Ident("v")): &s,
})
v = s.V
if s.Nil {
err = fmt.Errorf("unexpected nil %q", s.V)
}
return
}), "\xfd", nil},
{"apply nil", `f { v = nil; }`, makeStackCheck(func(
args FArgs,
) (v any, err error) {
s := make([]struct{}, 9)
err = args.Apply(map[unique.Handle[Ident]]any{
unique.Make(Ident("v")): &s,
})
if s != nil {
err = fmt.Errorf("got non-nil value %#v", s)
}
return
}), "", nil},
{"common inputs", `package name { inputs, v = []; }`, nil, "", EvaluationError{
Expr: Func{
Ident: Ident("name"),
@@ -278,8 +214,8 @@ func TestEvaluate(t *testing.T) {
}
var errEquals bool
if e, ok := errors.AsType[TypeError](err); ok {
errEquals = e.Is(tc.err)
if _, ok := errors.AsType[TypeError](err); ok {
errEquals = errors.Is(err, tc.err)
} else {
errEquals = reflect.DeepEqual(err, tc.err)
}
+1 -6
View File
@@ -18,11 +18,6 @@ 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.
@@ -107,7 +102,7 @@ func skipGNUTests(tests ...int64) string {
buf.WriteString(strconv.Itoa(int(n - 1)))
buf.WriteString(" ")
}
if i == len(tests)-1 || (tests[i+1] != n+1 && tests[i+1] != n+2) {
if i == len(tests)-1 || tests[i+1] != n+1 {
buf.WriteString(strconv.Itoa(int(n + 1)))
buf.WriteString("-")
}
-1
View File
@@ -16,7 +16,6 @@ func TestSkipGNUTests(t *testing.T) {
}{
{[]int64{764}, "1-763 765-"},
{[]int64{764, 0xcafe, 37, 9}, "1-8 10-36 38-763 765-51965 51967-"},
{[]int64{168, 170, 623, 764}, "1-167 169 171-622 624-763 765-"},
{[]int64{1, 2, 0xbed}, "3-3052 3054-"},
{[]int64{3, 4}, "1-2 5-"},
}
+124
View File
@@ -0,0 +1,124 @@
package rosa
import (
"fmt"
"io"
"net/http"
"os"
"time"
"hakurei.app/fhs"
"hakurei.app/internal/pkg"
)
// busyboxBin is a busybox binary distribution installed under bin/busybox.
type busyboxBin struct {
// Underlying busybox binary.
bin pkg.FileArtifact
}
// Kind returns the hardcoded [pkg.Kind] value.
func (a busyboxBin) Kind() pkg.Kind { return kindBusyboxBin }
// Params is a noop.
func (a busyboxBin) Params(*pkg.IContext) {}
// IsExclusive returns false: Cure performs a trivial filesystem write.
func (busyboxBin) IsExclusive() bool { return false }
// Dependencies returns the underlying busybox [pkg.FileArtifact].
func (a busyboxBin) Dependencies() []pkg.Artifact {
return []pkg.Artifact{a.bin}
}
func init() {
pkg.Register(kindBusyboxBin, func(r *pkg.IRReader) pkg.Artifact {
a := busyboxBin{r.Next().(pkg.FileArtifact)}
if _, ok := r.Finalise(); ok {
panic(pkg.ErrUnexpectedChecksum)
}
return a
})
}
// String returns the reporting name of the underlying file prefixed with expand.
func (a busyboxBin) String() string {
return "expand-" + a.bin.(fmt.Stringer).String()
}
// Cure installs the underlying busybox [pkg.File] to bin/busybox.
func (a busyboxBin) Cure(t *pkg.TContext) (err error) {
var r io.ReadCloser
if r, err = t.Open(a.bin); err != nil {
return
}
defer func() {
closeErr := r.Close()
if err == nil {
err = closeErr
}
}()
binDir := t.GetWorkDir().Append("bin")
if err = os.MkdirAll(binDir.String(), 0700); err != nil {
return
}
var w *os.File
if w, err = os.OpenFile(
binDir.Append("busybox").String(),
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
0500,
); err != nil {
return
}
defer func() {
closeErr := w.Close()
if err == nil {
err = closeErr
}
}()
_, err = io.Copy(w, r)
return
}
// newBusyboxBin returns a [pkg.Artifact] containing a busybox installation from
// the https://busybox.net/downloads/binaries/ binary release.
func (s *S) newBusyboxBin() pkg.Artifact {
var version, url, checksum string
switch s.arch {
case "amd64":
version = "1.35.0"
url = "https://busybox.net/downloads/binaries/" +
version + "-" + s.linuxArch() + "-linux-musl/busybox"
checksum = "L7OBIsPu9enNHn7FqpBT1kOg_mCLNmetSeNMA3i4Y60Z5jTgnlX3qX3zcQtLx5AB"
case "arm64":
version = "1.31.0"
url = "https://busybox.net/downloads/binaries/" +
version + "-defconfig-multiarch-musl/busybox-armv8l"
checksum = "npJjBO7iwhjW6Kx2aXeSxf8kXhVgTCDChOZTTsI8ZfFfa3tbsklxRiidZQdrVERg"
default:
panic("unsupported target " + s.arch)
}
return pkg.NewExec(
"busybox-bin-"+version, s.arch, nil, pkg.ExecTimeoutMax, false, false,
fhs.AbsRoot, []string{
"PATH=/system/bin",
},
AbsSystem.Append("bin", "busybox"),
[]string{"hush", "-c", "" +
"busybox mkdir -p /work/system/bin/ && " +
"busybox cp /system/bin/busybox /work/system/bin/ && " +
"busybox --install -s /work/system/bin/"},
pkg.Path(AbsSystem, true, busyboxBin{pkg.NewHTTPGet(
&http.Client{Transport: &http.Transport{
// busybox website is really slow to respond
TLSHandshakeTimeout: 2 * time.Minute,
}}, url,
mustDecode(checksum),
)}),
)
}
+4 -5
View File
@@ -35,7 +35,7 @@ type CMakeHelper struct {
var _ Helper = new(CMakeHelper)
// extra returns the cmake handle alongside either ninja or make.
func (attr *CMakeHelper) extra() P {
func (attr *CMakeHelper) extra(int) P {
if attr != nil && attr.Make {
return P{_cmake, _make}
}
@@ -61,10 +61,10 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
}
generate := "Ninja"
test := "ninja " + jobsFlagE + " " + loadFlagE + " test"
test := "ninja " + jobsFlagE + " test"
if attr.Make {
generate = "'Unix Makefiles'"
test = "make " + jobsFlagE + " " + loadFlagE + " test"
test = "make " + jobsFlagE + " test"
}
if attr.Test != "" {
test = attr.Test
@@ -84,7 +84,6 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
return `
cmake -G ` + generate + ` \
-Wno-author -Wno-unused-cli \
-DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \
-DCMAKE_CXX_COMPILER_TARGET="${ROSA_TRIPLE}" \
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
@@ -98,7 +97,7 @@ cmake -G ` + generate + ` \
}), " \\\n\t") + ` \
-DCMAKE_INSTALL_PREFIX=/system \
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
cmake --build . --parallel=` + jobsE + ` -- ` + loadFlagE + `
cmake --build . --parallel=` + jobsE + `
DESTDIR=/work cmake --install .
` + script
}
+2 -4
View File
@@ -107,8 +107,6 @@ func init() {
a := cureEtc{}
if r.ReadUint32() == 0 {
a.minimal = true
} else {
r.Next()
}
if _, ok := r.Finalise(); ok {
panic(pkg.ErrUnexpectedChecksum)
@@ -120,8 +118,8 @@ func init() {
// IsExclusive returns false: Cure performs a few trivial filesystem writes.
func (cureEtc) IsExclusive() bool { return false }
// Inputs returns a slice containing the backing iana-etc release.
func (a cureEtc) Inputs() []pkg.Artifact {
// Dependencies returns a slice containing the backing iana-etc release.
func (a cureEtc) Dependencies() []pkg.Artifact {
if !a.minimal {
return []pkg.Artifact{ianaEtc}
}
-104
View File
@@ -1,104 +0,0 @@
package rosa
import (
"errors"
"io/fs"
"os"
"path/filepath"
"hakurei.app/internal/pkg"
)
// gentooOverlay are symlinks on top of a Gentoo LLVM stage3 tarball for
// compatibility with the Rosa OS stage0 distribution.
type gentooOverlay struct{ stage3 pkg.Artifact }
// Kind returns the hardcoded [pkg.Kind] value.
func (a gentooOverlay) Kind() pkg.Kind { return kindGentooOverlay }
// Params is a noop.
func (a gentooOverlay) Params(*pkg.IContext) {}
// IsExclusive returns false: Cure performs a trivial filesystem write.
func (gentooOverlay) IsExclusive() bool { return false }
// Inputs returns the underlying Gentoo stage3.
func (a gentooOverlay) Inputs() []pkg.Artifact {
return []pkg.Artifact{a.stage3}
}
func init() {
pkg.Register(kindGentooOverlay, func(r *pkg.IRReader) pkg.Artifact {
a := gentooOverlay{r.Next()}
if _, ok := r.Finalise(); ok {
panic(pkg.ErrUnexpectedChecksum)
}
return a
})
}
// String returns a hardcoded name.
func (a gentooOverlay) String() string { return "gentoo-overlay" }
// Revision returns a hardcoded value incremented on layout changes.
func (a gentooOverlay) Revision() uint64 { return 0 }
// Cure installs the overlay.
func (a gentooOverlay) Cure(f *pkg.FContext) (err error) {
pathname, _ := f.GetArtifact(a.stage3)
var stage3 *os.Root
if stage3, err = os.OpenRoot(pathname.String()); err != nil {
return err
}
defer func() {
closeErr := stage3.Close()
if err == nil {
err = closeErr
}
}()
fsys := stage3.FS()
system := f.GetWorkDir().Append("system")
bin := system.Append("bin")
if err = os.MkdirAll(bin.String(), 0700); err != nil {
return
}
linknames := []string{
"../../bin/sh",
}
var dents []os.DirEntry
const llvm = "usr/lib/llvm"
dents, err = fs.ReadDir(fsys, llvm)
if err != nil {
return
}
if len(dents) != 1 {
return errors.New("stage3 /" + llvm + " contains more than one entry")
}
llvmBin := filepath.Join(llvm, dents[0].Name(), "bin")
dents, err = fs.ReadDir(fsys, llvmBin)
if err != nil {
return
}
for _, dent := range dents {
linknames = append(linknames, filepath.Join(
"../..",
llvmBin,
dent.Name(),
))
}
for _, linkname := range linknames {
if err = os.Symlink(
linkname,
bin.Append(filepath.Base(linkname)).String(),
); err != nil {
return
}
}
return
}
+5 -12
View File
@@ -20,13 +20,10 @@ func (t Toolchain) NewViaGit(
return t.New(strings.TrimSuffix(
path.Base(url),
".git",
)+"-src", path.Base(rev), nil, &PackageAttr{
KnownChecksum: &checksum,
HostNet: true,
Paths: []pkg.ExecPath{resolvconf()},
}, &GenericHelper{
Build: `
)+"-src-"+path.Base(rev), THostNet, t.Append(nil,
_nssCACert,
_git,
), &checksum, nil, `
git \
-c advice.detachedHead=false \
clone \
@@ -37,9 +34,5 @@ git \
`+url+` \
/work
rm -rf /work/.git
`,
},
_nssCACert,
_git,
)
`, resolvconf())
}
+28 -10
View File
@@ -13,7 +13,7 @@ func (t Toolchain) newGo(
script string,
boot ...pkg.Artifact,
) pkg.Artifact {
return t.New("go", version, newTar(
return t.NewPackage("go", version, newTar(
"https://go.dev/dl/go"+version+".src.tar.gz",
checksum,
pkg.Gzip,
@@ -56,15 +56,16 @@ ln -s \
func init() {
const (
version = "1.25.14"
checksum = "QKYjKzziCmD1eboU__Oi8VjqbPjaHrHAI9ceWyF3D9ORm7cPHN8muZuiGsoLKjCJ"
version = "1.26.4"
checksum = "fpqJlxa41wKRtbnviYNLk9VxgcL-5oIEDxsriF8svU6kNwQW70oRRA9gTz_ImVoB"
)
meta := Metadata{
Name: "go-bootstrap",
Description: "the Go programming language toolchain (bootstrap)",
Name: "go",
Description: "the Go programming language toolchain",
Website: "https://go.dev",
Version: version,
Exclude: true,
ID: 1227,
}
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
var (
@@ -75,7 +76,7 @@ func init() {
)
switch t.arch {
case "amd64":
bootstrapEarly = []pkg.Artifact{t.New("go", "1.4-bootstrap", newTar(
bootstrapEarly = []pkg.Artifact{t.NewPackage("go", "1.4-bootstrap", newTar(
"https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
"8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23",
pkg.Gzip,
@@ -151,8 +152,8 @@ sed -i \
)
go125 := t.newGo(
version,
checksum,
"1.25.11",
"cnqAQ8wpVZXcM6nHAfSqFkIW4L3H73ALB9rBfKUBbfgg4_pOF3I9zOZARgYQ6MR2",
[]string{"CGO_ENABLED=0"}, `
sed -i \
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
@@ -164,6 +165,23 @@ rm \
`, go123,
)
return &meta, go125
return &meta, t.newGo(
version,
checksum,
finalEnv, `
sed -i \
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
cmd/link/internal/`+t.arch+`/obj.go
sed -i \
's/cpu.X86.HasAVX512VBMI/& \&\& cpu.X86.HasPOPCNT/' \
internal/runtime/gc/scan/scan_amd64.go
rm \
os/root_unix_test.go \
cmd/cgo/internal/testsanitizers/tsan_test.go \
cmd/cgo/internal/testsanitizers/cshared_test.go
`, go125,
)
})
}
+178 -29
View File
@@ -1,9 +1,11 @@
package rosa
import (
"io/fs"
"regexp"
"slices"
"strings"
"unsafe"
"hakurei.app/internal/pkg"
)
@@ -11,12 +13,12 @@ import (
var (
_llvmSource = H("llvm-project")
_muslHeaders = H("musl-headers")
_earlyCompilerRT = H("early-compiler-rt")
_earlyRuntimes = H("early-runtimes")
_musl = H("musl")
_bash = H("bash")
_awk = H("awk")
_pythonEarly = H("python-early")
_gawk = H("gawk")
_coreutils = H("coreutils")
_diffutils = H("diffutils")
_findutils = H("findutils")
@@ -48,6 +50,165 @@ func litArgs(verbose bool, skipChecks ...string) string {
}
func init() {
var llvmPatches []KV
for _, name := range [...]string{
"increase-stack-size-unconditional",
"add-rosa-vendor",
"xfail-broken-tests",
"path-system-include",
"path-system-libraries",
} {
p, err := fs.ReadFile(nativeB, "package/llvm/"+name+".patch")
if err != nil {
panic(err)
}
llvmPatches = append(llvmPatches, KV{
name,
unsafe.String(unsafe.SliceData(p), len(p)),
})
}
native.MustRegister("early-compiler-rt", func(t Toolchain) (*Metadata, pkg.Artifact) {
meta := Metadata{
Name: "early-compiler-rt",
Description: "early LLVM runtime: compiler-rt",
Dependencies: P{_musl},
}
_meta, source := t.MustLoad(_llvmSource)
meta.Version = _meta.Version
major, _, _ := strings.Cut(meta.Version, ".")
return &meta, t.NewPackage("early-compiler-rt", meta.Version, source, &PackageAttr{
Flag: TExclusive,
}, &CMakeHelper{
Append: []string{"compiler-rt"},
Cache: []KV{
{"ENABLE_LINKER_BUILD_ID", "ON"},
// libc++ not yet available
{"CMAKE_CXX_COMPILER_TARGET", ""},
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
{"LLVM_ENABLE_RTTI", "ON"},
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
{"LLVM_LINK_LLVM_DYLIB", "ON"},
{"LLVM_ENABLE_PER_TARGET_RUNTIME_DIR", "ON"},
{"COMPILER_RT_BUILD_BUILTINS", "ON"},
{"COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"},
{"COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"},
{"COMPILER_RT_SANITIZERS_TO_BUILD", "asan"},
{"COMPILER_RT_BUILD_GWP_ASAN", "OFF"},
// does not work without libunwind
{"COMPILER_RT_BUILD_CTX_PROFILE", "OFF"},
{"COMPILER_RT_BUILD_LIBFUZZER", "OFF"},
{"COMPILER_RT_BUILD_MEMPROF", "OFF"},
{"COMPILER_RT_BUILD_PROFILE", "OFF"},
{"COMPILER_RT_BUILD_XRAY", "OFF"},
},
SkipTest: true,
Script: `
mkdir -p "/work/system/lib/clang/` + major + `/lib/"
ln -s \
"../../../${ROSA_TRIPLE}" \
"/work/system/lib/clang/` + major + `/lib/"
ln -s \
"clang_rt.crtbegin-` + t.linuxArch() + `.o" \
"/work/system/lib/${ROSA_TRIPLE}/crtbeginS.o"
ln -s \
"clang_rt.crtend-` + t.linuxArch() + `.o" \
"/work/system/lib/${ROSA_TRIPLE}/crtendS.o"
`,
},
_python,
_muslHeaders,
_kernelHeaders,
)
})
native.MustRegister("early-runtimes", func(t Toolchain) (*Metadata, pkg.Artifact) {
meta := Metadata{
Name: "early-runtimes",
Description: "early LLVM runtimes: libunwind, libcxx, libcxxabi",
Dependencies: P{
_earlyCompilerRT,
},
}
_meta, source := t.MustLoad(_llvmSource)
meta.Version = _meta.Version
return &meta, t.NewPackage("early-runtimes", meta.Version, source, &PackageAttr{
Flag: TExclusive,
}, &CMakeHelper{
Append: []string{"runtimes"},
Cache: []KV{
{"ENABLE_LINKER_BUILD_ID", "ON"},
// libc++ not yet available
{"CMAKE_CXX_COMPILER_WORKS", "ON"},
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
{"LLVM_ENABLE_RTTI", "ON"},
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
{"LLVM_LINK_LLVM_DYLIB", "ON"},
{"LLVM_ENABLE_RUNTIMES", "'libunwind;libcxx;libcxxabi'"},
{"LIBUNWIND_ENABLE_ASSERTIONS", "OFF"},
{"LIBUNWIND_USE_COMPILER_RT", "ON"},
{"LIBCXX_HAS_MUSL_LIBC", "ON"},
{"LIBCXX_USE_COMPILER_RT", "ON"},
{"LIBCXX_CXX_ABI", "libcxxabi"},
{"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"},
{"LIBCXX_HARDENING_MODE", "fast"},
{"LIBCXX_HAS_ATOMIC_LIB", "OFF"},
{"LIBCXXABI_USE_COMPILER_RT", "ON"},
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "OFF"},
{"LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL", "OFF"},
{"LLVM_ENABLE_ZLIB", "FORCE_ON"},
{"LLVM_ENABLE_ZSTD", "FORCE_ON"},
{"LLVM_ENABLE_LIBXML2", "OFF"},
},
SkipTest: true,
},
_python,
_zlib,
_zstd,
_earlyCompilerRT,
_kernelHeaders,
)
})
const (
version = "22.1.8"
checksum = "_QzoDE0W6cv0vfIWeLPDvqG_vKhz6IGWl1nqUUvhlKWiRzf5dMGqeC3tyS2XgI6j"
)
native.MustRegister("llvm-project", func(t Toolchain) (*Metadata, pkg.Artifact) {
meta := Metadata{
Name: "llvm-project",
Description: "LLVM monorepo with Rosa OS patches",
Version: version,
ID: 1830,
}
return &meta, t.NewPatchedSource("llvm-"+version, newFromGitHub(
"llvm/llvm-project",
"llvmorg-"+version,
checksum,
), true, llvmPatches...)
})
native.MustRegister("llvm", func(t Toolchain) (*Metadata, pkg.Artifact) {
meta := Metadata{
Name: "llvm",
@@ -83,11 +244,9 @@ func init() {
{"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"},
{"LIBCXX_HAS_MUSL_LIBC", "ON"},
{"LIBCXX_HARDENING_MODE", "fast"},
{"LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY", "ON"},
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "ON"},
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "OFF"},
{"LIBCXXABI_USE_COMPILER_RT", "ON"},
{"LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY", "ON"},
{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"},
{"LLVM_INSTALL_UTILS", "ON"},
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
@@ -140,10 +299,6 @@ func init() {
"CodeGen/PowerPC/ppc-tmmintrin.c",
"CodeGen/PowerPC/ppc-smmintrin.c",
"CodeGenCUDA/amdgpu-alias-undef-symbols.cu",
// clang: deadlocks with LIBCXXABI_ENABLE_STATIC_UNWINDER
"global-value-regex",
"global-hex-value-regex",
"check-globals",
// cxx: fails on musl
"close.dont-get-rid-of-buffer",
"re/re.traits",
@@ -184,19 +339,8 @@ func init() {
}...)
}
return &meta, t.New("llvm", meta.Version, source, &PackageAttr{
Exclusive: true,
Bin: []string{
"chmod",
"mkdir",
"rm",
"tr",
"awk",
},
ScriptEarly: `
rm -f /system/bin/clang++.cfg
`,
return &meta, t.NewPackage("llvm", meta.Version, source, &PackageAttr{
Flag: TExclusive,
}, &CMakeHelper{
Append: []string{"llvm"},
@@ -206,10 +350,6 @@ ln -s ld.lld /work/system/bin/ld
ln -s clang /work/system/bin/cc
ln -s clang /work/system/bin/cpp
ln -s clang++ /work/system/bin/c++
cat << EOF > /work/system/bin/clang++.cfg
-static-libstdc++
-Wl,--exclude-libs,libunwind.a:libc++.a:libc++experimental.a:libc++abi.a
EOF
`,
// LLVM_LINK_LLVM_DYLIB causes llvm test suite to leak system
@@ -218,13 +358,22 @@ EOF
// on 3-stage determinism to test later stages.
SkipTest: t.stage.isStage0(),
Test: "ninja " + jobsFlagE + " " + loadFlagE + " check-all",
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
`,
},
_pythonEarly,
_python,
_perl,
_diffutils,
_bash,
_awk,
_gawk,
_coreutils,
_findutils,
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func TestLLVMInputs(t *testing.T) {
const wantInputCount = 470
const wantInputCount = 553
_, llvm := rosa.Native().Std().MustLoad(rosa.H("llvm"))
var n int
+9 -13
View File
@@ -52,16 +52,15 @@ type MakeHelper struct {
var _ Helper = new(MakeHelper)
// extra returns make and other optional dependencies.
func (attr *MakeHelper) extra() P {
if attr == nil || !attr.OmitDefaults {
return P{
_make,
_awk,
func (attr *MakeHelper) extra(flag int) P {
extra := P{_make}
if (attr == nil || !attr.OmitDefaults) && flag&TEarly == 0 {
extra = append(extra,
_gawk,
_coreutils,
)
}
}
return P{_make}
return extra
}
// wantsChmod returns whether the build system needs to be generated.
@@ -90,7 +89,7 @@ func (attr *MakeHelper) wantsDir() (string, bool) {
if attr != nil && attr.InPlace {
return helperInPlace, false
}
return "/cure/", true
return `"$(mktemp -d)"`, false
}
// script generates the cure script.
@@ -161,8 +160,7 @@ func (attr *MakeHelper) script(t Toolchain, name string) string {
scriptMake := `
make \
` + jobsFlagE + ` \
` + loadFlagE
` + jobsFlagE
if len(attr.Make) > 0 {
scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t")
}
@@ -172,8 +170,6 @@ make \
(!attr.SkipCheckEarly || !t.stage.isStage0()) {
scriptMake += attr.ScriptCheckEarly + `make \
` + jobsFlagE + ` \
` + loadFlagE + ` \
AM_COLOR_TESTS=always \
`
if len(attr.Check) > 0 {
scriptMake += strings.Join(attr.Check, " \\\n\t")
+15 -45
View File
@@ -5,16 +5,10 @@ import (
"strings"
)
var (
_muon = H("muon")
_meson = H("meson")
)
var _meson = H("meson")
// MesonHelper builds and tests a meson project.
type MesonHelper struct {
// Use muon instead of meson.
Muon bool
// Runs after setup.
ScriptCompileEarly string
// Runs after compile.
@@ -35,12 +29,7 @@ type MesonHelper struct {
var _ Helper = new(MesonHelper)
// extra returns hardcoded meson runtime dependencies.
func (attr *MesonHelper) extra() P {
if !attr.isPython() {
return P{_muon}
}
return P{_meson}
}
func (*MesonHelper) extra(int) P { return P{_meson} }
// wantsChmod returns false.
func (*MesonHelper) wantsChmod() bool { return false }
@@ -54,12 +43,6 @@ func (*MesonHelper) scriptEarly() string { return "" }
// wantsDir requests a new directory in TMPDIR.
func (*MesonHelper) wantsDir() (string, bool) { return `"$(mktemp -d)"`, false }
// isPython returns whether the legacy python implementation is used.
func (attr *MesonHelper) isPython() bool {
return attr == nil ||
!attr.Muon || len(attr.SkipTests) != 0 || attr.InteractiveTest
}
// script generates the cure script.
func (attr *MesonHelper) script(t Toolchain, name string) string {
if attr == nil {
@@ -71,28 +54,11 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
scriptCompiled = "\n" + scriptCompiled
}
python := attr.isPython()
muon := "muon"
compile := " samu " + jobsFlagE
destdir := "-d"
if python {
muon = "meson"
compile = " compile " + jobsFlagE + " " + loadFlagE
destdir = "--destdir"
}
var scriptTest string
if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
scriptTest = `
` + muon + ` test \
` + jobsFlagE + ` \
-t 10`
if python {
scriptTest += ` \
meson test \
--print-errorlogs`
} else {
scriptTest += " -Rv"
}
if attr.InteractiveTest {
scriptTest += ` \
--interactive`
@@ -103,25 +69,29 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
}
return `
` + muon + ` setup \
cd "$(mktemp -d)"
meson setup \
` + strings.Join(slices.Collect(func(yield func(string) bool) {
for _, v := range append([]KV{
{"wrap_mode", "nofallback"},
{"wrap-mode", "nofallback"},
{"prefix", "/system"},
{"buildtype", "release"},
}, attr.Setup...) {
s := v[0]
s := "-" + v[0]
if len(v[0]) > 0 && v[0][0] != 'D' {
s = "-" + s
}
if v[1] != "" {
s = "-D" + s + "=" + v[1]
s += "=" + v[1]
}
if !yield(s) {
return
}
}
}), " \\\n\t") + ` \
'/usr/src/` + name + `'
` + muon + compile + scriptCompiled + scriptTest + `
` + muon + ` install \
` + destdir + ` /work
. '/usr/src/` + name + `'
meson compile` + scriptCompiled + scriptTest + `
meson install \
--destdir=/work
` + attr.Script
}
+113 -256
View File
@@ -14,7 +14,6 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"unique"
"hakurei.app/internal/pkg"
@@ -31,8 +30,8 @@ type Remote struct {
c *http.Client
}
// NewRemote returns a populated [Remote].
func NewRemote(c *http.Client, base string, pub ed25519.PublicKey) (Remote, error) {
// NewRemote returns a populated [Remote]
func NewRemote(base string, pub ed25519.PublicKey, c *http.Client) (Remote, error) {
u, err := url.Parse(base)
return Remote{u, pub, c}, err
}
@@ -202,261 +201,14 @@ func (r Remote) Status(
), nil
}
// 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.
// NewMirror returns an [http.Handler] for servicing mirror requests.
func NewMirror(
msg message.Msg,
fsys fs.FS,
key ed25519.PrivateKey,
) 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) {
) http.Handler {
const identName = "ident"
var mux http.ServeMux
mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func(
w http.ResponseWriter,
@@ -470,7 +222,38 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
writeF(m, w, &buf, m.writeArtifact)
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)
}
})
mux.HandleFunc("/"+dirOutcome+"/{"+identName+"}", func(
@@ -490,7 +273,40 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
writeF(m, w, &buf, m.writeOutcome)
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)
}
})
mux.HandleFunc("/"+dirStatus+"/{"+identName+"}", func(
@@ -505,6 +321,47 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
writeF(m, w, &buf, m.writeStatus)
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
}
})
return &mux
}
+4 -7
View File
@@ -4,7 +4,6 @@ import (
"crypto/ed25519"
"io/fs"
"log"
"net/http"
"net/http/httptest"
"os"
"testing"
@@ -31,7 +30,7 @@ func TestMirror(t *testing.T) {
msg.SwapVerbose(testing.Verbose())
var c *pkg.Cache
c, err = pkg.Open(t.Context(), msg, base, nil)
c, err = pkg.Open(t.Context(), msg, 0, 0, 0, base)
if err != nil {
t.Fatal(err)
}
@@ -53,16 +52,14 @@ func TestMirror(t *testing.T) {
}
wantChecksums := pkg.Encode(wantChecksum)
var mux http.ServeMux
rosa.NewMirror(msg, fstest.MapFS{
server := httptest.NewServer(rosa.NewMirror(msg, fstest.MapFS{
"identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)},
"checksum/" + wantChecksums: {Mode: os.ModeDir | 0500},
}, priv).Register(&mux)
server := httptest.NewServer(&mux)
}, priv))
t.Cleanup(server.Close)
var extern pkg.External
extern, err = rosa.NewRemote(server.Client(), "http://example.com:80", pub)
extern, err = rosa.NewRemote("http://example.com:80", pub, server.Client())
if err != nil {
t.Fatal(err)
}
+5 -3
View File
@@ -13,8 +13,10 @@ package attr {
patches = [ "musl-errno.patch" ];
bin = [ "perl" ];
populateUsrBin = true;
early = `
ln -s ../../system/bin/perl /usr/bin
`;
exec = make {};
inputs = [
@@ -39,7 +41,7 @@ package acl {
exec = make {
// makes assumptions about uid_map/gid_map
check = nil;
skipCheck = true;
};
inputs = [ attr, kernel-headers ];
-31
View File
@@ -1,31 +0,0 @@
package awk {
description = "one true awk";
website = "https://github.com/onetrueawk/awk";
anitya = 16171;
version# = "20260426";
source = remoteGitHub {
suffix = "onetrueawk/awk";
tag = version;
checksum = "ewAvWLEHajhm7cA7v4DsKVk1c11niCLKIE5Q-8W_sxv1XXsbZlcOuWn1KOBYMxjo";
};
enterSource = true;
writable = true;
chmod = true;
exec = make {
defaults = false;
chdir = false;
configure = nil;
make = [ "YACC='yacc -d -b awkgram'" ];
preCheck = "install -vD a.out /system/bin/awk\n";
install = "install -vD a.out /work/system/bin/awk";
};
inputs = [
m4,
byacc,
diffutils,
];
}
+6 -6
View File
@@ -5,19 +5,15 @@ package bison {
version# = "3.8.2";
source = remoteTar {
url = "https://mirrors.kernel.org/gnu/bison/bison-"+version+".tar.gz";
url = "https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz";
checksum = "BhRM6K7URj1LNOkIDCFDctSErLS-Xo5d9ba9seg10o6ACrgC1uNhED7CQPgIY29Y";
compress = gzip;
};
toyboxEarly = true;
exec = make {
defaults = false;
check = [
"TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests {
tests = [
// GNU-isms not implemented in toybox
168, 170, 623,
// clang miscompiles (SIGILL)
764,
];
@@ -26,5 +22,9 @@ package bison {
];
};
inputs = [ m4 ];
inputs = [
m4,
diffutils,
sed,
];
}
-24
View File
@@ -1,24 +0,0 @@
package byacc {
description = "Berkeley Yacc";
website = "https://invisible-island.net/byacc";
anitya = 233;
version# = "20260126";
source = remoteTar {
url = "https://invisible-island.net/archives/byacc/"+
"byacc-"+version+".tgz";
compress = gzip;
checksum = "3IXzewZmFUW3hkFKBuweR0hUSftlI2zE0lBZf16I8oK3mFEyj51FzVv1wvA12uoC";
};
// awk dependency loop
toyboxEarly = true;
// test suite assumes writable source
writable = true;
chmod = true;
exec = make {
defaults = false;
};
}
+7 -4
View File
@@ -15,10 +15,13 @@ package bzip2 {
enterSource = true;
exec = make {
chdir = false;
configure = nil;
make = [ "CC=cc" ];
check = nil;
skipConfigure = true;
skipCheck = true;
inPlace = true;
make = [
"CC=cc",
];
install = "make PREFIX=/work/system install";
};
}
+11 -11
View File
@@ -13,25 +13,25 @@ package cairo {
exec = meson {
setup = {
"dwrite": "enabled";
"fontconfig": "enabled";
"freetype": "enabled";
"Ddwrite": "enabled";
"Dfontconfig": "enabled";
"Dfreetype": "enabled";
"png": "enabled";
"tee": "enabled";
"xcb": "enabled";
"xlib": "disabled";
"xlib-xcb": "disabled";
"zlib": "enabled";
"Dpng": "enabled";
"Dtee": "enabled";
"Dxcb": "enabled";
"Dxlib": "disabled";
"Dxlib-xcb": "disabled";
"Dzlib": "enabled";
};
// runs the entire test suite in a single meson test
interactiveTest = true;
// only works with specific dependency versions
test = false;
skipTest = true;
};
inputs = [
awk,
gawk,
zlib,
libpng,
@@ -0,0 +1,13 @@
diff --git a/Tests/BootstrapTest.cmake b/Tests/BootstrapTest.cmake
index 137de78bc1..b4da52e664 100644
--- a/Tests/BootstrapTest.cmake
+++ b/Tests/BootstrapTest.cmake
@@ -9,7 +9,7 @@ if(NOT nproc EQUAL 0)
endif()
message(STATUS "running bootstrap: ${bootstrap} ${ninja_arg} ${parallel_arg}")
execute_process(
- COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg}
+ COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg} -- -DCMAKE_USE_OPENSSL=OFF
WORKING_DIRECTORY "${bin_dir}"
RESULT_VARIABLE result
)
+7 -5
View File
@@ -3,15 +3,18 @@ package cmake {
website = "https://cmake.org";
anitya = 306;
version# = "4.4.2";
version# = "4.3.4";
source = remoteGitHubRelease {
suffix = "Kitware/CMake";
tag = "v"+version;
name = "cmake-"+version+".tar.gz";
checksum = "IWlqJqJCZ6f-z-7Ft1U4ycvCX4riuihKale5NKWusiHemBgC3m5gCecrzikXoL7S";
checksum = "6A50pqarKDXKOCv7ffKMvWJWmNTVp_ep8KoaWwNdg-RYQRddgKbxayHveTo6jZ_7";
compress = gzip;
};
patches = [ "disable-broken-tests-musl.patch" ];
patches = [
"bootstrap-test-no-openssl.patch",
"disable-broken-tests-musl.patch",
];
// test suite expects writable source tree
writable = true;
@@ -20,7 +23,7 @@ package cmake {
chmod = true;
exec = make {
defaults = false;
omitDefaults = true;
configureName = "/usr/src/cmake/bootstrap";
configure = {
@@ -29,7 +32,6 @@ package cmake {
"--";
"-DCMAKE_USE_OPENSSL": "OFF";
"-DCMake_TEST_NO_NETWORK": "ON";
"-DCMake_TEST_BOOTSTRAP": "OFF";
};
check = [
+1 -1
View File
@@ -19,7 +19,7 @@ package connman {
inputs = [
automake,
libtool,
pkgconf,
pkg-config,
dbus,
iptables,
-43
View File
@@ -1,43 +0,0 @@
package cryptsetup {
description = "open-source disk encryption";
website = "https://gitlab.com/cryptsetup/cryptsetup";
anitya = 13709;
version# = "2.8.7";
source = remoteGitLab {
domain = "gitlab.com";
suffix = "cryptsetup/cryptsetup";
ref = "v"+version;
checksum = "eDi_UaMtwhIzqpsdcA91aVb56zCYDrsDzeMWfWXAnPbuvn2bEgeH5dFs7mouHz8V";
};
bin = [ "bash" ];
exec = meson {
setup = {
"asciidoc": "disabled";
"ssh-token": "false";
"blkid": "false";
};
};
inputs = [
bash,
gettext,
coreutils,
popt,
lvm2,
json-c,
e2fsprogs,
argp-standalone,
kernel-headers,
];
runtime = [
popt,
lvm2,
json-c,
e2fsprogs,
openssl,
];
}
+1 -1
View File
@@ -21,7 +21,7 @@ touch \
`;
exec = make {
chdir = false;
inPlace = true;
configureName = "../dist/configure";
forceAutoconf = true;
configure = {
+6 -6
View File
@@ -19,9 +19,9 @@ package dbus {
exec = meson {
setup = {
"epoll": "enabled";
"inotify": "enabled";
"x11_autolaunch": "disabled";
"Depoll": "enabled";
"Dinotify": "enabled";
"Dx11_autolaunch": "disabled";
};
};
@@ -41,16 +41,16 @@ package xdg-dbus-proxy {
website = "https://github.com/flatpak/xdg-dbus-proxy";
anitya = 58434;
version# = "0.1.8";
version# = "0.1.7";
source = remoteGitHub {
suffix = "flatpak/xdg-dbus-proxy";
tag = version;
checksum = "ygdW0EEvZ-_PJfnFTNoobITmRzqJecTinBsJd_iJQrRvzidwqESCjeNkB55smZ2y";
checksum = "UW5Pe-TP-XAaN-kTbxrkOQ7eYdmlAQlr2pdreLtPT0uwdAz-7rzDP8V_8PWuZBup";
};
exec = meson {
setup = {
"man": "disabled";
"Dman": "disabled";
};
};
+1 -1
View File
@@ -18,7 +18,7 @@ package dtc {
exec = meson {
setup = {
"yaml": "disabled";
"Dyaml": "disabled";
};
};
-28
View File
@@ -1,28 +0,0 @@
package e2fsprogs {
description = "ext2/3/4 filesystem userspace utilities";
website = "http://e2fsprogs.sourceforge.net";
anitya = 646;
version# = "1.47.4";
source = remoteTar {
url = "https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git"+
"/snapshot/e2fsprogs-"+version+".tar.gz";
compress = gzip;
checksum = "gdnAEVjncIciqG-ZhFfYVv4wbBbCHBmPPYwRxltIfOTqdYH5L3ri8wk75YIVlgN0";
};
exec = make {
configure = {
"enable-elf-shlibs";
};
};
inputs = [
perl,
gzip,
bzip2,
diffutils,
kernel-headers,
];
}
+4 -4
View File
@@ -18,17 +18,17 @@ package elfutils {
];
exec = make {
// nonstandard glibc extension
skipCheck = true;
configure = {
"enable-deterministic-archives";
};
// nonstandard glibc extension
check = nil;
};
inputs = [
m4,
pkgconf,
pkg-config,
zlib,
bzip2,
+2 -3
View File
@@ -5,9 +5,8 @@ package fcft {
version# = "3.3.3";
source = remoteTar {
url = "https://codeberg.org/dnkl/fcft/releases/download/"+version+
"/fcft-"+version+".tar.gz";
checksum = "pryAJA-d1OpY8KXbGFEHum9Wm6ME9XkPx9EM_OQ_ZEpOUpQnqlkzIq-cwS1ziMPk";
url = "https://codeberg.org/dnkl/fcft/archive/"+version+".tar.gz";
checksum = "bMj8OmqtoANRKZWbjHk4WfP09AxJYRbWGqUsm1gRJ_dOFg6gooNbgkDu597PLfz2";
compress = gzip;
};
+7 -7
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# = "20260810";
version# = "20260622";
source = remoteGitLab {
domain = "gitlab.com";
suffix = "kernel-firmware/linux-firmware";
ref = version;
checksum = "XNUhz9QstaDKNegM3Bl0-TtZzpsvX7-E8WMnDCO7KBhBC6t_TxsdG05-ETdXynry";
checksum = "gpytkDM58EVjaUuryOekcekh_rWsfuv3S7LQxopHlNlVGmMsuqNwfug4BjgTgizE";
};
// dedup creates temporary file
@@ -22,19 +22,19 @@ package firmware {
];
exec = make {
defaults = false;
chdir = false;
omitDefaults = true;
skipConfigure = true;
inPlace = true;
configure = nil;
make = [
"DESTDIR=/work/system",
"install-zst",
];
// requires pre-commit
check = nil;
skipCheck = true;
install = "make " + jobsFlagE + " " + loadFlagE + " DESTDIR=/work/system dedup";
install = "make " + jobsFlagE + " DESTDIR=/work/system dedup";
};
inputs = [
+3 -3
View File
@@ -3,12 +3,12 @@ package fontconfig {
website = "https://www.freedesktop.org/wiki/Software/fontconfig";
anitya = 827;
version# = "2.18.3";
version# = "2.18.1";
source = remoteGitLab {
domain = "gitlab.freedesktop.org";
suffix = "fontconfig/fontconfig";
ref = version;
checksum = "ZZzmt8fYh-3jKJ6vHXUDbeAWM2ilRusWxdynLt3Z4E_CQQ8cCwzpuAWACXmr9qHI";
checksum = "S3FJfh-PeZ2_YgNrUqL0H2G4Wf_ilj5HpIGV2oURnkK672AQHpWk526bNtRHwyJt";
};
exec = make {
@@ -18,7 +18,7 @@ package fontconfig {
inputs = [
automake,
libtool,
pkgconf,
pkg-config,
gettext,
gperf,
gzip,
+2 -3
View File
@@ -5,9 +5,8 @@ package foot {
version# = "1.27.0";
source = remoteTar {
url = "https://codeberg.org/dnkl/foot/releases/download/"+version+
"/foot-"+version+".tar.gz";
checksum = "22rG3rMuQI8Ae2XTcZgOJ-6AbF7Taex8XpgvD6Fyg1Mn5Va67FfUcK3tRaq61TFg";
url = "https://codeberg.org/dnkl/foot/archive/"+version+".tar.gz";
checksum = "E2XIPRD8t-WBBJUebIwChFT8K_85diwdalssUNwnuZBIynPa7rlXro5WCe9v3UlK";
compress = gzip;
};
+1 -1
View File
@@ -12,7 +12,7 @@ package fribidi {
exec = meson {
setup = {
"docs": "false";
"Ddocs": "false";
};
};
}
+5 -5
View File
@@ -14,15 +14,15 @@ package fuse {
exec = meson {
setup = {
"default_library": "both";
"tests": "true";
"useroot": "false";
"initscriptdir": "/system/etc";
"Ddefault_library": "both";
"Dtests": "true";
"Duseroot": "false";
"Dinitscriptdir": "/system/etc";
};
postCompile = "python3 -m pytest test/";
// this project uses pytest
test = false;
skipTest = true;
};
inputs = [
@@ -1,35 +0,0 @@
diff --git a/test/Makefile.am b/test/Makefile.am
index 88e15ef1f..bfc279fcb 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1726,7 +1726,7 @@ LOCALE_CHARSET_TESTS = \
SHLIB_TESTS = \
apiterm filefuncs fnmatch fork fork2 fts functab4 functab5 \
getfile indirectbuiltin2 inplace1 inplace2 inplace2bcomp inplace3 \
- inplace3bcomp ordchr ordchr2 readall readdir readdir_retest \
+ inplace3bcomp ordchr ordchr2 readall readdir_retest \
readdir_test readfile readfile2 revout revtwoway rwarray \
testext time
diff --git a/test/Makefile.in b/test/Makefile.in
index 2d4eeaa5a..7930af8d5 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1986,7 +1986,7 @@ LOCALE_CHARSET_TESTS = \
SHLIB_TESTS = \
apiterm filefuncs fnmatch fork fork2 fts functab4 functab5 \
getfile indirectbuiltin2 inplace1 inplace2 inplace2bcomp inplace3 \
- inplace3bcomp ordchr ordchr2 readall readdir readdir_retest \
+ inplace3bcomp ordchr ordchr2 readall readdir_retest \
readdir_test readfile readfile2 revout revtwoway rwarray \
testext time
diff --git a/test/clos1way6.ok b/test/clos1way6.ok
index 5768617d3..be4d73e79 100644
--- a/test/clos1way6.ok
+++ b/test/clos1way6.ok
@@ -1,3 +1,3 @@
gawk: clos1way6.awk:5: warning: fflush: cannot flush: two-way pipe `cat - 1>&2; sleep 2' has closed write end
-test1
Bad file descriptor
+test1
@@ -1,39 +0,0 @@
diff --git a/test/testext-mpfr.ok b/test/testext-mpfr.ok
index 6a5f98147..adf8685e2 100644
--- a/test/testext-mpfr.ok
+++ b/test/testext-mpfr.ok
@@ -21,7 +21,7 @@ var_test: sym_update of ARGC failed - correctly
var_test: sym_update("testvar") succeeded
var_test() returned 1, test_var = 42
-test_errno() returned 1, ERRNO = No child processes
+test_errno() returned 1, ERRNO = No child process
fubar = 9
rumpus = -5
diff --git a/test/testext.ok b/test/testext.ok
index 3e0c1328c..11d150fe3 100644
--- a/test/testext.ok
+++ b/test/testext.ok
@@ -21,7 +21,7 @@ var_test: sym_update of ARGC failed - correctly
var_test: sym_update("testvar") succeeded
var_test() returned 1, test_var = 42
-test_errno() returned 1, ERRNO = No child processes
+test_errno() returned 1, ERRNO = No child process
fubar = 9
rumpus = -5
diff --git a/vms/vmstest.com b/vms/vmstest.com
index a042764b1..c47984e38 100644
--- a/vms/vmstest.com
+++ b/vms/vmstest.com
@@ -917,7 +917,7 @@ $ set noOn
$ AWKLIBPATH_dir
$ gawk -f _'test'.awk >_'test'.tmp 2>&1
$ if .not. $status then call exit_code '$status' _'test'.tmp
-$ gawk "{gsub(""no children"",""No child processes"")}1" -
+$ gawk "{gsub(""no children"",""No child process"")}1" -
_'test'.tmp >_'test'.tmp1
$ rm sys$disk:[]_'test'.tmp;*
$ mv sys$disk:[]_'test'.tmp1 sys$disk:[]_'test'.tmp
-26
View File
@@ -1,26 +0,0 @@
package gawk {
description = "an implementation of awk with GNU extensions";
website = "https://www.gnu.org/software/gawk";
anitya = 868;
block = "regressions introduced in 5.4.1, "+
"does not even pass its own test suite";
version# = "5.4.0";
source = remoteTar {
url = "https://mirrors.kernel.org/gnu/gawk/gawk-"+version+".tar.gz";
checksum = "m0RkIolC-PI7EY5q8pcx5Y-0twlIW0Yp3wXXmV-QaHorSdf8BhZ7kW9F8iWomz0C";
compress = gzip;
};
patches = [
"musl-errno.patch",
"broken-tests.patch",
];
exec = make {};
inputs = [
diffutils,
util-linux,
];
}
+6 -7
View File
@@ -3,10 +3,10 @@ package binutils {
website = "https://www.gnu.org/software/binutils";
anitya = 7981;
version# = "2.47";
version# = "2.46.1";
source = remoteTar {
url = "https://mirrors.kernel.org/gnu/binutils/binutils-"+version+".tar.bz2";
checksum = "VjbMg5KtZ6VSeNc77Z5p8RKg9eZ56g29ViKbbsF3tcFhZu0Yurg0nZt7UwB577LM";
url = "https://ftpmirror.gnu.org/gnu/binutils/binutils-"+version+".tar.bz2";
checksum = "ihCVohBxX-URAR-YFDdVrL3inLYsEVX8KbbQmcbHaShHgqqmtsvUue1h3LXSjW-d";
compress = bzip2;
};
@@ -20,11 +20,11 @@ package gcc {
website = "https://www.gnu.org/software/gcc";
anitya = 6502;
version# = "16.2.0";
version# = "16.1.0";
source = remoteTar {
url = "https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"+
"gcc-"+version+"/gcc-"+version+".tar.gz";
checksum = "yWDNSrcKa6yA5ucD4G-a5nCN99yPA8cRlxKgQlaaT-jM4pWYR6e1EvI2qbjUqXWZ";
checksum = "4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K";
compress = gzip;
};
patches = [
@@ -65,7 +65,7 @@ ln -s system/lib /work/
// This toolchain is hacked to pieces, it is not expected to ever work
// well in its current state. That does not matter as long as the
// toolchain it produces passes its own test suite.
check = nil;
skipCheck = true;
};
inputs = [
@@ -82,7 +82,6 @@ ln -s system/lib /work/
mpc,
zlib,
zstd,
libucontext,
];
}
+3 -7
View File
@@ -12,6 +12,8 @@ package git {
};
early = `
ln -s ../../system/bin/perl /usr/bin/ || true
# test suite assumes apache
rm -f /system/bin/httpd
`;
@@ -20,10 +22,8 @@ rm -f /system/bin/httpd
enterSource = true;
env = [ "NO_RUST=YesPlease" ];
bin = [ "perl" ];
populateUsrBin = true;
exec = make {
chdir = false;
inPlace = true;
generate = "make configure";
preMake = `
@@ -60,9 +60,6 @@ disable_test t1451-fsck-buffer
disable_test t4104-apply-boundary
disable_test t4200-rerere
disable_test t5515-fetch-merge-logic
disable_test t4124-apply-ws-rule
disable_test t3404-rebase-interactive
disable_test t7527-builtin-fsmonitor
`;
check = [
@@ -73,7 +70,6 @@ disable_test t7527-builtin-fsmonitor
install = `make \
` + jobsFlagE + ` \
` + loadFlagE + ` \
DESTDIR=/work \
NO_INSTALL_HARDLINKS=1 \
install`;
+3 -3
View File
@@ -3,11 +3,11 @@ package glib {
website = "https://developer.gnome.org/glib";
anitya = 10024;
version# = "2.89.3";
version# = "2.89.1";
source = remoteGit {
url = "https://gitlab.gnome.org/GNOME/glib.git";
tag = version;
checksum = "eM9KrXwhwKiZferwrILKmDeq-IGnSjr0EKqV90EEVl0Ee82QVcyVSf2LDMROHcOF";
checksum = "9_6Eew2KIwa1AHopjU7CqC13_nur5FPJMu-iGUd7sD_1gAM1pa_HVUuAtqExJoYU";
};
files = {
@@ -17,7 +17,7 @@ package glib {
exec = meson {
setup = {
"default_library": "both";
"Ddefault_library": "both";
};
// fails with ipv6 disabled
skipTests = [ "gio" ];

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