Add the layout of the indexer's manifests bucket: the key by digest and its value (issue 1357)
This commit is contained in:
@@ -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 }
|
||||
Reference in New Issue
Block a user