aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/pkg.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-07-08 14:19:17 +0900
committerOphestra <cat@gensokyo.uk>2026-07-08 14:19:17 +0900
commit3c6e9b3d0526a9338dc897a8e288647b2ec12b10 (patch)
tree11116bbe25971f9e29de627857b599974132f8a3 /internal/pkg/pkg.go
parentaa5e77ef277d5cb144e4841f3c1ab41282faac01 (diff)
internal/pkg: expose cure whence
Useful for cure determinism validation of KindExec. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/pkg.go')
-rw-r--r--internal/pkg/pkg.go69
1 files changed, 62 insertions, 7 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index aadfa308..9d32231d 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -303,7 +303,7 @@ func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
}
var pathname *check.Absolute
- if pathname, _, err = c.cache.cure(a, true); err != nil {
+ if pathname, _, _, err = c.cache.cure(a, true); err != nil {
return
}
@@ -356,12 +356,12 @@ func (f *FContext) linkSubstitute(ids, substitutes string) (err error) {
return
}
-// InvalidLookupError is the identifier of non-dependency [Artifact] looked up
+// InvalidLookupError is the identifier of non-input [Artifact] looked up
// via [FContext.GetArtifact] by a misbehaving [Artifact] implementation.
type InvalidLookupError ID
func (e InvalidLookupError) Error() string {
- return "attempting to look up non-dependency artifact " + Encode(e)
+ return "attempting to look up non-input artifact " + Encode(e)
}
var _ error = InvalidLookupError{}
@@ -602,7 +602,7 @@ type cureRes struct {
checksum unique.Handle[Checksum]
}
-// A pendingArtifactDep is a dependency [Artifact] pending concurrent curing,
+// A pendingArtifactDep is an input [Artifact] pending concurrent curing,
// subject to the cures limit. Values pointed to by result addresses are safe
// to access after the [sync.WaitGroup] associated with this pendingArtifactDep
// is done. pendingArtifactDep must not be reused or modified after it is sent
@@ -676,7 +676,7 @@ const (
// suppressed regardless of [message.Msg] state.
CSuppressInit
- // CIgnoreSubstitutes disables content-based dependency substitution.
+ // CIgnoreSubstitutes disables content-based input substitution.
CIgnoreSubstitutes
// CExternShallow arranges for only non-flood inputs to be fetched when
@@ -733,7 +733,7 @@ type Cache struct {
parent context.Context
// For deriving curing context, must not be accessed directly.
toplevel atomic.Pointer[toplevel]
- // For waiting on dependency curing goroutines.
+ // For waiting on input curing goroutines.
wg sync.WaitGroup
// Reports new cures and passed to [Artifact].
msg message.Msg
@@ -1633,6 +1633,24 @@ func (c *Cache) Cure(a Artifact) (
return
}
+ pathname, checksum, _, err = c.cure(a, true)
+ return
+}
+
+// CureWhence is like Cure, but returns the whence value.
+func (c *Cache) CureWhence(a Artifact) (
+ pathname *check.Absolute,
+ checksum unique.Handle[Checksum],
+ whence int,
+ err error,
+) {
+ c.abortMu.RLock()
+ defer c.abortMu.RUnlock()
+
+ if err = c.toplevel.Load().ctx.Err(); err != nil {
+ return
+ }
+
return c.cure(a, true)
}
@@ -1971,11 +1989,41 @@ func (e HangingInputError) Error() string {
return Encode(unique.Handle[ID](e).Value()) + " is unavailable"
}
+const (
+ // WNew indicates a cure entering the implementation.
+ WNew = iota
+ // WCache indicates an [Artifact] present in the cache.
+ WCache
+ // WSubstitute indicates an [Artifact] hitting a content-based input
+ // substitution.
+ WSubstitute
+ // WExternal indicates a cure entering the external cache.
+ WExternal
+)
+
+// WhenceString returns a printable string for a whence value.
+func WhenceString(whence int) string {
+ switch whence {
+ case WNew:
+ return "new"
+ case WCache:
+ return "cache"
+ case WSubstitute:
+ return "substitute"
+ case WExternal:
+ return "external"
+
+ default:
+ return "invalid whence " + strconv.Itoa(whence)
+ }
+}
+
// cure implements Cure without acquiring a read lock on abortMu. cure must not
// be entered during Abort.
func (c *Cache) cure(a Artifact, curesExempt bool) (
pathname *check.Absolute,
checksum unique.Handle[Checksum],
+ whence int,
err error,
) {
id := c.Ident(a)
@@ -2001,6 +2049,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
)
ctx, done, checksum, err = c.loadOrStoreIdent(id)
if done == nil {
+ whence = WCache
return
} else {
defer func() { c.finaliseIdent(done, id, checksum, err) }()
@@ -2008,6 +2057,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
checksum, err = c.tryChecksum(pathname)
if err == nil || !errors.Is(err, os.ErrNotExist) {
+ whence = WCache
return
}
@@ -2077,6 +2127,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
}
}
+ whence = WNew
if c.msg.IsVerbose() {
rn := reportName(a, id)
c.msg.Verbosef("curing %s...", rn)
@@ -2095,6 +2146,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
// cure FileArtifact outside type switch to skip TContext initialisation
if f, ok := a.(FileArtifact); ok {
if checksumFi != nil {
+ whence = WCache
if !checksumFi.Mode().IsRegular() {
// unreachable
err = InvalidFileModeError(checksumFi.Mode())
@@ -2199,6 +2251,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
}
if checksumFi != nil {
+ whence = WCache
if !checksumFi.Mode().IsDir() {
// unreachable
err = InvalidFileModeError(checksumFi.Mode())
@@ -2308,6 +2361,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
return
}
if substituteChecksum != zeroChecksum {
+ whence = WSubstitute
checksum = substituteChecksum
checksums = Encode(checksum.Value())
checksumPathname = c.base.Append(
@@ -2332,6 +2386,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
defer f.destroy(&err)
if extern {
+ whence = WExternal
if checksum != zeroChecksum && externChecksum != checksum {
err = &ChecksumMismatchError{externChecksum.Value(), checksum.Value()}
if c.msg.IsVerbose() {
@@ -2471,7 +2526,7 @@ func (pending *pendingArtifactDep) cure(c *Cache) {
defer pending.Done()
var err error
- pending.resP.pathname, pending.resP.checksum, err = c.cure(pending.a, false)
+ pending.resP.pathname, pending.resP.checksum, _, err = c.cure(pending.a, false)
if err == nil {
return
}