Skip to content

Commit dcfa333

Browse files
committed
inputs+artifact adder+hint check
1 parent 9b45901 commit dcfa333

File tree

27 files changed

+352
-69
lines changed

27 files changed

+352
-69
lines changed

api/ocm/compdesc/componentdescriptor.go

+2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ type ReferenceHintProvider interface {
149149
type ReferenceHintSink interface {
150150
// SetReferenceHints sets the reference hints specified together with the metadata.
151151
SetReferenceHints([]refhints.ReferenceHint)
152+
// AddReferenceHints adds additional hints if their type is not yet available.
153+
AddReferenceHints(hints ...refhints.ReferenceHint)
152154
}
153155

154156
// ArtifactMetaPointer is a pointer to an artifact meta object.

api/ocm/compdesc/versions/v2/componentdescriptor.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ type SourceMeta struct {
245245
Type string `json:"type"`
246246
// ReferenceHints describe several types hints used by uploaders
247247
// to decide on used element identities.
248-
ReferenceHints []refhints.DefaultReferenceHint `json:"referenceHints,omitempty"`
248+
ReferenceHints refhints.DefaultReferenceHints `json:"referenceHints,omitempty"`
249249
}
250250

251251
// GetType returns the type of the object.
@@ -292,7 +292,7 @@ type Resource struct {
292292

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

297297
// Relation describes the relation of the resource to the component.
298298
// Can be a local or external resource

api/ocm/cpi/repocpi/view_cv.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func (c *componentVersionAccessView) SetResourceBlob(meta *cpi.ResourceMeta, blo
245245
return err
246246
}
247247
eff := cpi.NewBlobModificationOptions(opts...)
248-
hints = refhints.Join(meta.ReferenceHints, refhints.FilterImplicit(hints))
248+
hints = refhints.JoinUnique(meta.ReferenceHints, refhints.FilterImplicit(hints))
249249
acc, err := c.AddBlob(blob, meta.Type, hints, global, eff)
250250
if err != nil {
251251
return fmt.Errorf("unable to add blob (component %s:%s resource %s): %w", c.GetName(), c.GetVersion(), meta.GetName(), err)
@@ -271,7 +271,7 @@ func (c *componentVersionAccessView) SetSourceBlob(meta *cpi.SourceMeta, blob cp
271271
if err := utils.ValidateObject(blob); err != nil {
272272
return err
273273
}
274-
hints = refhints.Join(meta.ReferenceHints, refhints.FilterImplicit(hints))
274+
hints = refhints.JoinUnique(meta.ReferenceHints, refhints.FilterImplicit(hints))
275275
acc, err := c.AddBlob(blob, meta.Type, hints, global)
276276
if err != nil {
277277
return fmt.Errorf("unable to add blob: (component %s:%s source %s): %w", c.GetName(), c.GetVersion(), meta.GetName(), err)

api/ocm/refhints/hints.go

+109-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package refhints
22

33
import (
4+
"encoding/json"
45
"maps"
56
"slices"
67
"strings"
@@ -35,12 +36,6 @@ const (
3536
IMPLICIT_TRUE = "true"
3637
)
3738

38-
func MatchType(typs ...string) matcher.Matcher[ReferenceHint] {
39-
return func(h ReferenceHint) bool {
40-
return slices.Contains(typs, h.GetType())
41-
}
42-
}
43-
4439
// ReferenceHints is list of hints.
4540
// Notaion: a sequence of hint notations separated by a ;.
4641
type ReferenceHints []ReferenceHint
@@ -50,7 +45,7 @@ func NewHints(f func(ref string, implicit ...bool) ReferenceHint, ref string, im
5045
}
5146

5247
func (h *ReferenceHints) Add(hints ...ReferenceHint) {
53-
*h = sliceutils.AppendUniqueFunc(*h, runtime.MatchType[ReferenceHint], hints...)
48+
AddUnique(h, hints...)
5449
}
5550

5651
func (h ReferenceHints) Copy() ReferenceHints {
@@ -75,7 +70,7 @@ func (h ReferenceHints) GetReferenceHint(typs ...string) ReferenceHint {
7570
if len(typs) == 0 {
7671
return nil
7772
}
78-
hints := sliceutils.Filter(h, MatchType(typs...))
73+
hints := Filter(h, MatchType(typs...))
7974
if len(hints) == 0 {
8075
return nil
8176
}
@@ -128,18 +123,55 @@ type ReferenceHint interface {
128123
AsDefault() DefaultReferenceHint
129124
}
130125

131-
func IsImplicitHint(h ReferenceHint) bool {
126+
func MatchType(typs ...string) matcher.Matcher[ReferenceHint] {
127+
return func(h ReferenceHint) bool {
128+
return slices.Contains(typs, h.GetType())
129+
}
130+
}
131+
132+
func Equal(o ReferenceHint) matcher.Matcher[ReferenceHint] {
133+
d := o.Serialize()
134+
return func(h ReferenceHint) bool {
135+
return h.Serialize() == d
136+
}
137+
}
138+
139+
func IsImplicit(h ReferenceHint) bool {
132140
if h == nil {
133141
return false
134142
}
135143
return h.GetProperty(HINT_IMPLICIT) == IMPLICIT_TRUE
136144
}
137145

138-
func FilterImplicit(hints []ReferenceHint) ReferenceHints {
146+
func IsExplicit(h ReferenceHint) bool {
147+
if h == nil {
148+
return false
149+
}
150+
return !IsImplicit(h)
151+
}
152+
153+
func Filter(hints []ReferenceHint, cond matcher.Matcher[ReferenceHint]) ReferenceHints {
139154
if len(hints) == 0 {
140155
return nil
141156
}
142-
return sliceutils.Filter(hints, IsImplicitHint)
157+
return sliceutils.Filter(hints, cond)
158+
}
159+
160+
func FilterImplicit(hints []ReferenceHint) ReferenceHints {
161+
return Filter(hints, IsImplicit)
162+
}
163+
164+
func AsImplicit[S ~[]T, T ReferenceHint](hints S) DefaultReferenceHints {
165+
var result DefaultReferenceHints
166+
167+
for _, h := range hints {
168+
if IsImplicit(h) {
169+
result.Add(h)
170+
} else {
171+
result.Add(h.AsDefault().SetProperty(HINT_IMPLICIT, IMPLICIT_TRUE))
172+
}
173+
}
174+
return result
143175
}
144176

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

280+
////////////////////////////////////////////////////////////////////////////////
281+
282+
type DefaultReferenceHints []DefaultReferenceHint
283+
284+
func (h *DefaultReferenceHints) Add(hints ...ReferenceHint) {
285+
AddUnique(h, sliceutils.Transform(hints, AsDefault)...)
286+
}
287+
288+
func (h DefaultReferenceHints) Copy() ReferenceHints {
289+
var result ReferenceHints
290+
291+
for _, v := range h {
292+
result = append(result, v.Copy())
293+
}
294+
return result
295+
}
296+
297+
// Serialize provides a string representation. The implicit
298+
// attribute is only serialized, if it is called with true.
299+
func (h DefaultReferenceHints) Serialize(implicit ...bool) string {
300+
return HintsToString(sliceutils.Convert[ReferenceHint](h), implicit...)
301+
}
302+
303+
var _ json.Marshaler = DefaultReferenceHints{}
304+
305+
func (h DefaultReferenceHints) MarshalJSON() ([]byte, error) {
306+
return json.Marshal(([]DefaultReferenceHint)(h))
307+
}
308+
309+
var _ json.Unmarshaler = &DefaultReferenceHints{}
310+
311+
// UnmarshalJSON excepts the serialized form or the list form.
312+
func (h *DefaultReferenceHints) UnmarshalJSON(data []byte) error {
313+
var in []DefaultReferenceHint
314+
315+
err := json.Unmarshal(data, &in)
316+
if err == nil {
317+
*h = DefaultReferenceHints(in)
318+
return nil
319+
}
320+
var s string
321+
err = json.Unmarshal(data, &s)
322+
if err != nil {
323+
return err
324+
}
325+
*h = sliceutils.Transform(ParseHints(s), AsDefault)
326+
return nil
327+
}
328+
329+
////////////////////////////////////////////////////////////////////////////////
330+
248331
func escapeHintValue(v string) string {
249332
if !strings.ContainsAny(v, "\",;") {
250333
return v
@@ -413,10 +496,23 @@ func ParseHints(v string, implicit ...bool) ReferenceHints {
413496
return hints
414497
}
415498

416-
func Join(hints ...[]ReferenceHint) ReferenceHints {
499+
// JoinUnique joins multiple hint lists, where the first occurrence of a
500+
// hint type takes precedence.
501+
func JoinUnique(hints ...[]ReferenceHint) ReferenceHints {
417502
var result []ReferenceHint
418503
for _, h := range hints {
419-
result = sliceutils.AppendUniqueFunc(result, runtime.MatchType[ReferenceHint], h...)
504+
AddUnique(&result, h...)
420505
}
421506
return result
422507
}
508+
509+
// AddUnique adds hints to hint list, whode type is not yet present in the list.
510+
func AddUnique[S ~[]T, T ReferenceHint](hints *S, add ...T) {
511+
*hints = sliceutils.AppendUniqueFunc(*hints, runtime.MatchType[T], add...)
512+
}
513+
514+
// AsDefault transforms a generic hint into a default hint.
515+
// It can be used by sliceutils.Transform.
516+
func AsDefault(h ReferenceHint) DefaultReferenceHint {
517+
return h.AsDefault()
518+
}

api/ocm/refhints/hints_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package refhints_test
22

33
import (
4+
"encoding/json"
45
"strings"
56

7+
. "github.com/mandelsoft/goutils/testutils"
68
. "github.com/onsi/ginkgo/v2"
79
. "github.com/onsi/gomega"
810

@@ -133,6 +135,35 @@ var _ = Describe("Hints Test Environment", func() {
133135
CheckHintImplicit("typ", "test", "typ::implicit=true,reference=test")
134136
})
135137
})
138+
139+
Context("marshal unmarshal", func() {
140+
It("works", func() {
141+
var hints refhints.DefaultReferenceHints
142+
143+
hints.Add(refhints.New("test", "label"))
144+
145+
data := Must(json.Marshal(hints))
146+
Expect(string(data)).To(Equal(`[{"reference":"label","type":"test"}]`))
147+
148+
var result refhints.DefaultReferenceHints
149+
150+
MustBeSuccessful(json.Unmarshal(data, &result))
151+
Expect(result).To(DeepEqual(hints))
152+
})
153+
154+
It("unmarshalls string", func() {
155+
var hints refhints.DefaultReferenceHints
156+
157+
hints.Add(refhints.New("test", "label"))
158+
159+
data := hints.Serialize()
160+
161+
var result refhints.DefaultReferenceHints
162+
163+
MustBeSuccessful(json.Unmarshal([]byte(`"`+data+`"`), &result))
164+
Expect(result).To(DeepEqual(hints))
165+
})
166+
})
136167
})
137168

138169
func CheckHint(s string, h ...refhints.ReferenceHint) {

cmds/ocm/commands/ocmcmds/common/addhdlrs/interface.go

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/mandelsoft/goutils/sliceutils"
99

1010
clictx "ocm.software/ocm/api/cli"
11+
"ocm.software/ocm/api/ocm/compdesc"
1112
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
1213
"ocm.software/ocm/api/ocm/cpi"
1314
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs"
@@ -106,6 +107,14 @@ type ElementSpec interface {
106107
Validate(ctx clictx.Context, input *ResourceInput) error
107108
}
108109

110+
// ArtifactElementSpec is the interface for elements
111+
// representing artifacts (like Resources a d Source).
112+
type ArtifactElementSpec interface {
113+
ElementSpec
114+
compdesc.ReferenceHintSink
115+
compdesc.ReferenceHintProvider
116+
}
117+
109118
// Element is the abstraction over model elements handled by
110119
// the add handler, for example, resources, sources, references or complete
111120
// component versions.

cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go

+27-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import (
44
"fmt"
55

66
"github.com/mandelsoft/goutils/errors"
7+
"github.com/mandelsoft/goutils/sliceutils"
78
"k8s.io/apimachinery/pkg/util/validation/field"
89

910
clictx "ocm.software/ocm/api/cli"
1011
"ocm.software/ocm/api/ocm"
1112
"ocm.software/ocm/api/ocm/compdesc"
1213
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
1314
compdescv2 "ocm.software/ocm/api/ocm/compdesc/versions/v2"
15+
"ocm.software/ocm/api/ocm/refhints"
1416
"ocm.software/ocm/api/utils/runtime"
1517
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common"
1618
"ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/addhdlrs"
@@ -97,9 +99,10 @@ func (h *ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Eleme
9799
ExtraIdentity: spec.ExtraIdentity,
98100
Labels: spec.Labels,
99101
},
100-
Type: spec.Type,
101-
Relation: spec.Relation,
102-
SourceRefs: compdescv2.ConvertSourcerefsTo(spec.SourceRefs),
102+
Type: spec.Type,
103+
Relation: spec.Relation,
104+
SourceRefs: compdescv2.ConvertSourcerefsTo(spec.SourceRefs),
105+
ReferenceHints: spec.GetReferenceHints(),
103106
}
104107
opts := h.getModOpts()
105108
if spec.Options.SkipDigestGeneration {
@@ -130,13 +133,17 @@ type ResourceSpec struct {
130133
// component.sources.
131134
SourceRefs []compdescv2.SourceRef `json:"srcRefs"`
132135

136+
ReferenceHints refhints.DefaultReferenceHints `json:"referenceHints,omitempty"`
137+
133138
addhdlrs.ResourceInput `json:",inline"`
134139

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

145+
var _ addhdlrs.ArtifactElementSpec = (*ResourceSpec)(nil)
146+
140147
// ResourceOptions describes additional process related options
141148
// which reflect the handling of the resource without describing it directly.
142149
// Typical examples are any options that require specific changes in handling of the resource
@@ -176,13 +183,26 @@ func (r *ResourceSpec) Validate(ctx clictx.Context, input *addhdlrs.ResourceInpu
176183
r.Version = ComponentVersionTag
177184
}
178185
rsc := compdescv2.Resource{
179-
ElementMeta: r.ElementMeta,
180-
Type: r.Type,
181-
Relation: r.Relation,
182-
SourceRefs: r.SourceRefs,
186+
ElementMeta: r.ElementMeta,
187+
Type: r.Type,
188+
Relation: r.Relation,
189+
SourceRefs: r.SourceRefs,
190+
ReferenceHints: r.ReferenceHints,
183191
}
184192
if err := compdescv2.ValidateResource(fldPath, rsc, false); err != nil {
185193
allErrs = append(allErrs, err...)
186194
}
187195
return allErrs.ToAggregate()
188196
}
197+
198+
func (r *ResourceSpec) GetReferenceHints() refhints.ReferenceHints {
199+
return refhints.ReferenceHints(sliceutils.Convert[refhints.ReferenceHint](r.ReferenceHints))
200+
}
201+
202+
func (r *ResourceSpec) SetReferenceHints(hints []refhints.ReferenceHint) {
203+
r.ReferenceHints = sliceutils.Transform(hints, refhints.AsDefault)
204+
}
205+
206+
func (r *ResourceSpec) AddReferenceHints(hints ...refhints.ReferenceHint) {
207+
refhints.AddUnique(&r.ReferenceHints, sliceutils.Transform(hints, refhints.AsDefault)...)
208+
}

0 commit comments

Comments
 (0)