aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/pkg.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pkg/pkg.go')
-rw-r--r--internal/pkg/pkg.go41
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].