From c32d9bf24c3b670c3a56ea55aeefb6232f3d4ec8 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 13 Feb 2018 01:17:35 +0100 Subject: switch to subcommands --- vendor/github.com/google/subcommands/CONTRIBUTING | 27 ++ vendor/github.com/google/subcommands/LICENSE | 202 +++++++++++ vendor/github.com/google/subcommands/README.md | 67 ++++ .../github.com/google/subcommands/subcommands.go | 391 +++++++++++++++++++++ 4 files changed, 687 insertions(+) create mode 100644 vendor/github.com/google/subcommands/CONTRIBUTING create mode 100644 vendor/github.com/google/subcommands/LICENSE create mode 100644 vendor/github.com/google/subcommands/README.md create mode 100644 vendor/github.com/google/subcommands/subcommands.go (limited to 'vendor/github.com') diff --git a/vendor/github.com/google/subcommands/CONTRIBUTING b/vendor/github.com/google/subcommands/CONTRIBUTING new file mode 100644 index 0000000..2827b7d --- /dev/null +++ b/vendor/github.com/google/subcommands/CONTRIBUTING @@ -0,0 +1,27 @@ +Want to contribute? Great! First, read this page (including the small print at the end). + +### Before you contribute +Before we can use your code, you must sign the +[Google Individual Contributor License Agreement] +(https://cla.developers.google.com/about/google-individual) +(CLA), which you can do online. The CLA is necessary mainly because you own the +copyright to your changes, even after your contribution becomes part of our +codebase, so we need your permission to use and distribute your code. We also +need to be sure of various other things—for instance that you'll tell us if you +know that your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Code reviews +All submissions, including submissions by project members, require review. We +use Github pull requests for this purpose. + +### The small print +Contributions made by corporations are covered by a different agreement than +the one above, the +[Software Grant and Corporate Contributor License Agreement] +(https://cla.developers.google.com/about/google-corporate). diff --git a/vendor/github.com/google/subcommands/LICENSE b/vendor/github.com/google/subcommands/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/vendor/github.com/google/subcommands/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/subcommands/README.md b/vendor/github.com/google/subcommands/README.md new file mode 100644 index 0000000..c769745 --- /dev/null +++ b/vendor/github.com/google/subcommands/README.md @@ -0,0 +1,67 @@ +# subcommands # + +[![GoDoc](https://godoc.org/github.com/google/subcommands?status.svg)](https://godoc.org/github.com/google/subcommands) +Subcommands is a Go package that implements a simple way for a single command to +have many subcommands, each of which takes arguments and so forth. + +This is not an official Google product. + +## Usage ## + +Set up a 'print' subcommand: + +```go +import ( + "context" + "flag" + "fmt" + "os" + "strings" + + "github.com/google/subcommands" +) + +type printCmd struct { + capitalize bool +} + +func (*printCmd) Name() string { return "print" } +func (*printCmd) Synopsis() string { return "Print args to stdout." } +func (*printCmd) Usage() string { + return `print [-capitalize] : + Print args to stdout. +` +} + +func (p *printCmd) SetFlags(f *flag.FlagSet) { + f.BoolVar(&p.capitalize, "capitalize", false, "capitalize output") +} + +func (p *printCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { + for _, arg := range f.Args() { + if p.capitalize { + arg = strings.ToUpper(arg) + } + fmt.Printf("%s ", arg) + } + fmt.Println() + return subcommands.ExitSuccess +} +``` + +Register using the default Commander, also use some built in subcommands, +finally run Execute using ExitStatus as the exit code: + +```go +func main() { + subcommands.Register(subcommands.HelpCommand(), "") + subcommands.Register(subcommands.FlagsCommand(), "") + subcommands.Register(subcommands.CommandsCommand(), "") + subcommands.Register(&printCmd{}, "") + + flag.Parse() + ctx := context.Background() + os.Exit(int(subcommands.Execute(ctx))) +} +``` + diff --git a/vendor/github.com/google/subcommands/subcommands.go b/vendor/github.com/google/subcommands/subcommands.go new file mode 100644 index 0000000..a42a0c8 --- /dev/null +++ b/vendor/github.com/google/subcommands/subcommands.go @@ -0,0 +1,391 @@ +/* +Copyright 2016 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package subcommands implements a simple way for a single command to have many +// subcommands, each of which takes arguments and so forth. +package subcommands + +import ( + "context" + "flag" + "fmt" + "io" + "os" + "path" + "sort" +) + +// A Command represents a single command. +type Command interface { + // Name returns the name of the command. + Name() string + + // Synopsis returns a short string (less than one line) describing the command. + Synopsis() string + + // Usage returns a long string explaining the command and giving usage + // information. + Usage() string + + // SetFlags adds the flags for this command to the specified set. + SetFlags(*flag.FlagSet) + + // Execute executes the command and returns an ExitStatus. + Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) ExitStatus +} + +// A Commander represents a set of commands. +type Commander struct { + commands []*commandGroup + topFlags *flag.FlagSet // top-level flags + important []string // important top-level flags + name string // normally path.Base(os.Args[0]) + + Output io.Writer // Output specifies where the commander should write its output (default: os.Stdout). + Error io.Writer // Error specifies where the commander should write its error (default: os.Stderr). +} + +// A commandGroup represents a set of commands about a common topic. +type commandGroup struct { + name string + commands []Command +} + +// An ExitStatus represents a Posix exit status that a subcommand +// expects to be returned to the shell. +type ExitStatus int + +const ( + ExitSuccess ExitStatus = iota + ExitFailure + ExitUsageError +) + +// NewCommander returns a new commander with the specified top-level +// flags and command name. The Usage function for the topLevelFlags +// will be set as well. +func NewCommander(topLevelFlags *flag.FlagSet, name string) *Commander { + cdr := &Commander{ + topFlags: topLevelFlags, + name: name, + Output: os.Stdout, + Error: os.Stderr, + } + topLevelFlags.Usage = func() { cdr.explain(cdr.Error) } + return cdr +} + +// Register adds a subcommand to the supported subcommands in the +// specified group. (Help output is sorted and arranged by group name.) +// The empty string is an acceptable group name; such subcommands are +// explained first before named groups. +func (cdr *Commander) Register(cmd Command, group string) { + for _, g := range cdr.commands { + if g.name == group { + g.commands = append(g.commands, cmd) + return + } + } + cdr.commands = append(cdr.commands, &commandGroup{ + name: group, + commands: []Command{cmd}, + }) +} + +// ImportantFlag marks a top-level flag as important, which means it +// will be printed out as part of the output of an ordinary "help" +// subcommand. (All flags, important or not, are printed by the +// "flags" subcommand.) +func (cdr *Commander) ImportantFlag(name string) { + cdr.important = append(cdr.important, name) +} + +// Execute should be called once the top-level-flags on a Commander +// have been initialized. It finds the correct subcommand and executes +// it, and returns an ExitStatus with the result. On a usage error, an +// appropriate message is printed to os.Stderr, and ExitUsageError is +// returned. The additional args are provided as-is to the Execute method +// of the selected Command. +func (cdr *Commander) Execute(ctx context.Context, args ...interface{}) ExitStatus { + if cdr.topFlags.NArg() < 1 { + cdr.topFlags.Usage() + return ExitUsageError + } + + name := cdr.topFlags.Arg(0) + + for _, group := range cdr.commands { + for _, cmd := range group.commands { + if name != cmd.Name() { + continue + } + f := flag.NewFlagSet(name, flag.ContinueOnError) + f.Usage = func() { explain(cdr.Error, cmd) } + cmd.SetFlags(f) + if f.Parse(cdr.topFlags.Args()[1:]) != nil { + return ExitUsageError + } + return cmd.Execute(ctx, f, args...) + } + } + + // Cannot find this command. + cdr.topFlags.Usage() + return ExitUsageError +} + +// Sorting of a slice of command groups. +type byGroupName []*commandGroup + +func (p byGroupName) Len() int { return len(p) } +func (p byGroupName) Less(i, j int) bool { return p[i].name < p[j].name } +func (p byGroupName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// explain prints a brief description of all the subcommands and the +// important top-level flags. +func (cdr *Commander) explain(w io.Writer) { + fmt.Fprintf(w, "Usage: %s \n\n", cdr.name) + sort.Sort(byGroupName(cdr.commands)) + for _, group := range cdr.commands { + explainGroup(w, group) + } + if cdr.topFlags == nil { + fmt.Fprintln(w, "\nNo top level flags.") + return + } + if len(cdr.important) == 0 { + fmt.Fprintf(w, "\nUse \"%s flags\" for a list of top-level flags\n", cdr.name) + return + } + + fmt.Fprintf(w, "\nTop-level flags (use \"%s flags\" for a full list):\n", cdr.name) + for _, name := range cdr.important { + f := cdr.topFlags.Lookup(name) + if f == nil { + panic("Important flag is not defined") + } + fmt.Fprintf(w, " -%s=%s: %s\n", f.Name, f.DefValue, f.Usage) + } +} + +// Sorting of the commands within a group. +func (g commandGroup) Len() int { return len(g.commands) } +func (g commandGroup) Less(i, j int) bool { return g.commands[i].Name() < g.commands[j].Name() } +func (g commandGroup) Swap(i, j int) { g.commands[i], g.commands[j] = g.commands[j], g.commands[i] } + +// explainGroup explains all the subcommands for a particular group. +func explainGroup(w io.Writer, group *commandGroup) { + if len(group.commands) == 0 { + return + } + if group.name == "" { + fmt.Fprintf(w, "Subcommands:\n") + } else { + fmt.Fprintf(w, "Subcommands for %s:\n", group.name) + } + sort.Sort(group) + for _, cmd := range group.commands { + fmt.Fprintf(w, "\t%-15s %s\n", cmd.Name(), cmd.Synopsis()) + } + fmt.Fprintln(w) +} + +// explainCmd prints a brief description of a single command. +func explain(w io.Writer, cmd Command) { + fmt.Fprintf(w, "%s", cmd.Usage()) + subflags := flag.NewFlagSet(cmd.Name(), flag.PanicOnError) + subflags.SetOutput(w) + cmd.SetFlags(subflags) + subflags.PrintDefaults() +} + +// A helper is a Command implementing a "help" command for +// a given Commander. +type helper Commander + +func (h *helper) Name() string { return "help" } +func (h *helper) Synopsis() string { return "describe subcommands and their syntax" } +func (h *helper) SetFlags(*flag.FlagSet) {} +func (h *helper) Usage() string { + return `help []: + With an argument, prints detailed information on the use of + the specified subcommand. With no argument, print a list of + all commands and a brief description of each. +` +} +func (h *helper) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) ExitStatus { + switch f.NArg() { + case 0: + (*Commander)(h).explain(h.Output) + return ExitSuccess + + case 1: + for _, group := range h.commands { + for _, cmd := range group.commands { + if f.Arg(0) != cmd.Name() { + continue + } + explain(h.Output, cmd) + return ExitSuccess + } + } + fmt.Fprintf(h.Error, "Subcommand %s not understood\n", f.Arg(0)) + } + + f.Usage() + return ExitUsageError +} + +// HelpCommand returns a Command which implements a "help" subcommand. +func (cdr *Commander) HelpCommand() Command { + return (*helper)(cdr) +} + +// A flagger is a Command implementing a "flags" command for a given Commander. +type flagger Commander + +func (flg *flagger) Name() string { return "flags" } +func (flg *flagger) Synopsis() string { return "describe all known top-level flags" } +func (flg *flagger) SetFlags(*flag.FlagSet) {} +func (flg *flagger) Usage() string { + return `flags []: + With an argument, print all flags of . Else, + print a description of all known top-level flags. (The basic + help information only discusses the most generally important + top-level flags.) +` +} +func (flg *flagger) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) ExitStatus { + if f.NArg() > 1 { + f.Usage() + return ExitUsageError + } + + if f.NArg() == 0 { + if flg.topFlags == nil { + fmt.Fprintln(flg.Output, "No top-level flags are defined.") + } else { + flg.topFlags.PrintDefaults() + } + return ExitSuccess + } + + for _, group := range flg.commands { + for _, cmd := range group.commands { + if f.Arg(0) != cmd.Name() { + continue + } + subflags := flag.NewFlagSet(cmd.Name(), flag.PanicOnError) + subflags.SetOutput(flg.Output) + cmd.SetFlags(subflags) + subflags.PrintDefaults() + return ExitSuccess + } + } + fmt.Fprintf(flg.Error, "Subcommand %s not understood\n", f.Arg(0)) + return ExitFailure +} + +// FlagsCommand returns a Command which implements a "flags" subcommand. +func (cdr *Commander) FlagsCommand() Command { + return (*flagger)(cdr) +} + +// A lister is a Command implementing a "commands" command for a given Commander. +type lister Commander + +func (l *lister) Name() string { return "commands" } +func (l *lister) Synopsis() string { return "list all command names" } +func (l *lister) SetFlags(*flag.FlagSet) {} +func (l *lister) Usage() string { + return `commands: + Print a list of all commands. +` +} +func (l *lister) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) ExitStatus { + if f.NArg() != 0 { + f.Usage() + return ExitUsageError + } + + for _, group := range l.commands { + for _, cmd := range group.commands { + fmt.Fprintf(l.Output, "%s\n", cmd.Name()) + } + } + return ExitSuccess +} + +// CommandsCommand returns Command which implements a "commands" subcommand. +func (cdr *Commander) CommandsCommand() Command { + return (*lister)(cdr) +} + +// DefaultCommander is the default commander using flag.CommandLine for flags +// and os.Args[0] for the command name. +var DefaultCommander *Commander + +func init() { + DefaultCommander = NewCommander(flag.CommandLine, path.Base(os.Args[0])) +} + +// Register adds a subcommand to the supported subcommands in the +// specified group. (Help output is sorted and arranged by group +// name.) The empty string is an acceptable group name; such +// subcommands are explained first before named groups. It is a +// wrapper around DefaultCommander.Register. +func Register(cmd Command, group string) { + DefaultCommander.Register(cmd, group) +} + +// ImportantFlag marks a top-level flag as important, which means it +// will be printed out as part of the output of an ordinary "help" +// subcommand. (All flags, important or not, are printed by the +// "flags" subcommand.) It is a wrapper around +// DefaultCommander.ImportantFlag. +func ImportantFlag(name string) { + DefaultCommander.ImportantFlag(name) +} + +// Execute should be called once the default flags have been +// initialized by flag.Parse. It finds the correct subcommand and +// executes it, and returns an ExitStatus with the result. On a usage +// error, an appropriate message is printed to os.Stderr, and +// ExitUsageError is returned. The additional args are provided as-is +// to the Execute method of the selected Command. It is a wrapper +// around DefaultCommander.Execute. +func Execute(ctx context.Context, args ...interface{}) ExitStatus { + return DefaultCommander.Execute(ctx, args...) +} + +// HelpCommand returns a Command which implements "help" for the +// DefaultCommander. Use Register(HelpCommand(), ) for it to be +// recognized. +func HelpCommand() Command { + return DefaultCommander.HelpCommand() +} + +// FlagsCommand returns a Command which implements "flags" for the +// DefaultCommander. Use Register(FlagsCommand(), ) for it to be +// recognized. +func FlagsCommand() Command { + return DefaultCommander.FlagsCommand() +} + +// CommandsCommand returns Command which implements a "commands" subcommand. +func CommandsCommand() Command { + return DefaultCommander.CommandsCommand() +} -- cgit v1.2.3