Skip to content

Commit ab3ae4f

Browse files
committed
implement ocm transfer
1 parent 18d5702 commit ab3ae4f

File tree

4 files changed

+189
-1
lines changed

4 files changed

+189
-1
lines changed

cmd/ocmTransfer.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cmd
2+
3+
import (
4+
ocmcli "github.com/openmcp-project/bootstrapper/internal/ocm-cli"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// ocmTransferCmd represents the "ocm transfer componentversion" command
10+
var ocmTransferCmd = &cobra.Command{
11+
Use: "ocmTransfer source destination",
12+
Short: "Transfer an OCM component from a source to a destination",
13+
Long: `Transfers the specified OCM component version from the source location to the destination location.`,
14+
Aliases: []string{
15+
"transfer",
16+
},
17+
Args: cobra.ExactArgs(2),
18+
ArgAliases: []string{
19+
"source",
20+
"destination",
21+
},
22+
RunE: func(cmd *cobra.Command, args []string) error {
23+
transferCommands := []string{
24+
"transfer",
25+
"componentversion",
26+
}
27+
28+
transferArgs := []string{
29+
"--recursive",
30+
"--copy-resources",
31+
"--copy-sources",
32+
args[0], // source
33+
args[1], // destination
34+
}
35+
36+
return ocmcli.Execute(cmd.Context(), transferCommands, transferArgs, cmd.Flag("config").Value.String())
37+
},
38+
}
39+
40+
func init() {
41+
rootCmd.AddCommand(ocmTransferCmd)
42+
43+
ocmTransferCmd.PersistentFlags().StringP("config", "c", "", "ocm configuration file")
44+
}

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module github.com/openmcp-project/bootstrapper
22

33
go 1.24.5
44

5-
require github.com/spf13/cobra v1.9.1
5+
require (
6+
github.com/spf13/cobra v1.9.1
7+
gopkg.in/yaml.v3 v3.0.1
8+
)
69

710
require (
811
github.com/inconshreveable/mousetrap v1.1.0 // indirect

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
88
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
99
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1010
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
11+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
1112
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/ocm-cli/ocm.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package ocm_cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"gopkg.in/yaml.v3"
7+
"os"
8+
"os/exec"
9+
)
10+
11+
const (
12+
// NoOcmConfig is a constant to indicate that no OCM configuration file is being provided.
13+
NoOcmConfig = ""
14+
)
15+
16+
// Execute runs the specified OCM command with the provided arguments and configuration.
17+
// It captures the command's output and errors, and returns an error if the command fails.
18+
// The `commands` parameter is a slice of strings representing the OCM command and its subcommands.
19+
// The `args` parameter is a slice of strings representing the arguments to the command.
20+
// The `ocmConfig` parameter is a string representing the path to the OCM configuration file. Passing `NoOcmConfig` indicates that no configuration file should be used.
21+
func Execute(ctx context.Context, commands []string, args []string, ocmConfig string) error {
22+
var flags []string
23+
24+
flags = append(flags, commands...)
25+
flags = append(flags, args...)
26+
27+
if ocmConfig != NoOcmConfig {
28+
flags = append(flags, "--config", ocmConfig)
29+
}
30+
31+
cmd := exec.CommandContext(ctx, "ocm", flags...)
32+
cmd.Stdout = os.Stdout
33+
cmd.Stderr = os.Stderr
34+
35+
if err := cmd.Start(); err != nil {
36+
return fmt.Errorf("error starting ocm command: %w", err)
37+
}
38+
39+
if err := cmd.Wait(); err != nil {
40+
return fmt.Errorf("error waiting for ocm command to finish: %w", err)
41+
}
42+
43+
return nil
44+
}
45+
46+
// ComponentVersion represents a version of an OCM component.
47+
type ComponentVersion struct {
48+
// Component is the OCM component associated with this version.
49+
Component Component `json:"component"`
50+
}
51+
52+
// Component represents an OCM component with its name, version, references to other components, and resources.
53+
type Component struct {
54+
// Name is the name of the component.
55+
Name string `yaml:"name"`
56+
// Version is the version of the component.
57+
Version string `yaml:"version"`
58+
// ComponentReferences is a list of references to other components that this component depends on.
59+
ComponentReferences []ComponentReference `yaml:"componentReferences"`
60+
// Resources is a list of resources associated with this component, including their names, versions, types, and access information.
61+
Resources []Resource `yaml:"resources"`
62+
}
63+
64+
// ComponentReference represents a reference to another component, including its name, version, and the name of the component it refers to.
65+
type ComponentReference struct {
66+
// Name is the name of the component reference.
67+
Name string `yaml:"name"`
68+
// Version is the version of the component reference.
69+
Version string `yaml:"version"`
70+
// ComponentName is the name of the component that this reference points to.
71+
ComponentName string `yaml:"componentName"`
72+
}
73+
74+
// Resource represents a resource associated with a component, including its name, version, type, and access information.
75+
type Resource struct {
76+
// Name is the name of the resource.
77+
Name string `yaml:"name"`
78+
// Version is the version of the resource.
79+
Version string `yaml:"version"`
80+
// Type is the content type of the resource.
81+
Type string `yaml:"type"`
82+
// Access contains the information on how to access the resource.
83+
Access Access `yaml:"access"`
84+
}
85+
86+
// Access represents the access information for a resource, including the type of access.
87+
type Access struct {
88+
// Type is the content type of access to the resource.
89+
Type string `yaml:"type"`
90+
// ImageReference is the reference to the image if the Type is "ociArtifact".
91+
ImageReference string `yaml:"imageReference"`
92+
}
93+
94+
// GetResource retrieves a resource by its name from the component version.
95+
func (cv *ComponentVersion) GetResource(name string) (*Resource, error) {
96+
for _, resource := range cv.Component.Resources {
97+
if resource.Name == name {
98+
return &resource, nil
99+
}
100+
}
101+
return nil, fmt.Errorf("resource %s not found in component version %s", name, cv.Component.Name)
102+
}
103+
104+
// GetComponentReference retrieves a component reference by its name from the component version.
105+
func (cv *ComponentVersion) GetComponentReference(name string) (*ComponentReference, error) {
106+
for _, ref := range cv.Component.ComponentReferences {
107+
if ref.Name == name {
108+
return &ref, nil
109+
}
110+
}
111+
return nil, fmt.Errorf("component reference %s not found in component version %s", name, cv.Component.Name)
112+
}
113+
114+
// GetComponentVersion retrieves a component version by its reference using the OCM CLI.
115+
func GetComponentVersion(ctx context.Context, componentReference string, ocmConfig string) (*ComponentVersion, error) {
116+
flags := []string{
117+
"get",
118+
"componentversion",
119+
"--output", "yaml",
120+
componentReference,
121+
}
122+
123+
if ocmConfig != NoOcmConfig {
124+
flags = append(flags, "--config", ocmConfig)
125+
}
126+
127+
cmd := exec.CommandContext(ctx, "ocm", flags...)
128+
out, err := cmd.CombinedOutput()
129+
if err != nil {
130+
return nil, fmt.Errorf("error executing ocm command: %w", err)
131+
}
132+
133+
var cv ComponentVersion
134+
err = yaml.Unmarshal(out, &cv)
135+
if err != nil {
136+
return nil, fmt.Errorf("error unmarshalling component version: %w", err)
137+
}
138+
139+
return &cv, nil
140+
}

0 commit comments

Comments
 (0)