Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/manifests.go
T
jschoubben 9f7e082688 List a repository's modules from the merged message's manifests and the indexer's own bucket, not the controller's build records, so a new module gets a value and a key with no build asked (issue 1851, I1 I2 I4, ADR 0501 §6, ADR 0453 §6)
I1: a merge writes each module its manifests name, at its directory. I2: a pull request's changed directory, a
preview's touched module and a source revision's modules come from the modules bucket (a module a pull request adds is
found in the preview by its manifest). I4: the value of today's form (fp, none) is no longer written, since it was
computed from the build records; mesh-sdk keeps it readable until R4g. One commit: the three share applyMerged and its
tests. Pins mesh-sdk feat/r4e-sdk 9cb4d59.
2026-10-22 18:08:48 +02:00

69 lines
2.7 KiB
Go

package index
import (
"context"
"errors"
"fmt"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// keepManifest writes manifests.<digest> for a manifest as the forge answered it, create-once (issue 1449): a key that
// exists with the same value is left and is no error; one that holds another value is an error (it cannot happen for
// one digest, ManifestDigest being a hash of the bytes, so it says the bucket was written by hand). It answers the
// digest. A manifest that cannot be a value (empty, not UTF-8, not JSON) is an error the caller says; it is never tried
// again. With no manifests store nothing is written and the digest is still answered.
func (ix *Indexer) keepManifest(ctx context.Context, module, raw string) (string, error) {
digest := delivery.ManifestDigest([]byte(raw))
if ix.Manifests == nil {
return digest, nil
}
key, err := delivery.ManifestsKey(digest)
if err != nil {
return "", err
}
data, err := delivery.EncodeManifest(delivery.Manifest{Module: module, JSON: raw})
if err != nil {
return "", fmt.Errorf("%w: manifests.%s: %v", errCannotBeAValue, key, err)
}
err = ix.Manifests.Create(ctx, key, data)
if err == nil {
return digest, nil
}
if !errors.Is(err, ErrConflict) {
return "", fmt.Errorf("writing manifests.%s: %w", key, err)
}
held, _, found, err := ix.Manifests.Get(ctx, key)
if err != nil {
return "", fmt.Errorf("reading manifests.%s: %w", key, err)
}
if !found {
return "", fmt.Errorf("manifests.%s was there and is not: written again at the next delivery", key)
}
if cur, err := delivery.DecodeManifest(held); err == nil && delivery.SameManifest(cur, delivery.Manifest{V: delivery.Version, Module: module, JSON: raw}) {
return digest, nil
}
return "", fmt.Errorf("manifests.%s holds another value than the manifest of %s, which hashes to it", key, module)
}
// keepManifests writes the manifest of each directory a message carries, and answers the digest of each by directory.
// A manifest that cannot be kept is left out and said in the log, so the module reads as one with no manifest.
func (ix *Indexer) keepManifests(ctx context.Context, f delivery.Forge) (map[string]string, error) {
digests := make(map[string]string, len(f.Manifests))
for dir, raw := range f.Manifests {
module := manifestModule(raw) // the name the manifest gives itself: one digest always has one module
digest, err := ix.keepManifest(ctx, module, raw)
switch {
case err == nil:
digests[dir] = digest
case errors.Is(err, errCannotBeAValue):
ix.logf("%s#%d: the manifest of %q cannot be kept: %v", f.Repository, f.Number, dir, err)
default:
return nil, err
}
}
return digests, nil
}
var errCannotBeAValue = errors.New("not a manifest value")