mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-21 08:33:36 +02:00
fix: install tools using go.mod for versioning (#2562)
* fix: install tools using go.mod for versioning * Add helpful instructions for tool updates. * Add comment * Add boilerplate * Update go.mod * Gofmt feedback
This commit is contained in:
+27
@@ -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).
|
||||
+202
@@ -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.
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# subcommands #
|
||||
|
||||
[](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] <some text>:
|
||||
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)))
|
||||
}
|
||||
```
|
||||
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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])
|
||||
|
||||
Explain func(io.Writer) // A function to print a top level usage explanation. Can be overridden.
|
||||
ExplainGroup func(io.Writer, *CommandGroup) // A function to print a command group's usage explanation. Can be overridden.
|
||||
ExplainCommand func(io.Writer, Command) // A function to print a command usage explanation. Can be overridden.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Name returns the group name
|
||||
func (g *CommandGroup) Name() string {
|
||||
return g.name
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
cdr.Explain = cdr.explain
|
||||
cdr.ExplainGroup = explainGroup
|
||||
cdr.ExplainCommand = explain
|
||||
topLevelFlags.Usage = func() { cdr.Explain(cdr.Error) }
|
||||
return cdr
|
||||
}
|
||||
|
||||
// Name returns the commander's name
|
||||
func (cdr *Commander) Name() string {
|
||||
return cdr.name
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// VisitGroups visits each command group in lexicographical order, calling
|
||||
// fn for each.
|
||||
func (cdr *Commander) VisitGroups(fn func(*CommandGroup)) {
|
||||
sort.Sort(byGroupName(cdr.commands))
|
||||
for _, g := range cdr.commands {
|
||||
fn(g)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitCommands visits each command in registered order grouped by
|
||||
// command group in lexicographical order, calling fn for each.
|
||||
func (cdr *Commander) VisitCommands(fn func(*CommandGroup, Command)) {
|
||||
cdr.VisitGroups(func(g *CommandGroup) {
|
||||
for _, cmd := range g.commands {
|
||||
fn(g, cmd)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// VisitAllImportant visits the important top level flags in lexicographical
|
||||
// order, calling fn for each. It visits all flags, even those not set.
|
||||
func (cdr *Commander) VisitAllImportant(fn func(*flag.Flag)) {
|
||||
sort.Strings(cdr.important)
|
||||
for _, name := range cdr.important {
|
||||
f := cdr.topFlags.Lookup(name)
|
||||
if f == nil {
|
||||
panic(fmt.Sprintf("Important flag (%s) is not defined", name))
|
||||
}
|
||||
fn(f)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitAll visits the top level flags in lexicographical order, calling fn
|
||||
// for each. It visits all flags, even those not set.
|
||||
func (cdr *Commander) VisitAll(fn func(*flag.Flag)) {
|
||||
if cdr.topFlags != nil {
|
||||
cdr.topFlags.VisitAll(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// countFlags returns the number of top-level flags defined, even those not set.
|
||||
func (cdr *Commander) countTopFlags() int {
|
||||
count := 0
|
||||
cdr.VisitAll(func(*flag.Flag) {
|
||||
count++
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
// 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() { cdr.ExplainCommand(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
|
||||
|
||||
// TODO Sort by function rather than implement sortable?
|
||||
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 <flags> <subcommand> <subcommand args>\n\n", cdr.name)
|
||||
sort.Sort(byGroupName(cdr.commands))
|
||||
for _, group := range cdr.commands {
|
||||
cdr.ExplainGroup(w, group)
|
||||
}
|
||||
if cdr.topFlags == nil {
|
||||
fmt.Fprintln(w, "\nNo top level flags.")
|
||||
return
|
||||
}
|
||||
|
||||
sort.Strings(cdr.important)
|
||||
if len(cdr.important) == 0 {
|
||||
if cdr.countTopFlags() > 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(fmt.Sprintf("Important flag (%s) is not defined", name))
|
||||
}
|
||||
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)
|
||||
|
||||
aliases := make(map[string][]string)
|
||||
for _, cmd := range group.commands {
|
||||
if alias, ok := cmd.(*aliaser); ok {
|
||||
root := dealias(alias).Name()
|
||||
|
||||
if _, ok := aliases[root]; !ok {
|
||||
aliases[root] = []string{}
|
||||
}
|
||||
aliases[root] = append(aliases[root], alias.Name())
|
||||
}
|
||||
}
|
||||
|
||||
for _, cmd := range group.commands {
|
||||
if _, ok := cmd.(*aliaser); ok {
|
||||
continue
|
||||
}
|
||||
|
||||
name := cmd.Name()
|
||||
names := []string{name}
|
||||
|
||||
if a, ok := aliases[name]; ok {
|
||||
names = append(names, a...)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "\t%-15s %s\n", strings.Join(names, ", "), 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 [<subcommand>]:
|
||||
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
|
||||
}
|
||||
(*Commander)(h).ExplainCommand(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 [<subcommand>]:
|
||||
With an argument, print all flags of <subcommand>. 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)
|
||||
}
|
||||
|
||||
// An aliaser is a Command wrapping another Command but returning a
|
||||
// different name as its alias.
|
||||
type aliaser struct {
|
||||
alias string
|
||||
Command
|
||||
}
|
||||
|
||||
func (a *aliaser) Name() string { return a.alias }
|
||||
|
||||
// Alias returns a Command alias which implements a "commands" subcommand.
|
||||
func Alias(alias string, cmd Command) Command {
|
||||
return &aliaser{alias, cmd}
|
||||
}
|
||||
|
||||
// dealias recursivly dealiases a command until a non-aliased command
|
||||
// is reached.
|
||||
func dealias(cmd Command) Command {
|
||||
if alias, ok := cmd.(*aliaser); ok {
|
||||
return dealias(alias.Command)
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 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(), <group>) for it to be
|
||||
// recognized.
|
||||
func HelpCommand() Command {
|
||||
return DefaultCommander.HelpCommand()
|
||||
}
|
||||
|
||||
// FlagsCommand returns a Command which implements "flags" for the
|
||||
// DefaultCommander. Use Register(FlagsCommand(), <group>) 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()
|
||||
}
|
||||
Reference in New Issue
Block a user