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 uses: actions/checkout@v4
- name: Build for release - 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 - name: Release
uses: https://gitea.com/actions/release-action@main uses: https://gitea.com/actions/release-action@main
+9 -9
View File
@@ -12,7 +12,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - 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 - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -29,7 +29,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - 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 - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -46,7 +46,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - 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 - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -63,7 +63,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - 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 - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -80,7 +80,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - 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 - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -103,7 +103,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run checks - 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: dist:
name: Create distribution name: Create distribution
@@ -116,9 +116,9 @@ jobs:
id: build-test id: build-test
run: >- run: >-
export HAKUREI_REV="$(git rev-parse --short HEAD)" && export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' test/package.nix && sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
nix build --print-out-paths --print-build-logs ./test#dist && nix build --print-out-paths --print-build-logs .#dist &&
mv test/{package.nix.old,package.nix} && mv package.nix.old package.nix &&
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
- name: Upload test build - name: Upload test build
-1
View File
@@ -1,5 +1,4 @@
# produced by tools and text editors # produced by tools and text editors
*.swp
*.qcow2 *.qcow2
*.test *.test
*.out *.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> <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/> <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/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> <a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
</p> </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 New dependencies will generally not be added. Patches adding new dependencies
are very likely to be rejected. 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" "bufio"
"fmt" "fmt"
"io" "io"
"os"
"strconv" "strconv"
"strings" "strings"
@@ -336,19 +335,3 @@ func parse(
return &c, nil 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 ( import (
"context" "context"
"errors" "errors"
"fmt"
"io" "io"
"log" "log"
"os" "os"
@@ -76,7 +77,17 @@ func main() {
"enter", "Enter mutable state template", "enter", "Enter mutable state template",
func(args []string) error { func(args []string) error {
if len(args) != 1 { 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{ config := hst.Config{
@@ -148,7 +159,17 @@ func main() {
"run", "Start the named application", "run", "Start the named application",
func(args []string) error { func(args []string) error {
if len(args) < 1 { 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 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' 'files:files:__hakurei_files'
} }
_hakurei_kill() {
_alternative \
'instances:domains:__hakurei_instances'
}
__hakurei_files() { __hakurei_files() {
_files -g "*.(json|hakurei)" _files -g "*.(json|hakurei)"
return $? return $?
@@ -65,7 +60,6 @@ __hakurei_instances() {
"run:Load and start container from configuration file" "run:Load and start container from configuration file"
"exec:Configure and start a permissive container" "exec:Configure and start a permissive container"
"show:Show live or local instance configuration" "show:Show live or local instance configuration"
"kill:Terminate an active instance"
"ps:List active instances" "ps:List active instances"
"version:Display version information" "version:Display version information"
"license:Show full license text" "license:Show full license text"
+3 -3
View File
@@ -57,7 +57,7 @@ func main() {
verbose := os.Getenv("VERBOSE") != "" verbose := os.Getenv("VERBOSE") != ""
runTests := os.Getenv("HAKUREI_DIST_MAKE") == "" runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
version = getenv("HAKUREI_VERSION", strings.TrimSpace(version)) version = getenv("HAKUREI_VERSION", strings.TrimSpace(version))
prefix := getenv("PREFIX", "/usr/local") prefix := getenv("PREFIX", "/usr")
destdir := getenv("DESTDIR", "dist") destdir := getenv("DESTDIR", "dist")
if verbose { if verbose {
@@ -217,7 +217,7 @@ func main() {
mustWriteFile("comp/", nil, os.ModeDir|0755) mustWriteFile("comp/", nil, os.ModeDir|0755)
mustWriteFile("comp/_hakurei", comp, 0644) mustWriteFile("comp/_hakurei", comp, 0644)
mustWriteFile("install.sh", []byte(`#!/bin/sh -e 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/hakurei" "${DESTDIR}`+prefix+`/bin/hakurei"
install -vDm0755 "bin/sharefs" "${DESTDIR}`+prefix+`/bin/sharefs" install -vDm0755 "bin/sharefs" "${DESTDIR}`+prefix+`/bin/sharefs"
@@ -230,7 +230,7 @@ fi
install -vDm0644 "comp/_hakurei" "${DESTDIR}`+prefix+`/share/zsh/site-functions/_hakurei" install -vDm0644 "comp/_hakurei" "${DESTDIR}`+prefix+`/share/zsh/site-functions/_hakurei"
`), 0755) `), 0755)
mustWriteFromPath("LICENSE", "LICENSE", 0) mustWriteFromPath("README.md", "README.md", 0)
mustWriteFile("hsurc.default", []byte("1000 0"), 0400) mustWriteFile("hsurc.default", []byte("1000 0"), 0400)
mustWriteFromPath("bin/hsu", filepath.Join(s, "hsu"), 04511) mustWriteFromPath("bin/hsu", filepath.Join(s, "hsu"), 04511)
for _, name := range []string{ for _, name := range []string{
-18
View File
@@ -11,7 +11,6 @@ import (
"os/user" "os/user"
"strconv" "strconv"
"sync" "sync"
"syscall"
"time" "time"
"hakurei.app/check" "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") 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 var flagShort bool
c.NewCommand("ps", "List active instances", func(args []string) error { 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 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 run Load and start container from configuration file
exec Configure and start a permissive container exec Configure and start a permissive container
show Show live or local instance configuration show Show live or local instance configuration
kill Terminate an active instance
ps List active instances ps List active instances
version Display version information version Display version information
license Show full license text license Show full license text
@@ -35,14 +35,10 @@ commands:
`, `,
}, },
{ {
"exec", []string{"exec", "-h"}, `usage: hakurei exec [-h | --help] [--dbus-config <value>] "exec", []string{"exec", "-h"}, `
[--dbus-system <value>] [--mpris] [--dbus-log] 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]
[--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>]
flags: Flags:
-X Enable direct connection to X11 -X Enable direct connection to X11
-a int -a int
Application identity Application identity
+1 -1
View File
@@ -66,7 +66,7 @@ func TestEncodeJSON(t *testing.T) {
want string want string
}{ }{
{"marshaler", errorJSONMarshaler{}, {"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() {}, {"default", func() {},
`cannot write json: json: unsupported type: func()`}, `cannot write json: json: unsupported type: func()`},
} }
+1 -1
View File
@@ -8,7 +8,7 @@ buildGoModule {
pname = "${hakurei.pname}-hsu"; pname = "${hakurei.pname}-hsu";
inherit (hakurei) version; inherit (hakurei) version;
src = ../cmd/hsu; src = ./.;
inherit (hakurei) vendorHash; inherit (hakurei) vendorHash;
env.CGO_ENABLED = 0; env.CGO_ENABLED = 0;
+9 -65
View File
@@ -5,7 +5,6 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"testing" "testing"
"hakurei.app/check" "hakurei.app/check"
@@ -22,66 +21,41 @@ type cache struct {
// Should generally not be used directly. // Should generally not be used directly.
c *pkg.Cache c *pkg.Cache
attr pkg.CacheAttr cures, jobs int
// Primarily to work around missing landlock LSM. // Primarily to work around missing landlock LSM.
hostAbstract bool hostAbstract bool
// Set SCHED_IDLE. // Set SCHED_IDLE.
idle bool idle bool
// Unset [pkg.CSuppressInit]. // Unset [pkg.CSuppressInit].
verboseInit bool verboseInit bool
// Whether to enable output colours.
color bool
// Unset [pkg.CExternShallow].
deep bool
// Loaded artifact of [rosa.QEMU]. // Loaded artifact of [rosa.QEMU].
qemu pkg.Artifact qemu pkg.Artifact
base, mirror string 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]. // open opens the underlying [pkg.Cache].
func (cache *cache) open() (err error) { func (cache *cache) open() (err error) {
if cache.c != nil { if cache.c != nil {
return os.ErrInvalid return os.ErrInvalid
} }
var hostname string
if hostname, err = os.Hostname(); err != nil {
return
}
var base *check.Absolute var base *check.Absolute
if cache.base, err = filepath.Abs(cache.base); err != nil { if cache.base, err = filepath.Abs(cache.base); err != nil {
return return
} else if base, err = check.NewAbs(cache.base); err != nil { } else if base, err = check.NewAbs(cache.base); err != nil {
return return
} }
var notify chan bool
var flags int
if cache.idle { if cache.idle {
cache.attr.Flags |= pkg.CSchedIdle flags |= pkg.CSchedIdle
} }
if cache.hostAbstract { if cache.hostAbstract {
cache.attr.Flags |= pkg.CHostAbstract flags |= pkg.CHostAbstract
} }
if !cache.verboseInit { if !cache.verboseInit {
cache.attr.Flags |= pkg.CSuppressInit 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
} }
done := make(chan struct{}) done := make(chan struct{})
@@ -103,8 +77,10 @@ func (cache *cache) open() (err error) {
cache.c, err = pkg.Open( cache.c, err = pkg.Open(
cache.ctx, cache.ctx,
cache.msg, cache.msg,
flags,
cache.cures,
cache.jobs,
base, base,
&cache.attr,
) )
if err != nil { if err != nil {
return return
@@ -119,40 +95,13 @@ func (cache *cache) open() (err error) {
return return
} }
var r rosa.Remote 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() cache.c.Close()
return err return err
} }
cache.c.SetExternal(r) 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 { if cache.qemu != nil {
var pathname *check.Absolute var pathname *check.Absolute
pathname, _, err = cache.c.Cure(cache.qemu) pathname, _, err = cache.c.Cure(cache.qemu)
@@ -173,11 +122,6 @@ func (cache *cache) open() (err error) {
func (cache *cache) Close() { func (cache *cache) Close() {
if cache.c != nil { if cache.c != nil {
cache.c.Close() 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( c, err := pkg.Open(
t.Context(), t.Context(),
message.New(log.New(os.Stderr, "cir: ", 0)), message.New(log.New(os.Stderr, "cir: ", 0)),
0, 0, 0,
check.MustAbs(t.TempDir()), check.MustAbs(t.TempDir()),
nil,
) )
if err != nil { if err != nil {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
@@ -63,7 +63,7 @@ func TestNoReply(t *testing.T) {
} }
<-done <-done
wantIdent := pkg.MustDecode("bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32") wantIdent := pkg.MustDecode("fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG")
if gotIdent := c.Ident(a).Value(); gotIdent != wantIdent { if gotIdent := c.Ident(a).Value(); gotIdent != wantIdent {
t.Errorf( t.Errorf(
"cureFromIR: %s, want %s", "cureFromIR: %s, want %s",
@@ -124,7 +124,7 @@ func TestDaemon(t *testing.T) {
cancel() cancel()
<-done <-done
const want = "bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32" const want = "fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG"
if got := filepath.Base(p.String()); got != want { if got := filepath.Base(p.String()); got != want {
t.Errorf("cureRemote: %s, want %s", got, want) t.Errorf("cureRemote: %s, want %s", got, want)
} }
@@ -132,8 +132,8 @@ func TestDaemon(t *testing.T) {
wantLog := []string{ wantLog := []string{
"", "",
"daemon: aborting all pending cures", "daemon: aborting all pending cures",
"daemon: attempting to cancel invalid artifact 58Vy_5beLZCvZX__KzRKyIE6vATleaZP1ZBxbqoWnekz9aZ1zkxNgcIUFI5V1_Jf", "daemon: attempting to cancel invalid artifact kQm9fmnCmXST1-MMmxzcau2oKZCXXrlZydo4PkeV5hO_2PKfeC8t98hrbV_ZZx_j",
"daemon: fulfilled artifact " + want, "daemon: fulfilled artifact fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG",
} }
gotLog := strings.Split(buf.String(), "\n") gotLog := strings.Split(buf.String(), "\n")
slices.Sort(gotLog) slices.Sort(gotLog)
+1 -4
View File
@@ -21,10 +21,7 @@ func commandInfo(
r *rosa.Report, r *rosa.Report,
) (err error) { ) (err error) {
if len(args) == 0 { if len(args) == 0 {
for _, h := range rosa.Native().CollectAll() { return errors.New("info requires at least 1 argument")
fmt.Println(h)
}
return nil
} }
// recovered by HandleAccess // recovered by HandleAccess
+39 -213
View File
@@ -27,7 +27,6 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@@ -92,11 +91,6 @@ func main() {
var cm cache var cm cache
defer func() { cm.Close() }() 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 ( var (
flagQuiet bool flagQuiet bool
@@ -208,17 +202,13 @@ func main() {
"v", command.BoolFlag(false), "v", command.BoolFlag(false),
"Do not suppress verbose output from init", "Do not suppress verbose output from init",
).Flag( ).Flag(
&cm.attr.Cures, &cm.cures,
"cures", command.IntFlag(0), "cures", command.IntFlag(0),
"Maximum number of dependencies to cure at any given time", "Maximum number of dependencies to cure at any given time",
).Flag( ).Flag(
&cm.attr.Jobs, &cm.jobs,
"jobs", command.IntFlag(0), "jobs", command.IntFlag(0),
"Preferred number of jobs to run, when applicable", "Preferred number of jobs to run, when applicable",
).Flag(
&cm.attr.Load,
"load-average", command.IntFlag(0),
"Preferred load average number, when applicable",
).Flag( ).Flag(
&cm.base, &cm.base,
"d", command.StringFlag("$MBF_CACHE_DIR"), "d", command.StringFlag("$MBF_CACHE_DIR"),
@@ -227,11 +217,6 @@ func main() {
&cm.mirror, &cm.mirror,
"r", command.StringFlag("$MBF_REMOTE"), "r", command.StringFlag("$MBF_REMOTE"),
"URL of mirror service", "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( ).Flag(
&cm.idle, &cm.idle,
"sched-idle", command.BoolFlag(false), "sched-idle", command.BoolFlag(false),
@@ -283,7 +268,7 @@ func main() {
if _, err := io.Copy(h, os.Stdin); err != nil { if _, err := io.Copy(h, os.Stdin); err != nil {
return err return err
} }
fmt.Println(pkg.Encode(pkg.Checksum(h.Sum(nil)))) log.Println(pkg.Encode(pkg.Checksum(h.Sum(nil))))
return nil return nil
}, },
) )
@@ -554,9 +539,7 @@ func main() {
if base, err := os.OpenRoot(cm.base); err != nil { if base, err := os.OpenRoot(cm.base); err != nil {
return err return err
} else { } else {
var mux http.ServeMux h = rosa.NewMirror(msg, base.FS(), key)
rosa.NewMirror(msg, base.FS(), key).Register(&mux)
h = &mux
} }
server := http.Server{Addr: args[0], Handler: h} 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( c.NewCommand(
"stage4", "stage3",
"Check for toolchain 3-stage non-determinism", "Check for toolchain 3-stage non-determinism",
func(args []string) (err error) { 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 ( var (
pathname *check.Absolute pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum] checksum [2]unique.Handle[pkg.Checksum]
@@ -631,7 +590,7 @@ func main() {
_llvm := rosa.H("llvm") _llvm := rosa.H("llvm")
if err = cm.Do(func(cache *pkg.Cache) (err error) { 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) pathname, _, err = cache.Cure(llvm)
return return
}); err != nil { }); err != nil {
@@ -640,31 +599,21 @@ func main() {
log.Println("stage1:", pathname) log.Println("stage1:", pathname)
if err = cm.Do(func(cache *pkg.Cache) (err error) { if err = cm.Do(func(cache *pkg.Cache) (err error) {
_, llvm := rosa.Native().New(rosa.Std - 1).Load(_llvm) _, llvm := rosa.Native().New(s - 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)
pathname, checksum[0], err = cache.Cure(llvm) pathname, checksum[0], err = cache.Cure(llvm)
return return
}); err != nil { }); err != nil {
return return
} }
log.Println("stage3:", pathname) log.Println("stage2:", pathname)
if err = cm.Do(func(cache *pkg.Cache) (err error) { 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) pathname, checksum[1], err = cache.Cure(llvm)
return return
}); err != nil { }); err != nil {
return return
} }
log.Println("stage4:", pathname) log.Println("stage3:", pathname)
if checksum[0] != checksum[1] { if checksum[0] != checksum[1] {
err = &pkg.ChecksumMismatchError{ err = &pkg.ChecksumMismatchError{
@@ -673,34 +622,23 @@ func main() {
} }
} else { } else {
log.Println( log.Println(
"stage3 is identical to stage4", "stage2 is identical to stage3",
"("+pkg.Encode(checksum[0].Value())+")", "("+pkg.Encode(checksum[0].Value())+")",
) )
} }
return 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 ( var (
flagDump string flagDump string
@@ -710,13 +648,9 @@ func main() {
flagNoReply bool flagNoReply bool
flagFaults bool flagFaults bool
flagPop bool flagPop bool
flagRebuild bool
flagBoot bool flagBoot bool
flagStd bool flagStd bool
flagGentoo string
flagChecksum string
) )
c.NewCommand( c.NewCommand(
"cure", "cure",
@@ -733,18 +667,6 @@ func main() {
t -= 1 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]))) _, a := rosa.Native().New(t).Load(rosa.ArtifactH(unique.Make(args[0])))
if a == nil { if a == nil {
return fmt.Errorf("unknown artifact %q", args[0]) return fmt.Errorf("unknown artifact %q", args[0])
@@ -754,17 +676,13 @@ func main() {
default: default:
var pathname *check.Absolute var pathname *check.Absolute
err := cm.Do(func(cache *pkg.Cache) (err error) { err := cm.Do(func(cache *pkg.Cache) (err error) {
if flagRebuild {
pathname, _, err = cache.CureNew(a)
} else {
pathname, _, err = cache.Cure(a) pathname, _, err = cache.Cure(a)
}
return return
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Println(pathname) log.Println(pathname)
if flagExport != "" { if flagExport != "" {
msg.Verbosef("exporting %s to %s...", args[0], flagExport) msg.Verbosef("exporting %s to %s...", args[0], flagExport)
@@ -813,7 +731,7 @@ func main() {
ctx, ctx,
a, a,
"", true, os.Stdin, os.Stdout, os.Stderr, "", true, os.Stdin, os.Stdout, os.Stderr,
rosa.AbsSystem.Append("bin", "sh"), rosa.AbsSystem.Append("bin", "mksh"),
"sh", "sh",
) )
}) })
@@ -825,7 +743,7 @@ func main() {
} }
pathname, err := cureRemote(ctx, &addr, a, flags) pathname, err := cureRemote(ctx, &addr, a, flags)
if !flagNoReply && err == nil { if !flagNoReply && err == nil {
fmt.Println(pathname) log.Println(pathname)
} }
if errors.Is(err, context.Canceled) { if errors.Is(err, context.Canceled) {
@@ -919,97 +837,9 @@ func main() {
&flagPop, &flagPop,
"pop", command.BoolFlag(false), "pop", command.BoolFlag(false),
"Display and destroy the most recent fault entry", "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 := c.New("clean", "Remove unused entries from the cache")
cleanC.NewCommand( cleanC.NewCommand(
"fault", "fault",
@@ -1196,10 +1026,6 @@ func main() {
if w, ok := err.(interface{ Unwrap() []error }); !ok { if w, ok := err.(interface{ Unwrap() []error }); !ok {
log.Fatal(err) log.Fatal(err)
} else { } else {
if _, ok = w.(pkg.InputError); ok {
log.Fatal(w)
}
errs := w.Unwrap() errs := w.Unwrap()
for i, e := range errs { for i, e := range errs {
if i == len(errs)-1 { 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 return c
} }
// newNode initialises a subcommand tree and returns its address.
func newNode(output io.Writer, logf LogFunc, name, usage string) *node { func newNode(output io.Writer, logf LogFunc, name, usage string) *node {
n := &node{ n := &node{
name: name, usage: usage, 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.SetOutput(output)
n.set.Usage = func() { n.set.Usage = func() {
_ = n.writeHelp() _ = n.writeHelp()
if len(n.suffix) > 0 { if n.suffix.Len() > 0 {
_, _ = fmt.Fprintln(output, "flags:") _, _ = fmt.Fprintln(output, "Flags:")
n.set.PrintDefaults() n.set.PrintDefaults()
_, _ = fmt.Fprintln(output) _, _ = 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) { t.Run("direct zero length", func(t *testing.T) {
wantPanic := "invalid subcommand" wantPanic := "invalid subcommand"
t.Run("zero length name", func(t *testing.T) { t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("", "usage", stubHandler) })
defer checkRecover(t, "Command", wantPanic) t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "Command", wantPanic); c.Command("name", "", stubHandler) })
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) { 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) { t.Run("zero length", func(t *testing.T) {
wantPanic := "invalid subcommand tree" wantPanic := "invalid subcommand tree"
t.Run("zero length name", func(t *testing.T) { t.Run("zero length name", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("", "usage") })
defer checkRecover(t, "New", wantPanic) t.Run("zero length usage", func(t *testing.T) { defer checkRecover(t, "New", wantPanic); c.New("name", "") })
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) { t.Run("direct adopt unique names", func(t *testing.T) {
+6 -26
View File
@@ -6,43 +6,36 @@ import (
"strings" "strings"
) )
// UsageInternal is a special usage string that hides the command from the // UsageInternal causes the command to be hidden from help text when set as the usage string.
// generated help message. const UsageInternal = "internal"
const UsageInternal = "\x00"
type ( type (
// HandlerFunc is called when matching a directly handled subcommand tree. // HandlerFunc is called when matching a directly handled subcommand tree.
HandlerFunc = func(args []string) error HandlerFunc = func(args []string) error
// LogFunc is the function signature of a printf function. The zero value // LogFunc is the function signature of a printf function.
// implies [log.Printf].
LogFunc = func(format string, a ...any) LogFunc = func(format string, a ...any)
// FlagDefiner is a deferred flag definer value, usually encapsulating the // FlagDefiner is a deferred flag definer value, usually encapsulating the default value.
// default value.
FlagDefiner interface { FlagDefiner interface {
// Define defines the flag in set. // Define defines the flag in set.
Define(b *strings.Builder, set *flag.FlagSet, p any, name, usage string) 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[T any] interface {
// Flag defines a generic flag type in Node's flag set. // Flag defines a generic flag type in Node's flag set.
Flag(p any, name string, value FlagDefiner, usage string) T Flag(p any, name string, value FlagDefiner, usage string) T
} }
// A Command is the root of a command tree.
Command interface { Command interface {
Parse(arguments []string) error Parse(arguments []string) error
// MustParse determines exit outcomes for Parse errors and calls // MustParse determines exit outcomes for Parse errors
// handleError if [HandlerFunc] returns a non-nil error. // and calls handleError if [HandlerFunc] returns a non-nil error.
MustParse(arguments []string, handleError func(error)) MustParse(arguments []string, handleError func(error))
baseNode[Command] baseNode[Command]
} }
// A Node is a subcommand under a [Command].
Node baseNode[Node] Node baseNode[Node]
baseNode[T any] interface { baseNode[T any] interface {
@@ -60,16 +53,3 @@ type (
Flag[T] 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 { func (n *node) Flag(p any, name string, value FlagDefiner, usage string) Node {
var buf strings.Builder value.Define(&n.suffix, n.set, p, name, usage)
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)
return n return n
} }
+3 -21
View File
@@ -1,7 +1,6 @@
package command package command
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@@ -14,31 +13,14 @@ var ErrHelp = errors.New("help requested")
func (n *node) PrintHelp() { _ = n.writeHelp() } func (n *node) PrintHelp() { _ = n.writeHelp() }
func (n *node) writeHelp() error { 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, if _, err := fmt.Fprintf(n.out,
"usage: %s [-h | --help]%s <command> [<args>]\n", "\nUsage:\t%s [-h | --help]%s COMMAND [OPTIONS]\n",
prefix, &buf, strings.Join(append(n.prefix, n.name), " "), &n.suffix,
); err != nil { ); err != nil {
return err return err
} }
if n.child != nil { 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 return err
} }
} }
+2 -6
View File
@@ -3,9 +3,9 @@ package command
import ( import (
"flag" "flag"
"io" "io"
"strings"
) )
// A node represents a command.
type node struct { type node struct {
child, next *node child, next *node
name, usage string name, usage string
@@ -13,16 +13,13 @@ type node struct {
out io.Writer out io.Writer
logf LogFunc logf LogFunc
// Names of commands preceding node.
prefix []string prefix []string
// Short user-facing representations of flags received by node. suffix strings.Builder
suffix []string
f HandlerFunc f HandlerFunc
set *flag.FlagSet set *flag.FlagSet
} }
// adopt adds v as the last child of n.
func (n *node) adopt(v *node) bool { func (n *node) adopt(v *node) bool {
if n.child != nil { if n.child != nil {
return n.child.append(v) return n.child.append(v)
@@ -31,7 +28,6 @@ func (n *node) adopt(v *node) bool {
return true return true
} }
// append adds v as the last sibling of n.
func (n *node) append(v *node) bool { func (n *node) append(v *node) bool {
if n.name == v.name { if n.name == v.name {
return false return false
+22 -18
View File
@@ -70,7 +70,7 @@ func TestParse(t *testing.T) {
"d=0 out of order string flag", "d=0 out of order string flag",
buildTestCommand, buildTestCommand,
[]string{"string", "--string", "64d3b4b7b21788585845060e2199a78f"}, []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"), errors.New("flag provided but not defined: -string"),
}, },
{ {
@@ -120,7 +120,7 @@ func TestParse(t *testing.T) {
"d=1 empty sub help", "d=1 empty sub help",
buildTestCommand, buildTestCommand,
[]string{"empty", "-h"}, []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", "d=1 no match",
@@ -151,10 +151,10 @@ func TestParse(t *testing.T) {
"d=0 help", "d=0 help",
buildTestCommand, buildTestCommand,
[]string{}, []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 error return an error
print wraps Fprint print wraps Fprint
string print string passed by flag string print string passed by flag
@@ -171,10 +171,10 @@ commands:
"d=0 help flag", "d=0 help flag",
buildTestCommand, buildTestCommand,
[]string{"-h"}, []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 error return an error
print wraps Fprint print wraps Fprint
string print string passed by flag string print string passed by flag
@@ -185,7 +185,7 @@ commands:
succeed this command succeeds succeed this command succeeds
deep top level of command tree with various levels deep top level of command tree with various levels
flags: Flags:
-fail -fail
fail early fail early
-int int -int int
@@ -203,9 +203,10 @@ flags:
"d=1 help", "d=1 help",
buildTestCommand, buildTestCommand,
[]string{"join"}, []string{"join"},
`usage: test join [-h | --help] <command> [<args>] `
Usage: test join [-h | --help] COMMAND [OPTIONS]
commands: Commands:
out write result to wout out write result to wout
log log result to wlog log log result to wlog
@@ -215,9 +216,10 @@ commands:
"d=1 help flag", "d=1 help flag",
buildTestCommand, buildTestCommand,
[]string{"join", "-h"}, []string{"join", "-h"},
`usage: test join [-h | --help] <command> [<args>] `
Usage: test join [-h | --help] COMMAND [OPTIONS]
commands: Commands:
out write result to wout out write result to wout
log log result to wlog log log result to wlog
@@ -228,9 +230,10 @@ commands:
"d=2 help", "d=2 help",
buildTestCommand, buildTestCommand,
[]string{"deep", "d=2"}, []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 d=3 relative third level
`, "", command.ErrHelp, `, "", command.ErrHelp,
@@ -239,9 +242,10 @@ commands:
"d=2 help flag", "d=2 help flag",
buildTestCommand, buildTestCommand,
[]string{"deep", "d=2", "-h"}, []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 d=3 relative third level
`, "", flag.ErrHelp, `, "", flag.ErrHelp,
@@ -257,7 +261,7 @@ commands:
t.Errorf("Parse: error = %v; wantErr %v", err, tc.wantErr) t.Errorf("Parse: error = %v; wantErr %v", err, tc.wantErr)
} }
if got := wout.String(); got != tc.want { 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 { if gotLog := wlog.String(); gotLog != tc.wantLog {
t.Errorf("Parse: log = %s wantLog %s", 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": { "locked": {
"lastModified": 1787146702, "lastModified": 1780361225,
"narHash": "sha256-YbRcLdU/yK4gWsQg7V8WTKZHfXL33g8+wSFUX3wyevs=", "narHash": "sha256-wnV9ttf4fPWNonBIQmvlrSlNpQYgx5HgWWd007mwIFA=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "173b7e8d40fdc8c296a9c99854314f17a3a1704c", "rev": "e28654b71096e08c019d4861ca26acb646f583d8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -23,11 +23,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1787101114, "lastModified": 1780453794,
"narHash": "sha256-gwrPcFf/rDjHPaVflbDZ040ZDmBTRj/7+s8ZmE2SaIM=", "narHash": "sha256-bXMRa9VTsHSPXL4Cw8R6JJLQeY3Y/IP4+YJCYVmQ7FY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b18a4b905f8d028dc4476412e6d6891728695379", "rev": "6b316287bae2ee04c9b93c8c858d930fd07d7338",
"type": "github" "type": "github"
}, },
"original": { "original": {
+13 -13
View File
@@ -43,19 +43,19 @@
; ;
in in
{ {
hakurei = callPackage ./. { inherit system self; }; hakurei = callPackage ./test { inherit system self; };
race = callPackage ./. { race = callPackage ./test {
inherit system self; inherit system self;
withRace = true; withRace = true;
}; };
sandbox = callPackage ./sandbox { inherit self; }; sandbox = callPackage ./test/sandbox { inherit self; };
sandbox-race = callPackage ./sandbox { sandbox-race = callPackage ./test/sandbox {
inherit self; inherit self;
withRace = true; withRace = true;
}; };
sharefs = callPackage ./sharefs { inherit system self; }; sharefs = callPackage ./cmd/sharefs/test { inherit system self; };
formatting = runCommandLocal "check-formatting" { nativeBuildInputs = [ nixfmt ]; } '' formatting = runCommandLocal "check-formatting" { nativeBuildInputs = [ nixfmt ]; } ''
cd ${./.} cd ${./.}
@@ -99,7 +99,7 @@
hakurei = pkgs.pkgsStatic.callPackage ./package.nix { hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
inherit (pkgs) inherit (pkgs)
# passthru.buildInputs # passthru.buildInputs
go_1_27 go_1_26
clang clang
# nativeBuildInputs # nativeBuildInputs
@@ -116,7 +116,7 @@
nettools 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" { sharefs = pkgs.linkFarm "sharefs" {
"bin/sharefs" = "${hakurei}/libexec/sharefs"; "bin/sharefs" = "${hakurei}/libexec/sharefs";
"bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs"; "bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs";
@@ -180,7 +180,7 @@
let let
# this is used for interactive vm testing during development, where tests might be broken # this is used for interactive vm testing during development, where tests might be broken
package = self.packages.${pkgs.stdenv.hostPlatform.system}.hakurei.override { 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 in
{ {
@@ -190,11 +190,11 @@
}; };
} }
./interactive/configuration.nix ./test/interactive/configuration.nix
./interactive/vm.nix ./test/interactive/vm.nix
./interactive/hakurei.nix ./test/interactive/hakurei.nix
./interactive/trace.nix ./test/interactive/trace.nix
./interactive/raceattr.nix ./test/interactive/raceattr.nix
self.nixosModules.hakurei self.nixosModules.hakurei
home-manager.nixosModules.home-manager home-manager.nixosModules.home-manager
+1 -1
View File
@@ -1,3 +1,3 @@
module hakurei.app 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. // Dependencies returns a slice containing the backing file.
func (a archiveArtifact) Inputs() []Artifact { func (a archiveArtifact) Dependencies() []Artifact {
return []Artifact{a.f} return []Artifact{a.f}
} }
+2 -2
View File
@@ -186,7 +186,7 @@ func TestArchiveArtifact(t *testing.T) {
cureMany(t, c, []cureStep{ cureMany(t, c, []cureStep{
{"sample", pkg.NewArchive( {"sample", pkg.NewArchive(
pkg.NewFile("", buf.Bytes()), pkg.NewFile("", buf.Bytes()),
), ignorePathname, expectsFS(want), pkg.WNew, nil}, ), ignorePathname, expectsFS(want), nil},
}) })
}, expectsFS{ }, expectsFS{
".": {Mode: fs.ModeDir | 0700}, ".": {Mode: fs.ModeDir | 0700},
@@ -202,7 +202,7 @@ func TestArchiveArtifact(t *testing.T) {
"checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")}, "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")},
"identifier": {Mode: fs.ModeDir | 0700}, "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}, "substitute": {Mode: fs.ModeDir | 0700},
"work": {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 continue
} }
c.msg.Verbosef( c.msg.Verbosef("arranging for destruction of %s...", name)
"arranging for destruction of %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
idents = append(idents, identPair{id, 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 { if err = c.parent.Err(); err != nil {
return destroyedIdents, destroyedChecksums, err return destroyedIdents, destroyedChecksums, err
} }
c.msg.Verbosef( c.msg.Verbosef("destroying checksum %s...", name)
"destroying checksum %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
if !dry { if !dry {
if err = errors.Join(removeAll(c.base.Append( if err = errors.Join(removeAll(c.base.Append(
dirChecksum, dirChecksum,
@@ -136,10 +130,7 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
continue continue
} }
c.msg.Verbosef( c.msg.Verbosef("destroying substitute %s...", name)
"destroying substitute %s%s%s...",
c.sgrIdent, name, c.sgrRes,
)
if !dry { if !dry {
if err = os.Remove(c.base.Append( if err = os.Remove(c.base.Append(
dirStatus, dirStatus,
+12 -12
View File
@@ -48,7 +48,7 @@ func TestClean(t *testing.T) {
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400}, "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400},
"identifier": {Mode: fs.ModeDir | 0700}, "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}, "lock": {Mode: 0644},
"variant": {Mode: 0400}, "variant": {Mode: 0400},
@@ -69,7 +69,7 @@ func TestClean(t *testing.T) {
"checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk": {Mode: 0400, Data: []byte("\xfd")}, "checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk": {Mode: 0400, Data: []byte("\xfd")},
"identifier": {Mode: fs.ModeDir | 0700}, "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}, "lock": {Mode: 0644},
"variant": {Mode: 0400}, "variant": {Mode: 0400},
@@ -122,16 +122,16 @@ func TestClean(t *testing.T) {
"checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE/result": {Mode: 0444}, "checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE/result": {Mode: 0444},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")}, "identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {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/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"lock": {Mode: 0644}, "lock": {Mode: 0644},
"variant": {Mode: 0400}, "variant": {Mode: 0400},
"status": {Mode: fs.ModeDir | 0700}, "status": {Mode: fs.ModeDir | 0700},
"substitute": {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/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {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}, "fault": {Mode: fs.ModeDir | 0700},
"work": {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")}, "checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv": {Mode: 0400, Data: []byte("kept")},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")}, "identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
"identifier/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")}, "identifier/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
"lock": {Mode: 0644}, "lock": {Mode: 0644},
"variant": {Mode: 0400}, "variant": {Mode: 0400},
"status": {Mode: fs.ModeDir | 0700}, "status": {Mode: fs.ModeDir | 0700},
"status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0400, Data: []byte(statusHeader + "kept")}, "status/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: 0400, Data: []byte(statusHeader + "kept")},
"status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {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": {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}, "fault": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700},
@@ -238,7 +238,7 @@ func TestClean(t *testing.T) {
base := makeBase(t) base := makeBase(t)
msg := message.New(log.New(os.Stderr, "clean: ", 0)) msg := message.New(log.New(os.Stderr, "clean: ", 0))
msg.SwapVerbose(testing.Verbose()) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
+2 -29
View File
@@ -6,9 +6,6 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"hakurei.app/internal/xz"
"hakurei.app/internal/zstd"
) )
const ( const (
@@ -16,10 +13,6 @@ const (
Gzip = iota Gzip = iota
// Bzip2 denotes a stream compressed via [bzip2]. // Bzip2 denotes a stream compressed via [bzip2].
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 // A decompressArtifact is a [FileArtifact] decompressing a backing
@@ -73,8 +66,8 @@ func init() {
}) })
} }
// Inputs returns a slice containing the backing file. // Dependencies returns a slice containing the backing file.
func (a *decompressArtifact) Inputs() []Artifact { func (a *decompressArtifact) Dependencies() []Artifact {
return []Artifact{a.f} return []Artifact{a.f}
} }
@@ -98,9 +91,6 @@ func (c compoundCloser) Close() error {
return err return err
} }
// IsExecutable returns false.
func (*decompressArtifact) IsExecutable() bool { return false }
// Cure returns a decompressor [io.ReadCloser]. // Cure returns a decompressor [io.ReadCloser].
func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) { func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
sr, err := r.Open(a.f) sr, err := r.Open(a.f)
@@ -124,23 +114,6 @@ func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
io.Closer io.Closer
}{bzip2.NewReader(br), br}, nil }{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: default:
return nil, os.ErrInvalid return nil, os.ErrInvalid
} }
+7 -9
View File
@@ -36,12 +36,6 @@ func TestDecompress(t *testing.T) {
return (pkg.Checksum)(h.Sum(nil)) return (pkg.Checksum)(h.Sum(nil))
}() }()
gh := pkg.NewDecompress(pkg.NewHTTPGet(
&client,
"file:///testdata",
testdataChecksum,
), pkg.Gzip)
checkWithCache(t, []cacheTestCase{ checkWithCache(t, []cacheTestCase{
{"decompress", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { {"decompress", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
cureMany(t, c, []cureStep{ cureMany(t, c, []cureStep{
@@ -49,12 +43,16 @@ func TestDecompress(t *testing.T) {
&client, &client,
"file:///testdata", "file:///testdata",
pkg.Checksum{0xfd}, pkg.Checksum{0xfd},
), pkg.Gzip), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{ ), pkg.Gzip), nil, nil, &pkg.ChecksumMismatchError{
Got: testdataChecksum, Got: testdataChecksum,
Want: pkg.Checksum{0xfd}, 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{ }, expectsFS{
".": {Mode: fs.ModeDir | 0700}, ".": {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}}, "checksum/" + pkg.Encode(sha512.Sum384([]byte{0})): {Mode: 0400, Data: []byte{0}},
"identifier": {Mode: fs.ModeDir | 0700}, "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}, "substitute": {Mode: fs.ModeDir | 0700},
"work": {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. // AbsWork is the container pathname [TContext.GetWorkDir] is mounted on.
var AbsWork = fhs.AbsRoot.Append("work/") var AbsWork = fhs.AbsRoot.Append("work/")
const (
// EnvJobs is the name of the environment variable holding a decimal // EnvJobs is the name of the environment variable holding a decimal
// representation of the preferred job count. Its value must not affect cure // representation of the preferred job count. Its value must not affect cure
// outcome. // outcome.
EnvJobs = "CURE_JOBS" const EnvJobs = "CURE_JOBS"
// EnvLoad is the name of the environment variable holding a decimal
// representation of the preferred loadavg target. Its value must not affect
// cure outcome.
EnvLoad = "CURE_LOAD"
)
// ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make // ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make
// it available at under in the container. // it available at under in the container.
@@ -413,9 +407,9 @@ func init() {
func(r *IRReader) Artifact { return readExecArtifact(r, true) }) 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]. // [ExecPath].
func (a *execArtifact) Inputs() []Artifact { func (a *execArtifact) Dependencies() []Artifact {
artifacts := make([][]Artifact, 0, len(a.paths)) artifacts := make([][]Artifact, 0, len(a.paths))
for _, p := range a.paths { for _, p := range a.paths {
artifacts = append(artifacts, p.A) artifacts = append(artifacts, p.A)
@@ -444,7 +438,7 @@ func scanVerbose(
msg message.Msg, msg message.Msg,
cancel context.CancelFunc, cancel context.CancelFunc,
done chan<- struct{}, done chan<- struct{},
prefix, suffix string, prefix string,
r io.Reader, r io.Reader,
) { ) {
defer close(done) defer close(done)
@@ -454,7 +448,7 @@ func scanVerbose(
bufio.MaxScanTokenSize<<12, bufio.MaxScanTokenSize<<12,
) )
for s.Scan() { 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) { if err := s.Err(); err != nil && !errors.Is(err, os.ErrClosed) {
cancel() cancel()
@@ -477,7 +471,7 @@ const SeccompPresets = std.PresetStrict &
func (a *execArtifact) makeContainer( func (a *execArtifact) makeContainer(
ctx context.Context, ctx context.Context,
msg message.Msg, msg message.Msg,
flags, jobs, load int, flags, jobs int,
hostNet bool, hostNet bool,
temp, work *check.Absolute, temp, work *check.Absolute,
getArtifact GetArtifactFunc, getArtifact GetArtifactFunc,
@@ -514,10 +508,7 @@ func (a *execArtifact) makeContainer(
z.Quiet = flags&CSuppressInit != 0 z.Quiet = flags&CSuppressInit != 0
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1 z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
z.Dir, z.Path, z.Args = a.dir, a.path, a.args z.Dir, z.Path, z.Args = a.dir, a.path, a.args
z.Env = slices.Concat(a.env, []string{ z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
EnvJobs + "=" + strconv.Itoa(jobs),
EnvLoad + "=" + strconv.Itoa(load),
})
z.Grow(len(a.paths) + 4) z.Grow(len(a.paths) + 4)
if a.arch != runtime.GOARCH { if a.arch != runtime.GOARCH {
@@ -626,7 +617,7 @@ func (c *Cache) EnterExec(
return ErrNotExec return ErrNotExec
} }
deps := Collect(a.Inputs()) deps := Collect(a.Dependencies())
if _, _, err = c.Cure(&deps); err == nil { if _, _, err = c.Cure(&deps); err == nil {
return errors.New("unreachable") return errors.New("unreachable")
} else if !IsCollected(err) { } else if !IsCollected(err) {
@@ -658,9 +649,8 @@ func (c *Cache) EnterExec(
var z *container.Container var z *container.Container
z, err = e.makeContainer( z, err = e.makeContainer(
ctx, c.msg, ctx, c.msg,
c.attr.Flags, c.flags,
c.attr.Jobs, c.jobs,
c.attr.Load,
hostNet, hostNet,
temp, work, temp, work,
func(a Artifact) (*check.Absolute, unique.Handle[Checksum]) { 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() msg := f.GetMessage()
var z *container.Container var z *container.Container
if z, err = a.makeContainer( 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.GetTempDir(), f.GetWorkDir(),
f.GetArtifact, f.GetArtifact,
f.cache.Ident, 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) brStdout, brStderr := f.cache.getReader(stdout), f.cache.getReader(stderr)
stdoutDone, stderrDone := make(chan struct{}), make(chan struct{}) 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( go scanVerbose(
msg, cancel, stdoutDone, msg, cancel, stdoutDone,
prefixO, suffix, "("+a.name+":1)",
io.TeeReader(brStdout, status), io.TeeReader(brStdout, status),
) )
go scanVerbose( go scanVerbose(
msg, cancel, stderrDone, msg, cancel, stderrDone,
prefixE, suffix, "("+a.name+":2)",
io.TeeReader(brStderr, status), io.TeeReader(brStderr, status),
) )
defer func() { defer func() {
+25 -22
View File
@@ -84,7 +84,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil}, ), ignorePathname, wantOffline, nil},
{"substitution", pkg.NewExec( {"substitution", pkg.NewExec(
"exec-offline", "", new(wantOffline.hash()), 0, false, false, "exec-offline", "", new(wantOffline.hash()), 0, false, false,
@@ -108,7 +108,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WSubstitute, nil}, ), ignorePathname, wantOffline, nil},
{"error passthrough", pkg.NewExec( {"error passthrough", pkg.NewExec(
"", "", nil, 0, false, true, "", "", nil, 0, false, true,
@@ -118,8 +118,11 @@ func TestExec(t *testing.T) {
[]string{"testtool"}, []string{"testtool"},
pkg.MustPath("/proc/nonexistent", false, failingArtifact), pkg.MustPath("/proc/nonexistent", false, failingArtifact),
), nil, nil, pkg.WNew, pkg.InputError{ ), nil, nil, &pkg.DependencyCureError{
failingArtifact: stub.UniqueError(0xcafe), {
A: failingArtifact,
Err: stub.UniqueError(0xcafe),
},
}}, }},
{"invalid paths", pkg.NewExec( {"invalid paths", pkg.NewExec(
@@ -130,7 +133,7 @@ func TestExec(t *testing.T) {
[]string{"testtool"}, []string{"testtool"},
pkg.ExecPath{}, pkg.ExecPath{},
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths}, ), nil, nil, pkg.ErrInvalidPaths},
}) })
// check init failure passthrough // check init failure passthrough
@@ -180,11 +183,11 @@ func TestExec(t *testing.T) {
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}}, "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
"identifier": {Mode: fs.ModeDir | 0700}, "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/_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.Offline: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"identifier/" + expected.OfflineS: {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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -222,7 +225,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantNet, pkg.WNew, nil}, ), ignorePathname, wantNet, nil},
}) })
destroyStatus(t, base, 2, 0) destroyStatus(t, base, 2, 0)
@@ -239,7 +242,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.Net: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")}, "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/_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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -266,7 +269,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil}, ), ignorePathname, wantOffline, nil},
}) })
destroyStatus(t, base, 2, 0) destroyStatus(t, base, 2, 0)
@@ -281,7 +284,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.OvlRoot: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -313,7 +316,7 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700) return os.MkdirAll(t.GetWorkDir().String(), 0700)
}, },
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool), }), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil}, ), ignorePathname, wantOffline, nil},
}) })
destroyStatus(t, base, 2, 0) destroyStatus(t, base, 2, 0)
@@ -328,7 +331,7 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + expected.Work: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -382,7 +385,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil}, ), ignorePathname, wantOffline, nil},
}) })
destroyStatus(t, base, 2, 0) destroyStatus(t, base, 2, 0)
@@ -400,9 +403,9 @@ func TestExec(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")}, "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/" + 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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -435,7 +438,7 @@ func TestExec(t *testing.T) {
}, },
}), }),
pkg.MustPath("/opt", false, testtool), pkg.MustPath("/opt", false, testtool),
), ignorePathname, wantOffline, pkg.WNew, nil}, ), ignorePathname, wantOffline, nil},
}) })
destroyStatus(t, base, 2, 0) destroyStatus(t, base, 2, 0)
@@ -449,8 +452,8 @@ func TestExec(t *testing.T) {
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/Vzj9qaSVBtNyBQv_PW6uojFOWTwraHoaC0C6xdaGG1q_HTvSh4KLVxRcEQU1jd2Y": {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/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")},
"identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
"substitute": {Mode: fs.ModeDir | 0700}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -500,7 +503,7 @@ func TestExec(t *testing.T) {
".": {Mode: fs.ModeDir | 0500}, ".": {Mode: fs.ModeDir | 0500},
"check": {Mode: 0400, Data: []byte("binfmt")}, "check": {Mode: 0400, Data: []byte("binfmt")},
}, pkg.WNew, nil}, }, nil},
}) })
destroyStatus(t, base, 2, 0) 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")}, "checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3/check": {Mode: 0400, Data: []byte("binfmt")},
"identifier": {Mode: fs.ModeDir | 0700}, "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/_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}, "substitute": {Mode: fs.ModeDir | 0700},
+2 -17
View File
@@ -12,7 +12,6 @@ type fileArtifact []byte
var _ KnownChecksum = new(fileArtifact) var _ KnownChecksum = new(fileArtifact)
var _ CuresExempt = new(fileArtifact) var _ CuresExempt = new(fileArtifact)
var _ RevisionArtifact = new(fileArtifact)
// fileArtifactNamed embeds fileArtifact alongside a caller-supplied name. // fileArtifactNamed embeds fileArtifact alongside a caller-supplied name.
type fileArtifactNamed struct { type fileArtifactNamed struct {
@@ -64,8 +63,8 @@ func init() {
}) })
} }
// Inputs returns a nil slice. // Dependencies returns a nil slice.
func (*fileArtifact) Inputs() []Artifact { return nil } func (*fileArtifact) Dependencies() []Artifact { return nil }
// IsExclusive returns false: Cure returns a prepopulated buffer. // IsExclusive returns false: Cure returns a prepopulated buffer.
func (*fileArtifact) IsExclusive() bool { return false } func (*fileArtifact) IsExclusive() bool { return false }
@@ -77,20 +76,6 @@ func (a *fileArtifact) Checksum() Checksum {
return Checksum(h.Sum(nil)) 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. // Cure returns the caller-supplied data.
func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) { func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(*a)), nil return io.NopCloser(bytes.NewReader(*a)), nil
+5 -24
View File
@@ -12,41 +12,22 @@ func TestFile(t *testing.T) {
t.Parallel() t.Parallel()
want := expectsFile{0} 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{ checkWithCache(t, []cacheTestCase{
{"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { {"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
cureMany(t, c, []cureStep{ cureMany(t, c, []cureStep{
{"short", pkg.NewFile("null", want), base.Append( {"short", pkg.NewFile("null", []byte{0}), base.Append(
"identifier", "identifier",
ident, "3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
), want, pkg.WNew, nil}, ), want, 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},
}) })
}, expectsFS{ }, expectsFS{
".": {Mode: fs.ModeDir | 0700}, ".": {Mode: fs.ModeDir | 0700},
"checksum": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700},
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: want}, "checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: []byte{0}},
"checksum/" + pkg.Encode(wantShebang.hash()): {Mode: 0500, Data: wantShebang},
"checksum/" + pkg.Encode(wantELF.hash()): {Mode: 0500, Data: wantELF},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/" + ident: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(want.hash()))}, "identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
"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()))},
"substitute": {Mode: fs.ModeDir | 0700}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -1,11 +1,11 @@
package expected package expected
const ( const (
Offline = "IKmVhALejtYA3JhN1PCfjKF-Dio1XVcOeMWDHhfSHCbb4iBNhGjFy2UspZveZvb8" Offline = "q5ktDTq0miP-VvB2blxqXQeaRXCUWgP_KbC18KNtUDtyoaI_h5mHmGuPMArVEBDs"
OfflineS = "6ZubjSyCnz4-TKgQZi_BbY-JUwsStYCtD_f-BTDOOotfEbqkm47W20AazHRaLviz" OfflineS = "IY91PCtOpCYy21AaIK0c9f8-Z6fb2_2ewoHWkt4dxoLf0GOrWqS8yAGFLV84b1Dw"
OvlRoot = "Yox7WpG8B_OqIXWF4HWFZkUfsEl7DGzpFyZM0qtd9T8nQ-7SAkEUurlAe6_DJ6Iu" OvlRoot = "NacZGXwuRkTvcHaG08a22ujJ8qCWN0RSoFlRSR5FSt0ZcBbJ28FRvkYsHEtX7G8i"
Layers = "aAwfxDB-efVo379FNl178jK7HEKU3LEjHbZdaVVjk7GnXGZGEANNsXnB3SCUxM9A" Layers = "WBJDrATtX6rIE5yAu8ePX3WmDF0Tt9kFiue0m3cRnyRoVx1my8a67fh3CAW486oP"
Net = "IU3GwU2jTBd7HjotvFo2wsDWBQGVGpamwiSKdc2G1EnhM-ZaacxAuK6q0wbTVxra" Net = "CmYtj2sNB3LHtqiDuck_Lz3MjLLIiwyP8N4NDitQ1Icvv__LVP9p8tm-sHeQaKKp"
Promote = "rOjetGHzT_jPErrBR24IAZKDj8Q9dLLqxFQqloMgjsULss0VXDI--n6LxuMBHvmZ" Promote = "TX3eCloaQFkV-SZIH6Jg6E5WKH--rcXY1P0jnZKmLFKWrNqnOzd4G9eIBh6i5ywN"
Work = "7f9XDeREfvJIjCe0qesND0s0tasExAIcc-OH33-eq9tsrQPUXhJp4KEkpsYH4hCD" Work = "OuNiLSC68pZhAOr1YQ4WbV1tzASA0nxLEBcK7lO7MqxDY_j8dmP_C612RTuF23Lu"
) )
@@ -1,11 +1,11 @@
package expected package expected
const ( const (
Offline = "MTgCSzwPrzGigp9phvDPRwUTNGLm1KM2EsEtbz-l2cNieqjaGtnzm65CDXlSxXrl" Offline = "WapqyoPxbWSnq07dWHt71mHaJXq99pAjJfFlELlJljSiZMhTFqqlzU1_mN86shSj"
OfflineS = "p89bQg7_jR4nwaSbpEd08ne1jHOEw7Wlnlyv5FHq7ba1Kml3HSBZwEKRzu0gCqEb" OfflineS = "ibQZHcdXgNQ1OiMX1FrburBbGPVvKEHvPilbQCkm_0oV0BQCHomyyTbYNrFMGIwl"
OvlRoot = "9ifwO6MAaV9kTqRR2O5PJzm8XhfXbr50mFLWyEHQm8OHHcJtAEUgXZzJYoZt9YVV" OvlRoot = "V9anFOiRvjGfAeBhLl14AL8TKdWZyD0WTPYe4fS9mOBw8iW5Lmarvt6TG6MV8uWm"
Layers = "INuGActFPwJtS7mAR9Bkt7FD4yoHlXHSJ9CaSAQJrpkUBL_k815Cs_jvRfxy5-a7" Layers = "tKx7JNRoSBdK_7MdzI-nwTNV2wmiPzwYdcd17oLmXKL_iLmUzUiA79qTqdrTasrv"
Net = "kJvy24uk4ePvHoxSKf4vMOhR4NxLbmyWlA9bTS7d3z3fE9WF1Tvpao9g-QuYU4vm" Net = "aXyDLzBCJ9XltXZIfetEVsEkrqHfcXuD5XE_FcUnYbN3emwL55N6P8LlHzNfGnM5"
Promote = "lYqyYrfjPawIbld5Qz0NbKvd_bmI3nJC1eEnlIQWzsjWE9uA1HuKPAaClnDeyG6L" Promote = "3k4V16n96Lq04gjFSKmm4sFjyQ883FFBNXgTy9s_DjeTwxT3pg_iacEh8yMb_S4m"
Work = "V6k4FqOBMRCmHiqchs5-joVGZ_MhNWZyXm3gdbU0S7S5eMze7G4SwYMTf66ojKQL" Work = "6Q49MhFWRE3Ne6MycwAotgl1GtoU5WCHqJNWG2byYZCY-zX-IxPrWiKk7bKkNzhE"
) )
@@ -1,11 +1,11 @@
package expected package expected
const ( const (
Offline = "LlieSHVDe1lnKvfI8t4oGRg_2hPxwyy1drmaqc-EKCOENuS9C2YHrp2VY5pSyhbg" Offline = "Z6yXE5gOJScL3srmnVMWgCXccDiUNZ5snSrf6RkXuU1_U0rX_kGVwsfHUgNG_awd"
OfflineS = "qccjM8oYjUuEYPKFFzAxDFVzMerSUKUZc18NdVQoiPWf-70XOsNK8NaUQqjTgTAD" OfflineS = "zN16xv6LKRJRipUJwupyxg2rZcvf-qpsMn_qCxUmgxlTSuNwYI70ZEb7dHW5k0gO"
OvlRoot = "lpV2bb_KGYFHPiOn-jtGop8K_ew0y1p3BezRp0ebM93_a-T9J-vkqGD5uokda1aN" OvlRoot = "zYXJHFRLuxvUhuisZEXgGgVvdQd6piMfp5jmtT6jdVjvC2gICXquOq-UTwlrSD5I"
Layers = "sM3DJm210CHPGHkAquIbrXhspB81FpVC60ApQrvJGD5El2i7cSONj7LWf7EWqKpT" Layers = "_F8EDazHbcLeT0sVSQXRN_kn9IjduqJcDYgzXpsT-hpKU4EBcZ0PISN2zchpqMbm"
Net = "JihQUwsVETRYjb2-yIXLYZ6WVsaFebwl8btSYAsNQ2QapS5MZVaI-dYwrVoySycR" Net = "CA_FAaSIYJgapBEHV40doxpH23PdUEy_6s1TZc7wfSPN0XYqwGpMceXXDSabGveO"
Promote = "lGqwR4W2OjylSVitMQP1lc6wApOBkbMjsmIqkxQbfEZ3DHEQBbJr84ErW6Xb54zo" Promote = "_3LPrLp--4h9k4GsNNApu9hHtAafq-GUhfU6d4hJKBDKT3bz_szOsvkXxc5sK53d"
Work = "aZgtyv6aMtoHFkHAaJr6nLaA7N_SHjShgWPyQ5UdzaIqYSiVqvCrZqSokGTCcTii" 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 { environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
for _, t := range []string{ return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
} {
if s == t {
return true
}
}
return false
}) })
var hostNet, layers, promote bool var hostNet, layers, promote bool
+26 -44
View File
@@ -90,7 +90,7 @@ type IContext struct {
// returns and must not be exposed directly. // returns and must not be exposed directly.
w io.Writer w io.Writer
// Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with // 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 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 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 // WriteIdent is not defined for an [Artifact] not part of the slice returned by
// [Artifact.Inputs]. // [Artifact.Dependencies].
func (i *IContext) WriteIdent(a Artifact) { func (i *IContext) WriteIdent(a Artifact) {
buf := i.ic.getIdentBuf() buf := i.ic.getIdentBuf()
defer i.ic.putIdentBuf(buf) 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 // encode implements Encode but replaces identifiers with their cured checksums
// for a non-nil ident. The pathname field is unused. Caller must acquire // for a non-nil ident. Caller must acquire Cache.identMu.
// Cache.identMu.
func (ic *irCache) encode( func (ic *irCache) encode(
w io.Writer, w io.Writer,
a Artifact, a Artifact,
inputs map[Artifact]cureRes, inputs map[Artifact]cureRes,
) (err error) { ) (err error) {
deps := a.Inputs() deps := a.Dependencies()
idents := make([]*extIdent, len(deps)) idents := make([]*extIdent, len(deps))
if inputs == nil { if inputs == nil {
for i, d := range deps { for i, d := range deps {
@@ -278,11 +277,10 @@ func (ic *irCache) encode(
return *a == *b return *a == *b
}) })
// kind uint64 | rev uint64 | deps_sz uint64 // kind uint64 | deps_sz uint64
var buf [wordSize * 3]byte var buf [wordSize * 2]byte
binary.LittleEndian.PutUint64(buf[:], uint64(a.Kind())) binary.LittleEndian.PutUint64(buf[:], uint64(a.Kind()))
binary.LittleEndian.PutUint64(buf[wordSize:], GetRevision(a)) binary.LittleEndian.PutUint64(buf[wordSize:], uint64(len(idents)))
binary.LittleEndian.PutUint64(buf[wordSize*2:], uint64(len(idents)))
if _, err = w.Write(buf[:]); err != nil { if _, err = w.Write(buf[:]); err != nil {
return return
} }
@@ -332,7 +330,7 @@ func (ic *irCache) encodeAll(
return return
} }
for _, d := range a.Inputs() { for _, d := range a.Dependencies() {
if err = ic.encodeAll(w, d, encoded); err != nil { if err = ic.encodeAll(w, d, encoded); err != nil {
return return
} }
@@ -434,9 +432,9 @@ type (
// Common buffer for word-sized reads. // Common buffer for word-sized reads.
buf [wordSize]byte 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. // 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. // Number of values already read, -1 denotes a finalised IRReader.
count int count int
@@ -520,7 +518,7 @@ const (
irMaxValues = 1 << 12 irMaxValues = 1 << 12
// irMaxDeps is the arbitrary maximum number of direct dependencies allowed // 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]. // [IRDecoder].
irMaxDeps = 1 << 10 irMaxDeps = 1 << 10
) )
@@ -605,17 +603,17 @@ func (ir *IRReader) mustReadHeader(k IRValueKind) {
// putAll returns all dependency buffers to the underlying [Cache]. // putAll returns all dependency buffers to the underlying [Cache].
func (ir *IRReader) putAll() { func (ir *IRReader) putAll() {
for _, buf := range ir.inputs { for _, buf := range ir.deps {
ir.d.c.putIdentBuf(buf) ir.d.c.putIdentBuf(buf)
} }
ir.inputs = nil ir.deps = nil
} }
// DiscardAll discards all unstructured dependencies. This is useful to // DiscardAll discards all unstructured dependencies. This is useful to
// implementations that encode dependencies as [IRKindIdent] which are read back // implementations that encode dependencies as [IRKindIdent] which are read back
// via ReadIdent. // via ReadIdent.
func (ir *IRReader) DiscardAll() { func (ir *IRReader) DiscardAll() {
if ir.inputs == nil { if ir.deps == nil {
panic("attempting to discard dependencies twice") panic("attempting to discard dependencies twice")
} }
ir.putAll() ir.putAll()
@@ -627,13 +625,13 @@ var ErrDependencyDepleted = errors.New("reading past end of dependencies")
// Next returns the next unstructured dependency. // Next returns the next unstructured dependency.
func (ir *IRReader) Next() Artifact { func (ir *IRReader) Next() Artifact {
if len(ir.inputs) == 0 { if len(ir.deps) == 0 {
panic(ErrDependencyDepleted) panic(ErrDependencyDepleted)
} }
id := unique.Make(ID(ir.inputs[0][wordSize:])) id := unique.Make(ID(ir.deps[0][wordSize:]))
ir.d.c.putIdentBuf(ir.inputs[0]) ir.d.c.putIdentBuf(ir.deps[0])
ir.inputs = ir.inputs[1:] ir.deps = ir.deps[1:]
if a, ok := ir.d.ident[id]; !ok { if a, ok := ir.d.ident[id]; !ok {
ir.putAll() ir.putAll()
@@ -686,8 +684,8 @@ func (ir *IRReader) Finalise() (checksum unique.Handle[Checksum], ok bool) {
} }
ir.r, ir.ibw = nil, nil ir.r, ir.ibw = nil, nil
if len(ir.inputs) != 0 { if len(ir.deps) != 0 {
panic(MissedDependencyError(len(ir.inputs))) panic(MissedDependencyError(len(ir.deps)))
} }
return return
@@ -741,15 +739,6 @@ func (ir *IRReader) ReadString() string {
return unsafe.String(unsafe.SliceData(p), len(p)) 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 // decode decodes the next [Artifact] in the IR stream and returns any buffer
// originating from [Cache] before returning. decode returns [io.EOF] if and // originating from [Cache] before returning. decode returns [io.EOF] if and
// only if the underlying [io.Reader] is already read to EOF. // only if the underlying [io.Reader] is already read to EOF.
@@ -782,9 +771,6 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
return return
} }
ir.mustRead(ir.buf[:])
rev := binary.LittleEndian.Uint64(ir.buf[:])
defer ir.putAll() defer ir.putAll()
ir.mustRead(ir.buf[:]) ir.mustRead(ir.buf[:])
sz := binary.LittleEndian.Uint64(ir.buf[:]) sz := binary.LittleEndian.Uint64(ir.buf[:])
@@ -792,11 +778,11 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
err = ErrIRDepend err = ErrIRDepend
return return
} }
ir.inputs = make([]*extIdent, sz) ir.deps = make([]*extIdent, sz)
for i := range ir.inputs { for i := range ir.deps {
ir.inputs[i] = d.c.getIdentBuf() ir.deps[i] = d.c.getIdentBuf()
} }
for _, buf := range ir.inputs { for _, buf := range ir.deps {
ir.mustRead(buf[:]) ir.mustRead(buf[:])
} }
@@ -805,10 +791,6 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
err = syscall.ENOTRECOVERABLE err = syscall.ENOTRECOVERABLE
return return
} }
if _rev := GetRevision(a); _rev != rev {
err = RevisionError{rev, _rev}
return
}
if ir.count != -1 { if ir.count != -1 {
err = ErrRemainingIR err = ErrRemainingIR
@@ -823,8 +805,8 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
d.ident[id] = a d.ident[id] = a
} else { } else {
d.c.msg.Verbosef( d.c.msg.Verbosef(
"artifact %s%s%s appeared more than once in IR stream", "artifact %s appeared more than once in IR stream",
d.c.sgrIdent, Encode(id.Value()), d.c.sgrRes, Encode(id.Value()),
) )
} }
-33
View File
@@ -135,36 +135,3 @@ func TestIRRoundtrip(t *testing.T) {
} }
checkWithCache(t, testCasesCache) 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. // Dependencies returns a nil slice.
func (*httpArtifact) Inputs() []Artifact { return nil } func (*httpArtifact) Dependencies() []Artifact { return nil }
// IsExclusive returns false: Cure returns as soon as a response is received. // IsExclusive returns false: Cure returns as soon as a response is received.
func (*httpArtifact) IsExclusive() bool { return false } 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)) 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 // Cure sends the http request and returns the resulting response body reader
// wrapped to perform checksum validation. It is valid but not encouraged to // 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 // 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( wantPathname := base.Append(
"identifier", "identifier",
"COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue", "oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_",
) )
if pathname, checksum, err := c.Cure(f); err != nil { if pathname, checksum, err := c.Cure(f); err != nil {
t.Fatalf("Cure: error = %v", err) 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")}, "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": {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}, "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" "hakurei.app/message"
) )
var skipLock = func() pkg.CacheAttr { //go:linkname unsafeOpen hakurei.app/internal/pkg.open
var attr pkg.CacheAttr func unsafeOpen(
*(*bool)(unsafe.Pointer(reflect.ValueOf(&attr). ctx context.Context,
Elem(). msg message.Msg,
FieldByName("skipLock"). flags, cures, jobs int,
UnsafeAddr())) = true base *check.Absolute,
return attr lock bool,
}() ) (*pkg.Cache, error)
var ( var (
// extension is a string uniquely identifying a set of custom [Artifact] // 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) Kind() pkg.Kind { return a.kind }
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) } 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 (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
func (*stubArtifact) IsExclusive() bool { return false } 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) Kind() pkg.Kind { return a.kind }
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) } 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) Cure(f *pkg.FContext) error { return a.cure(f) }
func (a *stubArtifactF) IsExclusive() bool { return a.excl } func (a *stubArtifactF) IsExclusive() bool { return a.excl }
@@ -170,8 +170,6 @@ type stubFile struct {
stubArtifact stubArtifact
} }
func (*stubFile) IsExecutable() bool { return false }
func (a *stubFile) Cure(*pkg.RContext) (io.ReadCloser, error) { func (a *stubFile) Cure(*pkg.RContext) (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(a.data)), a.err return io.NopCloser(bytes.NewReader(a.data)), a.err
} }
@@ -332,7 +330,7 @@ func TestIdent(t *testing.T) {
}, },
nil, nil,
}, unique.Make[pkg.ID](pkg.MustDecode( }, 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 var cache *pkg.Cache
if a, err := check.NewAbs(t.TempDir()); err != nil { if a, err := check.NewAbs(t.TempDir()); err != nil {
t.Fatal(err) 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.Fatal(err)
} }
t.Cleanup(cache.Close) t.Cleanup(cache.Close)
@@ -521,10 +519,7 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
} }
var scrubFunc func() error // scrub after hashing var scrubFunc func() error // scrub after hashing
if c, err := pkg.Open(t.Context(), msg, base, &pkg.CacheAttr{ if c, err := pkg.Open(t.Context(), msg, flags, 1<<4, 0, base); err != nil {
Cures: 1 << 4,
Flags: flags,
}); err != nil {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} else { } else {
t.Cleanup(c.Close) t.Cleanup(c.Close)
@@ -632,7 +627,6 @@ type cureStep struct {
pathname *check.Absolute pathname *check.Absolute
output expectsKnown output expectsKnown
whence int
err error err error
} }
@@ -652,7 +646,7 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
for _, step := range steps { for _, step := range steps {
t.Log("cure step:", step.name) 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) faults, _err := c.ReadFaults(step.a)
if _err != nil { if _err != nil {
t.Errorf("ReadFaults: error = %v", _err) 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.Logf("faulting cure terminated %s ago", time.Since(faults[0].Time()))
} }
t.Fatalf("Cure: error = %v, want %v", err, step.err) 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) { } else if step.pathname != ignorePathname && !pathname.Is(step.pathname) {
t.Fatalf("Cure: pathname = %q, want %q", pathname, step.pathname) t.Fatalf("Cure: pathname = %q, want %q", pathname, step.pathname)
} else if step.output == nil || checksum != makeChecksumH(step.output.hash()) { } else if step.output == nil || checksum != makeChecksumH(step.output.hash()) {
@@ -782,28 +774,28 @@ func TestCache(t *testing.T) {
identifier, identifier,
new(testdata.hash()), new(testdata.hash()),
testdata, nil, testdata, nil,
), wantPathname, testdata, pkg.WNew, nil}, ), wantPathname, testdata, nil},
{"identical content", newStubFile( {"identical content", newStubFile(
pkg.KindHTTPGet, pkg.KindHTTPGet,
identifier0, identifier0,
new(testdata.hash()), new(testdata.hash()),
testdata, nil, testdata, nil,
), wantPathname0, testdata, pkg.WCache, nil}, ), wantPathname0, testdata, nil},
{"existing entry", newStubFile( {"existing entry", newStubFile(
pkg.KindHTTPGet, pkg.KindHTTPGet,
identifier, identifier,
new(testdata.hash()), new(testdata.hash()),
testdata, nil, testdata, nil,
), wantPathname, testdata, pkg.WCache, nil}, ), wantPathname, testdata, nil},
{"checksum mismatch", newStubFile( {"checksum mismatch", newStubFile(
pkg.KindHTTPGet, pkg.KindHTTPGet,
pkg.ID{0xff, 0}, pkg.ID{0xff, 0},
new(pkg.Checksum), new(pkg.Checksum),
testdata, nil, testdata, nil,
), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{ ), nil, nil, &pkg.ChecksumMismatchError{
Got: testdata.hash(), Got: testdata.hash(),
}}, }},
@@ -824,13 +816,13 @@ func TestCache(t *testing.T) {
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b, 0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
0x41, 0x34, 0x65, 0x96, 0x68, 0x17, 0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17, 0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
}, pkg.WNew, nil}, }, nil},
{"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{ {"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{
kind: pkg.KindExec, kind: pkg.KindExec,
params: []byte("artifact overridden to be incomplete"), params: []byte("artifact overridden to be incomplete"),
}}, nil, nil, pkg.WNew, pkg.InvalidArtifactError(pkg.MustDecode( }}, nil, nil, pkg.InvalidArtifactError(pkg.MustDecode(
"poVrv3zNINbHd-WUJihwgWQwJpbHURFHfpY7Zux-ztto_bQhhS5PdpbNMjdkXv-V", "E__uZ1sLIvb84vzSm5Uezb03RogsiaeTt1nfIVv8TKnnf4LqwtSi-smdHhlkZrUJ",
))}, ))},
{"error passthrough", newStubFile( {"error passthrough", newStubFile(
@@ -838,18 +830,18 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1}, pkg.ID{0xff, 1},
nil, nil,
nil, stub.UniqueError(0xcafe), nil, stub.UniqueError(0xcafe),
), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)}, ), nil, nil, stub.UniqueError(0xcafe)},
{"error caching", newStubFile( {"error caching", newStubFile(
pkg.KindHTTPGet, pkg.KindHTTPGet,
pkg.ID{0xff, 1}, pkg.ID{0xff, 1},
nil, nil,
nil, 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{ {"cache hit bad type", overrideChecksum{testdata.hash(), overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
}}}, nil, nil, pkg.WCache, pkg.InvalidFileModeError( }}}, nil, nil, pkg.InvalidFileModeError(
0400, 0400,
)}, )},
@@ -861,18 +853,21 @@ func TestCache(t *testing.T) {
cure: func(f *pkg.FContext) error { cure: func(f *pkg.FContext) error {
panic("attempting to cure impossible artifact") panic("attempting to cure impossible artifact")
}, },
}, nil, nil, pkg.WNew, pkg.InputError{ }, nil, nil, &pkg.DependencyCureError{
failingFile: struct { {
A: failingFile,
Err: struct {
_ []byte _ []byte
stub.UniqueError stub.UniqueError
}{UniqueError: 0xbad}, }{UniqueError: 0xbad},
},
}}, }},
}) })
if c0, err := pkg.Open( if c0, err := unsafeOpen(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
base, &skipLock, 0, 0, 0, base, false,
); err != nil { ); err != nil {
t.Fatalf("open: error = %v", err) t.Fatalf("open: error = %v", err)
} else { } else {
@@ -880,7 +875,7 @@ func TestCache(t *testing.T) {
cureMany(t, c0, []cureStep{ cureMany(t, c0, []cureStep{
{"cache hit ident", overrideIdent{ {"cache hit ident", overrideIdent{
id: identifier, id: identifier,
}, wantPathname, testdata, pkg.WCache, nil}, }, wantPathname, testdata, nil},
{"cache miss checksum match", newStubFile( {"cache miss checksum match", newStubFile(
pkg.KindHTTPGet, pkg.KindHTTPGet,
@@ -891,7 +886,7 @@ func TestCache(t *testing.T) {
), base.Append( ), base.Append(
"identifier", "identifier",
pkg.Encode(testdata.hash()), pkg.Encode(testdata.hash()),
), testdata, pkg.WNew, nil}, ), testdata, nil},
}) })
// cure after close // cure after close
@@ -1021,30 +1016,30 @@ func TestCache(t *testing.T) {
{"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{ {"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: makeSample, cure: makeSample,
}}}, wantPathname, want, pkg.WNew, nil}, }}}, wantPathname, want, nil},
{"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{ {"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
}}}, wantPathname, want, pkg.WCache, nil}, }}}, wantPathname, want, nil},
{"identical checksum", overrideIdent{id0, &stubArtifact{ {"identical checksum", overrideIdent{id0, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: makeSample, cure: makeSample,
}}, wantPathname0, want, pkg.WNew, nil}, }}, wantPathname0, want, nil},
{"cure fault", overrideIdent{pkg.ID{0xff, 0}, &stubArtifact{ {"cure fault", overrideIdent{pkg.ID{0xff, 0}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xcafe)) 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{ {"checksum mismatch", overrideChecksum{pkg.Checksum{}, overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), nil) return makeGarbage(t.GetWorkDir(), nil)
}, },
}}}, nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{ }}}, nil, nil, &pkg.ChecksumMismatchError{
Got: pkg.MustDecode( Got: pkg.MustDecode(
"CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT", "CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT",
), ),
@@ -1055,7 +1050,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 2}, pkg.ID{0xff, 2},
new(want.hash()), new(want.hash()),
testdata, nil, testdata, nil,
), nil, nil, pkg.WCache, pkg.InvalidFileModeError( ), nil, nil, pkg.InvalidFileModeError(
fs.ModeDir | 0500, fs.ModeDir | 0500,
)}, )},
@@ -1069,7 +1064,7 @@ func TestCache(t *testing.T) {
_, err = io.ReadAll(r) _, err = io.ReadAll(r)
return err return err
}, },
}}, nil, nil, pkg.WNew, &os.PathError{ }}, nil, nil, &os.PathError{
Op: "read", Op: "read",
Path: base.Append( Path: base.Append(
"checksum", "checksum",
@@ -1083,14 +1078,14 @@ func TestCache(t *testing.T) {
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return nil return nil
}, },
}}, nil, nil, pkg.WNew, pkg.NoOutputError{}}, }}, nil, nil, pkg.NoOutputError{}},
{"file output", overrideIdent{pkg.ID{0xff, 5}, &stubArtifact{ {"file output", overrideIdent{pkg.ID{0xff, 5}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return os.WriteFile(t.GetWorkDir().String(), []byte{0}, 0400) 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{ {"symlink output", overrideIdent{pkg.ID{0xff, 6}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
@@ -1100,7 +1095,7 @@ func TestCache(t *testing.T) {
t.GetWorkDir().String(), t.GetWorkDir().String(),
) )
}, },
}}, nil, nil, pkg.WNew, pkg.InvalidFileModeError( }}, nil, nil, pkg.InvalidFileModeError(
fs.ModeSymlink | 0777, fs.ModeSymlink | 0777,
)}, )},
@@ -1120,8 +1115,8 @@ func TestCache(t *testing.T) {
}, },
}, base.Append( }, base.Append(
"identifier", "identifier",
"gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9", "xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-",
), want, pkg.WNew, nil}, ), want, nil},
{"substitutable", &stubArtifactF{ {"substitutable", &stubArtifactF{
kind: pkg.KindExec, kind: pkg.KindExec,
@@ -1139,14 +1134,14 @@ func TestCache(t *testing.T) {
}, },
}, base.Append( }, base.Append(
"identifier", "identifier",
"VGjpp7NVw3OYLpgOQumfM0KcJgY3suz6torykUczcg4bGT24ySkPn5hy-4dNqqkR", "k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f",
), want, pkg.WSubstitute, nil}, ), want, nil},
}) })
if c0, err := pkg.Open( if c0, err := unsafeOpen(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
base, &skipLock, 0, 0, 0, base, false,
); err != nil { ); err != nil {
t.Fatalf("open: error = %v", err) t.Fatalf("open: error = %v", err)
} else { } else {
@@ -1168,8 +1163,8 @@ func TestCache(t *testing.T) {
}, },
}, base.Append( }, base.Append(
"identifier", "identifier",
"zeZ4JEZ0atAKl6Am67cBID6-KR18nZGgeYfU4qTuYaWhQC4eAn0dyTXdIBH9Bos8", "_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_",
), want, pkg.WSubstitute, nil}, ), want, nil},
}) })
} }
@@ -1193,15 +1188,15 @@ func TestCache(t *testing.T) {
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")}, "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/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/___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/_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/_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/k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
"identifier/gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9": {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": {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}, "work": {Mode: fs.ModeDir | 0700},
}}, }},
@@ -1240,7 +1235,7 @@ func TestCache(t *testing.T) {
pkg.ID{0xff, 1}, pkg.ID{0xff, 1},
nil, nil,
nil, stub.UniqueError(0xbad), nil, stub.UniqueError(0xbad),
), nil, nil, pkg.WNew, stub.UniqueError(0xbad)}, ), nil, nil, stub.UniqueError(0xbad)},
{"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{ {"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
@@ -1251,7 +1246,7 @@ func TestCache(t *testing.T) {
0400, 0400,
) )
}, },
}}, nil, nil, pkg.WNew, errors.New( }}, nil, nil, errors.New(
"non-file artifact produced regular file", "non-file artifact produced regular file",
)}, )},
}) })
@@ -1368,14 +1363,14 @@ func TestCache(t *testing.T) {
}}}, base.Append( }}}, base.Append(
"identifier", "identifier",
pkg.Encode(pkg.ID{0xff, 0}), pkg.Encode(pkg.ID{0xff, 0}),
), want, pkg.WNew, nil}, ), want, nil},
{"reject", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xfe, 1}, &stubArtifact{ {"reject", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xfe, 1}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xbad)) 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{ {"match", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
kind: pkg.KindTar, kind: pkg.KindTar,
@@ -1385,7 +1380,7 @@ func TestCache(t *testing.T) {
}}}, base.Append( }}}, base.Append(
"identifier", "identifier",
pkg.Encode(pkg.ID{0xff, 1}), pkg.Encode(pkg.ID{0xff, 1}),
), want, pkg.WNew, nil}, ), want, nil},
}) })
}, expectsFS{ }, expectsFS{
".": {Mode: fs.ModeDir | 0700}, ".": {Mode: fs.ModeDir | 0700},
@@ -1413,7 +1408,7 @@ func TestCache(t *testing.T) {
), base.Append( ), base.Append(
"identifier", "identifier",
pkg.Encode(pkg.Checksum{0xfe, 0}), pkg.Encode(pkg.Checksum{0xfe, 0}),
), expectsChecksum{0xff, 0}, pkg.WNew, nil}, ), expectsChecksum{0xff, 0}, nil},
}) })
for _, p := range [][]string{ for _, p := range [][]string{
@@ -1490,7 +1485,7 @@ func TestCache(t *testing.T) {
), expectsFS{ ), expectsFS{
".": {Mode: fs.ModeDir | 0500}, ".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444}, "result": {Mode: 0444},
}, pkg.WNew, nil}, }, nil},
{"substituted", substituted, base.Append( {"substituted", substituted, base.Append(
"identifier", "identifier",
@@ -1498,7 +1493,7 @@ func TestCache(t *testing.T) {
), expectsFS{ ), expectsFS{
".": {Mode: fs.ModeDir | 0500}, ".": {Mode: fs.ModeDir | 0500},
"result": {Mode: 0444}, "result": {Mode: 0444},
}, pkg.WSubstitute, nil}, }, nil},
}) })
}, expectsFS{ }, expectsFS{
".": {Mode: fs.ModeDir | 0700}, ".": {Mode: fs.ModeDir | 0700},
@@ -1509,18 +1504,18 @@ func TestCache(t *testing.T) {
"checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV": {Mode: 0400, Data: []byte("destroyed")}, "checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV": {Mode: 0400, Data: []byte("destroyed")},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/CLyyxJWn1yUGFs_0KnJ4ZSU2hH4-elvGFRB36x14LrNrKBJPxvORhL9O4Rc7oeYU": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")}, "identifier/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"identifier/arv8a6z4i0x6pUb5Z2T-3iE4ETvyZj-uReHGKsS7uiBgMgKNEOzTGG3LIZb8vp0L": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")}, "identifier/L-A8SK4ZX631eyealbJVH08u5pAVEf2NMk8RmLlxl7BVADkU4hNjWD6pi5H7uL1F": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"identifier/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")}, "identifier/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {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/aSMwvPAwdsIF9e1spuLyRNEc8aTFA4HRVasoNqGjxdm1laSMs2h2teGsoSzLp_pR": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
"status": {Mode: fs.ModeDir | 0700}, "status": {Mode: fs.ModeDir | 0700},
"status/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x")}, "status/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM")},
"status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0400, Data: []byte(statusHeader + "destroyed")}, "status/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0400, Data: []byte(statusHeader + "destroyed")}, "status/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
"substitute": {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/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
"work": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700},
}}, }},
@@ -1591,14 +1586,14 @@ func TestCache(t *testing.T) {
{"extern", a, base.Append( {"extern", a, base.Append(
"identifier", "identifier",
pkg.Encode(wantIdent.Value()), pkg.Encode(wantIdent.Value()),
), wantOutput, pkg.WExternal, nil}, ), wantOutput, nil},
{"substitute", _a, base.Append( {"substitute", _a, base.Append(
"identifier", "identifier",
pkg.Encode(_wantIdent.Value()), 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, 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")}, "checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "identifier/4HqRo4uTwRQjfy3d2cujMoDC_pC4iv20h4a7NYlx0UdbVuky18o5iK78TFEfPX2U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")}, "identifier/7AZcJm58ghFyTVf_v2baSntgpsxkP5el7ti9dC77C29n8YTEqQW9jRW92KGNdYnz": {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/c4aCI00C-ZVyo_FQDQLl1OYK4U_kjzxwrLdFDiXMHnbMcZXCkXo_nxUWauScZ_4V": {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/cNoG77frXGRCJa7fUi1INKUEQg7L4qrX5acsSv-wqZdGZT7dQwM93rD3at6kSFFF": {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/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"status": {Mode: fs.ModeDir | 0700}, "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": {Mode: fs.ModeDir | 0700},
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "substitute/qOYrxy9ztKeOA96Os811_0Ox5sd8FBOxis6psJAnRJL5MLazFMaqmd4g7t7k1OHk": {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")},
"work": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700},
}}, }},
@@ -1786,7 +1635,7 @@ func TestErrors(t *testing.T) {
}{ }{
{"InvalidLookupError", pkg.InvalidLookupError{ {"InvalidLookupError", pkg.InvalidLookupError{
0xff, 0xf0, 0xff, 0xf0,
}, "attempting to look up non-input artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}, }, "attempting to look up non-dependency artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
{"InvalidArtifactError", pkg.InvalidArtifactError{ {"InvalidArtifactError", pkg.InvalidArtifactError{
0xff, 0xfd, 0xff, 0xfd,
@@ -1946,7 +1795,7 @@ errors during scrub:
} }
} }
func TestInputError(t *testing.T) { func TestDependencyCureError(t *testing.T) {
t.Parallel() t.Parallel()
makeIdent := func(ident ...byte) pkg.Artifact { makeIdent := func(ident ...byte) pkg.Artifact {
@@ -1959,40 +1808,56 @@ func TestInputError(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
err pkg.InputError err pkg.DependencyCureError
want string want string
unwrap []error unwrap []error
}{ }{
{"simple", pkg.InputError{ {"simple", pkg.DependencyCureError{
makeIdent(0xff, 9): stub.UniqueError(0xbad09), {A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
makeIdent(0xff, 0): stub.UniqueError(0xbad00), {A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
makeIdent(0xff, 0xf): stub.UniqueError(0xbad0f), {A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
makeIdent(0xff, 1): stub.UniqueError(0xbad01), {A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
}, `errors curing inputs: }, `errors curing dependencies:
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite _wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite _wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite _wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{ _w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
stub.UniqueError(0xbad00), &pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
stub.UniqueError(0xbad01), &pkg.CureError{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
stub.UniqueError(0xbad09), &pkg.CureError{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
stub.UniqueError(0xbad0f), &pkg.CureError{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
}}, }},
{"dedup", pkg.InputError{ {"dedup", pkg.DependencyCureError{
makeIdent(0xff, 9): stub.UniqueError(0xbad09), {A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
makeIdent(0xff, 9): stub.UniqueError(0xbad09), {A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
makeIdent(0xff, 9): stub.UniqueError(0xbad09), {A: makeIdent(0xff, 0xfd), Err: &pkg.DependencyCureError{
makeIdent(0xff, 0): stub.UniqueError(0xbad00), {A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
makeIdent(0xff, 0): stub.UniqueError(0xbad00), {A: makeIdent(0xff, 0xc), Err: &pkg.DependencyCureError{
makeIdent(0xff, 1): stub.UniqueError(0xbad01), {A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
}, `errors curing inputs: {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 _wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite _wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite`, []error{ _wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
stub.UniqueError(0xbad00), _w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
stub.UniqueError(0xbad01), &pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
stub.UniqueError(0xbad09), &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 { for _, tc := range testCases {
@@ -2018,7 +1883,7 @@ func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
func (earlyFailureF) Params(*pkg.IContext) {} func (earlyFailureF) Params(*pkg.IContext) {}
func (earlyFailureF) IsExclusive() bool { return false } func (earlyFailureF) IsExclusive() bool { return false }
func (a earlyFailureF) Inputs() []pkg.Artifact { func (a earlyFailureF) Dependencies() []pkg.Artifact {
deps := make([]pkg.Artifact, a) deps := make([]pkg.Artifact, a)
for i := range deps { for i := range deps {
deps[i] = a - 1 deps[i] = a - 1
@@ -2036,21 +1901,19 @@ func (a earlyFailureF) Cure(*pkg.FContext) error {
func BenchmarkEarlyDCE(b *testing.B) { func BenchmarkEarlyDCE(b *testing.B) {
msg := message.New(log.New(os.Stderr, "dce: ", 0)) msg := message.New(log.New(os.Stderr, "dce: ", 0))
msg.SwapVerbose(testing.Verbose()) msg.SwapVerbose(testing.Verbose())
c, err := pkg.Open(b.Context(), msg, 0, 0, 0, check.MustAbs(b.TempDir()))
for b.Loop() {
b.StopTimer()
c, err := pkg.Open(b.Context(), msg, check.MustAbs(b.TempDir()), nil)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.StartTimer()
_, _, err = c.Cure(earlyFailureF(8)) _, _, err = c.Cure(earlyFailureF(8))
b.StopTimer()
if !errors.Is(err, stub.UniqueError(0xcafe)) { if !errors.Is(err, stub.UniqueError(0xcafe)) {
b.Fatalf("Cure: error = %v", err) b.Fatalf("Cure: error = %v", err)
} }
c.Close() 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( if _, err := pkg.Open(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
check.MustAbs(container.Nonexistent), 0, 0, 0, check.MustAbs(container.Nonexistent),
nil,
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr) t.Errorf("Open: error = %#v, want %#v", err, wantErr)
} }
@@ -2116,8 +1978,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
tempDir.Append("cache"), 0, 0, 0, tempDir.Append("cache"),
nil,
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr) t.Errorf("Open: error = %#v, want %#v", err, wantErr)
} }
@@ -2139,8 +2000,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
tempDir.Append("cache"), 0, 0, 0, tempDir.Append("cache"),
nil,
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr) t.Errorf("Open: error = %#v, want %#v", err, wantErr)
} }
@@ -2161,7 +2021,7 @@ func TestOpen(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), t.Context(),
message.New(nil), message.New(nil),
tempDir.Append("cache"), nil, 0, 0, 0, tempDir.Append("cache"),
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Errorf("Open: error = %#v, want %#v", err, wantErr) t.Errorf("Open: error = %#v, want %#v", err, wantErr)
} }
@@ -2214,8 +2074,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), t.Context(),
message.New(log.Default()), message.New(log.Default()),
0, 0, 0,
check.MustAbs(container.Nonexistent), check.MustAbs(container.Nonexistent),
nil,
); !errors.Is(err, os.ErrNotExist) { ); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} }
@@ -2253,7 +2113,7 @@ func TestExtensionRegister(t *testing.T) {
pkg.Register(pkg.KindCustomOffset, nil) pkg.Register(pkg.KindCustomOffset, nil)
t.Cleanup(func() { opened = false }) t.Cleanup(func() { opened = false })
_, _ = pkg.Open(nil, nil, nil, nil) _, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
panic("unreachable") panic("unreachable")
}) })
@@ -2264,7 +2124,11 @@ func TestExtensionRegister(t *testing.T) {
base := check.MustAbs(t.TempDir()) base := check.MustAbs(t.TempDir())
t.Cleanup(func() { opened = false }) 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) t.Fatal(err)
} else { } else {
c.Close() c.Close()
@@ -2292,7 +2156,8 @@ func TestExtensionRegister(t *testing.T) {
} }
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), nil, t.Context(), nil,
base, nil, 0, 0, 0,
base,
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("Open: error = %v, want %v", err, wantErr) t.Fatalf("Open: error = %v, want %v", err, wantErr)
} }
@@ -2313,8 +2178,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), nil, t.Context(), nil,
0, 0, 0,
base, base,
nil,
); !reflect.DeepEqual(err, pkg.ErrWouldPromote) { ); !reflect.DeepEqual(err, pkg.ErrWouldPromote) {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} }
@@ -2327,7 +2192,8 @@ func TestExtensionRegister(t *testing.T) {
if c, err := pkg.Open( if c, err := pkg.Open(
t.Context(), nil, t.Context(), nil,
base, &pkg.CacheAttr{Flags: pkg.CPromoteVariant}, pkg.CPromoteVariant, 0, 0,
base,
); err != nil { ); err != nil {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} else { } else {
@@ -2352,7 +2218,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), nil, t.Context(), nil,
base, nil, 0, 0, 0,
base,
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) { ); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} }
@@ -2369,7 +2236,8 @@ func TestExtensionRegister(t *testing.T) {
if _, err := pkg.Open( if _, err := pkg.Open(
t.Context(), nil, t.Context(), nil,
base, nil, 0, 0, 0,
base,
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) { ); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
t.Fatalf("Open: error = %v", err) t.Fatalf("Open: error = %v", err)
} }
+2 -9
View File
@@ -58,8 +58,8 @@ func init() {
}) })
} }
// Inputs returns a slice containing the backing file. // Dependencies returns a slice containing the backing file.
func (a *tarArtifact) Inputs() []Artifact { func (a *tarArtifact) Dependencies() []Artifact {
return []Artifact{a.f} return []Artifact{a.f}
} }
@@ -172,13 +172,6 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
} }
break 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: case tar.TypeXGlobalHeader:
continue // ignore continue // ignore
+30 -11
View File
@@ -3,6 +3,7 @@ package pkg_test
import ( import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"compress/gzip"
"crypto/sha512" "crypto/sha512"
"errors" "errors"
"io/fs" "io/fs"
@@ -79,8 +80,8 @@ func TestTar(t *testing.T) {
"checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500}, "checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, "identifier/T68YqeEW5moiwVe4J0wPvjERgyMUd4k_cKKxTcQx6AXqZaQAuuryu-Iv-qxDV6-T": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"identifier/v9DUj2R4YK_3ae0m9VuUYI-HJysDDCENu1k10thxioycRzFH1Qejw5bBGukm4IdL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)}, "identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
"substitute": {Mode: fs.ModeDir | 0700}, "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")}, "checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
"identifier": {Mode: fs.ModeDir | 0700}, "identifier": {Mode: fs.ModeDir | 0700},
"identifier/1SuvgGltcsgqps9tWqjULG8RCdpx_6KVWXdsMd5xPKvdtysOxqpE-3bLu4j0WpGk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)}, "identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
"identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {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}, "substitute": {Mode: fs.ModeDir | 0700},
@@ -131,7 +132,16 @@ func checkTarHTTP(
if err := w.Close(); err != nil { if err := w.Close(); err != nil {
t.Fatalf("Close: error = %v", err) 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 { testdataChecksum := func() pkg.Checksum {
@@ -198,19 +208,28 @@ func checkTarHTTP(
defer newDestroyArtifactFunc(&tarDirType)(t, base, c) defer newDestroyArtifactFunc(&tarDirType)(t, base, c)
cureMany(t, c, []cureStep{ cureMany(t, c, []cureStep{
{"file", pkg.NewTar(pkg.NewHTTPGet( {"file", pkg.NewTar(pkg.NewDecompress(pkg.NewHTTPGet(
&client, &client,
"file:///testdata", "file:///testdata",
testdataChecksum, 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", "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", "input directory does not contain a single regular file",
)}, )},
@@ -220,6 +239,6 @@ func checkTarHTTP(
cure: func(t *pkg.TContext) error { cure: func(t *pkg.TContext) error {
return stub.UniqueError(0xcafe) 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"} }, 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: rejecting coldboot loop: unique error 51966 injected by the test suite
dispatch: processed inconsistent uevent: duplicate add event on devpath "\x00" dispatch: processed inconsistent uevent: duplicate add event on devpath "\x00"
`, nil}, `, nil},
+6 -59
View File
@@ -12,7 +12,7 @@ import (
// Value are types supported by the language. // Value are types supported by the language.
type Value interface { type Value interface {
bool | int64 | string | []string | []int64 | [][2]string | Nil bool | int64 | string | []string | []int64 | [][2]string
} }
type ( type (
@@ -33,29 +33,6 @@ type (
F func(args FArgs) (v any, set bool, err error) F func(args FArgs) (v any, set bool, err error)
V map[unique.Handle[Ident]]any 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. // 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()) return UndefinedError(arg.K.Value())
} }
err := storeE(r, arg.V)
if err := storeE(r, arg.V); err != nil { if err != nil {
return err 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. // 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() 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) v := reflect.ValueOf(r)
if vt := v.Type(); !vt.AssignableTo(pt) { pt, vt := pv.Type(), v.Type()
if as { if !vt.AssignableTo(pt) {
var asv AString
if err := storeE(&asv.V, r); err != nil {
return err
}
pv.Set(reflect.ValueOf(asv))
return nil
}
return TypeError{vt, pt} return TypeError{vt, pt}
} }
pv.Set(v) pv.Set(v)
@@ -276,9 +226,6 @@ func evaluateAny(d PF, s []Frame, expr, rp any) bool {
case "false": case "false":
store(rp, false) store(rp, false)
return true return true
case "nil":
store(rp, Nil{})
return true
default: default:
return evaluateAny(d, s, v, rp) return evaluateAny(d, s, v, rp)
} }
+5 -69
View File
@@ -100,79 +100,15 @@ func TestEvaluate(t *testing.T) {
Err: UndefinedError("f"), Err: UndefinedError("f"),
}}, }},
{"error wrap deep", `f { v = nonexistent; }`, makeStackCheck(func( {"error wrap deep", `f { v = nil; }`, makeStackCheck(func(
FArgs, FArgs,
) (any, error) { ) (any, error) {
panic("unreachable") panic("unreachable")
}), "", EvaluationError{ }), "", EvaluationError{
Expr: Ident("nonexistent"), Expr: Ident("nil"),
Err: UndefinedError("nonexistent"), 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{ {"common inputs", `package name { inputs, v = []; }`, nil, "", EvaluationError{
Expr: Func{ Expr: Func{
Ident: Ident("name"), Ident: Ident("name"),
@@ -278,8 +214,8 @@ func TestEvaluate(t *testing.T) {
} }
var errEquals bool var errEquals bool
if e, ok := errors.AsType[TypeError](err); ok { if _, ok := errors.AsType[TypeError](err); ok {
errEquals = e.Is(tc.err) errEquals = errors.Is(err, tc.err)
} else { } else {
errEquals = reflect.DeepEqual(err, tc.err) errEquals = reflect.DeepEqual(err, tc.err)
} }
+1 -6
View File
@@ -18,11 +18,6 @@ const (
jobsLE = `"$(expr ` + jobsE + ` '*' 2)"` jobsLE = `"$(expr ` + jobsE + ` '*' 2)"`
// jobsLFlagE is expression for flag with double of preferred job count. // jobsLFlagE is expression for flag with double of preferred job count.
jobsLFlagE = `"-j$(expr ` + jobsE + ` '*' 2)"` 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. // 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(strconv.Itoa(int(n - 1)))
buf.WriteString(" ") 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(strconv.Itoa(int(n + 1)))
buf.WriteString("-") buf.WriteString("-")
} }
-1
View File
@@ -16,7 +16,6 @@ func TestSkipGNUTests(t *testing.T) {
}{ }{
{[]int64{764}, "1-763 765-"}, {[]int64{764}, "1-763 765-"},
{[]int64{764, 0xcafe, 37, 9}, "1-8 10-36 38-763 765-51965 51967-"}, {[]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{1, 2, 0xbed}, "3-3052 3054-"},
{[]int64{3, 4}, "1-2 5-"}, {[]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) var _ Helper = new(CMakeHelper)
// extra returns the cmake handle alongside either ninja or make. // 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 { if attr != nil && attr.Make {
return P{_cmake, _make} return P{_cmake, _make}
} }
@@ -61,10 +61,10 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
} }
generate := "Ninja" generate := "Ninja"
test := "ninja " + jobsFlagE + " " + loadFlagE + " test" test := "ninja " + jobsFlagE + " test"
if attr.Make { if attr.Make {
generate = "'Unix Makefiles'" generate = "'Unix Makefiles'"
test = "make " + jobsFlagE + " " + loadFlagE + " test" test = "make " + jobsFlagE + " test"
} }
if attr.Test != "" { if attr.Test != "" {
test = attr.Test test = attr.Test
@@ -84,7 +84,6 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
return ` return `
cmake -G ` + generate + ` \ cmake -G ` + generate + ` \
-Wno-author -Wno-unused-cli \
-DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \ -DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \
-DCMAKE_CXX_COMPILER_TARGET="${ROSA_TRIPLE}" \ -DCMAKE_CXX_COMPILER_TARGET="${ROSA_TRIPLE}" \
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \ -DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
@@ -98,7 +97,7 @@ cmake -G ` + generate + ` \
}), " \\\n\t") + ` \ }), " \\\n\t") + ` \
-DCMAKE_INSTALL_PREFIX=/system \ -DCMAKE_INSTALL_PREFIX=/system \
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `' '/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
cmake --build . --parallel=` + jobsE + ` -- ` + loadFlagE + ` cmake --build . --parallel=` + jobsE + `
DESTDIR=/work cmake --install . DESTDIR=/work cmake --install .
` + script ` + script
} }
+2 -4
View File
@@ -107,8 +107,6 @@ func init() {
a := cureEtc{} a := cureEtc{}
if r.ReadUint32() == 0 { if r.ReadUint32() == 0 {
a.minimal = true a.minimal = true
} else {
r.Next()
} }
if _, ok := r.Finalise(); ok { if _, ok := r.Finalise(); ok {
panic(pkg.ErrUnexpectedChecksum) panic(pkg.ErrUnexpectedChecksum)
@@ -120,8 +118,8 @@ func init() {
// IsExclusive returns false: Cure performs a few trivial filesystem writes. // IsExclusive returns false: Cure performs a few trivial filesystem writes.
func (cureEtc) IsExclusive() bool { return false } func (cureEtc) IsExclusive() bool { return false }
// Inputs returns a slice containing the backing iana-etc release. // Dependencies returns a slice containing the backing iana-etc release.
func (a cureEtc) Inputs() []pkg.Artifact { func (a cureEtc) Dependencies() []pkg.Artifact {
if !a.minimal { if !a.minimal {
return []pkg.Artifact{ianaEtc} 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( return t.New(strings.TrimSuffix(
path.Base(url), path.Base(url),
".git", ".git",
)+"-src", path.Base(rev), nil, &PackageAttr{ )+"-src-"+path.Base(rev), THostNet, t.Append(nil,
KnownChecksum: &checksum, _nssCACert,
_git,
HostNet: true, ), &checksum, nil, `
Paths: []pkg.ExecPath{resolvconf()},
}, &GenericHelper{
Build: `
git \ git \
-c advice.detachedHead=false \ -c advice.detachedHead=false \
clone \ clone \
@@ -37,9 +34,5 @@ git \
`+url+` \ `+url+` \
/work /work
rm -rf /work/.git rm -rf /work/.git
`, `, resolvconf())
},
_nssCACert,
_git,
)
} }
+28 -10
View File
@@ -13,7 +13,7 @@ func (t Toolchain) newGo(
script string, script string,
boot ...pkg.Artifact, boot ...pkg.Artifact,
) 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", "https://go.dev/dl/go"+version+".src.tar.gz",
checksum, checksum,
pkg.Gzip, pkg.Gzip,
@@ -56,15 +56,16 @@ ln -s \
func init() { func init() {
const ( const (
version = "1.25.14" version = "1.26.4"
checksum = "QKYjKzziCmD1eboU__Oi8VjqbPjaHrHAI9ceWyF3D9ORm7cPHN8muZuiGsoLKjCJ" checksum = "fpqJlxa41wKRtbnviYNLk9VxgcL-5oIEDxsriF8svU6kNwQW70oRRA9gTz_ImVoB"
) )
meta := Metadata{ meta := Metadata{
Name: "go-bootstrap", Name: "go",
Description: "the Go programming language toolchain (bootstrap)", Description: "the Go programming language toolchain",
Website: "https://go.dev", Website: "https://go.dev",
Version: version, Version: version,
Exclude: true,
ID: 1227,
} }
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) { native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
var ( var (
@@ -75,7 +76,7 @@ func init() {
) )
switch t.arch { switch t.arch {
case "amd64": 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", "https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
"8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23", "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23",
pkg.Gzip, pkg.Gzip,
@@ -151,8 +152,8 @@ sed -i \
) )
go125 := t.newGo( go125 := t.newGo(
version, "1.25.11",
checksum, "cnqAQ8wpVZXcM6nHAfSqFkIW4L3H73ALB9rBfKUBbfgg4_pOF3I9zOZARgYQ6MR2",
[]string{"CGO_ENABLED=0"}, ` []string{"CGO_ENABLED=0"}, `
sed -i \ sed -i \
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \ 's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
@@ -164,6 +165,23 @@ rm \
`, go123, `, 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 package rosa
import ( import (
"io/fs"
"regexp" "regexp"
"slices" "slices"
"strings" "strings"
"unsafe"
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
) )
@@ -11,12 +13,12 @@ import (
var ( var (
_llvmSource = H("llvm-project") _llvmSource = H("llvm-project")
_muslHeaders = H("musl-headers") _muslHeaders = H("musl-headers")
_earlyCompilerRT = H("early-compiler-rt")
_earlyRuntimes = H("early-runtimes") _earlyRuntimes = H("early-runtimes")
_musl = H("musl") _musl = H("musl")
_bash = H("bash") _bash = H("bash")
_awk = H("awk") _gawk = H("gawk")
_pythonEarly = H("python-early")
_coreutils = H("coreutils") _coreutils = H("coreutils")
_diffutils = H("diffutils") _diffutils = H("diffutils")
_findutils = H("findutils") _findutils = H("findutils")
@@ -48,6 +50,165 @@ func litArgs(verbose bool, skipChecks ...string) string {
} }
func init() { 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) { native.MustRegister("llvm", func(t Toolchain) (*Metadata, pkg.Artifact) {
meta := Metadata{ meta := Metadata{
Name: "llvm", Name: "llvm",
@@ -83,11 +244,9 @@ func init() {
{"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"}, {"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"},
{"LIBCXX_HAS_MUSL_LIBC", "ON"}, {"LIBCXX_HAS_MUSL_LIBC", "ON"},
{"LIBCXX_HARDENING_MODE", "fast"}, {"LIBCXX_HARDENING_MODE", "fast"},
{"LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY", "ON"},
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"}, {"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "ON"}, {"LIBCXXABI_ENABLE_STATIC_UNWINDER", "OFF"},
{"LIBCXXABI_USE_COMPILER_RT", "ON"}, {"LIBCXXABI_USE_COMPILER_RT", "ON"},
{"LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY", "ON"},
{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"}, {"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"},
{"LLVM_INSTALL_UTILS", "ON"}, {"LLVM_INSTALL_UTILS", "ON"},
{"LLVM_BUILD_LLVM_DYLIB", "ON"}, {"LLVM_BUILD_LLVM_DYLIB", "ON"},
@@ -140,10 +299,6 @@ func init() {
"CodeGen/PowerPC/ppc-tmmintrin.c", "CodeGen/PowerPC/ppc-tmmintrin.c",
"CodeGen/PowerPC/ppc-smmintrin.c", "CodeGen/PowerPC/ppc-smmintrin.c",
"CodeGenCUDA/amdgpu-alias-undef-symbols.cu", "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 // cxx: fails on musl
"close.dont-get-rid-of-buffer", "close.dont-get-rid-of-buffer",
"re/re.traits", "re/re.traits",
@@ -184,19 +339,8 @@ func init() {
}...) }...)
} }
return &meta, t.New("llvm", meta.Version, source, &PackageAttr{ return &meta, t.NewPackage("llvm", meta.Version, source, &PackageAttr{
Exclusive: true, Flag: TExclusive,
Bin: []string{
"chmod",
"mkdir",
"rm",
"tr",
"awk",
},
ScriptEarly: `
rm -f /system/bin/clang++.cfg
`,
}, &CMakeHelper{ }, &CMakeHelper{
Append: []string{"llvm"}, 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/cc
ln -s clang /work/system/bin/cpp ln -s clang /work/system/bin/cpp
ln -s clang++ /work/system/bin/c++ 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 // LLVM_LINK_LLVM_DYLIB causes llvm test suite to leak system
@@ -218,13 +358,22 @@ EOF
// on 3-stage determinism to test later stages. // on 3-stage determinism to test later stages.
SkipTest: t.stage.isStage0(), 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, _perl,
_diffutils, _diffutils,
_bash, _bash,
_awk, _gawk,
_coreutils, _coreutils,
_findutils, _findutils,
+1 -1
View File
@@ -8,7 +8,7 @@ import (
) )
func TestLLVMInputs(t *testing.T) { func TestLLVMInputs(t *testing.T) {
const wantInputCount = 470 const wantInputCount = 553
_, llvm := rosa.Native().Std().MustLoad(rosa.H("llvm")) _, llvm := rosa.Native().Std().MustLoad(rosa.H("llvm"))
var n int var n int
+9 -13
View File
@@ -52,16 +52,15 @@ type MakeHelper struct {
var _ Helper = new(MakeHelper) var _ Helper = new(MakeHelper)
// extra returns make and other optional dependencies. // extra returns make and other optional dependencies.
func (attr *MakeHelper) extra() P { func (attr *MakeHelper) extra(flag int) P {
if attr == nil || !attr.OmitDefaults { extra := P{_make}
return P{ if (attr == nil || !attr.OmitDefaults) && flag&TEarly == 0 {
_make, extra = append(extra,
_gawk,
_awk,
_coreutils, _coreutils,
)
} }
} return extra
return P{_make}
} }
// wantsChmod returns whether the build system needs to be generated. // 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 { if attr != nil && attr.InPlace {
return helperInPlace, false return helperInPlace, false
} }
return "/cure/", true return `"$(mktemp -d)"`, false
} }
// script generates the cure script. // script generates the cure script.
@@ -161,8 +160,7 @@ func (attr *MakeHelper) script(t Toolchain, name string) string {
scriptMake := ` scriptMake := `
make \ make \
` + jobsFlagE + ` \ ` + jobsFlagE
` + loadFlagE
if len(attr.Make) > 0 { if len(attr.Make) > 0 {
scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t") scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t")
} }
@@ -172,8 +170,6 @@ make \
(!attr.SkipCheckEarly || !t.stage.isStage0()) { (!attr.SkipCheckEarly || !t.stage.isStage0()) {
scriptMake += attr.ScriptCheckEarly + `make \ scriptMake += attr.ScriptCheckEarly + `make \
` + jobsFlagE + ` \ ` + jobsFlagE + ` \
` + loadFlagE + ` \
AM_COLOR_TESTS=always \
` `
if len(attr.Check) > 0 { if len(attr.Check) > 0 {
scriptMake += strings.Join(attr.Check, " \\\n\t") scriptMake += strings.Join(attr.Check, " \\\n\t")
+15 -45
View File
@@ -5,16 +5,10 @@ import (
"strings" "strings"
) )
var ( var _meson = H("meson")
_muon = H("muon")
_meson = H("meson")
)
// MesonHelper builds and tests a meson project. // MesonHelper builds and tests a meson project.
type MesonHelper struct { type MesonHelper struct {
// Use muon instead of meson.
Muon bool
// Runs after setup. // Runs after setup.
ScriptCompileEarly string ScriptCompileEarly string
// Runs after compile. // Runs after compile.
@@ -35,12 +29,7 @@ type MesonHelper struct {
var _ Helper = new(MesonHelper) var _ Helper = new(MesonHelper)
// extra returns hardcoded meson runtime dependencies. // extra returns hardcoded meson runtime dependencies.
func (attr *MesonHelper) extra() P { func (*MesonHelper) extra(int) P { return P{_meson} }
if !attr.isPython() {
return P{_muon}
}
return P{_meson}
}
// wantsChmod returns false. // wantsChmod returns false.
func (*MesonHelper) wantsChmod() bool { return false } func (*MesonHelper) wantsChmod() bool { return false }
@@ -54,12 +43,6 @@ func (*MesonHelper) scriptEarly() string { return "" }
// wantsDir requests a new directory in TMPDIR. // wantsDir requests a new directory in TMPDIR.
func (*MesonHelper) wantsDir() (string, bool) { return `"$(mktemp -d)"`, false } 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. // script generates the cure script.
func (attr *MesonHelper) script(t Toolchain, name string) string { func (attr *MesonHelper) script(t Toolchain, name string) string {
if attr == nil { if attr == nil {
@@ -71,28 +54,11 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
scriptCompiled = "\n" + scriptCompiled 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 var scriptTest string
if !attr.SkipTest && t.opts&OptSkipCheck == 0 { if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
scriptTest = ` scriptTest = `
` + muon + ` test \ meson test \
` + jobsFlagE + ` \
-t 10`
if python {
scriptTest += ` \
--print-errorlogs` --print-errorlogs`
} else {
scriptTest += " -Rv"
}
if attr.InteractiveTest { if attr.InteractiveTest {
scriptTest += ` \ scriptTest += ` \
--interactive` --interactive`
@@ -103,25 +69,29 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
} }
return ` return `
` + muon + ` setup \ cd "$(mktemp -d)"
meson setup \
` + strings.Join(slices.Collect(func(yield func(string) bool) { ` + strings.Join(slices.Collect(func(yield func(string) bool) {
for _, v := range append([]KV{ for _, v := range append([]KV{
{"wrap_mode", "nofallback"}, {"wrap-mode", "nofallback"},
{"prefix", "/system"}, {"prefix", "/system"},
{"buildtype", "release"}, {"buildtype", "release"},
}, attr.Setup...) { }, attr.Setup...) {
s := v[0] s := "-" + v[0]
if len(v[0]) > 0 && v[0][0] != 'D' {
s = "-" + s
}
if v[1] != "" { if v[1] != "" {
s = "-D" + s + "=" + v[1] s += "=" + v[1]
} }
if !yield(s) { if !yield(s) {
return return
} }
} }
}), " \\\n\t") + ` \ }), " \\\n\t") + ` \
'/usr/src/` + name + `' . '/usr/src/` + name + `'
` + muon + compile + scriptCompiled + scriptTest + ` meson compile` + scriptCompiled + scriptTest + `
` + muon + ` install \ meson install \
` + destdir + ` /work --destdir=/work
` + attr.Script ` + attr.Script
} }
+113 -256
View File
@@ -14,7 +14,6 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"syscall"
"unique" "unique"
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
@@ -31,8 +30,8 @@ type Remote struct {
c *http.Client c *http.Client
} }
// NewRemote returns a populated [Remote]. // NewRemote returns a populated [Remote]
func NewRemote(c *http.Client, base string, pub ed25519.PublicKey) (Remote, error) { func NewRemote(base string, pub ed25519.PublicKey, c *http.Client) (Remote, error) {
u, err := url.Parse(base) u, err := url.Parse(base)
return Remote{u, pub, c}, err return Remote{u, pub, c}, err
} }
@@ -202,261 +201,14 @@ func (r Remote) Status(
), nil ), nil
} }
// Mirror services requests made by [Remote]. // NewMirror returns an [http.Handler] for servicing mirror requests.
type Mirror struct {
// Cache on-filesystem format.
fsys fs.FS
// Signs payloads.
key ed25519.PrivateKey
// Verbose output.
msg message.Msg
}
// Populate fills an empty root with a static mirror snapshot.
func (m Mirror) Populate(root *os.Root) error {
if dents, err := fs.ReadDir(root.FS(), "."); err != nil {
return err
} else if len(dents) > 0 {
return syscall.ENOTEMPTY
}
for _, name := range []string{
dirArtifact,
dirOutcome,
dirStatus,
} {
if err := root.Mkdir(name, 0755); err != nil {
return err
}
}
var w *os.File
if dents, err := fs.ReadDir(m.fsys, "identifier"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf [2 * len(pkg.Checksum{})]byte
if err = pkg.Decode(
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
name,
); err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirArtifact, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
err = m.writeArtifact(&buf, w, nil)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
if dents, err := fs.ReadDir(m.fsys, "checksum"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf pkg.Checksum
if err = pkg.Decode(&buf, name); err != nil {
return err
}
var fsys fs.FS
fsys, err = fs.Sub(m.fsys, filepath.Join("checksum", name))
if err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirOutcome, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
m.msg.Verbosef("exporting outcome %s", name)
err = pkg.Write(fsys, ".", w)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
if dents, err := fs.ReadDir(m.fsys, "status"); err != nil {
return err
} else {
for _, dent := range dents {
name := dent.Name()
var buf [2 * len(pkg.Checksum{})]byte
if err = pkg.Decode(
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
name,
); err != nil {
return err
}
if w, err = root.OpenFile(
filepath.Join(dirStatus, name),
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
0444,
); err != nil {
return err
}
err = m.writeStatus(&buf, w, nil)
if err = errors.Join(err, w.Close()); err != nil {
return err
}
}
}
return nil
}
// NewMirror returns a populated [Mirror] for servicing mirror requests.
func NewMirror( func NewMirror(
msg message.Msg, msg message.Msg,
fsys fs.FS, fsys fs.FS,
key ed25519.PrivateKey, key ed25519.PrivateKey,
) Mirror { ) http.Handler {
return Mirror{fsys, key, msg}
}
// writeArtifact writes a signed dirArtifact response.
func (m Mirror) writeArtifact(
buf *[2 * len(pkg.Checksum{})]byte,
w io.Writer,
header http.Header,
) error {
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
if linkname, err := fs.ReadLink(m.fsys, filepath.Join(
"identifier",
ids,
)); err != nil {
return err
} else if err = pkg.Decode(
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
filepath.Base(linkname),
); err != nil {
return err
}
m.msg.Verbosef("serving artifact %s", ids)
if header != nil {
header.Set(
"Content-Length",
strconv.Itoa(ed25519.SignatureSize+len(buf)),
)
}
_, err := w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...))
return err
}
// writeOutcome writes a dirOutcome response.
func (m Mirror) writeOutcome(
buf *pkg.Checksum,
w io.Writer,
header http.Header,
) error {
checksums := pkg.Encode(*buf)
rel := filepath.Join("checksum", checksums)
if _, err := fs.Lstat(m.fsys, rel); err != nil {
return err
}
m.msg.Verbosef("serving outcome %s", checksums)
_fsys, err := fs.Sub(m.fsys, rel)
if err != nil {
return err
}
var gw *gzip.Writer
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
return err
}
if header != nil {
header.Set("Content-Encoding", "gzip")
}
if err = pkg.Write(_fsys, ".", gw); err != nil {
_ = gw.Close()
return err
}
return gw.Close()
}
// writeStatus writes a signed dirStatus response.
func (m Mirror) writeStatus(
buf *[2 * len(pkg.Checksum{})]byte,
w io.Writer,
_ http.Header,
) error {
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
f, err := m.fsys.Open(filepath.Join(
"status",
ids,
))
if err != nil {
return err
}
s, ok := f.(io.Seeker)
if !ok {
return &fs.PathError{Op: "seek", Path: ids, Err: fs.ErrInvalid}
}
m.msg.Verbosef("serving status %s", ids)
h := sha512.New384()
if _, err = io.Copy(h, f); err != nil {
_ = f.Close()
return err
}
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
if _, err = w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...)); err != nil {
_ = f.Close()
return err
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
_ = f.Close()
return err
} else if _, err = io.Copy(w, f); err != nil {
_ = f.Close()
return err
}
return f.Close()
}
// writeF is a helper for writing a mirror response with error handling.
func writeF[B any](
m Mirror,
w http.ResponseWriter,
buf B,
f func(
buf B,
w io.Writer,
header http.Header,
) error,
) {
err := f(buf, w, w.Header())
if err == nil {
return
}
if errors.Is(err, os.ErrNotExist) {
w.WriteHeader(http.StatusNotFound)
return
}
m.msg.GetLogger().Println(err)
w.WriteHeader(http.StatusInternalServerError)
}
// Register configures an [http.ServeMux] for servicing mirror requests.
func (m Mirror) Register(mux *http.ServeMux) {
const identName = "ident" const identName = "ident"
var mux http.ServeMux
mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func( mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func(
w http.ResponseWriter, w http.ResponseWriter,
@@ -470,7 +222,38 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return 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( mux.HandleFunc("/"+dirOutcome+"/{"+identName+"}", func(
@@ -490,7 +273,40 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return 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( mux.HandleFunc("/"+dirStatus+"/{"+identName+"}", func(
@@ -505,6 +321,47 @@ func (m Mirror) Register(mux *http.ServeMux) {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return 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" "crypto/ed25519"
"io/fs" "io/fs"
"log" "log"
"net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"testing" "testing"
@@ -31,7 +30,7 @@ func TestMirror(t *testing.T) {
msg.SwapVerbose(testing.Verbose()) msg.SwapVerbose(testing.Verbose())
var c *pkg.Cache 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -53,16 +52,14 @@ func TestMirror(t *testing.T) {
} }
wantChecksums := pkg.Encode(wantChecksum) wantChecksums := pkg.Encode(wantChecksum)
var mux http.ServeMux server := httptest.NewServer(rosa.NewMirror(msg, fstest.MapFS{
rosa.NewMirror(msg, fstest.MapFS{
"identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)}, "identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)},
"checksum/" + wantChecksums: {Mode: os.ModeDir | 0500}, "checksum/" + wantChecksums: {Mode: os.ModeDir | 0500},
}, priv).Register(&mux) }, priv))
server := httptest.NewServer(&mux)
t.Cleanup(server.Close) t.Cleanup(server.Close)
var extern pkg.External 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
+5 -3
View File
@@ -13,8 +13,10 @@ package attr {
patches = [ "musl-errno.patch" ]; patches = [ "musl-errno.patch" ];
bin = [ "perl" ]; early = `
populateUsrBin = true; ln -s ../../system/bin/perl /usr/bin
`;
exec = make {}; exec = make {};
inputs = [ inputs = [
@@ -39,7 +41,7 @@ package acl {
exec = make { exec = make {
// makes assumptions about uid_map/gid_map // makes assumptions about uid_map/gid_map
check = nil; skipCheck = true;
}; };
inputs = [ attr, kernel-headers ]; 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"; version# = "3.8.2";
source = remoteTar { 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"; checksum = "BhRM6K7URj1LNOkIDCFDctSErLS-Xo5d9ba9seg10o6ACrgC1uNhED7CQPgIY29Y";
compress = gzip; compress = gzip;
}; };
toyboxEarly = true;
exec = make { exec = make {
defaults = false;
check = [ check = [
"TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests { "TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests {
tests = [ tests = [
// GNU-isms not implemented in toybox
168, 170, 623,
// clang miscompiles (SIGILL) // clang miscompiles (SIGILL)
764, 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; enterSource = true;
exec = make { exec = make {
chdir = false; skipConfigure = true;
configure = nil; skipCheck = true;
make = [ "CC=cc" ]; inPlace = true;
check = nil;
make = [
"CC=cc",
];
install = "make PREFIX=/work/system install"; install = "make PREFIX=/work/system install";
}; };
} }
+11 -11
View File
@@ -13,25 +13,25 @@ package cairo {
exec = meson { exec = meson {
setup = { setup = {
"dwrite": "enabled"; "Ddwrite": "enabled";
"fontconfig": "enabled"; "Dfontconfig": "enabled";
"freetype": "enabled"; "Dfreetype": "enabled";
"png": "enabled"; "Dpng": "enabled";
"tee": "enabled"; "Dtee": "enabled";
"xcb": "enabled"; "Dxcb": "enabled";
"xlib": "disabled"; "Dxlib": "disabled";
"xlib-xcb": "disabled"; "Dxlib-xcb": "disabled";
"zlib": "enabled"; "Dzlib": "enabled";
}; };
// runs the entire test suite in a single meson test // runs the entire test suite in a single meson test
interactiveTest = true; interactiveTest = true;
// only works with specific dependency versions // only works with specific dependency versions
test = false; skipTest = true;
}; };
inputs = [ inputs = [
awk, gawk,
zlib, zlib,
libpng, 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"; website = "https://cmake.org";
anitya = 306; anitya = 306;
version# = "4.4.2"; version# = "4.3.4";
source = remoteGitHubRelease { source = remoteGitHubRelease {
suffix = "Kitware/CMake"; suffix = "Kitware/CMake";
tag = "v"+version; tag = "v"+version;
name = "cmake-"+version+".tar.gz"; name = "cmake-"+version+".tar.gz";
checksum = "IWlqJqJCZ6f-z-7Ft1U4ycvCX4riuihKale5NKWusiHemBgC3m5gCecrzikXoL7S"; checksum = "6A50pqarKDXKOCv7ffKMvWJWmNTVp_ep8KoaWwNdg-RYQRddgKbxayHveTo6jZ_7";
compress = gzip; 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 // test suite expects writable source tree
writable = true; writable = true;
@@ -20,7 +23,7 @@ package cmake {
chmod = true; chmod = true;
exec = make { exec = make {
defaults = false; omitDefaults = true;
configureName = "/usr/src/cmake/bootstrap"; configureName = "/usr/src/cmake/bootstrap";
configure = { configure = {
@@ -29,7 +32,6 @@ package cmake {
"--"; "--";
"-DCMAKE_USE_OPENSSL": "OFF"; "-DCMAKE_USE_OPENSSL": "OFF";
"-DCMake_TEST_NO_NETWORK": "ON"; "-DCMake_TEST_NO_NETWORK": "ON";
"-DCMake_TEST_BOOTSTRAP": "OFF";
}; };
check = [ check = [
+1 -1
View File
@@ -19,7 +19,7 @@ package connman {
inputs = [ inputs = [
automake, automake,
libtool, libtool,
pkgconf, pkg-config,
dbus, dbus,
iptables, 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 { exec = make {
chdir = false; inPlace = true;
configureName = "../dist/configure"; configureName = "../dist/configure";
forceAutoconf = true; forceAutoconf = true;
configure = { configure = {
+6 -6
View File
@@ -19,9 +19,9 @@ package dbus {
exec = meson { exec = meson {
setup = { setup = {
"epoll": "enabled"; "Depoll": "enabled";
"inotify": "enabled"; "Dinotify": "enabled";
"x11_autolaunch": "disabled"; "Dx11_autolaunch": "disabled";
}; };
}; };
@@ -41,16 +41,16 @@ package xdg-dbus-proxy {
website = "https://github.com/flatpak/xdg-dbus-proxy"; website = "https://github.com/flatpak/xdg-dbus-proxy";
anitya = 58434; anitya = 58434;
version# = "0.1.8"; version# = "0.1.7";
source = remoteGitHub { source = remoteGitHub {
suffix = "flatpak/xdg-dbus-proxy"; suffix = "flatpak/xdg-dbus-proxy";
tag = version; tag = version;
checksum = "ygdW0EEvZ-_PJfnFTNoobITmRzqJecTinBsJd_iJQrRvzidwqESCjeNkB55smZ2y"; checksum = "UW5Pe-TP-XAaN-kTbxrkOQ7eYdmlAQlr2pdreLtPT0uwdAz-7rzDP8V_8PWuZBup";
}; };
exec = meson { exec = meson {
setup = { setup = {
"man": "disabled"; "Dman": "disabled";
}; };
}; };
+1 -1
View File
@@ -18,7 +18,7 @@ package dtc {
exec = meson { exec = meson {
setup = { 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 { exec = make {
// nonstandard glibc extension
skipCheck = true;
configure = { configure = {
"enable-deterministic-archives"; "enable-deterministic-archives";
}; };
// nonstandard glibc extension
check = nil;
}; };
inputs = [ inputs = [
m4, m4,
pkgconf, pkg-config,
zlib, zlib,
bzip2, bzip2,
+2 -3
View File
@@ -5,9 +5,8 @@ package fcft {
version# = "3.3.3"; version# = "3.3.3";
source = remoteTar { source = remoteTar {
url = "https://codeberg.org/dnkl/fcft/releases/download/"+version+ url = "https://codeberg.org/dnkl/fcft/archive/"+version+".tar.gz";
"/fcft-"+version+".tar.gz"; checksum = "bMj8OmqtoANRKZWbjHk4WfP09AxJYRbWGqUsm1gRJ_dOFg6gooNbgkDu597PLfz2";
checksum = "pryAJA-d1OpY8KXbGFEHum9Wm6ME9XkPx9EM_OQ_ZEpOUpQnqlkzIq-cwS1ziMPk";
compress = gzip; 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"; website = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git";
anitya = 141464; anitya = 141464;
version# = "20260810"; version# = "20260622";
source = remoteGitLab { source = remoteGitLab {
domain = "gitlab.com"; domain = "gitlab.com";
suffix = "kernel-firmware/linux-firmware"; suffix = "kernel-firmware/linux-firmware";
ref = version; ref = version;
checksum = "XNUhz9QstaDKNegM3Bl0-TtZzpsvX7-E8WMnDCO7KBhBC6t_TxsdG05-ETdXynry"; checksum = "gpytkDM58EVjaUuryOekcekh_rWsfuv3S7LQxopHlNlVGmMsuqNwfug4BjgTgizE";
}; };
// dedup creates temporary file // dedup creates temporary file
@@ -22,19 +22,19 @@ package firmware {
]; ];
exec = make { exec = make {
defaults = false; omitDefaults = true;
chdir = false; skipConfigure = true;
inPlace = true;
configure = nil;
make = [ make = [
"DESTDIR=/work/system", "DESTDIR=/work/system",
"install-zst", "install-zst",
]; ];
// requires pre-commit // requires pre-commit
check = nil; skipCheck = true;
install = "make " + jobsFlagE + " " + loadFlagE + " DESTDIR=/work/system dedup"; install = "make " + jobsFlagE + " DESTDIR=/work/system dedup";
}; };
inputs = [ inputs = [
+3 -3
View File
@@ -3,12 +3,12 @@ package fontconfig {
website = "https://www.freedesktop.org/wiki/Software/fontconfig"; website = "https://www.freedesktop.org/wiki/Software/fontconfig";
anitya = 827; anitya = 827;
version# = "2.18.3"; version# = "2.18.1";
source = remoteGitLab { source = remoteGitLab {
domain = "gitlab.freedesktop.org"; domain = "gitlab.freedesktop.org";
suffix = "fontconfig/fontconfig"; suffix = "fontconfig/fontconfig";
ref = version; ref = version;
checksum = "ZZzmt8fYh-3jKJ6vHXUDbeAWM2ilRusWxdynLt3Z4E_CQQ8cCwzpuAWACXmr9qHI"; checksum = "S3FJfh-PeZ2_YgNrUqL0H2G4Wf_ilj5HpIGV2oURnkK672AQHpWk526bNtRHwyJt";
}; };
exec = make { exec = make {
@@ -18,7 +18,7 @@ package fontconfig {
inputs = [ inputs = [
automake, automake,
libtool, libtool,
pkgconf, pkg-config,
gettext, gettext,
gperf, gperf,
gzip, gzip,
+2 -3
View File
@@ -5,9 +5,8 @@ package foot {
version# = "1.27.0"; version# = "1.27.0";
source = remoteTar { source = remoteTar {
url = "https://codeberg.org/dnkl/foot/releases/download/"+version+ url = "https://codeberg.org/dnkl/foot/archive/"+version+".tar.gz";
"/foot-"+version+".tar.gz"; checksum = "E2XIPRD8t-WBBJUebIwChFT8K_85diwdalssUNwnuZBIynPa7rlXro5WCe9v3UlK";
checksum = "22rG3rMuQI8Ae2XTcZgOJ-6AbF7Taex8XpgvD6Fyg1Mn5Va67FfUcK3tRaq61TFg";
compress = gzip; compress = gzip;
}; };
+1 -1
View File
@@ -12,7 +12,7 @@ package fribidi {
exec = meson { exec = meson {
setup = { setup = {
"docs": "false"; "Ddocs": "false";
}; };
}; };
} }
+5 -5
View File
@@ -14,15 +14,15 @@ package fuse {
exec = meson { exec = meson {
setup = { setup = {
"default_library": "both"; "Ddefault_library": "both";
"tests": "true"; "Dtests": "true";
"useroot": "false"; "Duseroot": "false";
"initscriptdir": "/system/etc"; "Dinitscriptdir": "/system/etc";
}; };
postCompile = "python3 -m pytest test/"; postCompile = "python3 -m pytest test/";
// this project uses pytest // this project uses pytest
test = false; skipTest = true;
}; };
inputs = [ 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"; website = "https://www.gnu.org/software/binutils";
anitya = 7981; anitya = 7981;
version# = "2.47"; version# = "2.46.1";
source = remoteTar { source = remoteTar {
url = "https://mirrors.kernel.org/gnu/binutils/binutils-"+version+".tar.bz2"; url = "https://ftpmirror.gnu.org/gnu/binutils/binutils-"+version+".tar.bz2";
checksum = "VjbMg5KtZ6VSeNc77Z5p8RKg9eZ56g29ViKbbsF3tcFhZu0Yurg0nZt7UwB577LM"; checksum = "ihCVohBxX-URAR-YFDdVrL3inLYsEVX8KbbQmcbHaShHgqqmtsvUue1h3LXSjW-d";
compress = bzip2; compress = bzip2;
}; };
@@ -20,11 +20,11 @@ package gcc {
website = "https://www.gnu.org/software/gcc"; website = "https://www.gnu.org/software/gcc";
anitya = 6502; anitya = 6502;
version# = "16.2.0"; version# = "16.1.0";
source = remoteTar { source = remoteTar {
url = "https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"+ url = "https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"+
"gcc-"+version+"/gcc-"+version+".tar.gz"; "gcc-"+version+"/gcc-"+version+".tar.gz";
checksum = "yWDNSrcKa6yA5ucD4G-a5nCN99yPA8cRlxKgQlaaT-jM4pWYR6e1EvI2qbjUqXWZ"; checksum = "4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K";
compress = gzip; compress = gzip;
}; };
patches = [ patches = [
@@ -65,7 +65,7 @@ ln -s system/lib /work/
// This toolchain is hacked to pieces, it is not expected to ever 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 // well in its current state. That does not matter as long as the
// toolchain it produces passes its own test suite. // toolchain it produces passes its own test suite.
check = nil; skipCheck = true;
}; };
inputs = [ inputs = [
@@ -82,7 +82,6 @@ ln -s system/lib /work/
mpc, mpc,
zlib, zlib,
zstd,
libucontext, libucontext,
]; ];
} }
+3 -7
View File
@@ -12,6 +12,8 @@ package git {
}; };
early = ` early = `
ln -s ../../system/bin/perl /usr/bin/ || true
# test suite assumes apache # test suite assumes apache
rm -f /system/bin/httpd rm -f /system/bin/httpd
`; `;
@@ -20,10 +22,8 @@ rm -f /system/bin/httpd
enterSource = true; enterSource = true;
env = [ "NO_RUST=YesPlease" ]; env = [ "NO_RUST=YesPlease" ];
bin = [ "perl" ];
populateUsrBin = true;
exec = make { exec = make {
chdir = false; inPlace = true;
generate = "make configure"; generate = "make configure";
preMake = ` preMake = `
@@ -60,9 +60,6 @@ disable_test t1451-fsck-buffer
disable_test t4104-apply-boundary disable_test t4104-apply-boundary
disable_test t4200-rerere disable_test t4200-rerere
disable_test t5515-fetch-merge-logic disable_test t5515-fetch-merge-logic
disable_test t4124-apply-ws-rule
disable_test t3404-rebase-interactive
disable_test t7527-builtin-fsmonitor
`; `;
check = [ check = [
@@ -73,7 +70,6 @@ disable_test t7527-builtin-fsmonitor
install = `make \ install = `make \
` + jobsFlagE + ` \ ` + jobsFlagE + ` \
` + loadFlagE + ` \
DESTDIR=/work \ DESTDIR=/work \
NO_INSTALL_HARDLINKS=1 \ NO_INSTALL_HARDLINKS=1 \
install`; install`;
+3 -3
View File
@@ -3,11 +3,11 @@ package glib {
website = "https://developer.gnome.org/glib"; website = "https://developer.gnome.org/glib";
anitya = 10024; anitya = 10024;
version# = "2.89.3"; version# = "2.89.1";
source = remoteGit { source = remoteGit {
url = "https://gitlab.gnome.org/GNOME/glib.git"; url = "https://gitlab.gnome.org/GNOME/glib.git";
tag = version; tag = version;
checksum = "eM9KrXwhwKiZferwrILKmDeq-IGnSjr0EKqV90EEVl0Ee82QVcyVSf2LDMROHcOF"; checksum = "9_6Eew2KIwa1AHopjU7CqC13_nur5FPJMu-iGUd7sD_1gAM1pa_HVUuAtqExJoYU";
}; };
files = { files = {
@@ -17,7 +17,7 @@ package glib {
exec = meson { exec = meson {
setup = { setup = {
"default_library": "both"; "Ddefault_library": "both";
}; };
// fails with ipv6 disabled // fails with ipv6 disabled
skipTests = [ "gio" ]; skipTests = [ "gio" ];

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