Migrate volume commands to cobra.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
6bc3e23f65
commit
69264beb40
|
|
@ -60,6 +60,21 @@ func (cli *DockerCli) Initialize() error {
|
||||||
return cli.init()
|
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
|
// 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.
|
// from a non-tty client input stream, and if so, returns an error.
|
||||||
func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) 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 {
|
cli.init = func() error {
|
||||||
clientFlags.PostParse()
|
clientFlags.PostParse()
|
||||||
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
|
cli.configFile = LoadDefaultConfigFile(err)
|
||||||
if e != nil {
|
|
||||||
fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e)
|
|
||||||
}
|
|
||||||
if !configFile.ContainsAuth() {
|
|
||||||
credentials.DetectDefaultStore(configFile)
|
|
||||||
}
|
|
||||||
cli.configFile = configFile
|
|
||||||
|
|
||||||
host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions)
|
client, err := NewAPIClientFromFlags(clientFlags, cli.configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
cli.client = client
|
||||||
|
|
||||||
if cli.in != nil {
|
if cli.in != nil {
|
||||||
|
|
@ -176,6 +164,45 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cliflags.Cl
|
||||||
return cli
|
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) {
|
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, err error) {
|
||||||
switch len(hosts) {
|
switch len(hosts) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,6 @@ func (cli *DockerCli) Command(name string) func(...string) error {
|
||||||
"unpause": cli.CmdUnpause,
|
"unpause": cli.CmdUnpause,
|
||||||
"update": cli.CmdUpdate,
|
"update": cli.CmdUpdate,
|
||||||
"version": cli.CmdVersion,
|
"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,
|
"wait": cli.CmdWait,
|
||||||
}[name]
|
}[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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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}}
|
||||||
|
`
|
||||||
|
|
@ -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/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api/client"
|
"github.com/docker/docker/api/client"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
|
"github.com/docker/docker/cli/cobraadaptor"
|
||||||
cliflags "github.com/docker/docker/cli/flags"
|
cliflags "github.com/docker/docker/cli/flags"
|
||||||
"github.com/docker/docker/cliconfig"
|
"github.com/docker/docker/cliconfig"
|
||||||
"github.com/docker/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
|
|
@ -31,6 +32,8 @@ func main() {
|
||||||
|
|
||||||
flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
|
flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
|
||||||
|
|
||||||
|
cobraAdaptor := cobraadaptor.NewCobraAdaptor(clientFlags)
|
||||||
|
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n docker [ --help | -v | --version ]\n\n")
|
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")
|
fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
|
||||||
|
|
@ -40,8 +43,8 @@ func main() {
|
||||||
|
|
||||||
help := "\nCommands:\n"
|
help := "\nCommands:\n"
|
||||||
|
|
||||||
dockerCommands := sortCommands(cli.DockerCommandUsage)
|
dockerCommands := append(cli.DockerCommandUsage, cobraAdaptor.Usage()...)
|
||||||
for _, cmd := range dockerCommands {
|
for _, cmd := range sortCommands(dockerCommands) {
|
||||||
help += fmt.Sprintf(" %-10.10s%s\n", cmd.Name, cmd.Description)
|
help += fmt.Sprintf(" %-10.10s%s\n", cmd.Name, cmd.Description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +68,7 @@ func main() {
|
||||||
|
|
||||||
clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
|
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 err := c.Run(flag.Args()...); err != nil {
|
||||||
if sterr, ok := err.(cli.StatusError); ok {
|
if sterr, ok := err.(cli.StatusError); ok {
|
||||||
if sterr.Status != "" {
|
if sterr.Status != "" {
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,11 @@ func (opts *MapOpts) String() string {
|
||||||
return fmt.Sprintf("%v", map[string]string((opts.values)))
|
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.
|
// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
|
||||||
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
|
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
|
||||||
if values == nil {
|
if values == nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue