Migrate volume commands to cobra.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
6bc3e23f65
commit
69264beb40
12 changed files with 427 additions and 218 deletions
|
@ -60,6 +60,21 @@ func (cli *DockerCli) Initialize() error {
|
|||
return cli.init()
|
||||
}
|
||||
|
||||
// Client returns the APIClient
|
||||
func (cli *DockerCli) Client() client.APIClient {
|
||||
return cli.client
|
||||
}
|
||||
|
||||
// Out returns the writer used for stdout
|
||||
func (cli *DockerCli) Out() io.Writer {
|
||||
return cli.out
|
||||
}
|
||||
|
||||
// Err returns the writer used for stderr
|
||||
func (cli *DockerCli) Err() io.Writer {
|
||||
return cli.err
|
||||
}
|
||||
|
||||
// CheckTtyInput checks if we are trying to attach to a container tty
|
||||
// from a non-tty client input stream, and if so, returns an error.
|
||||
func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error {
|
||||
|
@ -127,40 +142,13 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cliflags.Cl
|
|||
|
||||
cli.init = func() error {
|
||||
clientFlags.PostParse()
|
||||
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
|
||||
if e != nil {
|
||||
fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e)
|
||||
}
|
||||
if !configFile.ContainsAuth() {
|
||||
credentials.DetectDefaultStore(configFile)
|
||||
}
|
||||
cli.configFile = configFile
|
||||
cli.configFile = LoadDefaultConfigFile(err)
|
||||
|
||||
host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions)
|
||||
client, err := NewAPIClientFromFlags(clientFlags, cli.configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
customHeaders := cli.configFile.HTTPHeaders
|
||||
if customHeaders == nil {
|
||||
customHeaders = map[string]string{}
|
||||
}
|
||||
customHeaders["User-Agent"] = clientUserAgent()
|
||||
|
||||
verStr := api.DefaultVersion
|
||||
if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" {
|
||||
verStr = tmpStr
|
||||
}
|
||||
|
||||
httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := client.NewClient(host, verStr, httpClient, customHeaders)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli.client = client
|
||||
|
||||
if cli.in != nil {
|
||||
|
@ -176,6 +164,45 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cliflags.Cl
|
|||
return cli
|
||||
}
|
||||
|
||||
// LoadDefaultConfigFile attempts to load the default config file and returns
|
||||
// an initialized ConfigFile struct if none is found.
|
||||
func LoadDefaultConfigFile(err io.Writer) *configfile.ConfigFile {
|
||||
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
|
||||
if e != nil {
|
||||
fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e)
|
||||
}
|
||||
if !configFile.ContainsAuth() {
|
||||
credentials.DetectDefaultStore(configFile)
|
||||
}
|
||||
return configFile
|
||||
}
|
||||
|
||||
// NewAPIClientFromFlags creates a new APIClient from command line flags
|
||||
func NewAPIClientFromFlags(clientFlags *cliflags.ClientFlags, configFile *configfile.ConfigFile) (client.APIClient, error) {
|
||||
host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions)
|
||||
if err != nil {
|
||||
return &client.Client{}, err
|
||||
}
|
||||
|
||||
customHeaders := configFile.HTTPHeaders
|
||||
if customHeaders == nil {
|
||||
customHeaders = map[string]string{}
|
||||
}
|
||||
customHeaders["User-Agent"] = clientUserAgent()
|
||||
|
||||
verStr := api.DefaultVersion
|
||||
if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" {
|
||||
verStr = tmpStr
|
||||
}
|
||||
|
||||
httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions)
|
||||
if err != nil {
|
||||
return &client.Client{}, err
|
||||
}
|
||||
|
||||
return client.NewClient(host, verStr, httpClient, customHeaders)
|
||||
}
|
||||
|
||||
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, err error) {
|
||||
switch len(hosts) {
|
||||
case 0:
|
||||
|
|
|
@ -49,11 +49,6 @@ func (cli *DockerCli) Command(name string) func(...string) error {
|
|||
"unpause": cli.CmdUnpause,
|
||||
"update": cli.CmdUpdate,
|
||||
"version": cli.CmdVersion,
|
||||
"volume": cli.CmdVolume,
|
||||
"volume create": cli.CmdVolumeCreate,
|
||||
"volume inspect": cli.CmdVolumeInspect,
|
||||
"volume ls": cli.CmdVolumeLs,
|
||||
"volume rm": cli.CmdVolumeRm,
|
||||
"wait": cli.CmdWait,
|
||||
}[name]
|
||||
}
|
||||
|
|
|
@ -1,181 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
)
|
||||
|
||||
// CmdVolume is the parent subcommand for all volume commands
|
||||
//
|
||||
// Usage: docker volume <COMMAND> <OPTS>
|
||||
func (cli *DockerCli) CmdVolume(args ...string) error {
|
||||
description := Cli.DockerCommands["volume"].Description + "\n\nCommands:\n"
|
||||
commands := [][]string{
|
||||
{"create", "Create a volume"},
|
||||
{"inspect", "Return low-level information on a volume"},
|
||||
{"ls", "List volumes"},
|
||||
{"rm", "Remove a volume"},
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
description += "\nRun 'docker volume COMMAND --help' for more information on a command"
|
||||
cmd := Cli.Subcmd("volume", []string{"[COMMAND]"}, description, false)
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdVolumeLs outputs a list of Docker volumes.
|
||||
//
|
||||
// Usage: docker volume ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdVolumeLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume ls", nil, "List volumes", true)
|
||||
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display volume names")
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
var err error
|
||||
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
volumes, err := cli.client.VolumeList(context.Background(), volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
if !*quiet {
|
||||
for _, warn := range volumes.Warnings {
|
||||
fmt.Fprintln(cli.err, warn)
|
||||
}
|
||||
fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
sort.Sort(byVolumeName(volumes.Volumes))
|
||||
for _, vol := range volumes.Volumes {
|
||||
if *quiet {
|
||||
fmt.Fprintln(w, vol.Name)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\n", vol.Driver, vol.Name)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
type byVolumeName []*types.Volume
|
||||
|
||||
func (r byVolumeName) Len() int { return len(r) }
|
||||
func (r byVolumeName) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byVolumeName) Less(i, j int) bool {
|
||||
return r[i].Name < r[j].Name
|
||||
}
|
||||
|
||||
// CmdVolumeInspect displays low-level information on one or more volumes.
|
||||
//
|
||||
// Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
|
||||
func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume inspect", []string{"VOLUME [VOLUME...]"}, "Return low-level information on a volume", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.VolumeInspect(ctx, name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdVolumeCreate creates a new volume.
|
||||
//
|
||||
// Usage: docker volume create [OPTIONS]
|
||||
func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume create", nil, "Create a volume", true)
|
||||
flDriver := cmd.String([]string{"d", "-driver"}, "local", "Specify volume driver name")
|
||||
flName := cmd.String([]string{"-name"}, "", "Specify volume name")
|
||||
|
||||
flDriverOpts := opts.NewMapOpts(nil, nil)
|
||||
cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
|
||||
|
||||
flLabels := opts.NewListOpts(nil)
|
||||
cmd.Var(&flLabels, []string{"-label"}, "Set metadata for a volume")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volReq := types.VolumeCreateRequest{
|
||||
Driver: *flDriver,
|
||||
DriverOpts: flDriverOpts.GetAll(),
|
||||
Name: *flName,
|
||||
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
|
||||
}
|
||||
|
||||
vol, err := cli.client.VolumeCreate(context.Background(), volReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "%s\n", vol.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdVolumeRm removes one or more volumes.
|
||||
//
|
||||
// Usage: docker volume rm VOLUME [VOLUME...]
|
||||
func (cli *DockerCli) CmdVolumeRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume rm", []string{"VOLUME [VOLUME...]"}, "Remove a volume", true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var status = 0
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.VolumeRemove(ctx, name); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
22
api/client/volume/cmd.go
Normal file
22
api/client/volume/cmd.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/docker/api/client"
|
||||
)
|
||||
|
||||
// NewVolumeCommand returns a cobra command for `volume` subcommands
|
||||
func NewVolumeCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "volume",
|
||||
Short: "Manage Docker volumes",
|
||||
}
|
||||
cmd.AddCommand(
|
||||
newCreateCommand(dockerCli),
|
||||
newInspectCommand(dockerCli),
|
||||
newListCommand(dockerCli),
|
||||
newRemoveCommand(dockerCli),
|
||||
)
|
||||
return cmd
|
||||
}
|
58
api/client/volume/create.go
Normal file
58
api/client/volume/create.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/opts"
|
||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type createOptions struct {
|
||||
name string
|
||||
driver string
|
||||
driverOpts opts.MapOpts
|
||||
labels []string
|
||||
}
|
||||
|
||||
func newCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||
var opts createOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a volume",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runCreate(dockerCli, opts)
|
||||
},
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&opts.driver, "driver", "d", "local", "Specify volume driver name")
|
||||
flags.StringVar(&opts.name, "name", "", "Specify volume name")
|
||||
flags.VarP(&opts.driverOpts, "opt", "o", "Set driver specific options")
|
||||
flags.StringSliceVar(&opts.labels, "label", []string{}, "Set metadata for a volume")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCreate(dockerCli *client.DockerCli, opts createOptions) error {
|
||||
client := dockerCli.Client()
|
||||
|
||||
volReq := types.VolumeCreateRequest{
|
||||
Driver: opts.driver,
|
||||
DriverOpts: opts.driverOpts.GetAll(),
|
||||
Name: opts.name,
|
||||
Labels: runconfigopts.ConvertKVStringsToMap(opts.labels),
|
||||
}
|
||||
|
||||
vol, err := client.VolumeCreate(context.Background(), volReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(dockerCli.Out(), "%s\n", vol.Name)
|
||||
return nil
|
||||
}
|
46
api/client/volume/inspect.go
Normal file
46
api/client/volume/inspect.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/api/client/inspect"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type inspectOptions struct {
|
||||
format string
|
||||
names []string
|
||||
}
|
||||
|
||||
func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||
var opts inspectOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "inspect [OPTIONS] VOLUME [VOLUME...]",
|
||||
Short: "Return low-level information on a volume",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := cli.MinRequiredArgs(args, 1, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
opts.names = args
|
||||
return runInspect(dockerCli, opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
|
||||
client := dockerCli.Client()
|
||||
|
||||
getVolFunc := func(name string) (interface{}, []byte, error) {
|
||||
i, err := client.VolumeInspect(context.Background(), name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getVolFunc)
|
||||
}
|
84
api/client/volume/list.go
Normal file
84
api/client/volume/list.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type byVolumeName []*types.Volume
|
||||
|
||||
func (r byVolumeName) Len() int { return len(r) }
|
||||
func (r byVolumeName) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byVolumeName) Less(i, j int) bool {
|
||||
return r[i].Name < r[j].Name
|
||||
}
|
||||
|
||||
type listOptions struct {
|
||||
quiet bool
|
||||
filter []string
|
||||
}
|
||||
|
||||
func newListCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||
var opts listOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Short: "List volumes",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runList(dockerCli, opts)
|
||||
},
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display volume names")
|
||||
flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Provide filter values (i.e. 'dangling=true')")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runList(dockerCli *client.DockerCli, opts listOptions) error {
|
||||
client := dockerCli.Client()
|
||||
|
||||
volFilterArgs := filters.NewArgs()
|
||||
for _, f := range opts.filter {
|
||||
var err error
|
||||
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
volumes, err := client.VolumeList(context.Background(), volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(dockerCli.Out(), 20, 1, 3, ' ', 0)
|
||||
if !opts.quiet {
|
||||
for _, warn := range volumes.Warnings {
|
||||
fmt.Fprintln(dockerCli.Err(), warn)
|
||||
}
|
||||
fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
sort.Sort(byVolumeName(volumes.Volumes))
|
||||
for _, vol := range volumes.Volumes {
|
||||
if opts.quiet {
|
||||
fmt.Fprintln(w, vol.Name)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\n", vol.Driver, vol.Name)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
44
api/client/volume/remove.go
Normal file
44
api/client/volume/remove.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newRemoveCommand(dockerCli *client.DockerCli) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "rm VOLUME [VOLUME]...",
|
||||
Aliases: []string{"remove"},
|
||||
Short: "Remove a volume",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := cli.MinRequiredArgs(args, 1, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
return runRemove(dockerCli, args)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runRemove(dockerCli *client.DockerCli, volumes []string) error {
|
||||
client := dockerCli.Client()
|
||||
var status = 0
|
||||
|
||||
for _, name := range volumes {
|
||||
if err := client.VolumeRemove(context.Background(), name); err != nil {
|
||||
fmt.Fprintf(dockerCli.Err(), "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(dockerCli.Err(), "%s\n", name)
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
return cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
83
cli/cobraadaptor/adaptor.go
Normal file
83
cli/cobraadaptor/adaptor.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package cobraadaptor
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/api/client/volume"
|
||||
"github.com/docker/docker/cli"
|
||||
cliflags "github.com/docker/docker/cli/flags"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// CobraAdaptor is an adaptor for supporting spf13/cobra commands in the
|
||||
// docker/cli framework
|
||||
type CobraAdaptor struct {
|
||||
rootCmd *cobra.Command
|
||||
dockerCli *client.DockerCli
|
||||
}
|
||||
|
||||
// NewCobraAdaptor returns a new handler
|
||||
func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "docker",
|
||||
}
|
||||
rootCmd.SetUsageTemplate(usageTemplate)
|
||||
|
||||
stdin, stdout, stderr := term.StdStreams()
|
||||
dockerCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
|
||||
|
||||
rootCmd.AddCommand(
|
||||
volume.NewVolumeCommand(dockerCli),
|
||||
)
|
||||
return CobraAdaptor{
|
||||
rootCmd: rootCmd,
|
||||
dockerCli: dockerCli,
|
||||
}
|
||||
}
|
||||
|
||||
// Usage returns the list of commands and their short usage string for
|
||||
// all top level cobra commands.
|
||||
func (c CobraAdaptor) Usage() []cli.Command {
|
||||
cmds := []cli.Command{}
|
||||
for _, cmd := range c.rootCmd.Commands() {
|
||||
cmds = append(cmds, cli.Command{Name: cmd.Use, Description: cmd.Short})
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
||||
func (c CobraAdaptor) run(cmd string, args []string) error {
|
||||
c.dockerCli.Initialize()
|
||||
// Prepend the command name to support normal cobra command delegation
|
||||
c.rootCmd.SetArgs(append([]string{cmd}, args...))
|
||||
return c.rootCmd.Execute()
|
||||
}
|
||||
|
||||
// Command returns a cli command handler if one exists
|
||||
func (c CobraAdaptor) Command(name string) func(...string) error {
|
||||
for _, cmd := range c.rootCmd.Commands() {
|
||||
if cmd.Name() == name {
|
||||
return func(args ...string) error {
|
||||
return c.run(name, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var usageTemplate = `Usage: {{if .Runnable}}{{if .HasFlags}}{{appendIfNotPresent .UseLine "[OPTIONS]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasSubCommands}}{{ .CommandPath}} COMMAND {{end}}{{if gt .Aliases 0}}
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}
|
||||
{{end}}{{if .HasExample}}
|
||||
|
||||
Examples:
|
||||
{{ .Example }}{{end}}{{ if .HasLocalFlags}}
|
||||
|
||||
Options:
|
||||
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableSubCommands}}
|
||||
|
||||
Commands:{{range .Commands}}{{if .IsAvailableCommand}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasSubCommands }}
|
||||
|
||||
Run '{{.CommandPath}} COMMAND --help' for more information on a command.{{end}}
|
||||
`
|
23
cli/required.go
Normal file
23
cli/required.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// MinRequiredArgs checks if the minimum number of args exists, and returns an
|
||||
// error if they do not.
|
||||
func MinRequiredArgs(args []string, min int, cmd *cobra.Command) error {
|
||||
if len(args) >= min {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf(
|
||||
"\"%s\" requires at least %d argument(s).\n\nUsage: %s\n\n%s",
|
||||
cmd.CommandPath(),
|
||||
min,
|
||||
cmd.UseLine(),
|
||||
cmd.Short,
|
||||
)
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/cobraadaptor"
|
||||
cliflags "github.com/docker/docker/cli/flags"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -31,6 +32,8 @@ func main() {
|
|||
|
||||
flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
|
||||
|
||||
cobraAdaptor := cobraadaptor.NewCobraAdaptor(clientFlags)
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n docker [ --help | -v | --version ]\n\n")
|
||||
fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
|
||||
|
@ -40,8 +43,8 @@ func main() {
|
|||
|
||||
help := "\nCommands:\n"
|
||||
|
||||
dockerCommands := sortCommands(cli.DockerCommandUsage)
|
||||
for _, cmd := range dockerCommands {
|
||||
dockerCommands := append(cli.DockerCommandUsage, cobraAdaptor.Usage()...)
|
||||
for _, cmd := range sortCommands(dockerCommands) {
|
||||
help += fmt.Sprintf(" %-10.10s%s\n", cmd.Name, cmd.Description)
|
||||
}
|
||||
|
||||
|
@ -65,7 +68,7 @@ func main() {
|
|||
|
||||
clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
|
||||
|
||||
c := cli.New(clientCli, NewDaemonProxy())
|
||||
c := cli.New(clientCli, NewDaemonProxy(), cobraAdaptor)
|
||||
if err := c.Run(flag.Args()...); err != nil {
|
||||
if sterr, ok := err.(cli.StatusError); ok {
|
||||
if sterr.Status != "" {
|
||||
|
|
|
@ -163,6 +163,11 @@ func (opts *MapOpts) String() string {
|
|||
return fmt.Sprintf("%v", map[string]string((opts.values)))
|
||||
}
|
||||
|
||||
// Type returns a string name for this Option type
|
||||
func (opts *MapOpts) Type() string {
|
||||
return "map"
|
||||
}
|
||||
|
||||
// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
|
||||
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
|
||||
if values == nil {
|
||||
|
|
Loading…
Reference in a new issue