Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fa145a1a0
|
||
|
|
b5a65d1255
|
||
|
|
ccdc0fa37e
|
||
|
|
b97518552d
|
||
|
|
67d14dc12c
|
||
|
|
695b1b4845
|
||
|
|
2e5d954f49
|
||
|
|
e6af0c405a
|
||
|
|
599a761b27
|
||
|
|
b7aa91f08f
|
||
|
|
280a736ce3
|
||
|
|
4e41b9bc99
|
||
|
|
153c980a61
|
||
|
|
a2f97f7e0f
|
||
|
|
5e1b4bb0b8
|
||
|
|
e73f9e0626
|
||
|
|
ddd90b780b
|
||
|
|
89c32f5614
|
||
|
|
1567a3e582
|
||
|
|
aa9952cd9e
|
||
|
|
99efc551ad
|
||
|
|
4dbfee0698
|
||
|
|
4e65e41101
|
||
|
|
b8306fe9e2
|
||
|
|
6b246e9036
|
||
|
|
869820ec6d
|
||
|
|
6fb2065a51
|
||
|
|
698fd2d66a
|
||
|
|
4cfbc93aa0
|
||
|
|
feec4b0d22
|
||
|
|
6487b41d92
|
||
|
|
7908fb9583
|
||
|
|
95aa7c205c
|
||
|
|
bd0cc3656f
|
||
|
|
0219240adb
|
||
|
|
aa4a15fc2c
|
||
|
|
0d3efeb456
|
||
|
|
35147f6dfb
|
||
|
|
e5abf51296
|
||
|
|
e26914cd6f
|
||
|
|
b647170d0c
|
||
|
|
5e655a0bf6
|
||
|
|
89eb3d27aa
|
||
|
|
3b7a22ff9b
|
||
|
|
6c2ca507b9
|
||
|
|
1a8212ee02
|
||
|
|
84bb2a5038
|
||
|
|
46b247f911
|
||
|
|
390f3b2dae
|
||
|
|
5d3e47d8e7
|
||
|
|
6f2852547b
|
||
|
|
3cff369368
|
||
|
|
09de939955
|
||
|
|
e0eec632d0
|
||
|
|
67dbb68818
|
||
|
|
0e689d9983
|
||
|
|
21a4067592
|
||
|
|
639766dfca
|
||
|
|
e4f025b9f1
|
||
|
|
1b65c8107c
|
||
|
|
1857ad8763
|
||
|
|
c822ff9aca
|
||
|
|
9df1609660
|
||
|
|
22e9e85a03
|
||
|
|
b79aa3ea1c
|
||
|
|
8d9b14dfe1
|
||
|
|
5770f957e5
|
||
|
|
e7903cf7e2
|
||
|
|
df199a8774
|
||
|
|
d906bc2ee0
|
||
|
|
e0e9910243
|
||
|
|
c8d54cebe9
|
||
|
|
74e7fb7818
|
||
|
|
8366cdd224
|
||
|
|
05f9939077
|
||
|
|
ae30f627dd
|
||
|
|
b4916dd431
|
||
|
|
4cf235675a
|
||
|
|
098943ab46
|
||
|
|
fb3df67ba6
|
||
|
|
b1c882b4de
|
||
|
|
0ed0d8abde
|
||
|
|
51e4426a4f
|
||
|
|
316edeb17b
|
||
|
|
8facae53c7
|
||
|
|
7881bfd027
|
||
|
|
9e9469fe6c
|
||
|
|
b6d90eb8e0
|
||
|
|
879f911fd8
|
||
|
|
1066fc0097
|
||
|
|
3a3d8efb1e
|
||
|
|
cb8c9e4e68
|
||
|
|
1c4a3b72bf
|
||
|
|
fdca05487c
|
||
|
|
89db730bb9
|
||
|
|
5161fc24ec
|
||
|
|
e1f16e7720
|
||
|
|
8e9b3a2ed1
|
||
|
|
fd0a81b304
|
||
|
|
1d6d89a11a
|
||
|
|
6a6fdab92d
|
||
|
|
67c67574e8
|
||
|
|
79be25433b
|
||
|
|
a4d78e8a32
|
||
|
|
ab3c37f75a
|
||
|
|
e6757fe254
|
||
|
|
b0f0d9e060
|
||
|
|
ce58895a0d
|
||
|
|
3c78551b24
|
||
|
|
223e8e56b3
|
||
|
|
17383ab353
|
||
|
|
237e793895
|
||
|
|
6cfd8fb934
|
||
|
|
2f1534853a
|
||
|
|
3f8e111d1c
|
||
|
|
9fae451dc0
|
||
|
|
e3666cda21
|
||
|
|
9c51805b47
|
||
|
|
3dca68fc95
|
||
|
|
6495118165
|
||
|
|
472849cfd6
|
||
|
|
3c6e9b3d05
|
||
|
|
aa5e77ef27
|
||
|
|
76360979f9
|
||
|
|
6d55ee536e
|
||
|
|
c8e8651694
|
||
|
|
aa5d38981d
|
||
|
|
b08feac26c
|
||
|
|
810b806a15
|
||
|
|
4a42657d88
|
||
|
|
f0b6659865
|
||
|
|
a8ffaa20e0
|
||
|
|
fb62ae00e4
|
||
|
|
512d9b95bd
|
||
|
|
5bf87561f5
|
||
|
|
dde69dde61
|
||
|
|
3ba6609444
|
||
|
|
6dcc2fdc17
|
||
|
|
c553b74807
|
||
|
|
8c853c3eb6
|
||
|
|
d2f322e911
|
||
|
|
b538c69e01
|
||
|
|
c921ba4680
|
||
|
|
7404bf6025
|
||
|
|
3975dd3e0f
|
||
|
|
3ab7116b29
|
||
|
|
9be165d6ee
|
||
|
|
1c55e7c772
|
||
|
|
a981d185cf
|
||
|
|
d91951ca97
|
||
|
|
09a2ffc3bc
|
||
|
|
a6444658da
|
||
|
|
ed5615033c
|
||
|
|
d1319a497c
|
||
|
|
cf7c34555c
|
||
|
|
d96eecded0
|
||
|
|
6863bcafd1
|
||
|
|
39f023d0e5
|
||
|
|
a8a2f692e7
|
||
|
|
19f24c7206
|
||
|
|
320432774a
|
||
|
|
0721b0fe6d
|
||
|
|
418e4a874d
|
||
|
|
8378e7a2c9
|
||
|
|
6210c9f272
|
||
|
|
c2038fa925
|
||
|
|
d797cca1f2
|
||
|
|
2a51b433c8
|
||
|
|
e5ce36532b
|
||
|
|
4c647388b0
|
||
|
|
3a5f4af114
|
||
|
|
6195260480
|
||
|
|
21044d5a60
|
||
|
|
025810bf0f
|
||
|
|
20354c0411
|
||
|
|
9fbcd0daf2
|
||
|
|
248f44a5a7
|
||
|
|
401dd57cbc
|
||
|
|
854bcc998b
|
||
|
|
358247be5b
|
||
|
|
f517a8ef07
|
||
|
|
973218f91f
|
||
|
|
0ea195837b
|
||
|
|
1348991634
|
||
|
|
14b445fde5
|
||
|
|
218f7fa345
|
||
|
|
cd493fd95f
|
||
|
|
9db70c83e3
|
||
|
|
4e09241e5f
|
||
|
|
bd4b300ea6
|
||
|
|
6dc8214a1a
|
||
|
|
cada5a46ad
|
||
|
|
e747942829
|
||
|
|
33b855123e
|
||
|
|
58ce134718
|
||
|
|
2066093343
|
||
|
|
07509b3ba2
|
||
|
|
a7485d587a
|
||
|
|
4892beefc1
|
||
|
|
7ab54b8c94
|
||
|
|
a4fab67811
|
||
|
|
ed5cdd38a4
|
||
|
|
f6318304ee
|
||
|
|
cb618093d5
|
||
|
|
b0b2471c0c
|
||
|
|
344d2b8207
|
||
|
|
3938e8bce5
|
||
|
|
aee15b4f2a
|
||
|
|
18b1103fdc
|
||
|
|
c5a02da0f0
|
||
|
|
c0c2f3233a
|
||
|
|
bda00ac90e
|
@@ -0,0 +1 @@
|
||||
*.az linguist-language=Azalea
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build for release
|
||||
run: nix build --print-out-paths --print-build-logs .#dist
|
||||
run: nix build --print-out-paths --print-build-logs ./test#dist
|
||||
|
||||
- name: Release
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.hakurei
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.hakurei
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.race
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.race
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox-race
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox-race
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sharefs
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sharefs
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run checks
|
||||
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check
|
||||
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check ./test
|
||||
|
||||
dist:
|
||||
name: Create distribution
|
||||
@@ -116,9 +116,9 @@ jobs:
|
||||
id: build-test
|
||||
run: >-
|
||||
export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
|
||||
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
|
||||
nix build --print-out-paths --print-build-logs .#dist &&
|
||||
mv package.nix.old package.nix &&
|
||||
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' test/package.nix &&
|
||||
nix build --print-out-paths --print-build-logs ./test#dist &&
|
||||
mv test/{package.nix.old,package.nix} &&
|
||||
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload test build
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# produced by tools and text editors
|
||||
*.swp
|
||||
*.qcow2
|
||||
*.test
|
||||
*.out
|
||||
|
||||
@@ -57,9 +57,4 @@ package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
|
||||
- [fuse](https://github.com/libfuse/libfuse) to implement the filesystem.
|
||||
|
||||
New dependencies will generally not be added. Patches adding new dependencies
|
||||
are very likely to be rejected.
|
||||
|
||||
## NixOS Module (deprecated)
|
||||
|
||||
The NixOS module is in maintenance mode and will be removed once planterette is
|
||||
feature-complete. Full module documentation can be found [here](options.md).
|
||||
are very likely to be rejected.
|
||||
+110
-20
@@ -4,10 +4,12 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/ext"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
@@ -31,10 +33,19 @@ func parsePair(s string) (source, target *check.Absolute, err error) {
|
||||
|
||||
// parse decodes a high-level configuration stream and returns its
|
||||
// corresponding [hst.Config].
|
||||
func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
func parse(
|
||||
id string,
|
||||
base *check.Absolute,
|
||||
r io.Reader,
|
||||
templateP *string,
|
||||
) (*hst.Config, error) {
|
||||
shell := fhs.AbsRoot.Append("bin", "zsh")
|
||||
home := hst.AbsPrivateTmp.Append("home")
|
||||
|
||||
root := hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{base.Append("initial")},
|
||||
}
|
||||
c := hst.Config{
|
||||
ID: id,
|
||||
Enablements: new(hst.Enablements),
|
||||
@@ -51,13 +62,7 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
Container: &hst.ContainerConfig{
|
||||
Env: make(map[string]string),
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{
|
||||
base.Append("template", "initial"),
|
||||
},
|
||||
Upper: base.Append("template", "upper"),
|
||||
}},
|
||||
{FilesystemConfig: &root},
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Target: home,
|
||||
Source: base.Append("state", id),
|
||||
@@ -70,12 +75,6 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
Write: true,
|
||||
Perm: 01777,
|
||||
}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
|
||||
},
|
||||
|
||||
Username: "chronos",
|
||||
@@ -102,21 +101,28 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
if err := scanOnce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, err := strconv.Atoi(s.Text()); err != nil {
|
||||
if template, identity, ok := strings.Cut(s.Text(), ":"); !ok {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
} else if v, err := strconv.Atoi(identity); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if templateP != nil {
|
||||
*templateP = template
|
||||
}
|
||||
c.Identity = v
|
||||
root.Upper = base.Append("template", template)
|
||||
}
|
||||
|
||||
if err := scanOnce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Args = append(c.Container.Args, s.Text())
|
||||
c.Container.Args = append(c.Container.Args, s.Text(), "")
|
||||
|
||||
var flagGPU, flagSystemBus bool
|
||||
var flagInteractive, flagGPU, flagSystemBus bool
|
||||
flags := map[string]*bool{
|
||||
"gpu": &flagGPU,
|
||||
"system_bus": &flagSystemBus,
|
||||
"interactive": &flagInteractive,
|
||||
"gpu": &flagGPU,
|
||||
"system_bus": &flagSystemBus,
|
||||
}
|
||||
|
||||
for s.Scan() {
|
||||
@@ -176,10 +182,43 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "username":
|
||||
c.Container.Username = value
|
||||
continue
|
||||
|
||||
case "hostname":
|
||||
c.Container.Hostname = value
|
||||
continue
|
||||
|
||||
case "group":
|
||||
c.Groups = append(c.Groups, value)
|
||||
continue
|
||||
|
||||
case "sched_policy":
|
||||
if err := c.SchedPolicy.UnmarshalText([]byte(value)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
|
||||
case "sched_priority":
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.SchedPriority = ext.Int(v)
|
||||
continue
|
||||
|
||||
case "insecure":
|
||||
switch value {
|
||||
case "pipewire":
|
||||
*c.Enablements |= hst.EPipeWire
|
||||
c.DirectPipeWire = true
|
||||
continue
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid insecure flag %q", value)
|
||||
}
|
||||
|
||||
case "env":
|
||||
if key, value, ok = strings.Cut(value, "="); !ok {
|
||||
return nil, fmt.Errorf("invalid environment %q", key)
|
||||
@@ -200,6 +239,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
)
|
||||
continue
|
||||
|
||||
case "ro+":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
||||
Target: target,
|
||||
Source: source,
|
||||
Optional: true,
|
||||
}},
|
||||
)
|
||||
continue
|
||||
|
||||
case "rw":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
@@ -214,6 +267,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
)
|
||||
continue
|
||||
|
||||
case "dev":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
||||
Target: target,
|
||||
Source: source,
|
||||
Device: true,
|
||||
}},
|
||||
)
|
||||
continue
|
||||
|
||||
case "own":
|
||||
c.SessionBus.Own = append(c.SessionBus.Own, value)
|
||||
continue
|
||||
@@ -236,6 +303,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flagInteractive {
|
||||
c.Container.Args[1] += "i"
|
||||
}
|
||||
|
||||
if flagGPU {
|
||||
c.Container.Filesystem = append(c.Container.Filesystem, []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
@@ -250,7 +321,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
c.SystemBus = nil
|
||||
}
|
||||
|
||||
if c.Container.Flags&hst.FShareTmpdir == 0 {
|
||||
if c.Container.Flags&hst.FShareTmpdir == 0 &&
|
||||
(c.Enablements.Unwrap()&hst.EX11 == 0 ||
|
||||
c.Container.Flags&(hst.FHostNet|hst.FHostAbstract) ==
|
||||
hst.FHostNet|hst.FHostAbstract) {
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
@@ -262,3 +336,19 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// list prints names of non-hidden entries in pathname.
|
||||
func list(pathname *check.Absolute, dir bool) error {
|
||||
dents, err := os.ReadDir(pathname.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
if (dent.IsDir() != dir) || (len(name) > 0 && name[0] == '.') {
|
||||
continue
|
||||
}
|
||||
fmt.Println(dent.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+5
-9
@@ -20,7 +20,7 @@ func TestParse(t *testing.T) {
|
||||
want *hst.Config
|
||||
err error
|
||||
}{
|
||||
{"com.discordapp.Discord", `8
|
||||
{"com.discordapp.Discord", `nonfree:8
|
||||
exec Discord --ozone-platform-hint=wayland
|
||||
|
||||
gpu
|
||||
@@ -74,9 +74,9 @@ talk com.canonical.Unity
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{
|
||||
base.Append("template", "initial"),
|
||||
base.Append("initial"),
|
||||
},
|
||||
Upper: base.Append("template", "upper"),
|
||||
Upper: base.Append("template", "nonfree"),
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Target: hst.AbsPrivateTmp.Append("home"),
|
||||
@@ -91,12 +91,6 @@ talk com.canonical.Unity
|
||||
Perm: 01777,
|
||||
}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Source: check.MustAbs("/sdcard"),
|
||||
Write: true,
|
||||
@@ -120,6 +114,7 @@ talk com.canonical.Unity
|
||||
Args: []string{
|
||||
"zsh", "-c",
|
||||
"exec Discord --ozone-platform-hint=wayland",
|
||||
"",
|
||||
},
|
||||
|
||||
Flags: hst.FCoverRun | hst.FUserns | hst.FHostNet | hst.FMapRealUID |
|
||||
@@ -135,6 +130,7 @@ talk com.canonical.Unity
|
||||
tc.name,
|
||||
base,
|
||||
strings.NewReader(tc.data),
|
||||
nil,
|
||||
)
|
||||
|
||||
if !reflect.DeepEqual(err, tc.err) {
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/lockedfile"
|
||||
"hakurei.app/internal/outcome"
|
||||
)
|
||||
|
||||
// MutationConflictError describes an active mutable instance.
|
||||
type MutationConflictError string
|
||||
|
||||
func (e MutationConflictError) Error() string {
|
||||
return "mutable instance active at " + string(e)
|
||||
}
|
||||
|
||||
// informTemplate guards intention of a template or its derivatives.
|
||||
func informTemplate(base *check.Absolute, name string, mutable bool) (func() error, error) {
|
||||
mu := lockedfile.MutexAt(base.Append("lock", name).String())
|
||||
if unlock, err := mu.Lock(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
defer unlock()
|
||||
}
|
||||
|
||||
marker := base.Append("lock", "."+name)
|
||||
if p, err := os.ReadFile(marker.String()); err == nil {
|
||||
if _, err = os.Stat(fhs.AbsProc.Append(string(p)).String()); err == nil {
|
||||
return nil, MutationConflictError(p)
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("removing stale marker by %s", string(p))
|
||||
if err = os.Remove(marker.String()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !mutable {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var active []hst.ID
|
||||
var sc hst.Paths
|
||||
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||
entries, copyError := outcome.NewStore(&sc).All()
|
||||
var s hst.State
|
||||
for eh := range entries {
|
||||
s = hst.State{}
|
||||
if _, err := eh.Load(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.Validate(0) != nil || len(s.Container.Filesystem) < 1 {
|
||||
continue
|
||||
}
|
||||
root, ok := s.Container.Filesystem[0].FilesystemConfig.(*hst.FSOverlay)
|
||||
if !ok || root == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !root.Target.Is(fhs.AbsRoot) ||
|
||||
len(root.Lower) != 1 ||
|
||||
!root.Lower[0].Is(base.Append("initial")) ||
|
||||
!root.Upper.Is(base.Append("template", name)) ||
|
||||
root.Work != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
active = append(active, s.ID)
|
||||
}
|
||||
if err := copyError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(active) != 0 {
|
||||
var buf strings.Builder
|
||||
buf.WriteString("derivative instances still active:")
|
||||
for _, id := range active {
|
||||
buf.WriteString("\n\t")
|
||||
buf.WriteString(id.String())
|
||||
}
|
||||
return nil, errors.New(buf.String())
|
||||
}
|
||||
|
||||
return func() error { return os.RemoveAll(marker.String()) }, os.WriteFile(
|
||||
marker.String(),
|
||||
[]byte(strconv.Itoa(os.Getpid())),
|
||||
0400,
|
||||
)
|
||||
}
|
||||
|
||||
// acquireTemplate obtains exclusivity of a template.
|
||||
func acquireTemplate(base *check.Absolute, name string) (remove func() error, err error) {
|
||||
return informTemplate(base, name, true)
|
||||
}
|
||||
|
||||
// enterTemplate checks against exclusivity of a template.
|
||||
func enterTemplate(base *check.Absolute, name string) error {
|
||||
_, err := informTemplate(base, name, false)
|
||||
return err
|
||||
}
|
||||
+92
-36
@@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -31,10 +32,11 @@ func main() {
|
||||
defer stop()
|
||||
|
||||
var (
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
flagInsecure bool
|
||||
|
||||
base, template, initial, upper, work *check.Absolute
|
||||
base, template, initial *check.Absolute
|
||||
)
|
||||
c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) {
|
||||
msg.SwapVerbose(flagVerbose)
|
||||
@@ -49,9 +51,7 @@ func main() {
|
||||
}
|
||||
|
||||
template = base.Append("template")
|
||||
initial = template.Append("initial")
|
||||
upper = template.Append("upper")
|
||||
work = template.Append("work")
|
||||
initial = base.Append("initial")
|
||||
return
|
||||
}).Flag(
|
||||
&flagVerbose,
|
||||
@@ -59,8 +59,12 @@ func main() {
|
||||
"Increase log verbosity",
|
||||
).Flag(
|
||||
&flagBase,
|
||||
"d", command.StringFlag("$HAKUREI_APP_PATH"),
|
||||
"d", command.StringFlag("$ROSA_APP_PATH"),
|
||||
"Configuration and state directory",
|
||||
).Flag(
|
||||
&flagInsecure,
|
||||
"insecure", command.BoolFlag(false),
|
||||
"Allow use of insecure compatibility options",
|
||||
)
|
||||
|
||||
{
|
||||
@@ -70,17 +74,21 @@ func main() {
|
||||
)
|
||||
c.NewCommand(
|
||||
"enter", "Enter mutable state template",
|
||||
func([]string) error {
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return list(template, true)
|
||||
}
|
||||
|
||||
config := hst.Config{
|
||||
ID: "app.hakurei.mutable",
|
||||
ID: "app.hakurei.mutable." + args[0],
|
||||
Container: &hst.ContainerConfig{
|
||||
Hostname: "mutable",
|
||||
Hostname: args[0] + "-mutable",
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{initial},
|
||||
Upper: upper,
|
||||
Work: work,
|
||||
Upper: template.Append(args[0]),
|
||||
Work: base.Append("work", args[0]),
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
@@ -89,7 +97,8 @@ func main() {
|
||||
}},
|
||||
},
|
||||
Username: "chronos",
|
||||
Flags: hst.FMultiarch |
|
||||
Flags: hst.FNoPlace |
|
||||
hst.FMultiarch |
|
||||
hst.FDevel |
|
||||
hst.FUserns |
|
||||
hst.FHostNet |
|
||||
@@ -113,7 +122,12 @@ func main() {
|
||||
config.Container.Home = a
|
||||
}
|
||||
|
||||
return run(ctx, msg, &config)
|
||||
remove, err := acquireTemplate(base, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = run(ctx, msg, false, &config)
|
||||
return errors.Join(err, remove())
|
||||
},
|
||||
).Flag(
|
||||
&flagShell,
|
||||
@@ -126,29 +140,65 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"run", "Start the named application",
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("run requires 1 argument")
|
||||
}
|
||||
{
|
||||
var (
|
||||
flagCommand string
|
||||
)
|
||||
c.NewCommand(
|
||||
"run", "Start the named application",
|
||||
func(args []string) error {
|
||||
if len(args) < 1 {
|
||||
return list(base.Append("app"), false)
|
||||
}
|
||||
|
||||
var config *hst.Config
|
||||
f, err := os.Open(base.Append("app", args[0]).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config, err = parse(args[0], base, f)
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var config *hst.Config
|
||||
var r io.Reader
|
||||
f, err := os.Open(base.Append("app", args[0]).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = f
|
||||
|
||||
return run(ctx, msg, config)
|
||||
},
|
||||
)
|
||||
var common *os.File
|
||||
if common, err = os.Open(base.Append("common").String()); err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
r = io.MultiReader(f, common)
|
||||
}
|
||||
|
||||
var name string
|
||||
config, err = parse(args[0], base, r, &name)
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
if common != nil {
|
||||
if closeErr := common.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if flagCommand != "" {
|
||||
config.Container.Args[2] = flagCommand
|
||||
}
|
||||
|
||||
if err = enterTemplate(base, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return run(ctx, msg, flagInsecure, config, args[1:]...)
|
||||
},
|
||||
).
|
||||
Flag(
|
||||
&flagCommand,
|
||||
"command", command.StringFlag(""),
|
||||
"Override configured command",
|
||||
)
|
||||
}
|
||||
|
||||
c.MustParse(os.Args[1:], func(err error) {
|
||||
if e, ok := errors.AsType[*exec.ExitError](err); ok && e != nil {
|
||||
@@ -156,7 +206,13 @@ func main() {
|
||||
}
|
||||
|
||||
if w, ok := err.(interface{ Unwrap() []error }); !ok {
|
||||
log.Fatal(err)
|
||||
var m string
|
||||
m, ok = message.GetMessage(err)
|
||||
if !ok {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
log.Fatal(m)
|
||||
} else {
|
||||
errs := w.Unwrap()
|
||||
for i, e := range errs {
|
||||
|
||||
+11
-1
@@ -12,7 +12,13 @@ import (
|
||||
)
|
||||
|
||||
// run starts a container via cmd/hakurei and returns after it terminates.
|
||||
func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
func run(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
insecure bool,
|
||||
config *hst.Config,
|
||||
args ...string,
|
||||
) error {
|
||||
c, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -24,7 +30,11 @@ func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
if msg.IsVerbose() {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
}
|
||||
if insecure {
|
||||
cmd.Args = append(cmd.Args, "--insecure")
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "run", "3")
|
||||
cmd.Args = append(cmd.Args, args...)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
v0.4.4
|
||||
v0.4.5
|
||||
|
||||
Vendored
+25
-10
@@ -35,8 +35,11 @@ func getenv(key, fallback string) string {
|
||||
|
||||
// mustRun runs a command with the current process's environment and panics
|
||||
// on error or non-zero exit code.
|
||||
func mustRun(ctx context.Context, name string, arg ...string) {
|
||||
func mustRun(ctx context.Context, env []string, name string, arg ...string) {
|
||||
cmd := exec.CommandContext(ctx, name, arg...)
|
||||
if env != nil {
|
||||
cmd.Env = append(cmd.Environ(), env...)
|
||||
}
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
panic(err)
|
||||
@@ -49,11 +52,12 @@ var comp []byte
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("")
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
verbose := os.Getenv("VERBOSE") != ""
|
||||
runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
|
||||
version = getenv("HAKUREI_VERSION", strings.TrimSpace(version))
|
||||
prefix := getenv("PREFIX", "/usr")
|
||||
prefix := getenv("PREFIX", "/usr/local")
|
||||
destdir := getenv("DESTDIR", "dist")
|
||||
|
||||
if verbose {
|
||||
@@ -91,26 +95,37 @@ func main() {
|
||||
verboseFlag = "-buildvcs=false"
|
||||
}
|
||||
|
||||
log.Printf("Building hakurei for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(ctx, "go", "generate", "./...")
|
||||
log.Printf("Building hakurei %s for %s/%s.", version, runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(ctx, nil, "go", "generate", "./...")
|
||||
mustRun(
|
||||
ctx, "go", "build",
|
||||
ctx, nil, "go", "build",
|
||||
"-trimpath",
|
||||
verboseFlag, "-o", s,
|
||||
"-ldflags=-s -w "+
|
||||
"-buildid= -linkmode external -extldflags=-static "+
|
||||
"-X hakurei.app/internal/info.buildVersion="+version+" "+
|
||||
"-X hakurei.app/internal/info.hakureiPath="+prefix+"/bin/hakurei "+
|
||||
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu "+
|
||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||
"./...",
|
||||
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu",
|
||||
"./cmd/hakurei",
|
||||
"./cmd/sharefs",
|
||||
)
|
||||
log.Println()
|
||||
|
||||
log.Printf("Building cmd/hsu for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(
|
||||
ctx, []string{"CGO_ENABLED=0"}, "go", "build",
|
||||
"-trimpath",
|
||||
verboseFlag, "-o", s,
|
||||
"-ldflags=-s -w "+
|
||||
"-buildid= "+
|
||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||
"./cmd/hsu",
|
||||
)
|
||||
|
||||
log.Println()
|
||||
if runTests {
|
||||
log.Println("##### Testing Hakurei.")
|
||||
mustRun(
|
||||
ctx, "go", "test",
|
||||
ctx, nil, "go", "test",
|
||||
"-ldflags=-buildid= -linkmode external -extldflags=-static",
|
||||
"./...",
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -51,13 +52,14 @@ func init() {
|
||||
func fatal(v ...any) {
|
||||
log.Println(v...)
|
||||
log.Println("unable to continue, please reboot and resolve the problem manually")
|
||||
log.SetOutput(io.Discard)
|
||||
select {}
|
||||
}
|
||||
|
||||
// must calls fatal with err if it is non-nil.
|
||||
func must(err error) {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
fatal(err)
|
||||
select {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,9 @@ var _ report.RepresentableError = ModprobeError{}
|
||||
func (ModprobeError) Representable() {}
|
||||
func (e ModprobeError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"modprobe exit status %d: %s",
|
||||
e.ExitCode, strings.TrimSpace(e.Stderr),
|
||||
"%s (exit status %d)",
|
||||
strings.TrimPrefix(strings.TrimSpace(e.Stderr), "modprobe: "),
|
||||
e.ExitCode,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestPrintShowInstance(t *testing.T) {
|
||||
Identity: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pipewire
|
||||
Groups: video, dialout, plugdev
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
@@ -161,7 +161,7 @@ App
|
||||
Identity: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pipewire
|
||||
Groups: video, dialout, plugdev
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
@@ -354,6 +354,7 @@ App
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
@@ -506,6 +507,7 @@ App
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
@@ -705,6 +707,7 @@ func TestPrintPs(t *testing.T) {
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
|
||||
+61
-9
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/check"
|
||||
@@ -21,41 +22,66 @@ type cache struct {
|
||||
// Should generally not be used directly.
|
||||
c *pkg.Cache
|
||||
|
||||
cures, jobs int
|
||||
attr pkg.CacheAttr
|
||||
// Primarily to work around missing landlock LSM.
|
||||
hostAbstract bool
|
||||
// Set SCHED_IDLE.
|
||||
idle bool
|
||||
// Unset [pkg.CSuppressInit].
|
||||
verboseInit bool
|
||||
// Whether to enable output colours.
|
||||
color bool
|
||||
// Unset [pkg.CExternShallow].
|
||||
deep bool
|
||||
// Loaded artifact of [rosa.QEMU].
|
||||
qemu pkg.Artifact
|
||||
|
||||
base, mirror string
|
||||
}
|
||||
|
||||
// writeTitle sets title of the terminal connected to [message.Msg].
|
||||
func writeTitle(msg message.Msg, s string) {
|
||||
msg.Suspend()
|
||||
w := msg.GetLogger().Writer()
|
||||
_, _ = w.Write([]byte("\x1b]0;" + s + "\a"))
|
||||
msg.Resume()
|
||||
}
|
||||
|
||||
// open opens the underlying [pkg.Cache].
|
||||
func (cache *cache) open() (err error) {
|
||||
if cache.c != nil {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
var hostname string
|
||||
if hostname, err = os.Hostname(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var base *check.Absolute
|
||||
if cache.base, err = filepath.Abs(cache.base); err != nil {
|
||||
return
|
||||
} else if base, err = check.NewAbs(cache.base); err != nil {
|
||||
return
|
||||
}
|
||||
var notify chan bool
|
||||
|
||||
var flags int
|
||||
if cache.idle {
|
||||
flags |= pkg.CSchedIdle
|
||||
cache.attr.Flags |= pkg.CSchedIdle
|
||||
}
|
||||
if cache.hostAbstract {
|
||||
flags |= pkg.CHostAbstract
|
||||
cache.attr.Flags |= pkg.CHostAbstract
|
||||
}
|
||||
if !cache.verboseInit {
|
||||
flags |= pkg.CSuppressInit
|
||||
cache.attr.Flags |= pkg.CSuppressInit
|
||||
}
|
||||
if !cache.deep {
|
||||
cache.attr.Flags |= pkg.CExternShallow
|
||||
}
|
||||
if cache.color {
|
||||
cache.attr.Flags |= pkg.CColourOutput
|
||||
notify = make(chan bool, 1<<12)
|
||||
cache.attr.Notify = notify
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
@@ -77,10 +103,8 @@ func (cache *cache) open() (err error) {
|
||||
cache.c, err = pkg.Open(
|
||||
cache.ctx,
|
||||
cache.msg,
|
||||
flags,
|
||||
cache.cures,
|
||||
cache.jobs,
|
||||
base,
|
||||
&cache.attr,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -95,13 +119,36 @@ func (cache *cache) open() (err error) {
|
||||
return
|
||||
}
|
||||
var r rosa.Remote
|
||||
if r, err = rosa.NewRemote(cache.mirror, pub, http.DefaultClient); err != nil {
|
||||
if r, err = rosa.NewRemote(http.DefaultClient, cache.mirror, pub); err != nil {
|
||||
cache.c.Close()
|
||||
return err
|
||||
}
|
||||
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 {
|
||||
n++
|
||||
nc++
|
||||
} else {
|
||||
nc--
|
||||
}
|
||||
|
||||
writeTitle(cache.msg, prefix+
|
||||
"("+strconv.FormatUint(nc, 10)+
|
||||
" of "+strconv.FormatUint(n, 10)+")")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if cache.qemu != nil {
|
||||
var pathname *check.Absolute
|
||||
pathname, _, err = cache.c.Cure(cache.qemu)
|
||||
@@ -122,6 +169,11 @@ func (cache *cache) open() (err error) {
|
||||
func (cache *cache) Close() {
|
||||
if cache.c != nil {
|
||||
cache.c.Close()
|
||||
if cache.attr.Notify != nil {
|
||||
cache.msg.Suspend()
|
||||
_, _ = cache.msg.GetLogger().Writer().Write([]byte("\x1b[23;0t"))
|
||||
cache.msg.Resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ func TestNoReply(t *testing.T) {
|
||||
c, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(log.New(os.Stderr, "cir: ", 0)),
|
||||
0, 0, 0,
|
||||
check.MustAbs(t.TempDir()),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
@@ -63,7 +63,7 @@ func TestNoReply(t *testing.T) {
|
||||
}
|
||||
|
||||
<-done
|
||||
wantIdent := pkg.MustDecode("fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG")
|
||||
wantIdent := pkg.MustDecode("bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32")
|
||||
if gotIdent := c.Ident(a).Value(); gotIdent != wantIdent {
|
||||
t.Errorf(
|
||||
"cureFromIR: %s, want %s",
|
||||
@@ -124,7 +124,7 @@ func TestDaemon(t *testing.T) {
|
||||
cancel()
|
||||
<-done
|
||||
|
||||
const want = "fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG"
|
||||
const want = "bpVsJ69hdKPBntMh_u777g7-quFNVmMlBJQOlM_thiQa9JnOFLAbe5OlR4zNjZ32"
|
||||
if got := filepath.Base(p.String()); got != want {
|
||||
t.Errorf("cureRemote: %s, want %s", got, want)
|
||||
}
|
||||
@@ -132,8 +132,8 @@ func TestDaemon(t *testing.T) {
|
||||
wantLog := []string{
|
||||
"",
|
||||
"daemon: aborting all pending cures",
|
||||
"daemon: attempting to cancel invalid artifact kQm9fmnCmXST1-MMmxzcau2oKZCXXrlZydo4PkeV5hO_2PKfeC8t98hrbV_ZZx_j",
|
||||
"daemon: fulfilled artifact fiZf-ZY_Yq6qxJNrHbMiIPYCsGkUiKCRsZrcSELXTqZWtCnESlHmzV5ThhWWGGYG",
|
||||
"daemon: attempting to cancel invalid artifact 58Vy_5beLZCvZX__KzRKyIE6vATleaZP1ZBxbqoWnekz9aZ1zkxNgcIUFI5V1_Jf",
|
||||
"daemon: fulfilled artifact " + want,
|
||||
}
|
||||
gotLog := strings.Split(buf.String(), "\n")
|
||||
slices.Sort(gotLog)
|
||||
|
||||
+4
-1
@@ -21,7 +21,10 @@ func commandInfo(
|
||||
r *rosa.Report,
|
||||
) (err error) {
|
||||
if len(args) == 0 {
|
||||
return errors.New("info requires at least 1 argument")
|
||||
for _, h := range rosa.Native().CollectAll() {
|
||||
fmt.Println(h)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// recovered by HandleAccess
|
||||
|
||||
+210
-40
@@ -27,6 +27,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@@ -91,6 +92,11 @@ func main() {
|
||||
|
||||
var cm cache
|
||||
defer func() { cm.Close() }()
|
||||
if cm.color = ext.Isatty(syscall.Stderr) &&
|
||||
os.Getenv("NO_COLOR") == "" &&
|
||||
os.Getenv("TERM") != "dumb"; cm.color {
|
||||
log.SetPrefix("\x1b[2mmbf: \x1b[0m")
|
||||
}
|
||||
|
||||
var (
|
||||
flagQuiet bool
|
||||
@@ -202,13 +208,17 @@ func main() {
|
||||
"v", command.BoolFlag(false),
|
||||
"Do not suppress verbose output from init",
|
||||
).Flag(
|
||||
&cm.cures,
|
||||
&cm.attr.Cures,
|
||||
"cures", command.IntFlag(0),
|
||||
"Maximum number of dependencies to cure at any given time",
|
||||
).Flag(
|
||||
&cm.jobs,
|
||||
&cm.attr.Jobs,
|
||||
"jobs", command.IntFlag(0),
|
||||
"Preferred number of jobs to run, when applicable",
|
||||
).Flag(
|
||||
&cm.attr.Load,
|
||||
"load-average", command.IntFlag(0),
|
||||
"Preferred load average number, when applicable",
|
||||
).Flag(
|
||||
&cm.base,
|
||||
"d", command.StringFlag("$MBF_CACHE_DIR"),
|
||||
@@ -217,6 +227,11 @@ func main() {
|
||||
&cm.mirror,
|
||||
"r", command.StringFlag("$MBF_REMOTE"),
|
||||
"URL of mirror service",
|
||||
).Flag(
|
||||
&cm.deep,
|
||||
"deep", command.BoolFlag(false),
|
||||
"Cure all inputs even when the required artifact is available "+
|
||||
"via the mirror service",
|
||||
).Flag(
|
||||
&cm.idle,
|
||||
"sched-idle", command.BoolFlag(false),
|
||||
@@ -268,7 +283,7 @@ func main() {
|
||||
if _, err := io.Copy(h, os.Stdin); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println(pkg.Encode(pkg.Checksum(h.Sum(nil))))
|
||||
fmt.Println(pkg.Encode(pkg.Checksum(h.Sum(nil))))
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -539,7 +554,9 @@ func main() {
|
||||
if base, err := os.OpenRoot(cm.base); err != nil {
|
||||
return err
|
||||
} else {
|
||||
h = rosa.NewMirror(msg, base.FS(), key)
|
||||
var mux http.ServeMux
|
||||
rosa.NewMirror(msg, base.FS(), key).Register(&mux)
|
||||
h = &mux
|
||||
}
|
||||
|
||||
server := http.Server{Addr: args[0], Handler: h}
|
||||
@@ -561,28 +578,52 @@ 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(
|
||||
"stage3",
|
||||
"stage4",
|
||||
"Check for toolchain 3-stage non-determinism",
|
||||
func(args []string) (err error) {
|
||||
s := rosa.Std
|
||||
if flagGentoo != "" {
|
||||
s -= 3 // magic number to discourage misuse
|
||||
|
||||
var checksum pkg.Checksum
|
||||
if len(flagChecksum) != 0 {
|
||||
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
rosa.Native().SetGentooStage3(flagGentoo, checksum)
|
||||
}
|
||||
|
||||
var (
|
||||
pathname *check.Absolute
|
||||
checksum [2]unique.Handle[pkg.Checksum]
|
||||
@@ -590,7 +631,7 @@ func main() {
|
||||
|
||||
_llvm := rosa.H("llvm")
|
||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
_, llvm := rosa.Native().New(s - 2).Load(_llvm)
|
||||
_, llvm := rosa.Native().New(rosa.Std - 2).Load(_llvm)
|
||||
pathname, _, err = cache.Cure(llvm)
|
||||
return
|
||||
}); err != nil {
|
||||
@@ -599,22 +640,32 @@ func main() {
|
||||
log.Println("stage1:", pathname)
|
||||
|
||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
_, llvm := rosa.Native().New(s - 1).Load(_llvm)
|
||||
pathname, checksum[0], err = cache.Cure(llvm)
|
||||
_, llvm := rosa.Native().New(rosa.Std - 1).Load(_llvm)
|
||||
pathname, _, err = cache.Cure(llvm)
|
||||
return
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
log.Println("stage2:", pathname)
|
||||
|
||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
_, llvm := rosa.Native().New(s).Load(_llvm)
|
||||
pathname, checksum[1], err = cache.Cure(llvm)
|
||||
_, llvm := rosa.Native().New(rosa.Std).Load(_llvm)
|
||||
pathname, checksum[0], err = cache.Cure(llvm)
|
||||
return
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
log.Println("stage3:", pathname)
|
||||
|
||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
_, llvm := rosa.Native().New(rosa.Stage3).Load(_llvm)
|
||||
pathname, checksum[1], err = cache.Cure(llvm)
|
||||
return
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
log.Println("stage4:", pathname)
|
||||
|
||||
if checksum[0] != checksum[1] {
|
||||
err = &pkg.ChecksumMismatchError{
|
||||
Got: checksum[0].Value(),
|
||||
@@ -622,23 +673,34 @@ func main() {
|
||||
}
|
||||
} else {
|
||||
log.Println(
|
||||
"stage2 is identical to stage3",
|
||||
"stage3 is identical to stage4",
|
||||
"("+pkg.Encode(checksum[0].Value())+")",
|
||||
)
|
||||
}
|
||||
return
|
||||
},
|
||||
).Flag(
|
||||
&flagGentoo,
|
||||
"gentoo", command.StringFlag(""),
|
||||
"Bootstrap from a Gentoo stage3 tarball",
|
||||
).Flag(
|
||||
&flagChecksum,
|
||||
"checksum", command.StringFlag(""),
|
||||
"Checksum of Gentoo stage3 tarball",
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"all",
|
||||
command.UsageInternal,
|
||||
func([]string) error {
|
||||
all := rosa.Native().CollectAll()
|
||||
a := make(pkg.Collect, len(all))
|
||||
for i, h := range all {
|
||||
_, a[i] = rosa.Native().Std().Load(h)
|
||||
}
|
||||
return cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
_, _, err = cache.Cure(&a)
|
||||
if pkg.IsCollected(err) {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
{
|
||||
var (
|
||||
flagDump string
|
||||
@@ -648,9 +710,13 @@ func main() {
|
||||
flagNoReply bool
|
||||
flagFaults bool
|
||||
flagPop bool
|
||||
flagRebuild bool
|
||||
|
||||
flagBoot bool
|
||||
flagStd bool
|
||||
|
||||
flagGentoo string
|
||||
flagChecksum string
|
||||
)
|
||||
c.NewCommand(
|
||||
"cure",
|
||||
@@ -667,6 +733,18 @@ func main() {
|
||||
t -= 1
|
||||
}
|
||||
|
||||
if flagGentoo != "" {
|
||||
var checksum pkg.Checksum
|
||||
if len(flagChecksum) != 0 {
|
||||
if err := pkg.Decode(&checksum, flagChecksum); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
rosa.Native().SetGentooStage3(flagGentoo, checksum)
|
||||
|
||||
t -= 3 // magic number to discourage misuse
|
||||
}
|
||||
|
||||
_, a := rosa.Native().New(t).Load(rosa.ArtifactH(unique.Make(args[0])))
|
||||
if a == nil {
|
||||
return fmt.Errorf("unknown artifact %q", args[0])
|
||||
@@ -676,13 +754,17 @@ func main() {
|
||||
default:
|
||||
var pathname *check.Absolute
|
||||
err := cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
pathname, _, err = cache.Cure(a)
|
||||
if flagRebuild {
|
||||
pathname, _, err = cache.CureNew(a)
|
||||
} else {
|
||||
pathname, _, err = cache.Cure(a)
|
||||
}
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println(pathname)
|
||||
fmt.Println(pathname)
|
||||
|
||||
if flagExport != "" {
|
||||
msg.Verbosef("exporting %s to %s...", args[0], flagExport)
|
||||
@@ -731,7 +813,7 @@ func main() {
|
||||
ctx,
|
||||
a,
|
||||
"", true, os.Stdin, os.Stdout, os.Stderr,
|
||||
rosa.AbsSystem.Append("bin", "mksh"),
|
||||
rosa.AbsSystem.Append("bin", "sh"),
|
||||
"sh",
|
||||
)
|
||||
})
|
||||
@@ -743,7 +825,7 @@ func main() {
|
||||
}
|
||||
pathname, err := cureRemote(ctx, &addr, a, flags)
|
||||
if !flagNoReply && err == nil {
|
||||
log.Println(pathname)
|
||||
fmt.Println(pathname)
|
||||
}
|
||||
|
||||
if errors.Is(err, context.Canceled) {
|
||||
@@ -837,9 +919,97 @@ func main() {
|
||||
&flagPop,
|
||||
"pop", command.BoolFlag(false),
|
||||
"Display and destroy the most recent fault entry",
|
||||
).Flag(
|
||||
&flagRebuild,
|
||||
"rebuild", command.BoolFlag(false),
|
||||
"Always enter the artifact implementation",
|
||||
).Flag(
|
||||
&flagGentoo,
|
||||
"gentoo", command.StringFlag(""),
|
||||
"Bootstrap from a Gentoo stage3 tarball",
|
||||
).Flag(
|
||||
&flagChecksum,
|
||||
"checksum", command.StringFlag(""),
|
||||
"Checksum of Gentoo stage3 tarball",
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"validate",
|
||||
"Repeatedly cure named artifact to validate determinism",
|
||||
func(args []string) error {
|
||||
stage := rosa.Std
|
||||
if len(args) == 3 {
|
||||
switch args[0] {
|
||||
case "boot":
|
||||
stage -= 2
|
||||
case "std":
|
||||
stage -= 1
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid stage %q", args[0])
|
||||
}
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
if len(args) != 2 {
|
||||
return errors.New("validate requires 2 arguments")
|
||||
}
|
||||
|
||||
n, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid passes %q", args[0])
|
||||
}
|
||||
|
||||
if n < 2 {
|
||||
return errors.New("validate must rebuild at least twice")
|
||||
}
|
||||
|
||||
_, a := rosa.Native().New(stage).Load(rosa.ArtifactH(unique.Make(args[1])))
|
||||
if a == nil {
|
||||
return fmt.Errorf("unknown artifact %q", args[1])
|
||||
}
|
||||
|
||||
if !a.IsExclusive() && cm.attr.Jobs < 1 {
|
||||
cm.attr.Jobs = runtime.NumCPU()/n + 1
|
||||
}
|
||||
|
||||
res := make([]unique.Handle[pkg.Checksum], n)
|
||||
if err = cm.Do(func(cache *pkg.Cache) error {
|
||||
errs := make([]error, n)
|
||||
var wg sync.WaitGroup
|
||||
for i := range n {
|
||||
wg.Go(func() {
|
||||
_, res[i], errs[i] = cache.CureNew(a)
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
return errors.Join(errs...)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range n - 1 {
|
||||
if res[i] == res[i+1] {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
buf.WriteString("nondeterminism:")
|
||||
for _, o := range res {
|
||||
buf.WriteString("\n\t")
|
||||
buf.WriteString(filepath.Join(
|
||||
cm.base,
|
||||
"checksum",
|
||||
pkg.Encode(o.Value()),
|
||||
))
|
||||
}
|
||||
return errors.New(buf.String())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
cleanC := c.New("clean", "Remove unused entries from the cache")
|
||||
cleanC.NewCommand(
|
||||
"fault",
|
||||
|
||||
@@ -65,6 +65,8 @@ const (
|
||||
// Some programs fail to connect to dbus session running as a different uid,
|
||||
// this option works around it by mapping priv-side caller uid in container.
|
||||
FMapRealUID
|
||||
// FNoPlace disables placement of /etc/passwd and /etc/group.
|
||||
FNoPlace
|
||||
|
||||
// FDevice mount /dev/ from the init mount namespace as is in the container
|
||||
// mount namespace.
|
||||
@@ -101,6 +103,8 @@ func (flags Flags) String() string {
|
||||
return "tty"
|
||||
case FMapRealUID:
|
||||
return "mapuid"
|
||||
case FNoPlace:
|
||||
return "noplace"
|
||||
case FDevice:
|
||||
return "device"
|
||||
case FCoverRun:
|
||||
@@ -197,6 +201,8 @@ type containerConfigJSON = struct {
|
||||
|
||||
// Corresponds to [FMapRealUID].
|
||||
MapRealUID bool `json:"map_real_uid"`
|
||||
// Corresponds to [FNoPlace].
|
||||
NoPlace bool `json:"noplace,omitempty"`
|
||||
|
||||
// Corresponds to [FDevice].
|
||||
Device bool `json:"device,omitempty"`
|
||||
@@ -224,6 +230,7 @@ func (c *ContainerConfig) MarshalJSON() ([]byte, error) {
|
||||
Tty: c.Flags&FTty != 0,
|
||||
Multiarch: c.Flags&FMultiarch != 0,
|
||||
MapRealUID: c.Flags&FMapRealUID != 0,
|
||||
NoPlace: c.Flags&FNoPlace != 0,
|
||||
Device: c.Flags&FDevice != 0,
|
||||
CoverRun: c.Flags&FCoverRun != 0,
|
||||
ShareRuntime: c.Flags&FShareRuntime != 0,
|
||||
@@ -266,6 +273,9 @@ func (c *ContainerConfig) UnmarshalJSON(data []byte) error {
|
||||
if v.MapRealUID {
|
||||
c.Flags |= FMapRealUID
|
||||
}
|
||||
if v.NoPlace {
|
||||
c.Flags |= FNoPlace
|
||||
}
|
||||
if v.Device {
|
||||
c.Flags |= FDevice
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ func TestFlagsString(t *testing.T) {
|
||||
}{
|
||||
{"none", 0, "none"},
|
||||
{"none high", hst.FAll + 1, "none"},
|
||||
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
|
||||
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
|
||||
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
|
||||
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -53,7 +53,7 @@ func TestContainerConfig(t *testing.T) {
|
||||
{"hostnet hostabstract mapuid", &hst.ContainerConfig{Flags: hst.FHostNet | hst.FHostAbstract | hst.FMapRealUID},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"host_net":true,"host_abstract":true,"map_real_uid":true}`},
|
||||
{"all", &hst.ContainerConfig{Flags: hst.FAll},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"noplace":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
+2
-2
@@ -82,9 +82,9 @@ func (o *FSOverlay) Apply(z *ApplyState) {
|
||||
z.Overlay(o.Target, o.Upper, o.Work, o.Lower...)
|
||||
} else {
|
||||
z.OverlayEphemeral(o.Target, slices.Concat(
|
||||
[]*check.Absolute{o.Upper},
|
||||
o.Lower,
|
||||
[]*check.Absolute{o.Upper})...,
|
||||
)
|
||||
)...)
|
||||
}
|
||||
} else {
|
||||
z.OverlayReadonly(o.Target, o.Lower...)
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestFSOverlay(t *testing.T) {
|
||||
Upper: m("/tmp/upper"),
|
||||
}, true, container.Ops{&container.MountOverlayOp{
|
||||
Target: m("/"),
|
||||
Lower: ms("/tmp/.src0", "/tmp/.src1", "/tmp/upper"),
|
||||
Lower: ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
|
||||
Upper: fhs.AbsRoot,
|
||||
}}, m("/"), ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
|
||||
"e*/:/tmp/upper:/tmp/.src0:/tmp/.src1"},
|
||||
|
||||
@@ -244,6 +244,7 @@ func TestTemplate(t *testing.T) {
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
|
||||
Vendored
+24
-4
@@ -1,21 +1,29 @@
|
||||
// Package env provides the [Paths] struct for efficiently building paths from the environment.
|
||||
// Package env provides the [Paths] struct for efficiently building paths from
|
||||
// the environment.
|
||||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
const VarRunNscd = fhs.Var + "run/nscd"
|
||||
|
||||
// Paths holds paths copied from the environment and is used to create [hst.Paths].
|
||||
type Paths struct {
|
||||
// TempDir is returned by [os.TempDir].
|
||||
TempDir *check.Absolute
|
||||
// RuntimePath is copied from $XDG_RUNTIME_DIR.
|
||||
RuntimePath *check.Absolute
|
||||
// Whether [VarRunNscd] is a directory.
|
||||
HasNscd bool
|
||||
}
|
||||
|
||||
// Copy expands [Paths] into [hst.Paths].
|
||||
@@ -37,14 +45,17 @@ func (env *Paths) Copy(v *hst.Paths, userid int) {
|
||||
}
|
||||
|
||||
// CopyPaths returns a populated [Paths].
|
||||
func CopyPaths() *Paths { return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv) }
|
||||
func CopyPaths() *Paths {
|
||||
return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv, os.Stat)
|
||||
}
|
||||
|
||||
// CopyPathsFunc returns a populated [Paths],
|
||||
// using the provided [log.Fatalf], [os.TempDir], [os.Getenv] functions.
|
||||
// CopyPathsFunc returns a populated [Paths], using the provided [log.Fatalf],
|
||||
// [os.TempDir], [os.Getenv] functions.
|
||||
func CopyPathsFunc(
|
||||
fatalf func(format string, v ...any),
|
||||
tempdir func() string,
|
||||
getenv func(key string) string,
|
||||
stat func(name string) (fs.FileInfo, error),
|
||||
) *Paths {
|
||||
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
||||
|
||||
@@ -61,5 +72,14 @@ func CopyPathsFunc(
|
||||
env.RuntimePath = a
|
||||
}
|
||||
|
||||
if fi, err := stat(VarRunNscd); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
fatalf("%v", err)
|
||||
panic("unreachable")
|
||||
}
|
||||
} else {
|
||||
env.HasNscd = fi.IsDir()
|
||||
}
|
||||
|
||||
return &env
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -2,6 +2,7 @@ package env_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -104,7 +105,9 @@ func TestCopyPaths(t *testing.T) {
|
||||
t.Fatalf("fatalf: %q, want %q", got, tc.fatal)
|
||||
}
|
||||
panic(stub.PanicExit)
|
||||
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] })
|
||||
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] }, func(name string) (fs.FileInfo, error) {
|
||||
return nil, fs.ErrNotExist
|
||||
})
|
||||
|
||||
if tc.fatal != "" {
|
||||
t.Fatalf("copyPaths: expected fatal %q", tc.fatal)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/std"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/stub"
|
||||
"hakurei.app/internal/system"
|
||||
"hakurei.app/message"
|
||||
@@ -174,6 +175,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
call("cmdOutput", stub.ExpectArgs{container.Nonexistent, os.Stderr, []string{}, "/"}, []byte("0"), nil),
|
||||
call("tempdir", stub.ExpectArgs{}, container.Nonexistent+"/tmp", nil),
|
||||
call("lookupEnv", stub.ExpectArgs{"XDG_RUNTIME_DIR"}, wantRuntimePath, nil),
|
||||
call("stat", stub.ExpectArgs{env.VarRunNscd}, stubFileInfoIsDir(true), nil),
|
||||
call("getuid", stub.ExpectArgs{}, 1000, nil),
|
||||
call("getgid", stub.ExpectArgs{}, 100, nil),
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *h
|
||||
Paths: env.CopyPathsFunc(k.fatalf, k.tempdir, func(key string) string {
|
||||
v, _ := k.lookupEnv(key)
|
||||
return v
|
||||
}),
|
||||
}, k.stat),
|
||||
Container: config.Container,
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +143,6 @@ func TestOutcomeRun(t *testing.T) {
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, std.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1971:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0).
|
||||
|
||||
@@ -453,7 +449,7 @@ func TestOutcomeRun(t *testing.T) {
|
||||
|
||||
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
||||
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FNoPlace | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
},
|
||||
SystemBus: &hst.BusConfig{
|
||||
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
|
||||
@@ -548,8 +544,6 @@ func TestOutcomeRun(t *testing.T) {
|
||||
Tmpfs(m("/run/user/"), xdgRuntimeDirSize, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), std.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), std.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
Bind(m("/run/user/1971/wayland-0"), m("/run/user/1971/wayland-0"), 0).
|
||||
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), m("/run/user/1971/pipewire-0"), 0).
|
||||
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), m("/run/user/1971/bus"), 0).
|
||||
@@ -716,7 +710,7 @@ func (k *stubNixOS) lookupEnv(key string) (string, bool) {
|
||||
func (k *stubNixOS) stat(name string) (fs.FileInfo, error) {
|
||||
switch name {
|
||||
case "/var/run/nscd":
|
||||
return nil, nil
|
||||
return stubFileInfoIsDir(true), nil
|
||||
case "/run/user/1971/pulse":
|
||||
return nil, nil
|
||||
case "/run/user/1971/pulse/native":
|
||||
|
||||
@@ -78,10 +78,6 @@ func TestShimEntrypoint(t *testing.T) {
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, std.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0).
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/validate"
|
||||
)
|
||||
|
||||
@@ -41,16 +42,18 @@ func (s spAccountOp) toContainer(state *outcomeStateParams) error {
|
||||
state.env["USER"] = username
|
||||
state.env["SHELL"] = state.Container.Shell.String()
|
||||
|
||||
state.params.
|
||||
Place(fhs.AbsEtc.Append("passwd"),
|
||||
[]byte(username+":x:"+
|
||||
state.mapuid.String()+":"+
|
||||
state.mapgid.String()+
|
||||
":Hakurei:"+
|
||||
state.Container.Home.String()+":"+
|
||||
state.Container.Shell.String()+"\n")).
|
||||
Place(fhs.AbsEtc.Append("group"),
|
||||
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
|
||||
if state.Container.Flags&hst.FNoPlace == 0 {
|
||||
state.params.
|
||||
Place(fhs.AbsEtc.Append("passwd"),
|
||||
[]byte(username+":x:"+
|
||||
state.mapuid.String()+":"+
|
||||
state.mapgid.String()+
|
||||
":Hakurei:"+
|
||||
state.Container.Home.String()+":"+
|
||||
state.Container.Shell.String()+"\n")).
|
||||
Place(fhs.AbsEtc.Append("group"),
|
||||
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestSpAccountOp(t *testing.T) {
|
||||
{"success fallback username", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Username = ""
|
||||
c.Container.Flags = hst.FMapRealUID
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
@@ -60,9 +61,7 @@ func TestSpAccountOp(t *testing.T) {
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, &container.Params{
|
||||
Dir: config.Container.Home,
|
||||
Ops: new(container.Ops).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")),
|
||||
Ops: new(container.Ops),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"HOME": config.Container.Home.String(),
|
||||
"USER": config.Container.Username,
|
||||
|
||||
@@ -18,13 +18,12 @@ import (
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/acl"
|
||||
"hakurei.app/internal/dbus"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/system"
|
||||
"hakurei.app/internal/validate"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
const varRunNscd = fhs.Var + "run/nscd"
|
||||
|
||||
func init() { gob.Register(new(spParamsOp)) }
|
||||
|
||||
// spParamsOp initialises unordered fields of [container.Params] and the
|
||||
@@ -136,17 +135,23 @@ type spFilesystemOp struct {
|
||||
}
|
||||
|
||||
func (s *spFilesystemOp) toSystem(state *outcomeStateSys) error {
|
||||
/* retrieve paths and hide them if they're made available in the sandbox;
|
||||
|
||||
this feature tries to improve user experience of permissive defaults, and
|
||||
to warn about issues in custom configuration; it is NOT a security feature
|
||||
and should not be treated as such, ALWAYS be careful with what you bind */
|
||||
// retrieve paths and hide them if they're made available in the sandbox
|
||||
//
|
||||
// this feature tries to improve user experience of permissive defaults, and
|
||||
// to warn about issues in custom configuration; it is NOT a security feature
|
||||
// and should not be treated as such, ALWAYS be careful with what you bind
|
||||
hidePaths := []string{
|
||||
state.sc.RuntimePath.String(),
|
||||
state.sc.SharePath.String(),
|
||||
}
|
||||
|
||||
// this causes emulated passwd database to be bypassed on some /etc/ setups
|
||||
varRunNscd,
|
||||
if state.Paths == nil || state.HasNscd {
|
||||
hidePaths = append(hidePaths,
|
||||
// this causes emulated passwd database to be bypassed on some /etc/
|
||||
// setups, made optional to avoid needlessly creating it on
|
||||
// non-glibc systems when invoking permissive defaults
|
||||
env.VarRunNscd,
|
||||
)
|
||||
}
|
||||
|
||||
// dbus.Address does not go through syscallDispatcher
|
||||
|
||||
@@ -278,6 +278,8 @@ type archiveArtifact struct {
|
||||
f Artifact
|
||||
}
|
||||
|
||||
var _ CuresExempt = archiveArtifact{}
|
||||
|
||||
// NewArchive returns a new [Artifact] backed by the supplied [Artifact]. The
|
||||
// source [Artifact] must be a [FileArtifact] and produce a stream compatible
|
||||
// with [Reader].
|
||||
@@ -301,8 +303,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a archiveArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a archiveArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -403,3 +405,7 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindArchive] implementation often found at
|
||||
// the end of a [FileArtifact] pipeline.
|
||||
func (archiveArtifact) CuresExempt() {}
|
||||
|
||||
@@ -186,7 +186,7 @@ func TestArchiveArtifact(t *testing.T) {
|
||||
cureMany(t, c, []cureStep{
|
||||
{"sample", pkg.NewArchive(
|
||||
pkg.NewFile("", buf.Bytes()),
|
||||
), ignorePathname, expectsFS(want), nil},
|
||||
), ignorePathname, expectsFS(want), pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -202,7 +202,7 @@ func TestArchiveArtifact(t *testing.T) {
|
||||
"checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/3oYyAbRJ_we7AgWo1BRcRcnxXFk3mAQ0Qui2nGQMi8GIJNJQtvUC6P2IeoA5mbjD": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")},
|
||||
"identifier/-zXKfphyWM2Ko7VMVURaEMSuixNokFSe0xFbnwR2RtRtvMrcPGWalV0LIn45PXTY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
+12
-3
@@ -73,7 +73,10 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
|
||||
continue
|
||||
}
|
||||
|
||||
c.msg.Verbosef("arranging for destruction of %s...", name)
|
||||
c.msg.Verbosef(
|
||||
"arranging for destruction of %s%s%s...",
|
||||
c.sgrIdent, name, c.sgrRes,
|
||||
)
|
||||
idents = append(idents, identPair{id, name})
|
||||
}
|
||||
|
||||
@@ -102,7 +105,10 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
|
||||
if err = c.parent.Err(); err != nil {
|
||||
return destroyedIdents, destroyedChecksums, err
|
||||
}
|
||||
c.msg.Verbosef("destroying checksum %s...", name)
|
||||
c.msg.Verbosef(
|
||||
"destroying checksum %s%s%s...",
|
||||
c.sgrIdent, name, c.sgrRes,
|
||||
)
|
||||
if !dry {
|
||||
if err = errors.Join(removeAll(c.base.Append(
|
||||
dirChecksum,
|
||||
@@ -130,7 +136,10 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) (
|
||||
continue
|
||||
}
|
||||
|
||||
c.msg.Verbosef("destroying substitute %s...", name)
|
||||
c.msg.Verbosef(
|
||||
"destroying substitute %s%s%s...",
|
||||
c.sgrIdent, name, c.sgrRes,
|
||||
)
|
||||
if !dry {
|
||||
if err = os.Remove(c.base.Append(
|
||||
dirStatus,
|
||||
|
||||
+12
-12
@@ -48,7 +48,7 @@ func TestClean(t *testing.T) {
|
||||
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/pPRjw2XYgjB5k8dYedwxTBMgHh4_v2JM_G2Vd-skQbAGOOgPsl3CGSUbEF7om_MO": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/h6qx7m0vsyhO6oLEJgY2rKa1c6RZuIZ4QXxZSh__NZJ9VU0MIj5bFB-KuaPcsfpE": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
|
||||
"lock": {Mode: 0644},
|
||||
"variant": {Mode: 0400},
|
||||
@@ -69,7 +69,7 @@ func TestClean(t *testing.T) {
|
||||
"checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk": {Mode: 0400, Data: []byte("\xfd")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/FMwSBYw22KqM8jZryfY2ChHXpLuVDdWYyNOYdHvIVYk8ujY6UnGRm5brr2sTTfpD": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk")},
|
||||
"identifier/tkrOYhQfTRaArk4nNYNjTmHQUmuJMVIoDeAKIQBm3I4uuMimBKXKMIY2gGZqwQg4": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/KgZ-FjbGuU-XP2QEHInpgv-2Zn0cTH5NqFMgTU0XrSdKmSwyC-3baVs1BMCP5spk")},
|
||||
|
||||
"lock": {Mode: 0644},
|
||||
"variant": {Mode: 0400},
|
||||
@@ -122,16 +122,16 @@ func TestClean(t *testing.T) {
|
||||
"checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE/result": {Mode: 0444},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
|
||||
"identifier/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
|
||||
"identifier/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
|
||||
"lock": {Mode: 0644},
|
||||
"variant": {Mode: 0400},
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"substitute/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
|
||||
"fault": {Mode: fs.ModeDir | 0700},
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
@@ -199,18 +199,18 @@ func TestClean(t *testing.T) {
|
||||
"checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv": {Mode: 0400, Data: []byte("kept")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/Ef8KX6s_rS_nLgze0rj90zKyrGAvOnzyU0DL7nrYQWEG_f4a9pmUKI6HBEMD8AE8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
|
||||
"identifier/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
|
||||
"identifier/KpxTUsUfGbsX6C6HU2j9cd9He3_tt2o2m2MgH4m0zial8lmoqSWY-Gc3KrS0k-UK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/H-eSiCo227-xdqyNl2R-5G3eqXPtbb8XegAB70I5OQb2majeZXJoCxTq9wJy5qqv")},
|
||||
"identifier/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
|
||||
|
||||
"lock": {Mode: 0644},
|
||||
"variant": {Mode: 0400},
|
||||
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
"status/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: 0400, Data: []byte(statusHeader + "kept")},
|
||||
"status/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: 0400, Data: []byte(statusHeader + "kept")},
|
||||
"status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0400, Data: []byte(statusHeader + "kept")},
|
||||
"status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0400, Data: []byte(statusHeader + "kept")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
|
||||
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
|
||||
|
||||
"fault": {Mode: fs.ModeDir | 0700},
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
@@ -238,7 +238,7 @@ func TestClean(t *testing.T) {
|
||||
base := makeBase(t)
|
||||
msg := message.New(log.New(os.Stderr, "clean: ", 0))
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
c, err := pkg.Open(t.Context(), msg, 0, 0, 0, base)
|
||||
c, err := pkg.Open(t.Context(), msg, base, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"hakurei.app/internal/xz"
|
||||
"hakurei.app/internal/zstd"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -13,6 +16,10 @@ const (
|
||||
Gzip = iota
|
||||
// Bzip2 denotes a stream compressed via [bzip2].
|
||||
Bzip2
|
||||
// Zstd denotes a stream compressed via [zstd].
|
||||
Zstd
|
||||
// XZ denotes a stream compressed via [xz].
|
||||
XZ
|
||||
)
|
||||
|
||||
// A decompressArtifact is a [FileArtifact] decompressing a backing
|
||||
@@ -25,6 +32,7 @@ type decompressArtifact struct {
|
||||
}
|
||||
|
||||
var _ FileArtifact = new(decompressArtifact)
|
||||
var _ CuresExempt = new(decompressArtifact)
|
||||
|
||||
// decompressArtifactNamed embeds decompressArtifact for a [fmt.Stringer] stream.
|
||||
type decompressArtifactNamed struct {
|
||||
@@ -65,8 +73,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a *decompressArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a *decompressArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -90,6 +98,9 @@ func (c compoundCloser) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// IsExecutable returns false.
|
||||
func (*decompressArtifact) IsExecutable() bool { return false }
|
||||
|
||||
// Cure returns a decompressor [io.ReadCloser].
|
||||
func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
|
||||
sr, err := r.Open(a.f)
|
||||
@@ -113,7 +124,28 @@ func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
|
||||
io.Closer
|
||||
}{bzip2.NewReader(br), br}, nil
|
||||
|
||||
case Zstd:
|
||||
return struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{zstd.NewReader(br), br}, nil
|
||||
|
||||
case XZ:
|
||||
var _dr io.Reader
|
||||
if _dr, err = xz.NewReader(br, 0); err != nil {
|
||||
_ = br.Close()
|
||||
return nil, err
|
||||
}
|
||||
return struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{_dr, br}, nil
|
||||
|
||||
default:
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindDecompress] implementation often part of
|
||||
// a [FileArtifact] pipeline.
|
||||
func (*decompressArtifact) CuresExempt() {}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestDecompress(t *testing.T) {
|
||||
&client,
|
||||
"file:///testdata",
|
||||
pkg.Checksum{0xfd},
|
||||
), pkg.Gzip), nil, nil, &pkg.ChecksumMismatchError{
|
||||
), pkg.Gzip), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: testdataChecksum,
|
||||
Want: pkg.Checksum{0xfd},
|
||||
}},
|
||||
@@ -52,7 +52,7 @@ func TestDecompress(t *testing.T) {
|
||||
&client,
|
||||
"file:///testdata",
|
||||
testdataChecksum,
|
||||
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), nil},
|
||||
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -61,7 +61,7 @@ func TestDecompress(t *testing.T) {
|
||||
"checksum/" + pkg.Encode(sha512.Sum384([]byte{0})): {Mode: 0400, Data: []byte{0}},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/QpjkahDrz7pz-tv0eAGNXR6x9NAtTjWCK5Hr7G1cIZj9rT7bLYJWUQeLD4wamAlF": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||
"identifier/mae-iR_9LFT_BOEJ2IRzKsAlI754SalMjjt95fZeMd3gEyAzsrvuOXnXN0bFZJi4": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
+37
-16
@@ -30,10 +30,16 @@ import (
|
||||
// AbsWork is the container pathname [TContext.GetWorkDir] is mounted on.
|
||||
var AbsWork = fhs.AbsRoot.Append("work/")
|
||||
|
||||
// EnvJobs is the name of the environment variable holding a decimal
|
||||
// representation of the preferred job count. Its value must not affect cure
|
||||
// outcome.
|
||||
const EnvJobs = "CURE_JOBS"
|
||||
const (
|
||||
// EnvJobs is the name of the environment variable holding a decimal
|
||||
// representation of the preferred job count. Its value must not affect cure
|
||||
// outcome.
|
||||
EnvJobs = "CURE_JOBS"
|
||||
// EnvLoad is the name of the environment variable holding a decimal
|
||||
// representation of the preferred loadavg target. Its value must not affect
|
||||
// cure outcome.
|
||||
EnvLoad = "CURE_LOAD"
|
||||
)
|
||||
|
||||
// ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make
|
||||
// it available at under in the container.
|
||||
@@ -407,9 +413,9 @@ func init() {
|
||||
func(r *IRReader) Artifact { return readExecArtifact(r, true) })
|
||||
}
|
||||
|
||||
// Dependencies returns a slice of all artifacts collected from caller-supplied
|
||||
// Inputs returns a slice of all artifacts collected from caller-supplied
|
||||
// [ExecPath].
|
||||
func (a *execArtifact) Dependencies() []Artifact {
|
||||
func (a *execArtifact) Inputs() []Artifact {
|
||||
artifacts := make([][]Artifact, 0, len(a.paths))
|
||||
for _, p := range a.paths {
|
||||
artifacts = append(artifacts, p.A)
|
||||
@@ -438,7 +444,7 @@ func scanVerbose(
|
||||
msg message.Msg,
|
||||
cancel context.CancelFunc,
|
||||
done chan<- struct{},
|
||||
prefix string,
|
||||
prefix, suffix string,
|
||||
r io.Reader,
|
||||
) {
|
||||
defer close(done)
|
||||
@@ -448,7 +454,7 @@ func scanVerbose(
|
||||
bufio.MaxScanTokenSize<<12,
|
||||
)
|
||||
for s.Scan() {
|
||||
msg.Verbose(prefix, s.Text())
|
||||
msg.Verbose(prefix, s.Text()+suffix)
|
||||
}
|
||||
if err := s.Err(); err != nil && !errors.Is(err, os.ErrClosed) {
|
||||
cancel()
|
||||
@@ -471,7 +477,7 @@ const SeccompPresets = std.PresetStrict &
|
||||
func (a *execArtifact) makeContainer(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, jobs int,
|
||||
flags, jobs, load int,
|
||||
hostNet bool,
|
||||
temp, work *check.Absolute,
|
||||
getArtifact GetArtifactFunc,
|
||||
@@ -508,7 +514,10 @@ func (a *execArtifact) makeContainer(
|
||||
z.Quiet = flags&CSuppressInit != 0
|
||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||
z.Dir, z.Path, z.Args = a.dir, a.path, a.args
|
||||
z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
|
||||
z.Env = slices.Concat(a.env, []string{
|
||||
EnvJobs + "=" + strconv.Itoa(jobs),
|
||||
EnvLoad + "=" + strconv.Itoa(load),
|
||||
})
|
||||
z.Grow(len(a.paths) + 4)
|
||||
|
||||
if a.arch != runtime.GOARCH {
|
||||
@@ -617,7 +626,7 @@ func (c *Cache) EnterExec(
|
||||
return ErrNotExec
|
||||
}
|
||||
|
||||
deps := Collect(a.Dependencies())
|
||||
deps := Collect(a.Inputs())
|
||||
if _, _, err = c.Cure(&deps); err == nil {
|
||||
return errors.New("unreachable")
|
||||
} else if !IsCollected(err) {
|
||||
@@ -649,8 +658,9 @@ func (c *Cache) EnterExec(
|
||||
var z *container.Container
|
||||
z, err = e.makeContainer(
|
||||
ctx, c.msg,
|
||||
c.flags,
|
||||
c.jobs,
|
||||
c.attr.Flags,
|
||||
c.attr.Jobs,
|
||||
c.attr.Load,
|
||||
hostNet,
|
||||
temp, work,
|
||||
func(a Artifact) (*check.Absolute, unique.Handle[Checksum]) {
|
||||
@@ -693,7 +703,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||
msg := f.GetMessage()
|
||||
var z *container.Container
|
||||
if z, err = a.makeContainer(
|
||||
ctx, msg, f.cache.flags, f.GetJobs(), hostNet,
|
||||
ctx, msg, f.cache.attr.Flags, f.GetJobs(), f.GetLoad(), hostNet,
|
||||
f.GetTempDir(), f.GetWorkDir(),
|
||||
f.GetArtifact,
|
||||
f.cache.Ident,
|
||||
@@ -718,14 +728,25 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||
|
||||
brStdout, brStderr := f.cache.getReader(stdout), f.cache.getReader(stderr)
|
||||
stdoutDone, stderrDone := make(chan struct{}), make(chan struct{})
|
||||
|
||||
var suffix, prefixO, prefixE string
|
||||
if f.cache.attr.Flags&CColourOutput != 0 {
|
||||
suffix = "\x1b[0m"
|
||||
prefixO = "\x1b[1;37m(" + a.name + ")\x1b[0m"
|
||||
prefixE = "\x1b[1;97m(" + a.name + ")\x1b[0m"
|
||||
} else {
|
||||
prefixO = "(" + a.name + ":1)"
|
||||
prefixE = "(" + a.name + ":2)"
|
||||
}
|
||||
|
||||
go scanVerbose(
|
||||
msg, cancel, stdoutDone,
|
||||
"("+a.name+":1)",
|
||||
prefixO, suffix,
|
||||
io.TeeReader(brStdout, status),
|
||||
)
|
||||
go scanVerbose(
|
||||
msg, cancel, stderrDone,
|
||||
"("+a.name+":2)",
|
||||
prefixE, suffix,
|
||||
io.TeeReader(brStderr, status),
|
||||
)
|
||||
defer func() {
|
||||
|
||||
+21
-21
@@ -84,7 +84,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
|
||||
{"substitution", pkg.NewExec(
|
||||
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
|
||||
@@ -108,7 +108,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WSubstitute, nil},
|
||||
|
||||
{"error passthrough", pkg.NewExec(
|
||||
"", "", nil, 0, false, true,
|
||||
@@ -118,7 +118,7 @@ func TestExec(t *testing.T) {
|
||||
[]string{"testtool"},
|
||||
|
||||
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
|
||||
), nil, nil, &pkg.DependencyCureError{
|
||||
), nil, nil, pkg.WNew, &pkg.DependencyCureError{
|
||||
{
|
||||
A: failingArtifact,
|
||||
Err: stub.UniqueError(0xcafe),
|
||||
@@ -133,7 +133,7 @@ func TestExec(t *testing.T) {
|
||||
[]string{"testtool"},
|
||||
|
||||
pkg.ExecPath{},
|
||||
), nil, nil, pkg.ErrInvalidPaths},
|
||||
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths},
|
||||
})
|
||||
|
||||
// check init failure passthrough
|
||||
@@ -183,11 +183,11 @@ func TestExec(t *testing.T) {
|
||||
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/QwS7SmiatdqryQYgESdGw7Yw2PcpNf0vNfpvUA0t92BTlKiUjfCrXyMW17G2X77X": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/" + expected.Offline: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
"identifier/" + expected.OfflineS: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/_OHzj_xdmfpaWfFN-_D9JpGpPlIjh84873E3Ui9xwv9PPPIt0BlzvH-cnPNeRsTl": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -225,7 +225,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantNet, nil},
|
||||
), ignorePathname, wantNet, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -242,7 +242,7 @@ func TestExec(t *testing.T) {
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/" + expected.Net: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")},
|
||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -284,7 +284,7 @@ func TestExec(t *testing.T) {
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/" + expected.OvlRoot: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -316,7 +316,7 @@ func TestExec(t *testing.T) {
|
||||
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
||||
},
|
||||
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -331,7 +331,7 @@ func TestExec(t *testing.T) {
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/" + expected.Work: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -385,7 +385,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -403,9 +403,9 @@ func TestExec(t *testing.T) {
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
|
||||
"identifier/2uIvmnqtzAx4Ed4PWV8xjZCWeJCwfE2IcCc0evM-Nd8mDUlgSU6nLtPLcpPUcMlG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
|
||||
"identifier/" + expected.Layers: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -438,7 +438,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -452,8 +452,8 @@ func TestExec(t *testing.T) {
|
||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/Vzj9qaSVBtNyBQv_PW6uojFOWTwraHoaC0C6xdaGG1q_HTvSh4KLVxRcEQU1jd2Y": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
@@ -503,7 +503,7 @@ func TestExec(t *testing.T) {
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
|
||||
"check": {Mode: 0400, Data: []byte("binfmt")},
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -519,9 +519,9 @@ func TestExec(t *testing.T) {
|
||||
"checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3/check": {Mode: 0400, Data: []byte("binfmt")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/6VQTJ1lI5BmVuI1YFYJ8ClO3MRORvTTrcWFDcUU-l5Ga8EofxCxGlSTYN-u8dKj_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3")},
|
||||
"identifier/c-HodmoEG0f_WGdst9aN-duLMH7QDDXOUi7UcyArXMeM1fc9lYKKQlTCW8ktaK8X": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3")},
|
||||
"identifier/_v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV")},
|
||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/MEaM1v6MLRQ60JQOOKbfDzfJOdC3L8i30IgOpYbQdX68enwF0FN-P36_M4RX_0Vd": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
|
||||
+21
-2
@@ -11,6 +11,8 @@ import (
|
||||
type fileArtifact []byte
|
||||
|
||||
var _ KnownChecksum = new(fileArtifact)
|
||||
var _ CuresExempt = new(fileArtifact)
|
||||
var _ RevisionArtifact = new(fileArtifact)
|
||||
|
||||
// fileArtifactNamed embeds fileArtifact alongside a caller-supplied name.
|
||||
type fileArtifactNamed struct {
|
||||
@@ -62,8 +64,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a nil slice.
|
||||
func (*fileArtifact) Dependencies() []Artifact { return nil }
|
||||
// Inputs returns a nil slice.
|
||||
func (*fileArtifact) Inputs() []Artifact { return nil }
|
||||
|
||||
// IsExclusive returns false: Cure returns a prepopulated buffer.
|
||||
func (*fileArtifact) IsExclusive() bool { return false }
|
||||
@@ -75,7 +77,24 @@ func (a *fileArtifact) Checksum() Checksum {
|
||||
return Checksum(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Revision satisfies [RevisionArtifact] for incompatible IsExecutable behaviour.
|
||||
func (*fileArtifact) Revision() uint64 { return 0 }
|
||||
|
||||
// IsExecutable returns whether the contents begin with shebang or the ELF
|
||||
// magic number.
|
||||
func (a *fileArtifact) IsExecutable() bool {
|
||||
return a != nil &&
|
||||
(bytes.HasPrefix(
|
||||
*a, []byte{'#', '!'},
|
||||
) || bytes.HasPrefix(
|
||||
*a, []byte{0x7f, 'E', 'L', 'F'},
|
||||
))
|
||||
}
|
||||
|
||||
// Cure returns the caller-supplied data.
|
||||
func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader(*a)), nil
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindFile] implementation.
|
||||
func (*fileArtifact) CuresExempt() {}
|
||||
|
||||
@@ -12,22 +12,41 @@ func TestFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
want := expectsFile{0}
|
||||
const ident = "N7M6W8-e55Wky_1q1a6qRKFVDw1S5XtPdB4HE2YZObG8OFum8HittyJgZUG5Ru2u"
|
||||
wantShebang := expectsFile("#!/bin/sh\n")
|
||||
const identShebang = "oKTGZb_TRtJf5G1iGGj4SOx1WUbI6YhmsUeEsCNvmK9tZYRwdwQf-DLFUxRPx5qm"
|
||||
wantELF := expectsFile("\x7fELF\xde\xad\xbe\xef")
|
||||
const identELF = "LjeHmIJgD1SiXIH8ewpGRed2_LU84NLapstnOAa_0hxLd8YY7x4KM0aApsj-RwCh"
|
||||
checkWithCache(t, []cacheTestCase{
|
||||
{"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||
cureMany(t, c, []cureStep{
|
||||
{"short", pkg.NewFile("null", []byte{0}), base.Append(
|
||||
{"short", pkg.NewFile("null", want), base.Append(
|
||||
"identifier",
|
||||
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
|
||||
), want, nil},
|
||||
ident,
|
||||
), want, pkg.WNew, nil},
|
||||
|
||||
{"shebang", pkg.NewFile("shebang", wantShebang), base.Append(
|
||||
"identifier",
|
||||
identShebang,
|
||||
), wantShebang, pkg.WNew, nil},
|
||||
|
||||
{"elf", pkg.NewFile("ELF", wantELF), base.Append(
|
||||
"identifier",
|
||||
identELF,
|
||||
), wantELF, pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
"checksum": {Mode: fs.ModeDir | 0700},
|
||||
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: []byte{0}},
|
||||
"checksum": {Mode: fs.ModeDir | 0700},
|
||||
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: want},
|
||||
"checksum/" + pkg.Encode(wantShebang.hash()): {Mode: 0500, Data: wantShebang},
|
||||
"checksum/" + pkg.Encode(wantELF.hash()): {Mode: 0500, Data: wantELF},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/" + ident: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(want.hash()))},
|
||||
"identifier/" + identShebang: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(wantShebang.hash()))},
|
||||
"identifier/" + identELF: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + pkg.Encode(wantELF.hash()))},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package expected
|
||||
|
||||
const (
|
||||
Offline = "q5ktDTq0miP-VvB2blxqXQeaRXCUWgP_KbC18KNtUDtyoaI_h5mHmGuPMArVEBDs"
|
||||
OfflineS = "IY91PCtOpCYy21AaIK0c9f8-Z6fb2_2ewoHWkt4dxoLf0GOrWqS8yAGFLV84b1Dw"
|
||||
OvlRoot = "NacZGXwuRkTvcHaG08a22ujJ8qCWN0RSoFlRSR5FSt0ZcBbJ28FRvkYsHEtX7G8i"
|
||||
Layers = "WBJDrATtX6rIE5yAu8ePX3WmDF0Tt9kFiue0m3cRnyRoVx1my8a67fh3CAW486oP"
|
||||
Net = "CmYtj2sNB3LHtqiDuck_Lz3MjLLIiwyP8N4NDitQ1Icvv__LVP9p8tm-sHeQaKKp"
|
||||
Promote = "TX3eCloaQFkV-SZIH6Jg6E5WKH--rcXY1P0jnZKmLFKWrNqnOzd4G9eIBh6i5ywN"
|
||||
Work = "OuNiLSC68pZhAOr1YQ4WbV1tzASA0nxLEBcK7lO7MqxDY_j8dmP_C612RTuF23Lu"
|
||||
Offline = "IKmVhALejtYA3JhN1PCfjKF-Dio1XVcOeMWDHhfSHCbb4iBNhGjFy2UspZveZvb8"
|
||||
OfflineS = "6ZubjSyCnz4-TKgQZi_BbY-JUwsStYCtD_f-BTDOOotfEbqkm47W20AazHRaLviz"
|
||||
OvlRoot = "Yox7WpG8B_OqIXWF4HWFZkUfsEl7DGzpFyZM0qtd9T8nQ-7SAkEUurlAe6_DJ6Iu"
|
||||
Layers = "aAwfxDB-efVo379FNl178jK7HEKU3LEjHbZdaVVjk7GnXGZGEANNsXnB3SCUxM9A"
|
||||
Net = "IU3GwU2jTBd7HjotvFo2wsDWBQGVGpamwiSKdc2G1EnhM-ZaacxAuK6q0wbTVxra"
|
||||
Promote = "rOjetGHzT_jPErrBR24IAZKDj8Q9dLLqxFQqloMgjsULss0VXDI--n6LxuMBHvmZ"
|
||||
Work = "7f9XDeREfvJIjCe0qesND0s0tasExAIcc-OH33-eq9tsrQPUXhJp4KEkpsYH4hCD"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package expected
|
||||
|
||||
const (
|
||||
Offline = "WapqyoPxbWSnq07dWHt71mHaJXq99pAjJfFlELlJljSiZMhTFqqlzU1_mN86shSj"
|
||||
OfflineS = "ibQZHcdXgNQ1OiMX1FrburBbGPVvKEHvPilbQCkm_0oV0BQCHomyyTbYNrFMGIwl"
|
||||
OvlRoot = "V9anFOiRvjGfAeBhLl14AL8TKdWZyD0WTPYe4fS9mOBw8iW5Lmarvt6TG6MV8uWm"
|
||||
Layers = "tKx7JNRoSBdK_7MdzI-nwTNV2wmiPzwYdcd17oLmXKL_iLmUzUiA79qTqdrTasrv"
|
||||
Net = "aXyDLzBCJ9XltXZIfetEVsEkrqHfcXuD5XE_FcUnYbN3emwL55N6P8LlHzNfGnM5"
|
||||
Promote = "3k4V16n96Lq04gjFSKmm4sFjyQ883FFBNXgTy9s_DjeTwxT3pg_iacEh8yMb_S4m"
|
||||
Work = "6Q49MhFWRE3Ne6MycwAotgl1GtoU5WCHqJNWG2byYZCY-zX-IxPrWiKk7bKkNzhE"
|
||||
Offline = "MTgCSzwPrzGigp9phvDPRwUTNGLm1KM2EsEtbz-l2cNieqjaGtnzm65CDXlSxXrl"
|
||||
OfflineS = "p89bQg7_jR4nwaSbpEd08ne1jHOEw7Wlnlyv5FHq7ba1Kml3HSBZwEKRzu0gCqEb"
|
||||
OvlRoot = "9ifwO6MAaV9kTqRR2O5PJzm8XhfXbr50mFLWyEHQm8OHHcJtAEUgXZzJYoZt9YVV"
|
||||
Layers = "INuGActFPwJtS7mAR9Bkt7FD4yoHlXHSJ9CaSAQJrpkUBL_k815Cs_jvRfxy5-a7"
|
||||
Net = "kJvy24uk4ePvHoxSKf4vMOhR4NxLbmyWlA9bTS7d3z3fE9WF1Tvpao9g-QuYU4vm"
|
||||
Promote = "lYqyYrfjPawIbld5Qz0NbKvd_bmI3nJC1eEnlIQWzsjWE9uA1HuKPAaClnDeyG6L"
|
||||
Work = "V6k4FqOBMRCmHiqchs5-joVGZ_MhNWZyXm3gdbU0S7S5eMze7G4SwYMTf66ojKQL"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package expected
|
||||
|
||||
const (
|
||||
Offline = "Z6yXE5gOJScL3srmnVMWgCXccDiUNZ5snSrf6RkXuU1_U0rX_kGVwsfHUgNG_awd"
|
||||
OfflineS = "zN16xv6LKRJRipUJwupyxg2rZcvf-qpsMn_qCxUmgxlTSuNwYI70ZEb7dHW5k0gO"
|
||||
OvlRoot = "zYXJHFRLuxvUhuisZEXgGgVvdQd6piMfp5jmtT6jdVjvC2gICXquOq-UTwlrSD5I"
|
||||
Layers = "_F8EDazHbcLeT0sVSQXRN_kn9IjduqJcDYgzXpsT-hpKU4EBcZ0PISN2zchpqMbm"
|
||||
Net = "CA_FAaSIYJgapBEHV40doxpH23PdUEy_6s1TZc7wfSPN0XYqwGpMceXXDSabGveO"
|
||||
Promote = "_3LPrLp--4h9k4GsNNApu9hHtAafq-GUhfU6d4hJKBDKT3bz_szOsvkXxc5sK53d"
|
||||
Work = "FEgHeiCD_WT4wsfB-9kDH5n6cRWCEYtJmXdKZgmUUukAOoXumH_hLlosXREC-tqq"
|
||||
Offline = "LlieSHVDe1lnKvfI8t4oGRg_2hPxwyy1drmaqc-EKCOENuS9C2YHrp2VY5pSyhbg"
|
||||
OfflineS = "qccjM8oYjUuEYPKFFzAxDFVzMerSUKUZc18NdVQoiPWf-70XOsNK8NaUQqjTgTAD"
|
||||
OvlRoot = "lpV2bb_KGYFHPiOn-jtGop8K_ew0y1p3BezRp0ebM93_a-T9J-vkqGD5uokda1aN"
|
||||
Layers = "sM3DJm210CHPGHkAquIbrXhspB81FpVC60ApQrvJGD5El2i7cSONj7LWf7EWqKpT"
|
||||
Net = "JihQUwsVETRYjb2-yIXLYZ6WVsaFebwl8btSYAsNQ2QapS5MZVaI-dYwrVoySycR"
|
||||
Promote = "lGqwR4W2OjylSVitMQP1lc6wApOBkbMjsmIqkxQbfEZ3DHEQBbJr84ErW6Xb54zo"
|
||||
Work = "aZgtyv6aMtoHFkHAaJr6nLaA7N_SHjShgWPyQ5UdzaIqYSiVqvCrZqSokGTCcTii"
|
||||
)
|
||||
|
||||
@@ -38,7 +38,15 @@ func main() {
|
||||
}
|
||||
|
||||
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
|
||||
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
|
||||
for _, t := range []string{
|
||||
"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
|
||||
"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
|
||||
} {
|
||||
if s == t {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
var hostNet, layers, promote bool
|
||||
|
||||
+44
-26
@@ -90,7 +90,7 @@ type IContext struct {
|
||||
// returns and must not be exposed directly.
|
||||
w io.Writer
|
||||
// Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with
|
||||
// checksum values if non-nil.
|
||||
// checksum values if non-nil. The pathname field may not be populated.
|
||||
inputs map[Artifact]cureRes
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func (i *IContext) mustWrite(p []byte) {
|
||||
|
||||
// WriteIdent writes the identifier of [Artifact] to the IR. The behaviour of
|
||||
// WriteIdent is not defined for an [Artifact] not part of the slice returned by
|
||||
// [Artifact.Dependencies].
|
||||
// [Artifact.Inputs].
|
||||
func (i *IContext) WriteIdent(a Artifact) {
|
||||
buf := i.ic.getIdentBuf()
|
||||
defer i.ic.putIdentBuf(buf)
|
||||
@@ -235,13 +235,14 @@ func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
|
||||
}
|
||||
|
||||
// encode implements Encode but replaces identifiers with their cured checksums
|
||||
// for a non-nil ident. Caller must acquire Cache.identMu.
|
||||
// for a non-nil ident. The pathname field is unused. Caller must acquire
|
||||
// Cache.identMu.
|
||||
func (ic *irCache) encode(
|
||||
w io.Writer,
|
||||
a Artifact,
|
||||
inputs map[Artifact]cureRes,
|
||||
) (err error) {
|
||||
deps := a.Dependencies()
|
||||
deps := a.Inputs()
|
||||
idents := make([]*extIdent, len(deps))
|
||||
if inputs == nil {
|
||||
for i, d := range deps {
|
||||
@@ -277,10 +278,11 @@ func (ic *irCache) encode(
|
||||
return *a == *b
|
||||
})
|
||||
|
||||
// kind uint64 | deps_sz uint64
|
||||
var buf [wordSize * 2]byte
|
||||
// kind uint64 | rev uint64 | deps_sz uint64
|
||||
var buf [wordSize * 3]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(a.Kind()))
|
||||
binary.LittleEndian.PutUint64(buf[wordSize:], uint64(len(idents)))
|
||||
binary.LittleEndian.PutUint64(buf[wordSize:], GetRevision(a))
|
||||
binary.LittleEndian.PutUint64(buf[wordSize*2:], uint64(len(idents)))
|
||||
if _, err = w.Write(buf[:]); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -330,7 +332,7 @@ func (ic *irCache) encodeAll(
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range a.Dependencies() {
|
||||
for _, d := range a.Inputs() {
|
||||
if err = ic.encodeAll(w, d, encoded); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -432,9 +434,9 @@ type (
|
||||
// Common buffer for word-sized reads.
|
||||
buf [wordSize]byte
|
||||
|
||||
// Dependencies sent before params, sorted by identifier. Resliced on
|
||||
// Inputs sent before params, sorted by identifier. Resliced on
|
||||
// each call to Next and checked to be depleted during Finalise.
|
||||
deps []*extIdent
|
||||
inputs []*extIdent
|
||||
|
||||
// Number of values already read, -1 denotes a finalised IRReader.
|
||||
count int
|
||||
@@ -518,7 +520,7 @@ const (
|
||||
irMaxValues = 1 << 12
|
||||
|
||||
// irMaxDeps is the arbitrary maximum number of direct dependencies allowed
|
||||
// to be returned by [Artifact.Dependencies] and subsequently decoded by
|
||||
// to be returned by [Artifact.Inputs] and subsequently decoded by
|
||||
// [IRDecoder].
|
||||
irMaxDeps = 1 << 10
|
||||
)
|
||||
@@ -603,17 +605,17 @@ func (ir *IRReader) mustReadHeader(k IRValueKind) {
|
||||
|
||||
// putAll returns all dependency buffers to the underlying [Cache].
|
||||
func (ir *IRReader) putAll() {
|
||||
for _, buf := range ir.deps {
|
||||
for _, buf := range ir.inputs {
|
||||
ir.d.c.putIdentBuf(buf)
|
||||
}
|
||||
ir.deps = nil
|
||||
ir.inputs = nil
|
||||
}
|
||||
|
||||
// DiscardAll discards all unstructured dependencies. This is useful to
|
||||
// implementations that encode dependencies as [IRKindIdent] which are read back
|
||||
// via ReadIdent.
|
||||
func (ir *IRReader) DiscardAll() {
|
||||
if ir.deps == nil {
|
||||
if ir.inputs == nil {
|
||||
panic("attempting to discard dependencies twice")
|
||||
}
|
||||
ir.putAll()
|
||||
@@ -625,13 +627,13 @@ var ErrDependencyDepleted = errors.New("reading past end of dependencies")
|
||||
|
||||
// Next returns the next unstructured dependency.
|
||||
func (ir *IRReader) Next() Artifact {
|
||||
if len(ir.deps) == 0 {
|
||||
if len(ir.inputs) == 0 {
|
||||
panic(ErrDependencyDepleted)
|
||||
}
|
||||
|
||||
id := unique.Make(ID(ir.deps[0][wordSize:]))
|
||||
ir.d.c.putIdentBuf(ir.deps[0])
|
||||
ir.deps = ir.deps[1:]
|
||||
id := unique.Make(ID(ir.inputs[0][wordSize:]))
|
||||
ir.d.c.putIdentBuf(ir.inputs[0])
|
||||
ir.inputs = ir.inputs[1:]
|
||||
|
||||
if a, ok := ir.d.ident[id]; !ok {
|
||||
ir.putAll()
|
||||
@@ -684,8 +686,8 @@ func (ir *IRReader) Finalise() (checksum unique.Handle[Checksum], ok bool) {
|
||||
}
|
||||
ir.r, ir.ibw = nil, nil
|
||||
|
||||
if len(ir.deps) != 0 {
|
||||
panic(MissedDependencyError(len(ir.deps)))
|
||||
if len(ir.inputs) != 0 {
|
||||
panic(MissedDependencyError(len(ir.inputs)))
|
||||
}
|
||||
|
||||
return
|
||||
@@ -739,6 +741,15 @@ func (ir *IRReader) ReadString() string {
|
||||
return unsafe.String(unsafe.SliceData(p), len(p))
|
||||
}
|
||||
|
||||
// A RevisionError describes the first [Artifact] in an IR stream claiming a
|
||||
// revision not supported by the registered implementation.
|
||||
type RevisionError [2]uint64
|
||||
|
||||
func (e RevisionError) Error() string {
|
||||
return "claimed revision " + strconv.FormatUint(e[0], 10) +
|
||||
" differs from implementation value " + strconv.FormatUint(e[1], 10)
|
||||
}
|
||||
|
||||
// decode decodes the next [Artifact] in the IR stream and returns any buffer
|
||||
// originating from [Cache] before returning. decode returns [io.EOF] if and
|
||||
// only if the underlying [io.Reader] is already read to EOF.
|
||||
@@ -771,6 +782,9 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
ir.mustRead(ir.buf[:])
|
||||
rev := binary.LittleEndian.Uint64(ir.buf[:])
|
||||
|
||||
defer ir.putAll()
|
||||
ir.mustRead(ir.buf[:])
|
||||
sz := binary.LittleEndian.Uint64(ir.buf[:])
|
||||
@@ -778,11 +792,11 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
|
||||
err = ErrIRDepend
|
||||
return
|
||||
}
|
||||
ir.deps = make([]*extIdent, sz)
|
||||
for i := range ir.deps {
|
||||
ir.deps[i] = d.c.getIdentBuf()
|
||||
ir.inputs = make([]*extIdent, sz)
|
||||
for i := range ir.inputs {
|
||||
ir.inputs[i] = d.c.getIdentBuf()
|
||||
}
|
||||
for _, buf := range ir.deps {
|
||||
for _, buf := range ir.inputs {
|
||||
ir.mustRead(buf[:])
|
||||
}
|
||||
|
||||
@@ -791,6 +805,10 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
|
||||
err = syscall.ENOTRECOVERABLE
|
||||
return
|
||||
}
|
||||
if _rev := GetRevision(a); _rev != rev {
|
||||
err = RevisionError{rev, _rev}
|
||||
return
|
||||
}
|
||||
|
||||
if ir.count != -1 {
|
||||
err = ErrRemainingIR
|
||||
@@ -805,8 +823,8 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
|
||||
d.ident[id] = a
|
||||
} else {
|
||||
d.c.msg.Verbosef(
|
||||
"artifact %s appeared more than once in IR stream",
|
||||
Encode(id.Value()),
|
||||
"artifact %s%s%s appeared more than once in IR stream",
|
||||
d.c.sgrIdent, Encode(id.Value()), d.c.sgrRes,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -135,3 +135,36 @@ func TestIRRoundtrip(t *testing.T) {
|
||||
}
|
||||
checkWithCache(t, testCasesCache)
|
||||
}
|
||||
|
||||
func TestRevision(t *testing.T) {
|
||||
checkWithCache(t, []cacheTestCase{{"revision", 0, nil,
|
||||
func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||
a := pkg.NewFile("", nil)
|
||||
var buf bytes.Buffer
|
||||
if err := c.EncodeAll(&buf, a); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := c.NewDecoder(
|
||||
bytes.NewReader(buf.Bytes()),
|
||||
).Decode(); err != nil {
|
||||
t.Fatalf("Decode: error = %v", err)
|
||||
}
|
||||
|
||||
p := buf.Bytes()
|
||||
p[8] = 0xfd
|
||||
wantErr := pkg.RevisionError{0xfd, 0}
|
||||
if _, err := c.NewDecoder(
|
||||
bytes.NewReader(p),
|
||||
).Decode(); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Fatalf("Decode: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
"checksum": {Mode: fs.ModeDir | 0700},
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
},
|
||||
}})
|
||||
}
|
||||
|
||||
+5
-2
@@ -54,8 +54,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a nil slice.
|
||||
func (*httpArtifact) Dependencies() []Artifact { return nil }
|
||||
// Inputs returns a nil slice.
|
||||
func (*httpArtifact) Inputs() []Artifact { return nil }
|
||||
|
||||
// IsExclusive returns false: Cure returns as soon as a response is received.
|
||||
func (*httpArtifact) IsExclusive() bool { return false }
|
||||
@@ -74,6 +74,9 @@ func (e ResponseStatusError) Error() string {
|
||||
return "the requested URL returned non-OK status: " + http.StatusText(int(e))
|
||||
}
|
||||
|
||||
// IsExecutable returns false.
|
||||
func (*httpArtifact) IsExecutable() bool { return false }
|
||||
|
||||
// Cure sends the http request and returns the resulting response body reader
|
||||
// wrapped to perform checksum validation. It is valid but not encouraged to
|
||||
// close the resulting [io.ReadCloser] before it is read to EOF, as that causes
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestHTTPGet(t *testing.T) {
|
||||
)
|
||||
wantPathname := base.Append(
|
||||
"identifier",
|
||||
"oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_",
|
||||
"COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue",
|
||||
)
|
||||
if pathname, checksum, err := c.Cure(f); err != nil {
|
||||
t.Fatalf("Cure: error = %v", err)
|
||||
@@ -158,7 +158,7 @@ func TestHTTPGet(t *testing.T) {
|
||||
"checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU": {Mode: 0400, Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
|
||||
"identifier/COBRUwkxpIvZWJggpRxn7HVXiw6epXZOex8jGRJKpowpwukV7GRBY_LBvOJNQHue": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
|
||||
+484
-165
File diff suppressed because it is too large
Load Diff
+257
-108
@@ -35,14 +35,14 @@ import (
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
//go:linkname unsafeOpen hakurei.app/internal/pkg.open
|
||||
func unsafeOpen(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, cures, jobs int,
|
||||
base *check.Absolute,
|
||||
lock bool,
|
||||
) (*pkg.Cache, error)
|
||||
var skipLock = func() pkg.CacheAttr {
|
||||
var attr pkg.CacheAttr
|
||||
*(*bool)(unsafe.Pointer(reflect.ValueOf(&attr).
|
||||
Elem().
|
||||
FieldByName("skipLock").
|
||||
UnsafeAddr())) = true
|
||||
return attr
|
||||
}()
|
||||
|
||||
var (
|
||||
// extension is a string uniquely identifying a set of custom [Artifact]
|
||||
@@ -140,11 +140,11 @@ type stubArtifact struct {
|
||||
cure func(t *pkg.TContext) error
|
||||
}
|
||||
|
||||
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifact) Dependencies() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
|
||||
func (*stubArtifact) IsExclusive() bool { return false }
|
||||
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifact) Inputs() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
|
||||
func (*stubArtifact) IsExclusive() bool { return false }
|
||||
|
||||
// A stubArtifactF implements [FloodArtifact] with hardcoded behaviour.
|
||||
type stubArtifactF struct {
|
||||
@@ -156,11 +156,11 @@ type stubArtifactF struct {
|
||||
cure func(f *pkg.FContext) error
|
||||
}
|
||||
|
||||
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifactF) Dependencies() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
|
||||
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
|
||||
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifactF) Inputs() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
|
||||
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
|
||||
|
||||
// A stubFile implements [FileArtifact] with hardcoded behaviour.
|
||||
type stubFile struct {
|
||||
@@ -170,6 +170,8 @@ type stubFile struct {
|
||||
stubArtifact
|
||||
}
|
||||
|
||||
func (*stubFile) IsExecutable() bool { return false }
|
||||
|
||||
func (a *stubFile) Cure(*pkg.RContext) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader(a.data)), a.err
|
||||
}
|
||||
@@ -330,7 +332,7 @@ func TestIdent(t *testing.T) {
|
||||
},
|
||||
nil,
|
||||
}, unique.Make[pkg.ID](pkg.MustDecode(
|
||||
"97Y85QewssfPbNIN9cyNhzD4e6dLHcDTU8rb2c34k-aCrZfBNXFUc0duPiLFFcw_",
|
||||
"fkmge-H56Ph2LzNNbEUjTypes8LfOxrF_CEXg07kq6ho_nbTNvzQde9-bjB7gyB_",
|
||||
))},
|
||||
}
|
||||
|
||||
@@ -339,7 +341,7 @@ func TestIdent(t *testing.T) {
|
||||
var cache *pkg.Cache
|
||||
if a, err := check.NewAbs(t.TempDir()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache, err = pkg.Open(t.Context(), msg, 0, 0, 0, a); err != nil {
|
||||
} else if cache, err = pkg.Open(t.Context(), msg, a, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(cache.Close)
|
||||
@@ -519,7 +521,10 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
|
||||
}
|
||||
|
||||
var scrubFunc func() error // scrub after hashing
|
||||
if c, err := pkg.Open(t.Context(), msg, flags, 1<<4, 0, base); err != nil {
|
||||
if c, err := pkg.Open(t.Context(), msg, base, &pkg.CacheAttr{
|
||||
Cures: 1 << 4,
|
||||
Flags: flags,
|
||||
}); err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
} else {
|
||||
t.Cleanup(c.Close)
|
||||
@@ -627,6 +632,7 @@ type cureStep struct {
|
||||
|
||||
pathname *check.Absolute
|
||||
output expectsKnown
|
||||
whence int
|
||||
err error
|
||||
}
|
||||
|
||||
@@ -646,7 +652,7 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
|
||||
|
||||
for _, step := range steps {
|
||||
t.Log("cure step:", step.name)
|
||||
if pathname, checksum, err := c.Cure(step.a); !reflect.DeepEqual(err, step.err) {
|
||||
if pathname, checksum, whence, err := c.CureWhence(step.a); !reflect.DeepEqual(err, step.err) {
|
||||
faults, _err := c.ReadFaults(step.a)
|
||||
if _err != nil {
|
||||
t.Errorf("ReadFaults: error = %v", _err)
|
||||
@@ -663,6 +669,8 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
|
||||
t.Logf("faulting cure terminated %s ago", time.Since(faults[0].Time()))
|
||||
}
|
||||
t.Fatalf("Cure: error = %v, want %v", err, step.err)
|
||||
} else if step.whence != whence {
|
||||
t.Fatalf("Cure: whence = %s, want %s", pkg.WhenceString(whence), pkg.WhenceString(step.whence))
|
||||
} else if step.pathname != ignorePathname && !pathname.Is(step.pathname) {
|
||||
t.Fatalf("Cure: pathname = %q, want %q", pathname, step.pathname)
|
||||
} else if step.output == nil || checksum != makeChecksumH(step.output.hash()) {
|
||||
@@ -774,28 +782,28 @@ func TestCache(t *testing.T) {
|
||||
identifier,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname, testdata, nil},
|
||||
), wantPathname, testdata, pkg.WNew, nil},
|
||||
|
||||
{"identical content", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
identifier0,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname0, testdata, nil},
|
||||
), wantPathname0, testdata, pkg.WCache, nil},
|
||||
|
||||
{"existing entry", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
identifier,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname, testdata, nil},
|
||||
), wantPathname, testdata, pkg.WCache, nil},
|
||||
|
||||
{"checksum mismatch", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
pkg.ID{0xff, 0},
|
||||
new(pkg.Checksum),
|
||||
testdata, nil,
|
||||
), nil, nil, &pkg.ChecksumMismatchError{
|
||||
), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: testdata.hash(),
|
||||
}},
|
||||
|
||||
@@ -816,13 +824,13 @@ func TestCache(t *testing.T) {
|
||||
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
|
||||
0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
|
||||
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
|
||||
{"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("artifact overridden to be incomplete"),
|
||||
}}, nil, nil, pkg.InvalidArtifactError(pkg.MustDecode(
|
||||
"E__uZ1sLIvb84vzSm5Uezb03RogsiaeTt1nfIVv8TKnnf4LqwtSi-smdHhlkZrUJ",
|
||||
}}, nil, nil, pkg.WNew, pkg.InvalidArtifactError(pkg.MustDecode(
|
||||
"poVrv3zNINbHd-WUJihwgWQwJpbHURFHfpY7Zux-ztto_bQhhS5PdpbNMjdkXv-V",
|
||||
))},
|
||||
|
||||
{"error passthrough", newStubFile(
|
||||
@@ -830,18 +838,18 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, stub.UniqueError(0xcafe),
|
||||
), nil, nil, stub.UniqueError(0xcafe)},
|
||||
), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"error caching", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, nil,
|
||||
), nil, nil, stub.UniqueError(0xcafe)},
|
||||
), nil, nil, pkg.WCache, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"cache hit bad type", overrideChecksum{testdata.hash(), overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
}}}, nil, nil, pkg.InvalidFileModeError(
|
||||
}}}, nil, nil, pkg.WCache, pkg.InvalidFileModeError(
|
||||
0400,
|
||||
)},
|
||||
|
||||
@@ -853,7 +861,7 @@ func TestCache(t *testing.T) {
|
||||
cure: func(f *pkg.FContext) error {
|
||||
panic("attempting to cure impossible artifact")
|
||||
},
|
||||
}, nil, nil, &pkg.DependencyCureError{
|
||||
}, nil, nil, pkg.WNew, &pkg.DependencyCureError{
|
||||
{
|
||||
A: failingFile,
|
||||
Err: struct {
|
||||
@@ -864,10 +872,10 @@ func TestCache(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
|
||||
if c0, err := unsafeOpen(
|
||||
if c0, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, base, false,
|
||||
base, &skipLock,
|
||||
); err != nil {
|
||||
t.Fatalf("open: error = %v", err)
|
||||
} else {
|
||||
@@ -875,7 +883,7 @@ func TestCache(t *testing.T) {
|
||||
cureMany(t, c0, []cureStep{
|
||||
{"cache hit ident", overrideIdent{
|
||||
id: identifier,
|
||||
}, wantPathname, testdata, nil},
|
||||
}, wantPathname, testdata, pkg.WCache, nil},
|
||||
|
||||
{"cache miss checksum match", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
@@ -886,7 +894,7 @@ func TestCache(t *testing.T) {
|
||||
), base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(testdata.hash()),
|
||||
), testdata, nil},
|
||||
), testdata, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
// cure after close
|
||||
@@ -1016,30 +1024,30 @@ func TestCache(t *testing.T) {
|
||||
{"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: makeSample,
|
||||
}}}, wantPathname, want, nil},
|
||||
}}}, wantPathname, want, pkg.WNew, nil},
|
||||
|
||||
{"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
}}}, wantPathname, want, nil},
|
||||
}}}, wantPathname, want, pkg.WCache, nil},
|
||||
|
||||
{"identical checksum", overrideIdent{id0, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: makeSample,
|
||||
}}, wantPathname0, want, nil},
|
||||
}}, wantPathname0, want, pkg.WNew, nil},
|
||||
|
||||
{"cure fault", overrideIdent{pkg.ID{0xff, 0}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xcafe))
|
||||
},
|
||||
}}, nil, nil, stub.UniqueError(0xcafe)},
|
||||
}}, nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"checksum mismatch", overrideChecksum{pkg.Checksum{}, overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), nil)
|
||||
},
|
||||
}}}, nil, nil, &pkg.ChecksumMismatchError{
|
||||
}}}, nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: pkg.MustDecode(
|
||||
"CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT",
|
||||
),
|
||||
@@ -1050,7 +1058,7 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 2},
|
||||
new(want.hash()),
|
||||
testdata, nil,
|
||||
), nil, nil, pkg.InvalidFileModeError(
|
||||
), nil, nil, pkg.WCache, pkg.InvalidFileModeError(
|
||||
fs.ModeDir | 0500,
|
||||
)},
|
||||
|
||||
@@ -1064,7 +1072,7 @@ func TestCache(t *testing.T) {
|
||||
_, err = io.ReadAll(r)
|
||||
return err
|
||||
},
|
||||
}}, nil, nil, &os.PathError{
|
||||
}}, nil, nil, pkg.WNew, &os.PathError{
|
||||
Op: "read",
|
||||
Path: base.Append(
|
||||
"checksum",
|
||||
@@ -1078,14 +1086,14 @@ func TestCache(t *testing.T) {
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return nil
|
||||
},
|
||||
}}, nil, nil, pkg.NoOutputError{}},
|
||||
}}, nil, nil, pkg.WNew, pkg.NoOutputError{}},
|
||||
|
||||
{"file output", overrideIdent{pkg.ID{0xff, 5}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return os.WriteFile(t.GetWorkDir().String(), []byte{0}, 0400)
|
||||
},
|
||||
}}, nil, nil, errors.New("non-file artifact produced regular file")},
|
||||
}}, nil, nil, pkg.WNew, errors.New("non-file artifact produced regular file")},
|
||||
|
||||
{"symlink output", overrideIdent{pkg.ID{0xff, 6}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1095,7 +1103,7 @@ func TestCache(t *testing.T) {
|
||||
t.GetWorkDir().String(),
|
||||
)
|
||||
},
|
||||
}}, nil, nil, pkg.InvalidFileModeError(
|
||||
}}, nil, nil, pkg.WNew, pkg.InvalidFileModeError(
|
||||
fs.ModeSymlink | 0777,
|
||||
)},
|
||||
|
||||
@@ -1115,8 +1123,8 @@ func TestCache(t *testing.T) {
|
||||
},
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-",
|
||||
), want, nil},
|
||||
"gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9",
|
||||
), want, pkg.WNew, nil},
|
||||
|
||||
{"substitutable", &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
@@ -1134,14 +1142,14 @@ func TestCache(t *testing.T) {
|
||||
},
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f",
|
||||
), want, nil},
|
||||
"VGjpp7NVw3OYLpgOQumfM0KcJgY3suz6torykUczcg4bGT24ySkPn5hy-4dNqqkR",
|
||||
), want, pkg.WSubstitute, nil},
|
||||
})
|
||||
|
||||
if c0, err := unsafeOpen(
|
||||
if c0, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, base, false,
|
||||
base, &skipLock,
|
||||
); err != nil {
|
||||
t.Fatalf("open: error = %v", err)
|
||||
} else {
|
||||
@@ -1163,8 +1171,8 @@ func TestCache(t *testing.T) {
|
||||
},
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_",
|
||||
), want, nil},
|
||||
"zeZ4JEZ0atAKl6Am67cBID6-KR18nZGgeYfU4qTuYaWhQC4eAn0dyTXdIBH9Bos8",
|
||||
), want, pkg.WSubstitute, nil},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1188,15 +1196,15 @@ func TestCache(t *testing.T) {
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/zeZ4JEZ0atAKl6Am67cBID6-KR18nZGgeYfU4qTuYaWhQC4eAn0dyTXdIBH9Bos8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/___9_QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
|
||||
"identifier/_wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
|
||||
"identifier/_woAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/7lfQ4QwSpV8nw7IDh0JiQ_jqUPrPv3_Vfie034RxsSy-cy4vO8DVvxgpx2LW08oO")},
|
||||
"identifier/k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/VGjpp7NVw3OYLpgOQumfM0KcJgY3suz6torykUczcg4bGT24ySkPn5hy-4dNqqkR": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"identifier/gIH5eti07nBAhVti3ZTn8EIGOBCZWWvNpxg5CmCZlDzIC4mBdomPmQLeEpf1IQg9": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/OyBGorh72Z9kVw35JUa8FbqDbpR4DqT-MX1jic0uKN5PdYmUBiAF38BRsIRnBigf": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
"substitute/nWPg893oqn_YNN8kgfZrs_LVLwP90e0mKxqU8UwoazQh-yBPwhoviD7of6YALx-M": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
@@ -1235,7 +1243,7 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, stub.UniqueError(0xbad),
|
||||
), nil, nil, stub.UniqueError(0xbad)},
|
||||
), nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
|
||||
|
||||
{"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1246,7 +1254,7 @@ func TestCache(t *testing.T) {
|
||||
0400,
|
||||
)
|
||||
},
|
||||
}}, nil, nil, errors.New(
|
||||
}}, nil, nil, pkg.WNew, errors.New(
|
||||
"non-file artifact produced regular file",
|
||||
)},
|
||||
})
|
||||
@@ -1363,14 +1371,14 @@ func TestCache(t *testing.T) {
|
||||
}}}, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.ID{0xff, 0}),
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
|
||||
{"reject", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xfe, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xbad))
|
||||
},
|
||||
}}}, nil, nil, stub.UniqueError(0xbad)},
|
||||
}}}, nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
|
||||
|
||||
{"match", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1380,7 +1388,7 @@ func TestCache(t *testing.T) {
|
||||
}}}, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.ID{0xff, 1}),
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -1408,7 +1416,7 @@ func TestCache(t *testing.T) {
|
||||
), base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.Checksum{0xfe, 0}),
|
||||
), expectsChecksum{0xff, 0}, nil},
|
||||
), expectsChecksum{0xff, 0}, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
for _, p := range [][]string{
|
||||
@@ -1485,7 +1493,7 @@ func TestCache(t *testing.T) {
|
||||
), expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: 0444},
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
|
||||
{"substituted", substituted, base.Append(
|
||||
"identifier",
|
||||
@@ -1493,7 +1501,7 @@ func TestCache(t *testing.T) {
|
||||
), expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: 0444},
|
||||
}, nil},
|
||||
}, pkg.WSubstitute, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -1504,18 +1512,18 @@ func TestCache(t *testing.T) {
|
||||
"checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV": {Mode: 0400, Data: []byte("destroyed")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"identifier/L-A8SK4ZX631eyealbJVH08u5pAVEf2NMk8RmLlxl7BVADkU4hNjWD6pi5H7uL1F": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
|
||||
"identifier/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"identifier/aSMwvPAwdsIF9e1spuLyRNEc8aTFA4HRVasoNqGjxdm1laSMs2h2teGsoSzLp_pR": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
|
||||
"identifier/CLyyxJWn1yUGFs_0KnJ4ZSU2hH4-elvGFRB36x14LrNrKBJPxvORhL9O4Rc7oeYU": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
|
||||
"identifier/arv8a6z4i0x6pUb5Z2T-3iE4ETvyZj-uReHGKsS7uiBgMgKNEOzTGG3LIZb8vp0L": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/wILUy2izpj2sgKJVhGUGIAde1XVuqvp5BpFMIQHanT5Q8R6jK4QPVSrJsjZh-njV")},
|
||||
"identifier/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"identifier/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
"status/0Jmc-vGnNDlXTD3jxy-4DGxHW-2-2LtLZ9SXaJtDIqu4uyHfDwDbghNBQ2aYRpab": {Mode: fs.ModeSymlink | 0777, Data: []byte("dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM")},
|
||||
"status/VbVV2dFVosCriHnG9t5vwfW4lbHvzOkV2eYwpGpPJZOgNBc0g1wZAhbdKEweLqmW": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
|
||||
"status/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
|
||||
"status/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x")},
|
||||
"status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
|
||||
"status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/dzO8FEY9lu4hwRT6BfRZOX-uYGsC_5XH4jEJ7sJyThcmG9J_w1ArOAaUCGfL8wAM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
@@ -1586,14 +1594,14 @@ func TestCache(t *testing.T) {
|
||||
{"extern", a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(wantIdent.Value()),
|
||||
), wantOutput, nil},
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"substitute", _a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(_wantIdent.Value()),
|
||||
), _wantOutput, nil},
|
||||
), _wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"mismatch", kca, nil, nil, &pkg.ChecksumMismatchError{
|
||||
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
|
||||
Got: wantChecksum,
|
||||
}},
|
||||
})
|
||||
@@ -1607,17 +1615,163 @@ func TestCache(t *testing.T) {
|
||||
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/4HqRo4uTwRQjfy3d2cujMoDC_pC4iv20h4a7NYlx0UdbVuky18o5iK78TFEfPX2U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/7AZcJm58ghFyTVf_v2baSntgpsxkP5el7ti9dC77C29n8YTEqQW9jRW92KGNdYnz": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/c4aCI00C-ZVyo_FQDQLl1OYK4U_kjzxwrLdFDiXMHnbMcZXCkXo_nxUWauScZ_4V": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/cNoG77frXGRCJa7fUi1INKUEQg7L4qrX5acsSv-wqZdGZT7dQwM93rD3at6kSFFF": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/ofaXbB5gIza_7W4Rzo5XDe_8FwlCPKWn3TBcmGgFAkkTWMl5GXGmOzX89Jd2Mk2A": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||
"identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
"status/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: 0400, Data: []byte("\x00")},
|
||||
"status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/qOYrxy9ztKeOA96Os811_0Ox5sd8FBOxis6psJAnRJL5MLazFMaqmd4g7t7k1OHk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
|
||||
{"extern shallow", pkg.CExternShallow, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||
a := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("extern"),
|
||||
}
|
||||
wantIdent := c.Ident(a)
|
||||
wantOutput := expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
|
||||
}
|
||||
var wantChecksum pkg.Checksum
|
||||
if err := pkg.SumFS(
|
||||
&wantChecksum,
|
||||
fstest.MapFS(wantOutput),
|
||||
".",
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantChecksumH := unique.Make(wantChecksum)
|
||||
|
||||
_a := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("extern substitute"),
|
||||
deps: []pkg.Artifact{pkg.NewFile("", nil)},
|
||||
}
|
||||
_wantIdent := c.Ident(_a)
|
||||
_wantOutput := expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
}
|
||||
var _wantChecksum pkg.Checksum
|
||||
if err := pkg.SumFS(
|
||||
&_wantChecksum,
|
||||
fstest.MapFS(_wantOutput),
|
||||
".",
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_wantChecksumH := unique.Make(_wantChecksum)
|
||||
|
||||
kca := pkg.NewExec(
|
||||
"", "",
|
||||
new(pkg.Checksum), 0, false, false,
|
||||
fhs.AbsRoot, nil, fhs.AbsRoot, nil,
|
||||
)
|
||||
kcIdent := c.Ident(kca)
|
||||
|
||||
fia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input"),
|
||||
deps: []pkg.Artifact{_a},
|
||||
}
|
||||
fiaIdent := c.Ident(fia)
|
||||
|
||||
flia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input local"),
|
||||
deps: []pkg.Artifact{_a},
|
||||
}
|
||||
fliaIdent := c.Ident(flia)
|
||||
|
||||
h := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("hanging input"),
|
||||
}
|
||||
|
||||
fhia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input local"),
|
||||
deps: []pkg.Artifact{h},
|
||||
}
|
||||
fhiaIdent := c.Ident(fhia)
|
||||
|
||||
c.SetExternal(stubExtern{
|
||||
artifact: map[unique.Handle[pkg.ID]]pkg.Checksum{
|
||||
wantIdent: wantChecksum,
|
||||
_wantIdent: _wantChecksum,
|
||||
kcIdent: wantChecksum,
|
||||
fiaIdent: wantChecksum,
|
||||
fliaIdent: wantChecksum,
|
||||
fhiaIdent: wantChecksum,
|
||||
},
|
||||
checksum: map[unique.Handle[pkg.Checksum]]fstest.MapFS{
|
||||
wantChecksumH: fstest.MapFS(wantOutput),
|
||||
_wantChecksumH: fstest.MapFS(_wantOutput),
|
||||
},
|
||||
status: map[unique.Handle[pkg.ID]]string{
|
||||
wantIdent: "\x00",
|
||||
kcIdent: "unreachable",
|
||||
},
|
||||
})
|
||||
|
||||
cureMany(t, c, []cureStep{
|
||||
{"extern", a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(wantIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow extern", fia, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(fiaIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"substitute", _a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(_wantIdent.Value()),
|
||||
), _wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow local", flia, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(fliaIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow hanging", fhia, nil, nil,
|
||||
pkg.WNew, pkg.HangingInputError(c.Ident(h))},
|
||||
|
||||
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
|
||||
Got: wantChecksum,
|
||||
}},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
"checksum": {Mode: fs.ModeDir | 0700},
|
||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl": {Mode: fs.ModeDir | 0500},
|
||||
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/3fYJjSiWhklt7TK9MPVLGk5_8AIU8ostTcFPXULJf_qeAVG6pmC-Cqqu4ZhEXRxn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/mXlNz_v77nW7jstn_rJn4RL7dCQlkakM0y-HjO6tkDubtzaj-wCmW1hIr2Gk64_O": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
"status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"substitute/MccYezQ4pshkeBV4w_aAEIwvZdKHL3OAgAkR3ouZ43EF94Ur1HBHaN7njPfJAj50": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"substitute/VV5W0_DiA1iylaqbKFThp1ZpV_y1ccVS1XyqDnDaXoHQ-EEyPI4XFrQHcHOF2hWG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
@@ -1635,7 +1789,7 @@ func TestErrors(t *testing.T) {
|
||||
}{
|
||||
{"InvalidLookupError", pkg.InvalidLookupError{
|
||||
0xff, 0xf0,
|
||||
}, "attempting to look up non-dependency artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
|
||||
}, "attempting to look up non-input artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
|
||||
|
||||
{"InvalidArtifactError", pkg.InvalidArtifactError{
|
||||
0xff, 0xfd,
|
||||
@@ -1883,7 +2037,7 @@ func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
|
||||
func (earlyFailureF) Params(*pkg.IContext) {}
|
||||
func (earlyFailureF) IsExclusive() bool { return false }
|
||||
|
||||
func (a earlyFailureF) Dependencies() []pkg.Artifact {
|
||||
func (a earlyFailureF) Inputs() []pkg.Artifact {
|
||||
deps := make([]pkg.Artifact, a)
|
||||
for i := range deps {
|
||||
deps[i] = a - 1
|
||||
@@ -1901,7 +2055,7 @@ func (a earlyFailureF) Cure(*pkg.FContext) error {
|
||||
func BenchmarkEarlyDCE(b *testing.B) {
|
||||
msg := message.New(log.New(os.Stderr, "dce: ", 0))
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
c, err := pkg.Open(b.Context(), msg, 0, 0, 0, check.MustAbs(b.TempDir()))
|
||||
c, err := pkg.Open(b.Context(), msg, check.MustAbs(b.TempDir()), nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -1950,7 +2104,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, check.MustAbs(container.Nonexistent),
|
||||
check.MustAbs(container.Nonexistent),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -1978,7 +2133,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2000,7 +2156,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2021,7 +2178,7 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"), nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2074,8 +2231,8 @@ func TestExtensionRegister(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(log.Default()),
|
||||
0, 0, 0,
|
||||
check.MustAbs(container.Nonexistent),
|
||||
nil,
|
||||
); !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2113,7 +2270,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
pkg.Register(pkg.KindCustomOffset, nil)
|
||||
|
||||
t.Cleanup(func() { opened = false })
|
||||
_, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
|
||||
_, _ = pkg.Open(nil, nil, nil, nil)
|
||||
panic("unreachable")
|
||||
})
|
||||
|
||||
@@ -2124,11 +2281,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); err != nil {
|
||||
if c, err := pkg.Open(t.Context(), nil, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
c.Close()
|
||||
@@ -2156,8 +2309,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
}
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Fatalf("Open: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
@@ -2178,8 +2330,8 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, pkg.ErrWouldPromote) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2192,8 +2344,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
pkg.CPromoteVariant, 0, 0,
|
||||
base,
|
||||
base, &pkg.CacheAttr{Flags: pkg.CPromoteVariant},
|
||||
); err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
} else {
|
||||
@@ -2218,8 +2369,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2236,8 +2386,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
|
||||
+15
-2
@@ -16,6 +16,8 @@ type tarArtifact struct {
|
||||
f Artifact
|
||||
}
|
||||
|
||||
var _ CuresExempt = new(tarArtifact)
|
||||
|
||||
// tarArtifactNamed embeds tarArtifact for a [fmt.Stringer] tarball.
|
||||
type tarArtifactNamed struct {
|
||||
tarArtifact
|
||||
@@ -56,8 +58,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a *tarArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a *tarArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -170,6 +172,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
break
|
||||
|
||||
case tar.TypeChar:
|
||||
t.GetMessage().Verbosef(
|
||||
"%sskipping character device %d, %d %q%s",
|
||||
t.cache.sgrWarn, header.Devmajor, header.Devminor, header.Name, t.cache.sgrRes,
|
||||
)
|
||||
continue
|
||||
|
||||
case tar.TypeXGlobalHeader:
|
||||
continue // ignore
|
||||
|
||||
@@ -211,3 +220,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindTar] implementation often at the end of a
|
||||
// [FileArtifact] pipeline.
|
||||
func (*tarArtifact) CuresExempt() {}
|
||||
|
||||
@@ -80,8 +80,8 @@ func TestTar(t *testing.T) {
|
||||
"checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/T68YqeEW5moiwVe4J0wPvjERgyMUd4k_cKKxTcQx6AXqZaQAuuryu-Iv-qxDV6-T": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
||||
"identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
||||
"identifier/7OZ5ErCxUJyRnaaFvUKhTryjsJAoOBUR2MZpUB1DD57jRa09Xxsh9BUs0dM9z5uH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
||||
"identifier/paWdPW_BowV3345c4GP4xxSNgxVs_7F09m9m7OaH5XbyuI3dTGZ-kFPOXFbwgr5O": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -104,8 +104,8 @@ func TestTar(t *testing.T) {
|
||||
"checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/WbWIIUGl6bqDBsjU-UB69JqOWLjG5waiUJBUBGeeRp3V7FBbwaBe3sG1qm7DlPSk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
||||
"identifier/e3BECw_x_vDyTvj2P48MJVgwpgALeXQ90Ye2Y8gr6SwIPtMup6SR2LVcCTDRGpVi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
||||
"identifier/1g2Tcg7pOJkZFxlKploBm4U0vIyMYbxDkcwwydwsF9BMs-w-knFJS41jnqOt16jT": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
||||
"identifier/7OZ5ErCxUJyRnaaFvUKhTryjsJAoOBUR2MZpUB1DD57jRa09Xxsh9BUs0dM9z5uH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -212,24 +212,24 @@ func checkTarHTTP(
|
||||
&client,
|
||||
"file:///testdata",
|
||||
testdataChecksum,
|
||||
), pkg.Gzip)), ignorePathname, want, nil},
|
||||
), pkg.Gzip)), ignorePathname, want, pkg.WNew, nil},
|
||||
|
||||
{"directory", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDir,
|
||||
pkg.Gzip,
|
||||
)), ignorePathname, want, nil},
|
||||
)), ignorePathname, want, pkg.WNew, nil},
|
||||
|
||||
{"multiple entries", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDirMulti,
|
||||
pkg.Gzip,
|
||||
)), nil, nil, errors.New(
|
||||
)), nil, nil, pkg.WNew, errors.New(
|
||||
"input directory does not contain a single regular file",
|
||||
)},
|
||||
|
||||
{"bad type", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDirType,
|
||||
pkg.Gzip,
|
||||
)), nil, nil, errors.New(
|
||||
)), nil, nil, pkg.WNew, errors.New(
|
||||
"input directory does not contain a single regular file",
|
||||
)},
|
||||
|
||||
@@ -239,6 +239,6 @@ func checkTarHTTP(
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return stub.UniqueError(0xcafe)
|
||||
},
|
||||
}), nil, nil, stub.UniqueError(0xcafe)},
|
||||
}), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ const (
|
||||
jobsLE = `"$(expr ` + jobsE + ` '*' 2)"`
|
||||
// jobsLFlagE is expression for flag with double of preferred job count.
|
||||
jobsLFlagE = `"-j$(expr ` + jobsE + ` '*' 2)"`
|
||||
|
||||
// loadE is expression for preferred loadavg target set by [pkg].
|
||||
loadE = `"$` + pkg.EnvLoad + `"`
|
||||
// loadFlagE is expression for flag with preferred loadavg target.
|
||||
loadFlagE = `"-l$` + pkg.EnvLoad + `"`
|
||||
)
|
||||
|
||||
// newTar wraps [pkg.NewHTTPGetTar] with a simpler function signature.
|
||||
@@ -102,7 +107,7 @@ func skipGNUTests(tests ...int64) string {
|
||||
buf.WriteString(strconv.Itoa(int(n - 1)))
|
||||
buf.WriteString(" ")
|
||||
}
|
||||
if i == len(tests)-1 || tests[i+1] != n+1 {
|
||||
if i == len(tests)-1 || (tests[i+1] != n+1 && tests[i+1] != n+2) {
|
||||
buf.WriteString(strconv.Itoa(int(n + 1)))
|
||||
buf.WriteString("-")
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ func TestSkipGNUTests(t *testing.T) {
|
||||
}{
|
||||
{[]int64{764}, "1-763 765-"},
|
||||
{[]int64{764, 0xcafe, 37, 9}, "1-8 10-36 38-763 765-51965 51967-"},
|
||||
{[]int64{168, 170, 623, 764}, "1-167 169 171-622 624-763 765-"},
|
||||
{[]int64{1, 2, 0xbed}, "3-3052 3054-"},
|
||||
{[]int64{3, 4}, "1-2 5-"},
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
// busyboxBin is a busybox binary distribution installed under bin/busybox.
|
||||
type busyboxBin struct {
|
||||
// Underlying busybox binary.
|
||||
bin pkg.FileArtifact
|
||||
}
|
||||
|
||||
// Kind returns the hardcoded [pkg.Kind] value.
|
||||
func (a busyboxBin) Kind() pkg.Kind { return kindBusyboxBin }
|
||||
|
||||
// Params is a noop.
|
||||
func (a busyboxBin) Params(*pkg.IContext) {}
|
||||
|
||||
// IsExclusive returns false: Cure performs a trivial filesystem write.
|
||||
func (busyboxBin) IsExclusive() bool { return false }
|
||||
|
||||
// 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),
|
||||
)}),
|
||||
)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ type CMakeHelper struct {
|
||||
var _ Helper = new(CMakeHelper)
|
||||
|
||||
// extra returns the cmake handle alongside either ninja or make.
|
||||
func (attr *CMakeHelper) extra(int) P {
|
||||
func (attr *CMakeHelper) extra() P {
|
||||
if attr != nil && attr.Make {
|
||||
return P{_cmake, _make}
|
||||
}
|
||||
@@ -61,10 +61,10 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
|
||||
}
|
||||
|
||||
generate := "Ninja"
|
||||
test := "ninja " + jobsFlagE + " test"
|
||||
test := "ninja " + jobsFlagE + " " + loadFlagE + " test"
|
||||
if attr.Make {
|
||||
generate = "'Unix Makefiles'"
|
||||
test = "make " + jobsFlagE + " test"
|
||||
test = "make " + jobsFlagE + " " + loadFlagE + " test"
|
||||
}
|
||||
if attr.Test != "" {
|
||||
test = attr.Test
|
||||
@@ -84,6 +84,7 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
|
||||
|
||||
return `
|
||||
cmake -G ` + generate + ` \
|
||||
-Wno-author -Wno-unused-cli \
|
||||
-DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||
-DCMAKE_CXX_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||
@@ -97,7 +98,7 @@ cmake -G ` + generate + ` \
|
||||
}), " \\\n\t") + ` \
|
||||
-DCMAKE_INSTALL_PREFIX=/system \
|
||||
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
|
||||
cmake --build . --parallel=` + jobsE + `
|
||||
cmake --build . --parallel=` + jobsE + ` -- ` + loadFlagE + `
|
||||
DESTDIR=/work cmake --install .
|
||||
` + script
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ func init() {
|
||||
a := cureEtc{}
|
||||
if r.ReadUint32() == 0 {
|
||||
a.minimal = true
|
||||
} else {
|
||||
r.Next()
|
||||
}
|
||||
if _, ok := r.Finalise(); ok {
|
||||
panic(pkg.ErrUnexpectedChecksum)
|
||||
@@ -118,8 +120,8 @@ func init() {
|
||||
// IsExclusive returns false: Cure performs a few trivial filesystem writes.
|
||||
func (cureEtc) IsExclusive() bool { return false }
|
||||
|
||||
// Dependencies returns a slice containing the backing iana-etc release.
|
||||
func (a cureEtc) Dependencies() []pkg.Artifact {
|
||||
// Inputs returns a slice containing the backing iana-etc release.
|
||||
func (a cureEtc) Inputs() []pkg.Artifact {
|
||||
if !a.minimal {
|
||||
return []pkg.Artifact{ianaEtc}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
// gentooOverlay are symlinks on top of a Gentoo LLVM stage3 tarball for
|
||||
// compatibility with the Rosa OS stage0 distribution.
|
||||
type gentooOverlay struct{ stage3 pkg.Artifact }
|
||||
|
||||
// Kind returns the hardcoded [pkg.Kind] value.
|
||||
func (a gentooOverlay) Kind() pkg.Kind { return kindGentooOverlay }
|
||||
|
||||
// Params is a noop.
|
||||
func (a gentooOverlay) Params(*pkg.IContext) {}
|
||||
|
||||
// IsExclusive returns false: Cure performs a trivial filesystem write.
|
||||
func (gentooOverlay) IsExclusive() bool { return false }
|
||||
|
||||
// Inputs returns the underlying Gentoo stage3.
|
||||
func (a gentooOverlay) Inputs() []pkg.Artifact {
|
||||
return []pkg.Artifact{a.stage3}
|
||||
}
|
||||
|
||||
func init() {
|
||||
pkg.Register(kindGentooOverlay, func(r *pkg.IRReader) pkg.Artifact {
|
||||
a := gentooOverlay{r.Next()}
|
||||
if _, ok := r.Finalise(); ok {
|
||||
panic(pkg.ErrUnexpectedChecksum)
|
||||
}
|
||||
return a
|
||||
})
|
||||
}
|
||||
|
||||
// String returns a hardcoded name.
|
||||
func (a gentooOverlay) String() string { return "gentoo-overlay" }
|
||||
|
||||
// Revision returns a hardcoded value incremented on layout changes.
|
||||
func (a gentooOverlay) Revision() uint64 { return 0 }
|
||||
|
||||
// Cure installs the overlay.
|
||||
func (a gentooOverlay) Cure(f *pkg.FContext) (err error) {
|
||||
pathname, _ := f.GetArtifact(a.stage3)
|
||||
var stage3 *os.Root
|
||||
if stage3, err = os.OpenRoot(pathname.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
closeErr := stage3.Close()
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
fsys := stage3.FS()
|
||||
|
||||
system := f.GetWorkDir().Append("system")
|
||||
bin := system.Append("bin")
|
||||
if err = os.MkdirAll(bin.String(), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
linknames := []string{
|
||||
"../../bin/sh",
|
||||
}
|
||||
|
||||
var dents []os.DirEntry
|
||||
|
||||
const llvm = "usr/lib/llvm"
|
||||
dents, err = fs.ReadDir(fsys, llvm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(dents) != 1 {
|
||||
return errors.New("stage3 /" + llvm + " contains more than one entry")
|
||||
}
|
||||
|
||||
llvmBin := filepath.Join(llvm, dents[0].Name(), "bin")
|
||||
dents, err = fs.ReadDir(fsys, llvmBin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, dent := range dents {
|
||||
linknames = append(linknames, filepath.Join(
|
||||
"../..",
|
||||
llvmBin,
|
||||
dent.Name(),
|
||||
))
|
||||
}
|
||||
|
||||
for _, linkname := range linknames {
|
||||
if err = os.Symlink(
|
||||
linkname,
|
||||
bin.Append(filepath.Base(linkname)).String(),
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
+14
-7
@@ -20,19 +20,26 @@ func (t Toolchain) NewViaGit(
|
||||
return t.New(strings.TrimSuffix(
|
||||
path.Base(url),
|
||||
".git",
|
||||
)+"-src-"+path.Base(rev), THostNet, t.Append(nil,
|
||||
_nssCACert,
|
||||
_git,
|
||||
), &checksum, nil, `
|
||||
)+"-src", path.Base(rev), nil, &PackageAttr{
|
||||
KnownChecksum: &checksum,
|
||||
|
||||
HostNet: true,
|
||||
Paths: []pkg.ExecPath{resolvconf()},
|
||||
}, &GenericHelper{
|
||||
Build: `
|
||||
git \
|
||||
-c advice.detachedHead=false \
|
||||
clone \
|
||||
--depth=1 \
|
||||
--revision=`+rev+` \
|
||||
--revision=` + rev + ` \
|
||||
--shallow-submodules \
|
||||
--recurse-submodules \
|
||||
`+url+` \
|
||||
` + url + ` \
|
||||
/work
|
||||
rm -rf /work/.git
|
||||
`, resolvconf())
|
||||
`,
|
||||
},
|
||||
_nssCACert,
|
||||
_git,
|
||||
)
|
||||
}
|
||||
|
||||
+10
-28
@@ -13,7 +13,7 @@ func (t Toolchain) newGo(
|
||||
script string,
|
||||
boot ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
return t.NewPackage("go", version, newTar(
|
||||
return t.New("go", version, newTar(
|
||||
"https://go.dev/dl/go"+version+".src.tar.gz",
|
||||
checksum,
|
||||
pkg.Gzip,
|
||||
@@ -56,16 +56,15 @@ ln -s \
|
||||
|
||||
func init() {
|
||||
const (
|
||||
version = "1.26.4"
|
||||
checksum = "fpqJlxa41wKRtbnviYNLk9VxgcL-5oIEDxsriF8svU6kNwQW70oRRA9gTz_ImVoB"
|
||||
version = "1.25.12"
|
||||
checksum = "XNrGD_boJl2-El_a_T3BuTcMin_WPoU-FGddcNG8dcXA8n2QuxZB7kaUaCWu60QX"
|
||||
)
|
||||
meta := Metadata{
|
||||
Name: "go",
|
||||
Description: "the Go programming language toolchain",
|
||||
Name: "go-bootstrap",
|
||||
Description: "the Go programming language toolchain (bootstrap)",
|
||||
Website: "https://go.dev",
|
||||
Version: version,
|
||||
|
||||
ID: 1227,
|
||||
Exclude: true,
|
||||
}
|
||||
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
var (
|
||||
@@ -76,7 +75,7 @@ func init() {
|
||||
)
|
||||
switch t.arch {
|
||||
case "amd64":
|
||||
bootstrapEarly = []pkg.Artifact{t.NewPackage("go", "1.4-bootstrap", newTar(
|
||||
bootstrapEarly = []pkg.Artifact{t.New("go", "1.4-bootstrap", newTar(
|
||||
"https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
|
||||
"8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23",
|
||||
pkg.Gzip,
|
||||
@@ -152,8 +151,8 @@ sed -i \
|
||||
)
|
||||
|
||||
go125 := t.newGo(
|
||||
"1.25.11",
|
||||
"cnqAQ8wpVZXcM6nHAfSqFkIW4L3H73ALB9rBfKUBbfgg4_pOF3I9zOZARgYQ6MR2",
|
||||
version,
|
||||
checksum,
|
||||
[]string{"CGO_ENABLED=0"}, `
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
@@ -165,23 +164,6 @@ rm \
|
||||
`, go123,
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
return &meta, go125
|
||||
})
|
||||
}
|
||||
|
||||
+37
-186
@@ -1,27 +1,25 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
var (
|
||||
_llvmSource = H("llvm-project")
|
||||
_muslHeaders = H("musl-headers")
|
||||
_earlyCompilerRT = H("early-compiler-rt")
|
||||
_earlyRuntimes = H("early-runtimes")
|
||||
_musl = H("musl")
|
||||
_llvmSource = H("llvm-project")
|
||||
_muslHeaders = H("musl-headers")
|
||||
_earlyRuntimes = H("early-runtimes")
|
||||
_musl = H("musl")
|
||||
|
||||
_bash = H("bash")
|
||||
_gawk = H("gawk")
|
||||
_coreutils = H("coreutils")
|
||||
_diffutils = H("diffutils")
|
||||
_findutils = H("findutils")
|
||||
_bash = H("bash")
|
||||
_awk = H("awk")
|
||||
_pythonEarly = H("python-early")
|
||||
_coreutils = H("coreutils")
|
||||
_diffutils = H("diffutils")
|
||||
_findutils = H("findutils")
|
||||
|
||||
_zlib = H("zlib")
|
||||
_zstd = H("zstd")
|
||||
@@ -50,165 +48,6 @@ func litArgs(verbose bool, skipChecks ...string) string {
|
||||
}
|
||||
|
||||
func init() {
|
||||
var llvmPatches []KV
|
||||
for _, name := range [...]string{
|
||||
"increase-stack-size-unconditional",
|
||||
"add-rosa-vendor",
|
||||
"xfail-broken-tests",
|
||||
"path-system-include",
|
||||
"path-system-libraries",
|
||||
} {
|
||||
p, err := fs.ReadFile(nativeB, "package/llvm/"+name+".patch")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
llvmPatches = append(llvmPatches, KV{
|
||||
name,
|
||||
unsafe.String(unsafe.SliceData(p), len(p)),
|
||||
})
|
||||
}
|
||||
|
||||
native.MustRegister("early-compiler-rt", func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
meta := Metadata{
|
||||
Name: "early-compiler-rt",
|
||||
Description: "early LLVM runtime: compiler-rt",
|
||||
|
||||
Dependencies: P{_musl},
|
||||
}
|
||||
_meta, source := t.MustLoad(_llvmSource)
|
||||
meta.Version = _meta.Version
|
||||
major, _, _ := strings.Cut(meta.Version, ".")
|
||||
return &meta, t.NewPackage("early-compiler-rt", meta.Version, source, &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"compiler-rt"},
|
||||
|
||||
Cache: []KV{
|
||||
{"ENABLE_LINKER_BUILD_ID", "ON"},
|
||||
|
||||
// libc++ not yet available
|
||||
{"CMAKE_CXX_COMPILER_TARGET", ""},
|
||||
|
||||
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_ENABLE_RTTI", "ON"},
|
||||
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
|
||||
{"LLVM_LINK_LLVM_DYLIB", "ON"},
|
||||
{"LLVM_ENABLE_PER_TARGET_RUNTIME_DIR", "ON"},
|
||||
|
||||
{"COMPILER_RT_BUILD_BUILTINS", "ON"},
|
||||
{"COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"},
|
||||
{"COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"},
|
||||
{"COMPILER_RT_SANITIZERS_TO_BUILD", "asan"},
|
||||
{"COMPILER_RT_BUILD_GWP_ASAN", "OFF"},
|
||||
|
||||
// does not work without libunwind
|
||||
{"COMPILER_RT_BUILD_CTX_PROFILE", "OFF"},
|
||||
{"COMPILER_RT_BUILD_LIBFUZZER", "OFF"},
|
||||
{"COMPILER_RT_BUILD_MEMPROF", "OFF"},
|
||||
{"COMPILER_RT_BUILD_PROFILE", "OFF"},
|
||||
{"COMPILER_RT_BUILD_XRAY", "OFF"},
|
||||
},
|
||||
SkipTest: true,
|
||||
Script: `
|
||||
mkdir -p "/work/system/lib/clang/` + major + `/lib/"
|
||||
ln -s \
|
||||
"../../../${ROSA_TRIPLE}" \
|
||||
"/work/system/lib/clang/` + major + `/lib/"
|
||||
|
||||
ln -s \
|
||||
"clang_rt.crtbegin-` + t.linuxArch() + `.o" \
|
||||
"/work/system/lib/${ROSA_TRIPLE}/crtbeginS.o"
|
||||
ln -s \
|
||||
"clang_rt.crtend-` + t.linuxArch() + `.o" \
|
||||
"/work/system/lib/${ROSA_TRIPLE}/crtendS.o"
|
||||
`,
|
||||
},
|
||||
_python,
|
||||
|
||||
_muslHeaders,
|
||||
_kernelHeaders,
|
||||
)
|
||||
})
|
||||
|
||||
native.MustRegister("early-runtimes", func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
meta := Metadata{
|
||||
Name: "early-runtimes",
|
||||
Description: "early LLVM runtimes: libunwind, libcxx, libcxxabi",
|
||||
|
||||
Dependencies: P{
|
||||
_earlyCompilerRT,
|
||||
},
|
||||
}
|
||||
_meta, source := t.MustLoad(_llvmSource)
|
||||
meta.Version = _meta.Version
|
||||
|
||||
return &meta, t.NewPackage("early-runtimes", meta.Version, source, &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"runtimes"},
|
||||
|
||||
Cache: []KV{
|
||||
{"ENABLE_LINKER_BUILD_ID", "ON"},
|
||||
|
||||
// libc++ not yet available
|
||||
{"CMAKE_CXX_COMPILER_WORKS", "ON"},
|
||||
|
||||
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_ENABLE_RTTI", "ON"},
|
||||
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
|
||||
{"LLVM_LINK_LLVM_DYLIB", "ON"},
|
||||
{"LLVM_ENABLE_RUNTIMES", "'libunwind;libcxx;libcxxabi'"},
|
||||
|
||||
{"LIBUNWIND_ENABLE_ASSERTIONS", "OFF"},
|
||||
{"LIBUNWIND_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXX_HAS_MUSL_LIBC", "ON"},
|
||||
{"LIBCXX_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXX_CXX_ABI", "libcxxabi"},
|
||||
{"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"},
|
||||
{"LIBCXX_HARDENING_MODE", "fast"},
|
||||
{"LIBCXX_HAS_ATOMIC_LIB", "OFF"},
|
||||
{"LIBCXXABI_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
|
||||
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "OFF"},
|
||||
{"LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL", "OFF"},
|
||||
|
||||
{"LLVM_ENABLE_ZLIB", "FORCE_ON"},
|
||||
{"LLVM_ENABLE_ZSTD", "FORCE_ON"},
|
||||
{"LLVM_ENABLE_LIBXML2", "OFF"},
|
||||
},
|
||||
SkipTest: true,
|
||||
},
|
||||
_python,
|
||||
|
||||
_zlib,
|
||||
_zstd,
|
||||
_earlyCompilerRT,
|
||||
_kernelHeaders,
|
||||
)
|
||||
})
|
||||
|
||||
const (
|
||||
version = "22.1.7"
|
||||
checksum = "GFjsoTzJ72YWQuAaNmlO67IIkoZ8Z12u3n0dOEMSpltmyXUJp8e3cccWDrscXILZ"
|
||||
)
|
||||
|
||||
native.MustRegister("llvm-project", func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
meta := Metadata{
|
||||
Name: "llvm-project",
|
||||
Description: "LLVM monorepo with Rosa OS patches",
|
||||
Version: version,
|
||||
|
||||
ID: 1830,
|
||||
}
|
||||
return &meta, t.NewPatchedSource("llvm-"+version, newFromGitHub(
|
||||
"llvm/llvm-project",
|
||||
"llvmorg-"+version,
|
||||
checksum,
|
||||
), true, llvmPatches...)
|
||||
})
|
||||
|
||||
native.MustRegister("llvm", func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
meta := Metadata{
|
||||
Name: "llvm",
|
||||
@@ -244,9 +83,11 @@ ln -s \
|
||||
{"LIBCXX_ENABLE_STATIC_ABI_LIBRARY", "OFF"},
|
||||
{"LIBCXX_HAS_MUSL_LIBC", "ON"},
|
||||
{"LIBCXX_HARDENING_MODE", "fast"},
|
||||
{"LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY", "ON"},
|
||||
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
|
||||
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "OFF"},
|
||||
{"LIBCXXABI_ENABLE_STATIC_UNWINDER", "ON"},
|
||||
{"LIBCXXABI_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY", "ON"},
|
||||
{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"},
|
||||
{"LLVM_INSTALL_UTILS", "ON"},
|
||||
{"LLVM_BUILD_LLVM_DYLIB", "ON"},
|
||||
@@ -299,6 +140,10 @@ ln -s \
|
||||
"CodeGen/PowerPC/ppc-tmmintrin.c",
|
||||
"CodeGen/PowerPC/ppc-smmintrin.c",
|
||||
"CodeGenCUDA/amdgpu-alias-undef-symbols.cu",
|
||||
// clang: deadlocks with LIBCXXABI_ENABLE_STATIC_UNWINDER
|
||||
"global-value-regex",
|
||||
"global-hex-value-regex",
|
||||
"check-globals",
|
||||
// cxx: fails on musl
|
||||
"close.dont-get-rid-of-buffer",
|
||||
"re/re.traits",
|
||||
@@ -339,8 +184,19 @@ ln -s \
|
||||
}...)
|
||||
}
|
||||
|
||||
return &meta, t.NewPackage("llvm", meta.Version, source, &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
return &meta, t.New("llvm", meta.Version, source, &PackageAttr{
|
||||
Exclusive: true,
|
||||
Bin: []string{
|
||||
"chmod",
|
||||
"mkdir",
|
||||
"rm",
|
||||
"tr",
|
||||
"awk",
|
||||
},
|
||||
|
||||
ScriptEarly: `
|
||||
rm -f /system/bin/clang++.cfg
|
||||
`,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"llvm"},
|
||||
|
||||
@@ -350,6 +206,10 @@ ln -s ld.lld /work/system/bin/ld
|
||||
ln -s clang /work/system/bin/cc
|
||||
ln -s clang /work/system/bin/cpp
|
||||
ln -s clang++ /work/system/bin/c++
|
||||
cat << EOF > /work/system/bin/clang++.cfg
|
||||
-static-libstdc++
|
||||
-Wl,--exclude-libs,libunwind.a:libc++.a:libc++experimental.a:libc++abi.a
|
||||
EOF
|
||||
`,
|
||||
|
||||
// LLVM_LINK_LLVM_DYLIB causes llvm test suite to leak system
|
||||
@@ -358,22 +218,13 @@ ln -s clang++ /work/system/bin/c++
|
||||
// on 3-stage determinism to test later stages.
|
||||
SkipTest: t.stage.isStage0(),
|
||||
|
||||
Test: `
|
||||
chmod +w /bin && ln -s \
|
||||
../system/bin/chmod \
|
||||
../system/bin/mkdir \
|
||||
../system/bin/rm \
|
||||
../system/bin/tr \
|
||||
../system/bin/awk \
|
||||
/bin
|
||||
ninja ` + jobsFlagE + ` check-all
|
||||
`,
|
||||
Test: "ninja " + jobsFlagE + " " + loadFlagE + " check-all",
|
||||
},
|
||||
_python,
|
||||
_pythonEarly,
|
||||
_perl,
|
||||
_diffutils,
|
||||
_bash,
|
||||
_gawk,
|
||||
_awk,
|
||||
_coreutils,
|
||||
_findutils,
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestLLVMInputs(t *testing.T) {
|
||||
const wantInputCount = 553
|
||||
const wantInputCount = 470
|
||||
|
||||
_, llvm := rosa.Native().Std().MustLoad(rosa.H("llvm"))
|
||||
var n int
|
||||
|
||||
+13
-9
@@ -52,15 +52,16 @@ type MakeHelper struct {
|
||||
var _ Helper = new(MakeHelper)
|
||||
|
||||
// extra returns make and other optional dependencies.
|
||||
func (attr *MakeHelper) extra(flag int) P {
|
||||
extra := P{_make}
|
||||
if (attr == nil || !attr.OmitDefaults) && flag&TEarly == 0 {
|
||||
extra = append(extra,
|
||||
_gawk,
|
||||
func (attr *MakeHelper) extra() P {
|
||||
if attr == nil || !attr.OmitDefaults {
|
||||
return P{
|
||||
_make,
|
||||
|
||||
_awk,
|
||||
_coreutils,
|
||||
)
|
||||
}
|
||||
}
|
||||
return extra
|
||||
return P{_make}
|
||||
}
|
||||
|
||||
// wantsChmod returns whether the build system needs to be generated.
|
||||
@@ -89,7 +90,7 @@ func (attr *MakeHelper) wantsDir() (string, bool) {
|
||||
if attr != nil && attr.InPlace {
|
||||
return helperInPlace, false
|
||||
}
|
||||
return `"$(mktemp -d)"`, false
|
||||
return "/cure/", true
|
||||
}
|
||||
|
||||
// script generates the cure script.
|
||||
@@ -160,7 +161,8 @@ func (attr *MakeHelper) script(t Toolchain, name string) string {
|
||||
|
||||
scriptMake := `
|
||||
make \
|
||||
` + jobsFlagE
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE
|
||||
if len(attr.Make) > 0 {
|
||||
scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t")
|
||||
}
|
||||
@@ -170,6 +172,8 @@ make \
|
||||
(!attr.SkipCheckEarly || !t.stage.isStage0()) {
|
||||
scriptMake += attr.ScriptCheckEarly + `make \
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE + ` \
|
||||
AM_COLOR_TESTS=always \
|
||||
`
|
||||
if len(attr.Check) > 0 {
|
||||
scriptMake += strings.Join(attr.Check, " \\\n\t")
|
||||
|
||||
+50
-15
@@ -5,10 +5,16 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _meson = H("meson")
|
||||
var (
|
||||
_muon = H("muon")
|
||||
_meson = H("meson")
|
||||
)
|
||||
|
||||
// MesonHelper builds and tests a meson project.
|
||||
type MesonHelper struct {
|
||||
// Use muon instead of meson.
|
||||
Muon bool
|
||||
|
||||
// Runs after setup.
|
||||
ScriptCompileEarly string
|
||||
// Runs after compile.
|
||||
@@ -18,6 +24,8 @@ type MesonHelper struct {
|
||||
|
||||
// Flags passed to the setup command.
|
||||
Setup []KV
|
||||
// Test suites to skip.
|
||||
SkipTests []string
|
||||
// Whether to skip meson test.
|
||||
SkipTest bool
|
||||
// Run tests with interactive input/output.
|
||||
@@ -27,7 +35,12 @@ type MesonHelper struct {
|
||||
var _ Helper = new(MesonHelper)
|
||||
|
||||
// extra returns hardcoded meson runtime dependencies.
|
||||
func (*MesonHelper) extra(int) P { return P{_meson} }
|
||||
func (attr *MesonHelper) extra() P {
|
||||
if !attr.isPython() {
|
||||
return P{_muon}
|
||||
}
|
||||
return P{_meson}
|
||||
}
|
||||
|
||||
// wantsChmod returns false.
|
||||
func (*MesonHelper) wantsChmod() bool { return false }
|
||||
@@ -41,6 +54,12 @@ func (*MesonHelper) scriptEarly() string { return "" }
|
||||
// wantsDir requests a new directory in TMPDIR.
|
||||
func (*MesonHelper) wantsDir() (string, bool) { return `"$(mktemp -d)"`, false }
|
||||
|
||||
// isPython returns whether the legacy python implementation is used.
|
||||
func (attr *MesonHelper) isPython() bool {
|
||||
return attr == nil ||
|
||||
!attr.Muon || len(attr.SkipTests) != 0 || attr.InteractiveTest
|
||||
}
|
||||
|
||||
// script generates the cure script.
|
||||
func (attr *MesonHelper) script(t Toolchain, name string) string {
|
||||
if attr == nil {
|
||||
@@ -52,41 +71,57 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
|
||||
scriptCompiled = "\n" + scriptCompiled
|
||||
}
|
||||
|
||||
python := attr.isPython()
|
||||
muon := "muon"
|
||||
compile := " samu " + jobsFlagE
|
||||
destdir := "-d"
|
||||
if python {
|
||||
muon = "meson"
|
||||
compile = " compile " + jobsFlagE + " " + loadFlagE
|
||||
destdir = "--destdir"
|
||||
}
|
||||
|
||||
var scriptTest string
|
||||
if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
|
||||
scriptTest = `
|
||||
meson test \
|
||||
` + muon + ` test \
|
||||
` + jobsFlagE + ` \
|
||||
-t 10`
|
||||
if python {
|
||||
scriptTest += ` \
|
||||
--print-errorlogs`
|
||||
} else {
|
||||
scriptTest += " -Rv"
|
||||
}
|
||||
if attr.InteractiveTest {
|
||||
scriptTest += ` \
|
||||
--interactive`
|
||||
}
|
||||
for _, suite := range attr.SkipTests {
|
||||
scriptTest += " \\\n\t--no-suite='" + suite + "'"
|
||||
}
|
||||
}
|
||||
|
||||
return `
|
||||
cd "$(mktemp -d)"
|
||||
meson setup \
|
||||
` + muon + ` setup \
|
||||
` + strings.Join(slices.Collect(func(yield func(string) bool) {
|
||||
for _, v := range append([]KV{
|
||||
{"wrap-mode", "nofallback"},
|
||||
{"wrap_mode", "nofallback"},
|
||||
{"prefix", "/system"},
|
||||
{"buildtype", "release"},
|
||||
}, attr.Setup...) {
|
||||
s := "-" + v[0]
|
||||
if len(v[0]) > 0 && v[0][0] != 'D' {
|
||||
s = "-" + s
|
||||
}
|
||||
s := v[0]
|
||||
if v[1] != "" {
|
||||
s += "=" + v[1]
|
||||
s = "-D" + s + "=" + v[1]
|
||||
}
|
||||
if !yield(s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}), " \\\n\t") + ` \
|
||||
. '/usr/src/` + name + `'
|
||||
meson compile` + scriptCompiled + scriptTest + `
|
||||
meson install \
|
||||
--destdir=/work
|
||||
'/usr/src/` + name + `'
|
||||
` + muon + compile + scriptCompiled + scriptTest + `
|
||||
` + muon + ` install \
|
||||
` + destdir + ` /work
|
||||
` + attr.Script
|
||||
}
|
||||
|
||||
+256
-113
@@ -14,6 +14,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unique"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
@@ -30,8 +31,8 @@ type Remote struct {
|
||||
c *http.Client
|
||||
}
|
||||
|
||||
// NewRemote returns a populated [Remote]
|
||||
func NewRemote(base string, pub ed25519.PublicKey, c *http.Client) (Remote, error) {
|
||||
// NewRemote returns a populated [Remote].
|
||||
func NewRemote(c *http.Client, base string, pub ed25519.PublicKey) (Remote, error) {
|
||||
u, err := url.Parse(base)
|
||||
return Remote{u, pub, c}, err
|
||||
}
|
||||
@@ -201,14 +202,261 @@ func (r Remote) Status(
|
||||
), nil
|
||||
}
|
||||
|
||||
// NewMirror returns an [http.Handler] for servicing mirror requests.
|
||||
// Mirror services requests made by [Remote].
|
||||
type Mirror struct {
|
||||
// Cache on-filesystem format.
|
||||
fsys fs.FS
|
||||
// Signs payloads.
|
||||
key ed25519.PrivateKey
|
||||
// Verbose output.
|
||||
msg message.Msg
|
||||
}
|
||||
|
||||
// Populate fills an empty root with a static mirror snapshot.
|
||||
func (m Mirror) Populate(root *os.Root) error {
|
||||
if dents, err := fs.ReadDir(root.FS(), "."); err != nil {
|
||||
return err
|
||||
} else if len(dents) > 0 {
|
||||
return syscall.ENOTEMPTY
|
||||
}
|
||||
|
||||
for _, name := range []string{
|
||||
dirArtifact,
|
||||
dirOutcome,
|
||||
dirStatus,
|
||||
} {
|
||||
if err := root.Mkdir(name, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var w *os.File
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "identifier"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf [2 * len(pkg.Checksum{})]byte
|
||||
if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
|
||||
name,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirArtifact, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.writeArtifact(&buf, w, nil)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "checksum"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf pkg.Checksum
|
||||
if err = pkg.Decode(&buf, name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fsys fs.FS
|
||||
fsys, err = fs.Sub(m.fsys, filepath.Join("checksum", name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirOutcome, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.msg.Verbosef("exporting outcome %s", name)
|
||||
err = pkg.Write(fsys, ".", w)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "status"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf [2 * len(pkg.Checksum{})]byte
|
||||
if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
|
||||
name,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirStatus, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.writeStatus(&buf, w, nil)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMirror returns a populated [Mirror] for servicing mirror requests.
|
||||
func NewMirror(
|
||||
msg message.Msg,
|
||||
fsys fs.FS,
|
||||
key ed25519.PrivateKey,
|
||||
) http.Handler {
|
||||
) Mirror {
|
||||
return Mirror{fsys, key, msg}
|
||||
}
|
||||
|
||||
// writeArtifact writes a signed dirArtifact response.
|
||||
func (m Mirror) writeArtifact(
|
||||
buf *[2 * len(pkg.Checksum{})]byte,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error {
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
if linkname, err := fs.ReadLink(m.fsys, filepath.Join(
|
||||
"identifier",
|
||||
ids,
|
||||
)); err != nil {
|
||||
return err
|
||||
} else if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
|
||||
filepath.Base(linkname),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
m.msg.Verbosef("serving artifact %s", ids)
|
||||
|
||||
if header != nil {
|
||||
header.Set(
|
||||
"Content-Length",
|
||||
strconv.Itoa(ed25519.SignatureSize+len(buf)),
|
||||
)
|
||||
}
|
||||
_, err := w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...))
|
||||
return err
|
||||
}
|
||||
|
||||
// writeOutcome writes a dirOutcome response.
|
||||
func (m Mirror) writeOutcome(
|
||||
buf *pkg.Checksum,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error {
|
||||
checksums := pkg.Encode(*buf)
|
||||
rel := filepath.Join("checksum", checksums)
|
||||
if _, err := fs.Lstat(m.fsys, rel); err != nil {
|
||||
return err
|
||||
}
|
||||
m.msg.Verbosef("serving outcome %s", checksums)
|
||||
|
||||
_fsys, err := fs.Sub(m.fsys, rel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var gw *gzip.Writer
|
||||
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
|
||||
return err
|
||||
}
|
||||
if header != nil {
|
||||
header.Set("Content-Encoding", "gzip")
|
||||
}
|
||||
if err = pkg.Write(_fsys, ".", gw); err != nil {
|
||||
_ = gw.Close()
|
||||
return err
|
||||
}
|
||||
return gw.Close()
|
||||
}
|
||||
|
||||
// writeStatus writes a signed dirStatus response.
|
||||
func (m Mirror) writeStatus(
|
||||
buf *[2 * len(pkg.Checksum{})]byte,
|
||||
w io.Writer,
|
||||
_ http.Header,
|
||||
) error {
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
f, err := m.fsys.Open(filepath.Join(
|
||||
"status",
|
||||
ids,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s, ok := f.(io.Seeker)
|
||||
if !ok {
|
||||
return &fs.PathError{Op: "seek", Path: ids, Err: fs.ErrInvalid}
|
||||
}
|
||||
m.msg.Verbosef("serving status %s", ids)
|
||||
|
||||
h := sha512.New384()
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
|
||||
if _, err = w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...)); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else if _, err = io.Copy(w, f); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
// writeF is a helper for writing a mirror response with error handling.
|
||||
func writeF[B any](
|
||||
m Mirror,
|
||||
w http.ResponseWriter,
|
||||
buf B,
|
||||
f func(
|
||||
buf B,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error,
|
||||
) {
|
||||
err := f(buf, w, w.Header())
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
m.msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Register configures an [http.ServeMux] for servicing mirror requests.
|
||||
func (m Mirror) Register(mux *http.ServeMux) {
|
||||
const identName = "ident"
|
||||
var mux http.ServeMux
|
||||
|
||||
mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func(
|
||||
w http.ResponseWriter,
|
||||
@@ -222,38 +470,7 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
if linkname, err := fs.ReadLink(fsys, filepath.Join(
|
||||
"identifier",
|
||||
ids,
|
||||
)); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
} else if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
|
||||
filepath.Base(linkname),
|
||||
); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving artifact %s", ids)
|
||||
|
||||
w.Header().Set(
|
||||
"Content-Length",
|
||||
strconv.Itoa(ed25519.SignatureSize+len(buf)),
|
||||
)
|
||||
if _, err := w.Write(append(
|
||||
ed25519.Sign(key, buf[:]),
|
||||
buf[:]...,
|
||||
)); err != nil {
|
||||
msg.Verbose(err)
|
||||
}
|
||||
writeF(m, w, &buf, m.writeArtifact)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/"+dirOutcome+"/{"+identName+"}", func(
|
||||
@@ -273,40 +490,7 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
checksums := pkg.Encode(buf)
|
||||
rel := filepath.Join("checksum", checksums)
|
||||
if _, err := fs.Lstat(fsys, rel); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving outcome %s", pkg.Encode(buf))
|
||||
|
||||
_fsys, err := fs.Sub(fsys, rel)
|
||||
if err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var gw *gzip.Writer
|
||||
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
if err = pkg.Write(_fsys, ".", gw); err != nil {
|
||||
msg.Verbose(err)
|
||||
}
|
||||
if err = gw.Close(); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
}
|
||||
writeF(m, w, &buf, m.writeOutcome)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/"+dirStatus+"/{"+identName+"}", func(
|
||||
@@ -321,47 +505,6 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
f, err := fsys.Open(filepath.Join(
|
||||
"status",
|
||||
ids,
|
||||
))
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
s, ok := f.(io.Seeker)
|
||||
if !ok {
|
||||
msg.GetLogger().Println("backing filesystem does not support seek")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving status %s", ids)
|
||||
|
||||
h := sha512.New384()
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
_ = f.Close()
|
||||
msg.Verbose(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
|
||||
if _, err = w.Write(append(ed25519.Sign(key, buf[:]), buf[:]...)); err != nil {
|
||||
msg.Verbose(err)
|
||||
return
|
||||
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
return
|
||||
} else if _, err = io.Copy(w, f); err != nil {
|
||||
msg.Verbose(err)
|
||||
return
|
||||
}
|
||||
writeF(m, w, &buf, m.writeStatus)
|
||||
})
|
||||
|
||||
return &mux
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/ed25519"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -30,7 +31,7 @@ func TestMirror(t *testing.T) {
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
|
||||
var c *pkg.Cache
|
||||
c, err = pkg.Open(t.Context(), msg, 0, 0, 0, base)
|
||||
c, err = pkg.Open(t.Context(), msg, base, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -52,14 +53,16 @@ func TestMirror(t *testing.T) {
|
||||
}
|
||||
wantChecksums := pkg.Encode(wantChecksum)
|
||||
|
||||
server := httptest.NewServer(rosa.NewMirror(msg, fstest.MapFS{
|
||||
var mux http.ServeMux
|
||||
rosa.NewMirror(msg, fstest.MapFS{
|
||||
"identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)},
|
||||
"checksum/" + wantChecksums: {Mode: os.ModeDir | 0500},
|
||||
}, priv))
|
||||
}, priv).Register(&mux)
|
||||
server := httptest.NewServer(&mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
var extern pkg.External
|
||||
extern, err = rosa.NewRemote("http://example.com:80", pub, server.Client())
|
||||
extern, err = rosa.NewRemote(server.Client(), "http://example.com:80", pub)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
From 8a80d895dfd779373363c3a4b62ecce5a549efb2 Mon Sep 17 00:00:00 2001
|
||||
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
|
||||
Date: Sat, 30 Mar 2024 10:17:10 +0100
|
||||
Subject: tools/attr.c: Add missing libgen.h include for basename(3)
|
||||
|
||||
Fixes compilation issue with musl and modern C99 compilers.
|
||||
|
||||
See: https://bugs.gentoo.org/926294
|
||||
---
|
||||
tools/attr.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tools/attr.c b/tools/attr.c
|
||||
index f12e4af..6a3c1e9 100644
|
||||
--- a/tools/attr.c
|
||||
+++ b/tools/attr.c
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
+#include <libgen.h>
|
||||
|
||||
#include <attr/attributes.h>
|
||||
|
||||
--
|
||||
cgit v1.1
|
||||
@@ -1,7 +1,7 @@
|
||||
diff --git a/test/attr.test b/test/attr.test
|
||||
index 6ce2f9b..e9bde92 100644
|
||||
--- a/test/attr.test
|
||||
+++ b/test/attr.test
|
||||
diff --git a/test/attr.run b/test/attr.run
|
||||
index 27d17f6..a4d60c0 100644
|
||||
--- a/test/attr.run
|
||||
+++ b/test/attr.run
|
||||
@@ -11,7 +11,7 @@ Try various valid and invalid names
|
||||
|
||||
$ touch f
|
||||
|
||||
@@ -3,25 +3,25 @@ package attr {
|
||||
website = "https://savannah.nongnu.org/projects/attr";
|
||||
anitya = 137;
|
||||
|
||||
version# = "2.5.2";
|
||||
version# = "2.6.0";
|
||||
source = remoteTar {
|
||||
url = "https://download.savannah.nongnu.org/releases/attr/"+
|
||||
"attr-"+version+".tar.gz";
|
||||
checksum = "YWEphrz6vg1sUMmHHVr1CRo53pFXRhq_pjN-AlG8UgwZK1y6m7zuDhxqJhD0SV0l";
|
||||
checksum = "pp-NvD1cMIwZycNwZGW2ez-PbTEpHxrRnVH27csj9QdN4oEBkEbJOZX1IIvKnTWS";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [
|
||||
"libgen-basename.patch",
|
||||
"musl-errno.patch",
|
||||
];
|
||||
|
||||
early = `
|
||||
ln -s ../../system/bin/perl /usr/bin
|
||||
`;
|
||||
patches = [ "musl-errno.patch" ];
|
||||
|
||||
bin = [ "perl" ];
|
||||
populateUsrBin = true;
|
||||
exec = make {};
|
||||
|
||||
inputs = [ perl ];
|
||||
inputs = [
|
||||
perl,
|
||||
|
||||
kernel-headers,
|
||||
];
|
||||
}
|
||||
|
||||
package acl {
|
||||
@@ -29,11 +29,11 @@ package acl {
|
||||
website = "https://savannah.nongnu.org/projects/acl";
|
||||
anitya = 16;
|
||||
|
||||
version# = "2.3.2";
|
||||
version# = "2.4.0";
|
||||
source = remoteTar {
|
||||
url = "https://download.savannah.nongnu.org/releases/acl/"+
|
||||
"acl-"+version+".tar.gz";
|
||||
checksum = "-fY5nwH4K8ZHBCRXrzLdguPkqjKI6WIiGu4dBtrZ1o0t6AIU73w8wwJz_UyjIS0P";
|
||||
checksum = "U2eaAsWrhhzEfhyprwHQQG55bFPZxtsHk1Usnd9Jb_g-H__pJod4H3RTrL4ipXDw";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
@@ -42,6 +42,6 @@ package acl {
|
||||
skipCheck = true;
|
||||
};
|
||||
|
||||
inputs = [ attr ];
|
||||
inputs = [ attr, kernel-headers ];
|
||||
runtime = [ attr ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
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 {
|
||||
omitDefaults = true;
|
||||
inPlace = true;
|
||||
skipConfigure = true;
|
||||
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,
|
||||
];
|
||||
}
|
||||
@@ -5,15 +5,19 @@ package bison {
|
||||
|
||||
version# = "3.8.2";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/bison/bison-"+version+".tar.gz";
|
||||
checksum = "BhRM6K7URj1LNOkIDCFDctSErLS-Xo5d9ba9seg10o6ACrgC1uNhED7CQPgIY29Y";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
toyboxEarly = true;
|
||||
exec = make {
|
||||
omitDefaults = true;
|
||||
check = [
|
||||
"TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests {
|
||||
tests = [
|
||||
// GNU-isms not implemented in toybox
|
||||
168, 170, 623,
|
||||
// clang miscompiles (SIGILL)
|
||||
764,
|
||||
];
|
||||
@@ -22,9 +26,5 @@ package bison {
|
||||
];
|
||||
};
|
||||
|
||||
inputs = [
|
||||
m4,
|
||||
diffutils,
|
||||
sed,
|
||||
];
|
||||
inputs = [ m4 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
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 {
|
||||
omitDefaults = true;
|
||||
};
|
||||
}
|
||||
@@ -13,16 +13,16 @@ package cairo {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Ddwrite": "enabled";
|
||||
"Dfontconfig": "enabled";
|
||||
"Dfreetype": "enabled";
|
||||
"dwrite": "enabled";
|
||||
"fontconfig": "enabled";
|
||||
"freetype": "enabled";
|
||||
|
||||
"Dpng": "enabled";
|
||||
"Dtee": "enabled";
|
||||
"Dxcb": "enabled";
|
||||
"Dxlib": "disabled";
|
||||
"Dxlib-xcb": "disabled";
|
||||
"Dzlib": "enabled";
|
||||
"png": "enabled";
|
||||
"tee": "enabled";
|
||||
"xcb": "enabled";
|
||||
"xlib": "disabled";
|
||||
"xlib-xcb": "disabled";
|
||||
"zlib": "enabled";
|
||||
};
|
||||
// runs the entire test suite in a single meson test
|
||||
interactiveTest = true;
|
||||
@@ -31,7 +31,7 @@ package cairo {
|
||||
};
|
||||
|
||||
inputs = [
|
||||
gawk,
|
||||
awk,
|
||||
|
||||
zlib,
|
||||
libpng,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
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
|
||||
)
|
||||
@@ -3,18 +3,15 @@ package cmake {
|
||||
website = "https://cmake.org";
|
||||
anitya = 306;
|
||||
|
||||
version# = "4.3.3";
|
||||
version# = "4.4.2";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "Kitware/CMake";
|
||||
tag = "v"+version;
|
||||
name = "cmake-"+version+".tar.gz";
|
||||
checksum = "VS-b6cN4S9hfNv3JOUAbAfI9nh3EeuVwY_IVgUdgq6VKwvfchhXwvvFAUcpZG6Ez";
|
||||
checksum = "IWlqJqJCZ6f-z-7Ft1U4ycvCX4riuihKale5NKWusiHemBgC3m5gCecrzikXoL7S";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [
|
||||
"bootstrap-test-no-openssl.patch",
|
||||
"disable-broken-tests-musl.patch",
|
||||
];
|
||||
patches = [ "disable-broken-tests-musl.patch" ];
|
||||
|
||||
// test suite expects writable source tree
|
||||
writable = true;
|
||||
@@ -32,6 +29,7 @@ package cmake {
|
||||
"--";
|
||||
"-DCMAKE_USE_OPENSSL": "OFF";
|
||||
"-DCMake_TEST_NO_NETWORK": "ON";
|
||||
"-DCMake_TEST_BOOTSTRAP": "OFF";
|
||||
};
|
||||
|
||||
check = [
|
||||
|
||||
@@ -3,10 +3,10 @@ package curl {
|
||||
website = "https://curl.se";
|
||||
anitya = 381;
|
||||
|
||||
version# = "8.20.0";
|
||||
version# = "8.21.0";
|
||||
source = remoteTar {
|
||||
url = "https://curl.se/download/curl-"+version+".tar.bz2";
|
||||
checksum = "xyHXwrngIRGMasuzhn-I5MSCOhktwINbsWt1f_LuR-5jRVvyx_g6U1EQfDLEbr9r";
|
||||
checksum = "lJSm8bVjS0OmsarEdbvejdQdvXsb7yGarlr6oMtA9FW1EXOga8zZxa1LPtfaq_qX";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ package dbus {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Depoll": "enabled";
|
||||
"Dinotify": "enabled";
|
||||
"Dx11_autolaunch": "disabled";
|
||||
"epoll": "enabled";
|
||||
"inotify": "enabled";
|
||||
"x11_autolaunch": "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ package xdg-dbus-proxy {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Dman": "disabled";
|
||||
"man": "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ package dtc {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Dyaml": "disabled";
|
||||
"yaml": "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ package fcft {
|
||||
|
||||
version# = "3.3.3";
|
||||
source = remoteTar {
|
||||
url = "https://codeberg.org/dnkl/fcft/archive/"+version+".tar.gz";
|
||||
checksum = "bMj8OmqtoANRKZWbjHk4WfP09AxJYRbWGqUsm1gRJ_dOFg6gooNbgkDu597PLfz2";
|
||||
url = "https://codeberg.org/dnkl/fcft/releases/download/"+version+
|
||||
"/fcft-"+version+".tar.gz";
|
||||
checksum = "pryAJA-d1OpY8KXbGFEHum9Wm6ME9XkPx9EM_OQ_ZEpOUpQnqlkzIq-cwS1ziMPk";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ package firmware {
|
||||
website = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git";
|
||||
anitya = 141464;
|
||||
|
||||
version# = "20260519";
|
||||
version# = "20260622";
|
||||
source = remoteGitLab {
|
||||
domain = "gitlab.com";
|
||||
suffix = "kernel-firmware/linux-firmware";
|
||||
ref = version;
|
||||
checksum = "l-wBRTWclYnJsgV4qtUV1-UL5Y4nknAPre8CMe0dH7PxtAqbaeudEIM_Fnuj0TCV";
|
||||
checksum = "gpytkDM58EVjaUuryOekcekh_rWsfuv3S7LQxopHlNlVGmMsuqNwfug4BjgTgizE";
|
||||
};
|
||||
|
||||
// dedup creates temporary file
|
||||
@@ -34,7 +34,7 @@ package firmware {
|
||||
// requires pre-commit
|
||||
skipCheck = true;
|
||||
|
||||
install = "make " + jobsFlagE + " DESTDIR=/work/system dedup";
|
||||
install = "make " + jobsFlagE + " " + loadFlagE + " DESTDIR=/work/system dedup";
|
||||
};
|
||||
|
||||
inputs = [
|
||||
|
||||
@@ -3,12 +3,12 @@ package fontconfig {
|
||||
website = "https://www.freedesktop.org/wiki/Software/fontconfig";
|
||||
anitya = 827;
|
||||
|
||||
version# = "2.18.1";
|
||||
version# = "2.18.2";
|
||||
source = remoteGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
suffix = "fontconfig/fontconfig";
|
||||
ref = version;
|
||||
checksum = "S3FJfh-PeZ2_YgNrUqL0H2G4Wf_ilj5HpIGV2oURnkK672AQHpWk526bNtRHwyJt";
|
||||
checksum = "P8YoQunIynBhc3gdDyPkImw_GGYoy1U4aX0jTnpkgtLmU4nqIgUyeqCH3-rNzpTd";
|
||||
};
|
||||
|
||||
exec = make {
|
||||
|
||||
@@ -5,8 +5,9 @@ package foot {
|
||||
|
||||
version# = "1.27.0";
|
||||
source = remoteTar {
|
||||
url = "https://codeberg.org/dnkl/foot/archive/"+version+".tar.gz";
|
||||
checksum = "E2XIPRD8t-WBBJUebIwChFT8K_85diwdalssUNwnuZBIynPa7rlXro5WCe9v3UlK";
|
||||
url = "https://codeberg.org/dnkl/foot/releases/download/"+version+
|
||||
"/foot-"+version+".tar.gz";
|
||||
checksum = "22rG3rMuQI8Ae2XTcZgOJ-6AbF7Taex8XpgvD6Fyg1Mn5Va67FfUcK3tRaq61TFg";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ package fribidi {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Ddocs": "false";
|
||||
"docs": "false";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ package fuse {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Ddefault_library": "both";
|
||||
"Dtests": "true";
|
||||
"Duseroot": "false";
|
||||
"Dinitscriptdir": "/system/etc";
|
||||
"default_library": "both";
|
||||
"tests": "true";
|
||||
"useroot": "false";
|
||||
"initscriptdir": "/system/etc";
|
||||
};
|
||||
|
||||
postCompile = "python3 -m pytest test/";
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
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
|
||||
@@ -0,0 +1,39 @@
|
||||
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
|
||||
@@ -0,0 +1,26 @@
|
||||
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,
|
||||
];
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package binutils {
|
||||
website = "https://www.gnu.org/software/binutils";
|
||||
anitya = 7981;
|
||||
|
||||
version# = "2.46.1";
|
||||
version# = "2.47";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/binutils/binutils-"+version+".tar.bz2";
|
||||
checksum = "ihCVohBxX-URAR-YFDdVrL3inLYsEVX8KbbQmcbHaShHgqqmtsvUue1h3LXSjW-d";
|
||||
url = "https://mirrors.kernel.org/gnu/binutils/binutils-"+version+".tar.bz2";
|
||||
checksum = "VjbMg5KtZ6VSeNc77Z5p8RKg9eZ56g29ViKbbsF3tcFhZu0Yurg0nZt7UwB577LM";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
@@ -82,6 +82,7 @@ ln -s system/lib /work/
|
||||
|
||||
mpc,
|
||||
zlib,
|
||||
zstd,
|
||||
libucontext,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,24 +3,25 @@ package git {
|
||||
website = "https://www.git-scm.com";
|
||||
anitya = 5350;
|
||||
|
||||
version# = "2.54.0";
|
||||
version# = "2.55.0";
|
||||
source = remoteTar {
|
||||
url = "https://www.kernel.org/pub/software/scm/git/"+
|
||||
"git-"+version+".tar.gz";
|
||||
checksum = "7vGKtFOJGqY8DO4e8UMRax7dLgImXKQz5MMalec6MlgYrsarffSJjgOughwRFpSH";
|
||||
checksum = "lOer6jb8vZQk6Nd1rLZIgsYys8whLvjJq8XbmCdTATcPFAYuQcK1Rgj1Jj6a00W8";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
early = `
|
||||
ln -s ../../system/bin/perl /usr/bin/ || true
|
||||
|
||||
# test suite assumes apache
|
||||
rm -f /system/bin/httpd
|
||||
`;
|
||||
|
||||
// uses source tree as scratch space
|
||||
enterSource = true;
|
||||
env = [ "NO_RUST=YesPlease" ];
|
||||
|
||||
bin = [ "perl" ];
|
||||
populateUsrBin = true;
|
||||
exec = make {
|
||||
inPlace = true;
|
||||
generate = "make configure";
|
||||
@@ -59,6 +60,8 @@ disable_test t1451-fsck-buffer
|
||||
disable_test t4104-apply-boundary
|
||||
disable_test t4200-rerere
|
||||
disable_test t5515-fetch-merge-logic
|
||||
disable_test t4124-apply-ws-rule
|
||||
disable_test t3404-rebase-interactive
|
||||
`;
|
||||
|
||||
check = [
|
||||
@@ -69,6 +72,7 @@ disable_test t5515-fetch-merge-logic
|
||||
|
||||
install = `make \
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE + ` \
|
||||
DESTDIR=/work \
|
||||
NO_INSTALL_HARDLINKS=1 \
|
||||
install`;
|
||||
@@ -85,6 +89,7 @@ disable_test t5515-fetch-merge-logic
|
||||
zlib,
|
||||
curl,
|
||||
libexpat,
|
||||
kernel-headers,
|
||||
];
|
||||
|
||||
runtime = [
|
||||
|
||||
@@ -3,11 +3,11 @@ package glib {
|
||||
website = "https://developer.gnome.org/glib";
|
||||
anitya = 10024;
|
||||
|
||||
version# = "2.89.0";
|
||||
version# = "2.89.3";
|
||||
source = remoteGit {
|
||||
url = "https://gitlab.gnome.org/GNOME/glib.git";
|
||||
tag = version;
|
||||
checksum = "4FXKhdS3pC98LevYa_h7piRylG86cZ_c9zAtGr78oHodU1ob8rBxGU0hoIZ4nzcA";
|
||||
checksum = "eM9KrXwhwKiZferwrILKmDeq-IGnSjr0EKqV90EEVl0Ee82QVcyVSf2LDMROHcOF";
|
||||
};
|
||||
|
||||
files = {
|
||||
@@ -17,8 +17,10 @@ package glib {
|
||||
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Ddefault_library": "both";
|
||||
"default_library": "both";
|
||||
};
|
||||
// fails with ipv6 disabled
|
||||
skipTests = [ "gio" ];
|
||||
};
|
||||
|
||||
inputs = [
|
||||
|
||||
@@ -3,11 +3,11 @@ package glslang {
|
||||
website = "https://github.com/KhronosGroup/glslang";
|
||||
anitya = 205796;
|
||||
|
||||
version# = "16.3.0";
|
||||
version# = "16.4.0";
|
||||
source = remoteGitHub {
|
||||
suffix = "KhronosGroup/glslang";
|
||||
tag = version;
|
||||
checksum = "xyqDf8k3-D0_BXHGi0uLgMglnJ05Rf3j73QgbDs3sGtKNdBIQhY8JfqX1NcNoJQN";
|
||||
checksum = "u67ps8Fv_75QDiusvKjzgttPPPxb5V7HsObb0q6OvqQfHh0UGN2_x8Y0RKb9JEie";
|
||||
};
|
||||
|
||||
// test suite writes to source
|
||||
|
||||
@@ -7,7 +7,7 @@ package m4 {
|
||||
|
||||
version# = "1.4.21";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/m4/m4-"+version+".tar.bz2";
|
||||
url = "https://mirrors.kernel.org/gnu/m4/m4-"+version+".tar.bz2";
|
||||
checksum = "pPa6YOo722Jw80l1OsH1tnUaklnPFjFT-bxGw5iAVrZTm1P8FQaWao_NXop46-pm";
|
||||
compress = bzip2;
|
||||
};
|
||||
@@ -17,7 +17,10 @@ package m4 {
|
||||
chmod +w tests/test-c32ispunct.sh && echo '#!/bin/sh' > tests/test-c32ispunct.sh
|
||||
`;
|
||||
|
||||
exec = make {};
|
||||
toyboxEarly = true;
|
||||
exec = make {
|
||||
omitDefaults = true;
|
||||
};
|
||||
|
||||
inputs = [
|
||||
diffutils,
|
||||
@@ -33,7 +36,7 @@ package autoconf {
|
||||
|
||||
version# = "2.73";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/autoconf/autoconf-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/autoconf/autoconf-"+version+".tar.gz";
|
||||
checksum = "yGabDTeOfaCUB0JX-h3REYLYzMzvpDwFmFFzHNR7QilChCUNE4hR6q7nma4viDYg";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -68,7 +71,7 @@ package automake {
|
||||
|
||||
version# = "1.18.1";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/automake/automake-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/automake/automake-"+version+".tar.gz";
|
||||
checksum = "FjvLG_GdQP7cThTZJLDMxYpRcKdpAVG-YDs1Fj1yaHlSdh_Kx6nRGN14E0r_BjcG";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -102,10 +105,10 @@ package libtool {
|
||||
website = "https://www.gnu.org/software/libtool";
|
||||
anitya = 1741;
|
||||
|
||||
version# = "2.5.4";
|
||||
version# = "2.6.2";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/libtool/libtool-"+version+".tar.gz";
|
||||
checksum = "pa6LSrQggh8mSJHQfwGjysAApmZlGJt8wif2cCLzqAAa2jpsTY0jZ-6stS3BWZ2Q";
|
||||
url = "https://mirrors.kernel.org/gnu/libtool/libtool-"+version+".tar.gz";
|
||||
checksum = "roFqdjyoGjpK7CWWLJJrTS56LuOQcIdq6Tgr4yplacSwirFHoaiDe6CojIWYinWe";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
@@ -132,7 +135,7 @@ package gzip {
|
||||
|
||||
version# = "1.14";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/gzip/gzip-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/gzip/gzip-"+version+".tar.gz";
|
||||
checksum = "NWhjUavnNfTDFkZJyAUonL9aCOak8GVajWX2OMlzpFnuI0ErpBFyj88mz2xSjz0q";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -150,11 +153,18 @@ package sed {
|
||||
|
||||
version# = "4.10";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/sed/sed-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/sed/sed-"+version+".tar.gz";
|
||||
checksum = "TXTRFQJCyflb-bpBRI2S5Y1DpplwvT7-KfXtpqN4AdZgZ5OtI6yStn1-bkhDKx51";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
writable = true;
|
||||
early = `
|
||||
test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
|
||||
|
||||
test_disable '#!/bin/sh' testsuite/read-error-stale-errno.sh
|
||||
`;
|
||||
|
||||
exec = make {};
|
||||
|
||||
inputs = [
|
||||
@@ -171,7 +181,7 @@ package diffutils {
|
||||
|
||||
version# = "3.12";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/diffutils/diffutils-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/diffutils/diffutils-"+version+".tar.gz";
|
||||
checksum = "9J5VAq5oA7eqwzS1Yvw-l3G5o-TccUrNQR3PvyB_lgdryOFAfxtvQfKfhdpquE44";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -186,7 +196,9 @@ test_disable '#!/bin/sh' tests/cmp
|
||||
`;
|
||||
|
||||
toyboxEarly = true;
|
||||
exec = make {};
|
||||
exec = make {
|
||||
omitDefaults = true;
|
||||
};
|
||||
}
|
||||
|
||||
package patch {
|
||||
@@ -196,7 +208,7 @@ package patch {
|
||||
|
||||
version# = "2.8";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/patch/patch-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/patch/patch-"+version+".tar.gz";
|
||||
checksum = "MA0BQc662i8QYBD-DdGgyyfTwaeALZ1K0yusV9rAmNiIsQdX-69YC4t9JEGXZkeR";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -209,26 +221,9 @@ test_disable '#!/bin/sh' tests/ed-style
|
||||
test_disable '#!/bin/sh' tests/need-filename
|
||||
`;
|
||||
|
||||
toyboxEarly = true;
|
||||
exec = make {};
|
||||
}
|
||||
|
||||
package gawk {
|
||||
description = "an implementation of awk with GNU extensions";
|
||||
website = "https://www.gnu.org/software/gawk";
|
||||
anitya = 868;
|
||||
|
||||
version# = "5.4.0";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/gawk/gawk-"+version+".tar.gz";
|
||||
checksum = "m0RkIolC-PI7EY5q8pcx5Y-0twlIW0Yp3wXXmV-QaHorSdf8BhZ7kW9F8iWomz0C";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
toyboxEarly = true;
|
||||
exec = make {
|
||||
// dependency loop
|
||||
skipCheck = true;
|
||||
omitDefaults = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -239,7 +234,7 @@ package grep {
|
||||
|
||||
version# = "3.12";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/grep/grep-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/grep/grep-"+version+".tar.gz";
|
||||
checksum = "qMB4RjaPNRRYsxix6YOrjE8gyAT1zVSTy4nW4wKW9fqa0CHYAuWgPwDTirENzm_1";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -264,7 +259,7 @@ package gettext {
|
||||
|
||||
version# = "1.0";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/gettext/gettext-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/gettext/gettext-"+version+".tar.gz";
|
||||
checksum = "3MasKeEdPeFEgWgzsBKk7JqWqql1wEMbgPmzAfs-mluyokoW0N8oQVxPQoOnSdgC";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -302,14 +297,18 @@ package findutils {
|
||||
website = "https://www.gnu.org/software/findutils";
|
||||
anitya = 812;
|
||||
|
||||
version# = "4.10.0";
|
||||
source = remoteFile {
|
||||
url = "https://ftpmirror.gnu.org/gnu/findutils/findutils-"+version+".tar.xz";
|
||||
checksum = "ZXABdNBQXL7QjTygynRRTdXYWxQKZ0Wn5eMd3NUnxR0xaS0u0VfcKoTlbo50zxv6";
|
||||
version# = "4.11.0";
|
||||
source = remoteTar {
|
||||
url = "https://mirrors.kernel.org/gnu/findutils/findutils-"+version+".tar.xz";
|
||||
compress = xz;
|
||||
checksum = "X-qsv9aUoBL583q-4iZcBI3_7Ufd3fSIqFmNLXWdEpUihlRfMpGGyAUt8SAvDKae";
|
||||
};
|
||||
|
||||
writable = true;
|
||||
chmod = true;
|
||||
early = `
|
||||
echo '#!/bin/sh' > gnulib-tests/test-c32ispunct.sh
|
||||
echo 'int main(){return 0;}' > gnulib-tests/test-fstatat.c
|
||||
echo 'int main(){return 0;}' > tests/xargs/test-sigusr.c
|
||||
`;
|
||||
|
||||
@@ -317,7 +316,6 @@ echo 'int main(){return 0;}' > tests/xargs/test-sigusr.c
|
||||
|
||||
inputs = [
|
||||
diffutils,
|
||||
xz,
|
||||
sed,
|
||||
];
|
||||
}
|
||||
@@ -329,13 +327,14 @@ package bash {
|
||||
|
||||
version# = "5.3";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/bash/bash-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/bash/bash-"+version+".tar.gz";
|
||||
checksum = "4LQ_GRoB_ko-Ih8QPf_xRKA02xAm_TOxQgcJLmFDT6udUPxTAWrsj-ZNeuTusyDq";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
toyboxEarly = true;
|
||||
exec = make {
|
||||
omitDefaults = true;
|
||||
configure = {
|
||||
"without-bash-malloc";
|
||||
};
|
||||
@@ -350,7 +349,7 @@ package coreutils {
|
||||
|
||||
version# = "9.11";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/coreutils/coreutils-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/coreutils/coreutils-"+version+".tar.gz";
|
||||
checksum = "t8UMed5wpFEoC56aa42_yidfOAaRGzOfj7MRtQkkqgGbpXiskNA8bd-EmVSQkZie";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -363,12 +362,16 @@ test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
|
||||
test_disable '#!/bin/sh' gnulib-tests/test-c32ispunct.sh
|
||||
test_disable '#!/bin/sh' tests/ls/hyperlink.sh
|
||||
test_disable '#!/bin/sh' tests/misc/user.sh
|
||||
test_disable '#!/bin/sh' tests/split/line-bytes.sh
|
||||
test_disable '#!/bin/sh' tests/ls/stat-vs-dirent.sh
|
||||
test_disable '#!/bin/sh' tests/dd/sparse.sh
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-chown.c
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-fchownat.c
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-lchown.c
|
||||
`;
|
||||
|
||||
exec = make {
|
||||
omitDefaults = true;
|
||||
configure = {
|
||||
"enable-single-binary": "symlinks";
|
||||
};
|
||||
@@ -389,7 +392,7 @@ package tar {
|
||||
|
||||
version# = "1.35";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/tar/tar-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/tar/tar-"+version+".tar.gz";
|
||||
checksum = "zSaoSlVUDW0dSfm4sbL4FrXLFR8U40Fh3zY5DWhR5NCIJ6GjU6Kc4VZo2-ZqpBRA";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -426,7 +429,7 @@ package texinfo {
|
||||
|
||||
version# = "7.3";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/texinfo/texinfo-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/texinfo/texinfo-"+version+".tar.gz";
|
||||
checksum = "RRmC8Xwdof7JuZJeWGAQ_GeASIHAuJFQMbNONXBz5InooKIQGmqmWRjGNGEr5n4-";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -440,7 +443,7 @@ package texinfo {
|
||||
|
||||
runtime = [
|
||||
perl,
|
||||
gawk,
|
||||
awk,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -451,7 +454,7 @@ package gperf {
|
||||
|
||||
version# = "3.3";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gperf/gperf-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/gperf/gperf-"+version+".tar.gz";
|
||||
checksum = "RtIy9pPb_Bb8-31J2Nw-rRGso2JlS-lDlVhuNYhqR7Nt4xM_nObznxAlBMnarJv7";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -468,7 +471,7 @@ package bc {
|
||||
|
||||
version# = "1.08.2";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/bc/bc-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/bc/bc-"+version+".tar.gz";
|
||||
checksum = "8h6f3hjV80XiFs6v9HOPF2KEyg1kuOgn5eeFdVspV05ODBVQss-ey5glc8AmneLy";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -491,7 +494,7 @@ package libiconv {
|
||||
|
||||
version# = "1.19";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/libiconv/libiconv-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/libiconv/libiconv-"+version+".tar.gz";
|
||||
checksum = "UibB6E23y4MksNqYmCCrA3zTFO6vJugD1DEDqqWYFZNuBsUWMVMcncb_5pPAr88x";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -504,17 +507,14 @@ package parallel {
|
||||
website = "https://www.gnu.org/software/parallel";
|
||||
anitya = 5448;
|
||||
|
||||
version# = "20260522";
|
||||
version# = "20260722";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/parallel/parallel-"+version+".tar.bz2";
|
||||
checksum = "ezg3NZMlY-q-478YXmjWmDrDlaL55T7aBCuv3B7Z3DkAlfZRQEKO8eumqbcxTIy6";
|
||||
url = "https://mirrors.kernel.org/gnu/parallel/parallel-"+version+".tar.bz2";
|
||||
checksum = "liG9pBSRqUPqDuRXmnJPoVh-G53lDKkkO8GGabSxQnSho4b9BD0EaJDdScgVhnwj";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
early = `
|
||||
ln -s ../system/bin/bash /bin/
|
||||
`;
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = make {};
|
||||
|
||||
inputs = [
|
||||
@@ -532,7 +532,7 @@ package libunistring {
|
||||
|
||||
version# = "1.4.2";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/libunistring/libunistring-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/libunistring/libunistring-"+version+".tar.gz";
|
||||
checksum = "iW9BbfLoVlXjWoLTZ4AekQSu4cFBnLcZ4W8OHWbv0AhJNgD3j65_zqaLMzFKylg2";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -559,7 +559,7 @@ package libtasn1 {
|
||||
|
||||
version# = "4.21.0";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/libtasn1/libtasn1-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/libtasn1/libtasn1-"+version+".tar.gz";
|
||||
checksum = "9DYI3UYbfYLy8JsKUcY6f0irskbfL0fHZA91Q-JEOA3kiUwpodyjemRsYRjUpjuq";
|
||||
compress = gzip;
|
||||
};
|
||||
@@ -574,7 +574,7 @@ package readline {
|
||||
|
||||
version# = "8.3";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/readline/readline-"+version+".tar.gz";
|
||||
url = "https://mirrors.kernel.org/gnu/readline/readline-"+version+".tar.gz";
|
||||
checksum = "r-lcGRJq_MvvBpOq47Z2Y1OI2iqrmtcqhTLVXR0xWo37ZpC2uT_md7gKq5o_qTMV";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
@@ -34,7 +34,8 @@ echo 'int main(){return 0;}' > tests/mini-dtls-fragments.c
|
||||
"with-zstd": "link";
|
||||
|
||||
"": arch {
|
||||
arm64 = "disable-hardware-acceleration";
|
||||
// miscompilation on arm64
|
||||
arm64 = "--disable-hardware-acceleration";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From 45929774c3d5c084cc478afba63c77cf67a68bd7 Mon Sep 17 00:00:00 2001
|
||||
From: khr@golang.org <khr@golang.org>
|
||||
Date: Wed, 18 Feb 2026 09:09:57 -0800
|
||||
Subject: [PATCH] internal/runtime/gc/scan: require popcnt for x86
|
||||
|
||||
The GOAMD64=v1 test disables popcnt instructions, which is a feature
|
||||
this package's amd64 assembly uses.
|
||||
|
||||
Fixes #77674
|
||||
|
||||
Change-Id: I7be9bb665838f5da50275f96ef3df398412bb44a
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/746640
|
||||
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
||||
Reviewed-by: Michael Knyszek <mknyszek@google.com>
|
||||
Reviewed-by: Keith Randall <khr@google.com>
|
||||
Auto-Submit: Keith Randall <khr@golang.org>
|
||||
---
|
||||
|
||||
diff --git a/src/internal/runtime/gc/scan/scan_amd64.go b/src/internal/runtime/gc/scan/scan_amd64.go
|
||||
index c03021c7d4..544b237770 100644
|
||||
--- a/src/internal/runtime/gc/scan/scan_amd64.go
|
||||
+++ b/src/internal/runtime/gc/scan/scan_amd64.go
|
||||
@@ -39,4 +39,5 @@ var avx512ScanPackedReqsMet = cpu.X86.HasAVX512VL &&
|
||||
cpu.X86.HasGFNI &&
|
||||
cpu.X86.HasAVX512BITALG &&
|
||||
cpu.X86.HasAVX512DQ && // for kmovb, see #79871
|
||||
- cpu.X86.HasAVX512VBMI
|
||||
+ cpu.X86.HasAVX512VBMI &&
|
||||
+ cpu.X86.HasPOPCNT
|
||||
@@ -0,0 +1,135 @@
|
||||
From 06f90ebfa6f3e0a744584513e2786988b26569da Mon Sep 17 00:00:00 2001
|
||||
From: Damien Neil <dneil@google.com>
|
||||
Date: Wed, 08 Jul 2026 11:11:48 -0700
|
||||
Subject: [PATCH] os: properly handle trailing / in Root.MkdirAll
|
||||
|
||||
MkdirAll("dir/") should create "dir", not return an error.
|
||||
|
||||
Fixes #80308
|
||||
|
||||
Change-Id: I75458c30b6cb94be3a3d368f6024caef6a6a6964
|
||||
---
|
||||
|
||||
diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go
|
||||
index 228b580..a84e952 100644
|
||||
--- a/src/os/root_noopenat.go
|
||||
+++ b/src/os/root_noopenat.go
|
||||
@@ -158,6 +158,9 @@
|
||||
if err := checkPathEscapes(r, name); err == errPathEscapes {
|
||||
return &PathError{Op: "mkdirat", Path: name, Err: err}
|
||||
}
|
||||
+ if name == "" {
|
||||
+ return &PathError{Op: "mkdirat", Path: name, Err: syscall.ENOENT}
|
||||
+ }
|
||||
prefix := r.root.name + string(PathSeparator)
|
||||
if err := MkdirAll(prefix+name, perm); err != nil {
|
||||
if pe, ok := err.(*PathError); ok {
|
||||
diff --git a/src/os/root_openat.go b/src/os/root_openat.go
|
||||
index d7c9334..92865e4 100644
|
||||
--- a/src/os/root_openat.go
|
||||
+++ b/src/os/root_openat.go
|
||||
@@ -167,6 +167,12 @@
|
||||
fi, e := r.Stat(fullname)
|
||||
if e == nil && fi.Mode().IsDir() {
|
||||
err = nil
|
||||
+ } else if e == nil {
|
||||
+ err = syscall.ENOTDIR
|
||||
+ } else if !IsNotExist(e) {
|
||||
+ // EPERM, ELOOP, etc.,
|
||||
+ // probably more useful than EEXIST.
|
||||
+ err = e
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,7 +183,12 @@
|
||||
}
|
||||
return struct{}{}, &PathError{Op: "mkdirat", Err: err}
|
||||
}
|
||||
- _, err := doInRoot(r, fullname, 0, openDirFunc, openLastComponentFunc)
|
||||
+ flags := uint(doInRootCreatingDirectory)
|
||||
+ switch runtime.GOOS {
|
||||
+ case "linux", "windows":
|
||||
+ flags = doInRootNoHandleTerminalSlash // see rootMkdir
|
||||
+ }
|
||||
+ _, err := doInRoot(r, fullname, flags, openDirFunc, openLastComponentFunc)
|
||||
if err != nil {
|
||||
if _, ok := err.(*PathError); !ok {
|
||||
err = &PathError{Op: "mkdirat", Path: fullname, Err: err}
|
||||
diff --git a/src/os/root_test.go b/src/os/root_test.go
|
||||
index 5e0acf9..33a2f33 100644
|
||||
--- a/src/os/root_test.go
|
||||
+++ b/src/os/root_test.go
|
||||
@@ -585,6 +585,11 @@
|
||||
|
||||
func TestRootMkdirAll(t *testing.T) {
|
||||
for _, test := range rootTestCases {
|
||||
+ if test.name == "directory does not exist" {
|
||||
+ // Test expects error, mkdirall creates the missing directory.
|
||||
+ // TestRootMultiMkdirAll covers this case better anyway, just skip.
|
||||
+ continue
|
||||
+ }
|
||||
test.run(t, func(t *testing.T, target string, root *os.Root) {
|
||||
wantError := test.wantError
|
||||
if test.ltarget != "" {
|
||||
@@ -593,7 +598,7 @@
|
||||
wantError = true
|
||||
}
|
||||
|
||||
- err := root.Mkdir(test.open, 0o777)
|
||||
+ err := root.MkdirAll(test.open, 0o777)
|
||||
if errEndsTest(t, err, wantError, "root.MkdirAll(%q)", test.open) {
|
||||
return
|
||||
}
|
||||
@@ -3133,6 +3138,52 @@
|
||||
})
|
||||
}
|
||||
|
||||
+func TestRootMultiMkdirAllShallow(t *testing.T) {
|
||||
+ runRootMultiTest(t, func(t *testing.T, test *rootMultiTest) (string, error) {
|
||||
+ return testRootMultiMkdirAll(t, test, test.targetPath)
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+func TestRootMultiMkdirAllDeep(t *testing.T) {
|
||||
+ runRootMultiTest(t, func(t *testing.T, test *rootMultiTest) (string, error) {
|
||||
+ targetPath := test.targetPath
|
||||
+ if len(targetPath) > 0 && os.IsPathSeparator(targetPath[len(targetPath)-1]) {
|
||||
+ targetPath += "a/b/"
|
||||
+ } else {
|
||||
+ targetPath += "/a/b"
|
||||
+ }
|
||||
+ return testRootMultiMkdirAll(t, test, targetPath)
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+func testRootMultiMkdirAll(t *testing.T, test *rootMultiTest, targetPath string) (string, error) {
|
||||
+ var mkdirAll = os.MkdirAll
|
||||
+ if test.root != nil {
|
||||
+ mkdirAll = test.root.MkdirAll
|
||||
+ }
|
||||
+
|
||||
+ test.setOp("MkdirAll(%q, 0o777)", targetPath)
|
||||
+ gotErr := mkdirAll(targetPath, 0o777)
|
||||
+
|
||||
+ switch {
|
||||
+ case test.root != nil && test.target.lescapes():
|
||||
+ // "mkdir ../target", or equivalent escaping path.
|
||||
+ test.wantError(t, gotErr, os.ErrPathEscapes)
|
||||
+ case test.root != nil && test.target.escapes():
|
||||
+ // "mkdir ../target", or equivalent escaping path.
|
||||
+ test.wantError(t, gotErr, errAny)
|
||||
+ return "", errSkipRootConsistencyCheck
|
||||
+ case test.root != nil && test.target.kind == testFileSymlink && test.target.target.kind == testFileAbsent && targetPath != test.targetPath:
|
||||
+ // A minor inconsistency between Root.MkdirAll and os.MkdirAll:
|
||||
+ // When an intermediate component of the tree being constructed is a
|
||||
+ // dangling symlink, Root.MkdirAll will follow the symlink and create
|
||||
+ // its target directory, while os.MkdirAll will fail with an error.
|
||||
+ return "", errSkipRootConsistencyCheck
|
||||
+ default:
|
||||
+ }
|
||||
+ return "", gotErr
|
||||
+}
|
||||
+
|
||||
func TestRootMultiRename(t *testing.T) {
|
||||
if runtime.GOOS == "wasip1" {
|
||||
switch os.Getenv("GOWASIRUNTIME") {
|
||||
@@ -0,0 +1,64 @@
|
||||
package go {
|
||||
description = "the Go programming language toolchain";
|
||||
website = "https://go.dev";
|
||||
anitya = 1227;
|
||||
|
||||
version# = "1.26.5";
|
||||
source = remoteTar {
|
||||
url = "https://go.dev/dl/go"+version+".src.tar.gz";
|
||||
checksum = "13yt1u_NGOd62LO-WZ8W6CUXodOrEF5CdkiTTiH9E635IHn1luvlXYjsHpBXNFSw";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
patches = [
|
||||
// https://go.dev/issue/77674
|
||||
"746640.patch",
|
||||
// https://go.dev/issue/80308
|
||||
"799064.patch",
|
||||
];
|
||||
|
||||
env = [
|
||||
"CC=cc",
|
||||
"GOCACHE=/tmp/gocache",
|
||||
"GOROOT_BOOTSTRAP=/system/go",
|
||||
"TMPDIR=/dev/shm/go",
|
||||
];
|
||||
|
||||
enterSource = true;
|
||||
|
||||
exec = generic {
|
||||
inPlace = true;
|
||||
build = `
|
||||
mkdir /work/system/ "${TMPDIR}"
|
||||
cp -r . /work/system/go
|
||||
cd /work/system/go/src/
|
||||
chmod -R +w ..
|
||||
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch+`.so.1,/system/bin/linker,' \
|
||||
cmd/link/internal/`+arch+`/obj.go
|
||||
|
||||
rm \
|
||||
os/root_unix_test.go \
|
||||
runtime/crash_cgo_test.go \
|
||||
cmd/cgo/internal/testsanitizers/tsan_test.go \
|
||||
cmd/cgo/internal/testsanitizers/cshared_test.go
|
||||
|
||||
set +u
|
||||
. ./make.bash "$@" --no-banner
|
||||
set -u
|
||||
`;
|
||||
check = "bash run.bash --no-rebuild\n";
|
||||
install = `
|
||||
../bin/go tool dist banner # print build info
|
||||
|
||||
mkdir /work/system/bin
|
||||
ln -s \
|
||||
../go/bin/go \
|
||||
../go/bin/gofmt \
|
||||
/work/system/bin
|
||||
`;
|
||||
};
|
||||
|
||||
inputs = [ bash, go-bootstrap ];
|
||||
}
|
||||
@@ -2,11 +2,11 @@ package hakurei-source {
|
||||
description = "hakurei source tree";
|
||||
exclude = true;
|
||||
|
||||
version# = "0.4.3";
|
||||
version# = "0.4.5";
|
||||
output = remoteTar {
|
||||
url = "https://git.gensokyo.uk/rosa/hakurei/archive/"+
|
||||
"v"+version+".tar.gz";
|
||||
checksum = "1LqBJIcYcAFTVfydCahOm4hjjKhY953X9ars0eQj32hnpNncWFefuT6OJpZzIlZv";
|
||||
checksum = "5bvbuIRcDIrtijogwqXn3y8h5f3rVS4ZSVhOig6Galfzt3g-O3Ufb-tHL1kQCQWK";
|
||||
compress = gzip;
|
||||
};
|
||||
}
|
||||
@@ -48,8 +48,13 @@ go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||
-X hakurei.app/internal/info.buildVersion=$(cat cmd/dist/VERSION)
|
||||
-X hakurei.app/internal/info.hakureiPath=/system/bin/hakurei
|
||||
-X hakurei.app/internal/info.hsuPath=/system/bin/hsu
|
||||
" ./cmd/hakurei ./cmd/sharefs
|
||||
|
||||
echo "Building hsu for $(go env GOOS)/$(go env GOARCH)."
|
||||
CGO_ENABLED=0 go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||
-buildid=
|
||||
-X main.hakureiPath=/system/bin/hakurei
|
||||
" ./...
|
||||
" ./cmd/hsu
|
||||
echo`;
|
||||
check = `
|
||||
echo '##### Testing hakurei.'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user