Add the layout of the indexer's manifests bucket: the key by digest and its value (issue 1357)

This commit is contained in:
2026-10-20 01:43:17 +00:00
parent 605eca2c0a
commit 1bbf75ae19
+85
View File
@@ -0,0 +1,85 @@
package delivery
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"unicode/utf8"
)
// ManifestDigest is the hex sha256 of a manifest's bytes exactly as read at the commit: the key of a manifests value
// and the digest a Module and a candidate's module carry (novox/hq ADR 0429 clause 16).
func ManifestDigest(raw []byte) string {
sum := sha256.Sum256(raw)
return hex.EncodeToString(sum[:])
}
// ManifestsKey is the key, in ManifestsBucket, of a manifest: its digest, 64 lowercase hex digits. The indexer
// writes it once, by a create that fails when the key exists.
func ManifestsKey(digest string) (string, error) {
if !isHex64(digest) {
return "", fmt.Errorf("delivery: %q is not a manifest digest, 64 lowercase hex digits", digest)
}
return digest, nil
}
// ParseManifestsKey is the inverse of ManifestsKey.
func ParseManifestsKey(key string) (digest string, err error) {
if digest, err = ManifestsKey(key); err != nil {
return "", fmt.Errorf("delivery: %q is not a manifests key: %w", key, err)
}
return digest, nil
}
// Manifest is the value of a manifests key: the module and its manifest, the raw text of its module.json as read at the
// commit, byte for byte (ManifestDigest of JSON is the key). It is the one value of delivery that is larger than about
// 500 bytes: the largest manifest of the catalogue is about 21 KB. It is a string, not nested JSON, because nesting
// would re-write the manifest's spacing and so change its digest.
type Manifest struct {
V int `json:"v"`
Module string `json:"module"`
JSON string `json:"manifest"`
}
func (m Manifest) check() error {
if err := checkName("module", m.Module); err != nil {
return err
}
if m.JSON == "" {
return fmt.Errorf("delivery: the manifest of %s is empty", m.Module)
}
if !utf8.ValidString(m.JSON) {
return fmt.Errorf("delivery: the manifest of %s is not UTF-8 text, which a value cannot hold byte for byte", m.Module)
}
if !json.Valid([]byte(m.JSON)) {
return fmt.Errorf("delivery: the manifest of %s is not JSON", m.Module)
}
return nil
}
// EncodeManifest is m as JSON at Version; it refuses a module that is not a name, and a manifest that is empty, not
// UTF-8 or not JSON.
func EncodeManifest(m Manifest) ([]byte, error) {
if err := m.check(); err != nil {
return nil, err
}
m.V = Version
return json.Marshal(m)
}
// DecodeManifest reads a manifests value; it refuses an unknown version (ErrUnknownVersion) and what EncodeManifest
// refuses.
func DecodeManifest(data []byte) (Manifest, error) {
var m Manifest
if err := decode(data, &m); err != nil {
return Manifest{}, err
}
if err := m.check(); err != nil {
return Manifest{}, err
}
return m, nil
}
// SameManifest says whether two manifests are the same value, so a writer writes only when they differ.
func SameManifest(a, b Manifest) bool { return a == b }