From a7e2c3ea1edd195df98cb62bc353fcbf034764cd Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 4 Nov 2022 13:46:36 +0100 Subject: [PATCH] cli/command: add Cli.CurrentVersion() function This internalizes constructing the Client(), which allows us to provide fallbacks when trying to determin the current API version. Signed-off-by: Sebastiaan van Stijn --- cli/command/cli.go | 10 ++++++++++ cli/command/container/run.go | 2 +- cli/command/system/version.go | 2 +- cmd/docker/docker.go | 17 ++++++++--------- internal/test/cli.go | 5 +++++ 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cli/command/cli.go b/cli/command/cli.go index f27d43a5f7..b6fb6b5124 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -55,6 +55,7 @@ type Cli interface { ServerInfo() ServerInfo NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) DefaultVersion() string + CurrentVersion() string ManifestStore() manifeststore.Store RegistryClient(bool) registryclient.RegistryClient ContentTrustEnabled() bool @@ -86,6 +87,15 @@ func (cli *DockerCli) DefaultVersion() string { return api.DefaultVersion } +// CurrentVersion returns the API version currently negotiated, or the default +// version otherwise. +func (cli *DockerCli) CurrentVersion() string { + if cli.client == nil { + return api.DefaultVersion + } + return cli.client.ClientVersion() +} + // Client returns the APIClient func (cli *DockerCli) Client() client.APIClient { return cli.client diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 037d580fba..5cdcffc23d 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -111,7 +111,7 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt reportError(dockerCli.Err(), "run", err.Error(), true) return cli.StatusError{StatusCode: 125} } - if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil { + if err = validateAPIVersion(containerConfig, dockerCli.CurrentVersion()); err != nil { reportError(dockerCli.Err(), "run", err.Error(), true) return cli.StatusError{StatusCode: 125} } diff --git a/cli/command/system/version.go b/cli/command/system/version.go index d573681ff7..3ead03215c 100644 --- a/cli/command/system/version.go +++ b/cli/command/system/version.go @@ -136,7 +136,7 @@ func runVersion(dockerCli command.Cli, opts *versionOptions) error { Client: clientVersion{ Platform: struct{ Name string }{version.PlatformName}, Version: version.Version, - APIVersion: dockerCli.Client().ClientVersion(), + APIVersion: dockerCli.CurrentVersion(), DefaultAPIVersion: dockerCli.DefaultVersion(), GoVersion: runtime.Version(), GitCommit: version.GitCommit, diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index c175ef64cb..0105c7fb58 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -14,7 +14,6 @@ import ( cliflags "github.com/docker/cli/cli/flags" "github.com/docker/cli/cli/version" "github.com/docker/docker/api/types/versions" - "github.com/docker/docker/client" "github.com/moby/buildkit/util/appcontext" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -274,7 +273,7 @@ func main() { } type versionDetails interface { - Client() client.APIClient + CurrentVersion() string ServerInfo() command.ServerInfo } @@ -333,7 +332,7 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) error { return false } } - versionOlderThan = func(v string) bool { return versions.LessThan(details.Client().ClientVersion(), v) } + versionOlderThan = func(v string) bool { return versions.LessThan(details.CurrentVersion(), v) } ) cmd.Flags().VisitAll(func(f *pflag.Flag) { @@ -390,8 +389,8 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error { if !f.Changed { return } - if !isVersionSupported(f, details.Client().ClientVersion()) { - errs = append(errs, fmt.Sprintf(`"--%s" requires API version %s, but the Docker daemon API version is %s`, f.Name, getFlagAnnotation(f, "version"), details.Client().ClientVersion())) + if !isVersionSupported(f, details.CurrentVersion()) { + errs = append(errs, fmt.Sprintf(`"--%s" requires API version %s, but the Docker daemon API version is %s`, f.Name, getFlagAnnotation(f, "version"), details.CurrentVersion())) return } if !isOSTypeSupported(f, details.ServerInfo().OSType) { @@ -417,11 +416,11 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error { func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error { // Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack` for curr := cmd; curr != nil; curr = curr.Parent() { - if cmdVersion, ok := curr.Annotations["version"]; ok && versions.LessThan(details.Client().ClientVersion(), cmdVersion) { - return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, details.Client().ClientVersion()) + if cmdVersion, ok := curr.Annotations["version"]; ok && versions.LessThan(details.CurrentVersion(), cmdVersion) { + return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, details.CurrentVersion()) } - if os, ok := curr.Annotations["ostype"]; ok && os != details.ServerInfo().OSType { - return fmt.Errorf("%s is only supported on a Docker daemon running on %s, but the Docker daemon is running on %s", cmd.CommandPath(), os, details.ServerInfo().OSType) + if ost, ok := curr.Annotations["ostype"]; ok && ost != details.ServerInfo().OSType { + return fmt.Errorf("%s is only supported on a Docker daemon running on %s, but the Docker daemon is running on %s", cmd.CommandPath(), ost, details.ServerInfo().OSType) } if _, ok := curr.Annotations["experimental"]; ok && !details.ServerInfo().HasExperimental { return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath()) diff --git a/internal/test/cli.go b/internal/test/cli.go index 62bf6351e7..db800bec8c 100644 --- a/internal/test/cli.go +++ b/internal/test/cli.go @@ -101,6 +101,11 @@ func (c *FakeCli) Client() client.APIClient { return c.client } +// CurrentVersion returns the API version used by FakeCli. +func (c *FakeCli) CurrentVersion() string { + return c.DefaultVersion() +} + // Out returns the output stream (stdout) the cli should write on func (c *FakeCli) Out() *streams.Out { return c.out