Files
mesh-catalog/modules/distribution/cmd/distribution-tools/contract.go
T
jschoubben b3261ccc03 G-catalog-B 6: on registry 2.8.3 a shared-digest tagged version's remove answers and says kept
Saying removed for a version the store still holds told the builder something false. remove now answers
kept with the reason shared-digest and the other tags naming its digest, removed false, and says the
seat's event kept with them (mesh-contracts' shared registry part); the builder raises no retry.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 18:15:24 +01:00

72 lines
3.0 KiB
Go

package main
// The seats' contracts (mesh-contracts, generated from the seat definitions; ADR 0620): every verb's input and answer,
// and every event's body, as the two seats distribution holds define them. The verbs common to both seats have one
// shape in every registry seat, so containerimageregistry's types serve oci-artifact-registry's too. The holder's own
// types stay inside; what crosses the bus is the contract's.
import (
"encoding/base64"
"fmt"
"time"
reg "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
"distribution/internal/holder"
)
func publishOf(in reg.PublishInput) holder.PublishRequest {
r := holder.PublishRequest{Transfer: in.Transfer, Name: in.Name, Version: in.Version, Tag: in.Tag, Kind: in.Kind,
Fingerprint: in.Fingerprint, Commit: in.Commit, Digest: in.Digest}
for _, p := range in.Parts {
r.Parts = append(r.Parts, holder.Part{Digest: p.Digest, Size: p.Size})
}
return r
}
func publishAnswer(a holder.PublishAnswer) reg.PublishAnswer {
return reg.PublishAnswer{Transfer: a.Transfer, Lacks: a.Missing, Held: a.Ended && len(a.Missing) == 0}
}
func partOf(in reg.PublishPartInput) (holder.PartRequest, error) {
data, err := base64.StdEncoding.DecodeString(in.Data)
if err != nil {
return holder.PartRequest{}, fmt.Errorf("publish-part: data is not base64: %w", err)
}
return holder.PartRequest{Transfer: in.Transfer, Digest: in.Part, Sequence: int(in.Sequence), Last: in.Last, Data: data}, nil
}
func partAnswer(in reg.PublishPartInput, a holder.PublishAnswer) reg.PublishPartAnswer {
return reg.PublishPartAnswer{Transfer: in.Transfer, Part: in.Part, Received: in.Sequence + 1, Complete: a.Ended}
}
// versionsAnswer is `versions`: each version with the digest the store holds under it.
func versionsAnswer(v *holder.Verbs, kind string, a holder.VersionsAnswer) reg.VersionsAnswer {
out := reg.VersionsAnswer{Name: a.Name, Versions: []reg.Artifact{}}
for _, ver := range a.Versions {
d, _ := v.Catalog.Digest(a.Name, ver)
out.Versions = append(out.Versions, reg.Artifact{Name: a.Name, Version: ver, Digest: d, Kind: kind})
}
return out
}
func tagsAnswer(v *holder.Verbs, a holder.VersionsAnswer) reg.TagsAnswer {
out := reg.TagsAnswer{Name: a.Name, Tags: []reg.TagsAnswerTagsItem{}}
for _, t := range a.Versions {
d, _ := v.Catalog.Digest(a.Name, t)
out.Tags = append(out.Tags, reg.TagsAnswerTagsItem{Tag: t, Digest: d})
}
return out
}
// eventBody is an event's body as the seat's contract defines it: an Outcome for published, refused, removed and kept, a
// Hold for held and released.
func eventBody(event string, e holder.Event) any {
switch event {
case holder.EventHeld, holder.EventReleased:
return reg.Hold{Name: e.Name, Digest: e.Digest, Holder: e.Holder, By: e.By, Reason: e.Reason, At: time.Now().UTC().Format(time.RFC3339)}
}
return reg.Outcome{Name: e.Name, Version: e.Version, Kind: e.Kind, Tag: e.Tag, Digest: e.Digest, Fingerprint: e.Fingerprint,
Commit: e.Commit, Holder: e.Holder, Transfer: e.Transfer, Reference: e.Reference, Reason: e.Reason, Tags: e.Tags}
}