internal/pkg: standardise artifact IR
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m41s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m35s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 6m0s
Test / Flake checks (push) Successful in 1m46s
All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m41s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m35s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 6m0s
Test / Flake checks (push) Successful in 1m46s
This should hopefully provide good separation between the artifact curing backend implementation and the (still work in progress) language. Making the IR parseable also guarantees uniqueness of the representation. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -65,35 +65,6 @@ func MustDecode(s string) (checksum Checksum) {
|
||||
return
|
||||
}
|
||||
|
||||
// IContext is passed to [Artifact.Params] and provides identifier information
|
||||
// and the target [hash.Hash] for writing params into.
|
||||
//
|
||||
// Methods of IContext are safe for concurrent use. IContext is valid
|
||||
// until [Artifact.Params] returns.
|
||||
type IContext struct {
|
||||
// Address of underlying [Cache], should be zeroed or made unusable after
|
||||
// [Artifact.Params] returns and must not be exposed directly.
|
||||
cache *Cache
|
||||
// Made available for writing, should be zeroed after [Artifact.Params]
|
||||
// returns. Internal state must not be inspected.
|
||||
h hash.Hash
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying [context.Context].
|
||||
func (i *IContext) Unwrap() context.Context { return i.cache.ctx }
|
||||
|
||||
// GetHash returns the underlying [hash.Hash] for writing. Callers must not
|
||||
// attempt to inspect its internal state.
|
||||
func (i *IContext) GetHash() hash.Hash { return i.h }
|
||||
|
||||
// WriteIdent writes the identifier of [Artifact] to the underlying [hash.Hash].
|
||||
func (i *IContext) WriteIdent(a Artifact) {
|
||||
buf := i.cache.getIdentBuf()
|
||||
*(*ID)(buf[wordSize:]) = i.cache.Ident(a).Value()
|
||||
i.h.Write(buf[wordSize:])
|
||||
i.cache.putIdentBuf(buf)
|
||||
}
|
||||
|
||||
// TContext is passed to [TrivialArtifact.Cure] and provides information and
|
||||
// methods required for curing the [TrivialArtifact].
|
||||
//
|
||||
@@ -238,10 +209,12 @@ type Artifact interface {
|
||||
// [Artifact] is allowed to return the same [Kind] value.
|
||||
Kind() Kind
|
||||
|
||||
// Params writes opaque bytes that describes [Artifact]. Implementations
|
||||
// Params writes deterministic values describing [Artifact]. Implementations
|
||||
// must guarantee that these values are unique among differing instances
|
||||
// of the same implementation with the same dependencies. Callers must not
|
||||
// attempt to interpret these params.
|
||||
// of the same implementation with identical dependencies and conveys enough
|
||||
// information to create another instance of [Artifact] identical to the
|
||||
// instance emitting these values. The new instance created via [IRReadFunc]
|
||||
// from these values must then produce identical IR values.
|
||||
//
|
||||
// Result must remain identical across multiple invocations.
|
||||
Params(ctx *IContext)
|
||||
@@ -564,47 +537,13 @@ func (c *Cache) unsafeIdent(a Artifact, encodeKind bool) (
|
||||
return
|
||||
}
|
||||
|
||||
deps := a.Dependencies()
|
||||
idents := make([]*extIdent, len(deps))
|
||||
for i, d := range deps {
|
||||
dbuf, did := c.unsafeIdent(d, true)
|
||||
if dbuf == nil {
|
||||
dbuf = c.getIdentBuf()
|
||||
binary.LittleEndian.PutUint64(dbuf[:], uint64(d.Kind()))
|
||||
*(*ID)(dbuf[wordSize:]) = did.Value()
|
||||
} else {
|
||||
c.storeIdent(d, dbuf)
|
||||
}
|
||||
defer c.putIdentBuf(dbuf)
|
||||
idents[i] = dbuf
|
||||
}
|
||||
slices.SortFunc(idents, func(a, b *extIdent) int {
|
||||
return bytes.Compare(a[:], b[:])
|
||||
})
|
||||
idents = slices.CompactFunc(idents, func(a, b *extIdent) bool {
|
||||
return *a == *b
|
||||
})
|
||||
|
||||
buf = c.getIdentBuf()
|
||||
h := sha512.New384()
|
||||
if err := c.Encode(h, a); err != nil {
|
||||
// unreachable
|
||||
panic(err)
|
||||
}
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(a.Kind()))
|
||||
h.Write(buf[:wordSize])
|
||||
for _, dn := range idents {
|
||||
h.Write(dn[:])
|
||||
}
|
||||
kcBuf := c.getIdentBuf()
|
||||
if kc, ok := a.(KnownChecksum); ok {
|
||||
*(*Checksum)(kcBuf[:]) = kc.Checksum()
|
||||
} else {
|
||||
*(*Checksum)(kcBuf[:]) = Checksum{}
|
||||
}
|
||||
h.Write((*Checksum)(kcBuf[:])[:])
|
||||
c.putIdentBuf(kcBuf)
|
||||
|
||||
i := IContext{c, h}
|
||||
a.Params(&i)
|
||||
i.cache, i.h = nil, nil
|
||||
|
||||
h.Sum(buf[wordSize:wordSize])
|
||||
return
|
||||
}
|
||||
@@ -1000,8 +939,9 @@ func (c *Cache) openFile(f FileArtifact) (r io.ReadCloser, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// InvalidFileModeError describes an [Artifact.Cure] that did not result in
|
||||
// a regular file or directory located at the work pathname.
|
||||
// InvalidFileModeError describes a [FloodArtifact.Cure] or
|
||||
// [TrivialArtifact.Cure] that did not result in a regular file or directory
|
||||
// located at the work pathname.
|
||||
type InvalidFileModeError fs.FileMode
|
||||
|
||||
// Error returns a constant string.
|
||||
@@ -1009,8 +949,8 @@ func (e InvalidFileModeError) Error() string {
|
||||
return "artifact did not produce a regular file or directory"
|
||||
}
|
||||
|
||||
// NoOutputError describes an [Artifact.Cure] that did not populate its
|
||||
// work pathname despite completing successfully.
|
||||
// NoOutputError describes a [FloodArtifact.Cure] or [TrivialArtifact.Cure]
|
||||
// that did not populate its work pathname despite completing successfully.
|
||||
type NoOutputError struct{}
|
||||
|
||||
// Unwrap returns [os.ErrNotExist].
|
||||
|
||||
Reference in New Issue
Block a user