From e5a6985473cc21426f9ad132173fe909b9826787 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Wed, 31 Jul 2024 11:31:59 +0200 Subject: [PATCH] rework selectors (#858) #### What this PR does / why we need it: A new ocm sub package `selectors` now bundles an enhanced mechanism to select resources, sources and references for a component descriptor as well as for a component version. The old methods there are deprecated. Particular sub packaged (rscsel, srcsel, refsel) provide a type specific view for common and special selector functions and the appropriate logical operators And,Or and Not. --- cmds/ocm/commands/ocmcmds/pubsub/get/cmd.go | 2 +- cmds/ocm/commands/ocmcmds/pubsub/set/cmd.go | 2 +- docs/reference/ocm_get_pubsub.md | 2 +- go.mod | 2 +- pkg/contexts/ocm/compdesc/accessors.go | 84 +++++ .../ocm/compdesc/componentdescriptor.go | 113 ++----- pkg/contexts/ocm/compdesc/deprecated.go | 287 ++++++++++++++++ pkg/contexts/ocm/compdesc/helper.go | 307 +++++------------- pkg/contexts/ocm/compdesc/selector.go | 61 ++++ pkg/contexts/ocm/compdesc/selectors.go | 80 +++++ pkg/contexts/ocm/cpi/dummy.go | 30 ++ pkg/contexts/ocm/cpi/repocpi/view_cv.go | 75 ++++- pkg/contexts/ocm/internal/repository.go | 39 ++- .../ocm/pubsub/types/compound/type.go | 4 +- .../ocm/selectors/accessors/accessors.go | 56 ++++ pkg/contexts/ocm/selectors/artifacts.go | 54 +++ pkg/contexts/ocm/selectors/identity.go | 195 +++++++++++ pkg/contexts/ocm/selectors/label.go | 86 +++++ .../ocm/selectors/labelsel/interface.go | 178 ++++++++++ .../ocm/selectors/labelsel/label_test.go | 88 +++++ .../ocm/selectors/labelsel/operators.go | 56 ++++ .../ocm/selectors/labelsel/suite_test.go | 13 + pkg/contexts/ocm/selectors/refsel/element.go | 35 ++ .../ocm/selectors/refsel/interface.go | 59 ++++ .../ocm/selectors/refsel/operators.go | 72 ++++ pkg/contexts/ocm/selectors/rscsel/artifact.go | 15 + pkg/contexts/ocm/selectors/rscsel/element.go | 39 +++ .../ocm/selectors/rscsel/interface.go | 40 +++ .../ocm/selectors/rscsel/operators.go | 72 ++++ pkg/contexts/ocm/selectors/select.go | 170 ++++++++++ pkg/contexts/ocm/selectors/srcsel/artifact.go | 15 + pkg/contexts/ocm/selectors/srcsel/element.go | 39 +++ .../ocm/selectors/srcsel/interface.go | 10 + .../ocm/selectors/srcsel/operators.go | 72 ++++ 34 files changed, 2134 insertions(+), 318 deletions(-) create mode 100644 pkg/contexts/ocm/compdesc/accessors.go create mode 100644 pkg/contexts/ocm/compdesc/deprecated.go create mode 100644 pkg/contexts/ocm/compdesc/selector.go create mode 100644 pkg/contexts/ocm/selectors/accessors/accessors.go create mode 100644 pkg/contexts/ocm/selectors/artifacts.go create mode 100644 pkg/contexts/ocm/selectors/identity.go create mode 100644 pkg/contexts/ocm/selectors/label.go create mode 100644 pkg/contexts/ocm/selectors/labelsel/interface.go create mode 100644 pkg/contexts/ocm/selectors/labelsel/label_test.go create mode 100644 pkg/contexts/ocm/selectors/labelsel/operators.go create mode 100644 pkg/contexts/ocm/selectors/labelsel/suite_test.go create mode 100644 pkg/contexts/ocm/selectors/refsel/element.go create mode 100644 pkg/contexts/ocm/selectors/refsel/interface.go create mode 100644 pkg/contexts/ocm/selectors/refsel/operators.go create mode 100644 pkg/contexts/ocm/selectors/rscsel/artifact.go create mode 100644 pkg/contexts/ocm/selectors/rscsel/element.go create mode 100644 pkg/contexts/ocm/selectors/rscsel/interface.go create mode 100644 pkg/contexts/ocm/selectors/rscsel/operators.go create mode 100644 pkg/contexts/ocm/selectors/select.go create mode 100644 pkg/contexts/ocm/selectors/srcsel/artifact.go create mode 100644 pkg/contexts/ocm/selectors/srcsel/element.go create mode 100644 pkg/contexts/ocm/selectors/srcsel/interface.go create mode 100644 pkg/contexts/ocm/selectors/srcsel/operators.go diff --git a/cmds/ocm/commands/ocmcmds/pubsub/get/cmd.go b/cmds/ocm/commands/ocmcmds/pubsub/get/cmd.go index 4f6d2e17b..c314bb608 100644 --- a/cmds/ocm/commands/ocmcmds/pubsub/get/cmd.go +++ b/cmds/ocm/commands/ocmcmds/pubsub/get/cmd.go @@ -41,7 +41,7 @@ func (o *Command) ForName(name string) *cobra.Command { Short: "Get the pubsub spec for an ocm repository", Long: ` A repository may be able to store a publish/subscribe specification -to propagate the creation or update of component version. +to propagate the creation or update of component versions. If such an implementation is available and a specification is assigned to the repository, it is shown. The specification can be set with the ocm set pubsub. diff --git a/cmds/ocm/commands/ocmcmds/pubsub/set/cmd.go b/cmds/ocm/commands/ocmcmds/pubsub/set/cmd.go index fbc815a15..ae958e84a 100644 --- a/cmds/ocm/commands/ocmcmds/pubsub/set/cmd.go +++ b/cmds/ocm/commands/ocmcmds/pubsub/set/cmd.go @@ -44,7 +44,7 @@ func (o *Command) ForName(name string) *cobra.Command { Short: "Set the pubsub spec for an ocm repository", Long: ` A repository may be able to store a publish/subscribe specification -to propagate the creation or update of component version. +to propagate the creation or update of component versions. If such an implementation is available this command can be used to set the pub/sub specification for a repository. If no specification is given an existing specification diff --git a/docs/reference/ocm_get_pubsub.md b/docs/reference/ocm_get_pubsub.md index 8df9aee94..153e4ca31 100644 --- a/docs/reference/ocm_get_pubsub.md +++ b/docs/reference/ocm_get_pubsub.md @@ -24,7 +24,7 @@ pubsub, ps A repository may be able to store a publish/subscribe specification -to propagate the creation or update of component version. +to propagate the creation or update of component versions. If such an implementation is available and a specification is assigned to the repository, it is shown. The specification can be set with the [ocm set pubsub](ocm_set_pubsub.md). diff --git a/go.mod b/go.mod index 77a6eed5a..4221763d6 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 github.com/go-test/deep v1.1.0 + github.com/gobwas/glob v0.2.3 github.com/golang/mock v1.6.0 github.com/google/go-github/v45 v45.2.0 github.com/hashicorp/vault-client-go v0.4.3 @@ -193,7 +194,6 @@ require ( github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/goccy/go-yaml v1.11.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect diff --git a/pkg/contexts/ocm/compdesc/accessors.go b/pkg/contexts/ocm/compdesc/accessors.go new file mode 100644 index 000000000..51215f722 --- /dev/null +++ b/pkg/contexts/ocm/compdesc/accessors.go @@ -0,0 +1,84 @@ +package compdesc + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/equivalent" + metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +// NameAccessor describes a accessor for a named object. +type NameAccessor interface { + // GetName returns the name of the object. + GetName() string + // SetName sets the name of the object. + SetName(name string) +} + +// VersionAccessor describes a accessor for a versioned object. +type VersionAccessor interface { + // GetVersion returns the version of the object. + GetVersion() string + // SetVersion sets the version of the object. + SetVersion(version string) +} + +// LabelsAccessor describes a accessor for a labeled object. +type LabelsAccessor interface { + // GetLabels returns the labels of the object. + GetLabels() metav1.Labels + // SetLabels sets the labels of the object. + SetLabels(labels []metav1.Label) +} + +// ObjectMetaAccessor describes a accessor for named and versioned object. +type ObjectMetaAccessor interface { + NameAccessor + VersionAccessor + LabelsAccessor +} + +// ElementMetaAccessor provides generic access an elements meta information. +type ElementMetaAccessor interface { + ElementMetaProvider + Equivalent(ElementMetaAccessor) equivalent.EqualState +} + +// ElementAccessor provides generic access to list of elements. +type ElementAccessor interface { + Len() int + Get(i int) ElementMetaAccessor +} + +type ElementMetaProvider interface { + GetMeta() *ElementMeta +} + +// ElementArtifactAccessor provides access to generic artifact information of an element. +type ElementArtifactAccessor interface { + ElementMetaAccessor + GetType() string + GetAccess() AccessSpec + SetAccess(a AccessSpec) +} + +type ElementDigestAccessor interface { + GetDigest() *metav1.DigestSpec + SetDigest(*metav1.DigestSpec) +} + +// ArtifactAccessor provides generic access to list of artifacts. +// There are resources or sources. +type ArtifactAccessor interface { + ElementAccessor + GetArtifact(i int) ElementArtifactAccessor +} + +// AccessSpec is an abstract specification of an access method +// The outbound object is typicall a runtime.UnstructuredTypedObject. +// Inbound any serializable AccessSpec implementation is possible. +type AccessSpec = accessors.AccessSpec + +// AccessProvider provides access to an access specification of elements. +type AccessProvider interface { + GetAccess() AccessSpec +} diff --git a/pkg/contexts/ocm/compdesc/componentdescriptor.go b/pkg/contexts/ocm/compdesc/componentdescriptor.go index 56da53aac..e4b1d592f 100644 --- a/pkg/contexts/ocm/compdesc/componentdescriptor.go +++ b/pkg/contexts/ocm/compdesc/componentdescriptor.go @@ -9,6 +9,7 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/equivalent" metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" "github.com/open-component-model/ocm/pkg/runtime" "github.com/open-component-model/ocm/pkg/semverutils" ) @@ -112,8 +113,8 @@ type ComponentSpec struct { } const ( - SystemIdentityName = "name" - SystemIdentityVersion = "version" + SystemIdentityName = metav1.SystemIdentityName + SystemIdentityVersion = metav1.SystemIdentityVersion ) type ElementMetaAccess interface { @@ -247,6 +248,31 @@ func (o *ElementMeta) GetIdentity(accessor ElementAccessor) metav1.Identity { return identity } +// GetIdentityForContext returns the identity of the object. +func (o *ElementMeta) GetIdentityForContext(accessor accessors.ElementListAccessor) metav1.Identity { + identity := o.ExtraIdentity.Copy() + if identity == nil { + identity = metav1.Identity{} + } + identity[SystemIdentityName] = o.Name + if accessor != nil { + found := false + l := accessor.Len() + for i := 0; i < l; i++ { + m := accessor.Get(i).GetMeta() + if m.GetName() == o.GetName() && m.GetExtraIdentity().Equals(o.ExtraIdentity) { + if found { + identity[SystemIdentityVersion] = o.Version + + break + } + found = true + } + } + } + return identity +} + // GetRawIdentity returns the identity plus version. func (o *ElementMeta) GetRawIdentity() metav1.Identity { identity := o.ExtraIdentity.Copy() @@ -304,43 +330,6 @@ func (o *ElementMeta) Equivalent(a *ElementMeta) equivalent.EqualState { return state.Apply(o.Labels.Equivalent(a.Labels)) } -// NameAccessor describes a accessor for a named object. -type NameAccessor interface { - // GetName returns the name of the object. - GetName() string - // SetName sets the name of the object. - SetName(name string) -} - -// VersionAccessor describes a accessor for a versioned object. -type VersionAccessor interface { - // GetVersion returns the version of the object. - GetVersion() string - // SetVersion sets the version of the object. - SetVersion(version string) -} - -// LabelsAccessor describes a accessor for a labeled object. -type LabelsAccessor interface { - // GetLabels returns the labels of the object. - GetLabels() metav1.Labels - // SetLabels sets the labels of the object. - SetLabels(labels []metav1.Label) -} - -// ObjectMetaAccessor describes a accessor for named and versioned object. -type ObjectMetaAccessor interface { - NameAccessor - VersionAccessor - LabelsAccessor -} - -// ElementMetaAccessor provides generic access an elements meta information. -type ElementMetaAccessor interface { - ElementMetaProvider - Equivalent(ElementMetaAccessor) equivalent.EqualState -} - func GetByIdentity(a ElementAccessor, id metav1.Identity) ElementMetaAccessor { l := a.Len() for i := 0; i < l; i++ { @@ -363,47 +352,10 @@ func GetIndexByIdentity(a ElementAccessor, id metav1.Identity) int { return -1 } -// ElementAccessor provides generic access to list of elements. -type ElementAccessor interface { - Len() int - Get(i int) ElementMetaAccessor -} - -type ElementMetaProvider interface { - GetMeta() *ElementMeta -} - -// ElementArtifactAccessor provides access to generic artifact information of an element. -type ElementArtifactAccessor interface { - ElementMetaAccessor - GetType() string - GetAccess() AccessSpec - SetAccess(a AccessSpec) -} - -type ElementDigestAccessor interface { - GetDigest() *metav1.DigestSpec - SetDigest(*metav1.DigestSpec) -} - -// ArtifactAccessor provides generic access to list of artifacts. -// There are resources or sources. -type ArtifactAccessor interface { - ElementAccessor - GetArtifact(i int) ElementArtifactAccessor -} - // ArtifactAccess provides access to a dedicated kind of artifact set // in the component descriptor (resources or sources). type ArtifactAccess func(cd *ComponentDescriptor) ArtifactAccessor -// AccessSpec is an abstract specification of an access method -// The outbound object is typicall a runtime.UnstructuredTypedObject. -// Inbound any serializable AccessSpec implementation is possible. -type AccessSpec interface { - runtime.VersionedTypedObject -} - // GenericAccessSpec returns a generic AccessSpec implementation for an unstructured object. // It can always be used instead of a dedicated access spec implementation. The core // methods will map these spec into effective ones before an access is returned to the caller. @@ -413,11 +365,6 @@ func GenericAccessSpec(un *runtime.UnstructuredTypedObject) AccessSpec { } } -// AccessProvider provides access to an access specification of elements. -type AccessProvider interface { - GetAccess() AccessSpec -} - // Sources describes a set of source specifications. type Sources []Source @@ -652,6 +599,10 @@ func (r *Resource) SetDigest(d *metav1.DigestSpec) { r.Digest = d } +func (r *Resource) GetRelation() metav1.ResourceRelation { + return r.Relation +} + func (r *Resource) Equivalent(e ElementMetaAccessor) equivalent.EqualState { if o, ok := e.(*Resource); !ok { state := equivalent.StateNotLocalHashEqual() diff --git a/pkg/contexts/ocm/compdesc/deprecated.go b/pkg/contexts/ocm/compdesc/deprecated.go new file mode 100644 index 000000000..669150bb9 --- /dev/null +++ b/pkg/contexts/ocm/compdesc/deprecated.go @@ -0,0 +1,287 @@ +package compdesc + +import ( + "bytes" + "fmt" + + "github.com/mandelsoft/goutils/sliceutils" + + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/utils/selector" +) + +// GetResourceAccessByIdentity returns a pointer to the resource that matches the given identity. +// +// Deprecated: use GetResourceByIdentity. +func (cd *ComponentDescriptor) GetResourceAccessByIdentity(id v1.Identity) *Resource { + dig := id.Digest() + for i, res := range cd.Resources { + if bytes.Equal(res.GetIdentityDigest(cd.Resources), dig) { + return &cd.Resources[i] + } + } + return nil +} + +// GetResourceByRegexSelector returns resources that match the given selectors. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourceByRegexSelector(sel interface{}) (Resources, error) { + identitySelector, err := selector.ParseRegexSelector(sel) + if err != nil { + return nil, fmt.Errorf("unable to parse selector: %w", err) + } + return cd.GetResourcesByIdentitySelectors(identitySelector) +} + +// GetResourcesByIdentitySelectors returns resources that match the given identity selectors. +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourcesByIdentitySelectors(selectors ...IdentitySelector) (Resources, error) { + return cd.GetResourcesBySelectors(selectors, nil) +} + +// GetResourcesByResourceSelectors returns resources that match the given resource selectors. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourcesByResourceSelectors(selectors ...ResourceSelector) (Resources, error) { + return cd.GetResourcesBySelectors(nil, selectors) +} + +// GetResourcesBySelectors returns resources that match the given selector. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourcesBySelectors(selectors []IdentitySelector, resourceSelectors []ResourceSelector) (Resources, error) { + resources := make(Resources, 0) + for i := range cd.Resources { + selctx := NewResourceSelectionContext(i, cd.Resources) + if len(selectors) > 0 { + ok, err := selector.MatchSelectors(selctx.Identity(), selectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) + } + if !ok { + continue + } + } + ok, err := MatchResourceByResourceSelector(selctx, resourceSelectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) + } + if !ok { + continue + } + resources = append(resources, *selctx.Resource) + } + if len(resources) == 0 { + return resources, NotFound + } + return resources, nil +} + +// GetExternalResources returns external resource with the given type, name and version. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetExternalResources(rtype, name, version string) (Resources, error) { + return cd.GetResourcesBySelectors( + []selector.Interface{ + ByName(name), + ByVersion(version), + }, + []ResourceSelector{ + ByResourceType(rtype), + ByRelation(v1.ExternalRelation), + }) +} + +// GetExternalResource returns external resource with the given type, name and version. +// +// If multiple resources match, the first one is returned. +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetExternalResource(rtype, name, version string) (Resource, error) { + resources, err := cd.GetExternalResources(rtype, name, version) + if err != nil { + return Resource{}, err + } + // at least one resource must be defined, otherwise the getResourceBySelectors functions returns a NotFound err. + return resources[0], nil +} + +// GetLocalResources returns all local resources with the given type, name and version. +func (cd *ComponentDescriptor) GetLocalResources(rtype, name, version string) (Resources, error) { + return cd.GetResourcesBySelectors( + []selector.Interface{ + ByName(name), + ByVersion(version), + }, + []ResourceSelector{ + ByResourceType(rtype), + ByRelation(v1.LocalRelation), + }) +} + +// GetLocalResource returns a local resource with the given type, name and version. +// +// If multiple resources match, the first one is returned. +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetLocalResource(rtype, name, version string) (Resource, error) { + resources, err := cd.GetLocalResources(rtype, name, version) + if err != nil { + return Resource{}, err + } + // at least one resource must be defined, otherwise the getResourceBySelectors functions returns a NotFound err. + return resources[0], nil +} + +// GetResourcesByType returns all resources that match the given type and selectors. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourcesByType(rtype string, selectors ...IdentitySelector) (Resources, error) { + return cd.GetResourcesBySelectors( + selectors, + []ResourceSelector{ + ByResourceType(rtype), + }) +} + +// GetResourcesByName returns all local and external resources with a name. +// +// Deprecated: use GetResources with appropriate selectors. +func (cd *ComponentDescriptor) GetResourcesByName(name string, selectors ...IdentitySelector) (Resources, error) { + return cd.GetResourcesBySelectors( + sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name)), + nil) +} + +//////////////////////////////////////////////////////////////////////////////// + +// GetSourceAccessByIdentity returns a pointer to the source that matches the given identity. +// +// Deprecated: use GetSourceByIdentity. +func (cd *ComponentDescriptor) GetSourceAccessByIdentity(id v1.Identity) *Source { + dig := id.Digest() + for i, res := range cd.Sources { + if bytes.Equal(res.GetIdentityDigest(cd.Sources), dig) { + return &cd.Sources[i] + } + } + return nil +} + +// GetSourcesByIdentitySelectors returns references that match the given selector. +// +// Deprecated: use GetSources with appropriate selectors. +func (cd *ComponentDescriptor) GetSourcesByIdentitySelectors(selectors ...IdentitySelector) (Sources, error) { + srcs := make(Sources, 0) + for _, src := range cd.Sources { + ok, err := selector.MatchSelectors(src.GetIdentity(cd.Sources), selectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for source %s: %w", src.Name, err) + } + if ok { + srcs = append(srcs, src) + } + } + if len(srcs) == 0 { + return srcs, NotFound + } + return srcs, nil +} + +// GetSourcesByName returns all sources with a name. +// +// Deprecated: use GetSources with appropriate selectors. +func (cd *ComponentDescriptor) GetSourcesByName(name string, selectors ...IdentitySelector) (Sources, error) { + return cd.GetSourcesByIdentitySelectors( + sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name))...) +} + +//////////////////////////////////////////////////////////////////////////////// + +// GetComponentReferences returns all component references that matches the given selectors. +// +// Deprectated: use GetReferences with appropriate selectors. +func (cd *ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelector) ([]ComponentReference, error) { + refs := make([]ComponentReference, 0) + for _, ref := range cd.References { + ok, err := selector.MatchSelectors(ref.GetIdentity(cd.References), selectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for resource %s: %w", ref.Name, err) + } + if ok { + refs = append(refs, ref) + } + } + if len(refs) == 0 { + return refs, NotFound + } + return refs, nil +} + +// GetComponentReferenceIndex returns the index of a given component reference. +// If the index is not found -1 is returned. +// Deprecated: use GetReferenceIndex. +func (cd *ComponentDescriptor) GetComponentReferenceIndex(ref ComponentReference) int { + return cd.GetReferenceIndex(ref.GetMeta()) +} + +// GetReferenceAccessByIdentity returns a pointer to the reference that matches the given identity. +// Deprectated: use GetReferenceByIdentity. +func (cd *ComponentDescriptor) GetReferenceAccessByIdentity(id v1.Identity) *ComponentReference { + dig := id.Digest() + for i, ref := range cd.References { + if bytes.Equal(ref.GetIdentityDigest(cd.Resources), dig) { + return &cd.References[i] + } + } + return nil +} + +// GetReferencesByIdentitySelectors returns resources that match the given identity selectors. +// Deprectated: use GetReferences with appropriate selectors. +func (cd *ComponentDescriptor) GetReferencesByIdentitySelectors(selectors ...IdentitySelector) (References, error) { + return cd.GetReferencesBySelectors(selectors, nil) +} + +// GetReferencesByReferenceSelectors returns resources that match the given resource selectors. +// Deprectated: use GetReferences with appropriate selectors. +func (cd *ComponentDescriptor) GetReferencesByReferenceSelectors(selectors ...ReferenceSelector) (References, error) { + return cd.GetReferencesBySelectors(nil, selectors) +} + +// GetReferencesBySelectors returns resources that match the given selector. +// Deprectated: use GetReferences with appropriate selectors. +func (cd *ComponentDescriptor) GetReferencesBySelectors(selectors []IdentitySelector, referenceSelectors []ReferenceSelector) (References, error) { + references := make(References, 0) + for i := range cd.References { + selctx := NewReferenceSelectionContext(i, cd.References) + if len(selectors) > 0 { + ok, err := selector.MatchSelectors(selctx.Identity(), selectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) + } + if !ok { + continue + } + } + ok, err := MatchReferencesByReferenceSelector(selctx, referenceSelectors...) + if err != nil { + return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) + } + if !ok { + continue + } + references = append(references, *selctx.ComponentReference) + } + if len(references) == 0 { + return references, NotFound + } + return references, nil +} + +// GetReferencesByName returns references that match the given name. +// Deprectated: use GetReferences with appropriate selectors. +func (cd *ComponentDescriptor) GetReferencesByName(name string, selectors ...IdentitySelector) (References, error) { + return cd.GetReferencesBySelectors( + sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name)), + nil) +} diff --git a/pkg/contexts/ocm/compdesc/helper.go b/pkg/contexts/ocm/compdesc/helper.go index 8d50b892a..f394b098f 100644 --- a/pkg/contexts/ocm/compdesc/helper.go +++ b/pkg/contexts/ocm/compdesc/helper.go @@ -5,9 +5,12 @@ import ( "fmt" "github.com/mandelsoft/goutils/errors" - "github.com/mandelsoft/goutils/sliceutils" v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/refsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/rscsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/srcsel" "github.com/open-component-model/ocm/pkg/runtime" "github.com/open-component-model/ocm/pkg/utils/selector" ) @@ -37,22 +40,34 @@ func (cd *ComponentDescriptor) AddRepositoryContext(repoCtx runtime.TypedObject) return nil } -// GetComponentReferences returns all component references that matches the given selectors. -func (cd *ComponentDescriptor) GetComponentReferences(selectors ...IdentitySelector) ([]ComponentReference, error) { - refs := make([]ComponentReference, 0) - for _, ref := range cd.References { - ok, err := selector.MatchSelectors(ref.GetIdentity(cd.References), selectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for resource %s: %w", ref.Name, err) - } - if ok { - refs = append(refs, ref) +func (cd *ComponentDescriptor) SelectResources(sel ...rscsel.Selector) ([]Resource, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } + + list := MapToSelectorElementList(cd.Resources) + result := []Resource{} + for _, r := range cd.Resources { + if len(sel) > 0 { + mr := MapToSelectorResource(&r) + for _, s := range sel { + if !s.MatchResource(list, mr) { + continue + } + } } + result = append(result, r) } - if len(refs) == 0 { - return refs, NotFound + return result, nil +} + +func (cd *ComponentDescriptor) GetResources() []Resource { + result := []Resource{} + for _, r := range cd.Resources { + result = append(result, r) } - return refs, nil + return result } // GetResourceByIdentity returns resource that matches the given identity. @@ -66,17 +81,6 @@ func (cd *ComponentDescriptor) GetResourceByIdentity(id v1.Identity) (Resource, return Resource{}, NotFound } -// GetResourceAccessByIdentity returns a pointer to the resource that matches the given identity. -func (cd *ComponentDescriptor) GetResourceAccessByIdentity(id v1.Identity) *Resource { - dig := id.Digest() - for i, res := range cd.Resources { - if bytes.Equal(res.GetIdentityDigest(cd.Resources), dig) { - return &cd.Resources[i] - } - } - return nil -} - // GetResourceIndexByIdentity returns the index of the resource that matches the given identity. func (cd *ComponentDescriptor) GetResourceIndexByIdentity(id v1.Identity) int { dig := id.Digest() @@ -106,129 +110,40 @@ func (cd *ComponentDescriptor) GetResourceByDefaultSelector(sel interface{}) (Re return cd.GetResourcesByIdentitySelectors(identitySelector) } -// GetResourceByRegexSelector returns resources that match the given selectors. -func (cd *ComponentDescriptor) GetResourceByRegexSelector(sel interface{}) (Resources, error) { - identitySelector, err := selector.ParseRegexSelector(sel) - if err != nil { - return nil, fmt.Errorf("unable to parse selector: %w", err) - } - return cd.GetResourcesByIdentitySelectors(identitySelector) -} - -// GetResourcesByIdentitySelectors returns resources that match the given identity selectors. -func (cd *ComponentDescriptor) GetResourcesByIdentitySelectors(selectors ...IdentitySelector) (Resources, error) { - return cd.GetResourcesBySelectors(selectors, nil) +// GetResourceIndex returns the index of a given resource. +// If the index is not found -1 is returned. +func (cd *ComponentDescriptor) GetResourceIndex(res *ResourceMeta) int { + return ElementIndex(cd.Resources, res) } -// GetResourcesByResourceSelectors returns resources that match the given resource selectors. -func (cd *ComponentDescriptor) GetResourcesByResourceSelectors(selectors ...ResourceSelector) (Resources, error) { - return cd.GetResourcesBySelectors(nil, selectors) -} +func (cd *ComponentDescriptor) SelectSources(sel ...srcsel.Selector) ([]Source, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } -// GetResourcesBySelectors returns resources that match the given selector. -func (cd *ComponentDescriptor) GetResourcesBySelectors(selectors []IdentitySelector, resourceSelectors []ResourceSelector) (Resources, error) { - resources := make(Resources, 0) - for i := range cd.Resources { - selctx := NewResourceSelectionContext(i, cd.Resources) - if len(selectors) > 0 { - ok, err := selector.MatchSelectors(selctx.Identity(), selectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) - } - if !ok { - continue + list := MapToSelectorElementList(cd.Sources) + result := []Source{} + for _, r := range cd.Sources { + if len(sel) > 0 { + mr := MapToSelectorSource(&r) + for _, s := range sel { + if !s.MatchSource(list, mr) { + continue + } } } - ok, err := MatchResourceByResourceSelector(selctx, resourceSelectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) - } - if !ok { - continue - } - resources = append(resources, *selctx.Resource) - } - if len(resources) == 0 { - return resources, NotFound + result = append(result, r) } - return resources, nil + return result, nil } -// GetExternalResources returns external resource with the given type, name and version. -func (cd *ComponentDescriptor) GetExternalResources(rtype, name, version string) (Resources, error) { - return cd.GetResourcesBySelectors( - []selector.Interface{ - ByName(name), - ByVersion(version), - }, - []ResourceSelector{ - ByResourceType(rtype), - ByRelation(v1.ExternalRelation), - }) -} - -// GetExternalResource returns external resource with the given type, name and version. -// If multiple resources match, the first one is returned. -func (cd *ComponentDescriptor) GetExternalResource(rtype, name, version string) (Resource, error) { - resources, err := cd.GetExternalResources(rtype, name, version) - if err != nil { - return Resource{}, err +func (cd *ComponentDescriptor) GetSources() []Source { + result := []Source{} + for _, r := range cd.Sources { + result = append(result, r) } - // at least one resource must be defined, otherwise the getResourceBySelectors functions returns a NotFound err. - return resources[0], nil -} - -// GetLocalResources returns all local resources with the given type, name and version. -func (cd *ComponentDescriptor) GetLocalResources(rtype, name, version string) (Resources, error) { - return cd.GetResourcesBySelectors( - []selector.Interface{ - ByName(name), - ByVersion(version), - }, - []ResourceSelector{ - ByResourceType(rtype), - ByRelation(v1.LocalRelation), - }) -} - -// GetLocalResource returns a local resource with the given type, name and version. -// If multiple resources match, the first one is returned. -func (cd *ComponentDescriptor) GetLocalResource(rtype, name, version string) (Resource, error) { - resources, err := cd.GetLocalResources(rtype, name, version) - if err != nil { - return Resource{}, err - } - // at least one resource must be defined, otherwise the getResourceBySelectors functions returns a NotFound err. - return resources[0], nil -} - -// GetResourcesByType returns all resources that match the given type and selectors. -func (cd *ComponentDescriptor) GetResourcesByType(rtype string, selectors ...IdentitySelector) (Resources, error) { - return cd.GetResourcesBySelectors( - selectors, - []ResourceSelector{ - ByResourceType(rtype), - }) -} - -// GetResourcesByName returns all local and external resources with a name. -func (cd *ComponentDescriptor) GetResourcesByName(name string, selectors ...IdentitySelector) (Resources, error) { - return cd.GetResourcesBySelectors( - sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name)), - nil) -} - -// GetResourceIndex returns the index of a given resource. -// If the index is not found -1 is returned. -func (cd *ComponentDescriptor) GetResourceIndex(res *ResourceMeta) int { - return ElementIndex(cd.Resources, res) -} - -// GetComponentReferenceIndex returns the index of a given component reference. -// If the index is not found -1 is returned. -// Deprecated: use GetReferenceIndex. -func (cd *ComponentDescriptor) GetComponentReferenceIndex(ref ComponentReference) int { - return cd.GetReferenceIndex(ref.GetMeta()) + return result } // GetSourceByIdentity returns source that match the given identity. @@ -242,17 +157,6 @@ func (cd *ComponentDescriptor) GetSourceByIdentity(id v1.Identity) (Source, erro return Source{}, NotFound } -// GetSourceByIdentity returns a pointer to the source that matches the given identity. -func (cd *ComponentDescriptor) GetSourceAccessByIdentity(id v1.Identity) *Source { - dig := id.Digest() - for i, res := range cd.Sources { - if bytes.Equal(res.GetIdentityDigest(cd.Sources), dig) { - return &cd.Sources[i] - } - } - return nil -} - // GetSourceIndexByIdentity returns the index of the source that matches the given identity. func (cd *ComponentDescriptor) GetSourceIndexByIdentity(id v1.Identity) int { dig := id.Digest() @@ -264,36 +168,12 @@ func (cd *ComponentDescriptor) GetSourceIndexByIdentity(id v1.Identity) int { return -1 } -// GetSourcesByIdentitySelectors returns references that match the given selector. -func (cd *ComponentDescriptor) GetSourcesByIdentitySelectors(selectors ...IdentitySelector) (Sources, error) { - srcs := make(Sources, 0) - for _, src := range cd.Sources { - ok, err := selector.MatchSelectors(src.GetIdentity(cd.Sources), selectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for source %s: %w", src.Name, err) - } - if ok { - srcs = append(srcs, src) - } - } - if len(srcs) == 0 { - return srcs, NotFound - } - return srcs, nil -} - // GetSourceIndex returns the index of a given source. // If the index is not found -1 is returned. func (cd *ComponentDescriptor) GetSourceIndex(src *SourceMeta) int { return ElementIndex(cd.Sources, src) } -// GetSourcesByName returns all sources with a name. -func (cd *ComponentDescriptor) GetSourcesByName(name string, selectors ...IdentitySelector) (Sources, error) { - return cd.GetSourcesByIdentitySelectors( - sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name))...) -} - // GetReferenceByIdentity returns reference that matches the given identity. func (cd *ComponentDescriptor) GetReferenceByIdentity(id v1.Identity) (ComponentReference, error) { dig := id.Digest() @@ -305,15 +185,34 @@ func (cd *ComponentDescriptor) GetReferenceByIdentity(id v1.Identity) (Component return ComponentReference{}, errors.ErrNotFound(KIND_REFERENCE, id.String()) } -// GetReferenceAccessByIdentity returns a pointer to the reference that matches the given identity. -func (cd *ComponentDescriptor) GetReferenceAccessByIdentity(id v1.Identity) *ComponentReference { - dig := id.Digest() - for i, ref := range cd.References { - if bytes.Equal(ref.GetIdentityDigest(cd.Resources), dig) { - return &cd.References[i] +func (cd *ComponentDescriptor) SelectReferences(sel ...refsel.Selector) ([]ComponentReference, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } + + list := MapToSelectorElementList(cd.References) + result := []ComponentReference{} + for _, r := range cd.References { + if len(sel) > 0 { + mr := MapToSelectorReference(&r) + for _, s := range sel { + if !s.MatchReference(list, mr) { + continue + } + } } + result = append(result, r) } - return nil + return result, nil +} + +func (cd *ComponentDescriptor) GetReferences() []ComponentReference { + result := []ComponentReference{} + for _, r := range cd.References { + result = append(result, r) + } + return result } // GetReferenceIndexByIdentity returns the index of the reference that matches the given identity. @@ -327,52 +226,6 @@ func (cd *ComponentDescriptor) GetReferenceIndexByIdentity(id v1.Identity) int { return -1 } -// GetReferencesByName returns references that match the given name. -func (cd *ComponentDescriptor) GetReferencesByName(name string, selectors ...IdentitySelector) (References, error) { - return cd.GetReferencesBySelectors( - sliceutils.CopyAppend[IdentitySelector](selectors, ByName(name)), - nil) -} - -// GetReferencesByIdentitySelectors returns resources that match the given identity selectors. -func (cd *ComponentDescriptor) GetReferencesByIdentitySelectors(selectors ...IdentitySelector) (References, error) { - return cd.GetReferencesBySelectors(selectors, nil) -} - -// GetReferencesByReferenceSelectors returns resources that match the given resource selectors. -func (cd *ComponentDescriptor) GetReferencesByReferenceSelectors(selectors ...ReferenceSelector) (References, error) { - return cd.GetReferencesBySelectors(nil, selectors) -} - -// GetReferencesBySelectors returns resources that match the given selector. -func (cd *ComponentDescriptor) GetReferencesBySelectors(selectors []IdentitySelector, referenceSelectors []ReferenceSelector) (References, error) { - references := make(References, 0) - for i := range cd.References { - selctx := NewReferenceSelectionContext(i, cd.References) - if len(selectors) > 0 { - ok, err := selector.MatchSelectors(selctx.Identity(), selectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) - } - if !ok { - continue - } - } - ok, err := MatchReferencesByReferenceSelector(selctx, referenceSelectors...) - if err != nil { - return nil, fmt.Errorf("unable to match selector for resource %s: %w", selctx.Name, err) - } - if !ok { - continue - } - references = append(references, *selctx.ComponentReference) - } - if len(references) == 0 { - return references, NotFound - } - return references, nil -} - // GetReferenceIndex returns the index of a given source. // If the index is not found -1 is returned. func (cd *ComponentDescriptor) GetReferenceIndex(src ElementMetaProvider) int { diff --git a/pkg/contexts/ocm/compdesc/selector.go b/pkg/contexts/ocm/compdesc/selector.go new file mode 100644 index 000000000..578ccde40 --- /dev/null +++ b/pkg/contexts/ocm/compdesc/selector.go @@ -0,0 +1,61 @@ +package compdesc + +import ( + "github.com/mandelsoft/goutils/generics" + + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +type elemList struct { + ElementAccessor +} + +func (e *elemList) Get(i int) accessors.ElementMetaAccessor { + return generics.Cast[accessors.ElementMetaAccessor](e.ElementAccessor.Get(i)) +} + +func MapToSelectorElementList(accessor ElementAccessor) accessors.ElementListAccessor { + return &elemList{accessor} +} + +//////////////////////////////////////////////////////////////////////////////// + +type rscAcc struct { + *Resource +} + +func (a rscAcc) GetMeta() accessors.ElementMeta { + return a.Resource.GetMeta() +} + +func MapToSelectorResource(r *Resource) accessors.ResourceAccessor { + return rscAcc{r} +} + +//////////////////////////////////////////////////////////////////////////////// + +type srcAcc struct { + *Source +} + +func (a srcAcc) GetMeta() accessors.ElementMeta { + return a.Source.GetMeta() +} + +func MapToSelectorSource(r *Source) accessors.SourceAccessor { + return srcAcc{r} +} + +//////////////////////////////////////////////////////////////////////////////// + +type refAcc struct { + *ComponentReference +} + +func (a refAcc) GetMeta() accessors.ElementMeta { + return a.ComponentReference.GetMeta() +} + +func MapToSelectorReference(r *ComponentReference) accessors.ReferenceAccessor { + return refAcc{r} +} diff --git a/pkg/contexts/ocm/compdesc/selectors.go b/pkg/contexts/ocm/compdesc/selectors.go index 81c6f6098..c3a96438f 100644 --- a/pkg/contexts/ocm/compdesc/selectors.go +++ b/pkg/contexts/ocm/compdesc/selectors.go @@ -12,6 +12,7 @@ import ( "github.com/open-component-model/ocm/pkg/utils/selector" ) +// Deprecated: use package selectors and its sub packages. type IdentityBasedSelector interface { IdentitySelector ElementSelector @@ -19,12 +20,14 @@ type IdentityBasedSelector interface { ReferenceSelector } +// Deprecated: use package selectors and its sub packages. type ElementBasedSelector interface { ElementSelector ResourceSelector ReferenceSelector } +// Deprecated: use package selectors and its sub packages. type LabelBasedSelector interface { LabelSelector ElementSelector @@ -34,6 +37,7 @@ type LabelBasedSelector interface { //////////////////////////////////////////////////////////////////////////////// +// Deprecated: use package selectors and its sub packages. type IdentitySelector = selector.Interface type byVersion struct { @@ -60,6 +64,8 @@ func (b *byVersion) MatchReference(obj ReferenceSelectionContext) (bool, error) // ByVersion creates a new selector that // selects an element based on its version. +// +// Deprecated: use package selectors and its sub packages. func ByVersion(version string) IdentityBasedSelector { return &byVersion{version: version} } @@ -88,6 +94,8 @@ func (b *byName) MatchReference(obj ReferenceSelectionContext) (bool, error) { // ByName creates a new selector that // selects an element based on its name. +// +// Deprecated: use package selectors and its sub packages. func ByName(name string) IdentityBasedSelector { return &byName{name: name} } @@ -126,6 +134,8 @@ func (b *byIdentity) MatchReference(obj ReferenceSelectionContext) (bool, error) // ByIdentity creates a new resource and identity selector that // selects a resource based on its identity. +// +// Deprecated: use package selectors and its sub packages. func ByIdentity(name string, extras ...string) IdentityBasedSelector { id := v1.NewIdentity(name, extras...) return &byIdentity{id: id} @@ -135,6 +145,8 @@ func ByIdentity(name string, extras ...string) IdentityBasedSelector { // selects a resource based on its partial identity. // All given attributes must match, but potential additional attributes // of a resource identity are ignored. +// +// Deprecated: use package selectors and its sub packages. func ByPartialIdentity(name string, extras ...string) IdentityBasedSelector { id := v1.NewIdentity(name, extras...) return &byIdentity{id: id, partial: true} @@ -172,6 +184,8 @@ func (b *withExtraId) MatchReference(obj ReferenceSelectionContext) (bool, error // WithExtraIdentity creates a new selector that // selects an element based on extra identities. +// +// Deprecated: use package selectors and its sub packages. func WithExtraIdentity(args ...string) IdentityBasedSelector { ids := v1.Identity{} for i := 0; i < len(args); i += 2 { @@ -185,6 +199,8 @@ func WithExtraIdentity(args ...string) IdentityBasedSelector { //////////////////////////////////////////////////////////////////////////////// // ResourceSelectorFunc defines a function to filter a resource. +// +// Deprecated: use package selectors and its sub packages. type ResourceSelectorFunc func(obj ResourceSelectionContext) (bool, error) var _ ResourceSelector = ResourceSelectorFunc(nil) @@ -198,6 +214,7 @@ type resourceSelectionContext struct { identity } +// Deprecated: use package selectors and its sub packages. func NewResourceSelectionContext(index int, rscs Resources) ResourceSelectionContext { return &resourceSelectionContext{ Resource: &rscs[index], @@ -211,14 +228,20 @@ func NewResourceSelectionContext(index int, rscs Resources) ResourceSelectionCon // ResourceSelectionContext describes the selction context for a resource // selector. It contains the resource and provides access to its // identity in the context of its component descriptor. +// +// Deprecated: use package selectors and its sub packages. type ResourceSelectionContext = *resourceSelectionContext // ResourceSelector defines a selector based on resource attributes. +// +// Deprecated: use package selectors and its sub packages. type ResourceSelector interface { MatchResource(obj ResourceSelectionContext) (bool, error) } // MatchResourceByResourceSelector applies all resource selector against the given resource object. +// +// Deprecated: use package selectors and its sub packages. func MatchResourceByResourceSelector(obj ResourceSelectionContext, resourceSelectors ...ResourceSelector) (bool, error) { for _, sel := range resourceSelectors { ok, err := sel.MatchResource(obj) @@ -233,6 +256,8 @@ func MatchResourceByResourceSelector(obj ResourceSelectionContext, resourceSelec } // AndR is an AND resource selector. +// +// Deprecated: use package labelsel. func AndR(sel ...ResourceSelector) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { for _, s := range sel { @@ -246,6 +271,8 @@ func AndR(sel ...ResourceSelector) ResourceSelector { } // OrR is an OR resource selector. +// +// Deprecated: use package labelsel. func OrR(sel ...ResourceSelector) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { for _, s := range sel { @@ -259,6 +286,8 @@ func OrR(sel ...ResourceSelector) ResourceSelector { } // NotR is a negated resource selector. +// +// Deprecated: use package labelsel. func NotR(sel ResourceSelector) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { ok, err := sel.MatchResource(obj) @@ -271,6 +300,8 @@ func NotR(sel ResourceSelector) ResourceSelector { // ByResourceType creates a new resource selector that // selects a resource based on its type. +// +// Deprecated: use package selectors and its sub packages. func ByResourceType(ttype string) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { return ttype == "" || obj.GetType() == ttype, nil @@ -279,6 +310,8 @@ func ByResourceType(ttype string) ResourceSelector { // ByRelation creates a new resource selector that // selects a resource based on its relation type. +// +// Deprecated: use package selectors and its sub packages. func ByRelation(relation v1.ResourceRelation) ResourceSelectorFunc { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { return obj.Relation == relation, nil @@ -286,6 +319,8 @@ func ByRelation(relation v1.ResourceRelation) ResourceSelectorFunc { } // ByAccessMethod creates a new selector that matches a resource access method type. +// +// Deprecated: use package selectors and its sub packages. func ByAccessMethod(name string) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { if obj.Access == nil { @@ -296,6 +331,8 @@ func ByAccessMethod(name string) ResourceSelector { } // ForExecutable creates a new selector that matches a resource for an executable. +// +// Deprecated: use package selectors and its sub packages. func ForExecutable(name string) ResourceSelector { return ResourceSelectorFunc(func(obj ResourceSelectionContext) (bool, error) { return obj.Name == name && obj.Type == resourcetypes.EXECUTABLE && obj.ExtraIdentity != nil && @@ -307,11 +344,15 @@ func ForExecutable(name string) ResourceSelector { //////////////////////////////////////////////////////////////////////////////// // LabelSelector is used to match a label in a label set. +// +// Deprecated: use package selectors and its sub packages. type LabelSelector interface { MatchLabel(l v1.Label) (bool, error) } // LabelSelectorFunc is a function used as LabelSelector. +// +// Deprecated: use package selectors and its sub packages. type LabelSelectorFunc func(l v1.Label) (bool, error) func (l LabelSelectorFunc) MatchLabel(label v1.Label) (bool, error) { @@ -319,6 +360,8 @@ func (l LabelSelectorFunc) MatchLabel(label v1.Label) (bool, error) { } // AndL is an AND label selector. +// +// Deprecated: use package selectors and its sub packages. func AndL(sel ...LabelSelector) LabelSelector { return LabelSelectorFunc(func(obj v1.Label) (bool, error) { for _, s := range sel { @@ -332,6 +375,8 @@ func AndL(sel ...LabelSelector) LabelSelector { } // OrL is an OR label selector. +// +// Deprecated: use package selectors and its sub packages. func OrL(sel ...LabelSelector) LabelSelector { return LabelSelectorFunc(func(obj v1.Label) (bool, error) { for _, s := range sel { @@ -345,6 +390,8 @@ func OrL(sel ...LabelSelector) LabelSelector { } // NotL is a negated label selector. +// +// Deprecated: use package selectors and its sub packages. func NotL(sel LabelSelector) LabelSelector { return LabelSelectorFunc(func(obj v1.Label) (bool, error) { ok, err := sel.MatchLabel(obj) @@ -392,6 +439,8 @@ func (b *byLabel) MatchLabel(l v1.Label) (bool, error) { // be grouped into a single label selector to be applied in // combination. Otherwise, a resource might match if the label // selectors all match, but different labels. +// +// Deprecated: use package selectors and its sub packages. func ByLabel(sel ...LabelSelector) LabelBasedSelector { return &byLabel{selector: LabelSelectorFunc(func(l v1.Label) (bool, error) { return MatchLabels(v1.Labels{l}, sel...) @@ -399,12 +448,16 @@ func ByLabel(sel ...LabelSelector) LabelBasedSelector { } // ByLabelName matches an element by a label name. +// +// Deprecated: use package selectors and its sub packages. func ByLabelName(name string) LabelBasedSelector { return &byLabel{selector: LabelSelectorFunc(func(l v1.Label) (bool, error) { return l.Name == name, nil })} } // ByLabelValue matches a resource or label by a label value. // This selector should typically be combined with ByLabelName. +// +// Deprecated: use package selectors and its sub packages. func ByLabelValue(value interface{}) LabelBasedSelector { return &byLabel{selector: LabelSelectorFunc(func(l v1.Label) (bool, error) { var data interface{} @@ -417,18 +470,24 @@ func ByLabelValue(value interface{}) LabelBasedSelector { // ByLabelVersion matches a resource or label by a label version. // This selector should typically be combined with ByLabelName. +// +// Deprecated: use package selectors and its sub packages. func ByLabelVersion(version string) LabelBasedSelector { return &byLabel{selector: LabelSelectorFunc(func(l v1.Label) (bool, error) { return l.Version == version, nil })} } // BySignedLabel matches a resource or label by a label indicated to be signed. // This selector should typically be combined with ByLabelName. +// +// Deprecated: use package selectors and its sub packages. func BySignedLabel(flags ...bool) LabelBasedSelector { flag := utils.OptionalDefaultedBool(true, flags...) return &byLabel{selector: LabelSelectorFunc(func(l v1.Label) (bool, error) { return l.Signing == flag, nil })} } // MatchLabels checks whether a set of labels matches the given label selectors. +// +// Deprecated: use package selectors and its sub packages. func MatchLabels(labels v1.Labels, sel ...LabelSelector) (bool, error) { if len(labels) == 0 && len(sel) == 0 { return true, nil @@ -453,6 +512,8 @@ outer: } // SelectLabels returns labels matching the given label selectors. +// +// Deprecated: use package selectors and its sub packages. func SelectLabels(labels v1.Labels, sel ...LabelSelector) (v1.Labels, error) { list := make(v1.Labels, 0) outer: @@ -473,6 +534,8 @@ outer: } // MatchReferencesByReferenceSelector applies all resource selector against the given resource object. +// +// Deprecated: use package selectors and its sub packages. func MatchReferencesByReferenceSelector(obj ReferenceSelectionContext, resourceSelectors ...ReferenceSelector) (bool, error) { for _, sel := range resourceSelectors { ok, err := sel.MatchReference(obj) @@ -493,8 +556,10 @@ type elementSelectionContext struct { identity } +// Deprecated: not supported anymore. type ElementSelectionContext = *elementSelectionContext +// Deprecated: not supported anymore. func NewElementSelectionContext(index int, elems ElementAccessor) ElementSelectionContext { return &elementSelectionContext{ ElementMeta: elems.Get(index).GetMeta(), @@ -505,6 +570,7 @@ func NewElementSelectionContext(index int, elems ElementAccessor) ElementSelecti } } +// Deprecated: use package selectors and its sub packages. type ElementSelector interface { MatchElement(obj ElementSelectionContext) (bool, error) } @@ -512,6 +578,8 @@ type ElementSelector interface { //////////////////////////////////////////////////////////////////////////////// // ReferenceSelectorFunc defines a function to filter a resource. +// +// Deprecated: use package selectors and its sub packages. type ReferenceSelectorFunc func(obj ReferenceSelectionContext) (bool, error) var _ ReferenceSelector = ReferenceSelectorFunc(nil) @@ -525,6 +593,7 @@ type referenceSelectionContext struct { identity } +// Deprecated: use package selectors and its sub packages. func NewReferenceSelectionContext(index int, refs References) ReferenceSelectionContext { return &referenceSelectionContext{ ComponentReference: &refs[index], @@ -538,14 +607,20 @@ func NewReferenceSelectionContext(index int, refs References) ReferenceSelection // ReferenceSelectionContext describes the selection context for a reference // selector. It contains the reference and provides access to its // identity in the context of its component descriptor. +// +// Deprecated: use package selectors and its sub packages. type ReferenceSelectionContext = *referenceSelectionContext // ReferenceSelector defines a selector based on reference attributes. +// +// Deprecated: use package selectors and its sub packages. type ReferenceSelector interface { MatchReference(obj ReferenceSelectionContext) (bool, error) } // AndC is an AND reference selector. +// +// Deprecated: use package selectors and its sub packages. func AndC(sel ...ReferenceSelector) ReferenceSelector { return ReferenceSelectorFunc(func(obj ReferenceSelectionContext) (bool, error) { for _, s := range sel { @@ -559,6 +634,8 @@ func AndC(sel ...ReferenceSelector) ReferenceSelector { } // OrC is an OR resource selector. +// +// Deprecated: use package selectors and its sub packages. func OrC(sel ...ReferenceSelector) ReferenceSelector { return ReferenceSelectorFunc(func(obj ReferenceSelectionContext) (bool, error) { for _, s := range sel { @@ -572,6 +649,8 @@ func OrC(sel ...ReferenceSelector) ReferenceSelector { } // NotC is a negated resource selector. +// +// Deprecated: use package selectors and its sub packages. func NotC(sel ReferenceSelector) ReferenceSelector { return ReferenceSelectorFunc(func(obj ReferenceSelectionContext) (bool, error) { ok, err := sel.MatchReference(obj) @@ -582,6 +661,7 @@ func NotC(sel ReferenceSelector) ReferenceSelector { }) } +// Deprecated: use package selectors and its sub packages. func ByComponent(name string) ReferenceSelector { return ReferenceSelectorFunc(func(obj ReferenceSelectionContext) (bool, error) { return obj.ComponentName == name, nil diff --git a/pkg/contexts/ocm/cpi/dummy.go b/pkg/contexts/ocm/cpi/dummy.go index 4111edbe0..0ea31bc10 100644 --- a/pkg/contexts/ocm/cpi/dummy.go +++ b/pkg/contexts/ocm/cpi/dummy.go @@ -8,6 +8,9 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc" metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" "github.com/open-component-model/ocm/pkg/contexts/ocm/internal" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/refsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/rscsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/srcsel" ) type DummyComponentVersionAccess struct { @@ -67,6 +70,10 @@ func (d *DummyComponentVersionAccess) GetDescriptor() *compdesc.ComponentDescrip return nil } +func (d *DummyComponentVersionAccess) SelectResources(sel ...rscsel.Selector) ([]ResourceAccess, error) { + return nil, nil +} + func (d *DummyComponentVersionAccess) GetResources() []ResourceAccess { return nil } @@ -83,10 +90,15 @@ func (d *DummyComponentVersionAccess) GetResourceByIndex(i int) (ResourceAccess, return nil, errors.ErrInvalid("resource index", strconv.Itoa(i)) } +// Deprecated: use GetResources. func (d *DummyComponentVersionAccess) GetResourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]ResourceAccess, error) { return nil, errors.ErrInvalid("resource", name) } +func (d *DummyComponentVersionAccess) SelectSources(sel ...srcsel.Selector) ([]SourceAccess, error) { + return nil, nil +} + func (d *DummyComponentVersionAccess) GetSources() []SourceAccess { return nil } @@ -107,6 +119,14 @@ func (d *DummyComponentVersionAccess) GetReference(meta metav1.Identity) (Compon return ComponentReference{}, errors.ErrNotFound("reference", meta.String()) } +func (d *DummyComponentVersionAccess) SelectReferences(sel ...refsel.Selector) ([]ComponentReference, error) { + return nil, nil +} + +func (d *DummyComponentVersionAccess) GetReferences() []ComponentReference { + return nil +} + func (d *DummyComponentVersionAccess) GetReferenceIndex(metav1.Identity) int { return -1 } @@ -115,6 +135,7 @@ func (d *DummyComponentVersionAccess) GetReferenceByIndex(i int) (ComponentRefer return ComponentReference{}, errors.ErrInvalid("reference index", strconv.Itoa(i)) } +// Deprecated: use GetSources. func (d *DummyComponentVersionAccess) GetSourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]SourceAccess, error) { return nil, errors.ErrInvalid("source", name) } @@ -137,6 +158,10 @@ func (d *DummyComponentVersionAccess) Update() error { return errors.ErrNotSupported("update") } +func (d *DummyComponentVersionAccess) Execute(f func() error) error { + return f() +} + func (d *DummyComponentVersionAccess) AddBlob(blob BlobAccess, arttype, refName string, global AccessSpec, opts ...BlobUploadOption) (AccessSpec, error) { return nil, errors.ErrNotSupported("adding blobs") } @@ -184,22 +209,27 @@ func (d *DummyComponentVersionAccess) UseDirectAccess() bool { return true } +// Deprecated: use GetResources. func (d *DummyComponentVersionAccess) GetResourcesByIdentitySelectors(selectors ...compdesc.IdentitySelector) ([]internal.ResourceAccess, error) { return nil, nil } +// Deprecated: use GetResources. func (d *DummyComponentVersionAccess) GetResourcesByResourceSelectors(selectors ...compdesc.ResourceSelector) ([]internal.ResourceAccess, error) { return nil, nil } +// Deprecated: use GetReferences. func (d *DummyComponentVersionAccess) GetReferencesByName(name string, selectors ...compdesc.IdentitySelector) (compdesc.References, error) { return nil, nil } +// Deprecated: use GetReferences. func (d *DummyComponentVersionAccess) GetReferencesByIdentitySelectors(selectors ...compdesc.IdentitySelector) (compdesc.References, error) { return nil, nil } +// Deprecated: use GetReferences. func (d *DummyComponentVersionAccess) GetReferencesByReferenceSelectors(selectors ...compdesc.ReferenceSelector) (compdesc.References, error) { return nil, nil } diff --git a/pkg/contexts/ocm/cpi/repocpi/view_cv.go b/pkg/contexts/ocm/cpi/repocpi/view_cv.go index 6586e58f4..ec0cc6db0 100644 --- a/pkg/contexts/ocm/cpi/repocpi/view_cv.go +++ b/pkg/contexts/ocm/cpi/repocpi/view_cv.go @@ -17,6 +17,10 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi/accspeccpi" "github.com/open-component-model/ocm/pkg/contexts/ocm/internal" "github.com/open-component-model/ocm/pkg/contexts/ocm/plugin/descriptor" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/refsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/rscsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/srcsel" "github.com/open-component-model/ocm/pkg/refmgmt" "github.com/open-component-model/ocm/pkg/refmgmt/resource" "github.com/open-component-model/ocm/pkg/utils" @@ -643,6 +647,7 @@ func (c *componentVersionAccessView) GetResourceByIndex(i int) (cpi.ResourceAcce return cpi.NewResourceAccess(c, r.Access, r.ResourceMeta), nil } +// Deprecated: use GetResources with appropriate selectors. func (c *componentVersionAccessView) GetResourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]cpi.ResourceAccess, error) { resources, err := c.GetDescriptor().GetResourcesByName(name, selectors...) if err != nil { @@ -656,6 +661,28 @@ func (c *componentVersionAccessView) GetResourcesByName(name string, selectors . return result, nil } +func (c *componentVersionAccessView) SelectResources(sel ...rscsel.Selector) ([]cpi.ResourceAccess, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } + + list := compdesc.MapToSelectorElementList(c.GetDescriptor().Resources) + result := []cpi.ResourceAccess{} + for _, r := range c.GetDescriptor().Resources { + if len(sel) > 0 { + mr := compdesc.MapToSelectorResource(&r) + for _, s := range sel { + if !s.MatchResource(list, mr) { + continue + } + } + } + result = append(result, cpi.NewResourceAccess(c, r.Access, r.ResourceMeta)) + } + return result, nil +} + func (c *componentVersionAccessView) GetResources() []cpi.ResourceAccess { result := []cpi.ResourceAccess{} for _, r := range c.GetDescriptor().Resources { @@ -665,16 +692,22 @@ func (c *componentVersionAccessView) GetResources() []cpi.ResourceAccess { } // GetResourcesByIdentitySelectors returns resources that match the given identity selectors. +// +// Deprecated: use GetReferences. func (c *componentVersionAccessView) GetResourcesByIdentitySelectors(selectors ...compdesc.IdentitySelector) ([]cpi.ResourceAccess, error) { return c.GetResourcesBySelectors(selectors, nil) } // GetResourcesByResourceSelectors returns resources that match the given resource selectors. +// +// Deprecated: use GetResources. func (c *componentVersionAccessView) GetResourcesByResourceSelectors(selectors ...compdesc.ResourceSelector) ([]cpi.ResourceAccess, error) { return c.GetResourcesBySelectors(nil, selectors) } // GetResourcesBySelectors returns resources that match the given selector. +// +// Deprecated: use GetResources. func (c *componentVersionAccessView) GetResourcesBySelectors(selectors []compdesc.IdentitySelector, resourceSelectors []compdesc.ResourceSelector) ([]cpi.ResourceAccess, error) { resources := make([]cpi.ResourceAccess, 0) rscs := c.GetDescriptor().Resources @@ -728,6 +761,7 @@ func (c *componentVersionAccessView) GetSourceByIndex(i int) (cpi.SourceAccess, return cpi.NewSourceAccess(c, r.Access, r.SourceMeta), nil } +// Deprecated: use GetSources with appropriate selectors. func (c *componentVersionAccessView) GetSourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]cpi.SourceAccess, error) { sources, err := c.GetDescriptor().GetSourcesByName(name, selectors...) if err != nil { @@ -741,6 +775,28 @@ func (c *componentVersionAccessView) GetSourcesByName(name string, selectors ... return result, nil } +func (c *componentVersionAccessView) SelectSources(sel ...srcsel.Selector) ([]cpi.SourceAccess, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } + + list := compdesc.MapToSelectorElementList(c.GetDescriptor().Sources) + result := []cpi.SourceAccess{} + for _, r := range c.GetDescriptor().Sources { + if len(sel) > 0 { + mr := compdesc.MapToSelectorSource(&r) + for _, s := range sel { + if !s.MatchSource(list, mr) { + continue + } + } + } + result = append(result, cpi.NewSourceAccess(c, r.Access, r.SourceMeta)) + } + return result, nil +} + func (c *componentVersionAccessView) GetSources() []cpi.SourceAccess { result := []cpi.SourceAccess{} for _, r := range c.GetDescriptor().Sources { @@ -749,8 +805,16 @@ func (c *componentVersionAccessView) GetSources() []cpi.SourceAccess { return result } -func (c *componentVersionAccessView) GetReferences() compdesc.References { - return c.GetDescriptor().References +func (c *componentVersionAccessView) SelectReferences(sel ...refsel.Selector) ([]compdesc.ComponentReference, error) { + err := selectors.ValidateSelectors(sel...) + if err != nil { + return nil, err + } + return c.GetDescriptor().SelectReferences(sel...) +} + +func (c *componentVersionAccessView) GetReferences() []compdesc.ComponentReference { + return c.GetDescriptor().GetReferences() } func (c *componentVersionAccessView) GetReference(id metav1.Identity) (cpi.ComponentReference, error) { @@ -768,21 +832,28 @@ func (c *componentVersionAccessView) GetReferenceByIndex(i int) (cpi.ComponentRe return c.GetDescriptor().References[i], nil } +// Deprecated: use GetReferences. func (c *componentVersionAccessView) GetReferencesByName(name string, selectors ...compdesc.IdentitySelector) (compdesc.References, error) { return c.GetDescriptor().GetReferencesByName(name, selectors...) } // GetReferencesByIdentitySelectors returns references that match the given identity selectors. +// +// Deprecated: use GetReferences. func (c *componentVersionAccessView) GetReferencesByIdentitySelectors(selectors ...compdesc.IdentitySelector) (compdesc.References, error) { return c.GetReferencesBySelectors(selectors, nil) } // GetReferencesByReferenceSelectors returns references that match the given resource selectors. +// +// Deprecated: use GetReferences. func (c *componentVersionAccessView) GetReferencesByReferenceSelectors(selectors ...compdesc.ReferenceSelector) (compdesc.References, error) { return c.GetReferencesBySelectors(nil, selectors) } // GetReferencesBySelectors returns references that match the given selector. +// +// Deprecated: use GetReferences. func (c *componentVersionAccessView) GetReferencesBySelectors(selectors []compdesc.IdentitySelector, referenceSelectors []compdesc.ReferenceSelector) (compdesc.References, error) { references := make(compdesc.References, 0) refs := c.GetDescriptor().References diff --git a/pkg/contexts/ocm/internal/repository.go b/pkg/contexts/ocm/internal/repository.go index 2ef145b15..6c0c67e86 100644 --- a/pkg/contexts/ocm/internal/repository.go +++ b/pkg/contexts/ocm/internal/repository.go @@ -8,6 +8,9 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/credentials" "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc" metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/refsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/rscsel" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/srcsel" "github.com/open-component-model/ocm/pkg/refmgmt/resource" ) @@ -128,20 +131,37 @@ type ComponentVersionAccess interface { GetProvider() *compdesc.Provider SetProvider(provider *compdesc.Provider) error - GetResources() []ResourceAccess GetResource(meta metav1.Identity) (ResourceAccess, error) GetResourceIndex(meta metav1.Identity) int GetResourceByIndex(i int) (ResourceAccess, error) + GetResources() []ResourceAccess + SelectResources(sel ...rscsel.Selector) ([]ResourceAccess, error) + + // + // Deprecated: use GetResources with selector arguments. + //nolint: staticcheck // deprecated GetResourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]ResourceAccess, error) + + // + // Deprecated: use GetResources with selector arguments. + //nolint: staticcheck // deprecated GetResourcesByIdentitySelectors(selectors ...compdesc.IdentitySelector) ([]ResourceAccess, error) + + // + // Deprecated: use GetResources with selector arguments. + //nolint: staticcheck // deprecated GetResourcesByResourceSelectors(selectors ...compdesc.ResourceSelector) ([]ResourceAccess, error) SetResource(*ResourceMeta, compdesc.AccessSpec, ...ModificationOption) error SetResourceByAccess(art ResourceAccess, modopts ...BlobModificationOption) error - GetSources() []SourceAccess GetSource(meta metav1.Identity) (SourceAccess, error) GetSourceIndex(meta metav1.Identity) int GetSourceByIndex(i int) (SourceAccess, error) + GetSources() []SourceAccess + SelectSources(sel ...srcsel.Selector) ([]SourceAccess, error) + + // Deprecated: use GetResources with appropriate selectors. + //nolint: staticcheck // deprecated GetSourcesByName(name string, selectors ...compdesc.IdentitySelector) ([]SourceAccess, error) // SetSource updates or sets anew source. The options only use the // target options. All other options are ignored. @@ -153,8 +173,19 @@ type ComponentVersionAccess interface { GetReference(meta metav1.Identity) (ComponentReference, error) GetReferenceIndex(meta metav1.Identity) int GetReferenceByIndex(i int) (ComponentReference, error) + GetReferences() []ComponentReference + SelectReferences(sel ...refsel.Selector) ([]ComponentReference, error) + + // Deprecated: use GetReferences with appropriate selectors. + //nolint: staticcheck // deprecated GetReferencesByName(name string, selectors ...compdesc.IdentitySelector) (compdesc.References, error) + + // Deprecated: use GetReferences with appropriate selectors. + //nolint: staticcheck // deprecated GetReferencesByIdentitySelectors(selectors ...compdesc.IdentitySelector) (compdesc.References, error) + + // Deprecated: use GetReferences with appropriate selectors. + //nolint: staticcheck // deprecated GetReferencesByReferenceSelectors(selectors ...compdesc.ReferenceSelector) (compdesc.References, error) SetReference(ref *ComponentReference, opts ...TargetOption) error @@ -188,6 +219,10 @@ type ComponentVersionAccess interface { // Update adds the version with all changes to the component instance it has been created for. Update() error + + // Execute executes a function on a valid and locked component version reference. + // If it returns an error this error is forwarded. + Execute(func() error) error } // ComponentLister provides the optional repository list functionality of diff --git a/pkg/contexts/ocm/pubsub/types/compound/type.go b/pkg/contexts/ocm/pubsub/types/compound/type.go index 31df9279f..29f132cd4 100644 --- a/pkg/contexts/ocm/pubsub/types/compound/type.go +++ b/pkg/contexts/ocm/pubsub/types/compound/type.go @@ -19,9 +19,9 @@ const ( func init() { pubsub.RegisterType(pubsub.NewPubSubType[*Spec](Type, - pubsub.WithDesciption("a pub/sub system forwarding events to described sub-level systems."))) + pubsub.WithDesciption("A pub/sub system forwarding events to described sub-level systems."))) pubsub.RegisterType(pubsub.NewPubSubType[*Spec](TypeV1, - pubsub.WithFormatSpec(`It is describe by the following field: + pubsub.WithFormatSpec(`It is described by the following field: - **specifications** *list of pubsub specs* diff --git a/pkg/contexts/ocm/selectors/accessors/accessors.go b/pkg/contexts/ocm/selectors/accessors/accessors.go new file mode 100644 index 000000000..1559f89d2 --- /dev/null +++ b/pkg/contexts/ocm/selectors/accessors/accessors.go @@ -0,0 +1,56 @@ +package accessors + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/runtime" +) + +// ElementListAccessor provides generic access to list of elements. +type ElementListAccessor interface { + Len() int + Get(i int) ElementMetaAccessor +} + +// ElementMeta describes the access to common element meta data attributes. +type ElementMeta interface { + GetName() string + GetVersion() string + GetExtraIdentity() v1.Identity + GetLabels() v1.Labels + GetIdentityForContext(accessor ElementListAccessor) v1.Identity +} + +// ElementMetaAccessor provides generic access an elements meta information. +type ElementMetaAccessor interface { + GetMeta() ElementMeta +} + +// AccessSpec is the minimal interface for access spec attributes. +type AccessSpec interface { + runtime.VersionedTypedObject +} + +// ArtifactAccessor provides access to generic artifact information of an element. +type ArtifactAccessor interface { + ElementMetaAccessor + GetType() string + GetAccess() AccessSpec +} + +// ResourceAccessor provides access to resource attribute. +type ResourceAccessor interface { + ArtifactAccessor + GetRelation() v1.ResourceRelation + GetDigest() *v1.DigestSpec +} + +// SourceAccessor provides access to source attribute. +type SourceAccessor interface { + ArtifactAccessor +} + +// ReferenceAccessor provides access to source attribute. +type ReferenceAccessor interface { + ElementMetaAccessor + GetComponentName() string +} diff --git a/pkg/contexts/ocm/selectors/artifacts.go b/pkg/contexts/ocm/selectors/artifacts.go new file mode 100644 index 000000000..c6dd782ba --- /dev/null +++ b/pkg/contexts/ocm/selectors/artifacts.go @@ -0,0 +1,54 @@ +package selectors + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +type ArtifactSelector interface { + MatchArtifact(a accessors.ArtifactAccessor) bool +} + +type ArtifactSelectorImpl struct { + ArtifactSelector +} + +func (i *ArtifactSelectorImpl) MatchResource(list accessors.ElementListAccessor, a accessors.ResourceAccessor) bool { + return i.MatchArtifact(a) +} + +func (i *ArtifactSelectorImpl) MatchSource(list accessors.ElementListAccessor, a accessors.SourceAccessor) bool { + return i.MatchArtifact(a) +} + +type ArtifactErrorSelectorImpl struct { + ErrorSelectorBase + ArtifactSelectorImpl +} + +func NewArtifactErrorSelectorImpl(s ArtifactSelector, err error) *ArtifactErrorSelectorImpl { + return &ArtifactErrorSelectorImpl{NewErrorSelectorBase(err), ArtifactSelectorImpl{s}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type artType string + +func (n artType) MatchArtifact(a accessors.ArtifactAccessor) bool { + return string(n) == a.GetType() +} + +func ArtifactType(n string) *ArtifactSelectorImpl { + return &ArtifactSelectorImpl{artType(n)} +} + +//////////////////////////////////////////////////////////////////////////////// + +type accessKind string + +func (n accessKind) MatchArtifact(a accessors.ArtifactAccessor) bool { + return string(n) == a.GetAccess().GetKind() +} + +func AccessKind(n string) *ArtifactSelectorImpl { + return &ArtifactSelectorImpl{accessKind(n)} +} diff --git a/pkg/contexts/ocm/selectors/identity.go b/pkg/contexts/ocm/selectors/identity.go new file mode 100644 index 000000000..0ba701b84 --- /dev/null +++ b/pkg/contexts/ocm/selectors/identity.go @@ -0,0 +1,195 @@ +package selectors + +import ( + "regexp" + + "github.com/Masterminds/semver/v3" + + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +type IdentitySelector interface { + MatchIdentity(identity v1.Identity) bool +} + +type IdentitySelectorImpl struct { + IdentitySelector +} + +func (i *IdentitySelectorImpl) MatchResource(list accessors.ElementListAccessor, a accessors.ResourceAccessor) bool { + return i.MatchIdentity(a.GetMeta().GetIdentityForContext(list)) +} + +func (i *IdentitySelectorImpl) MatchSource(list accessors.ElementListAccessor, a accessors.SourceAccessor) bool { + return i.MatchIdentity(a.GetMeta().GetIdentityForContext(list)) +} + +func (i *IdentitySelectorImpl) MatchReference(list accessors.ElementListAccessor, a accessors.ReferenceAccessor) bool { + return i.MatchIdentity(a.GetMeta().GetIdentityForContext(list)) +} + +type IdentityErrorSelectorImpl struct { + ErrorSelectorBase + IdentitySelectorImpl +} + +func NewIdentityErrorSelectorImpl(s IdentitySelector, err error) *IdentityErrorSelectorImpl { + return &IdentityErrorSelectorImpl{NewErrorSelectorBase(err), IdentitySelectorImpl{s}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type idattrs struct { + v1.Identity +} + +func (i *idattrs) MatchIdentity(identity v1.Identity) bool { + for n, v := range i.Identity { + if identity[n] != v { + return false + } + } + return true +} + +func IdentityAttributesByKeyPairs(extra ...string) *IdentitySelectorImpl { + return &IdentitySelectorImpl{&idattrs{v1.NewExtraIdentity(extra...)}} +} + +func IdentityAttributes(identity v1.Identity) *IdentitySelectorImpl { + return &IdentitySelectorImpl{&idattrs{identity}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type id struct { + v1.Identity +} + +func (i *id) MatchIdentity(identity v1.Identity) bool { + if len(i.Identity) != len(identity) { + return false + } + for n, v := range i.Identity { + if identity[n] != v { + return false + } + } + return true +} + +func IdentityByKeyPairs(extra ...string) *IdentitySelectorImpl { + return &IdentitySelectorImpl{&id{v1.NewExtraIdentity(extra...)}} +} + +func Identity(identity v1.Identity) *IdentitySelectorImpl { + return &IdentitySelectorImpl{&id{identity}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type num int + +func (i num) MatchIdentity(identity v1.Identity) bool { + return len(identity) == int(i) +} + +func NumberOfIdentityAttributes(n int) *IdentitySelectorImpl { + return &IdentitySelectorImpl{num(n)} +} + +//////////////////////////////////////////////////////////////////////////////// + +type idRegEx struct { + attr string + *regexp.Regexp +} + +func (c *idRegEx) MatchIdentity(identity v1.Identity) bool { + v, ok := identity[c.attr] + if !ok { + return false + } + return c.Regexp.MatchString(v) +} + +func IdentityAttrRegex(name, ex string) *IdentitySelectorImpl { + c, _ := regexp.Compile(ex) + return &IdentitySelectorImpl{&idRegEx{name, c}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type Name string + +func (n Name) MatchIdentity(identity v1.Identity) bool { + return string(n) == identity[v1.SystemIdentityName] +} + +func (n Name) MatchResource(list accessors.ElementListAccessor, r accessors.ResourceAccessor) bool { + return string(n) == r.GetMeta().GetName() +} + +func (n Name) MatchSource(list accessors.ElementListAccessor, r accessors.SourceAccessor) bool { + return string(n) == r.GetMeta().GetName() +} + +func (n Name) MatchReference(list accessors.ElementListAccessor, r accessors.ReferenceAccessor) bool { + return string(n) == r.GetMeta().GetName() +} + +//////////////////////////////////////////////////////////////////////////////// + +type Version string + +func (v Version) MatchIdentity(identity v1.Identity) bool { + return string(v) == identity[v1.SystemIdentityVersion] +} + +func (v Version) MatchResource(list accessors.ElementListAccessor, r accessors.ResourceAccessor) bool { + return string(v) == r.GetMeta().GetVersion() +} + +func (v Version) MatchSource(list accessors.ElementListAccessor, r accessors.SourceAccessor) bool { + return string(v) == r.GetMeta().GetVersion() +} + +func (v Version) MatchReference(list accessors.ElementListAccessor, r accessors.ReferenceAccessor) bool { + return string(v) == r.GetMeta().GetVersion() +} + +//////////////////////////////////////////////////////////////////////////////// + +type semverConstraint struct { + *semver.Constraints +} + +func VersionConstraint(expr string) *semverConstraint { + c, _ := semver.NewConstraint(expr) + return &semverConstraint{c} +} + +func (v *semverConstraint) check(vers string) bool { + sv, _ := semver.NewVersion(vers) + if sv == nil { + return false + } + return v.Constraints.Check(sv) +} + +func (v *semverConstraint) MatchIdentity(identity v1.Identity) bool { + return v.check(identity[v1.SystemIdentityVersion]) +} + +func (v *semverConstraint) MatchResource(list accessors.ElementListAccessor, r accessors.ResourceAccessor) bool { + return v.check(r.GetMeta().GetVersion()) +} + +func (v *semverConstraint) MatchSource(list accessors.ElementListAccessor, r accessors.SourceAccessor) bool { + return v.check(r.GetMeta().GetVersion()) +} + +func (v *semverConstraint) MatchReference(list accessors.ElementListAccessor, r accessors.ReferenceAccessor) bool { + return v.check(r.GetMeta().GetVersion()) +} diff --git a/pkg/contexts/ocm/selectors/label.go b/pkg/contexts/ocm/selectors/label.go new file mode 100644 index 000000000..dd3a7cbd5 --- /dev/null +++ b/pkg/contexts/ocm/selectors/label.go @@ -0,0 +1,86 @@ +package selectors + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +func SelectLabels(labels v1.Labels, sel ...LabelSelector) ([]v1.Label, error) { + err := ValidateSelectors(sel...) + if err != nil { + return nil, err + } + return GetLabels(labels, sel...), nil +} + +func GetLabels(labels v1.Labels, sel ...LabelSelector) []v1.Label { + var result []v1.Label + for _, l := range labels { + for _, s := range sel { + if !s.MatchLabel(&l) { + continue + } + } + result = append(result, l) + } + return result +} + +//////////////////////////////////////////////////////////////////////////////// + +type LabelSelectorImpl struct { + LabelSelector +} + +func (i *LabelSelectorImpl) MatchResource(list accessors.ElementListAccessor, a accessors.ResourceAccessor) bool { + return len(GetLabels(a.GetMeta().GetLabels(), i)) > 0 +} + +func (i *LabelSelectorImpl) MatchSource(list accessors.ElementListAccessor, a accessors.SourceAccessor) bool { + return len(GetLabels(a.GetMeta().GetLabels(), i)) > 0 +} + +func (i *LabelSelectorImpl) MatchReference(list accessors.ElementListAccessor, a accessors.ReferenceAccessor) bool { + return len(GetLabels(a.GetMeta().GetLabels(), i)) > 0 +} + +type LabelErrPropSelectorImpl struct { + LabelSelectorImpl +} + +func (l *LabelErrPropSelectorImpl) GetError() error { + if e, ok := l.LabelSelector.(ErrorProvider); ok { + return e.GetError() + } + return nil +} + +type LabelErrorSelectorImpl struct { + ErrorSelectorBase + LabelSelectorImpl +} + +func NewLabelErrorSelectorImpl(s LabelSelector, err error) *LabelErrorSelectorImpl { + return &LabelErrorSelectorImpl{NewErrorSelectorBase(err), LabelSelectorImpl{s}} +} + +//////////////////////////////////////////////////////////////////////////////// + +type label []LabelSelector + +func (s label) MatchLabel(l *v1.Label) bool { + for _, n := range s { + if !n.MatchLabel(l) { + return false + } + } + return true +} + +func (s label) GetError() error { + return ValidateSubSelectors("and", []LabelSelector(s)...) +} + +func Label(sel ...LabelSelector) *LabelErrPropSelectorImpl { + return &LabelErrPropSelectorImpl{LabelSelectorImpl{label(sel)}} +} diff --git a/pkg/contexts/ocm/selectors/labelsel/interface.go b/pkg/contexts/ocm/selectors/labelsel/interface.go new file mode 100644 index 000000000..fe1b4103f --- /dev/null +++ b/pkg/contexts/ocm/selectors/labelsel/interface.go @@ -0,0 +1,178 @@ +package labelsel + +import ( + "bytes" + "container/list" + "encoding/json" + "reflect" + + "github.com/mandelsoft/goutils/errors" + "github.com/mikefarah/yq/v4/pkg/yqlib" + "gopkg.in/op/go-logging.v1" + + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/runtime" + "github.com/open-component-model/ocm/pkg/utils" +) + +func init() { + logging.SetLevel(logging.ERROR, "yq-lib") + yqlib.InitExpressionParser() +} + +type Selector = selectors.LabelSelector + +func Select(labels v1.Labels, sel ...Selector) ([]v1.Label, error) { + return selectors.SelectLabels(labels, sel...) +} + +func Get(labels v1.Labels, sel ...Selector) []v1.Label { + return selectors.GetLabels(labels, sel...) +} + +//////////////////////////////////////////////////////////////////////////////// + +type name string + +func (n name) MatchLabel(l *v1.Label) bool { + return string(n) == l.Name +} + +func Name(n string) *selectors.LabelSelectorImpl { + return &selectors.LabelSelectorImpl{name(n)} +} + +//////////////////////////////////////////////////////////////////////////////// + +type version string + +func (n version) MatchLabel(l *v1.Label) bool { + return string(n) == l.Version +} + +func Version(n string) *selectors.LabelSelectorImpl { + return &selectors.LabelSelectorImpl{version(n)} +} + +/////////////////////////////////////////////////////////////////////////////// + +type signed bool + +func (n signed) MatchLabel(l *v1.Label) bool { + return bool(n) == l.Signing +} + +func Signed(b ...bool) *selectors.LabelSelectorImpl { + return &selectors.LabelSelectorImpl{signed(utils.OptionalDefaultedBool(true, b...))} +} + +/////////////////////////////////////////////////////////////////////////////// + +type mergealgo string + +func (n mergealgo) MatchLabel(l *v1.Label) bool { + a := string(n) + if l.Merge == nil { + return a == "" + } + return a == l.Merge.Algorithm +} + +func MergeAlgo(algo string) *selectors.LabelSelectorImpl { + return &selectors.LabelSelectorImpl{mergealgo(algo)} +} + +//////////////////////////////////////////////////////////////////////////////// + +func AsStructure(value interface{}) (interface{}, error) { + var err error + + data, ok := value.([]byte) + if !ok { + data, err = json.Marshal(value) + if err != nil { + return nil, err + } + } + + var v interface{} + err = runtime.DefaultYAMLEncoding.Unmarshal(data, &v) + if err != nil { + return nil, err + } + return v, nil +} + +// Value matches a label by a label value. +// This selector should typically be combined with Name. +func Value(value interface{}) *selectors.LabelErrorSelectorImpl { + data, err := AsStructure(value) + return selectors.NewLabelErrorSelectorImpl(selectors.LabelSelectorFunc(func(l *v1.Label) bool { + var value interface{} + err := json.Unmarshal(l.Value, &value) + if err != nil { + return false + } + return reflect.DeepEqual(value, data) + }), err) +} + +//////////////////////////////////////////////////////////////////////////////// + +func YQParse(data []byte) (*yqlib.CandidateNode, error) { + decoder := yqlib.NewYamlDecoder(yqlib.YamlPreferences{}) + err := decoder.Init(bytes.NewReader(data)) + if err != nil { + return nil, err + } + return decoder.Decode() +} + +type yqeval struct { + expr *yqlib.ExpressionNode + value interface{} +} + +func (v *yqeval) MatchLabel(l *v1.Label) bool { + if v.expr == nil { + return false + } + in, err := YQParse(l.Value) + if err != nil { + return false + } + t := yqlib.NewDataTreeNavigator() + docs := list.New() + docs.PushBack(in) + context, err := t.GetMatchingNodes(yqlib.Context{MatchingNodes: docs}, v.expr) + if err != nil { + return false + } + if context.MatchingNodes.Len() != 1 { + return false + } + data, err := context.MatchingNodes.Front().Value.(*yqlib.CandidateNode).MarshalJSON() + if err != nil { + return false + } + var out interface{} + err = json.Unmarshal(data, &out) + if err != nil { + return false + } + return reflect.DeepEqual(v.value, out) +} + +// YQExpression matches a part of a label values described by a YQ expression. +// If value is a []byte, it is interpreted as JSON data, otherwise the value +// marshalled as JSON. +func YQExpression(expr string, value interface{}) *selectors.LabelErrorSelectorImpl { + var data interface{} + + node, err := yqlib.ExpressionParser.ParseExpression(expr) + if err == nil { + data, err = AsStructure(value) + } + return selectors.NewLabelErrorSelectorImpl(&yqeval{node, data}, errors.Wrapf(err, "YQExpression selector")) +} diff --git a/pkg/contexts/ocm/selectors/labelsel/label_test.go b/pkg/contexts/ocm/selectors/labelsel/label_test.go new file mode 100644 index 000000000..1e0dc22dc --- /dev/null +++ b/pkg/contexts/ocm/selectors/labelsel/label_test.go @@ -0,0 +1,88 @@ +package labelsel_test + +import ( + "bytes" + + . "github.com/mandelsoft/goutils/testutils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/labelsel" + "sigs.k8s.io/yaml" + + "github.com/mikefarah/yq/v4/pkg/yqlib" +) + +func Parse(data []byte) (*yqlib.CandidateNode, error) { + decoder := yqlib.NewYamlDecoder(yqlib.YamlPreferences{}) + err := decoder.Init(bytes.NewReader(data)) + if err != nil { + return nil, err + } + return decoder.Decode() +} + +var _ = Describe("yq label values", func() { + data := ` +people: +- name: alice + age: 25 +- name: bob + age: 26 +data: + attr: value +` + Context("yq", func() { + It("", func() { + doc := Must(Parse([]byte(data))) + eval := yqlib.NewAllAtOnceEvaluator() + r := Must(eval.EvaluateNodes(".people[0].name", doc)) + Expect(r.Len()).To(Equal(1)) + e := r.Front() + v := e.Value.(*yqlib.CandidateNode) + data := Must(v.MarshalJSON()) + Expect(data).To(YAMLEqual("alice")) + }) + }) + + Context("labels", func() { + var datav map[string]interface{} + labels := v1.Labels{} + MustBeSuccessful(yaml.Unmarshal([]byte(data), &datav)) + MustBeSuccessful(labels.SetValue("data", datav)) + MustBeSuccessful(labels.SetValue("string", "some data")) + + It("check complex data", func() { + m := labelsel.YQExpression(".data", datav["data"]) + Expect(m).NotTo(BeNil()) + Expect(selectors.ValidateSelectors(m)).NotTo(HaveOccurred()) + + Expect(m.MatchLabel(&labels[0])).To(BeTrue()) + Expect(m.MatchLabel(&labels[1])).To(BeFalse()) + }) + + It("check complex expression", func() { + m := labelsel.YQExpression(".people[0].name", "alice") + Expect(m).NotTo(BeNil()) + Expect(selectors.ValidateSelectors(m)).NotTo(HaveOccurred()) + + Expect(m.MatchLabel(&labels[0])).To(BeTrue()) + Expect(m.MatchLabel(&labels[1])).To(BeFalse()) + }) + + It("detects error", func() { + m := labelsel.YQExpression(".people[0]].name", "alice") + Expect(m).NotTo(BeNil()) + Expect(selectors.ValidateSelectors(m)).To(MatchError("error in selector list: YQExpression selector: bad expression, could not find matching `)`")) + }) + + It("detects error in expressions", func() { + m := labelsel.YQExpression(".people[0]].name", "alice") + Expect(m).NotTo(BeNil()) + Expect(selectors.ValidateSelectors(labelsel.Or(m))).To(MatchError("error in selector list: or: YQExpression selector: bad expression, could not find matching `)`")) + Expect(selectors.ValidateSelectors(labelsel.And(m))).To(MatchError("error in selector list: and: YQExpression selector: bad expression, could not find matching `)`")) + Expect(selectors.ValidateSelectors(labelsel.Not(m))).To(MatchError("error in selector list: not: YQExpression selector: bad expression, could not find matching `)`")) + }) + }) +}) diff --git a/pkg/contexts/ocm/selectors/labelsel/operators.go b/pkg/contexts/ocm/selectors/labelsel/operators.go new file mode 100644 index 000000000..7b628ca38 --- /dev/null +++ b/pkg/contexts/ocm/selectors/labelsel/operators.go @@ -0,0 +1,56 @@ +package labelsel + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" +) + +var ( + _ selectors.ErrorProvider = (or)(nil) + _ selectors.ErrorProvider = (*not)(nil) +) + +//////////////////////////////////////////////////////////////////////////////// + +func And(sel ...Selector) *selectors.LabelErrPropSelectorImpl { + return selectors.Label(sel...) +} + +//////////////////////////////////////////////////////////////////////////////// + +type or []Selector + +func (a or) MatchLabel(l *v1.Label) bool { + for _, o := range a { + if o.MatchLabel(l) { + return true + } + } + return false +} + +func (a or) GetError() error { + return selectors.ValidateSubSelectors("or", []Selector(a)...) +} + +func Or(operands ...Selector) Selector { + return or(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type not struct { + sel Selector +} + +func (a *not) MatchLabel(l *v1.Label) bool { + return !a.sel.MatchLabel(l) +} + +func (a *not) GetError() error { + return selectors.ValidateSubSelectors("not", a.sel) +} + +func Not(operand Selector) Selector { + return ¬{operand} +} diff --git a/pkg/contexts/ocm/selectors/labelsel/suite_test.go b/pkg/contexts/ocm/selectors/labelsel/suite_test.go new file mode 100644 index 000000000..a73a112c6 --- /dev/null +++ b/pkg/contexts/ocm/selectors/labelsel/suite_test.go @@ -0,0 +1,13 @@ +package labelsel_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "label selectorTest Suite") +} diff --git a/pkg/contexts/ocm/selectors/refsel/element.go b/pkg/contexts/ocm/selectors/refsel/element.go new file mode 100644 index 000000000..1aa996474 --- /dev/null +++ b/pkg/contexts/ocm/selectors/refsel/element.go @@ -0,0 +1,35 @@ +package refsel + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/labelsel" +) + +// Identity selectors + +func IdentityByKeyPairs(extras ...string) Selector { + return selectors.IdentityByKeyPairs(extras...) +} + +func Identity(id v1.Identity) Selector { + return selectors.Identity(id) +} + +func Name(n string) Selector { + return selectors.Name(n) +} + +func Version(n string) Selector { + return selectors.Version(n) +} + +// Label selectors + +func Label(sel ...selectors.LabelSelector) Selector { + return selectors.Label(sel...) +} + +func LabelName(n string) Selector { + return labelsel.Name(n) +} diff --git a/pkg/contexts/ocm/selectors/refsel/interface.go b/pkg/contexts/ocm/selectors/refsel/interface.go new file mode 100644 index 000000000..872222c5f --- /dev/null +++ b/pkg/contexts/ocm/selectors/refsel/interface.go @@ -0,0 +1,59 @@ +package refsel + +import ( + "regexp" + + "github.com/gobwas/glob" + + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +type ( + Selector = selectors.ReferenceSelector + SelectorFunc = selectors.ReferenceSelectorFunc +) + +//////////////////////////////////////////////////////////////////////////////// + +type Component string + +func (c Component) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + return string(c) == ref.GetComponentName() +} + +//////////////////////////////////////////////////////////////////////////////// + +type compGlob struct { + glob.Glob +} + +func (c *compGlob) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + if c.Glob == nil { + return false + } + return c.Glob.Match(ref.GetComponentName()) +} + +func ComponentGlob(g string) Selector { + c, err := glob.Compile(g, '/') + return selectors.NewReferenceErrorSelectorImpl(&compGlob{c}, err) +} + +//////////////////////////////////////////////////////////////////////////////// + +type compRegEx struct { + *regexp.Regexp +} + +func (c *compRegEx) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + if c.Regexp == nil { + return false + } + return c.Regexp.MatchString(ref.GetComponentName()) +} + +func ComponentRegex(g string) selectors.ReferenceSelector { + c, err := regexp.Compile(g) + return selectors.NewReferenceErrorSelectorImpl(&compRegEx{c}, err) +} diff --git a/pkg/contexts/ocm/selectors/refsel/operators.go b/pkg/contexts/ocm/selectors/refsel/operators.go new file mode 100644 index 000000000..08ce91320 --- /dev/null +++ b/pkg/contexts/ocm/selectors/refsel/operators.go @@ -0,0 +1,72 @@ +package refsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +var ( + _ selectors.ErrorProvider = (and)(nil) + _ selectors.ErrorProvider = (or)(nil) + _ selectors.ErrorProvider = (*not)(nil) +) + +//////////////////////////////////////////////////////////////////////////////// + +type and []Selector + +func (a and) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + for _, o := range a { + if !o.MatchReference(list, ref) { + return false + } + } + return true +} + +func (a and) GetError() error { + return selectors.ValidateSubSelectors("and", []Selector(a)...) +} + +func And(operands ...Selector) Selector { + return and(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type or []Selector + +func (a or) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + for _, o := range a { + if o.MatchReference(list, ref) { + return true + } + } + return false +} + +func (a or) GetError() error { + return selectors.ValidateSubSelectors("or", []Selector(a)...) +} + +func Or(operands ...Selector) Selector { + return or(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type not struct { + Selector +} + +func (a *not) MatchReference(list accessors.ElementListAccessor, ref accessors.ReferenceAccessor) bool { + return !a.Selector.MatchReference(list, ref) +} + +func (a *not) GetError() error { + return selectors.ValidateSubSelectors("not", a.Selector) +} + +func Not(operand Selector) Selector { + return ¬{operand} +} diff --git a/pkg/contexts/ocm/selectors/rscsel/artifact.go b/pkg/contexts/ocm/selectors/rscsel/artifact.go new file mode 100644 index 000000000..68107f4ea --- /dev/null +++ b/pkg/contexts/ocm/selectors/rscsel/artifact.go @@ -0,0 +1,15 @@ +package rscsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" +) + +// Artifact selectors + +func ArtifactType(n string) Selector { + return selectors.ArtifactType(n) +} + +func AccessKind(n string) Selector { + return selectors.AccessKind(n) +} diff --git a/pkg/contexts/ocm/selectors/rscsel/element.go b/pkg/contexts/ocm/selectors/rscsel/element.go new file mode 100644 index 000000000..b2383ced8 --- /dev/null +++ b/pkg/contexts/ocm/selectors/rscsel/element.go @@ -0,0 +1,39 @@ +package rscsel + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/labelsel" +) + +// Identity selectors + +func IdentityByKeyPairs(extras ...string) Selector { + return selectors.IdentityByKeyPairs(extras...) +} + +func Identity(id v1.Identity) Selector { + return selectors.Identity(id) +} + +func Name(n string) Selector { + return selectors.Name(n) +} + +func Version(n string) Selector { + return selectors.Version(n) +} + +func VersionConstraint(expr string) Selector { + return selectors.VersionConstraint(expr) +} + +// Label selectors + +func Label(sel ...selectors.LabelSelector) Selector { + return selectors.Label(sel...) +} + +func LabelName(n string) Selector { + return labelsel.Name(n) +} diff --git a/pkg/contexts/ocm/selectors/rscsel/interface.go b/pkg/contexts/ocm/selectors/rscsel/interface.go new file mode 100644 index 000000000..c783de7d1 --- /dev/null +++ b/pkg/contexts/ocm/selectors/rscsel/interface.go @@ -0,0 +1,40 @@ +package rscsel + +import ( + "runtime" + + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/extraid" + "github.com/open-component-model/ocm/pkg/contexts/ocm/resourcetypes" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +type ( + Selector = selectors.ResourceSelector + SelectorFunc = selectors.ResourceSelectorFunc +) + +//////////////////////////////////////////////////////////////////////////////// + +type Relation v1.ResourceRelation + +func (r Relation) MatchResource(list accessors.ElementListAccessor, res accessors.ResourceAccessor) bool { + return v1.ResourceRelation(r) == res.GetRelation() +} + +var ( + Local = Relation(v1.LocalRelation) + External = Relation(v1.ExternalRelation) +) + +//////////////////////////////////////////////////////////////////////////////// + +func Executable(name string) Selector { + return SelectorFunc(func(list accessors.ElementListAccessor, a accessors.ResourceAccessor) bool { + extra := a.GetMeta().GetExtraIdentity() + return a.GetMeta().GetName() == name && a.GetType() == resourcetypes.EXECUTABLE && extra != nil && + extra[extraid.ExecutableOperatingSystem] == runtime.GOOS && + extra[extraid.ExecutableArchitecture] == runtime.GOARCH + }) +} diff --git a/pkg/contexts/ocm/selectors/rscsel/operators.go b/pkg/contexts/ocm/selectors/rscsel/operators.go new file mode 100644 index 000000000..c69120170 --- /dev/null +++ b/pkg/contexts/ocm/selectors/rscsel/operators.go @@ -0,0 +1,72 @@ +package rscsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +var ( + _ selectors.ErrorProvider = (and)(nil) + _ selectors.ErrorProvider = (or)(nil) + _ selectors.ErrorProvider = (*not)(nil) +) + +//////////////////////////////////////////////////////////////////////////////// + +type and []Selector + +func (a and) MatchResource(list accessors.ElementListAccessor, e accessors.ResourceAccessor) bool { + for _, o := range a { + if !o.MatchResource(list, e) { + return false + } + } + return true +} + +func (a and) GetError() error { + return selectors.ValidateSubSelectors("and", []Selector(a)...) +} + +func And(operands ...Selector) Selector { + return and(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type or []Selector + +func (a or) MatchResource(list accessors.ElementListAccessor, e accessors.ResourceAccessor) bool { + for _, o := range a { + if o.MatchResource(list, e) { + return true + } + } + return false +} + +func (a or) GetError() error { + return selectors.ValidateSubSelectors("or", []Selector(a)...) +} + +func Or(operands ...Selector) Selector { + return or(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type not struct { + Selector +} + +func (a *not) MatchResource(list accessors.ElementListAccessor, e accessors.ResourceAccessor) bool { + return !a.Selector.MatchResource(list, e) +} + +func (a *not) GetError() error { + return selectors.ValidateSubSelectors("not", a.Selector) +} + +func Not(operand Selector) Selector { + return ¬{operand} +} diff --git a/pkg/contexts/ocm/selectors/select.go b/pkg/contexts/ocm/selectors/select.go new file mode 100644 index 000000000..352530d1e --- /dev/null +++ b/pkg/contexts/ocm/selectors/select.go @@ -0,0 +1,170 @@ +package selectors + +import ( + "github.com/mandelsoft/goutils/errors" + "github.com/mandelsoft/goutils/generics" + + metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +// ErrorProvider is an optional interface a Selector can offer +// to propagate an error determined setting up the selector. +// Such an error cannot be returned directly by the function +// creating the selector, because this would prohibit to +// compose selector sets as variadic arguments. +type ErrorProvider interface { + GetError() error +} + +type ErrorSelectorBase struct { + err error +} + +func NewErrorSelectorBase(err error) ErrorSelectorBase { + return ErrorSelectorBase{err} +} + +func (s *ErrorSelectorBase) GetError() error { + return s.err +} + +//////////////////////////////////////////////////////////////////////////////// + +type ResourceSelector interface { + MatchResource(accessors.ElementListAccessor, accessors.ResourceAccessor) bool +} + +type ResourceSelectorFunc func(accessors.ElementListAccessor, accessors.ResourceAccessor) bool + +func (f ResourceSelectorFunc) MatchResource(list accessors.ElementListAccessor, a accessors.ResourceAccessor) bool { + return f(list, a) +} + +type ResourceErrorSelectorImpl struct { + ErrorSelectorBase + ResourceSelector +} + +func NewResourceErrorSelectorImpl(s ResourceSelector, err error) *ResourceErrorSelectorImpl { + return &ResourceErrorSelectorImpl{NewErrorSelectorBase(err), s} +} + +//////////////////////////////////////////////////////////////////////////////// + +type SourceSelector interface { + MatchSource(accessors.ElementListAccessor, accessors.SourceAccessor) bool +} + +type SourceSelectorFunc func(accessors.ElementListAccessor, accessors.SourceAccessor) bool + +func (f SourceSelectorFunc) MatchSource(list accessors.ElementListAccessor, a accessors.SourceAccessor) bool { + return f(list, a) +} + +type SourceErrorSelectorImpl struct { + ErrorSelectorBase + SourceSelector +} + +func NewSourceErrorSelectorImpl(s SourceSelector, err error) *SourceErrorSelectorImpl { + return &SourceErrorSelectorImpl{NewErrorSelectorBase(err), s} +} + +//////////////////////////////////////////////////////////////////////////////// + +type ReferenceSelector interface { + MatchReference(accessors.ElementListAccessor, accessors.ReferenceAccessor) bool +} + +type ReferenceSelectorFunc func(accessors.ElementListAccessor, accessors.ReferenceAccessor) bool + +func (f ReferenceSelectorFunc) MatchReference(list accessors.ElementListAccessor, a accessors.ReferenceAccessor) bool { + return f(list, a) +} + +type ReferenceErrorSelectorImpl struct { + ErrorSelectorBase + ReferenceSelector +} + +func NewReferenceErrorSelectorImpl(s ReferenceSelector, err error) *ReferenceErrorSelectorImpl { + return &ReferenceErrorSelectorImpl{NewErrorSelectorBase(err), s} +} + +//////////////////////////////////////////////////////////////////////////////// + +type LabelSelector interface { + MatchLabel(label *metav1.Label) bool +} + +type LabelSelectorFunc func(label *metav1.Label) bool + +func (f LabelSelectorFunc) MatchLabel(l *metav1.Label) bool { + return f(l) +} + +//////////////////////////////////////////////////////////////////////////////// + +func ValidateSelectors[T any](sel ...T) error { + list := errors.ErrListf("error in selector list") + return validateSelectors(list, sel...) +} + +func ValidateSubSelectors[T any](msg string, sel ...T) error { + list := errors.ErrList(msg) + return validateSelectors(list, sel...) +} + +func validateSelectors[T any](list *errors.ErrorList, sel ...T) error { + for _, s := range sel { + if p, ok := generics.TryCast[ErrorProvider](s); ok { + list.Add(p.GetError()) + } + } + return list.Result() +} + +//////////////////////////////////////////////////////////////////////////////// + +func _select[S, E any](list accessors.ElementListAccessor, m func(S, E) bool, sel ...S) []E { + var result []E + for i := 0; i < list.Len(); i++ { + e := list.Get(i).(E) + for _, s := range sel { + if !m(s, e) { + continue + } + } + result = append(result, e) + } + return result +} + +// SelectResources select resources by a set of selectors. +// It requires to be called with a compdesc.Resources list. +func SelectResources(list accessors.ElementListAccessor, sel ...ResourceSelector) []accessors.ResourceAccessor { + return _select(list, + func(s ResourceSelector, e accessors.ResourceAccessor) bool { + return s.MatchResource(list, e) + }, + sel...) +} + +// SelectSources select sources by a set of selectors. +// It requires to be called with a compdesc.Sources list. +func SelectSources(list accessors.ElementListAccessor, sel ...SourceSelector) []accessors.SourceAccessor { + return _select(list, + func(s SourceSelector, e accessors.SourceAccessor) bool { + return s.MatchSource(list, e) + }, sel...) +} + +// SelectReferences select resources by a set of selectors. +// It requires to be called with a compdesc.References list. +func SelectReferences(list accessors.ElementListAccessor, sel ...ReferenceSelector) []accessors.ReferenceAccessor { + return _select(list, + func(s ReferenceSelector, e accessors.ReferenceAccessor) bool { + return s.MatchReference(list, e) + }, sel...) +} diff --git a/pkg/contexts/ocm/selectors/srcsel/artifact.go b/pkg/contexts/ocm/selectors/srcsel/artifact.go new file mode 100644 index 000000000..ebb2d7023 --- /dev/null +++ b/pkg/contexts/ocm/selectors/srcsel/artifact.go @@ -0,0 +1,15 @@ +package srcsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" +) + +// Artifact selectors + +func ArtifactType(n string) Selector { + return selectors.ArtifactType(n) +} + +func AccessKind(n string) Selector { + return selectors.AccessKind(n) +} diff --git a/pkg/contexts/ocm/selectors/srcsel/element.go b/pkg/contexts/ocm/selectors/srcsel/element.go new file mode 100644 index 000000000..e0e26a799 --- /dev/null +++ b/pkg/contexts/ocm/selectors/srcsel/element.go @@ -0,0 +1,39 @@ +package srcsel + +import ( + v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/labelsel" +) + +// Identity selectors + +func IdentityByKeyPairs(extras ...string) Selector { + return selectors.IdentityByKeyPairs(extras...) +} + +func Identity(id v1.Identity) Selector { + return selectors.Identity(id) +} + +func Name(n string) Selector { + return selectors.Name(n) +} + +func Version(n string) Selector { + return selectors.Version(n) +} + +func VersionConstraint(expr string) Selector { + return selectors.VersionConstraint(expr) +} + +// Label selectors + +func Label(sel ...selectors.LabelSelector) Selector { + return selectors.Label(sel...) +} + +func LabelName(n string) Selector { + return labelsel.Name(n) +} diff --git a/pkg/contexts/ocm/selectors/srcsel/interface.go b/pkg/contexts/ocm/selectors/srcsel/interface.go new file mode 100644 index 000000000..063d72383 --- /dev/null +++ b/pkg/contexts/ocm/selectors/srcsel/interface.go @@ -0,0 +1,10 @@ +package srcsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" +) + +type ( + Selector = selectors.SourceSelector + SelectorFunc = selectors.SourceSelectorFunc +) diff --git a/pkg/contexts/ocm/selectors/srcsel/operators.go b/pkg/contexts/ocm/selectors/srcsel/operators.go new file mode 100644 index 000000000..5adc21390 --- /dev/null +++ b/pkg/contexts/ocm/selectors/srcsel/operators.go @@ -0,0 +1,72 @@ +package srcsel + +import ( + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors" + "github.com/open-component-model/ocm/pkg/contexts/ocm/selectors/accessors" +) + +var ( + _ selectors.ErrorProvider = (and)(nil) + _ selectors.ErrorProvider = (or)(nil) + _ selectors.ErrorProvider = (*not)(nil) +) + +//////////////////////////////////////////////////////////////////////////////// + +type and []Selector + +func (a and) MatchSource(list accessors.ElementListAccessor, e accessors.SourceAccessor) bool { + for _, o := range a { + if !o.MatchSource(list, e) { + return false + } + } + return true +} + +func (a and) GetError() error { + return selectors.ValidateSubSelectors("and", []Selector(a)...) +} + +func And(operands ...Selector) Selector { + return and(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type or []Selector + +func (a or) MatchSource(list accessors.ElementListAccessor, e accessors.SourceAccessor) bool { + for _, o := range a { + if o.MatchSource(list, e) { + return true + } + } + return false +} + +func (a or) GetError() error { + return selectors.ValidateSubSelectors("or", []Selector(a)...) +} + +func Or(operands ...Selector) Selector { + return or(operands) +} + +//////////////////////////////////////////////////////////////////////////////// + +type not struct { + Selector +} + +func (a *not) MatchReference(list accessors.ElementListAccessor, e accessors.SourceAccessor) bool { + return !a.Selector.MatchSource(list, e) +} + +func (a *not) GetError() error { + return selectors.ValidateSubSelectors("not", a.Selector) +} + +func Not(operand Selector) Selector { + return ¬{operand} +}