diff --git a/internal/pkg/dir_test.go b/internal/pkg/dir_test.go index ab456c9..87683fb 100644 --- a/internal/pkg/dir_test.go +++ b/internal/pkg/dir_test.go @@ -410,6 +410,27 @@ func TestFlatten(t *testing.T) { {Mode: fs.ModeDir | 0700, Path: "temp"}, {Mode: fs.ModeDir | 0700, Path: "work"}, }, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")}, + + {"sample file short", fstest.MapFS{ + ".": {Mode: fs.ModeDir | 0700}, + + "checksum": {Mode: fs.ModeDir | 0700}, + "checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: 0400, Data: []byte{0}}, + + "identifier": {Mode: fs.ModeDir | 0700}, + "identifier/lIx_W4M7tVOcQ8jh08EJOfXf4brRmkEEjvUa7c17vVUzlmtUxlhhrgqmc9aZhjbn": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")}, + + "work": {Mode: fs.ModeDir | 0700}, + }, []pkg.FlatEntry{ + {Mode: fs.ModeDir | 0700, Path: "."}, + {Mode: fs.ModeDir | 0700, Path: "checksum"}, + {Mode: 0400, Path: "checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX", Data: []byte{0}}, + + {Mode: fs.ModeDir | 0700, Path: "identifier"}, + {Mode: fs.ModeSymlink | 0777, Path: "identifier/lIx_W4M7tVOcQ8jh08EJOfXf4brRmkEEjvUa7c17vVUzlmtUxlhhrgqmc9aZhjbn", Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")}, + + {Mode: fs.ModeDir | 0700, Path: "work"}, + }, pkg.MustDecode("hnrfmJtivNKcgtETsKnU9gP_OwPgpNY3DSUJnmxnmeOODSO-YBvEBiTgieY4AAd7")}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/pkg/file.go b/internal/pkg/file.go new file mode 100644 index 0000000..d7ac933 --- /dev/null +++ b/internal/pkg/file.go @@ -0,0 +1,40 @@ +package pkg + +import ( + "crypto/sha512" + "syscall" +) + +// A fileArtifact is an [Artifact] that cures into data known ahead of time. +type fileArtifact []byte + +var _ KnownChecksum = fileArtifact{} + +// NewFile returns a [File] that cures into a caller-supplied byte slice. +// +// Caller must not modify data after NewBin returns. +func NewFile(data []byte) File { return fileArtifact(data) } + +// Kind returns the hardcoded [Kind] constant. +func (a fileArtifact) Kind() Kind { return KindFile } + +// Params returns the result of Data. +func (a fileArtifact) Params() []byte { return a } + +// Dependencies returns a nil slice. +func (a fileArtifact) Dependencies() []Artifact { return nil } + +// Checksum computes and returns the checksum of caller-supplied data. +func (a fileArtifact) Checksum() Checksum { + h := sha512.New384() + h.Write(a) + return Checksum(h.Sum(nil)) +} + +// Data returns the caller-supplied data. +func (a fileArtifact) Data() ([]byte, error) { return a, nil } + +// Cure returns syscall.ENOTSUP. Callers should use Data instead. +func (a fileArtifact) Cure(*CureContext) (err error) { + return syscall.ENOTSUP +} diff --git a/internal/pkg/file_test.go b/internal/pkg/file_test.go new file mode 100644 index 0000000..48e5562 --- /dev/null +++ b/internal/pkg/file_test.go @@ -0,0 +1,29 @@ +package pkg_test + +import ( + "testing" + + "hakurei.app/container/check" + "hakurei.app/internal/pkg" +) + +func TestFile(t *testing.T) { + t.Parallel() + + checkWithCache(t, []cacheTestCase{ + {"file", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { + c.SetStrict(true) + + cureMany(t, c, []cureStep{ + {"short", pkg.NewFile([]byte{0}), base.Append( + "identifier", + "lIx_W4M7tVOcQ8jh08EJOfXf4brRmkEEjvUa7c17vVUzlmtUxlhhrgqmc9aZhjbn", + ), pkg.MustDecode( + "vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX", + ), nil}, + }) + }, pkg.MustDecode( + "hnrfmJtivNKcgtETsKnU9gP_OwPgpNY3DSUJnmxnmeOODSO-YBvEBiTgieY4AAd7", + )}, + }) +} diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index 423aea1..93677db 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -188,6 +188,8 @@ const ( // KindExecNet is the kind of [Artifact] returned by [NewExec] but with a // non-nil checksum. KindExecNet + // KindFile is the kind of [Artifact] returned by [NewFile]. + KindFile ) // Ident returns a deterministic identifier for the supplied params and