Refactor stack command

- Define command and subcommands only once
- Use annotations for k8s or swarm specific flags or subcommands

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester
2017-12-04 12:30:39 +01:00
committed by Silvin Lubecki
parent 0508c09494
commit dedd0db51a
49 changed files with 780 additions and 591 deletions

View File

@ -195,6 +195,7 @@ type versionDetails interface {
Client() client.APIClient
ClientInfo() command.ClientInfo
ServerInfo() command.ServerInfo
ClientInfo() command.ClientInfo
}
func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
@ -202,6 +203,7 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
osType := details.ServerInfo().OSType
hasExperimental := details.ServerInfo().HasExperimental
hasExperimentalCLI := details.ClientInfo().HasExperimental
hasKubernetes := details.ClientInfo().HasKubernetes
cmd.Flags().VisitAll(func(f *pflag.Flag) {
// hide experimental flags
@ -215,6 +217,15 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
f.Hidden = true
}
}
if !hasKubernetes {
if _, ok := f.Annotations["kubernetes"]; ok {
f.Hidden = true
}
} else {
if _, ok := f.Annotations["swarm"]; ok {
f.Hidden = true
}
}
// hide flags not supported by the server
if !isOSTypeSupported(f, osType) || !isVersionSupported(f, clientVersion) {
@ -235,6 +246,16 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
}
}
if !hasKubernetes {
if _, ok := subcmd.Annotations["kubernetes"]; ok {
subcmd.Hidden = true
}
} else {
if _, ok := subcmd.Annotations["swarm"]; ok {
subcmd.Hidden = true
}
}
// hide subcommands not supported by the server
if subcmdVersion, ok := subcmd.Annotations["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
subcmd.Hidden = true
@ -243,23 +264,22 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
}
func isSupported(cmd *cobra.Command, details versionDetails) error {
if err := areSubcommandsSupported(cmd, details); err != nil {
return err
}
if err := areFlagsSupported(cmd, details); err != nil {
return err
}
return nil
}
func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
clientVersion := details.Client().ClientVersion()
osType := details.ServerInfo().OSType
hasExperimental := details.ServerInfo().HasExperimental
hasExperimentalCLI := details.ClientInfo().HasExperimental
// 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(clientVersion, cmdVersion) {
return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, clientVersion)
}
if _, ok := curr.Annotations["experimental"]; ok && !hasExperimental {
return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath())
}
if _, ok := curr.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
return fmt.Errorf("%s is only supported when experimental cli features are enabled", cmd.CommandPath())
}
}
hasKubernetes := details.ClientInfo().HasKubernetes
errs := []string{}
@ -279,12 +299,45 @@ func isSupported(cmd *cobra.Command, details versionDetails) error {
if _, ok := f.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported when experimental cli features are enabled", f.Name))
}
if _, ok := f.Annotations["kubernetes"]; ok && !hasKubernetes {
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker cli with kubernetes features enabled", f.Name))
}
if _, ok := f.Annotations["swarm"]; ok && hasKubernetes {
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker cli with swarm features enabled", f.Name))
}
}
})
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
}
// Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack`
func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error {
clientVersion := details.Client().ClientVersion()
hasExperimental := details.ServerInfo().HasExperimental
hasExperimentalCLI := details.ClientInfo().HasExperimental
hasKubernetes := details.ClientInfo().HasKubernetes
// 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(clientVersion, cmdVersion) {
return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, clientVersion)
}
if _, ok := curr.Annotations["experimental"]; ok && !hasExperimental {
return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath())
}
if _, ok := curr.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
return fmt.Errorf("%s is only supported when experimental cli features are enabled", cmd.CommandPath())
}
if _, ok := curr.Annotations["kubernetes"]; ok && !hasKubernetes {
return fmt.Errorf("%s is only supported on a Docker cli with kubernetes features enabled", cmd.CommandPath())
}
if _, ok := curr.Annotations["swarm"]; ok && hasKubernetes {
return fmt.Errorf("%s is only supported on a Docker cli with swarm features enabled", cmd.CommandPath())
}
}
return nil
}