Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Rework of Reference Hints #1212

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/config/markdownlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ default: true

MD013: false #Line length - https://github.com/DavidAnson/markdownlint/blob/HEAD/doc/Rules.md#md013
MD033: false #Inline HTML - https://github.com/DavidAnson/markdownlint/blob/HEAD/doc/Rules.md#md033
MD001: false #Inline HTML - https://github.com/DavidAnson/markdownlint/blob/HEAD/doc/Rules.md#md001
MD004:
style: consistent
MD024:
siblings_only: true #Multiple headers with the same content
6 changes: 5 additions & 1 deletion .github/config/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ typename
unmarshaller
unmodifiable
untrusted
untyped
updatevendorhash
uploadable
uploader
uploaderdescriptor
uploaders
Expand All @@ -308,4 +310,6 @@ xml
yaml
yitsushi
yml
yyyy
yyyy
fabianburth
jakobmoellerdev
53 changes: 31 additions & 22 deletions api/helper/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"ocm.software/ocm/api/ocm"
"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/utils"
"ocm.software/ocm/api/utils/accessio"
"ocm.software/ocm/api/utils/blobaccess/blobaccess"
Expand Down Expand Up @@ -45,20 +46,28 @@ type static struct {
def_modopts ocm.ModificationOptions
}

// state descibes an actual set of targets
// for different kinds of information added
// by builder methods. If such a method is applicable
// for a given context depends on the set of
// available targets.
// Every method may provide a new (extended) context
// for embedded function calls by adding more targets.
type state struct {
*static
ocm_repo ocm.Repository
ocm_comp ocm.ComponentAccess
ocm_vers ocm.ComponentVersionAccess
ocm_rsc *compdesc.ResourceMeta
ocm_src *compdesc.SourceMeta
ocm_meta *compdesc.ElementMeta
ocm_labels *metav1.Labels
ocm_acc *compdesc.AccessSpec
ocm_modopts *ocm.ModificationOptions

blob *blobaccess.BlobAccess
hint *string
ocm_repo ocm.Repository
ocm_comp ocm.ComponentAccess
ocm_vers ocm.ComponentVersionAccess
ocm_rsc *compdesc.ResourceMeta
ocm_src *compdesc.SourceMeta
ocm_meta *compdesc.ElementMeta
ocm_metahints compdesc.ReferenceHintSink
ocm_labels *metav1.Labels
ocm_acc *compdesc.AccessSpec
ocm_modopts *ocm.ModificationOptions

blob *blobaccess.BlobAccess
blobhint *refhints.ReferenceHints

oci_repo oci.Repository
oci_nsacc oci.NamespaceAccess
Expand All @@ -70,6 +79,16 @@ type state struct {
oci_platform *artdesc.Platform
}

// Builder provides composition methods
// working on an actual context described by
// a state providing information about possible
// information targets. A method may depend on the
// availability of dedicated targets in the actual context.
// Every method may provide
// an own (extended) context for nested function calls.
// The previous contexts will be preserved in a stack,
// and restored when the method providing a new context
// is left.
type Builder struct {
*env.Environment
stack []element
Expand Down Expand Up @@ -198,13 +217,3 @@ func (b *Builder) Configure(funcs ...func()) {
}
}
}

////////////////////////////////////////////////////////////////////////////////

func (b *Builder) Hint(hint string) {
b.expect(b.hint, T_OCMACCESS)
if b.ocm_acc != nil && *b.ocm_acc != nil {
b.fail("access already set")
}
*(b.hint) = hint
}
2 changes: 1 addition & 1 deletion api/helper/builder/ocm_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func (b *Builder) Access(acc compdesc.AccessSpec) {
if b.blob != nil && *b.blob != nil {
b.fail("access already set")
}
if b.hint != nil && *b.hint != "" {
if *b.blobhint != nil {
b.fail("hint requires blob", 1)
}

Expand Down
35 changes: 35 additions & 0 deletions api/helper/builder/ocm_hint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package builder

import (
"ocm.software/ocm/api/ocm/refhints"
)

// AccessHint provides reference hints for
// an access (either an access method or blob data).
func (b *Builder) AccessHint(hint interface{}) {
b.expect(b.blobhint, T_OCMACCESS)
if b.ocm_acc != nil && *b.ocm_acc != nil {
b.fail("access already set")
}
hints, err := refhints.HintsFor(hint, true)
if err != nil {
b.fail(err.Error())
}
*b.blobhint = hints
}

////////////////////////////////////////////////////////////////////////////////

const T_OCMARTIFACT = "ocm artifact"

// ArtifactHint provides reference hints stored
// togetjer with the metadata of an artifact
// (source or resource).
func (b *Builder) ArtifactHint(hint interface{}) {
b.expect(b.ocm_metahints, T_OCMARTIFACT)
hints, err := refhints.HintsFor(hint)
if err != nil {
b.fail(err.Error())
}
b.ocm_metahints.SetReferenceHints(hints)
}
6 changes: 4 additions & 2 deletions api/helper/builder/ocm_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"ocm.software/ocm/api/ocm"
"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/utils/blobaccess/blobaccess"
)

Expand All @@ -17,7 +18,7 @@ type ocmResource struct {
access compdesc.AccessSpec
blob blobaccess.BlobAccess
opts ocm.ModificationOptions
hint string
hint refhints.ReferenceHints
}

const T_OCMRESOURCE = "resource"
Expand All @@ -30,10 +31,11 @@ func (r *ocmResource) Set() {
r.Builder.ocm_rsc = &r.meta
r.Builder.ocm_acc = &r.access
r.Builder.ocm_meta = &r.meta.ElementMeta
r.Builder.ocm_metahints = &r.meta
r.Builder.ocm_labels = &r.meta.ElementMeta.Labels
r.Builder.ocm_modopts = &r.opts
r.Builder.blob = &r.blob
r.Builder.hint = &r.hint
r.Builder.blobhint = &r.hint
}

func (r *ocmResource) Close() error {
Expand Down
6 changes: 5 additions & 1 deletion api/helper/builder/ocm_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/mandelsoft/goutils/errors"

"ocm.software/ocm/api/ocm/compdesc"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/utils/blobaccess/blobaccess"
)

Expand All @@ -13,6 +14,7 @@ type ocmSource struct {
meta compdesc.SourceMeta
access compdesc.AccessSpec
blob blobaccess.BlobAccess
hint refhints.ReferenceHints
}

const T_OCMSOURCE = "source"
Expand All @@ -25,16 +27,18 @@ func (r *ocmSource) Set() {
r.Builder.ocm_src = &r.meta
r.Builder.ocm_acc = &r.access
r.Builder.ocm_meta = &r.meta.ElementMeta
r.Builder.ocm_metahints = &r.meta
r.Builder.ocm_labels = &r.meta.ElementMeta.Labels
r.Builder.blob = &r.blob
r.Builder.blobhint = &r.hint
}

func (r *ocmSource) Close() error {
switch {
case r.access != nil:
return r.Builder.ocm_vers.SetSource(&r.meta, r.access)
case r.blob != nil:
return r.Builder.ocm_vers.SetSourceBlob(&r.meta, r.blob, "", nil)
return r.Builder.ocm_vers.SetSourceBlob(&r.meta, r.blob, r.hint, nil)
}
return errors.New("access or blob required")
}
Expand Down
57 changes: 29 additions & 28 deletions api/ocm/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
. "github.com/mandelsoft/goutils/testutils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"ocm.software/ocm/api/ocm/refhints"
. "ocm.software/ocm/api/ocm/testhelper"

"ocm.software/ocm/api/datacontext"
Expand Down Expand Up @@ -38,50 +39,50 @@ var _ = Describe("add resources", func() {
It("adds resource", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(Must(cv.SelectResources(selectors.Name("test")))[0].Meta().Digest).To(Equal(DS_TESTDATA))
})

It("replaces resource", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil))
Expect(Must(cv.SelectResources(selectors.Name("test")))[0].Meta().Digest).To(Equal(DS_OTHERDATA))
})

It("replaces resource (enforced)", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement))
Expect(Must(cv.SelectResources(selectors.Name("test")))[0].Meta().Digest).To(Equal(DS_OTHERDATA))

MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v2"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement))
Expect(Must(cv.SelectResources(selectors.Name("test")))[0].Meta().Digest).To(Equal(DS_OTHERDATA))
})

It("fails replace non-existent resource)", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

Expect(cv.SetResourceBlob(meta.WithVersion("v1").WithExtraIdentity("attr", "value"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement)).To(
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement)).To(
MatchError("unable to set resource: element \"attr\"=\"value\",\"name\"=\"test\" not found"))
})

It("adds duplicate resource with different version", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v2"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement))
Expect(len(Must(cv.SelectResources(selectors.Name("test"))))).To(Equal(2))
Expect(Must(cv.SelectResources(selectors.Name("test")))[0].Meta().Digest).To(Equal(DS_TESTDATA))
Expect(Must(cv.SelectResources(selectors.Name("test")))[1].Meta().Digest).To(Equal(DS_OTHERDATA))
Expand All @@ -90,18 +91,18 @@ var _ = Describe("add resources", func() {
It("rejects duplicate resource with same version", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation)
MustBeSuccessful(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(cv.SetResourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement)).
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement)).
To(MatchError("unable to set resource: adding a new resource with same base identity requires different version"))
})

It("rejects duplicate resource with extra identity", func() {
meta := ocm.NewResourceMeta("test", resourcetypes.PLAIN_TEXT, metav1.LocalRelation).WithExtraIdentity("attr", "value")
MustBeSuccessful(cv.SetResourceBlob(meta,
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(cv.SetResourceBlob(meta,
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement)).
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement)).
To(MatchError("unable to set resource: adding a new resource with same base identity requires different version"))
})
})
Expand All @@ -110,68 +111,68 @@ var _ = Describe("add resources", func() {
It("adds source", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(len(cv.GetDescriptor().Sources)).To(Equal(1))
})

It("replaces source", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil))
Expect(len(Must(cv.SelectSources(selectors.Name("test"))))).To(Equal(1))
})

It("replaces source (enforced)", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement))
Expect(len(Must(cv.SelectSources(selectors.Name("test"))))).To(Equal(1))

MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v2"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement))
Expect(len(Must(cv.SelectSources(selectors.Name("test"))))).To(Equal(1))
})

It("fails replace non-existent source)", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))

Expect(cv.SetSourceBlob(meta.WithVersion("v1").WithExtraIdentity("attr", "value"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.UpdateElement)).To(
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.UpdateElement)).To(
MatchError("unable to set source: element \"attr\"=\"value\",\"name\"=\"test\" not found"))
})

It("adds duplicate source with different version", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v2"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement))
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement))
Expect(len(Must(cv.SelectSources(selectors.Name("test"))))).To(Equal(2))
})

It("rejects duplicate source with same version", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT)
MustBeSuccessful(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(cv.SetSourceBlob(meta.WithVersion("v1"),
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement)).
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement)).
To(MatchError("unable to set source: adding a new source with same base identity requires different version"))
})

It("rejects duplicate source with extra identity", func() {
meta := ocm.NewSourceMeta("test", resourcetypes.PLAIN_TEXT).WithExtraIdentity("attr", "value")
MustBeSuccessful(cv.SetSourceBlob(meta,
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), "", nil))
blobaccess.ForString(mime.MIME_TEXT, S_TESTDATA), refhints.NONE, nil))
Expect(cv.SetSourceBlob(meta,
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), "", nil, ocm.AppendElement)).
blobaccess.ForString(mime.MIME_TEXT, S_OTHERDATA), refhints.NONE, nil, ocm.AppendElement)).
To(MatchError("unable to set source: adding a new source with same base identity requires different version"))
})
})
Expand Down
Loading
Loading