diff options
Diffstat (limited to 'internal/pkg/pkg.go')
| -rw-r--r-- | internal/pkg/pkg.go | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index 73b93e3e..40bad6ff 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -2,11 +2,14 @@ package pkg import ( + "bytes" "crypto/sha512" "encoding/base64" + "encoding/binary" "errors" "io" "os" + "slices" "sync" "hakurei.app/container/check" @@ -39,6 +42,11 @@ func MustDecode(s string) (checksum Checksum) { // deterministically but might not currently be available in memory or on the // filesystem. type Artifact interface { + // Kind returns the [Kind] of artifact. This is usually unique to the + // concrete type but two functionally identical implementations of + // [Artifact] is allowed to return the same [Kind] value. + Kind() Kind + // ID returns a globally unique identifier referring to the current // [Artifact]. This value must be known ahead of time and guaranteed to be // unique without having obtained the full contents of the [Artifact]. @@ -71,6 +79,39 @@ type File interface { Artifact } +// Kind corresponds to the concrete type of [Artifact] and is used to create +// identifier for an [Artifact] with dependencies. +type Kind uint64 + +const ( + // KindHTTP is the kind of [Artifact] returned by [Cache.NewHTTP]. + KindHTTP Kind = iota + KindTar +) + +// Ident returns a deterministic identifier for the supplied params and +// dependencies. The caller is responsible for ensuring params uniquely and +// deterministically describes the current [Artifact]. +func (k Kind) Ident(params []byte, deps ...Artifact) ID { + type extIdent [len(ID{}) + wordSize]byte + identifiers := make([]extIdent, len(deps)) + for i, a := range deps { + id := a.ID() + copy(identifiers[i][wordSize:], id[:]) + binary.LittleEndian.PutUint64(identifiers[i][:], uint64(a.Kind())) + } + slices.SortFunc(identifiers, func(a, b extIdent) int { return bytes.Compare(a[:], b[:]) }) + slices.Compact(identifiers) + + h := sha512.New384() + h.Write(binary.LittleEndian.AppendUint64(nil, uint64(k))) + h.Write(params) + for _, e := range identifiers { + h.Write(e[:]) + } + return ID(h.Sum(nil)) +} + const ( // dirIdentifier is the directory name appended to Cache.base for storing // artifacts named after their [ID]. |
