diff --git a/command/checkpoint/cmd.go b/command/checkpoint/cmd.go index 7f9e537779..f186232a4d 100644 --- a/command/checkpoint/cmd.go +++ b/command/checkpoint/cmd.go @@ -1,8 +1,6 @@ package checkpoint import ( - "fmt" - "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/spf13/cobra" @@ -15,9 +13,10 @@ func NewCheckpointCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage checkpoints", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, - Tags: map[string]string{"experimental": ""}, + Tags: map[string]string{"experimental": "", "version": "1.25"}, } cmd.AddCommand( newCreateCommand(dockerCli), diff --git a/command/cli.go b/command/cli.go index 33a26c4c64..ef9de2edf1 100644 --- a/command/cli.go +++ b/command/cli.go @@ -10,6 +10,7 @@ import ( "runtime" "github.com/docker/docker/api" + "github.com/docker/docker/api/types/versions" cliflags "github.com/docker/docker/cli/flags" "github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig/configfile" @@ -32,21 +33,24 @@ type Streams interface { // DockerCli represents the docker command line client. // Instances of the client can be returned from NewDockerCli. type DockerCli struct { - configFile *configfile.ConfigFile - in *InStream - out *OutStream - err io.Writer - keyFile string - client client.APIClient + configFile *configfile.ConfigFile + in *InStream + out *OutStream + err io.Writer + keyFile string + client client.APIClient + hasExperimental bool + defaultVersion string } -// HasExperimental returns true if experimental features are accessible +// HasExperimental returns true if experimental features are accessible. func (cli *DockerCli) HasExperimental() bool { - if cli.client == nil { - return false - } - enabled, _ := cli.client.Ping(context.Background()) - return enabled + return cli.hasExperimental +} + +// DefaultVersion returns api.defaultVersion of DOCKER_API_VERSION if specified. +func (cli *DockerCli) DefaultVersion() string { + return cli.defaultVersion } // Client returns the APIClient @@ -93,12 +97,28 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error { if err != nil { return err } + + cli.defaultVersion = cli.client.ClientVersion() + if opts.Common.TrustKey == "" { cli.keyFile = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) } else { cli.keyFile = opts.Common.TrustKey } + if ping, err := cli.client.Ping(context.Background()); err == nil { + cli.hasExperimental = ping.Experimental + + // since the new header was added in 1.25, assume server is 1.24 if header is not present. + if ping.APIVersion == "" { + ping.APIVersion = "1.24" + } + + // if server version is lower than the current cli, downgrade + if versions.LessThan(ping.APIVersion, cli.client.ClientVersion()) { + cli.client.UpdateClientVersion(ping.APIVersion) + } + } return nil } diff --git a/command/container/cmd.go b/command/container/cmd.go index f06b863b58..075f936bd9 100644 --- a/command/container/cmd.go +++ b/command/container/cmd.go @@ -1,8 +1,6 @@ package container import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewContainerCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage containers", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/container/exec.go b/command/container/exec.go index 48964693b2..84eba113cf 100644 --- a/command/container/exec.go +++ b/command/container/exec.go @@ -59,6 +59,7 @@ func NewExecCommand(dockerCli *command.DockerCli) *cobra.Command { flags.StringVarP(&opts.user, "user", "u", "", "Username or UID (format: [:])") flags.BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the command") flags.VarP(opts.env, "env", "e", "Set environment variables") + flags.SetAnnotation("env", "version", []string{"1.25"}) return cmd } diff --git a/command/container/prune.go b/command/container/prune.go index 99a97f6cd8..ec6b0e3147 100644 --- a/command/container/prune.go +++ b/command/container/prune.go @@ -35,6 +35,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command { fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) return nil }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/image/build.go b/command/image/build.go index 604888b6fa..ebec87d641 100644 --- a/command/image/build.go +++ b/command/image/build.go @@ -113,6 +113,7 @@ func NewBuildCommand(dockerCli *command.DockerCli) *cobra.Command { flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer") flags.SetAnnotation("squash", "experimental", nil) + flags.SetAnnotation("squash", "version", []string{"1.25"}) return cmd } @@ -144,7 +145,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error { progBuff io.Writer buildBuff io.Writer ) - + specifiedContext := options.context progBuff = dockerCli.Out() buildBuff = dockerCli.Out() diff --git a/command/image/cmd.go b/command/image/cmd.go index 6f8e7b7d4b..dc98257438 100644 --- a/command/image/cmd.go +++ b/command/image/cmd.go @@ -1,8 +1,6 @@ package image import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewImageCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage images", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( @@ -33,6 +32,5 @@ func NewImageCommand(dockerCli *command.DockerCli) *cobra.Command { newInspectCommand(dockerCli), NewPruneCommand(dockerCli), ) - return cmd } diff --git a/command/image/prune.go b/command/image/prune.go index 46bd56cb10..ea84cda877 100644 --- a/command/image/prune.go +++ b/command/image/prune.go @@ -36,6 +36,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command { fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) return nil }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/network/cmd.go b/command/network/cmd.go index 77c8e4908e..c2a7e83dd8 100644 --- a/command/network/cmd.go +++ b/command/network/cmd.go @@ -1,8 +1,6 @@ package network import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewNetworkCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage networks", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/network/prune.go b/command/network/prune.go index 00e05d3bdf..f2f8cc20c4 100644 --- a/command/network/prune.go +++ b/command/network/prune.go @@ -33,6 +33,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command { } return nil }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/node/cmd.go b/command/node/cmd.go index c7d0cf8181..d70ee81789 100644 --- a/command/node/cmd.go +++ b/command/node/cmd.go @@ -1,8 +1,6 @@ package node import ( - "fmt" - "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" apiclient "github.com/docker/docker/client" @@ -17,7 +15,8 @@ func NewNodeCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage Swarm nodes", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/plugin/cmd.go b/command/plugin/cmd.go index c78f43a8d4..03d01c8882 100644 --- a/command/plugin/cmd.go +++ b/command/plugin/cmd.go @@ -1,8 +1,6 @@ package plugin import ( - "fmt" - "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/spf13/cobra" @@ -15,7 +13,8 @@ func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage plugins", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, Tags: map[string]string{"experimental": ""}, } diff --git a/command/service/cmd.go b/command/service/cmd.go index 9f342e1342..f4f7d00f91 100644 --- a/command/service/cmd.go +++ b/command/service/cmd.go @@ -1,8 +1,6 @@ package service import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage services", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/stack/cmd.go b/command/stack/cmd.go index 70afec9c6d..4189504403 100644 --- a/command/stack/cmd.go +++ b/command/stack/cmd.go @@ -1,8 +1,6 @@ package stack import ( - "fmt" - "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/spf13/cobra" @@ -15,9 +13,10 @@ func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage Docker stacks", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, - Tags: map[string]string{"experimental": ""}, + Tags: map[string]string{"experimental": "", "version": "1.25"}, } cmd.AddCommand( newConfigCommand(dockerCli), diff --git a/command/stack/deploy.go b/command/stack/deploy.go index b0f6b455a8..435a9193b4 100644 --- a/command/stack/deploy.go +++ b/command/stack/deploy.go @@ -36,7 +36,7 @@ func newDeployCommand(dockerCli *command.DockerCli) *cobra.Command { opts.namespace = strings.TrimSuffix(args[0], ".dab") return runDeploy(dockerCli, opts) }, - Tags: map[string]string{"experimental": ""}, + Tags: map[string]string{"experimental": "", "version": "1.25"}, } flags := cmd.Flags() diff --git a/command/swarm/cmd.go b/command/swarm/cmd.go index 9f9df53950..f0a6bcdeb8 100644 --- a/command/swarm/cmd.go +++ b/command/swarm/cmd.go @@ -1,8 +1,6 @@ package swarm import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewSwarmCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage Swarm", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/system/cmd.go b/command/system/cmd.go index 46caa2491c..9cd74b5d4b 100644 --- a/command/system/cmd.go +++ b/command/system/cmd.go @@ -1,8 +1,6 @@ package system import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -16,7 +14,8 @@ func NewSystemCommand(dockerCli *command.DockerCli) *cobra.Command { Short: "Manage Docker", Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( @@ -25,5 +24,6 @@ func NewSystemCommand(dockerCli *command.DockerCli) *cobra.Command { NewDiskUsageCommand(dockerCli), NewPruneCommand(dockerCli), ) + return cmd } diff --git a/command/system/df.go b/command/system/df.go index 293946c188..9f712484aa 100644 --- a/command/system/df.go +++ b/command/system/df.go @@ -23,6 +23,7 @@ func NewDiskUsageCommand(dockerCli *command.DockerCli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runDiskUsage(dockerCli, opts) }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/system/prune.go b/command/system/prune.go index c79bc6910e..92dddbdca6 100644 --- a/command/system/prune.go +++ b/command/system/prune.go @@ -26,6 +26,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runPrune(dockerCli, opts) }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/system/version.go b/command/system/version.go index 6040c79361..00a84a3cbc 100644 --- a/command/system/version.go +++ b/command/system/version.go @@ -1,6 +1,7 @@ package system import ( + "fmt" "runtime" "time" @@ -70,10 +71,15 @@ func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error { Status: "Template parsing error: " + err.Error()} } + APIVersion := dockerCli.Client().ClientVersion() + if defaultAPIVersion := dockerCli.DefaultVersion(); APIVersion != defaultAPIVersion { + APIVersion = fmt.Sprintf("%s (downgraded from %s)", APIVersion, defaultAPIVersion) + } + vd := types.VersionResponse{ Client: &types.Version{ Version: dockerversion.Version, - APIVersion: dockerCli.Client().ClientVersion(), + APIVersion: APIVersion, GoVersion: runtime.Version(), GitCommit: dockerversion.GitCommit, BuildTime: dockerversion.BuildTime, diff --git a/command/volume/cmd.go b/command/volume/cmd.go index f35181ffaf..39e4b7f46e 100644 --- a/command/volume/cmd.go +++ b/command/volume/cmd.go @@ -1,8 +1,6 @@ package volume import ( - "fmt" - "github.com/spf13/cobra" "github.com/docker/docker/cli" @@ -17,7 +15,8 @@ func NewVolumeCommand(dockerCli *command.DockerCli) *cobra.Command { Long: volumeDescription, Args: cli.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString()) + cmd.SetOutput(dockerCli.Err()) + cmd.HelpFunc()(cmd, args) }, } cmd.AddCommand( diff --git a/command/volume/prune.go b/command/volume/prune.go index a4bb0092d6..ac9c94451a 100644 --- a/command/volume/prune.go +++ b/command/volume/prune.go @@ -35,6 +35,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command { fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) return nil }, + Tags: map[string]string{"version": "1.25"}, } flags := cmd.Flags() diff --git a/command/volume/remove.go b/command/volume/remove.go index 213ad26ab5..f464bb3e1a 100644 --- a/command/volume/remove.go +++ b/command/volume/remove.go @@ -34,7 +34,7 @@ func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command { flags := cmd.Flags() flags.BoolVarP(&opts.force, "force", "f", false, "Force the removal of one or more volumes") - + flags.SetAnnotation("force", "version", []string{"1.25"}) return cmd }