internal/pkg: temporary scratch space for cure
All checks were successful
Test / Create distribution (push) Successful in 43s
Test / Sandbox (push) Successful in 2m30s
Test / ShareFS (push) Successful in 3m40s
Test / Hpkg (push) Successful in 4m21s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m52s
Test / Hakurei (push) Successful in 2m35s
Test / Flake checks (push) Successful in 1m52s

This allows for more flexibility during implementation. The use case that required this was for expanding single directory tarballs.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-01-05 01:05:27 +09:00
parent 4da26681b5
commit f3aa31e401
4 changed files with 52 additions and 37 deletions

View File

@@ -89,7 +89,11 @@ type Artifact interface {
// If the implementation produces a single file, it must implement [File]
// as well. In that case, Cure must produce a single regular file with
// contents identical to that returned by [File.Data].
Cure(work *check.Absolute, loadData CacheDataFunc) (err error)
//
// Implementations may use temp as scratch space. The caller is not required
// to create a directory here, implementations are expected to create it if
// they wish to use it, using [os.MkdirAll].
Cure(work, temp *check.Absolute, loadData CacheDataFunc) (err error)
}
// KnownIdent is optionally implemented by [Artifact] and is used instead of
@@ -183,6 +187,9 @@ const (
// dirWork is the directory name appended to Cache.base for working
// pathnames set up during [Cache.Cure].
dirWork = "work"
// dirTemp is the directory name appended to Cache.base for scratch space
// pathnames allocated during [Cache.Cure].
dirTemp = "temp"
// checksumLinknamePrefix is prepended to the encoded [Checksum] value
// of an [Artifact] when creating a symbolic link to dirChecksum.
@@ -346,6 +353,28 @@ func (NoOutputError) Error() string {
return "artifact cured successfully but did not produce any output"
}
// removeAll is similar to [os.RemoveAll] but is robust against any permissions.
func removeAll(pathname *check.Absolute) (chmodErr, removeErr error) {
chmodErr = filepath.WalkDir(pathname.String(), func(
path string,
d fs.DirEntry,
err error,
) error {
if err != nil {
return err
}
if d.IsDir() {
return os.Chmod(path, 0700)
}
return nil
})
if errors.Is(chmodErr, os.ErrNotExist) {
chmodErr = nil
}
removeErr = os.RemoveAll(pathname.String())
return
}
// Cure cures the [Artifact] and returns its pathname and [Checksum].
func (c *Cache) Cure(a Artifact) (
pathname *check.Absolute,
@@ -489,27 +518,8 @@ func (c *Cache) Cure(a Artifact) (
workPathname := c.base.Append(dirWork, ids)
defer func() {
// must not use the value of checksum string as it might be zeroed
// to cancel the deferred symlink operation
if err != nil {
chmodErr := filepath.WalkDir(workPathname.String(), func(
path string,
d fs.DirEntry,
err error,
) error {
if err != nil {
return err
}
if d.IsDir() {
return os.Chmod(path, 0700)
}
return nil
})
if errors.Is(chmodErr, os.ErrNotExist) {
chmodErr = nil
}
removeErr := os.RemoveAll(workPathname.String())
chmodErr, removeErr := removeAll(workPathname)
if chmodErr != nil || removeErr != nil {
err = errors.Join(err, chmodErr, removeErr)
} else if errors.Is(err, os.ErrExist) {
@@ -519,7 +529,12 @@ func (c *Cache) Cure(a Artifact) (
}
}()
if err = a.Cure(workPathname, c.loadData); err != nil {
tempPathname := c.base.Append(dirTemp, ids)
if err = a.Cure(workPathname, tempPathname, c.loadData); err != nil {
return
}
if chmodErr, removeErr := removeAll(tempPathname); chmodErr != nil || removeErr != nil {
err = errors.Join(err, chmodErr, removeErr)
return
}