diff --git a/.github/workflows/push_ocm.yaml b/.github/workflows/push_ocm.yaml index 6217d032e3..8197605ce7 100644 --- a/.github/workflows/push_ocm.yaml +++ b/.github/workflows/push_ocm.yaml @@ -55,7 +55,7 @@ jobs: key: ${{ runner.os }}-go-build-cache-${{ hashFiles('**/go.sum') }} - name: inject go-build-cache into docker - uses: reproducible-containers/buildkit-cache-dance@v2 + uses: reproducible-containers/buildkit-cache-dance@v3 with: cache-source: go-build-cache diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 253b145af8..ee2bcd6b8c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -143,7 +143,7 @@ jobs: uses: anchore/sbom-action/download-syft@ab5d7b5f48981941c4c5d6bf33aeb98fe3bae38c # v0.15.10 - name: Setup Cosign - uses: sigstore/cosign-installer@v3.4.0 + uses: sigstore/cosign-installer@v3.5.0 - name: Setup git config run: | diff --git a/cmds/ocm/app/app.go b/cmds/ocm/app/app.go index 2c94b2cb25..71af0e4282 100644 --- a/cmds/ocm/app/app.go +++ b/cmds/ocm/app/app.go @@ -45,6 +45,7 @@ import ( "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/get" "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/hash" "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/install" + "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/list" "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/show" "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/sign" "github.com/open-component-model/ocm/cmds/ocm/commands/verbs/transfer" @@ -234,6 +235,7 @@ func newCliCommand(opts *CLIOptions, mod ...func(clictx.Context, *cobra.Command) cmd.AddCommand(check.NewCommand(opts.Context)) cmd.AddCommand(get.NewCommand(opts.Context)) + cmd.AddCommand(list.NewCommand(opts.Context)) cmd.AddCommand(create.NewCommand(opts.Context)) cmd.AddCommand(add.NewCommand(opts.Context)) cmd.AddCommand(sign.NewCommand(opts.Context)) diff --git a/cmds/ocm/commands/common/options/keyoption/option.go b/cmds/ocm/commands/common/options/keyoption/option.go index cf02f69737..ace52bcb06 100644 --- a/cmds/ocm/commands/common/options/keyoption/option.go +++ b/cmds/ocm/commands/common/options/keyoption/option.go @@ -47,7 +47,7 @@ func (o *Option) AddFlags(fs *pflag.FlagSet) { fs.StringArrayVarP(&o.publicKeys, "public-key", "k", nil, "public key setting") fs.StringArrayVarP(&o.privateKeys, "private-key", "K", nil, "private key setting") fs.StringArrayVarP(&o.issuers, "issuer", "I", nil, "issuer name or distinguished name (DN) (optionally for dedicated signature) ([:=]") - fs.StringArrayVarP(&o.rootCAs, "ca-cert", "", nil, "additional root certificate authorities") + fs.StringArrayVarP(&o.rootCAs, "ca-cert", "", nil, "additional root certificate authorities (for signing certificates)") } func (o *Option) Configure(ctx clictx.Context) error { diff --git a/cmds/ocm/commands/misccmds/hash/sign/cmd.go b/cmds/ocm/commands/misccmds/hash/sign/cmd.go index 537f000ecf..68777ad498 100644 --- a/cmds/ocm/commands/misccmds/hash/sign/cmd.go +++ b/cmds/ocm/commands/misccmds/hash/sign/cmd.go @@ -5,6 +5,7 @@ package sign import ( + "crypto/x509" "crypto/x509/pkix" "fmt" "strings" @@ -36,6 +37,7 @@ type Command struct { pubFile string rootFile string + rootCAs []string stype string priv signutils.GenericPrivateKey @@ -72,7 +74,9 @@ $ ocm sign hash key.priv SHA-256:810ff2fb242a5dee4220f2cb0e6a519891fb67f2f828a6c func (o *Command) AddFlags(set *pflag.FlagSet) { set.StringVarP(&o.stype, "algorithm", "S", rsa.Algorithm, "signature algorithm") set.StringVarP(&o.pubFile, "publicKey", "", "", "public key certificate file") - set.StringVarP(&o.rootFile, "rootCerts", "", "", "root certificates file") + set.StringVarP(&o.rootFile, "rootCerts", "", "", "root certificates file (deprecated)") + set.StringArrayVarP(&o.rootCAs, "ca-cert", "", nil, "additional root certificate authorities (for signing certificates)") + } func (o *Command) Complete(args []string) error { @@ -109,6 +113,28 @@ func (o *Command) Complete(args []string) error { } } + if len(o.rootCAs) > 0 { + var list []*x509.Certificate + for _, r := range o.rootCAs { + data, err := utils2.ReadFile(r, o.FileSystem()) + if err != nil { + return errors.Wrapf(err, "root CA") + } + certs, err := signutils.GetCertificateChain(data, false) + if err != nil { + return errors.Wrapf(err, "root CA") + } + list = append(list, certs...) + } + if o.roots != nil { + for _, c := range list { + o.roots.(*x509.CertPool).AddCert(c) + } + } else { + o.roots = list + } + } + o.priv, err = utils2.ReadFile(args[0], o.FileSystem()) if err != nil { return err diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go index dff1093f70..7569f6e8e2 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go @@ -166,16 +166,5 @@ func (r *ResourceSpec) Validate(ctx clictx.Context, input *addhdlrs.ResourceInpu if err := compdescv2.ValidateResource(fldPath, rsc, false); err != nil { allErrs = append(allErrs, err...) } - - if input.Access != nil { - if r.Relation == metav1.LocalRelation { - allErrs = append(allErrs, field.Forbidden(fldPath.Child("relation"), "access requires external relation")) - } - } - if input.Input != nil { - if r.Relation != metav1.LocalRelation { - allErrs = append(allErrs, field.Forbidden(fldPath.Child("relation"), "input requires local relation")) - } - } return allErrs.ToAggregate() } diff --git a/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr/sort.go b/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr/sort.go index 4b83411a50..cd252766a0 100644 --- a/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr/sort.go +++ b/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr/sort.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/open-component-model/ocm/cmds/ocm/pkg/processing" + "github.com/open-component-model/ocm/pkg/semverutils" ) func Compare(a, b interface{}) int { @@ -18,7 +19,7 @@ func Compare(a, b interface{}) int { if c != 0 { return c } - return strings.Compare(aa.ComponentVersion.GetVersion(), ab.ComponentVersion.GetVersion()) + return semverutils.Compare(aa.ComponentVersion.GetVersion(), ab.ComponentVersion.GetVersion()) } // Sort is a processing chain sorting original objects provided by type handler. diff --git a/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/options.go b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/options.go new file mode 100644 index 0000000000..6f6e842841 --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/options.go @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package vershdlr + +import ( + "github.com/Masterminds/semver/v3" + + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/lookupoption" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/versionconstraintsoption" + "github.com/open-component-model/ocm/cmds/ocm/pkg/options" + "github.com/open-component-model/ocm/pkg/contexts/ocm" + "github.com/open-component-model/ocm/pkg/utils" +) + +type Option interface { + ApplyToHandler(handler *TypeHandler) +} + +type Options []Option + +func (o Options) ApplyToHandler(handler *TypeHandler) { + for _, e := range o { + e.ApplyToHandler(handler) + } +} + +func OptionsFor(o options.OptionSetProvider) Options { + var hopts []Option + if constr := versionconstraintsoption.From(o); constr != nil { + if len(constr.Constraints) > 0 { + hopts = append(hopts, WithVersionConstraints(constr.Constraints)) + } + if constr.Latest { + hopts = append(hopts, LatestOnly()) + } + } + if lookup := lookupoption.From(o); lookup != nil { + hopts = append(hopts, Resolver(lookup)) + } + return hopts +} + +//////////////////////////////////////////////////////////////////////////////// + +type constraints struct { + constraints []*semver.Constraints +} + +func (o constraints) ApplyToHandler(handler *TypeHandler) { + handler.constraints = o.constraints +} + +func WithVersionConstraints(c []*semver.Constraints) Option { + return constraints{c} +} + +//////////////////////////////////////////////////////////////////////////////// + +type latestonly struct { + flag bool +} + +func (o latestonly) ApplyToHandler(handler *TypeHandler) { + handler.latest = o.flag +} + +func LatestOnly(b ...bool) Option { + return latestonly{utils.OptionalDefaultedBool(true, b...)} +} + +//////////////////////////////////////////////////////////////////////////////// + +type resolver struct { + resolver ocm.ComponentVersionResolver +} + +func (o resolver) ApplyToHandler(handler *TypeHandler) { + handler.resolver = o.resolver +} + +func Resolver(r ocm.ComponentVersionResolver) Option { + return resolver{r} +} + +//////////////////////////////////////////////////////////////////////////////// + +type repository struct { + repository ocm.Repository +} + +func (o repository) ApplyToHandler(handler *TypeHandler) { + handler.repobase = o.repository +} + +func Repository(r ocm.Repository) Option { + return repository{r} +} diff --git a/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/sort.go b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/sort.go new file mode 100644 index 0000000000..3ada0c6851 --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/sort.go @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package vershdlr + +import ( + "strings" + + "github.com/open-component-model/ocm/cmds/ocm/pkg/processing" + "github.com/open-component-model/ocm/pkg/semverutils" +) + +func Compare(a, b interface{}) int { + aa := a.(*Object) + ab := b.(*Object) + + c := strings.Compare(aa.Component, ab.Component) + if c != 0 { + return c + } + return semverutils.Compare(aa.Version, ab.Version) +} + +// Sort is a processing chain sorting original objects provided by type handler. +var Sort = processing.Sort(Compare) diff --git a/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler.go b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler.go new file mode 100644 index 0000000000..b3ec2de9ba --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr/typehandler.go @@ -0,0 +1,234 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package vershdlr + +import ( + "fmt" + "os" + + "github.com/Masterminds/semver/v3" + + "github.com/open-component-model/ocm/cmds/ocm/pkg/output" + "github.com/open-component-model/ocm/cmds/ocm/pkg/utils" + "github.com/open-component-model/ocm/pkg/contexts/clictx" + "github.com/open-component-model/ocm/pkg/contexts/ocm" + "github.com/open-component-model/ocm/pkg/errors" + "github.com/open-component-model/ocm/pkg/semverutils" +) + +func Elem(e interface{}) *Object { + return e.(*Object) +} + +//////////////////////////////////////////////////////////////////////////////// + +type Object struct { + Spec ocm.RefSpec + Repository ocm.Repository + Component string + Version string +} + +type Manifest struct { + Component string `json:"component"` + Version string `json:"version"` + Message string `json:"error,omitempty"` +} + +func (o *Object) AsManifest() interface{} { + tag := "" + msg := "" + if o.Spec.Version != nil { + tag = *o.Spec.Version + } + if o.Version == "" { + msg = "" + } + return &Manifest{ + o.Component, + tag, + msg, + } +} + +//////////////////////////////////////////////////////////////////////////////// + +type TypeHandler struct { + octx clictx.OCM + session ocm.Session + repobase ocm.Repository + resolver ocm.ComponentVersionResolver + constraints []*semver.Constraints + latest bool +} + +func NewTypeHandler(octx clictx.OCM, session ocm.Session, repobase ocm.Repository, opts ...Option) utils.TypeHandler { + h := &TypeHandler{ + octx: octx, + session: session, + repobase: repobase, + } + for _, o := range opts { + o.ApplyToHandler(h) + } + return h +} + +func (h *TypeHandler) Close() error { + return nil +} + +func (h *TypeHandler) All() ([]output.Object, error) { + if h.repobase == nil { + return nil, nil + } + return h.all(h.repobase) +} + +func (h *TypeHandler) all(repo ocm.Repository) ([]output.Object, error) { + lister := repo.ComponentLister() + if lister == nil { + return nil, nil + } + list, err := lister.GetComponents("", true) + if err != nil { + return nil, err + } + var result []output.Object + for _, l := range list { + part, err := h.get(repo, utils.StringSpec(l)) + if err != nil { + fmt.Fprintf(os.Stderr, "Warning: %s\n", err) + } + result = append(result, part...) + } + return result, nil +} + +func (h *TypeHandler) Get(elemspec utils.ElemSpec) ([]output.Object, error) { + return h.get(h.repobase, elemspec) +} + +func (h *TypeHandler) filterVersions(vers []string) []string { + if len(h.constraints) == 0 && !h.latest { + return vers + } + versions, _ := semverutils.MatchVersionStrings(vers, h.constraints...) + if h.latest && len(versions) > 1 { + versions = versions[len(versions)-1:] + } + vers = nil + for _, v := range versions { + vers = append(vers, v.Original()) + } + return vers +} + +func (h *TypeHandler) get(repo ocm.Repository, elemspec utils.ElemSpec) ([]output.Object, error) { + var component ocm.ComponentAccess + var result []output.Object + var err error + + name := elemspec.String() + spec := ocm.RefSpec{} + if repo == nil { + evaluated, err := h.session.EvaluateComponentRef(h.octx.Context(), name) + if err != nil { + if !errors.IsErrNotFound(err) { + if h.resolver != nil { + comp, err := ocm.ParseComp(name) + if err != nil { + return nil, errors.Wrapf(err, "invalid component version reference %q", name) + } + if comp.IsVersion() { + cv, err := h.resolver.LookupComponentVersion(comp.Component, *comp.Version) + if err != nil { + return nil, err + } + if cv != nil { + evaluated = &ocm.EvaluationResult{} + evaluated.Ref.UniformRepositorySpec = *cv.Repository().GetSpecification().AsUniformSpec(h.octx.Context()) + evaluated.Ref.CompSpec = comp + evaluated.Version = cv + evaluated.Repository = cv.Repository() + h.session.Closer(cv) + } + } + } + } + if evaluated == nil { + return nil, errors.Wrapf(err, "%s: invalid component version reference", name) + } + } + if evaluated.Version != nil { + result = append(result, &Object{ + Spec: evaluated.Ref, + Repository: evaluated.Repository, + Component: evaluated.Component.GetName(), + Version: evaluated.Version.GetVersion(), + }) + return result, nil + } + spec = evaluated.Ref + component = evaluated.Component + repo = evaluated.Repository + } else { + comp := ocm.CompSpec{Component: ""} + if name != "" { + comp, err = ocm.ParseComp(name) + if err != nil { + return nil, errors.Wrapf(err, "reference %q", name) + } + } + component, err = h.session.LookupComponent(repo, comp.Component) + if err != nil { + return nil, errors.Wrapf(err, "reference %q", name) + } + spec.UniformRepositorySpec = *repo.GetSpecification().AsUniformSpec(h.octx.Context()) + spec.Component = comp.Component + spec.Version = comp.Version + } + + if spec.IsVersion() { + vers := "" + v, err := h.session.GetComponentVersion(component, *spec.Version) + if err != nil { + if !errors.IsErrNotFound(err) { + return nil, err + } + } else { + vers = v.GetVersion() + } + result = append(result, &Object{ + Repository: repo, + Spec: spec, + Component: component.GetName(), + Version: vers, + }) + } else { + if component == nil { + return h.all(repo) + } else { + versions, err := component.ListVersions() + if err != nil { + return nil, err + } + versions = h.filterVersions(versions) + + for _, vers := range versions { + t := vers + s := spec + s.Version = &t + result = append(result, &Object{ + Repository: repo, + Spec: s, + Component: component.GetName(), + Version: vers, + }) + } + } + } + return result, nil +} diff --git a/cmds/ocm/commands/ocmcmds/components/cmd.go b/cmds/ocm/commands/ocmcmds/components/cmd.go index 7bee1e2726..f15db411f5 100644 --- a/cmds/ocm/commands/ocmcmds/components/cmd.go +++ b/cmds/ocm/commands/ocmcmds/components/cmd.go @@ -12,6 +12,7 @@ import ( "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/download" "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/get" "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/hash" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/list" "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/sign" "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/transfer" "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/verify" @@ -34,6 +35,7 @@ func NewCommand(ctx clictx.Context) *cobra.Command { func AddCommands(ctx clictx.Context, cmd *cobra.Command) { cmd.AddCommand(add.NewCommand(ctx, add.Verb)) cmd.AddCommand(get.NewCommand(ctx, get.Verb)) + cmd.AddCommand(list.NewCommand(ctx, list.Verb)) cmd.AddCommand(hash.NewCommand(ctx, hash.Verb)) cmd.AddCommand(sign.NewCommand(ctx, sign.Verb)) cmd.AddCommand(transfer.NewCommand(ctx, transfer.Verb)) diff --git a/cmds/ocm/commands/ocmcmds/components/list/cmd.go b/cmds/ocm/commands/ocmcmds/components/list/cmd.go new file mode 100644 index 0000000000..47d2757abd --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/components/list/cmd.go @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package list + +import ( + "fmt" + + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/handlers/vershdlr" + "github.com/spf13/cobra" + + ocmcommon "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/lookupoption" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/repooption" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/schemaoption" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/common/options/versionconstraintsoption" + "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/names" + "github.com/open-component-model/ocm/cmds/ocm/commands/verbs" + "github.com/open-component-model/ocm/cmds/ocm/pkg/output" + "github.com/open-component-model/ocm/cmds/ocm/pkg/processing" + "github.com/open-component-model/ocm/cmds/ocm/pkg/utils" + "github.com/open-component-model/ocm/pkg/contexts/clictx" + "github.com/open-component-model/ocm/pkg/contexts/ocm" +) + +var ( + Names = names.Components + Verb = verbs.List +) + +type Command struct { + utils.BaseCommand + + Refs []string +} + +// NewCommand creates a new ctf command. +func NewCommand(ctx clictx.Context, names ...string) *cobra.Command { + return utils.SetupCommand( + &Command{BaseCommand: utils.NewBaseCommand(ctx, + versionconstraintsoption.New(), repooption.New(), + output.OutputOptions(outputs, + lookupoption.New(), + schemaoption.New("", true), + ))}, + utils.Names(Names, names...)..., + ) +} + +func (o *Command) ForName(name string) *cobra.Command { + return &cobra.Command{ + Use: "[] {}", + Short: "list component version names", + Long: ` +List lists the version names of the specified objects, if only a component is specified +all versions according to the given versuin constraints are listed. +`, + Example: ` +$ ocm list componentversion ghcr.io/mandelsoft/kubelink +$ ocm list componentversion --repo OCIRegistry::ghcr.io mandelsoft/kubelink +`, + } +} + +func (o *Command) Complete(args []string) error { + o.Refs = args + if len(args) == 0 && repooption.From(o).Spec == "" { + return fmt.Errorf("a repository or at least one argument that defines the reference is needed") + } + return nil +} + +func (o *Command) Run() error { + session := ocm.NewSession(nil) + defer session.Close() + + err := o.ProcessOnOptions(ocmcommon.CompleteOptionsWithSession(o, session)) + if err != nil { + return err + } + handler := vershdlr.NewTypeHandler(o.Context.OCM(), session, repooption.From(o).Repository, vershdlr.OptionsFor(o)) + return utils.HandleArgs(output.From(o), handler, o.Refs...) +} + +///////////////////////////////////////////////////////////////////////////// + +func addIdentityField(e interface{}) []string { + p := e.(*comphdlr.Object) + return []string{p.Identity.String()} +} + +func TableOutput(opts *output.Options, mapping processing.MappingFunction) *output.TableOutput { + return &output.TableOutput{ + Headers: output.Fields("COMPONENT", "VERSION", "MESSAGE"), + Options: opts, + Chain: vershdlr.Sort, + Mapping: mapping, + } +} + +///////////////////////////////////////////////////////////////////////////// + +var outputs = output.NewOutputs(getRegular, output.Outputs{}).AddManifestOutputs() + +func getRegular(opts *output.Options) output.Output { + return TableOutput(opts, mapGetRegularOutput).New() +} + +func mapGetRegularOutput(e interface{}) interface{} { + p := vershdlr.Elem(e) + + tag := "" + if p.Spec.Version != nil { + tag = *p.Spec.Version + } + if p.Version == "" { + return []string{p.Component, tag, ""} + } + return []string{p.Spec.Component, tag, ""} +} diff --git a/cmds/ocm/commands/ocmcmds/components/list/cmd_test.go b/cmds/ocm/commands/ocmcmds/components/list/cmd_test.go new file mode 100644 index 0000000000..031cc9264f --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/components/list/cmd_test.go @@ -0,0 +1,225 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package list_test + +import ( + "bytes" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/open-component-model/ocm/cmds/ocm/testhelper" + . "github.com/open-component-model/ocm/pkg/testutils" + + "github.com/open-component-model/ocm/pkg/common/accessio" +) + +const ARCH = "/tmp/ca" +const ARCH2 = "/tmp/ca2" +const VERSION = "v1" +const VERSION11 = "v1.1" +const VERSION2 = "v2" +const COMP = "test.de/x" +const COMP2 = "test.de/y" +const COMP3 = "test.de/z" +const PROVIDER = "mandelsoft" + +var _ = Describe("Test Environment", func() { + var env *TestEnv + + BeforeEach(func() { + env = NewTestEnv() + }) + + AfterEach(func() { + env.Cleanup() + }) + + It("list component archive", func() { + env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { + env.Provider(PROVIDER) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", ARCH)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1 +`)) + }) + + It("list component archive with refs", func() { + env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { + env.Provider(PROVIDER) + env.Reference("ref", COMP2, VERSION) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", ARCH)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1 +`)) + }) + + It("lists ctf file", func() { + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.Component(COMP, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + }) + }) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", ARCH)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1 +`)) + }) + + Context("ctf with multiple versions", func() { + BeforeEach(func() { + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.Component(COMP, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + }) + }) + env.Component(COMP, func() { + env.Version(VERSION11, func() { + env.Provider(PROVIDER) + }) + }) + env.Component(COMP, func() { + env.Version(VERSION2, func() { + env.Provider(PROVIDER) + }) + }) + }) + }) + + It("lists all versions", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--repo", ARCH, COMP)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1 +test.de/x v1.1 +test.de/x v2 +`)) + }) + + It("lists latest version", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--latest", "--repo", ARCH, COMP)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v2 +`)) + }) + + It("lists constrainted version", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--constraints", ">1.0", "--repo", ARCH, COMP)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1.1 +test.de/x v2 +`)) + }) + + It("lists constrainted version", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--constraints", "1.x.x", "--latest", "--repo", ARCH, COMP)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1.1 +`)) + }) + + }) + + Context("ctf", func() { + BeforeEach(func() { + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.Component(COMP2, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + env.Reference("xx", COMP, VERSION) + }) + }) + env.Component(COMP, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + }) + }) + }) + }) + + It("lists all components", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--repo", ARCH)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/x v1 +test.de/y v1 +`)) + }) + + It("lists all components as json", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--repo", ARCH, "-o", "json")).To(Succeed()) + fmt.Printf("%s\n", buf.String()) + Expect(buf.String()).To(YAMLEqual(` +items: +- component: test.de/x + version: v1 +- component: test.de/y + version: v1 +`)) + }) + + It("reports unknown in repo", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", "--repo", ARCH, COMP3+":v1")).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/z v1 +`)) + }) + + It("reports unknown", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", ARCH+"//"+COMP3+":v1")).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +COMPONENT VERSION MESSAGE +test.de/z v1 +`)) + }) + + It("reports unknown as json", func() { + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("list", "components", ARCH+"//"+COMP3+":v1", "-o", "json")).To(Succeed()) + Expect(buf.String()).To(YAMLEqual(` +items: +- component: test.de/z + version: v1 + error: +`)) + }) + }) +}) diff --git a/cmds/ocm/commands/ocmcmds/components/list/suite_test.go b/cmds/ocm/commands/ocmcmds/components/list/suite_test.go new file mode 100644 index 0000000000..a1299859ed --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/components/list/suite_test.go @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package list_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "OCM list component versions") +} diff --git a/cmds/ocm/commands/ocmcmds/sources/add/cmd.go b/cmds/ocm/commands/ocmcmds/sources/add/cmd.go index 0f11b46d01..1b8e16782b 100644 --- a/cmds/ocm/commands/ocmcmds/sources/add/cmd.go +++ b/cmds/ocm/commands/ocmcmds/sources/add/cmd.go @@ -50,7 +50,8 @@ $ ocm add sources --file path/to/cafile sources.yaml func (o *Command) Long() string { return ` -Add source information specified in a resource file to a component version. +Add information about the sources, e.g. commits in a Github repository, +that have been used to create the resources specified in a resource file to a component version. So far only component archives are supported as target. This command accepts source specification files describing the sources diff --git a/cmds/ocm/commands/verbs/list/cmd.go b/cmds/ocm/commands/verbs/list/cmd.go new file mode 100644 index 0000000000..9be99c6001 --- /dev/null +++ b/cmds/ocm/commands/verbs/list/cmd.go @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. +// +// SPDX-License-Identifier: Apache-2.0 + +package list + +import ( + "github.com/spf13/cobra" + + components "github.com/open-component-model/ocm/cmds/ocm/commands/ocmcmds/components/list" + "github.com/open-component-model/ocm/cmds/ocm/commands/verbs" + "github.com/open-component-model/ocm/cmds/ocm/pkg/utils" + "github.com/open-component-model/ocm/pkg/contexts/clictx" +) + +// NewCommand creates a new command. +func NewCommand(ctx clictx.Context) *cobra.Command { + cmd := utils.MassageCommand(&cobra.Command{ + Short: "List information about components", + }, verbs.List) + cmd.AddCommand(components.NewCommand(ctx)) + return cmd +} diff --git a/cmds/ocm/commands/verbs/verbs.go b/cmds/ocm/commands/verbs/verbs.go index b7ed57982f..636e929676 100644 --- a/cmds/ocm/commands/verbs/verbs.go +++ b/cmds/ocm/commands/verbs/verbs.go @@ -6,6 +6,7 @@ package verbs const ( Get = "get" + List = "list" Check = "check" Describe = "describe" Hash = "hash" diff --git a/cmds/ocm/pkg/output/tableoutput.go b/cmds/ocm/pkg/output/tableoutput.go index 6e2314dbbe..5027043ccb 100644 --- a/cmds/ocm/pkg/output/tableoutput.go +++ b/cmds/ocm/pkg/output/tableoutput.go @@ -8,6 +8,8 @@ import ( "strings" . "github.com/open-component-model/ocm/cmds/ocm/pkg/processing" + "github.com/open-component-model/ocm/pkg/semverutils" + "github.com/open-component-model/ocm/pkg/utils" "github.com/open-component-model/ocm/cmds/ocm/pkg/data" "github.com/open-component-model/ocm/pkg/errors" @@ -126,7 +128,7 @@ func (this *TableProcessingOutput) Out() error { if n < this.opts.FixedColums { return errors.Newf("field '%s' not possible", k) } - cmp := compareColumn(idxs[key]) + cmp := compareColumn(idxs[key], strings.Contains(strings.ToLower(key), "version")) if this.opts.FixedColums > 0 { sortFixed(this.opts.FixedColums, slice, cmp) } else { @@ -139,12 +141,23 @@ func (this *TableProcessingOutput) Out() error { return this.ElementOutput.Out() } -func compareColumn(c int) CompareFunction { +// compareColumn returns a compare function for a dedicated output column. +// if vers is set to true, a semver based comparison is applied, otherwise +// a regular string comparison. +func compareColumn(c int, vers ...bool) CompareFunction { + if utils.Optional(vers...) { + return _compareColumn(c, semverutils.Compare) + } else { + return _compareColumn(c, strings.Compare) + } +} + +func _compareColumn(c int, cmp func(a, b string) int) CompareFunction { return func(a interface{}, b interface{}) int { aa := a.([]string) ab := b.([]string) if len(aa) > c && len(ab) > c { - return strings.Compare(aa[c], ab[c]) + return cmp(aa[c], ab[c]) } return len(aa) - len(ab) } diff --git a/docs/reference/ocm.md b/docs/reference/ocm.md index 77ee2b50e7..3046ee8c66 100644 --- a/docs/reference/ocm.md +++ b/docs/reference/ocm.md @@ -10,7 +10,7 @@ ocm [] ... ``` -X, --attribute stringArray attribute setting - --ca-cert stringArray additional root certificate authorities + --ca-cert stringArray additional root certificate authorities (for signing certificates) --config stringArray configuration file --config-set strings apply configuration set -C, --cred stringArray credential setting @@ -367,6 +367,7 @@ by a certificate delivered with the signature. * [ocm get](ocm_get.md) — Get information about artifacts and components * [ocm hash](ocm_hash.md) — Hash and normalization operations * [ocm install](ocm_install.md) — Install elements. +* [ocm list](ocm_list.md) — List information about components * [ocm show](ocm_show.md) — Show tags or versions * [ocm sign](ocm_sign.md) — Sign components or hashes * [ocm transfer](ocm_transfer.md) — Transfer artifacts or components diff --git a/docs/reference/ocm_add_componentversions.md b/docs/reference/ocm_add_componentversions.md index 558b4c4cdd..d54e8dd1f5 100644 --- a/docs/reference/ocm_add_componentversions.md +++ b/docs/reference/ocm_add_componentversions.md @@ -149,7 +149,7 @@ script with the script option family.
-$ ocm add componentversions ‐‐file ctf ‐‐version 1.0 component-constructor.yaml
+$ ocm add componentversions ‐‐file ctf ‐‐version 1.0 component‐constructor.yaml
 
diff --git a/docs/reference/ocm_add_sources.md b/docs/reference/ocm_add_sources.md index 88289f54cb..0270fae913 100644 --- a/docs/reference/ocm_add_sources.md +++ b/docs/reference/ocm_add_sources.md @@ -93,7 +93,8 @@ sources, source, src, s ### Description -Add source information specified in a resource file to a component version. +Add information about the sources, e.g. commits in a Github repository, +that have been used to create the resources specified in a resource file to a component version. So far only component archives are supported as target. This command accepts source specification files describing the sources diff --git a/docs/reference/ocm_list.md b/docs/reference/ocm_list.md new file mode 100644 index 0000000000..3324efee87 --- /dev/null +++ b/docs/reference/ocm_list.md @@ -0,0 +1,25 @@ +## ocm list — List Information About Components + +### Synopsis + +``` +ocm list [] ... +``` + +### Options + +``` + -h, --help help for list +``` + +### SEE ALSO + +##### Parents + +* [ocm](ocm.md) — Open Component Model command line client + + +##### Sub Commands + +* [ocm list componentversions](ocm_list_componentversions.md) — list component version names + diff --git a/docs/reference/ocm_list_componentversions.md b/docs/reference/ocm_list_componentversions.md new file mode 100644 index 0000000000..9eabce871c --- /dev/null +++ b/docs/reference/ocm_list_componentversions.md @@ -0,0 +1,126 @@ +## ocm list componentversions — List Component Version Names + +### Synopsis + +``` +ocm list componentversions [] {} +``` + +##### Aliases + +``` +componentversions, componentversion, cv, components, component, comps, comp, c +``` + +### Options + +``` + -c, --constraints constraints version constraint + -h, --help help for componentversions + --latest restrict component versions to latest + --lookup stringArray repository name or spec for closure lookup fallback + -o, --output string output mode (JSON, json, yaml) + --repo string repository name or spec + -S, --scheme string schema version + -s, --sort stringArray sort fields +``` + +### Description + + +List lists the version names of the specified objects, if only a component is specified +all versions according to the given versuin constraints are listed. + + +If the option --constraints is given, and no version is specified +for a component, only versions matching the given version constraints +(semver https://github.com/Masterminds/semver) are selected. +With --latest only +the latest matching versions will be selected. + + +If the --repo option is specified, the given names are interpreted +relative to the specified repository using the syntax + +
+
<component>[:<version>]
+
+ +If no --repo option is specified the given names are interpreted +as located OCM component version references: + +
+
[<repo type>::]<host>[:<port>][/<base path>]//<component>[:<version>]
+
+ +Additionally there is a variant to denote common transport archives +and general repository specifications + +
+
[<repo type>::]<filepath>|<spec json>[//<component>[:<version>]]
+
+ +The --repo option takes an OCM repository specification: + +
+
[<repo type>::]<configured name>|<file path>|<spec json>
+
+ +For the *Common Transport Format* the types directory, +tar or tgz is possible. + +Using the JSON variant any repository types supported by the +linked library can be used: + +Dedicated OCM repository types: + - ComponentArchive: v1 + +OCI Repository types (using standard component repository to OCI mapping): + - CommonTransportFormat: v1 + - OCIRegistry: v1 + - oci: v1 + - ociRegistry + + +\ +If a component lookup for building a reference closure is required +the --lookup option can be used to specify a fallback +lookup repository. By default, the component versions are searched in +the repository holding the component version for which the closure is +determined. For *Component Archives* this is never possible, because +it only contains a single component version. Therefore, in this scenario +this option must always be specified to be able to follow component +references. + + +If the option --scheme is given, the component descriptor +is converted to the specified format for output. If no format is given +the storage format of the actual descriptor is used or, for new ones v2 +is used. +With internal the internal representation is shown. +The following schema versions are supported for explicit conversions: + - ocm.software/v3alpha1 + - v2 + +With the option --output the output mode can be selected. +The following modes are supported: + - (default) + - JSON + - json + - yaml + + +### Examples + +``` +$ ocm list componentversion ghcr.io/mandelsoft/kubelink +$ ocm list componentversion --repo OCIRegistry::ghcr.io mandelsoft/kubelink +``` + +### SEE ALSO + +##### Parents + +* [ocm list](ocm_list.md) — List information about components +* [ocm](ocm.md) — Open Component Model command line client + diff --git a/docs/reference/ocm_sign_componentversions.md b/docs/reference/ocm_sign_componentversions.md index c2c2ffd972..f349615e29 100644 --- a/docs/reference/ocm_sign_componentversions.md +++ b/docs/reference/ocm_sign_componentversions.md @@ -16,7 +16,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c ``` -S, --algorithm string signature handler (default "RSASSA-PKCS1-V1_5") - --ca-cert stringArray additional root certificate authorities + --ca-cert stringArray additional root certificate authorities (for signing certificates) -c, --constraints constraints version constraint -H, --hash string hash algorithm (default "SHA-256") -h, --help help for componentversions diff --git a/docs/reference/ocm_sign_hash.md b/docs/reference/ocm_sign_hash.md index 8360af3b18..ee5af1c0bb 100644 --- a/docs/reference/ocm_sign_hash.md +++ b/docs/reference/ocm_sign_hash.md @@ -9,10 +9,11 @@ ocm sign hash [] ### Options ``` - -S, --algorithm string signature algorithm (default "RSASSA-PKCS1-V1_5") - -h, --help help for hash - --publicKey string public key certificate file - --rootCerts string root certificates file + -S, --algorithm string signature algorithm (default "RSASSA-PKCS1-V1_5") + --ca-cert stringArray additional root certificate authorities (for signing certificates) + -h, --help help for hash + --publicKey string public key certificate file + --rootCerts string root certificates file (deprecated) ``` ### Description diff --git a/docs/reference/ocm_verify_componentversions.md b/docs/reference/ocm_verify_componentversions.md index fd5e2ad2db..e34ae26685 100644 --- a/docs/reference/ocm_verify_componentversions.md +++ b/docs/reference/ocm_verify_componentversions.md @@ -15,7 +15,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c ### Options ``` - --ca-cert stringArray additional root certificate authorities + --ca-cert stringArray additional root certificate authorities (for signing certificates) -c, --constraints constraints version constraint -h, --help help for componentversions -I, --issuer stringArray issuer name or distinguished name (DN) (optionally for dedicated signature) ([:=] diff --git a/pkg/common/accessobj/cachedblob_test.go b/pkg/common/accessobj/cachedblob_test.go index 6f7e6549d4..4bf670e50b 100644 --- a/pkg/common/accessobj/cachedblob_test.go +++ b/pkg/common/accessobj/cachedblob_test.go @@ -1,17 +1,12 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. -// -// SPDX-License-Identifier: Apache-2.0 - package accessobj_test import ( "io" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" "github.com/open-component-model/ocm/pkg/blobaccess" "github.com/open-component-model/ocm/pkg/common/accessio" @@ -72,7 +67,7 @@ var _ = Describe("cached blob", func() { Expect(err).To(Succeed()) ctx = datacontext.New(nil) vfsattr.Set(ctx, fs) - tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp"}) + tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp", Filesystem: fs}) }) AfterEach(func() { diff --git a/pkg/common/types.go b/pkg/common/types.go index 5468a2dee9..2bba104131 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/open-component-model/ocm/pkg/errors" + "github.com/open-component-model/ocm/pkg/semverutils" ) // VersionedElement describes an element that has a name and a version. @@ -56,7 +57,7 @@ func (n NameVersion) MarshalJSON() ([]byte, error) { func (n NameVersion) Compare(o NameVersion) int { c := strings.Compare(n.name, o.name) if c == 0 { - return strings.Compare(n.version, o.version) + return semverutils.Compare(n.version, o.version) } return c } diff --git a/pkg/contexts/datacontext/attrs/tmpcache/attr.go b/pkg/contexts/datacontext/attrs/tmpcache/attr.go index 54a3591b84..7c4164ed7f 100644 --- a/pkg/contexts/datacontext/attrs/tmpcache/attr.go +++ b/pkg/contexts/datacontext/attrs/tmpcache/attr.go @@ -1,12 +1,7 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. -// -// SPDX-License-Identifier: Apache-2.0 - package tmpcache import ( "fmt" - "os" "github.com/mandelsoft/vfs/pkg/vfs" @@ -14,6 +9,7 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/datacontext/attrs/vfsattr" "github.com/open-component-model/ocm/pkg/errors" "github.com/open-component-model/ocm/pkg/runtime" + "github.com/open-component-model/ocm/pkg/utils" ) const ( @@ -76,18 +72,17 @@ func (a *Attribute) CreateTempFile(pat string) (vfs.File, error) { //////////////////////////////////////////////////////////////////////////////// -var def = &Attribute{ - Path: os.TempDir(), -} - func Get(ctx datacontext.Context) *Attribute { v := ctx.GetAttributes().GetAttribute(ATTR_KEY) - a := def - + fs := utils.FileSystem(vfsattr.Get(ctx)) if v != nil { - a, _ = v.(*Attribute) + a := v.(*Attribute) + if a.Filesystem == nil { + a.Filesystem = fs + } + return a } - return &Attribute{a.Path, vfsattr.Get(ctx)} + return &Attribute{fs.FSTempDir(), fs} } func Set(ctx datacontext.Context, a *Attribute) { diff --git a/pkg/contexts/ocm/accessmethods/github/method_test.go b/pkg/contexts/ocm/accessmethods/github/method_test.go index 184395abc0..df6b50e003 100644 --- a/pkg/contexts/ocm/accessmethods/github/method_test.go +++ b/pkg/contexts/ocm/accessmethods/github/method_test.go @@ -1,7 +1,3 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. -// -// SPDX-License-Identifier: Apache-2.0 - package github_test import ( @@ -11,20 +7,18 @@ import ( "net/http" "os" - _ "github.com/open-component-model/ocm/pkg/contexts/datacontext/config" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/mandelsoft/filepath/pkg/filepath" "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" "github.com/open-component-model/ocm/pkg/contexts/credentials" "github.com/open-component-model/ocm/pkg/contexts/credentials/builtin/github/identity" "github.com/open-component-model/ocm/pkg/contexts/datacontext" "github.com/open-component-model/ocm/pkg/contexts/datacontext/attrs/tmpcache" "github.com/open-component-model/ocm/pkg/contexts/datacontext/attrs/vfsattr" + _ "github.com/open-component-model/ocm/pkg/contexts/datacontext/config" "github.com/open-component-model/ocm/pkg/contexts/ocm" me "github.com/open-component-model/ocm/pkg/contexts/ocm/accessmethods/github" "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi" @@ -105,7 +99,7 @@ var _ = Describe("Method", func() { fs, err = osfs.NewTempFileSystem() Expect(err).To(Succeed()) vfsattr.Set(ctx, fs) - tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp"}) + tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp", Filesystem: fs}) }) AfterEach(func() { diff --git a/pkg/contexts/ocm/accessmethods/s3/method_test.go b/pkg/contexts/ocm/accessmethods/s3/method_test.go index 3baf76b0ea..e5f5de1dc1 100644 --- a/pkg/contexts/ocm/accessmethods/s3/method_test.go +++ b/pkg/contexts/ocm/accessmethods/s3/method_test.go @@ -1,7 +1,3 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors. -// -// SPDX-License-Identifier: Apache-2.0 - package s3_test import ( @@ -11,14 +7,11 @@ import ( "os" "reflect" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/open-component-model/ocm/pkg/env/builder" - . "github.com/open-component-model/ocm/pkg/testutils" - "github.com/mandelsoft/filepath/pkg/filepath" "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" "github.com/open-component-model/ocm/pkg/common/accessio/downloader" "github.com/open-component-model/ocm/pkg/contexts/credentials" @@ -29,7 +22,9 @@ import ( "github.com/open-component-model/ocm/pkg/contexts/ocm/accessmethods/s3" "github.com/open-component-model/ocm/pkg/contexts/ocm/accessmethods/s3/identity" "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi" + . "github.com/open-component-model/ocm/pkg/env/builder" "github.com/open-component-model/ocm/pkg/generics" + . "github.com/open-component-model/ocm/pkg/testutils" ) type mockDownloader struct { @@ -141,7 +136,7 @@ var _ = Describe("Method", func() { Expect(err).To(Succeed()) ctx = datacontext.New(nil) vfsattr.Set(ctx, fs) - tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp"}) + tmpcache.Set(ctx, &tmpcache.Attribute{Path: "/tmp", Filesystem: fs}) mcc = ocm.New(datacontext.MODE_INITIAL) mcc.CredentialsContext().SetCredentialsForConsumer(credentials.ConsumerIdentity{credentials.ID_TYPE: identity.CONSUMER_TYPE}, credentials.DirectCredentials{ "accessKeyID": "accessKeyID", diff --git a/pkg/contexts/ocm/compdesc/componentdescriptor.go b/pkg/contexts/ocm/compdesc/componentdescriptor.go index e7a0caf68b..b25fe36e61 100644 --- a/pkg/contexts/ocm/compdesc/componentdescriptor.go +++ b/pkg/contexts/ocm/compdesc/componentdescriptor.go @@ -13,6 +13,7 @@ import ( metav1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1" "github.com/open-component-model/ocm/pkg/errors" "github.com/open-component-model/ocm/pkg/runtime" + "github.com/open-component-model/ocm/pkg/semverutils" ) const InternalSchemaVersion = "internal" @@ -742,7 +743,7 @@ func (r References) Less(i, j int) bool { if c != 0 { return c < 0 } - return strings.Compare(r[i].Version, r[j].Version) < 0 + return semverutils.Compare(r[i].Version, r[j].Version) < 0 } func (r References) Copy() References { diff --git a/pkg/contexts/ocm/session.go b/pkg/contexts/ocm/session.go index 81e11f8ea8..b257b52953 100644 --- a/pkg/contexts/ocm/session.go +++ b/pkg/contexts/ocm/session.go @@ -217,7 +217,7 @@ func (s *session) EvaluateVersionRef(ctx Context, ref string) (*EvaluationResult func (s *session) EvaluateComponentRef(ctx Context, ref string) (*EvaluationResult, error) { evaluated, err := s.EvaluateRef(ctx, ref) if err != nil { - return nil, err + return evaluated, err } if evaluated.Component == nil { lister := evaluated.Repository.ComponentLister() diff --git a/pkg/semverutils/sort.go b/pkg/semverutils/sort.go index a25e9f4f9e..895194d3e2 100644 --- a/pkg/semverutils/sort.go +++ b/pkg/semverutils/sort.go @@ -6,6 +6,7 @@ package semverutils import ( "sort" + "strings" "github.com/Masterminds/semver/v3" "golang.org/x/exp/slices" @@ -25,6 +26,30 @@ func (c VersionCache) Get(v string) (*semver.Version, error) { return s, nil } +func (c VersionCache) Compare(a, b string) int { + va, err := c.Get(a) + if err != nil { + return strings.Compare(a, b) + } + vb, err := c.Get(b) + if err != nil { + return strings.Compare(a, b) + } + return va.Compare(vb) +} + +func Compare(a, b string) int { + va, err := semver.NewVersion(a) + if err != nil { + return strings.Compare(a, b) + } + vb, err := semver.NewVersion(b) + if err != nil { + return strings.Compare(a, b) + } + return va.Compare(vb) +} + func SortVersions(vers []string) error { cache := VersionCache{} for _, v := range vers {