diff options
Diffstat (limited to 'internal/pkg/pkg.go')
| -rw-r--r-- | internal/pkg/pkg.go | 68 |
1 files changed, 48 insertions, 20 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index ec81995d..e1055aca 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -53,9 +53,36 @@ func MustDecode(s string) Checksum { } } -// CacheDataFunc tries to load [File] from [Cache], and if that fails, obtains -// it via [File.Data] instead. -type CacheDataFunc func(f File) (data []byte, err error) +// CureContext is passed to [Artifact.Cure] and contains information and methods +// useful for curing the [Artifact], like requesting the data of [File], or that +// other artifacts be cured. +// +// Methods of CureContext are safe for concurrent use. CureContext is valid +// until [Artifact.Cure] returns. +type CureContext struct { + // Address of underlying [Cache], should be zeroed after [Artifact.Cure] + // returns and must not be exposed directly. + cache *Cache + + // Populated during [Cache.Cure]. + work, temp *check.Absolute +} + +// GetWorkDir returns a pathname to a directory which [Artifact] is expected to +// write its output to. This is not the final resting place of the [Artifact] +// and this pathname should not be directly referred to in the final contents. +func (c *CureContext) GetWorkDir() *check.Absolute { return c.work } + +// GetTempDir returns a pathname which implementations may use as scratch space. +// A directory is not created automatically, implementations are expected to +// create it if they wish to use it, using [os.MkdirAll]. +func (c *CureContext) GetTempDir() *check.Absolute { return c.temp } + +// LoadData tries to load [File] from [Cache], and if that fails, obtains it via +// [File.Data] instead. Notably, it does not cure [File]. +func (c *CureContext) LoadData(f File) (data []byte, err error) { + return c.cache.loadData(f) +} // An Artifact is a read-only reference to a piece of data that may be created // deterministically but might not currently be available in memory or on the @@ -83,18 +110,15 @@ type Artifact interface { // Result must remain identical across multiple invocations. Dependencies() []Artifact - // Cure cures the current [Artifact] to the caller-specified temporary - // pathname. This is not the final resting place of the [Artifact] and this - // pathname should not be directly referred to in the final contents. + // Cure cures the current [Artifact] to the working directory obtained via + // [CureContext.GetWorkDir]. // // 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]. // - // 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) + // Implementations must not retain c. + Cure(c *CureContext) (err error) } // KnownIdent is optionally implemented by [Artifact] and is used instead of @@ -515,7 +539,7 @@ func (c *Cache) finaliseIdent( close(done) } -// loadData provides [CacheDataFunc] for [Artifact.Cure]. +// loadData provides [CureContext.LoadData] for [Artifact.Cure]. func (c *Cache) loadData(f File) (data []byte, err error) { var r *os.File if kc, ok := f.(KnownChecksum); ok { @@ -790,10 +814,14 @@ func (c *Cache) Cure(a Artifact) ( return } - workPathname := c.base.Append(dirWork, ids) + cc := CureContext{ + cache: c, + work: c.base.Append(dirWork, ids), + temp: c.base.Append(dirTemp, ids), + } defer func() { if err != nil { - chmodErr, removeErr := removeAll(workPathname) + chmodErr, removeErr := removeAll(cc.work) if chmodErr != nil || removeErr != nil { err = errors.Join(err, chmodErr, removeErr) } else if errors.Is(err, os.ErrExist) { @@ -803,17 +831,17 @@ func (c *Cache) Cure(a Artifact) ( } }() - tempPathname := c.base.Append(dirTemp, ids) - if err = a.Cure(workPathname, tempPathname, c.loadData); err != nil { + if err = a.Cure(&cc); err != nil { return } - if chmodErr, removeErr := removeAll(tempPathname); chmodErr != nil || removeErr != nil { + cc.cache = nil + if chmodErr, removeErr := removeAll(cc.temp); chmodErr != nil || removeErr != nil { err = errors.Join(err, chmodErr, removeErr) return } var fi os.FileInfo - if fi, err = os.Lstat(workPathname.String()); err != nil { + if fi, err = os.Lstat(cc.work.String()); err != nil { if errors.Is(err, os.ErrNotExist) { err = NoOutputError{} } @@ -831,7 +859,7 @@ func (c *Cache) Cure(a Artifact) ( var gotChecksum Checksum if gotChecksum, err = HashFS( - dotOverrideFS{os.DirFS(workPathname.String()).(dirFS)}, + dotOverrideFS{os.DirFS(cc.work.String()).(dirFS)}, ".", ); err != nil { return @@ -854,12 +882,12 @@ func (c *Cache) Cure(a Artifact) ( } } - if err = os.Chmod(workPathname.String(), 0700); err != nil { + if err = os.Chmod(cc.work.String(), 0700); err != nil { return } c.checksumMu.Lock() if err = os.Rename( - workPathname.String(), + cc.work.String(), checksumPathname.String(), ); err != nil { if !errors.Is(err, os.ErrExist) { |
