72 lines
2.9 KiB
Go
72 lines
2.9 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
|
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg"
|
|
"git.novox.be/novox/mesh-sdk/go/keys"
|
|
)
|
|
|
|
// 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 := meshcatalogclient.ManifestDigest([]byte(raw))
|
|
if ix.Manifests == nil {
|
|
return digest, nil
|
|
}
|
|
key, err := meshcatalogclient.ManifestsKey(digest)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
data, err := meshcatalogclient.EncodeManifest(meshcatalog.ManifestsByDigestValue{Module: module, Manifest: 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 := meshcatalogclient.DecodeManifest(held); err == nil && cur == (meshcatalog.ManifestsByDigestValue{V: keys.Version, Module: module, Manifest: 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 forgemsg.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")
|