J8: sdk/forms names an image and an upstream copy in the seat reference form, each deriving its artifact-store form
ADR 0624: container-image-registry/<module>/<artifact>@<digest> and the holder's container-image-registry/upstream/<host>/<path>@<digest> are form:seat-reference; Older derives artifact-store://... so a key keeps both. The registry form now precedes the artifact-store form, so a node stating nothing keeps the recorded store form of an image. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -1365,39 +1365,48 @@ func aDoneKeyKeepsEachFormACountedNodeReads(t *testing.T) {
|
||||
// The builder's own forms (forms.Current): a bundle a build step answers in the registry seat's form (mesh-build-go's
|
||||
// oci-artifact-registry/<module>/<artifact>@<digest>) keeps the artifact-store form it derives for each counted node
|
||||
// whose engine does not state form:seat-reference, that one in the single reference (ADR 0624 §1, §3).
|
||||
seatRef, storeRef := "oci-artifact-registry/m/code@"+digest, "artifact-store://m/code/blobs/"+digest
|
||||
seat := []string{forms.FormNeed(forms.FormSeatReference), "word:module"}
|
||||
for _, row := range []struct {
|
||||
name string
|
||||
present, counted map[string][]string
|
||||
reference string
|
||||
references []string
|
||||
needs []string
|
||||
}{
|
||||
{"seat form answered, B away stating nothing: the derived store form stays, in the single reference",
|
||||
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": nil}, storeRef, []string{storeRef, seatRef},
|
||||
[]string{"form:artifact-store", "form:seat-reference"}},
|
||||
{"seat form answered, every counted engine reads it: the seat form only",
|
||||
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": seat}, seatRef, nil, []string{"form:seat-reference"}},
|
||||
{"seat form answered, a present engine stating nothing: the store form only",
|
||||
map[string][]string{"a": seat, "b": nil}, map[string][]string{"a": seat, "b": nil}, storeRef, nil, []string{"form:artifact-store"}},
|
||||
{"seat form answered, no node present: the store form", nil, map[string][]string{"a": seat}, storeRef, nil, []string{"form:artifact-store"}},
|
||||
// Each kind the seat form names (a bundle through oci-artifact-registry, an image and an upstream copy through
|
||||
// container-image-registry, the copy under the holder's own upstream/<host>/<path>), with the artifact-store form it derives.
|
||||
for _, k := range []struct{ kind, seatRef, storeRef string }{
|
||||
{"bundle", "oci-artifact-registry/m/code@" + digest, "artifact-store://m/code/blobs/" + digest},
|
||||
{"image", "container-image-registry/m/code@" + digest, "artifact-store://m/code@" + digest},
|
||||
{"upstream", "container-image-registry/upstream/quay.io:443/org/app@" + digest, "artifact-store://upstream/quay.io:443/org/app@" + digest},
|
||||
} {
|
||||
a := forms.Current.Choose(delivery.BuiltArtifact{Name: "code", Kind: "bundle", Digest: digest}, []string{seatRef}, row.present, row.counted)
|
||||
if a.Reference != row.reference || !slices.Equal(a.References, row.references) {
|
||||
t.Errorf("%s: %q %v, want %q %v", row.name, a.Reference, a.References, row.reference, row.references)
|
||||
}
|
||||
needs := forms.Current.Needs([]delivery.BuiltArtifact{a})
|
||||
if !slices.Equal(needs, row.needs) {
|
||||
t.Errorf("%s: needs %v, want %v", row.name, needs, row.needs)
|
||||
}
|
||||
for node, stated := range row.counted {
|
||||
if forms.Current.Held(needs, stated) {
|
||||
t.Errorf("%s: the want of %s is held", row.name, node)
|
||||
seatRef, storeRef := k.seatRef, k.storeRef
|
||||
for _, row := range []struct {
|
||||
name string
|
||||
present, counted map[string][]string
|
||||
reference string
|
||||
references []string
|
||||
needs []string
|
||||
}{
|
||||
{"seat form answered, B away stating nothing: the derived store form stays, in the single reference",
|
||||
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": nil}, storeRef, []string{storeRef, seatRef},
|
||||
[]string{"form:artifact-store", "form:seat-reference"}},
|
||||
{"seat form answered, every counted engine reads it: the seat form only",
|
||||
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": seat}, seatRef, nil, []string{"form:seat-reference"}},
|
||||
{"seat form answered, a present engine stating nothing: the store form only",
|
||||
map[string][]string{"a": seat, "b": nil}, map[string][]string{"a": seat, "b": nil}, storeRef, nil, []string{"form:artifact-store"}},
|
||||
{"seat form answered, no node present: the store form", nil, map[string][]string{"a": seat}, storeRef, nil, []string{"form:artifact-store"}},
|
||||
} {
|
||||
a := forms.Current.Choose(delivery.BuiltArtifact{Name: "code", Kind: k.kind, Digest: digest}, []string{seatRef}, row.present, row.counted)
|
||||
if a.Reference != row.reference || !slices.Equal(a.References, row.references) {
|
||||
t.Errorf("%s %s: %q %v, want %q %v", k.kind, row.name, a.Reference, a.References, row.reference, row.references)
|
||||
}
|
||||
needs := forms.Current.Needs([]delivery.BuiltArtifact{a})
|
||||
if !slices.Equal(needs, row.needs) {
|
||||
t.Errorf("%s %s: needs %v, want %v", k.kind, row.name, needs, row.needs)
|
||||
}
|
||||
for node, stated := range row.counted {
|
||||
if forms.Current.Held(needs, stated) {
|
||||
t.Errorf("%s %s: the want of %s is held", k.kind, row.name, node)
|
||||
}
|
||||
}
|
||||
// mesh-sdk's referenceProblem does not yet know the holder's upstream/<host>/<path> naming (a request to the SDK's owner).
|
||||
if _, err := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.TrimPrefix(digest, "sha256:"), Artifacts: []delivery.BuiltArtifact{a}, Needs: needs}); err != nil && k.kind != "upstream" {
|
||||
t.Errorf("%s %s: %v", k.kind, row.name, err)
|
||||
}
|
||||
}
|
||||
if _, err := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.TrimPrefix(digest, "sha256:"), Artifacts: []delivery.BuiltArtifact{a}, Needs: needs}); err != nil {
|
||||
t.Errorf("%s: %v", row.name, err)
|
||||
}
|
||||
}
|
||||
// What the assigner holds a want by (ADR 0624 §2), from the same forms.
|
||||
|
||||
+39
-12
@@ -32,12 +32,31 @@ const (
|
||||
FormPackageVersion = "package-version"
|
||||
)
|
||||
|
||||
// FormSeatReference is the form a registry seat answers for a bundle or an archive it published,
|
||||
// oci-artifact-registry/<module>/<artifact>@sha256:<digest> (novox/hq ADR 0605 §9; catalogue.SeatReference, read back by
|
||||
// catalogue.InRegistrySeat), read by a node-engine that states form:seat-reference (catalogue.ReferenceFormSeat). Not a
|
||||
// first form: an engine stating nothing reads its blob only in the older artifact-store form, which it derives (Older).
|
||||
// FormSeatReference is the form a registry seat answers for what it published,
|
||||
// <seat>/<module>/<artifact>@sha256:<digest> (novox/hq ADR 0605 §9; catalogue.SeatReference, read back by
|
||||
// catalogue.InRegistrySeat): a bundle or an archive through oci-artifact-registry, an image through
|
||||
// container-image-registry, and an upstream copy through container-image-registry under the holder's own naming,
|
||||
// container-image-registry/upstream/<host>/<path>@sha256:<digest>. It is read by a node-engine that states
|
||||
// form:seat-reference (catalogue.ReferenceFormSeat). Not a first form: an engine stating nothing reads the artifact in the
|
||||
// older artifact-store form, which it derives (Older).
|
||||
const FormSeatReference = catalogue.ReferenceFormSeat
|
||||
|
||||
// upstreamPrefix opens an upstream copy's name in the image seat's answer: the holder's naming, upstream/<host>/<path>.
|
||||
const upstreamPrefix = "upstream/"
|
||||
|
||||
// inSeatReference reads a reference in the seat form: the seat it came through and the name and digest after it,
|
||||
// <module>/<artifact>@<digest> (or upstream/<host>/<path>@<digest> for an upstream copy of the image seat).
|
||||
func inSeatReference(r string) (seat, path string, ok bool) {
|
||||
if seat, path, ok = catalogue.InRegistrySeat(r); ok {
|
||||
return seat, path, true
|
||||
}
|
||||
rest, found := strings.CutPrefix(r, catalogue.ContainerImageRegistrySeat+"/"+upstreamPrefix)
|
||||
if !found || !strings.Contains(rest, "@sha256:") {
|
||||
return "", "", false
|
||||
}
|
||||
return catalogue.ContainerImageRegistrySeat, upstreamPrefix + rest, true
|
||||
}
|
||||
|
||||
// ArtifactForm is one reference form: its name, whether it is a first form, the artifact kinds it names, how a
|
||||
// reference is told to be in it, and, for a form that names the same artifact an older form does, that older reference
|
||||
// (Older, nil when it derives none): the old-form window writes it beside the answered one (ADR 0624 §1, §3).
|
||||
@@ -55,21 +74,29 @@ type ArtifactForms []ArtifactForm
|
||||
// Current are the forms the builder writes and the assigner knows: the three first forms (delivery.BuiltArtifact's
|
||||
// reference by kind), then the registry seat's form of a bundle or an archive.
|
||||
var Current = ArtifactForms{
|
||||
{Name: FormArtifactStore, First: true, Is: func(r string) bool { return strings.HasPrefix(r, artifactStore) },
|
||||
Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
|
||||
// The registry form precedes the artifact-store form: what a build key kept of an image is recorded without the
|
||||
// registry's address (catalogue.Recorded), so the artifact-store form is the newest first form an image has, the one
|
||||
// Kept keeps for a node that states nothing.
|
||||
{Name: FormRegistry, First: true, Is: func(r string) bool { return !strings.HasPrefix(r, artifactStore) && strings.Contains(r, "@sha256:") },
|
||||
Kinds: []string{catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
|
||||
{Name: FormArtifactStore, First: true, Is: func(r string) bool { return strings.HasPrefix(r, artifactStore) },
|
||||
Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
|
||||
{Name: FormPackageVersion, First: true, Is: func(r string) bool { return strings.LastIndex(r, "@") > 0 && !strings.Contains(r, "@sha256:") },
|
||||
Kinds: []string{catalogue.ArtifactPackage}},
|
||||
{Name: FormSeatReference, Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive},
|
||||
{Name: FormSeatReference, Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream},
|
||||
Is: func(r string) bool {
|
||||
seat, _, ok := catalogue.InRegistrySeat(r)
|
||||
return ok && seat == catalogue.OciArtifactRegistrySeat
|
||||
seat, _, ok := inSeatReference(r)
|
||||
return ok && (seat == catalogue.OciArtifactRegistrySeat || seat == catalogue.ContainerImageRegistrySeat)
|
||||
},
|
||||
// The same blob in the artifact store's form: oci-artifact-registry/<m>/<a>@<d> is artifact-store://<m>/<a>/blobs/<d>.
|
||||
// The same artifact in the artifact store's form: oci-artifact-registry/<m>/<a>@<d> is artifact-store://<m>/<a>/blobs/<d>;
|
||||
// container-image-registry/<m>/<a>@<d> (an upstream copy's upstream/<h>/<p>@<d> likewise) is artifact-store://<m>/<a>@<d>.
|
||||
Older: func(r string) string {
|
||||
path, _ := catalogue.InArtifactStore(r)
|
||||
return catalogue.ArtifactStoreScheme + path
|
||||
seat, rest, _ := inSeatReference(r)
|
||||
if seat == catalogue.OciArtifactRegistrySeat {
|
||||
path, _ := catalogue.InArtifactStore(r)
|
||||
return catalogue.ArtifactStoreScheme + path
|
||||
}
|
||||
return catalogue.ArtifactStoreScheme + rest
|
||||
}},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user