Skip to content

Commit

Permalink
inputs+artifact adder+hint check
Browse files Browse the repository at this point in the history
  • Loading branch information
mandelsoft committed Dec 27, 2024
1 parent 3c358b7 commit 269f248
Show file tree
Hide file tree
Showing 27 changed files with 352 additions and 69 deletions.
2 changes: 2 additions & 0 deletions api/ocm/compdesc/componentdescriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ type ReferenceHintProvider interface {
type ReferenceHintSink interface {
// SetReferenceHints sets the reference hints specified together with the metadata.
SetReferenceHints([]refhints.ReferenceHint)
// AddReferenceHints adds additional hints if their type is not yet available.
AddReferenceHints(hints ...refhints.ReferenceHint)
}

// ArtifactMetaPointer is a pointer to an artifact meta object.
Expand Down
4 changes: 2 additions & 2 deletions api/ocm/compdesc/versions/v2/componentdescriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ type SourceMeta struct {
Type string `json:"type"`
// ReferenceHints describe several types hints used by uploaders
// to decide on used element identities.
ReferenceHints []refhints.DefaultReferenceHint `json:"referenceHints,omitempty"`
ReferenceHints refhints.DefaultReferenceHints `json:"referenceHints,omitempty"`
}

// GetType returns the type of the object.
Expand Down Expand Up @@ -292,7 +292,7 @@ type Resource struct {

// ReferenceHints describe several types hints used by uploaders
// to decide on used element identities.
ReferenceHints []refhints.DefaultReferenceHint `json:"referenceHints,omitempty"`
ReferenceHints refhints.DefaultReferenceHints `json:"referenceHints,omitempty"`

// Relation describes the relation of the resource to the component.
// Can be a local or external resource
Expand Down
4 changes: 2 additions & 2 deletions api/ocm/cpi/repocpi/view_cv.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func (c *componentVersionAccessView) SetResourceBlob(meta *cpi.ResourceMeta, blo
return err
}
eff := cpi.NewBlobModificationOptions(opts...)
hints = refhints.Join(meta.ReferenceHints, refhints.FilterImplicit(hints))
hints = refhints.JoinUnique(meta.ReferenceHints, refhints.FilterImplicit(hints))
acc, err := c.AddBlob(blob, meta.Type, hints, global, eff)
if err != nil {
return fmt.Errorf("unable to add blob (component %s:%s resource %s): %w", c.GetName(), c.GetVersion(), meta.GetName(), err)
Expand All @@ -271,7 +271,7 @@ func (c *componentVersionAccessView) SetSourceBlob(meta *cpi.SourceMeta, blob cp
if err := utils.ValidateObject(blob); err != nil {
return err
}
hints = refhints.Join(meta.ReferenceHints, refhints.FilterImplicit(hints))
hints = refhints.JoinUnique(meta.ReferenceHints, refhints.FilterImplicit(hints))
acc, err := c.AddBlob(blob, meta.Type, hints, global)
if err != nil {
return fmt.Errorf("unable to add blob: (component %s:%s source %s): %w", c.GetName(), c.GetVersion(), meta.GetName(), err)
Expand Down
122 changes: 109 additions & 13 deletions api/ocm/refhints/hints.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package refhints

import (
"encoding/json"
"maps"
"slices"
"strings"
Expand Down Expand Up @@ -35,12 +36,6 @@ const (
IMPLICIT_TRUE = "true"
)

func MatchType(typs ...string) matcher.Matcher[ReferenceHint] {
return func(h ReferenceHint) bool {
return slices.Contains(typs, h.GetType())
}
}

// ReferenceHints is list of hints.
// Notaion: a sequence of hint notations separated by a ;.
type ReferenceHints []ReferenceHint
Expand All @@ -50,7 +45,7 @@ func NewHints(f func(ref string, implicit ...bool) ReferenceHint, ref string, im
}

func (h *ReferenceHints) Add(hints ...ReferenceHint) {
*h = sliceutils.AppendUniqueFunc(*h, runtime.MatchType[ReferenceHint], hints...)
AddUnique(h, hints...)
}

func (h ReferenceHints) Copy() ReferenceHints {
Expand All @@ -75,7 +70,7 @@ func (h ReferenceHints) GetReferenceHint(typs ...string) ReferenceHint {
if len(typs) == 0 {
return nil
}
hints := sliceutils.Filter(h, MatchType(typs...))
hints := Filter(h, MatchType(typs...))
if len(hints) == 0 {
return nil
}
Expand Down Expand Up @@ -128,18 +123,55 @@ type ReferenceHint interface {
AsDefault() DefaultReferenceHint
}

func IsImplicitHint(h ReferenceHint) bool {
func MatchType(typs ...string) matcher.Matcher[ReferenceHint] {
return func(h ReferenceHint) bool {
return slices.Contains(typs, h.GetType())
}
}

func Equal(o ReferenceHint) matcher.Matcher[ReferenceHint] {
d := o.Serialize()
return func(h ReferenceHint) bool {
return h.Serialize() == d
}
}

func IsImplicit(h ReferenceHint) bool {
if h == nil {
return false
}
return h.GetProperty(HINT_IMPLICIT) == IMPLICIT_TRUE
}

func FilterImplicit(hints []ReferenceHint) ReferenceHints {
func IsExplicit(h ReferenceHint) bool {
if h == nil {
return false
}
return !IsImplicit(h)
}

func Filter(hints []ReferenceHint, cond matcher.Matcher[ReferenceHint]) ReferenceHints {
if len(hints) == 0 {
return nil
}
return sliceutils.Filter(hints, IsImplicitHint)
return sliceutils.Filter(hints, cond)
}

func FilterImplicit(hints []ReferenceHint) ReferenceHints {
return Filter(hints, IsImplicit)
}

func AsImplicit[S ~[]T, T ReferenceHint](hints S) DefaultReferenceHints {
var result DefaultReferenceHints

for _, h := range hints {
if IsImplicit(h) {
result.Add(h)
} else {
result.Add(h.AsDefault().SetProperty(HINT_IMPLICIT, IMPLICIT_TRUE))
}
}
return result
}

// GetReference returns the default reference hint attribute
Expand Down Expand Up @@ -245,6 +277,57 @@ func (h DefaultReferenceHint) Serialize(implicit ...bool) string {
return s
}

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

type DefaultReferenceHints []DefaultReferenceHint

func (h *DefaultReferenceHints) Add(hints ...ReferenceHint) {
AddUnique(h, sliceutils.Transform(hints, AsDefault)...)
}

func (h DefaultReferenceHints) Copy() ReferenceHints {
var result ReferenceHints

for _, v := range h {
result = append(result, v.Copy())
}
return result
}

// Serialize provides a string representation. The implicit
// attribute is only serialized, if it is called with true.
func (h DefaultReferenceHints) Serialize(implicit ...bool) string {
return HintsToString(sliceutils.Convert[ReferenceHint](h), implicit...)
}

var _ json.Marshaler = DefaultReferenceHints{}

func (h DefaultReferenceHints) MarshalJSON() ([]byte, error) {
return json.Marshal(([]DefaultReferenceHint)(h))
}

var _ json.Unmarshaler = &DefaultReferenceHints{}

// UnmarshalJSON excepts the serialized form or the list form.
func (h *DefaultReferenceHints) UnmarshalJSON(data []byte) error {
var in []DefaultReferenceHint

err := json.Unmarshal(data, &in)
if err == nil {
*h = DefaultReferenceHints(in)
return nil
}
var s string
err = json.Unmarshal(data, &s)
if err != nil {
return err
}
*h = sliceutils.Transform(ParseHints(s), AsDefault)
return nil
}

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

func escapeHintValue(v string) string {
if !strings.ContainsAny(v, "\",;") {
return v
Expand Down Expand Up @@ -413,10 +496,23 @@ func ParseHints(v string, implicit ...bool) ReferenceHints {
return hints
}

func Join(hints ...[]ReferenceHint) ReferenceHints {
// JoinUnique joins multiple hint lists, where the first occurrence of a
// hint type takes precedence.
func JoinUnique(hints ...[]ReferenceHint) ReferenceHints {
var result []ReferenceHint
for _, h := range hints {
result = sliceutils.AppendUniqueFunc(result, runtime.MatchType[ReferenceHint], h...)
AddUnique(&result, h...)
}
return result
}

// AddUnique adds hints to hint list, whode type is not yet present in the list.
func AddUnique[S ~[]T, T ReferenceHint](hints *S, add ...T) {
*hints = sliceutils.AppendUniqueFunc(*hints, runtime.MatchType[T], add...)
}

// AsDefault transforms a generic hint into a default hint.
// It can be used by sliceutils.Transform.
func AsDefault(h ReferenceHint) DefaultReferenceHint {
return h.AsDefault()
}
31 changes: 31 additions & 0 deletions api/ocm/refhints/hints_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package refhints_test

import (
"encoding/json"
"strings"

. "github.com/mandelsoft/goutils/testutils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand Down Expand Up @@ -133,6 +135,35 @@ var _ = Describe("Hints Test Environment", func() {
CheckHintImplicit("typ", "test", "typ::implicit=true,reference=test")
})
})

Context("marshal unmarshal", func() {
It("works", func() {
var hints refhints.DefaultReferenceHints

hints.Add(refhints.New("test", "label"))

data := Must(json.Marshal(hints))
Expect(string(data)).To(Equal(`[{"reference":"label","type":"test"}]`))

var result refhints.DefaultReferenceHints

MustBeSuccessful(json.Unmarshal(data, &result))
Expect(result).To(DeepEqual(hints))
})

It("unmarshalls string", func() {
var hints refhints.DefaultReferenceHints

hints.Add(refhints.New("test", "label"))

data := hints.Serialize()

var result refhints.DefaultReferenceHints

MustBeSuccessful(json.Unmarshal([]byte(`"`+data+`"`), &result))
Expect(result).To(DeepEqual(hints))
})
})
})

func CheckHint(s string, h ...refhints.ReferenceHint) {
Expand Down
9 changes: 9 additions & 0 deletions cmds/ocm/commands/ocmcmds/common/addhdlrs/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/mandelsoft/goutils/sliceutils"

clictx "ocm.software/ocm/api/cli"
"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
"ocm.software/ocm/api/ocm/cpi"
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs"
Expand Down Expand Up @@ -106,6 +107,14 @@ type ElementSpec interface {
Validate(ctx clictx.Context, input *ResourceInput) error
}

// ArtifactElementSpec is the interface for elements
// representing artifacts (like Resources a d Source).
type ArtifactElementSpec interface {
ElementSpec
compdesc.ReferenceHintSink
compdesc.ReferenceHintProvider
}

// Element is the abstraction over model elements handled by
// the add handler, for example, resources, sources, references or complete
// component versions.
Expand Down
34 changes: 27 additions & 7 deletions cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"fmt"

"github.com/mandelsoft/goutils/errors"
"github.com/mandelsoft/goutils/sliceutils"
"k8s.io/apimachinery/pkg/util/validation/field"

clictx "ocm.software/ocm/api/cli"
"ocm.software/ocm/api/ocm"
"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
compdescv2 "ocm.software/ocm/api/ocm/compdesc/versions/v2"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/utils/runtime"
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common"
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/addhdlrs"
Expand Down Expand Up @@ -97,9 +99,10 @@ func (h *ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Eleme
ExtraIdentity: spec.ExtraIdentity,
Labels: spec.Labels,
},
Type: spec.Type,
Relation: spec.Relation,
SourceRefs: compdescv2.ConvertSourcerefsTo(spec.SourceRefs),
Type: spec.Type,
Relation: spec.Relation,
SourceRefs: compdescv2.ConvertSourcerefsTo(spec.SourceRefs),
ReferenceHints: spec.GetReferenceHints(),
}
opts := h.getModOpts()
if spec.Options.SkipDigestGeneration {
Expand Down Expand Up @@ -130,13 +133,17 @@ type ResourceSpec struct {
// component.sources.
SourceRefs []compdescv2.SourceRef `json:"srcRefs"`

ReferenceHints refhints.DefaultReferenceHints `json:"referenceHints,omitempty"`

addhdlrs.ResourceInput `json:",inline"`

// Options describes additional process related options
// see ResourceOptions for more details.
Options ResourceOptions `json:"options,omitempty"`
}

var _ addhdlrs.ArtifactElementSpec = (*ResourceSpec)(nil)

// ResourceOptions describes additional process related options
// which reflect the handling of the resource without describing it directly.
// Typical examples are any options that require specific changes in handling of the resource
Expand Down Expand Up @@ -176,13 +183,26 @@ func (r *ResourceSpec) Validate(ctx clictx.Context, input *addhdlrs.ResourceInpu
r.Version = ComponentVersionTag
}
rsc := compdescv2.Resource{
ElementMeta: r.ElementMeta,
Type: r.Type,
Relation: r.Relation,
SourceRefs: r.SourceRefs,
ElementMeta: r.ElementMeta,
Type: r.Type,
Relation: r.Relation,
SourceRefs: r.SourceRefs,
ReferenceHints: r.ReferenceHints,
}
if err := compdescv2.ValidateResource(fldPath, rsc, false); err != nil {
allErrs = append(allErrs, err...)
}
return allErrs.ToAggregate()
}

func (r *ResourceSpec) GetReferenceHints() refhints.ReferenceHints {
return refhints.ReferenceHints(sliceutils.Convert[refhints.ReferenceHint](r.ReferenceHints))
}

func (r *ResourceSpec) SetReferenceHints(hints []refhints.ReferenceHint) {
r.ReferenceHints = sliceutils.Transform(hints, refhints.AsDefault)
}

func (r *ResourceSpec) AddReferenceHints(hints ...refhints.ReferenceHint) {
refhints.AddUnique(&r.ReferenceHints, sliceutils.Transform(hints, refhints.AsDefault)...)
}
Loading

0 comments on commit 269f248

Please sign in to comment.