Skip to content

Commit

Permalink
Merge pull request #524 from AkihiroSuda/unfork-cobra
Browse files Browse the repository at this point in the history
Unfork spf13/{cobra, pflag}
  • Loading branch information
AkihiroSuda authored Nov 18, 2021
2 parents 70bc9aa + c9d49e9 commit a81cb69
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 120 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1103,10 +1103,12 @@ Unimplemented `docker-compose ps` (V1) flags: `--quiet`, `--services`, `--filter
Unimplemented `docker compose ps` (V2) flags: `--format`, `--status`

## Global flags
- :nerd_face: :blue_square: `-a`, `--address`: containerd address, optionally with "unix://" prefix
- :whale: `-H`, `--host`: Docker-compatible alias for `-a`, `--address`
- :nerd_face: :blue_square: `-n`, `--namespace`: containerd namespace
- :nerd_face: :blue_square: `--address`: containerd address, optionally with "unix://" prefix
- :nerd_face: :blue_square: `-a`, `--host`, `-H`: deprecated aliases of `--address`
- :nerd_face: :blue_square: `--namespace`: containerd namespace
- :nerd_face: :blue_square: `-n`: deprecated alias of `--namespace`
- :nerd_face: :blue_square: `--snapshotter`: containerd snapshotter
- :nerd_face: :blue_square: `--storage-driver`: deprecated alias of `--snapshotter`
- :nerd_face: :blue_square: `--cni-path`: CNI binary path (default: `/opt/cni/bin`) [`$CNI_PATH`]
- :nerd_face: :blue_square: `--cni-netconfpath`: CNI netconf path (default: `/etc/cni/net.d`) [`$NETCONFPATH`]
- :nerd_face: :blue_square: `--data-root`: nerdctl data root, e.g. "/var/lib/nerdctl"
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/apparmor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func newApparmorCommand() *cobra.Command {
cmd := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "apparmor",
Short: "Manage AppArmor profiles",
RunE: unknownSubcommandAction,
Expand Down
10 changes: 1 addition & 9 deletions cmd/nerdctl/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (

"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func newBuildCommand() *cobra.Command {
Expand All @@ -45,14 +44,7 @@ func newBuildCommand() *cobra.Command {
SilenceUsage: true,
SilenceErrors: true,
}
buildCommand.Flags().AddFlag(
&pflag.Flag{
Name: "buildkit-host",
Usage: `BuildKit address`,
EnvVars: []string{"BUILDKIT_HOST"},
Value: pflag.NewStringValue(defaults.BuildKitHost(), new(string)),
},
)
AddStringFlag(buildCommand, "buildkit-host", nil, defaults.BuildKitHost(), "BUILDKIT_HOST", "BuildKit address")
buildCommand.Flags().StringArrayP("tag", "t", nil, "Name and optionally a tag in the 'name:tag' format")
buildCommand.Flags().StringP("file", "f", "", "Name of the Dockerfile")
buildCommand.Flags().String("target", "", "Set the target build stage to build")
Expand Down
16 changes: 9 additions & 7 deletions cmd/nerdctl/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ import (

func newComposeCommand() *cobra.Command {
var composeCommand = &cobra.Command{
Use: "compose",
Short: "Compose",
RunE: unknownSubcommandAction,
SilenceUsage: true,
SilenceErrors: true,
}
composeCommand.PersistentFlags().StringP("file", "f", "", "Specify an alternate compose file")
Use: "compose",
Short: "Compose",
RunE: unknownSubcommandAction,
SilenceUsage: true,
SilenceErrors: true,
TraverseChildren: true, // required for global short hands like -f
}
// `-f` is a nonPersistentAlias, as it conflicts with `nerdctl compose logs --follow`
AddPersistentStringFlag(composeCommand, "file", nil, []string{"f"}, "", "", "Specify an alternate compose file")
composeCommand.PersistentFlags().String("project-directory", "", "Specify an alternate working directory")
composeCommand.PersistentFlags().StringP("project-name", "p", "", "Specify an alternate project name")
composeCommand.PersistentFlags().String("env-file", "", "Specify an alternate environment file")
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func newContainerCommand() *cobra.Command {
containerCommand := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "container",
Short: "Manage containers",
RunE: unknownSubcommandAction,
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func newImageCommand() *cobra.Command {
cmd := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "image",
Short: "Manage images",
RunE: unknownSubcommandAction,
Expand Down
169 changes: 95 additions & 74 deletions cmd/nerdctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,32 @@ import (
"github.com/spf13/pflag"
)

type Category = string

const (
CategoryManagement = Category("Management")
Category = "category"
Management = "management"
)

// mainHelpTemplate was derived from https://github.com/spf13/cobra/blob/v1.2.1/command.go#L491-L514
const mainHelpTemplate = `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
Management commands:{{range .Commands}}{{if (eq (index .Annotations "category") "management")}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Commands:{{range .Commands}}{{if (eq (index .Annotations "category") "")}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`

func main() {
if err := xmain(); err != nil {
HandleExitCoder(err)
Expand All @@ -61,81 +81,26 @@ func xmain() error {

func newApp() *cobra.Command {
var rootCmd = &cobra.Command{
Use: "nerdctl",
Short: "nerdctl is a command line interface for containerd",
Version: strings.TrimPrefix(version.Version, "v"),
SilenceUsage: true,
SilenceErrors: true,
Use: "nerdctl",
Short: "nerdctl is a command line interface for containerd",
Version: strings.TrimPrefix(version.Version, "v"),
SilenceUsage: true,
SilenceErrors: true,
TraverseChildren: true, // required for global short hands like -a, -H, -n
}
rootCmd.SetHelpTemplate(mainHelpTemplate)
rootCmd.PersistentFlags().Bool("debug", false, "debug mode")
rootCmd.PersistentFlags().Bool("debug-full", false, "debug mode (with full output)")
{
address := new(string)
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "address",
Shorthand: "a",
Usage: `containerd address, optionally with "unix://" prefix`,
EnvVars: []string{"CONTAINERD_ADDRESS"},
Value: pflag.NewStringValue(defaults.DefaultAddress, address),
},
)
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "host",
Shorthand: "H",
Usage: `alias of --address`,
Value: pflag.NewStringValue(defaults.DefaultAddress, address),
},
)
}
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "namespace",
Shorthand: "n",
Usage: `containerd namespace, such as "moby" for Docker, "k8s.io" for Kubernetes`,
EnvVars: []string{"CONTAINERD_NAMESPACE"},
Value: pflag.NewStringValue(namespaces.Default, new(string)),
},
)
// -a is nonPersistentAlias (conflicts with nerdctl images -a)
AddPersistentStringFlag(rootCmd, "address", []string{"host"}, []string{"a", "H"}, defaults.DefaultAddress, "CONTAINERD_ADDRESS", `containerd address, optionally with "unix://" prefix`)
// -n is nonPersistentAlias (conflicts with nerdctl logs -n)
AddPersistentStringFlag(rootCmd, "namespace", nil, []string{"n"}, namespaces.Default, "CONTAINERD_NAMESPACE", `containerd namespace, such as "moby" for Docker, "k8s.io" for Kubernetes`)
rootCmd.RegisterFlagCompletionFunc("namespace", shellCompleteNamespaceNames)
{
snapshotter := new(string)
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "snapshotter",
Usage: "containerd snapshotter",
EnvVars: []string{"CONTAINERD_SNAPSHOTTER"},
Value: pflag.NewStringValue(containerd.DefaultSnapshotter, snapshotter),
},
)
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "storage-driver",
Usage: "alias of --snapshotter",
Value: pflag.NewStringValue(containerd.DefaultSnapshotter, snapshotter),
},
)
rootCmd.RegisterFlagCompletionFunc("snapshotter", shellCompleteSnapshotterNames)
rootCmd.RegisterFlagCompletionFunc("storage-driver", shellCompleteSnapshotterNames)
}

rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "cni-path",
Usage: "Set the cni-plugins binary directory",
EnvVars: []string{"CNI_PATH"},
Value: pflag.NewStringValue(ncdefaults.CNIPath(), new(string)),
},
)
rootCmd.PersistentFlags().AddFlag(
&pflag.Flag{
Name: "cni-netconfpath",
Usage: "Set the CNI config directory",
EnvVars: []string{"NETCONFPATH"},
Value: pflag.NewStringValue(ncdefaults.CNINetConfPath(), new(string)),
},
)
AddPersistentStringFlag(rootCmd, "snapshotter", []string{"storage-driver"}, nil, containerd.DefaultSnapshotter, "CONTAINERD_SNAPSHOTTER", "containerd snapshotter")
rootCmd.RegisterFlagCompletionFunc("snapshotter", shellCompleteSnapshotterNames)
rootCmd.RegisterFlagCompletionFunc("storage-driver", shellCompleteSnapshotterNames)
AddPersistentStringFlag(rootCmd, "cni-path", nil, nil, ncdefaults.CNIPath(), "CNI_PATH", "cni plugins binary directory")
AddPersistentStringFlag(rootCmd, "cni-netconfpath", nil, nil, ncdefaults.CNINetConfPath(), "NETCONFPATH", "cni config directory")
rootCmd.PersistentFlags().String("data-root", ncdefaults.DataRoot(), "Root directory of persistent nerdctl state (managed by nerdctl, not by containerd)")
rootCmd.PersistentFlags().String("cgroup-manager", ncdefaults.CgroupManager(), `Cgroup manager to use ("cgroupfs"|"systemd")`)
rootCmd.RegisterFlagCompletionFunc("cgroup-manager", shellCompleteCgroupManagerNames)
Expand Down Expand Up @@ -176,6 +141,7 @@ func newApp() *cobra.Command {
}
return nil
}
rootCmd.RunE = unknownSubcommandAction
rootCmd.AddCommand(
// #region Run & Exec
newRunCommand(),
Expand Down Expand Up @@ -313,3 +279,58 @@ func unknownSubcommandAction(cmd *cobra.Command, args []string) error {
}
return errors.New(msg)
}

// AddStringFlag is similar to cmd.Flags().String but supports aliases and env var
func AddStringFlag(cmd *cobra.Command, name string, aliases []string, value string, env, usage string) {
if env != "" {
usage = fmt.Sprintf("%s [$%s]", usage, env)
}
if envV, ok := os.LookupEnv(env); ok {
value = envV
}
aliasesUsage := fmt.Sprintf("Alias of --%s", name)
p := new(string)
flags := cmd.Flags()
flags.StringVar(p, name, value, usage)
for _, a := range aliases {
if len(a) == 1 {
// pflag doesn't support short-only flags, so we have to register long one as well here
flags.StringVarP(p, a, a, value, aliasesUsage)
} else {
flags.StringVar(p, a, value, aliasesUsage)
}
}
}

// AddPersistentStringFlag is similar to AddStringFlag but persistent.
// See https://github.com/spf13/cobra/blob/master/user_guide.md#persistent-flags to learn what is "persistent".
func AddPersistentStringFlag(cmd *cobra.Command, name string, aliases, nonPersistentAliases []string, value string, env, usage string) {
if env != "" {
usage = fmt.Sprintf("%s [$%s]", usage, env)
}
if envV, ok := os.LookupEnv(env); ok {
value = envV
}
aliasesUsage := fmt.Sprintf("Alias of --%s", name)
p := new(string)
flags := cmd.Flags()
for _, a := range nonPersistentAliases {
if len(a) == 1 {
// pflag doesn't support short-only flags, so we have to register long one as well here
flags.StringVarP(p, a, a, value, aliasesUsage)
} else {
flags.StringVar(p, a, value, aliasesUsage)
}
}

persistentFlags := cmd.PersistentFlags()
persistentFlags.StringVar(p, name, value, usage)
for _, a := range aliases {
if len(a) == 1 {
// pflag doesn't support short-only flags, so we have to register long one as well here
persistentFlags.StringVarP(p, a, a, value, aliasesUsage)
} else {
persistentFlags.StringVar(p, a, value, aliasesUsage)
}
}
}
2 changes: 1 addition & 1 deletion cmd/nerdctl/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (

func newNamespaceCommand() *cobra.Command {
namespaceCommand := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "namespace",
Short: "Manage containerd namespaces",
Long: "Unrelated to Linux namespaces and Kubernetes namespaces",
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func newNetworkCommand() *cobra.Command {
networkCommand := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "network",
Short: "Manage networks",
RunE: unknownSubcommandAction,
Expand Down
6 changes: 3 additions & 3 deletions cmd/nerdctl/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ func newPullCommand() *cobra.Command {
SilenceUsage: true,
SilenceErrors: true,
}
pullCommand.PersistentFlags().String("unpack", "auto", "Unpack the image for the current single platform (auto/true/false)")
pullCommand.Flags().String("unpack", "auto", "Unpack the image for the current single platform (auto/true/false)")
pullCommand.RegisterFlagCompletionFunc("unpack", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"auto", "true", "false"}, cobra.ShellCompDirectiveNoFileComp
})

// #region platform flags
// platform is defined as StringSlice, not StringArray, to allow specifying "--platform=amd64,arm64"
pullCommand.PersistentFlags().StringSlice("platform", nil, "Pull content for a specific platform")
pullCommand.Flags().StringSlice("platform", nil, "Pull content for a specific platform")
pullCommand.RegisterFlagCompletionFunc("platform", shellCompletePlatforms)
pullCommand.PersistentFlags().Bool("all-platforms", false, "Pull content for all platforms")
pullCommand.Flags().Bool("all-platforms", false, "Pull content for all platforms")
// #endregion

return pullCommand
Expand Down
4 changes: 2 additions & 2 deletions cmd/nerdctl/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ func newPushCommand() *cobra.Command {
pushCommand.Flags().Bool("all-platforms", false, "Push content for all platforms")
// #endregion

pushCommand.PersistentFlags().Bool("estargz", false, "Convert the image into eStargz")
pushCommand.PersistentFlags().Bool("ipfs-ensure-image", true, "Ensure the entire contents of the image is locally available before push")
pushCommand.Flags().Bool("estargz", false, "Convert the image into eStargz")
pushCommand.Flags().Bool("ipfs-ensure-image", true, "Ensure the entire contents of the image is locally available before push")

return pushCommand
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func newRunCommand() *cobra.Command {
longHelp += "WARNING: `nerdctl run` is experimental on FreeBSD and currently requires `--net=none` (https://github.com/containerd/nerdctl/blob/master/docs/freebsd.md)"
}
var runCommand = &cobra.Command{
Use: "run IMAGE [COMMAND] [ARG...]",
Use: "run [flags] IMAGE [COMMAND] [ARG...]",
Args: cobra.MinimumNArgs(1),
Short: shortHelp,
Long: longHelp,
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func newSystemCommand() *cobra.Command {
var systemCommand = &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "system",
Short: "Manage containerd",
RunE: unknownSubcommandAction,
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

func newVolumeCommand() *cobra.Command {
volumeCommand := &cobra.Command{
Category: CategoryManagement,
Annotations: map[string]string{Category: Management},
Use: "volume",
Short: "Manage volumes",
RunE: unknownSubcommandAction,
Expand Down
12 changes: 4 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ require (
github.com/opencontainers/runtime-spec v1.0.3-0.20211101234015-a3c33d663ebc
github.com/rootless-containers/rootlesskit v0.14.6
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.2.1 // replaced, see the bottom of this file
github.com/spf13/pflag v1.0.5 // replaced, see the bottom of this file
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
github.com/tidwall/gjson v1.11.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
Expand All @@ -47,9 +47,5 @@ require (
gotest.tools/v3 v3.0.3
)

replace (
// Temporary fork for avoiding importing patent-protected code: https://github.com/hashicorp/golang-lru/issues/73
github.com/hashicorp/golang-lru => github.com/ktock/golang-lru v0.5.5-0.20211029085301-ec551be6f75c
github.com/spf13/cobra => github.com/robberphex/cobra v1.2.2-0.20211012081327-8e3ac9400ac4 // https://github.com/spf13/cobra/pull/1503
github.com/spf13/pflag => github.com/robberphex/pflag v1.0.6-0.20211014094653-9df3e45100fd // https://github.com/spf13/pflag/pull/333
)
// Temporary fork for avoiding importing patent-protected code: https://github.com/hashicorp/golang-lru/issues/73
replace github.com/hashicorp/golang-lru => github.com/ktock/golang-lru v0.5.5-0.20211029085301-ec551be6f75c
Loading

0 comments on commit a81cb69

Please sign in to comment.