internal/pkg: implement caching for files
All checks were successful
Test / Create distribution (push) Successful in 45s
Test / Sandbox (push) Successful in 2m30s
Test / Hakurei (push) Successful in 3m30s
Test / ShareFS (push) Successful in 3m27s
Test / Hpkg (push) Successful in 4m19s
Test / Sandbox (race detector) (push) Successful in 4m40s
Test / Hakurei (race detector) (push) Successful in 5m37s
Test / Flake checks (push) Successful in 1m40s
All checks were successful
Test / Create distribution (push) Successful in 45s
Test / Sandbox (push) Successful in 2m30s
Test / Hakurei (push) Successful in 3m30s
Test / ShareFS (push) Successful in 3m27s
Test / Hpkg (push) Successful in 4m19s
Test / Sandbox (race detector) (push) Successful in 4m40s
Test / Hakurei (race detector) (push) Successful in 5m37s
Test / Flake checks (push) Successful in 1m40s
This change contains primitives for validating and caching single-file artifacts. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
68
internal/pkg/dir.go
Normal file
68
internal/pkg/dir.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/gob"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"hakurei.app/container/check"
|
||||
)
|
||||
|
||||
// FlatEntry is the representation of a directory entry via [Flatten].
|
||||
type FlatEntry struct {
|
||||
Name string // base name of the file
|
||||
Mode fs.FileMode // file mode bits
|
||||
Data []byte // file content or symlink destination
|
||||
}
|
||||
|
||||
// Flatten writes a deterministic representation of the contents of fsys to w.
|
||||
// The resulting data can be hashed to produce a deterministic checksum for the
|
||||
// directory.
|
||||
func Flatten(fsys fs.FS, root string, w io.Writer) error {
|
||||
e := gob.NewEncoder(w)
|
||||
return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fi fs.FileInfo
|
||||
fi, err = d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ent := FlatEntry{
|
||||
Name: fi.Name(),
|
||||
Mode: fi.Mode(),
|
||||
}
|
||||
if ent.Mode.IsRegular() {
|
||||
if ent.Data, err = fs.ReadFile(fsys, path); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if ent.Mode&fs.ModeSymlink != 0 {
|
||||
var newpath string
|
||||
if newpath, err = fs.ReadLink(fsys, path); err != nil {
|
||||
return err
|
||||
}
|
||||
ent.Data = []byte(newpath)
|
||||
}
|
||||
|
||||
return e.Encode(&ent)
|
||||
})
|
||||
}
|
||||
|
||||
// HashFS returns a checksum produced by hashing the result of [Flatten].
|
||||
func HashFS(fsys fs.FS, root string) (Checksum, error) {
|
||||
h := sha512.New384()
|
||||
if err := Flatten(fsys, root, h); err != nil {
|
||||
return Checksum{}, err
|
||||
}
|
||||
return (Checksum)(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// HashDir returns a checksum produced by hashing the result of [Flatten].
|
||||
func HashDir(pathname *check.Absolute) (Checksum, error) {
|
||||
return HashFS(os.DirFS(pathname.String()), ".")
|
||||
}
|
||||
Reference in New Issue
Block a user