Skip to content

Commit e201b4e

Browse files
authored
Merge pull request #5902 from thaJeztah/cli_plugin_metadata
move cli-plugins metadata types/consts to a separate package
2 parents ceef542 + 292713c commit e201b4e

20 files changed

Lines changed: 174 additions & 103 deletions

File tree

cli-plugins/examples/helloworld/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"fmt"
66
"os"
77

8-
"github.com/docker/cli/cli-plugins/manager"
8+
"github.com/docker/cli/cli-plugins/metadata"
99
"github.com/docker/cli/cli-plugins/plugin"
1010
"github.com/docker/cli/cli/command"
1111
"github.com/spf13/cobra"
@@ -97,7 +97,7 @@ func main() {
9797
cmd.AddCommand(goodbye, apiversion, exitStatus2)
9898
return cmd
9999
},
100-
manager.Metadata{
100+
metadata.Metadata{
101101
SchemaVersion: "0.1.0",
102102
Vendor: "Docker Inc.",
103103
Version: "testing",

cli-plugins/manager/annotations.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package manager
2+
3+
import "github.com/docker/cli/cli-plugins/metadata"
4+
5+
const (
6+
// CommandAnnotationPlugin is added to every stub command added by
7+
// AddPluginCommandStubs with the value "true" and so can be
8+
// used to distinguish plugin stubs from regular commands.
9+
CommandAnnotationPlugin = metadata.CommandAnnotationPlugin
10+
11+
// CommandAnnotationPluginVendor is added to every stub command
12+
// added by AddPluginCommandStubs and contains the vendor of
13+
// that plugin.
14+
CommandAnnotationPluginVendor = metadata.CommandAnnotationPluginVendor
15+
16+
// CommandAnnotationPluginVersion is added to every stub command
17+
// added by AddPluginCommandStubs and contains the version of
18+
// that plugin.
19+
CommandAnnotationPluginVersion = metadata.CommandAnnotationPluginVersion
20+
21+
// CommandAnnotationPluginInvalid is added to any stub command
22+
// added by AddPluginCommandStubs for an invalid command (that
23+
// is, one which failed it's candidate test) and contains the
24+
// reason for the failure.
25+
CommandAnnotationPluginInvalid = metadata.CommandAnnotationPluginInvalid
26+
27+
// CommandAnnotationPluginCommandPath is added to overwrite the
28+
// command path for a plugin invocation.
29+
CommandAnnotationPluginCommandPath = metadata.CommandAnnotationPluginCommandPath
30+
)

cli-plugins/manager/candidate.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package manager
22

3-
import "os/exec"
3+
import (
4+
"os/exec"
5+
6+
"github.com/docker/cli/cli-plugins/metadata"
7+
)
48

59
// Candidate represents a possible plugin candidate, for mocking purposes
610
type Candidate interface {
@@ -17,5 +21,5 @@ func (c *candidate) Path() string {
1721
}
1822

1923
func (c *candidate) Metadata() ([]byte, error) {
20-
return exec.Command(c.path, MetadataSubcommandName).Output() // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
24+
return exec.Command(c.path, metadata.MetadataSubcommandName).Output() // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
2125
}

cli-plugins/manager/candidate_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77
"testing"
88

9+
"github.com/docker/cli/cli-plugins/metadata"
910
"github.com/spf13/cobra"
1011
"gotest.tools/v3/assert"
1112
"gotest.tools/v3/assert/cmp"
@@ -30,10 +31,10 @@ func (c *fakeCandidate) Metadata() ([]byte, error) {
3031

3132
func TestValidateCandidate(t *testing.T) {
3233
const (
33-
goodPluginName = NamePrefix + "goodplugin"
34+
goodPluginName = metadata.NamePrefix + "goodplugin"
3435

35-
builtinName = NamePrefix + "builtin"
36-
builtinAlias = NamePrefix + "alias"
36+
builtinName = metadata.NamePrefix + "builtin"
37+
builtinAlias = metadata.NamePrefix + "alias"
3738

3839
badPrefixPath = "/usr/local/libexec/cli-plugins/wobble"
3940
badNamePath = "/usr/local/libexec/cli-plugins/docker-123456"
@@ -43,9 +44,9 @@ func TestValidateCandidate(t *testing.T) {
4344

4445
fakeroot := &cobra.Command{Use: "docker"}
4546
fakeroot.AddCommand(&cobra.Command{
46-
Use: strings.TrimPrefix(builtinName, NamePrefix),
47+
Use: strings.TrimPrefix(builtinName, metadata.NamePrefix),
4748
Aliases: []string{
48-
strings.TrimPrefix(builtinAlias, NamePrefix),
49+
strings.TrimPrefix(builtinAlias, metadata.NamePrefix),
4950
},
5051
})
5152

@@ -59,7 +60,7 @@ func TestValidateCandidate(t *testing.T) {
5960
}{
6061
/* Each failing one of the tests */
6162
{name: "empty path", c: &fakeCandidate{path: ""}, err: "plugin candidate path cannot be empty"},
62-
{name: "bad prefix", c: &fakeCandidate{path: badPrefixPath}, err: fmt.Sprintf("does not have %q prefix", NamePrefix)},
63+
{name: "bad prefix", c: &fakeCandidate{path: badPrefixPath}, err: fmt.Sprintf("does not have %q prefix", metadata.NamePrefix)},
6364
{name: "bad path", c: &fakeCandidate{path: badNamePath}, invalid: "did not match"},
6465
{name: "builtin command", c: &fakeCandidate{path: builtinName}, invalid: `plugin "builtin" duplicates builtin command`},
6566
{name: "builtin alias", c: &fakeCandidate{path: builtinAlias}, invalid: `plugin "alias" duplicates an alias of builtin command "builtin"`},
@@ -84,7 +85,7 @@ func TestValidateCandidate(t *testing.T) {
8485
assert.ErrorContains(t, p.Err, tc.invalid)
8586
default:
8687
assert.NilError(t, err)
87-
assert.Equal(t, NamePrefix+p.Name, goodPluginName)
88+
assert.Equal(t, metadata.NamePrefix+p.Name, goodPluginName)
8889
assert.Equal(t, p.SchemaVersion, "0.1.0")
8990
assert.Equal(t, p.Vendor, "e2e-testing")
9091
}

cli-plugins/manager/cobra.go

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,11 @@ import (
55
"os"
66
"sync"
77

8+
"github.com/docker/cli/cli-plugins/metadata"
89
"github.com/docker/cli/cli/config"
910
"github.com/spf13/cobra"
1011
)
1112

12-
const (
13-
// CommandAnnotationPlugin is added to every stub command added by
14-
// AddPluginCommandStubs with the value "true" and so can be
15-
// used to distinguish plugin stubs from regular commands.
16-
CommandAnnotationPlugin = "com.docker.cli.plugin"
17-
18-
// CommandAnnotationPluginVendor is added to every stub command
19-
// added by AddPluginCommandStubs and contains the vendor of
20-
// that plugin.
21-
CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
22-
23-
// CommandAnnotationPluginVersion is added to every stub command
24-
// added by AddPluginCommandStubs and contains the version of
25-
// that plugin.
26-
CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
27-
28-
// CommandAnnotationPluginInvalid is added to any stub command
29-
// added by AddPluginCommandStubs for an invalid command (that
30-
// is, one which failed it's candidate test) and contains the
31-
// reason for the failure.
32-
CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
33-
34-
// CommandAnnotationPluginCommandPath is added to overwrite the
35-
// command path for a plugin invocation.
36-
CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
37-
)
38-
3913
var pluginCommandStubsOnce sync.Once
4014

4115
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
@@ -54,12 +28,12 @@ func AddPluginCommandStubs(dockerCLI config.Provider, rootCmd *cobra.Command) (e
5428
vendor = "unknown"
5529
}
5630
annotations := map[string]string{
57-
CommandAnnotationPlugin: "true",
58-
CommandAnnotationPluginVendor: vendor,
59-
CommandAnnotationPluginVersion: p.Version,
31+
metadata.CommandAnnotationPlugin: "true",
32+
metadata.CommandAnnotationPluginVendor: vendor,
33+
metadata.CommandAnnotationPluginVersion: p.Version,
6034
}
6135
if p.Err != nil {
62-
annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
36+
annotations[metadata.CommandAnnotationPluginInvalid] = p.Err.Error()
6337
}
6438
rootCmd.AddCommand(&cobra.Command{
6539
Use: p.Name,

cli-plugins/manager/manager.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"sync"
1111

12+
"github.com/docker/cli/cli-plugins/metadata"
1213
"github.com/docker/cli/cli/config"
1314
"github.com/docker/cli/cli/config/configfile"
1415
"github.com/fvbommel/sortorder"
@@ -21,7 +22,7 @@ const (
2122
// used to originally invoke the docker CLI when executing a
2223
// plugin. Assuming $PATH and $CWD remain unchanged this should allow
2324
// the plugin to re-execute the original CLI.
24-
ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
25+
ReexecEnvvar = metadata.ReexecEnvvar
2526

2627
// ResourceAttributesEnvvar is the name of the envvar that includes additional
2728
// resource attributes for OTEL.
@@ -92,10 +93,10 @@ func addPluginCandidatesFromDir(res map[string][]string, d string) {
9293
continue
9394
}
9495
name := dentry.Name()
95-
if !strings.HasPrefix(name, NamePrefix) {
96+
if !strings.HasPrefix(name, metadata.NamePrefix) {
9697
continue
9798
}
98-
name = strings.TrimPrefix(name, NamePrefix)
99+
name = strings.TrimPrefix(name, metadata.NamePrefix)
99100
var err error
100101
if name, err = trimExeSuffix(name); err != nil {
101102
continue
@@ -200,7 +201,7 @@ func PluginRunCommand(dockerCli config.Provider, name string, rootcmd *cobra.Com
200201
// fallback to their "invalid" command path.
201202
return nil, errPluginNotFound(name)
202203
}
203-
exename := addExeSuffix(NamePrefix + name)
204+
exename := addExeSuffix(metadata.NamePrefix + name)
204205
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
205206
if err != nil {
206207
return nil, err
@@ -237,7 +238,7 @@ func PluginRunCommand(dockerCli config.Provider, name string, rootcmd *cobra.Com
237238
cmd.Stdout = os.Stdout
238239
cmd.Stderr = os.Stderr
239240

240-
cmd.Env = append(cmd.Environ(), ReexecEnvvar+"="+os.Args[0])
241+
cmd.Env = append(cmd.Environ(), metadata.ReexecEnvvar+"="+os.Args[0])
241242
cmd.Env = appendPluginResourceAttributesEnvvar(cmd.Env, rootcmd, plugin)
242243

243244
return cmd, nil
@@ -247,5 +248,5 @@ func PluginRunCommand(dockerCli config.Provider, name string, rootcmd *cobra.Com
247248

248249
// IsPluginCommand checks if the given cmd is a plugin-stub.
249250
func IsPluginCommand(cmd *cobra.Command) bool {
250-
return cmd.Annotations[CommandAnnotationPlugin] == "true"
251+
return cmd.Annotations[metadata.CommandAnnotationPlugin] == "true"
251252
}

cli-plugins/manager/metadata.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,23 @@
11
package manager
22

3+
import (
4+
"github.com/docker/cli/cli-plugins/metadata"
5+
)
6+
37
const (
48
// NamePrefix is the prefix required on all plugin binary names
5-
NamePrefix = "docker-"
9+
NamePrefix = metadata.NamePrefix
610

711
// MetadataSubcommandName is the name of the plugin subcommand
812
// which must be supported by every plugin and returns the
913
// plugin metadata.
10-
MetadataSubcommandName = "docker-cli-plugin-metadata"
14+
MetadataSubcommandName = metadata.MetadataSubcommandName
1115

1216
// HookSubcommandName is the name of the plugin subcommand
1317
// which must be implemented by plugins declaring support
1418
// for hooks in their metadata.
15-
HookSubcommandName = "docker-cli-plugin-hooks"
19+
HookSubcommandName = metadata.HookSubcommandName
1620
)
1721

1822
// Metadata provided by the plugin.
19-
type Metadata struct {
20-
// SchemaVersion describes the version of this struct. Mandatory, must be "0.1.0"
21-
SchemaVersion string `json:",omitempty"`
22-
// Vendor is the name of the plugin vendor. Mandatory
23-
Vendor string `json:",omitempty"`
24-
// Version is the optional version of this plugin.
25-
Version string `json:",omitempty"`
26-
// ShortDescription should be suitable for a single line help message.
27-
ShortDescription string `json:",omitempty"`
28-
// URL is a pointer to the plugin's homepage.
29-
URL string `json:",omitempty"`
30-
}
23+
type Metadata = metadata.Metadata

cli-plugins/manager/plugin.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"regexp"
1010
"strings"
1111

12+
"github.com/docker/cli/cli-plugins/metadata"
1213
"github.com/pkg/errors"
1314
"github.com/spf13/cobra"
1415
)
@@ -17,7 +18,7 @@ var pluginNameRe = regexp.MustCompile("^[a-z][a-z0-9]*$")
1718

1819
// Plugin represents a potential plugin with all it's metadata.
1920
type Plugin struct {
20-
Metadata
21+
metadata.Metadata
2122

2223
Name string `json:",omitempty"`
2324
Path string `json:",omitempty"`
@@ -50,12 +51,12 @@ func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
5051
if fullname, err = trimExeSuffix(fullname); err != nil {
5152
return Plugin{}, errors.Wrapf(err, "plugin candidate %q", path)
5253
}
53-
if !strings.HasPrefix(fullname, NamePrefix) {
54-
return Plugin{}, errors.Errorf("plugin candidate %q: does not have %q prefix", path, NamePrefix)
54+
if !strings.HasPrefix(fullname, metadata.NamePrefix) {
55+
return Plugin{}, errors.Errorf("plugin candidate %q: does not have %q prefix", path, metadata.NamePrefix)
5556
}
5657

5758
p := Plugin{
58-
Name: strings.TrimPrefix(fullname, NamePrefix),
59+
Name: strings.TrimPrefix(fullname, metadata.NamePrefix),
5960
Path: path,
6061
}
6162

@@ -112,9 +113,9 @@ func (p *Plugin) RunHook(ctx context.Context, hookData HookPluginData) ([]byte,
112113
return nil, wrapAsPluginError(err, "failed to marshall hook data")
113114
}
114115

115-
pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes)) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
116+
pCmd := exec.CommandContext(ctx, p.Path, p.Name, metadata.HookSubcommandName, string(hDataBytes)) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
116117
pCmd.Env = os.Environ()
117-
pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0])
118+
pCmd.Env = append(pCmd.Env, metadata.ReexecEnvvar+"="+os.Args[0])
118119
hookCmdOutput, err := pCmd.Output()
119120
if err != nil {
120121
return nil, wrapAsPluginError(err, "failed to execute plugin hook subcommand")

cli-plugins/manager/telemetry.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"strings"
77

8+
"github.com/docker/cli/cli-plugins/metadata"
89
"github.com/spf13/cobra"
910
"go.opentelemetry.io/otel"
1011
"go.opentelemetry.io/otel/attribute"
@@ -26,7 +27,7 @@ const (
2627
)
2728

2829
func getPluginResourceAttributes(cmd *cobra.Command, plugin Plugin) attribute.Set {
29-
commandPath := cmd.Annotations[CommandAnnotationPluginCommandPath]
30+
commandPath := cmd.Annotations[metadata.CommandAnnotationPluginCommandPath]
3031
if commandPath == "" {
3132
commandPath = fmt.Sprintf("%s %s", cmd.CommandPath(), plugin.Name)
3233
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package metadata
2+
3+
const (
4+
// CommandAnnotationPlugin is added to every stub command added by
5+
// AddPluginCommandStubs with the value "true" and so can be
6+
// used to distinguish plugin stubs from regular commands.
7+
CommandAnnotationPlugin = "com.docker.cli.plugin"
8+
9+
// CommandAnnotationPluginVendor is added to every stub command
10+
// added by AddPluginCommandStubs and contains the vendor of
11+
// that plugin.
12+
CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
13+
14+
// CommandAnnotationPluginVersion is added to every stub command
15+
// added by AddPluginCommandStubs and contains the version of
16+
// that plugin.
17+
CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
18+
19+
// CommandAnnotationPluginInvalid is added to any stub command
20+
// added by AddPluginCommandStubs for an invalid command (that
21+
// is, one which failed it's candidate test) and contains the
22+
// reason for the failure.
23+
CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
24+
25+
// CommandAnnotationPluginCommandPath is added to overwrite the
26+
// command path for a plugin invocation.
27+
CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
28+
)

0 commit comments

Comments
 (0)