install/uninstall: allow aliasing buildx to `docker builder`

Currently the user can type `docker buildx` to use this tool.
This patch allows the user to install buildx as a `docker builder` alias.

As an additional benefit, this allows the regular `docker build` to hook
into `buildx build`.

Note that the install and uninstall commands are currently hidden.

Signed-off-by: Tibor Vass <tibor@docker.com>
pull/34/head
Tibor Vass 6 years ago
parent 7f474ed28e
commit 416b7bb23f

@ -35,7 +35,8 @@ COPY . .
FROM golang:1.12-alpine AS docker-cli-build FROM golang:1.12-alpine AS docker-cli-build
RUN apk add -U git bash coreutils gcc musl-dev RUN apk add -U git bash coreutils gcc musl-dev
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
ARG REPO=github.com/docker/cli ARG REPO=github.com/tiborvass/cli
ARG BRANCH=cli-plugin-aliases
ARG CLI_VERSION ARG CLI_VERSION
WORKDIR /go/src/github.com/docker/cli WORKDIR /go/src/github.com/docker/cli
RUN git clone git://$REPO . && git checkout $BRANCH RUN git clone git://$REPO . && git checkout $BRANCH
@ -58,7 +59,7 @@ RUN mkdir -p /usr/local/lib/docker/cli-plugins && ln -s /usr/local/bin/buildx /u
COPY ./hack/demo-env/entrypoint.sh /usr/local/bin COPY ./hack/demo-env/entrypoint.sh /usr/local/bin
COPY ./hack/demo-env/tmux.conf /root/.tmux.conf COPY ./hack/demo-env/tmux.conf /root/.tmux.conf
COPY --from=dockerd-release /usr/local/bin /usr/local/bin COPY --from=dockerd-release /usr/local/bin /usr/local/bin
#COPY --from=docker-cli-build /go/src/github.com/docker/cli/build/docker /usr/local/bin COPY --from=docker-cli-build /go/src/github.com/docker/cli/build/docker /usr/local/bin
WORKDIR /work WORKDIR /work
COPY ./hack/demo-env/examples . COPY ./hack/demo-env/examples .

@ -0,0 +1,52 @@
package commands
import (
"os"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type installOptions struct {
}
func runInstall(dockerCli command.Cli, in installOptions) error {
dir := config.Dir()
if err := os.MkdirAll(dir, 0755); err != nil {
return errors.Wrap(err, "could not create docker config")
}
cfg, err := config.Load(dir)
if err != nil {
return err
}
if cfg.Aliases == nil {
cfg.Aliases = map[string]string{}
}
cfg.Aliases["builder"] = "buildx"
if err := cfg.Save(); err != nil {
return errors.Wrap(err, "could not write docker config")
}
return nil
}
func installCmd(dockerCli command.Cli) *cobra.Command {
var options installOptions
cmd := &cobra.Command{
Use: "install",
Short: "Install buildx as a 'docker builder' alias",
Args: cli.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return runInstall(dockerCli, options)
},
Hidden: true,
}
return cmd
}

@ -32,6 +32,8 @@ func addCommands(cmd *cobra.Command, dockerCli command.Cli) {
useCmd(dockerCli), useCmd(dockerCli),
inspectCmd(dockerCli), inspectCmd(dockerCli),
stopCmd(dockerCli), stopCmd(dockerCli),
installCmd(dockerCli),
uninstallCmd(dockerCli),
imagetoolscmd.RootCmd(dockerCli), imagetoolscmd.RootCmd(dockerCli),
) )
} }

@ -0,0 +1,58 @@
package commands
import (
"os"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type uninstallOptions struct {
}
func runUninstall(dockerCli command.Cli, in uninstallOptions) error {
dir := config.Dir()
cfg, err := config.Load(dir)
if err != nil {
return errors.Wrap(err, "could not load docker config to uninstall 'docker builder' alias")
}
// config.Load does not return an error if config file does not exist
// so let's detect that case, to avoid writing an empty config to disk.
if _, err := os.Stat(cfg.Filename); err != nil {
if !os.IsNotExist(err) {
// should never happen, already handled in config.Load
return errors.Wrap(err, "unexpected error loading docker config")
}
// no-op
return nil
}
delete(cfg.Aliases, "builder")
if len(cfg.Aliases) == 0 {
cfg.Aliases = nil
}
if err := cfg.Save(); err != nil {
return errors.Wrap(err, "could not write docker config")
}
return nil
}
func uninstallCmd(dockerCli command.Cli) *cobra.Command {
var options uninstallOptions
cmd := &cobra.Command{
Use: "uninstall",
Short: "Uninstall the 'docker builder' alias",
Args: cli.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return runUninstall(dockerCli, options)
},
Hidden: true,
}
return cmd
}

@ -95,3 +95,5 @@ require (
) )
replace github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305 replace github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305
replace github.com/docker/cli => github.com/tiborvass/cli v0.0.0-20190419012645-1ed02c40fe68

@ -63,8 +63,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 h1:tTngnoO/B6HQnJ+pK8tN7kEAhmhIfaJOutqq/A4/JTM= github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 h1:tTngnoO/B6HQnJ+pK8tN7kEAhmhIfaJOutqq/A4/JTM=
github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0 h1:E7NTtHfZYV+iu35yZ49AbrxqhMHpiOl3FstDYm38vQ0=
github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/compose-on-kubernetes v0.4.19-0.20190128150448-356b2919c496 h1:90ytrX1dbzL7Uf/hHiuWwvywC+gikHv4hkAy4CwRTbs= github.com/docker/compose-on-kubernetes v0.4.19-0.20190128150448-356b2919c496 h1:90ytrX1dbzL7Uf/hHiuWwvywC+gikHv4hkAy4CwRTbs=
github.com/docker/compose-on-kubernetes v0.4.19-0.20190128150448-356b2919c496/go.mod h1:iT2pYfi580XlpaV4KmK0T6+4/9+XoKmk/fhoDod1emE= github.com/docker/compose-on-kubernetes v0.4.19-0.20190128150448-356b2919c496/go.mod h1:iT2pYfi580XlpaV4KmK0T6+4/9+XoKmk/fhoDod1emE=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE=
@ -256,6 +254,8 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0= github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0=
github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY= github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY=
github.com/tiborvass/cli v0.0.0-20190419012645-1ed02c40fe68 h1:NYTot8AmowoFRqpczwLpi7JRKJblipjgfXh3XE+hi5o=
github.com/tiborvass/cli v0.0.0-20190419012645-1ed02c40fe68/go.mod h1:S/jEQ1OdFvFXmvGs5oicYe8IJS7pBTP99Z0EtGfRs8s=
github.com/tonistiigi/fsutil v0.0.0-20190327153851-3bbb99cdbd76 h1:eGfgYrNUSD448sa4mxH6nQpyZfN39QH0mLB7QaKIjus= github.com/tonistiigi/fsutil v0.0.0-20190327153851-3bbb99cdbd76 h1:eGfgYrNUSD448sa4mxH6nQpyZfN39QH0mLB7QaKIjus=
github.com/tonistiigi/fsutil v0.0.0-20190327153851-3bbb99cdbd76/go.mod h1:pzh7kdwkDRh+Bx8J30uqaKJ1M4QrSH/um8fcIXeM8rc= github.com/tonistiigi/fsutil v0.0.0-20190327153851-3bbb99cdbd76/go.mod h1:pzh7kdwkDRh+Bx8J30uqaKJ1M4QrSH/um8fcIXeM8rc=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=

@ -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...)

@ -40,10 +40,13 @@ func runPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
return err return err
} }
cmd, _, err := tcmd.HandleGlobalFlags() cmd, args, err := tcmd.HandleGlobalFlags()
if err != nil { if err != nil {
return err return err
} }
// We've parsed global args already, so reset args to those
// which remain.
cmd.SetArgs(args)
return cmd.Execute() return cmd.Execute()
} }

@ -42,6 +42,10 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *p
rootCmd.SetFlagErrorFunc(FlagErrorFunc) rootCmd.SetFlagErrorFunc(FlagErrorFunc)
rootCmd.SetHelpCommand(helpCommand) rootCmd.SetHelpCommand(helpCommand)
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
rootCmd.PersistentFlags().Lookup("help").Hidden = true
return opts, flags, helpCommand return opts, flags, helpCommand
} }
@ -52,20 +56,12 @@ func SetupRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *pflag.F
rootCmd.SetVersionTemplate("Docker version {{.Version}}\n") rootCmd.SetVersionTemplate("Docker version {{.Version}}\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
rootCmd.PersistentFlags().Lookup("help").Hidden = true
return opts, flags, helpCmd return opts, flags, helpCmd
} }
// SetupPluginRootCommand sets default usage, help and error handling for a plugin root command. // SetupPluginRootCommand sets default usage, help and error handling for a plugin root command.
func SetupPluginRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *pflag.FlagSet) { func SetupPluginRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *pflag.FlagSet) {
opts, flags, _ := setupCommonRootCommand(rootCmd) opts, flags, _ := setupCommonRootCommand(rootCmd)
rootCmd.PersistentFlags().BoolP("help", "", false, "Print usage")
rootCmd.PersistentFlags().Lookup("help").Hidden = true
return opts, flags return opts, flags
} }

@ -28,16 +28,22 @@ func ElectAuthServer(ctx context.Context, cli Cli) string {
// used. This is essential in cross-platforms environment, where for // used. This is essential in cross-platforms environment, where for
// example a Linux client might be interacting with a Windows daemon, hence // example a Linux client might be interacting with a Windows daemon, hence
// the default registry URL might be Windows specific. // the default registry URL might be Windows specific.
serverAddress := registry.IndexServer info, err := cli.Client().Info(ctx)
if info, err := cli.Client().Info(ctx); err != nil && debug.IsEnabled() { if err != nil {
// Daemon is not responding so use system default.
if debug.IsEnabled() {
// Only report the warning if we're in debug mode to prevent nagging during engine initialization workflows // Only report the warning if we're in debug mode to prevent nagging during engine initialization workflows
fmt.Fprintf(cli.Err(), "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) fmt.Fprintf(cli.Err(), "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, registry.IndexServer)
} else if info.IndexServerAddress == "" && debug.IsEnabled() { }
fmt.Fprintf(cli.Err(), "Warning: Empty registry endpoint from daemon. Using system default: %s\n", serverAddress) return registry.IndexServer
} else { }
serverAddress = info.IndexServerAddress if info.IndexServerAddress == "" {
if debug.IsEnabled() {
fmt.Fprintf(cli.Err(), "Warning: Empty registry endpoint from daemon. Using system default: %s\n", registry.IndexServer)
}
return registry.IndexServer
} }
return serverAddress return info.IndexServerAddress
} }
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload // EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload

@ -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
}

@ -634,7 +634,8 @@ func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails)
func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails) (types.FileObjectConfig, error) { func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails) (types.FileObjectConfig, error) {
// if "external: true" // if "external: true"
if obj.External.External { switch {
case obj.External.External:
// handle deprecated external.name // handle deprecated external.name
if obj.External.Name != "" { if obj.External.Name != "" {
if obj.Name != "" { if obj.Name != "" {
@ -651,7 +652,11 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
} }
} }
// if not "external: true" // if not "external: true"
} else { case obj.Driver != "":
if obj.File != "" {
return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
}
default:
obj.File = absPath(details.WorkingDir, obj.File) obj.File = absPath(details.WorkingDir, obj.File)
} }

@ -510,45 +510,45 @@ bnBpPlHfjORjkTRf1wyAwiYqMXd9/G6313QfoXs6/sbZ66r6e179PwAA//8ZL3SpvkUAAA==
"/data/config_schema_v3.8.json": { "/data/config_schema_v3.8.json": {
local: "data/config_schema_v3.8.json", local: "data/config_schema_v3.8.json",
size: 18006, size: 18246,
modtime: 1518458244, modtime: 1518458244,
compressed: ` compressed: `
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
jmPjVfX3tPpvAAAA//+mJNa5VkYAAA== ean7MQBPP+U4w19V/z+t/hsAAP//Fd/bF0ZHAAA=
`, `,
}, },

@ -500,8 +500,7 @@ func (e External) MarshalJSON() ([]byte, error) {
// CredentialSpecConfig for credential spec on Windows // CredentialSpecConfig for credential spec on Windows
type CredentialSpecConfig struct { type CredentialSpecConfig struct {
// @TODO Config is not yet in use Config string `yaml:",omitempty" json:"config,omitempty"` // Config was added in API v1.40
Config string `yaml:"-" json:"-"` // Config was added in API v1.40
File string `yaml:",omitempty" json:"file,omitempty"` File string `yaml:",omitempty" json:"file,omitempty"`
Registry string `yaml:",omitempty" json:"registry,omitempty"` Registry string `yaml:",omitempty" json:"registry,omitempty"`
} }
@ -513,6 +512,8 @@ type FileObjectConfig struct {
External External `yaml:",omitempty" json:"external,omitempty"` External External `yaml:",omitempty" json:"external,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
Extras map[string]interface{} `yaml:",inline" json:"-"` Extras map[string]interface{} `yaml:",inline" json:"-"`
Driver string `yaml:",omitempty" json:"driver,omitempty"`
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
TemplateDriver string `mapstructure:"template_driver" yaml:"template_driver,omitempty" json:"template_driver,omitempty"` TemplateDriver string `mapstructure:"template_driver" yaml:"template_driver,omitempty" json:"template_driver,omitempty"`
} }

@ -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),
} }
} }

@ -18,6 +18,10 @@ type NetworkAttachmentOpts struct {
Target string Target string
Aliases []string Aliases []string
DriverOpts map[string]string DriverOpts map[string]string
Links []string // TODO add support for links in the csv notation of `--network`
IPv4Address string // TODO add support for IPv4-address in the csv notation of `--network`
IPv6Address string // TODO add support for IPv6-address in the csv notation of `--network`
LinkLocalIPs []string // TODO add support for LinkLocalIPs in the csv notation of `--network` ?
} }
// NetworkOpt represents a network config in swarm mode. // NetworkOpt represents a network config in swarm mode.
@ -95,6 +99,16 @@ func (n *NetworkOpt) String() string {
return "" return ""
} }
// NetworkMode return the network mode for the network option
func (n *NetworkOpt) NetworkMode() string {
networkIDOrName := "default"
netOptVal := n.Value()
if len(netOptVal) > 0 {
networkIDOrName = netOptVal[0].Target
}
return networkIDOrName
}
func parseDriverOpt(driverOpt string) (string, string, error) { func parseDriverOpt(driverOpt string) (string, string, error) {
parts := strings.SplitN(driverOpt, "=", 2) parts := strings.SplitN(driverOpt, "=", 2)
if len(parts) != 2 { if len(parts) != 2 {

@ -95,7 +95,7 @@ github.com/containerd/fifo
github.com/containerd/typeurl github.com/containerd/typeurl
# github.com/davecgh/go-spew v1.1.1 # github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew github.com/davecgh/go-spew/spew
# github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0 # github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0 => github.com/tiborvass/cli v0.0.0-20190419012645-1ed02c40fe68
github.com/docker/cli/cli/compose/loader github.com/docker/cli/cli/compose/loader
github.com/docker/cli/cli/compose/types github.com/docker/cli/cli/compose/types
github.com/docker/cli/cli-plugins/manager github.com/docker/cli/cli-plugins/manager
@ -103,13 +103,13 @@ github.com/docker/cli/cli-plugins/plugin
github.com/docker/cli/cli/command github.com/docker/cli/cli/command
github.com/docker/cli/cli/flags github.com/docker/cli/cli/flags
github.com/docker/cli/cli github.com/docker/cli/cli
github.com/docker/cli/cli/config
github.com/docker/cli/cli/context/docker github.com/docker/cli/cli/context/docker
github.com/docker/cli/opts github.com/docker/cli/opts
github.com/docker/cli/cli/config/types github.com/docker/cli/cli/config/types
github.com/docker/cli/cli/compose/interpolation github.com/docker/cli/cli/compose/interpolation
github.com/docker/cli/cli/compose/schema github.com/docker/cli/cli/compose/schema
github.com/docker/cli/cli/compose/template github.com/docker/cli/cli/compose/template
github.com/docker/cli/cli/config
github.com/docker/cli/cli/config/configfile github.com/docker/cli/cli/config/configfile
github.com/docker/cli/cli/connhelper github.com/docker/cli/cli/connhelper
github.com/docker/cli/cli/context github.com/docker/cli/cli/context

Loading…
Cancel
Save