The verbs answered the holder's own shapes (missing and ended, a part named digest, versions as bare strings, held as the publish's event) while the seat definitions, now generated into mesh-contracts, name lacks and held, part, versions of artifacts, tags with digests and a hold's own body. A build module using mesh-sdk's parts helper would have read no lacking part and sent nothing. The bundle now takes and answers the contract's types and says each event in its body; an image's manifest is the part whose digest is the publish's, as the contract names no media type, and a hold on the image seat is of a copied base. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
72 lines
3.0 KiB
Go
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 and removed, 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}
|
|
}
|