aboutsummaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/archive.go85
-rw-r--r--pkg/archive_test.go63
-rw-r--r--pkg/clean_test.go12
-rw-r--r--pkg/exec.go7
-rw-r--r--pkg/exec_test.go112
-rw-r--r--pkg/internal/tester/expected/expected.go (renamed from pkg/internal/testtool/expected/expected.go)0
-rw-r--r--pkg/internal/tester/expected/sum_amd64.go11
-rw-r--r--pkg/internal/tester/expected/sum_arm64.go11
-rw-r--r--pkg/internal/tester/expected/sum_riscv64.go11
-rw-r--r--pkg/internal/tester/main.go (renamed from pkg/internal/testtool/main.go)31
-rw-r--r--pkg/internal/testtool/expected/sum_amd64.go11
-rw-r--r--pkg/internal/testtool/expected/sum_arm64.go11
-rw-r--r--pkg/internal/testtool/expected/sum_riscv64.go11
-rw-r--r--pkg/ir_test.go18
-rw-r--r--pkg/pkg.go34
-rw-r--r--pkg/pkg_test.go55
-rw-r--r--pkg/tar.go57
-rw-r--r--pkg/tar_test.go46
18 files changed, 399 insertions, 187 deletions
diff --git a/pkg/archive.go b/pkg/archive.go
index ea4017d9..ba7c61b9 100644
--- a/pkg/archive.go
+++ b/pkg/archive.go
@@ -311,31 +311,28 @@ func (a archiveArtifact) Inputs() []Artifact {
// IsExclusive returns false: [Reader] is fully sequential.
func (archiveArtifact) IsExclusive() bool { return false }
-// Cure cures the [Artifact], producing a directory located at work.
-func (a archiveArtifact) Cure(t *TContext) (err error) {
- var r io.ReadCloser
- if r, err = t.Open(a.f); err != nil {
- return
- }
-
- defer func() {
- closeErr := r.Close()
- if err == nil {
- err = closeErr
- }
- }()
+// Revision satisfies [RevisionArtifact] for status behaviour.
+func (archiveArtifact) Revision() uint64 { return 0 }
+// Extract reads an archive stream from r and writes its contents to dir. If
+// writeStatus is non-nil, it is called with a user-facing message after
+// each successfully extracted entry.
+func Extract(
+ r io.Reader,
+ dir string,
+ writeStatus func(s string) error,
+) (err error) {
type dirTargetPerm struct {
path string
mode fs.FileMode
}
var madeDirectories []dirTargetPerm
- if err = os.MkdirAll(t.GetWorkDir().String(), 0700); err != nil {
+ if err = os.MkdirAll(dir, 0700); err != nil {
return
}
var root *os.Root
- if root, err = os.OpenRoot(t.GetWorkDir().String()); err != nil {
+ if root, err = os.OpenRoot(dir); err != nil {
return
}
defer func() {
@@ -348,6 +345,7 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
var header *ArchiveHeader
ar := NewReader(r)
for header, err = ar.Next(); err == nil; header, err = ar.Next() {
+ var m string
if header.Mode.IsRegular() {
var f *os.File
if f, err = root.OpenFile(
@@ -363,18 +361,33 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
} else if err = f.Close(); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s (%d bytes)",
+ header.Mode,
+ header.Path,
+ header.Size,
+ )
} else if header.Mode&fs.ModeSymlink != 0 {
var p []byte
if p, err = io.ReadAll(ar); err != nil {
return
}
+ linkname := unsafe.String(unsafe.SliceData(p), len(p))
if err = root.Symlink(
- unsafe.String(unsafe.SliceData(p), len(p)),
+ linkname,
header.Path,
); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s linkname %s",
+ header.Mode,
+ header.Path,
+ linkname,
+ )
} else if header.Mode.IsDir() {
if header.Path == "." {
continue
@@ -387,9 +400,21 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
if err = root.Mkdir(header.Path, 0700); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s",
+ header.Mode,
+ header.Path,
+ )
} else {
return InvalidFileModeError(header.Mode)
}
+
+ if writeStatus != nil && m != "" {
+ if err = writeStatus(m); err != nil {
+ return
+ }
+ }
}
if errors.Is(err, io.EOF) {
err = nil
@@ -406,6 +431,34 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
return
}
+// Cure cures the [Artifact], producing a directory located at work.
+func (a archiveArtifact) Cure(t *TContext) (err error) {
+ var status io.Writer
+ if status, err = t.GetStatusWriter(); err != nil {
+ return
+ }
+
+ var r io.ReadCloser
+ if r, err = t.Open(a.f); err != nil {
+ return
+ }
+
+ msg := t.GetMessage()
+ err = Extract(r, t.GetWorkDir().String(), func(s string) (err error) {
+ msg.Verbose(s)
+ if _, err = io.WriteString(status, s); err != nil {
+ return
+ }
+ _, err = status.Write([]byte{'\n'})
+ return
+ })
+
+ if closeErr := r.Close(); err == nil {
+ err = closeErr
+ }
+ return
+}
+
// CuresExempt exempts the cheap [KindArchive] implementation often found at
// the end of a [FileArtifact] pipeline.
func (archiveArtifact) CuresExempt() {}
diff --git a/pkg/archive_test.go b/pkg/archive_test.go
index 44ea56a7..0171d914 100644
--- a/pkg/archive_test.go
+++ b/pkg/archive_test.go
@@ -2,9 +2,12 @@ package pkg_test
import (
"bytes"
+ "crypto/sha512"
+ "errors"
"io"
"io/fs"
"maps"
+ "net/http"
"reflect"
"testing"
"testing/fstest"
@@ -176,33 +179,63 @@ func TestArchiveArtifact(t *testing.T) {
want := maps.Clone(archiveTestdata)
want["."].Mode = fs.ModeDir | 0500
+ var buf bytes.Buffer
+ if err := pkg.Write(archiveTestdata, ".", &buf); err != nil {
+ t.Fatal(err)
+ }
+ wantChecksum := sha512.Sum384(buf.Bytes())
+ wantChecksumEncode := pkg.Encode(wantChecksum)
+
+ var transport http.Transport
+ client := http.Client{Transport: &transport}
+ transport.RegisterProtocol("file", http.NewFileTransportFS(fstest.MapFS{
+ "testdata": {Data: buf.Bytes(), Mode: 0400},
+ }))
+
checkWithCache(t, []cacheTestCase{
{"unpack", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- var buf bytes.Buffer
- if err := pkg.Write(archiveTestdata, ".", &buf); err != nil {
- t.Fatal(err)
- }
-
cureMany(t, c, []cureStep{
{"sample", pkg.NewArchive(
pkg.NewFile("", buf.Bytes()),
), ignorePathname, expectsFS(want), pkg.WNew, nil},
+
+ {"close error passthrough", pkg.NewArchive(
+ pkg.NewHTTPGet(
+ &client,
+ "file:///testdata",
+ pkg.Checksum{},
+ ),
+ ), nil, nil, pkg.WNew, errors.Join(&pkg.ChecksumMismatchError{
+ Got: wantChecksum,
+ })},
})
+
+ dropFaults(t, base)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
- "checksum": {Mode: fs.ModeDir | 0700},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F": {Mode: fs.ModeDir | 0500},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/block": {Mode: fs.ModeDir | 0700},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/block/uevent": {Mode: 0600},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices": {Mode: fs.ModeDir | 0700},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/empty": {Mode: fs.ModeDir | 0700},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/sub": {Mode: fs.ModeDir | 0700},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/sub/uevent": {Mode: 0600, Data: []byte("add")},
- "checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F/devices/uevent": {Mode: 0600, Data: []byte("add")},
+ "checksum": {Mode: fs.ModeDir | 0700},
+ "checksum/" + wantChecksumEncode: {Mode: fs.ModeDir | 0500},
+ "checksum/" + wantChecksumEncode + "/block": {Mode: fs.ModeDir | 0700},
+ "checksum/" + wantChecksumEncode + "/block/uevent": {Mode: 0600},
+ "checksum/" + wantChecksumEncode + "/devices": {Mode: fs.ModeDir | 0700},
+ "checksum/" + wantChecksumEncode + "/devices/empty": {Mode: fs.ModeDir | 0700},
+ "checksum/" + wantChecksumEncode + "/devices/sub": {Mode: fs.ModeDir | 0700},
+ "checksum/" + wantChecksumEncode + "/devices/sub/uevent": {Mode: 0600, Data: []byte("add")},
+ "checksum/" + wantChecksumEncode + "/devices/uevent": {Mode: 0600, Data: []byte("add")},
"identifier": {Mode: fs.ModeDir | 0700},
- "identifier/-zXKfphyWM2Ko7VMVURaEMSuixNokFSe0xFbnwR2RtRtvMrcPGWalV0LIn45PXTY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CBPcoVHuVUTVRCMbRl8J30RSSzm_tyfuXaZ-HlZsanY1sY50meOVmgaWDrGKbx9F")},
+ "identifier/iyvWY0irMoW4AVRnG_du07d_nAEUtbHdeiaAYRdp-vf3wstM9u67IokOsPfU9eyM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksumEncode)},
+
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/iyvWY0irMoW4AVRnG_du07d_nAEUtbHdeiaAYRdp-vf3wstM9u67IokOsPfU9eyM": {Mode: 0444, Data: []byte(statusHeader + `drwx------ block
+-rw------- block/uevent (0 bytes)
+drwx------ devices
+drwx------ devices/empty
+drwx------ devices/sub
+-rw------- devices/sub/uevent (3 bytes)
+-rw------- devices/uevent (3 bytes)
+`)},
"substitute": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
diff --git a/pkg/clean_test.go b/pkg/clean_test.go
index e31d52aa..3b5d0b3b 100644
--- a/pkg/clean_test.go
+++ b/pkg/clean_test.go
@@ -52,7 +52,7 @@ func TestClean(t *testing.T) {
"lock": {Mode: 0644},
"variant": {Mode: 0400},
- "status": {Mode: fs.ModeDir | 0700},
+ "status": {Mode: fs.ModeDir | 0711},
"substitute": {Mode: fs.ModeDir | 0700},
"fault": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
@@ -73,7 +73,7 @@ func TestClean(t *testing.T) {
"lock": {Mode: 0644},
"variant": {Mode: 0400},
- "status": {Mode: fs.ModeDir | 0700},
+ "status": {Mode: fs.ModeDir | 0711},
"substitute": {Mode: fs.ModeDir | 0700},
"fault": {Mode: fs.ModeDir | 0700},
"work": {Mode: fs.ModeDir | 0700},
@@ -127,7 +127,7 @@ func TestClean(t *testing.T) {
"lock": {Mode: 0644},
"variant": {Mode: 0400},
- "status": {Mode: fs.ModeDir | 0700},
+ "status": {Mode: fs.ModeDir | 0711},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
@@ -205,9 +205,9 @@ func TestClean(t *testing.T) {
"lock": {Mode: 0644},
"variant": {Mode: 0400},
- "status": {Mode: fs.ModeDir | 0700},
- "status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0400, Data: []byte(statusHeader + "kept")},
- "status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0400, Data: []byte(statusHeader + "kept")},
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/xxQ43VMIS1WHMSEFnUdBNd6pulbtgiTorP_mtJpEsZENYhGBiDEL6Y2D8yqn0Sra": {Mode: 0444, Data: []byte(statusHeader + "kept")},
+ "status/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: 0444, Data: []byte(statusHeader + "kept")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/td1tf1kb3z8iUFg2k1xlHeTTEz3xR4e77WSWdv2JhjmZyY6iuvodhdT8BblDOi0E": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")},
diff --git a/pkg/exec.go b/pkg/exec.go
index b40ae84b..fe099ac9 100644
--- a/pkg/exec.go
+++ b/pkg/exec.go
@@ -601,7 +601,12 @@ func (a *execArtifact) makeContainer(
fhs.AbsTmp,
std.BindWritable|std.BindEnsure,
)
- z.Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
+ z.
+ Proc(fhs.AbsProc).
+ DevWritable(fhs.AbsDev, true).
+ Tmpfs(fhs.AbsDevShm, 0, 01777).
+ Bind(fhs.AbsDevKvm, fhs.AbsDevKvm, std.BindOptional|std.BindDevice).
+ Remount(fhs.AbsDev, syscall.MS_RDONLY)
return
}
diff --git a/pkg/exec_test.go b/pkg/exec_test.go
index 051af551..a24c1e5e 100644
--- a/pkg/exec_test.go
+++ b/pkg/exec_test.go
@@ -23,18 +23,18 @@ import (
"hakurei.app/internal/stub"
"hakurei.app/pkg"
- "hakurei.app/pkg/internal/testtool/expected"
+ "hakurei.app/pkg/internal/tester/expected"
)
-// testtoolBin is the container test tool binary made available to the
+// testHelperBin is the container test helper binary made available to the
// execArtifact for testing its curing environment.
//
-//go:generate env CGO_ENABLED=0 go build -tags testtool -o internal/testtool ./internal/testtool
-//go:embed internal/testtool/testtool
-var testtoolBin []byte
+//go:generate env CGO_ENABLED=0 go build -tags tester -o internal/tester ./internal/tester
+//go:embed internal/tester/tester
+var testHelperBin []byte
func init() {
- pathname, err := filepath.Abs("internal/testtool/testtool")
+ pathname, err := filepath.Abs("internal/tester/tester")
if err != nil {
panic(err)
}
@@ -153,15 +153,15 @@ func TestExec(t *testing.T) {
checkWithCache(t, []cacheTestCase{
{"offline", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/file", false, newStubFile(
pkg.KindHTTPGet,
@@ -176,15 +176,15 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantOffline, pkg.WNew, nil},
{"substitution", pkg.NewExec(
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/file", false, newStubFile(
pkg.KindHTTPGet,
@@ -192,7 +192,7 @@ func TestExec(t *testing.T) {
nil,
nil, nil,
)),
- // substitution miss fails in testtool due to differing idents
+ // substitution miss fails in tester due to differing idents
pkg.MustPath("/.hakurei", false, &stubArtifact{
kind: pkg.KindTar,
params: []byte("empty directory (substituted)"),
@@ -200,15 +200,15 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantOffline, pkg.WSubstitute, nil},
{"error passthrough", pkg.NewExec(
"", "", nil, 0, false, true,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
), nil, nil, pkg.WNew, pkg.InputError{
@@ -219,8 +219,8 @@ func TestExec(t *testing.T) {
"", "", nil, 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.ExecPath{},
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths},
@@ -231,8 +231,8 @@ func TestExec(t *testing.T) {
"", "", nil, 0, false, false,
pkg.AbsWork,
nil,
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
)
var exitError *exec.ExitError
if _, _, err := c.Cure(initFailureArtifact); !errors.As(err, &exitError) ||
@@ -256,13 +256,13 @@ func TestExec(t *testing.T) {
if !bytes.HasPrefix(faultStatus, []byte(
"hakurei.app/pkg ",
)) || !bytes.Contains(faultStatus, []byte(
- "\ninit: fork/exec /opt/bin/testtool: no such file or directory\n",
+ "\ninit: fork/exec /opt/bin/tester: no such file or directory\n",
)) {
t.Errorf("unexpected status:\n%s", string(faultStatus))
}
destroyStatus(t, base, 2, 1)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -286,7 +286,7 @@ func TestExec(t *testing.T) {
}},
{"net", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
wantNet := expectsFS{
".": {Mode: fs.ModeDir | 0500},
@@ -298,8 +298,8 @@ func TestExec(t *testing.T) {
"exec-net", "", new(wantNet.hash()), 0, true, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool", "net"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester", "net"},
pkg.MustPath("/file", false, newStubFile(
pkg.KindHTTPGet,
@@ -314,12 +314,12 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantNet, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -341,15 +341,15 @@ func TestExec(t *testing.T) {
}},
{"overlay root", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
"exec-overlay-root", "", nil, 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/", true, &stubArtifact{
kind: pkg.KindTar,
@@ -358,12 +358,12 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -383,15 +383,15 @@ func TestExec(t *testing.T) {
}},
{"overlay work", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
"exec-overlay-work", "", nil, 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
- check.MustAbs("/work/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/work/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/", true, &stubArtifact{
kind: pkg.KindTar,
@@ -405,12 +405,12 @@ func TestExec(t *testing.T) {
cure: func(t *pkg.TContext) error {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
- }), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
+ }), pkg.Path(pkg.AbsWork, false /* ignored */, testHelper),
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -430,15 +430,15 @@ func TestExec(t *testing.T) {
}},
{"multiple layers", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
"exec-multiple-layers", "", nil, 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool", "layers"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester", "layers"},
pkg.MustPath("/", true, &stubArtifact{
kind: pkg.KindTar,
@@ -474,12 +474,12 @@ func TestExec(t *testing.T) {
return os.WriteFile(work.Append("check").String(), []byte("layers"), 0400)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -504,15 +504,15 @@ func TestExec(t *testing.T) {
}},
{"overlay layer promotion", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
- testtool, testtoolDestroy := newTesttool()
+ testHelper, destroyTestHelper := newTestHelper()
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
"exec-layer-promotion", "", nil, 0, false, true,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool", "promote"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester", "promote"},
pkg.MustPath("/", true, &stubArtifact{
kind: pkg.KindTar,
@@ -527,12 +527,12 @@ func TestExec(t *testing.T) {
return os.MkdirAll(t.GetWorkDir().String(), 0700)
},
}),
- pkg.MustPath("/opt", false, testtool),
+ pkg.MustPath("/opt", false, testHelper),
), ignorePathname, wantOffline, pkg.WNew, nil},
})
destroyStatus(t, base, 2, 0)
- testtoolDestroy(t, base, c)
+ destroyTestHelper(t, base, c)
}, expectsFS{
".": {Mode: fs.ModeDir | 0700},
@@ -621,14 +621,14 @@ func TestExec(t *testing.T) {
})
}
-// newTesttool returns an [Artifact] that cures into testtoolBin. The returned
+// newTestHelper returns an [Artifact] that cures into testHelperBin. The returned
// function must be called at the end of the test but not deferred.
-func newTesttool() (
- testtool pkg.Artifact,
- testtoolDestroy func(t *testing.T, base *check.Absolute, c *pkg.Cache),
+func newTestHelper() (
+ testHelper pkg.Artifact,
+ destroyTestHelper func(t *testing.T, base *check.Absolute, c *pkg.Cache),
) {
- // testtoolBin is built during go:generate and is not deterministic
- testtool = overrideIdent{pkg.ID{0xfe, 0xff}, &stubArtifact{
+ // testHelperBin is built during go:generate and is not deterministic
+ testHelper = overrideIdent{pkg.ID{0xfe, 0xff}, &stubArtifact{
kind: pkg.KindTar,
cure: func(t *pkg.TContext) error {
work := t.GetWorkDir()
@@ -661,10 +661,10 @@ func newTesttool() (
return os.WriteFile(t.GetWorkDir().Append(
"bin",
- "testtool",
- ).String(), testtoolBin, 0500)
+ "tester",
+ ).String(), testHelperBin, 0500)
},
}}
- testtoolDestroy = newDestroyArtifactFunc(testtool)
+ destroyTestHelper = newDestroyArtifactFunc(testHelper)
return
}
diff --git a/pkg/internal/testtool/expected/expected.go b/pkg/internal/tester/expected/expected.go
index c0e8e4a2..c0e8e4a2 100644
--- a/pkg/internal/testtool/expected/expected.go
+++ b/pkg/internal/tester/expected/expected.go
diff --git a/pkg/internal/tester/expected/sum_amd64.go b/pkg/internal/tester/expected/sum_amd64.go
new file mode 100644
index 00000000..c3ef87b6
--- /dev/null
+++ b/pkg/internal/tester/expected/sum_amd64.go
@@ -0,0 +1,11 @@
+package expected
+
+const (
+ Offline = "8cvRbO_908FqbZvom0pp2MdLHiZMlllsBBHtwJMDOPeIm_Y55AvL8nkB5-ZvKQP7"
+ OfflineS = "R4nw81-Egce4yJgi4eoK0nDzPNkvCffaPUn8KPP1q1sdQ-dxjGc6YaYtBViUZTz4"
+ OvlRoot = "0W_DBfLbYbYiXkCL9BIwq1BBL_CAOQw1Al75FmU-w1pYWxc-s1CpaUl2VGiK1wU6"
+ Layers = "X0e6BdvAC_-MOguDI8f_9OrLyv9r32nV4zKRkLMr2Xye0-Nlc3Rew9Cycm0FlNfb"
+ Net = "B4VXPvG7mhh96PWmjwwma8Fy4HliP9WFEEW5vtq2lQrPEulZT_lSixX7Iowqpe_J"
+ Promote = "T_WzFNqwS4hZvNXsnDKOQkc7iwl38CY0GUsCGVnAhiJkU7iLARbeNDtAcA7C-FX1"
+ Work = "HknOKpTaBKOA5hwAP4eiqwzOQrw9JPQpJVhf-mpd2mIpQc6dfP7xqDALV2h4z0Ce"
+)
diff --git a/pkg/internal/tester/expected/sum_arm64.go b/pkg/internal/tester/expected/sum_arm64.go
new file mode 100644
index 00000000..3b0d3a5b
--- /dev/null
+++ b/pkg/internal/tester/expected/sum_arm64.go
@@ -0,0 +1,11 @@
+package expected
+
+const (
+ Offline = "f2G7Tr0wDhFL8LuJcgggob3C6jjVUvR1Vrs_xIQVaFt7qaoZJwtWIZ3-KgI0BjAE"
+ OfflineS = "6ShIakYroFkApzv_spmRfdhndwnnUVZFD2fgBRVA8n6GiSuYoeqF_37Loun6DneC"
+ OvlRoot = "RDokIPUWpf6kGWaaOtowwNGkeBFOIyQBjUY3sQbJ_KDnioKTQTKn2kijDdQ9L6Fp"
+ Layers = "dKXuQIWrySwPm5CNlR86XCe6FLrppcAJ6UxQKP75RCIjuK0nXA8ee6FMh4VNmKQS"
+ Net = "vxarc7CMN1BFQe7jOf4iDKNpz2DVT1Om1KdrVCAZyQd_7mr3loB0GjSnbE-mpjyC"
+ Promote = "oypLdVJZmZ1c9Tmfk-8N-3EBzgO99MymPS9H5nsCBPtm9CV9woEj8CBtlKk3b7gH"
+ Work = "JlGKRqXYGu6cREq_D4FIAHRT4zqu7uGIUtppWXDdEzRpQKflh7Y4sNHda1ecxRzj"
+)
diff --git a/pkg/internal/tester/expected/sum_riscv64.go b/pkg/internal/tester/expected/sum_riscv64.go
new file mode 100644
index 00000000..77c58120
--- /dev/null
+++ b/pkg/internal/tester/expected/sum_riscv64.go
@@ -0,0 +1,11 @@
+package expected
+
+const (
+ Offline = "Xa9l5ZZx7lt0B0YZeHihzWa6P6bGQT3rYn2kaftMDqZ7L6bpE9eCG9_e1dWlz-pn"
+ OfflineS = "6_GnlF6L7phCGuzeG91SAXCgxYPMJqv3UsZVvvoTdCvTtl8nCKnYxTlxAjdTNYY_"
+ OvlRoot = "2VZwLevuQ_ZmwFbAS-eZ4jGjcc71VqQYMkbZgzsV175oL3hGMto6jK-kFp6tcOF9"
+ Layers = "QukD3gaFOC-1wSm4XvdLtkZllw5APdTSX4mcWT88XEDNGMhvcblgaOr6Q1a20D7W"
+ Net = "XJME3Hjy2iZ2kGepJXtUOhETEMD6Li9ccLwi7y_4vQ7Kur0KGpXrfM8tyFnfLkFg"
+ Promote = "l71HASLptywY1pYL_pJBD8qoBkuUJCUobA6mSLUIsajew1IYkscZckBsqPu_czYn"
+ Work = "ZTJD0WoYxSB15h_VPjXHMuLhlL2bMgyGrJgltHRd4XBZhNr-WYNGVodt53GCBRXC"
+)
diff --git a/pkg/internal/testtool/main.go b/pkg/internal/tester/main.go
index edffab7e..72e20426 100644
--- a/pkg/internal/testtool/main.go
+++ b/pkg/internal/tester/main.go
@@ -1,5 +1,6 @@
-//go:build testtool
+//go:build tester
+// The tester program checks containers started by package pkg.
package main
import (
@@ -17,12 +18,12 @@ import (
"hakurei.app/fhs"
"hakurei.app/vfs"
- "hakurei.app/pkg/internal/testtool/expected"
+ "hakurei.app/pkg/internal/tester/expected"
)
func main() {
log.SetFlags(0)
- log.SetPrefix("testtool: ")
+ log.SetPrefix("tester: ")
if os.Getenv("HAKUREI_BINFMT") == "1" {
wantArgs := []string{"/interpreter", "/opt/bin/sample"}
@@ -50,27 +51,27 @@ func main() {
})
var hostNet, layers, promote bool
- if len(os.Args) == 2 && os.Args[0] == "testtool" {
+ if len(os.Args) == 2 && os.Args[0] == "tester" {
switch os.Args[1] {
case "net":
hostNet = true
- log.SetPrefix("testtool(net): ")
+ log.SetPrefix("tester(net): ")
break
case "layers":
layers = true
- log.SetPrefix("testtool(layers): ")
+ log.SetPrefix("tester(layers): ")
break
case "promote":
promote = true
- log.SetPrefix("testtool(promote): ")
+ log.SetPrefix("tester(promote): ")
default:
log.Fatalf("Args: %q", os.Args)
return
}
- } else if wantArgs := []string{"testtool"}; !slices.Equal(os.Args, wantArgs) {
+ } else if wantArgs := []string{"tester"}; !slices.Equal(os.Args, wantArgs) {
log.Fatalf("Args: %q, want %q", os.Args, wantArgs)
}
@@ -79,7 +80,7 @@ func main() {
if len(environ) == 2 {
overlayRoot = true
if !layers && !promote {
- log.SetPrefix("testtool(overlay root): ")
+ log.SetPrefix("tester(overlay root): ")
}
wantEnv = []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}
}
@@ -89,8 +90,8 @@ func main() {
var overlayWork bool
const (
- wantExec = "/opt/bin/testtool"
- wantExecWork = "/work/bin/testtool"
+ wantExec = "/opt/bin/tester"
+ wantExecWork = "/work/bin/tester"
)
var iftPath string
if got, err := os.Executable(); err != nil {
@@ -102,7 +103,7 @@ func main() {
switch got {
case wantExecWork:
overlayWork = true
- log.SetPrefix("testtool(overlay work): ")
+ log.SetPrefix("tester(overlay work): ")
default:
log.Fatalf("Executable: %q, want %q", got, wantExec)
@@ -225,7 +226,7 @@ func main() {
ident = expected.Promote
}
- next() // testtool artifact
+ next() // test helper artifact
next()
if overlayWork {
@@ -259,6 +260,10 @@ func main() {
next()
}
+ if m.Next != nil && m.Next.Root == "/kvm" {
+ next()
+ }
+
if m.Next != nil {
log.Println("unexpected extra mount entries")
for m.Next != nil {
diff --git a/pkg/internal/testtool/expected/sum_amd64.go b/pkg/internal/testtool/expected/sum_amd64.go
deleted file mode 100644
index 354931be..00000000
--- a/pkg/internal/testtool/expected/sum_amd64.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package expected
-
-const (
- Offline = "IKmVhALejtYA3JhN1PCfjKF-Dio1XVcOeMWDHhfSHCbb4iBNhGjFy2UspZveZvb8"
- OfflineS = "6ZubjSyCnz4-TKgQZi_BbY-JUwsStYCtD_f-BTDOOotfEbqkm47W20AazHRaLviz"
- OvlRoot = "Yox7WpG8B_OqIXWF4HWFZkUfsEl7DGzpFyZM0qtd9T8nQ-7SAkEUurlAe6_DJ6Iu"
- Layers = "aAwfxDB-efVo379FNl178jK7HEKU3LEjHbZdaVVjk7GnXGZGEANNsXnB3SCUxM9A"
- Net = "IU3GwU2jTBd7HjotvFo2wsDWBQGVGpamwiSKdc2G1EnhM-ZaacxAuK6q0wbTVxra"
- Promote = "rOjetGHzT_jPErrBR24IAZKDj8Q9dLLqxFQqloMgjsULss0VXDI--n6LxuMBHvmZ"
- Work = "7f9XDeREfvJIjCe0qesND0s0tasExAIcc-OH33-eq9tsrQPUXhJp4KEkpsYH4hCD"
-)
diff --git a/pkg/internal/testtool/expected/sum_arm64.go b/pkg/internal/testtool/expected/sum_arm64.go
deleted file mode 100644
index 2e6f7cbf..00000000
--- a/pkg/internal/testtool/expected/sum_arm64.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package expected
-
-const (
- Offline = "MTgCSzwPrzGigp9phvDPRwUTNGLm1KM2EsEtbz-l2cNieqjaGtnzm65CDXlSxXrl"
- OfflineS = "p89bQg7_jR4nwaSbpEd08ne1jHOEw7Wlnlyv5FHq7ba1Kml3HSBZwEKRzu0gCqEb"
- OvlRoot = "9ifwO6MAaV9kTqRR2O5PJzm8XhfXbr50mFLWyEHQm8OHHcJtAEUgXZzJYoZt9YVV"
- Layers = "INuGActFPwJtS7mAR9Bkt7FD4yoHlXHSJ9CaSAQJrpkUBL_k815Cs_jvRfxy5-a7"
- Net = "kJvy24uk4ePvHoxSKf4vMOhR4NxLbmyWlA9bTS7d3z3fE9WF1Tvpao9g-QuYU4vm"
- Promote = "lYqyYrfjPawIbld5Qz0NbKvd_bmI3nJC1eEnlIQWzsjWE9uA1HuKPAaClnDeyG6L"
- Work = "V6k4FqOBMRCmHiqchs5-joVGZ_MhNWZyXm3gdbU0S7S5eMze7G4SwYMTf66ojKQL"
-)
diff --git a/pkg/internal/testtool/expected/sum_riscv64.go b/pkg/internal/testtool/expected/sum_riscv64.go
deleted file mode 100644
index 53872c08..00000000
--- a/pkg/internal/testtool/expected/sum_riscv64.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package expected
-
-const (
- Offline = "LlieSHVDe1lnKvfI8t4oGRg_2hPxwyy1drmaqc-EKCOENuS9C2YHrp2VY5pSyhbg"
- OfflineS = "qccjM8oYjUuEYPKFFzAxDFVzMerSUKUZc18NdVQoiPWf-70XOsNK8NaUQqjTgTAD"
- OvlRoot = "lpV2bb_KGYFHPiOn-jtGop8K_ew0y1p3BezRp0ebM93_a-T9J-vkqGD5uokda1aN"
- Layers = "sM3DJm210CHPGHkAquIbrXhspB81FpVC60ApQrvJGD5El2i7cSONj7LWf7EWqKpT"
- Net = "JihQUwsVETRYjb2-yIXLYZ6WVsaFebwl8btSYAsNQ2QapS5MZVaI-dYwrVoySycR"
- Promote = "lGqwR4W2OjylSVitMQP1lc6wApOBkbMjsmIqkxQbfEZ3DHEQBbJr84ErW6Xb54zo"
- Work = "aZgtyv6aMtoHFkHAaJr6nLaA7N_SHjShgWPyQ5UdzaIqYSiVqvCrZqSokGTCcTii"
-)
diff --git a/pkg/ir_test.go b/pkg/ir_test.go
index 9cc024ae..7ad5a8f5 100644
--- a/pkg/ir_test.go
+++ b/pkg/ir_test.go
@@ -40,8 +40,8 @@ func TestIRRoundtrip(t *testing.T) {
"exec-offline", "", nil, 0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester"},
pkg.MustPath("/file", false, pkg.NewFile("file", []byte(
"stub file",
@@ -49,7 +49,7 @@ func TestIRRoundtrip(t *testing.T) {
nil, "file:///hakurei.tar",
pkg.Checksum(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
))), pkg.MustPath("/opt", false, pkg.NewTar(pkg.NewDecompress(pkg.NewHTTPGet(
- nil, "file:///testtool.tar.gz",
+ nil, "file:///test-helper.tar.gz",
pkg.Checksum(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
), pkg.Gzip))),
)},
@@ -60,8 +60,8 @@ func TestIRRoundtrip(t *testing.T) {
0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool", "net"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester", "net"},
pkg.MustPath("/file", false, pkg.NewFile("file", []byte(
"stub file",
@@ -69,7 +69,7 @@ func TestIRRoundtrip(t *testing.T) {
nil, "file:///hakurei.tar",
pkg.Checksum(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
))), pkg.MustPath("/opt", false, pkg.NewTar(pkg.NewDecompress(pkg.NewHTTPGet(
- nil, "file:///testtool.tar.gz",
+ nil, "file:///test-helper.tar.gz",
pkg.Checksum(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
), pkg.Gzip))),
)},
@@ -80,8 +80,8 @@ func TestIRRoundtrip(t *testing.T) {
0, false, false,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
- check.MustAbs("/opt/bin/testtool"),
- []string{"testtool", "measured"},
+ check.MustAbs("/opt/bin/tester"),
+ []string{"tester", "measured"},
pkg.MustPath("/file", false, pkg.NewFile("file", []byte(
"stub file",
@@ -89,7 +89,7 @@ func TestIRRoundtrip(t *testing.T) {
nil, "file:///hakurei.tar",
pkg.Checksum(bytes.Repeat([]byte{0xfd}, len(pkg.Checksum{}))),
))), pkg.MustPath("/opt", false, pkg.NewTar(pkg.NewDecompress(pkg.NewHTTPGet(
- nil, "file:///testtool.tar.gz",
+ nil, "file:///test-helper.tar.gz",
pkg.Checksum(bytes.Repeat([]byte{0xfd}, len(pkg.Checksum{}))),
), pkg.Gzip))),
)},
diff --git a/pkg/pkg.go b/pkg/pkg.go
index 5d9d8d48..3515f99f 100644
--- a/pkg/pkg.go
+++ b/pkg/pkg.go
@@ -206,7 +206,7 @@ func (t *TContext) prepareStatus(writeHeader bool) error {
if t.status, t.statusErr = os.OpenFile(
t.statusPath.String(),
syscall.O_CREAT|syscall.O_EXCL|syscall.O_WRONLY,
- 0400,
+ 0444,
); t.statusErr != nil {
return t.statusErr
}
@@ -364,6 +364,9 @@ func (f *FContext) linkSubstitute(ids, substitutes string) (err error) {
if err == nil {
f.statusSPath = statusS
}
+ if errors.Is(err, os.ErrExist) {
+ err = nil
+ }
return
}
@@ -954,8 +957,9 @@ type ChecksumMismatchError struct {
}
func (e *ChecksumMismatchError) Error() string {
- return "got " + Encode(e.Got) +
- " instead of " + Encode(e.Want)
+ return "unexpected checksum\n" +
+ "\t got: " + Encode(e.Got) + "\n" +
+ "\twant: " + Encode(e.Want)
}
// LinknamePrefixError describes a malformed linkname to a [Checksum].
@@ -1521,7 +1525,7 @@ func (c *Cache) openFile(
id := c.Ident(f)
if c.msg.IsVerbose() {
rn := reportName(f, id)
- c.msg.Verbosef("curing %s%s%s in memory...", c.sgrIdent, rn, c.sgrRes)
+ c.msg.Verbosef("opening %s%s%s...", c.sgrIdent, rn, c.sgrRes)
defer func() {
if err == nil {
c.msg.Verbosef("opened %s%s%s for reading", c.sgrIdent, rn, c.sgrRes)
@@ -2053,6 +2057,9 @@ func WhenceString(whence int) string {
}
}
+// isType returns whether v is of concrete type T.
+func isType[T any](v any) bool { _, ok := v.(T); return ok }
+
// cure implements Cure without acquiring a read lock on abortMu. cure must not
// be entered during Abort.
func (c *Cache) cure(a Artifact, curesExempt, rebuild bool) (
@@ -2170,7 +2177,7 @@ func (c *Cache) cure(a Artifact, curesExempt, rebuild bool) (
}
whence = WNew
- if c.msg.IsVerbose() {
+ if c.msg.IsVerbose() && !isType[*Collect](a) {
rn := reportName(a, id)
c.msg.Verbosef("curing %s%s%s...", c.sgrIdent, rn, c.sgrRes)
defer func() {
@@ -2504,7 +2511,7 @@ func (c *Cache) cure(a Artifact, curesExempt, rebuild bool) (
err = f.linkSubstitute(ids, substitutes)
}
if err != nil {
- if c.msg.IsVerbose() {
+ if c.msg.IsVerbose() && !IsCollected(err) {
c.msg.Verbosef(
"cure %s%s%s: %s%v%s",
c.sgrIdent, reportName(ca, id), c.sgrRes,
@@ -2794,7 +2801,6 @@ func Open(
dirSubstitute,
dirIdentifier,
dirChecksum,
- dirStatus,
dirFault,
dirWork,
} {
@@ -2806,6 +2812,17 @@ func Open(
}
}
+ for _, name := range []string{
+ dirStatus,
+ } {
+ if err := os.MkdirAll(
+ base.Append(name).String(),
+ 0711,
+ ); err != nil && !errors.Is(err, os.ErrExist) {
+ return nil, err
+ }
+ }
+
c := Cache{
parent: ctx,
@@ -2919,6 +2936,9 @@ func Open(
return &c, nil
}
+// Path returns the pathname of the directory holding [Cache] state.
+func (c *Cache) Path() *check.Absolute { return c.base }
+
// Collected is returned by [Collect.Cure] to indicate a successful collection.
type Collected struct{}
diff --git a/pkg/pkg_test.go b/pkg/pkg_test.go
index c11b6ac4..66639b5b 100644
--- a/pkg/pkg_test.go
+++ b/pkg/pkg_test.go
@@ -587,7 +587,9 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
// destroy empty fault directory
if err := os.Remove(base.Append("fault").String()); err != nil {
- t.Fatal(err)
+ if !errors.Is(err, syscall.ENOTEMPTY) {
+ t.Fatal(err)
+ }
}
want := tc.want.hash()
@@ -738,6 +740,16 @@ func newWantScrubError(base *check.Absolute) *pkg.ScrubError {
}
}
+// dropFaults removes all fault entries from a cache under testing.
+func dropFaults(t *testing.T, base *check.Absolute) {
+ fault := base.Append("fault")
+ if err := os.RemoveAll(fault.String()); err != nil {
+ t.Fatal(err)
+ } else if err = os.Mkdir(fault.String(), 0); err != nil {
+ t.Fatal(err)
+ }
+}
+
func TestCache(t *testing.T) {
t.Parallel()
@@ -1512,10 +1524,10 @@ func TestCache(t *testing.T) {
"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": {Mode: fs.ModeDir | 0711},
"status/q-VoVBI3IjcWTqwIokpi3y05CP113CHgHslc-XWnhOvDULwzVc3q9Y5xOCm_YyLZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x")},
- "status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
- "status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0400, Data: []byte(statusHeader + "destroyed")},
+ "status/heRgWhNJmhm898V68kw0ta76t4rP1o29tYW_TrdyBWXGfo37K3QWA7Z-JkLXAwcn": {Mode: 0444, Data: []byte(statusHeader + "destroyed")},
+ "status/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: 0444, Data: []byte(statusHeader + "destroyed")},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/dP-6_wIDRRouOaOF-nkBy-IaUbLdYHbOUTrptu7j_qfW01mnHSjYJ0oykUmvUd2x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UjZSrgz7_B7XMd9fHU7jM33UZhWlFgX0rz7JZbCBYR28bCS7jr_CAJdcDhi52ruE")},
@@ -1610,14 +1622,16 @@ func TestCache(t *testing.T) {
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
"identifier": {Mode: fs.ModeDir | 0700},
- "identifier/k8yyhlBV3JpYzzywAnrRWkfp2TmgIDNC6FqMFwrrR2x0C3unBLveDNKgigOjG9MM": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
- "identifier/Xys8hPpJsKirZmTTuT7SwQ6661TCp_ZRu8iUjPPD7pC5E3ll7xw4zhNlZ2PVcz_-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"identifier/8sInO_dhPW9kweit7jVuH_vtMkRxlZT7XE4_yEKPZmpGkgVxkmxz0OpXgbMsH6ET": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
+ "identifier/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
+ "identifier/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {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/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0400, Data: []byte("\x00")},
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0444, Data: []byte("\x00")},
+ "status/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: 0444, Data: []byte(statusHeader + "Lrwxrwxrwx result linkname /proc/nonexistent\n")},
+ "status/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: 0444, Data: []byte(statusHeader)},
"substitute": {Mode: fs.ModeDir | 0700},
"substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
@@ -1756,17 +1770,19 @@ func TestCache(t *testing.T) {
"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/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
+ "identifier/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {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")},
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/8VL-egZySw-RbnHZtxGWdf5Z2v9S9CihrdFwa54Bc5EYMQcEgWEem7QrdCTWlCb8": {Mode: 0444, Data: []byte("\x00")},
+ "status/9_LKKy-vVT9DxQj-SkqSJFZAc0Yehan3LhldTw8fOIP4XX_DrvkpcPkBV5_46e2q": {Mode: 0444, Data: []byte(statusHeader + "Lrwxrwxrwx result linkname /proc/nonexistent\n")},
+ "status/kHH2amyzTN_EpsOyKEOenCROONllTrWAXAwVXOKzx3TgM95-y9ipiz0vkRE-ujBf": {Mode: 0444, Data: []byte(statusHeader)},
"substitute": {Mode: fs.ModeDir | 0700},
- "substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"substitute/MccYezQ4pshkeBV4w_aAEIwvZdKHL3OAgAkR3ouZ43EF94Ur1HBHaN7njPfJAj50": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
"substitute/VV5W0_DiA1iylaqbKFThp1ZpV_y1ccVS1XyqDnDaXoHQ-EEyPI4XFrQHcHOF2hWG": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
+ "substitute/socGRnhdsJlJ4Z01ZwHFZdLzFH0rWvoaJrylcUKtvhBdGsE7VoYl-vdUuvfK8B4I": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
"work": {Mode: fs.ModeDir | 0700},
}},
@@ -1794,8 +1810,9 @@ func TestErrors(t *testing.T) {
Want: (pkg.Checksum)(bytes.Repeat([]byte{
0x75, 0xe6, 0x9d, 0x6d, 0xe7, 0x9f,
}, 8)),
- }, "got AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
- " instead of deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
+ }, "unexpected checksum\n" +
+ "\t got: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" +
+ "\twant: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
{"ResponseStatusError", pkg.ResponseStatusError(
http.StatusNotAcceptable,
@@ -1856,7 +1873,9 @@ func TestScrubError(t *testing.T) {
{"sample", *newWantScrubError(
fhs.AbsVarLib.Append("cure"),
), `checksum mismatches:
-got vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX instead of _wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+unexpected checksum
+ got: vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX
+ want: _wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
dangling identifiers:
_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@@ -1911,7 +1930,9 @@ errors during scrub:
},
},
}, `checksum mismatches:
-got AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA instead of CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN
+unexpected checksum
+ got: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ want: CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN
dangling identifiers:
deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
diff --git a/pkg/tar.go b/pkg/tar.go
index 9a8c4b76..33952b05 100644
--- a/pkg/tar.go
+++ b/pkg/tar.go
@@ -66,6 +66,9 @@ func (a *tarArtifact) Inputs() []Artifact {
// IsExclusive returns false: decompressor and tar reader are fully sequential.
func (a *tarArtifact) IsExclusive() bool { return false }
+// Revision satisfies [RevisionArtifact] for status behaviour.
+func (*tarArtifact) Revision() uint64 { return 0 }
+
// A DisallowedTypeflagError describes a disallowed typeflag encountered while
// unpacking a tarball.
type DisallowedTypeflagError byte
@@ -76,6 +79,11 @@ func (e DisallowedTypeflagError) Error() string {
// Cure cures the [Artifact], producing a directory located at work.
func (a *tarArtifact) Cure(t *TContext) (err error) {
+ var status io.Writer
+ if status, err = t.GetStatusWriter(); err != nil {
+ return
+ }
+
var r io.ReadCloser
if r, err = t.Open(a.f); err != nil {
return
@@ -110,6 +118,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
var header *tar.Header
tr := tar.NewReader(r)
+ msg := t.GetMessage()
for header, err = tr.Next(); err == nil; header, err = tr.Next() {
typeflag := header.Typeflag
if typeflag == 0 {
@@ -126,6 +135,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
}
}
+ var m string
switch typeflag {
case tar.TypeReg:
var f *os.File
@@ -142,6 +152,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
} else if err = f.Close(); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s (%d bytes)",
+ header.FileInfo().Mode(),
+ header.Name,
+ header.Size,
+ )
break
case tar.TypeLink:
@@ -151,6 +168,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s linkname %s",
+ header.FileInfo().Mode(),
+ header.Name,
+ header.Linkname,
+ )
break
case tar.TypeSymlink:
@@ -160,6 +184,13 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s linkname %s",
+ header.FileInfo().Mode(),
+ header.Name,
+ header.Linkname,
+ )
break
case tar.TypeDir:
@@ -170,21 +201,37 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
if err = root.MkdirAll(header.Name, 0700); err != nil {
return
}
+
+ m = fmt.Sprintf(
+ "%s %s",
+ header.FileInfo().Mode(),
+ header.Name,
+ )
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,
+ m = fmt.Sprintf(
+ "skipping character device %d, %d %q",
+ header.Devmajor, header.Devminor, header.Name,
)
- continue
+ break
case tar.TypeXGlobalHeader:
- continue // ignore
+ m = "skipping PAX global key-value record"
+ break
default:
return DisallowedTypeflagError(typeflag)
}
+
+ if m != "" {
+ msg.Verbose(m)
+ if _, err = io.WriteString(status, m); err != nil {
+ return
+ } else if _, err = status.Write([]byte{'\n'}); err != nil {
+ return
+ }
+ }
}
if errors.Is(err, io.EOF) {
err = nil
diff --git a/pkg/tar_test.go b/pkg/tar_test.go
index 5462714f..e8a42f73 100644
--- a/pkg/tar_test.go
+++ b/pkg/tar_test.go
@@ -44,6 +44,24 @@ func TestTar(t *testing.T) {
}
wantExpandEncode := pkg.Encode(wantExpand.hash())
+ const (
+ wantStatus = `drwx------ checksum/
+drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/
+-r-------- checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check (2 bytes)
+drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/
+Lrwxrwxrwx checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so linkname /proc/nonexistent/libedac.so
+drwx------ checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig/
+drwx------ identifier/
+Lrwxrwxrwx identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY linkname ../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP
+Lrwxrwxrwx identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa linkname ../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP
+drwx------ work/
+`
+
+ wantStatusExpand = `drwx------ lib/
+Lrwxrwxrwx lib/libedac.so linkname /proc/nonexistent/libedac.so
+`
+ )
+
checkWithCache(t, []cacheTestCase{
{"http", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
checkTarHTTP(t, base, c, fstest.MapFS{
@@ -79,8 +97,12 @@ func TestTar(t *testing.T) {
"checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500},
"identifier": {Mode: fs.ModeDir | 0700},
- "identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
- "identifier/v9DUj2R4YK_3ae0m9VuUYI-HJysDDCENu1k10thxioycRzFH1Qejw5bBGukm4IdL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
+ "identifier/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
+ "identifier/ld6DxwiP2Gj47Ue2L_pFv6NrOth8nkU5W1voMyivd2aVROrorGqPlpbyHUnU1AvI": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
+
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: 0444, Data: []byte(statusHeader + wantStatus)},
+ "status/ld6DxwiP2Gj47Ue2L_pFv6NrOth8nkU5W1voMyivd2aVROrorGqPlpbyHUnU1AvI": {Mode: 0444, Data: []byte(statusHeader + wantStatus)},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -103,8 +125,12 @@ func TestTar(t *testing.T) {
"checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
"identifier": {Mode: fs.ModeDir | 0700},
- "identifier/1SuvgGltcsgqps9tWqjULG8RCdpx_6KVWXdsMd5xPKvdtysOxqpE-3bLu4j0WpGk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
- "identifier/snWp53xxNdx6cV5KSJqzyVWzLlTsFd8udOisIu8Rgxly09mGcxufYCoQ5CQrHDyZ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
+ "identifier/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
+ "identifier/fsMFOV4_LoYWbC8GNqL2zjbpzNzT80vPWbSw4L47caKVIta333WIW2TZXoSW8ntH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
+
+ "status": {Mode: fs.ModeDir | 0711},
+ "status/82-Dwiovp_DGXPBmnmrTk4XtsduvTBBXxnJTBgyp6avsUhjcqmL9yKQLxkwJJM0x": {Mode: 0444, Data: []byte(statusHeader + wantStatusExpand)},
+ "status/fsMFOV4_LoYWbC8GNqL2zjbpzNzT80vPWbSw4L47caKVIta333WIW2TZXoSW8ntH": {Mode: 0444, Data: []byte(statusHeader + wantStatusExpand)},
"substitute": {Mode: fs.ModeDir | 0700},
@@ -206,13 +232,13 @@ func checkTarHTTP(
{"directory", pkg.NewTar(&tarDir), ignorePathname, want, pkg.WNew, nil},
- {"multiple entries", pkg.NewTar(&tarDirMulti), nil, nil, pkg.WNew, errors.New(
+ {"multiple entries", pkg.NewTar(&tarDirMulti), nil, nil, pkg.WNew, errors.Join(errors.New(
"input directory does not contain a single regular file",
- )},
+ ))},
- {"bad type", pkg.NewTar(&tarDirType), nil, nil, pkg.WNew, errors.New(
+ {"bad type", pkg.NewTar(&tarDirType), nil, nil, pkg.WNew, errors.Join(errors.New(
"input directory does not contain a single regular file",
- )},
+ ))},
{"error passthrough", pkg.NewTar(&stubArtifact{
kind: pkg.KindExec,
@@ -220,6 +246,8 @@ func checkTarHTTP(
cure: func(t *pkg.TContext) error {
return stub.UniqueError(0xcafe)
},
- }), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
+ }), nil, nil, pkg.WNew, errors.Join(stub.UniqueError(0xcafe))},
})
+
+ dropFaults(t, base)
}