mirror of https://github.com/docker/cli.git
cli-plugins: alias an existing allowed command (only builder for now)
With this patch it is possible to alias an existing allowed command. At the moment only builder allows an alias. This also properly puts the build command under builder, instead of image where it was for historical reasons. Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
2432af701a
commit
1ed02c40fe
|
@ -164,6 +164,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if plugin.Err != nil {
|
if plugin.Err != nil {
|
||||||
|
// TODO: why are we not returning plugin.Err?
|
||||||
return nil, errPluginNotFound(name)
|
return nil, errPluginNotFound(name)
|
||||||
}
|
}
|
||||||
cmd := exec.Command(plugin.Path, args...)
|
cmd := exec.Command(plugin.Path, args...)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/docker/cli/cli/command/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewBuilderCommand returns a cobra command for `builder` subcommands
|
// NewBuilderCommand returns a cobra command for `builder` subcommands
|
||||||
|
@ -18,6 +19,7 @@ func NewBuilderCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
}
|
}
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
NewPruneCommand(dockerCli),
|
NewPruneCommand(dockerCli),
|
||||||
|
image.NewBuildCommand(dockerCli),
|
||||||
)
|
)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,3 +161,34 @@ func ValidateOutputPathFileMode(fileMode os.FileMode) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringSliceIndex(s, subs []string) int {
|
||||||
|
j := 0
|
||||||
|
if len(subs) > 0 {
|
||||||
|
for i, x := range s {
|
||||||
|
if j < len(subs) && subs[j] == x {
|
||||||
|
j++
|
||||||
|
} else {
|
||||||
|
j = 0
|
||||||
|
}
|
||||||
|
if len(subs) == j {
|
||||||
|
return i + 1 - j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSliceReplaceAt replaces the sub-slice old, with the sub-slice new, in the string
|
||||||
|
// slice s, returning a new slice and a boolean indicating if the replacement happened.
|
||||||
|
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
|
||||||
|
func StringSliceReplaceAt(s, old, new []string, requireIndex int) ([]string, bool) {
|
||||||
|
idx := stringSliceIndex(s, old)
|
||||||
|
if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
out := append([]string{}, s[:idx]...)
|
||||||
|
out = append(out, new...)
|
||||||
|
out = append(out, s[idx+len(old):]...)
|
||||||
|
return out, true
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringSliceReplaceAt(t *testing.T) {
|
||||||
|
out, ok := StringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, -1)
|
||||||
|
assert.Assert(t, ok)
|
||||||
|
assert.DeepEqual(t, []string{"abc", "baz", "bax"}, out)
|
||||||
|
|
||||||
|
out, ok = StringSliceReplaceAt([]string{"foo"}, []string{"foo", "bar"}, []string{"baz"}, -1)
|
||||||
|
assert.Assert(t, !ok)
|
||||||
|
assert.DeepEqual(t, []string{"foo"}, out)
|
||||||
|
|
||||||
|
out, ok = StringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
|
||||||
|
assert.Assert(t, !ok)
|
||||||
|
assert.DeepEqual(t, []string{"abc", "foo", "bar", "bax"}, out)
|
||||||
|
|
||||||
|
out, ok = StringSliceReplaceAt([]string{"foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
|
||||||
|
assert.Assert(t, ok)
|
||||||
|
assert.DeepEqual(t, []string{"baz", "bax"}, out)
|
||||||
|
|
||||||
|
out, ok = StringSliceReplaceAt([]string{"abc", "foo", "bar", "baz"}, []string{"foo", "bar"}, nil, -1)
|
||||||
|
assert.Assert(t, ok)
|
||||||
|
assert.DeepEqual(t, []string{"abc", "baz"}, out)
|
||||||
|
|
||||||
|
out, ok = StringSliceReplaceAt([]string{"foo"}, nil, []string{"baz"}, -1)
|
||||||
|
assert.Assert(t, !ok)
|
||||||
|
assert.DeepEqual(t, []string{"foo"}, out)
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ type ConfigFile struct {
|
||||||
CurrentContext string `json:"currentContext,omitempty"`
|
CurrentContext string `json:"currentContext,omitempty"`
|
||||||
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
||||||
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
||||||
|
Aliases map[string]string `json:"aliases,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyConfig contains proxy configuration settings
|
// ProxyConfig contains proxy configuration settings
|
||||||
|
@ -72,6 +73,7 @@ func New(fn string) *ConfigFile {
|
||||||
HTTPHeaders: make(map[string]string),
|
HTTPHeaders: make(map[string]string),
|
||||||
Filename: fn,
|
Filename: fn,
|
||||||
Plugins: make(map[string]map[string]string),
|
Plugins: make(map[string]map[string]string),
|
||||||
|
Aliases: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -16,11 +15,16 @@ import (
|
||||||
"github.com/docker/cli/cli/version"
|
"github.com/docker/cli/cli/version"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var allowedAliases = map[string]struct{}{
|
||||||
|
"builder": {},
|
||||||
|
}
|
||||||
|
|
||||||
func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
|
func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
|
||||||
var (
|
var (
|
||||||
opts *cliflags.ClientOptions
|
opts *cliflags.ClientOptions
|
||||||
|
@ -204,6 +208,38 @@ func tryPluginRun(dockerCli command.Cli, cmd *cobra.Command, subcommand string)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processAliases(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []string) ([]string, []string, error) {
|
||||||
|
aliasMap := dockerCli.ConfigFile().Aliases
|
||||||
|
aliases := make([][2][]string, 0, len(aliasMap))
|
||||||
|
|
||||||
|
for k, v := range aliasMap {
|
||||||
|
if _, ok := allowedAliases[k]; !ok {
|
||||||
|
return args, osArgs, errors.Errorf("Not allowed to alias %q. Allowed aliases: %#v", k, allowedAliases)
|
||||||
|
}
|
||||||
|
if _, _, err := cmd.Find(strings.Split(v, " ")); err == nil {
|
||||||
|
return args, osArgs, errors.Errorf("Not allowed to alias with builtin %q as target", v)
|
||||||
|
}
|
||||||
|
aliases = append(aliases, [2][]string{{k}, {v}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := aliasMap["builder"]; ok {
|
||||||
|
aliases = append(aliases,
|
||||||
|
[2][]string{{"build"}, {v, "build"}},
|
||||||
|
[2][]string{{"image", "build"}, {v, "build"}},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for _, al := range aliases {
|
||||||
|
var didChange bool
|
||||||
|
args, didChange = command.StringSliceReplaceAt(args, al[0], al[1], 0)
|
||||||
|
if didChange {
|
||||||
|
osArgs, _ = command.StringSliceReplaceAt(osArgs, al[0], al[1], -1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, osArgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func runDocker(dockerCli *command.DockerCli) error {
|
func runDocker(dockerCli *command.DockerCli) error {
|
||||||
tcmd := newDockerCommand(dockerCli)
|
tcmd := newDockerCommand(dockerCli)
|
||||||
|
|
||||||
|
@ -216,6 +252,11 @@ func runDocker(dockerCli *command.DockerCli) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args, os.Args, err = processAliases(dockerCli, cmd, args, os.Args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
if _, _, err := cmd.Find(args); err != nil {
|
if _, _, err := cmd.Find(args); err != nil {
|
||||||
err := tryPluginRun(dockerCli, cmd, args[0])
|
err := tryPluginRun(dockerCli, cmd, args[0])
|
||||||
|
|
Loading…
Reference in New Issue