pax_global_header00006660000000000000000000000064141561603730014520gustar00rootroot0000000000000052 comment=178edbb247f35e466578211dcf5f4892dbbd369b cobra-1.3.0/000077500000000000000000000000001415616037300126075ustar00rootroot00000000000000cobra-1.3.0/.github/000077500000000000000000000000001415616037300141475ustar00rootroot00000000000000cobra-1.3.0/.github/dependabot.yml000066400000000000000000000003611415616037300167770ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: gomod directory: / schedule: interval: weekly open-pull-requests-limit: 99 - package-ecosystem: github-actions directory: / schedule: interval: weekly open-pull-requests-limit: 99 cobra-1.3.0/.github/labeler.yml000066400000000000000000000004701415616037300163010ustar00rootroot00000000000000# changes to documentation generation "area/doc-gen": doc/**/* # changes to the core Go cobra lib package "area/lib": ./*.go # changes to the Cobra CLI "area/cli": cobra/**/* # changes to Github workflows "area/github": .github/**/* # changes to shell completions "area/*sh completion": - ./*completions* cobra-1.3.0/.github/workflows/000077500000000000000000000000001415616037300162045ustar00rootroot00000000000000cobra-1.3.0/.github/workflows/labeler.yml000066400000000000000000000003041415616037300203320ustar00rootroot00000000000000name: "Pull Request Labeler" on: - pull_request_target jobs: triage: runs-on: ubuntu-latest steps: - uses: actions/labeler@v3 with: repo-token: "${{ github.token }}" cobra-1.3.0/.github/workflows/stale.yml000066400000000000000000000011041415616037300200330ustar00rootroot00000000000000name: Mark stale issues and pull requests on: schedule: - cron: "0 0 * * *" jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is being marked as stale due to a long period of inactivity' stale-pr-message: 'This PR is being marked as stale due to a long period of inactivity' stale-issue-label: 'kind/stale' stale-pr-label: 'kind/stale' exempt-issue-label: 'kind/stale' exempt-pr-label: 'kind/stale' cobra-1.3.0/.github/workflows/test.yml000066400000000000000000000041321415616037300177060ustar00rootroot00000000000000name: Test on: push: pull_request: env: GO111MODULE: on jobs: golangci-lint: runs-on: ubuntu-latest steps: - uses: actions/setup-go@v2 with: go-version: '1.17' - uses: actions/checkout@v2 - uses: golangci/golangci-lint-action@v2 with: version: latest args: --verbose test-unix: strategy: fail-fast: false matrix: platform: - ubuntu - macOS go: - 14 - 15 - 16 - 17 name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x' runs-on: ${{ matrix.platform }}-latest steps: - uses: actions/setup-go@v2 with: go-version: 1.${{ matrix.go }}.x - uses: actions/checkout@v2 - uses: actions/cache@v2 with: path: ~/go/pkg/mod key: ${{ runner.os }}-1.${{ matrix.go }}.x-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-1.${{ matrix.go }}.x- - run: | export GOBIN=$HOME/go/bin case "${{ matrix.go }}" in 16|17) _version='@latest';; *) _version='';; esac go install github.com/kyoh86/richgo"${_version}" go install github.com/mitchellh/gox"${_version}" - run: PATH=$HOME/go/bin/:$PATH make test cobra_generator test-win: name: MINGW64 defaults: run: shell: msys2 {0} runs-on: windows-latest steps: - shell: bash run: git config --global core.autocrlf input - uses: msys2/setup-msys2@v2 with: msystem: MINGW64 update: true install: > git make unzip mingw-w64-x86_64-go - uses: actions/checkout@v2 - uses: actions/cache@v2 with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ matrix.go }}-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-${{ matrix.go }}- - run: | export GOBIN=$HOME/go/bin go install github.com/kyoh86/richgo@latest go install github.com/mitchellh/gox@latest - run: PATH=$HOME/go/bin:$PATH make test cobra_generator cobra-1.3.0/.gitignore000066400000000000000000000007441415616037300146040ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go # Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore # swap [._]*.s[a-w][a-z] [._]s[a-w][a-z] # session Session.vim # temporary .netrwhist *~ # auto-generated tag files tags *.exe cobra.test bin .idea/ *.iml cobra-1.3.0/.golangci.yml000066400000000000000000000013201415616037300151670ustar00rootroot00000000000000run: deadline: 5m linters: disable-all: true enable: #- bodyclose - deadcode #- depguard #- dogsled #- dupl - errcheck #- exhaustive #- funlen - gas #- gochecknoinits - goconst #- gocritic #- gocyclo #- gofmt - goimports - golint #- gomnd #- goprintffuncname #- gosec #- gosimple - govet - ineffassign - interfacer #- lll - maligned - megacheck #- misspell #- nakedret #- noctx #- nolintlint #- rowserrcheck #- scopelint #- staticcheck - structcheck #- stylecheck #- typecheck - unconvert #- unparam #- unused - varcheck #- whitespace fast: false cobra-1.3.0/.mailmap000066400000000000000000000002541415616037300142310ustar00rootroot00000000000000Steve Francia Bjørn Erik Pedersen Fabiano Franz cobra-1.3.0/CHANGELOG.md000066400000000000000000000041241415616037300144210ustar00rootroot00000000000000# Cobra Changelog ## v1.1.3 * **Fix:** release-branch.cobra1.1 only: Revert "Deprecate Go < 1.14" to maintain backward compatibility ## v1.1.2 ### Notable Changes * Bump license year to 2021 in golden files (#1309) @Bowbaq * Enhance PowerShell completion with custom comp (#1208) @Luap99 * Update gopkg.in/yaml.v2 to v2.4.0: The previous breaking change in yaml.v2 v2.3.0 has been reverted, see go-yaml/yaml#670 * Documentation readability improvements (#1228 etc.) @zaataylor etc. * Use golangci-lint: Repair warnings and errors resulting from linting (#1044) @umarcor ## v1.1.1 * **Fix:** yaml.v2 2.3.0 contained a unintended breaking change. This release reverts to yaml.v2 v2.2.8 which has recent critical CVE fixes, but does not have the breaking changes. See https://github.com/spf13/cobra/pull/1259 for context. * **Fix:** correct internal formatting for go-md2man v2 (which caused man page generation to be broken). See https://github.com/spf13/cobra/issues/1049 for context. ## v1.1.0 ### Notable Changes * Extend Go completions and revamp zsh comp (#1070) * Fix man page doc generation - no auto generated tag when `cmd.DisableAutoGenTag = true` (#1104) @jpmcb * Add completion for help command (#1136) * Complete subcommands when TraverseChildren is set (#1171) * Fix stderr printing functions (#894) * fix: fish output redirection (#1247) ## v1.0.0 Announcing v1.0.0 of Cobra. 🎉 ### Notable Changes * Fish completion (including support for Go custom completion) @marckhouzam * API (urgent): Rename BashCompDirectives to ShellCompDirectives @marckhouzam * Remove/replace SetOutput on Command - deprecated @jpmcb * add support for autolabel stale PR @xchapter7x * Add Labeler Actions @xchapter7x * Custom completions coded in Go (instead of Bash) @marckhouzam * Partial Revert of #922 @jharshman * Add Makefile to project @jharshman * Correct documentation for InOrStdin @desponda * Apply formatting to templates @jharshman * Revert change so help is printed on stdout again @marckhouzam * Update md2man to v2.0.0 @pdf * update viper to v1.4.0 @umarcor * Update cmd/root.go example in README.md @jharshman cobra-1.3.0/CONDUCT.md000066400000000000000000000060621415616037300142340ustar00rootroot00000000000000## Cobra User Contract ### Versioning Cobra will follow a steady release cadence. Non breaking changes will be released as minor versions quarterly. Patch bug releases are at the discretion of the maintainers. Users can expect security patch fixes to be released within relatively short order of a CVE becoming known. For more information on security patch fixes see the CVE section below. Releases will follow [Semantic Versioning](https://semver.org/). Users tracking the Master branch should expect unpredictable breaking changes as the project continues to move forward. For stability, it is highly recommended to use a release. ### Backward Compatibility We will maintain two major releases in a moving window. The N-1 release will only receive bug fixes and security updates and will be dropped once N+1 is released. ### Deprecation Deprecation of Go versions or dependent packages will only occur in major releases. To reduce the change of this taking users by surprise, any large deprecation will be preceded by an announcement in the [#cobra slack channel](https://gophers.slack.com/archives/CD3LP1199) and an Issue on Github. ### CVE Maintainers will make every effort to release security patches in the case of a medium to high severity CVE directly impacting the library. The speed in which these patches reach a release is up to the discretion of the maintainers. A low severity CVE may be a lower priority than a high severity one. ### Communication Cobra maintainers will use GitHub issues and the [#cobra slack channel](https://gophers.slack.com/archives/CD3LP1199) as the primary means of communication with the community. This is to foster open communication with all users and contributors. ### Breaking Changes Breaking changes are generally allowed in the master branch, as this is the branch used to develop the next release of Cobra. There may be times, however, when master is closed for breaking changes. This is likely to happen as we near the release of a new version. Breaking changes are not allowed in release branches, as these represent minor versions that have already been released. These version have consumers who expect the APIs, behaviors, etc, to remain stable during the lifetime of the patch stream for the minor release. Examples of breaking changes include: - Removing or renaming exported constant, variable, type, or function. - Updating the version of critical libraries such as `spf13/pflag`, `spf13/viper` etc... - Some version updates may be acceptable for picking up bug fixes, but maintainers must exercise caution when reviewing. There may, at times, need to be exceptions where breaking changes are allowed in release branches. These are at the discretion of the project's maintainers, and must be carefully considered before merging. ### CI Testing Maintainers will ensure the Cobra test suite utilizes the current supported versions of Golang. ### Disclaimer Changes to this document and the contents therein are at the discretion of the maintainers. None of the contents of this document are legally binding in any way to the maintainers or the users. cobra-1.3.0/CONTRIBUTING.md000066400000000000000000000040611415616037300150410ustar00rootroot00000000000000# Contributing to Cobra Thank you so much for contributing to Cobra. We appreciate your time and help. Here are some guidelines to help you get started. ## Code of Conduct Be kind and respectful to the members of the community. Take time to educate others who are seeking help. Harassment of any kind will not be tolerated. ## Questions If you have questions regarding Cobra, feel free to ask it in the community [#cobra Slack channel][cobra-slack] ## Filing a bug or feature 1. Before filing an issue, please check the existing issues to see if a similar one was already opened. If there is one already opened, feel free to comment on it. 1. If you believe you've found a bug, please provide detailed steps of reproduction, the version of Cobra and anything else you believe will be useful to help troubleshoot it (e.g. OS environment, environment variables, etc...). Also state the current behavior vs. the expected behavior. 1. If you'd like to see a feature or an enhancement please open an issue with a clear title and description of what the feature is and why it would be beneficial to the project and its users. ## Submitting changes 1. CLA: Upon submitting a Pull Request (PR), contributors will be prompted to sign a CLA. Please sign the CLA :slightly_smiling_face: 1. Tests: If you are submitting code, please ensure you have adequate tests for the feature. Tests can be run via `go test ./...` or `make test`. 1. Since this is golang project, ensure the new code is properly formatted to ensure code consistency. Run `make all`. ### Quick steps to contribute 1. Fork the project. 1. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`) 1. Create your feature branch (`git checkout -b my-new-feature`) 1. Make changes and run tests (`make test`) 1. Add them to staging (`git add .`) 1. Commit your changes (`git commit -m 'Add some feature'`) 1. Push to the branch (`git push origin my-new-feature`) 1. Create new pull request [cobra-slack]: https://gophers.slack.com/archives/CD3LP1199 cobra-1.3.0/LICENSE.txt000066400000000000000000000236341415616037300144420ustar00rootroot00000000000000 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. cobra-1.3.0/Makefile000066400000000000000000000020601415616037300142450ustar00rootroot00000000000000BIN="./bin" SRC=$(shell find . -name "*.go") ifeq (, $(shell which golangci-lint)) $(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh") endif ifeq (, $(shell which richgo)) $(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo") endif .PHONY: fmt lint test cobra_generator install_deps clean default: all all: fmt test cobra_generator fmt: $(info ******************** checking formatting ********************) @test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1) lint: $(info ******************** running lint tools ********************) golangci-lint run -v test: install_deps $(info ******************** running tests ********************) richgo test -v ./... cobra_generator: install_deps $(info ******************** building generator ********************) mkdir -p $(BIN) make -C cobra all install_deps: $(info ******************** downloading dependencies ********************) go get -v ./... clean: rm -rf $(BIN) cobra-1.3.0/README.md000066400000000000000000000106731415616037300140750ustar00rootroot00000000000000![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/), [Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra. [![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) [![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra) [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199) # Overview Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools. Cobra is also an application that will generate your application scaffolding to rapidly develop a Cobra-based application. Cobra provides: * Easy subcommand-based CLIs: `app server`, `app fetch`, etc. * Fully POSIX-compliant flags (including short & long versions) * Nested subcommands * Global, local and cascading flags * Easy generation of applications & commands with `cobra init` & `cobra add cmdname` * Intelligent suggestions (`app srver`... did you mean `app server`?) * Automatic help generation for commands and flags * Automatic help flag recognition of `-h`, `--help`, etc. * Automatically generated shell autocomplete for your application (bash, zsh, fish, powershell) * Automatically generated man pages for your application * Command aliases so you can change things without breaking them * The flexibility to define your own help, usage, etc. * Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps # Concepts Cobra is built on a structure of commands, arguments & flags. **Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. The best applications read like sentences when used, and as a result, users intuitively know how to interact with them. The pattern to follow is `APPNAME VERB NOUN --ADJECTIVE.` or `APPNAME COMMAND ARG --FLAG` A few good real world examples may better illustrate this point. In the following example, 'server' is a command, and 'port' is a flag: hugo server --port=1313 In this command we are telling Git to clone the url bare. git clone URL --bare ## Commands Command is the central point of the application. Each interaction that the application supports will be contained in a Command. A command can have children commands and optionally run an action. In the example above, 'server' is the command. [More about cobra.Command](https://pkg.go.dev/github.com/spf13/cobra#Command) ## Flags A flag is a way to modify the behavior of a command. Cobra supports fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). A Cobra command can define flags that persist through to children commands and flags that are only available to that command. In the example above, 'port' is the flag. Flag functionality is provided by the [pflag library](https://github.com/spf13/pflag), a fork of the flag standard library which maintains the same interface while adding POSIX compliance. # Installing Using Cobra is easy. First, use `go get` to install the latest version of the library. This command will install the `cobra` generator executable along with the library and its dependencies: go get -u github.com/spf13/cobra Next, include Cobra in your application: ```go import "github.com/spf13/cobra" ``` # Usage Cobra provides its own program that will create your application and add any commands you want. It's the easiest way to incorporate Cobra into your application. For complete details on using the Cobra generator, please read [The Cobra Generator README](https://github.com/spf13/cobra/blob/master/cobra/README.md) For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md). # License Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) cobra-1.3.0/args.go000066400000000000000000000066311415616037300141000ustar00rootroot00000000000000package cobra import ( "fmt" "strings" ) type PositionalArgs func(cmd *Command, args []string) error // Legacy arg validation has the following behaviour: // - root commands with no subcommands can take arbitrary arguments // - root commands with subcommands will do subcommand validity checking // - subcommands will always accept arbitrary arguments func legacyArgs(cmd *Command, args []string) error { // no subcommand, always take args if !cmd.HasSubCommands() { return nil } // root command with subcommands, do subcommand checking. if !cmd.HasParent() && len(args) > 0 { return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) } return nil } // NoArgs returns an error if any args are included. func NoArgs(cmd *Command, args []string) error { if len(args) > 0 { return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) } return nil } // OnlyValidArgs returns an error if any args are not in the list of ValidArgs. func OnlyValidArgs(cmd *Command, args []string) error { if len(cmd.ValidArgs) > 0 { // Remove any description that may be included in ValidArgs. // A description is following a tab character. var validArgs []string for _, v := range cmd.ValidArgs { validArgs = append(validArgs, strings.Split(v, "\t")[0]) } for _, v := range args { if !stringInSlice(v, validArgs) { return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) } } } return nil } // ArbitraryArgs never returns an error. func ArbitraryArgs(cmd *Command, args []string) error { return nil } // MinimumNArgs returns an error if there is not at least N args. func MinimumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < n { return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) } return nil } } // MaximumNArgs returns an error if there are more than N args. func MaximumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) > n { return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) } return nil } } // ExactArgs returns an error if there are not exactly n args. func ExactArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) != n { return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) } return nil } } // ExactValidArgs returns an error if // there are not exactly N positional args OR // there are any positional args that are not in the `ValidArgs` field of `Command` func ExactValidArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if err := ExactArgs(n)(cmd, args); err != nil { return err } return OnlyValidArgs(cmd, args) } } // RangeArgs returns an error if the number of args is not within the expected range. func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < min || len(args) > max { return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) } return nil } } // MatchAll allows combining several PositionalArgs to work in concert. func MatchAll(pargs ...PositionalArgs) PositionalArgs { return func(cmd *Command, args []string) error { for _, parg := range pargs { if err := parg(cmd, args); err != nil { return err } } return nil } } cobra-1.3.0/args_test.go000066400000000000000000000157561415616037300151470ustar00rootroot00000000000000package cobra import ( "fmt" "strings" "testing" ) func getCommand(args PositionalArgs, withValid bool) *Command { c := &Command{ Use: "c", Args: args, Run: emptyRun, } if withValid { c.ValidArgs = []string{"one", "two", "three"} } return c } func expectSuccess(output string, err error, t *testing.T) { if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Fatalf("Unexpected error: %v", err) } } func validWithInvalidArgs(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `invalid argument "a" for "c"` if got != expected { t.Errorf("Expected: %q, got: %q", expected, got) } } func noArgsWithArgs(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "c"` if got != expected { t.Errorf("Expected: %q, got: %q", expected, got) } } func minimumNArgsWithLessArgs(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "requires at least 2 arg(s), only received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func maximumNArgsWithMoreArgs(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts at most 2 arg(s), received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func exactArgsWithInvalidCount(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts 2 arg(s), received 3" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func rangeArgsWithInvalidCount(err error, t *testing.T) { if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := "accepts between 2 and 4 arg(s), received 1" if got != expected { t.Fatalf("Expected %q, got %q", expected, got) } } func TestNoArgs(t *testing.T) { c := getCommand(NoArgs, false) output, err := executeCommand(c) expectSuccess(output, err, t) } func TestNoArgsWithArgs(t *testing.T) { c := getCommand(NoArgs, false) _, err := executeCommand(c, "illegal") noArgsWithArgs(err, t) } func TestOnlyValidArgs(t *testing.T) { c := getCommand(OnlyValidArgs, true) output, err := executeCommand(c, "one", "two") expectSuccess(output, err, t) } func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { c := getCommand(OnlyValidArgs, true) _, err := executeCommand(c, "a") validWithInvalidArgs(err, t) } func TestArbitraryArgs(t *testing.T) { c := getCommand(ArbitraryArgs, false) output, err := executeCommand(c, "a", "b") expectSuccess(output, err, t) } func TestMinimumNArgs(t *testing.T) { c := getCommand(MinimumNArgs(2), false) output, err := executeCommand(c, "a", "b", "c") expectSuccess(output, err, t) } func TestMinimumNArgsWithLessArgs(t *testing.T) { c := getCommand(MinimumNArgs(2), false) _, err := executeCommand(c, "a") minimumNArgsWithLessArgs(err, t) } func TestMaximumNArgs(t *testing.T) { c := getCommand(MaximumNArgs(3), false) output, err := executeCommand(c, "a", "b") expectSuccess(output, err, t) } func TestMaximumNArgsWithMoreArgs(t *testing.T) { c := getCommand(MaximumNArgs(2), false) _, err := executeCommand(c, "a", "b", "c") maximumNArgsWithMoreArgs(err, t) } func TestExactArgs(t *testing.T) { c := getCommand(ExactArgs(3), false) output, err := executeCommand(c, "a", "b", "c") expectSuccess(output, err, t) } func TestExactArgsWithInvalidCount(t *testing.T) { c := getCommand(ExactArgs(2), false) _, err := executeCommand(c, "a", "b", "c") exactArgsWithInvalidCount(err, t) } func TestExactValidArgs(t *testing.T) { c := getCommand(ExactValidArgs(3), true) output, err := executeCommand(c, "three", "one", "two") expectSuccess(output, err, t) } func TestExactValidArgsWithInvalidCount(t *testing.T) { c := getCommand(ExactValidArgs(2), false) _, err := executeCommand(c, "three", "one", "two") exactArgsWithInvalidCount(err, t) } func TestExactValidArgsWithInvalidArgs(t *testing.T) { c := getCommand(ExactValidArgs(3), true) _, err := executeCommand(c, "three", "a", "two") validWithInvalidArgs(err, t) } func TestRangeArgs(t *testing.T) { c := getCommand(RangeArgs(2, 4), false) output, err := executeCommand(c, "a", "b", "c") expectSuccess(output, err, t) } func TestRangeArgsWithInvalidCount(t *testing.T) { c := getCommand(RangeArgs(2, 4), false) _, err := executeCommand(c, "a") rangeArgsWithInvalidCount(err, t) } func TestRootTakesNoArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "illegal", "args") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "root"` if !strings.Contains(got, expected) { t.Errorf("expected %q, got %q", expected, got) } } func TestRootTakesArgs(t *testing.T) { rootCmd := &Command{Use: "root", Args: ArbitraryArgs, Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "legal", "args") if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestChildTakesNoArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "child", "illegal", "args") if err == nil { t.Fatal("Expected an error") } got := err.Error() expected := `unknown command "illegal" for "root child"` if !strings.Contains(got, expected) { t.Errorf("expected %q, got %q", expected, got) } } func TestChildTakesArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Args: ArbitraryArgs, Run: emptyRun} rootCmd.AddCommand(childCmd) _, err := executeCommand(rootCmd, "child", "legal", "args") if err != nil { t.Fatalf("Unexpected error: %v", err) } } func TestMatchAll(t *testing.T) { // Somewhat contrived example check that ensures there are exactly 3 // arguments, and each argument is exactly 2 bytes long. pargs := MatchAll( ExactArgs(3), func(cmd *Command, args []string) error { for _, arg := range args { if len([]byte(arg)) != 2 { return fmt.Errorf("expected to be exactly 2 bytes long") } } return nil }, ) testCases := map[string]struct { args []string fail bool }{ "happy path": { []string{"aa", "bb", "cc"}, false, }, "incorrect number of args": { []string{"aa", "bb", "cc", "dd"}, true, }, "incorrect number of bytes in one arg": { []string{"aa", "bb", "abc"}, true, }, } rootCmd := &Command{Use: "root", Args: pargs, Run: emptyRun} for name, tc := range testCases { t.Run(name, func(t *testing.T) { _, err := executeCommand(rootCmd, tc.args...) if err != nil && !tc.fail { t.Errorf("unexpected: %v\n", err) } if err == nil && tc.fail { t.Errorf("expected error") } }) } } cobra-1.3.0/bash_completions.go000066400000000000000000000535001415616037300164720ustar00rootroot00000000000000package cobra import ( "bytes" "fmt" "io" "os" "sort" "strings" "github.com/spf13/pflag" ) // Annotations for Bash completion. const ( BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" BashCompCustom = "cobra_annotation_bash_completion_custom" BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" ) func writePreamble(buf io.StringWriter, name string) { WriteStringAndCheck(buf, fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(` __%[1]s_debug() { if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } # Homebrew on Macs have version 1.3 of bash-completion which doesn't include # _init_completion. This is a very minimal version of that function. __%[1]s_init_completion() { COMPREPLY=() _get_comp_words_by_ref "$@" cur prev words cword } __%[1]s_index_of_word() { local w word=$1 shift index=0 for w in "$@"; do [[ $w = "$word" ]] && return index=$((index+1)) done index=-1 } __%[1]s_contains_word() { local w word=$1; shift for w in "$@"; do [[ $w = "$word" ]] && return done return 1 } __%[1]s_handle_go_custom_completion() { __%[1]s_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}" local shellCompDirectiveError=%[3]d local shellCompDirectiveNoSpace=%[4]d local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d local out requestComp lastParam lastChar comp directive args # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly %[1]s allows to handle aliases args=("${words[@]:1}") requestComp="${words[0]} %[2]s ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} __%[1]s_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}" if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "${FUNCNAME[0]}: Adding extra empty parameter" requestComp="${requestComp} \"\"" fi __%[1]s_debug "${FUNCNAME[0]}: calling ${requestComp}" # Use eval to handle any environment variables and such out=$(eval "${requestComp}" 2>/dev/null) # Extract the directive integer at the very end of the output following a colon (:) directive=${out##*:} # Remove the directive out=${out%%:*} if [ "${directive}" = "${out}" ]; then # There is not directive specified directive=0 fi __%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. __%[1]s_debug "${FUNCNAME[0]}: received error from custom completion go code" return else if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __%[1]s_debug "${FUNCNAME[0]}: activating no space" compopt -o nospace fi fi if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __%[1]s_debug "${FUNCNAME[0]}: activating no file completion" compopt +o default fi fi fi if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local fullFilter filter filteringCmd # Do not use quotes around the $out variable or else newline # characters will be kept. for filter in ${out[*]}; do fullFilter+="$filter|" done filteringCmd="_filedir $fullFilter" __%[1]s_debug "File filtering command: $filteringCmd" $filteringCmd elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only local subdir # Use printf to strip any trailing newline subdir=$(printf "%%s" "${out[0]}") if [ -n "$subdir" ]; then __%[1]s_debug "Listing directories in $subdir" __%[1]s_handle_subdirs_in_dir_flag "$subdir" else __%[1]s_debug "Listing directories in ." _filedir -d fi else while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${out[*]}" -- "$cur") fi } __%[1]s_handle_reply() { __%[1]s_debug "${FUNCNAME[0]}" local comp case $cur in -*) if [[ $(type -t compopt) = "builtin" ]]; then compopt -o nospace fi local allflags if [ ${#must_have_one_flag[@]} -ne 0 ]; then allflags=("${must_have_one_flag[@]}") else allflags=("${flags[*]} ${two_word_flags[*]}") fi while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${allflags[*]}" -- "$cur") if [[ $(type -t compopt) = "builtin" ]]; then [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace fi # complete after --flag=abc if [[ $cur == *=* ]]; then if [[ $(type -t compopt) = "builtin" ]]; then compopt +o nospace fi local index flag flag="${cur%%=*}" __%[1]s_index_of_word "${flag}" "${flags_with_completion[@]}" COMPREPLY=() if [[ ${index} -ge 0 ]]; then PREFIX="" cur="${cur#*=}" ${flags_completion[${index}]} if [ -n "${ZSH_VERSION:-}" ]; then # zsh completion needs --flag= prefix eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" fi fi fi if [[ -z "${flag_parsing_disabled}" ]]; then # If flag parsing is enabled, we have completed the flags and can return. # If flag parsing is disabled, we may not know all (or any) of the flags, so we fallthrough # to possibly call handle_go_custom_completion. return 0; fi ;; esac # check if we are handling a flag with special work handling local index __%[1]s_index_of_word "${prev}" "${flags_with_completion[@]}" if [[ ${index} -ge 0 ]]; then ${flags_completion[${index}]} return fi # we are parsing a flag and don't have a special handler, no completion if [[ ${cur} != "${words[cword]}" ]]; then return fi local completions completions=("${commands[@]}") if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then completions+=("${must_have_one_noun[@]}") elif [[ -n "${has_completion_function}" ]]; then # if a go completion function is provided, defer to that function __%[1]s_handle_go_custom_completion fi if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then completions+=("${must_have_one_flag[@]}") fi while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${completions[*]}" -- "$cur") if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${noun_aliases[*]}" -- "$cur") fi if [[ ${#COMPREPLY[@]} -eq 0 ]]; then if declare -F __%[1]s_custom_func >/dev/null; then # try command name qualified custom func __%[1]s_custom_func else # otherwise fall back to unqualified for compatibility declare -F __custom_func >/dev/null && __custom_func fi fi # available in bash-completion >= 2, not always present on macOS if declare -F __ltrim_colon_completions >/dev/null; then __ltrim_colon_completions "$cur" fi # If there is only 1 completion and it is a flag with an = it will be completed # but we don't want a space after the = if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then compopt -o nospace fi } # The arguments should be in the form "ext1|ext2|extn" __%[1]s_handle_filename_extension_flag() { local ext="$1" _filedir "@(${ext})" } __%[1]s_handle_subdirs_in_dir_flag() { local dir="$1" pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return } __%[1]s_handle_flag() { __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" # if a command required a flag, and we found it, unset must_have_one_flag() local flagname=${words[c]} local flagvalue="" # if the word contained an = if [[ ${words[c]} == *"="* ]]; then flagvalue=${flagname#*=} # take in as flagvalue after the = flagname=${flagname%%=*} # strip everything after the = flagname="${flagname}=" # but put the = back fi __%[1]s_debug "${FUNCNAME[0]}: looking for ${flagname}" if __%[1]s_contains_word "${flagname}" "${must_have_one_flag[@]}"; then must_have_one_flag=() fi # if you set a flag which only applies to this command, don't show subcommands if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then commands=() fi # keep flag value with flagname as flaghash # flaghash variable is an associative array which is only supported in bash > 3. if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then if [ -n "${flagvalue}" ] ; then flaghash[${flagname}]=${flagvalue} elif [ -n "${words[ $((c+1)) ]}" ] ; then flaghash[${flagname}]=${words[ $((c+1)) ]} else flaghash[${flagname}]="true" # pad "true" for bool flag fi fi # skip the argument to a two word flag if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" c=$((c+1)) # if we are looking for a flags value, don't show commands if [[ $c -eq $cword ]]; then commands=() fi fi c=$((c+1)) } __%[1]s_handle_noun() { __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if __%[1]s_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then must_have_one_noun=() elif __%[1]s_contains_word "${words[c]}" "${noun_aliases[@]}"; then must_have_one_noun=() fi nouns+=("${words[c]}") c=$((c+1)) } __%[1]s_handle_command() { __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" local next_command if [[ -n ${last_command} ]]; then next_command="_${last_command}_${words[c]//:/__}" else if [[ $c -eq 0 ]]; then next_command="_%[1]s_root_command" else next_command="_${words[c]//:/__}" fi fi c=$((c+1)) __%[1]s_debug "${FUNCNAME[0]}: looking for ${next_command}" declare -F "$next_command" >/dev/null && $next_command } __%[1]s_handle_word() { if [[ $c -ge $cword ]]; then __%[1]s_handle_reply return fi __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if [[ "${words[c]}" == -* ]]; then __%[1]s_handle_flag elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then __%[1]s_handle_command elif [[ $c -eq 0 ]]; then __%[1]s_handle_command elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then # aliashash variable is an associative array which is only supported in bash > 3. if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then words[c]=${aliashash[${words[c]}]} __%[1]s_handle_command else __%[1]s_handle_noun fi else __%[1]s_handle_noun fi __%[1]s_handle_word } `, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } func writePostscript(buf io.StringWriter, name string) { name = strings.Replace(name, ":", "__", -1) WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(`{ local cur prev words cword split declare -A flaghash 2>/dev/null || : declare -A aliashash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then _init_completion -s || return else __%[1]s_init_completion -n "=" || return fi local c=0 local flag_parsing_disabled= local flags=() local two_word_flags=() local local_nonpersistent_flags=() local flags_with_completion=() local flags_completion=() local commands=("%[1]s") local command_aliases=() local must_have_one_flag=() local must_have_one_noun=() local has_completion_function="" local last_command="" local nouns=() local noun_aliases=() __%[1]s_handle_word } `, name)) WriteStringAndCheck(buf, fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then complete -o default -F __start_%s %s else complete -o default -o nospace -F __start_%s %s fi `, name, name, name, name)) WriteStringAndCheck(buf, "# ex: ts=4 sw=4 et filetype=sh\n") } func writeCommands(buf io.StringWriter, cmd *Command) { WriteStringAndCheck(buf, " commands=()\n") for _, c := range cmd.Commands() { if !c.IsAvailableCommand() && c != cmd.helpCommand { continue } WriteStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name())) writeCmdAliases(buf, c) } WriteStringAndCheck(buf, "\n") } func writeFlagHandler(buf io.StringWriter, name string, annotations map[string][]string, cmd *Command) { for key, value := range annotations { switch key { case BashCompFilenameExt: WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) > 0 { ext = fmt.Sprintf("__%s_handle_filename_extension_flag ", cmd.Root().Name()) + strings.Join(value, "|") } else { ext = "_filedir" } WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext)) case BashCompCustom: WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) if len(value) > 0 { handlers := strings.Join(value, "; ") WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) } else { WriteStringAndCheck(buf, " flags_completion+=(:)\n") } case BashCompSubdirsInDir: WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) == 1 { ext = fmt.Sprintf("__%s_handle_subdirs_in_dir_flag ", cmd.Root().Name()) + value[0] } else { ext = "_filedir -d" } WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext)) } } } const cbn = "\")\n" func writeShortFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) { name := flag.Shorthand format := " " if len(flag.NoOptDefVal) == 0 { format += "two_word_" } format += "flags+=(\"-%s" + cbn WriteStringAndCheck(buf, fmt.Sprintf(format, name)) writeFlagHandler(buf, "-"+name, flag.Annotations, cmd) } func writeFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) { name := flag.Name format := " flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { format += "=" } format += cbn WriteStringAndCheck(buf, fmt.Sprintf(format, name)) if len(flag.NoOptDefVal) == 0 { format = " two_word_flags+=(\"--%s" + cbn WriteStringAndCheck(buf, fmt.Sprintf(format, name)) } writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) } func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) { name := flag.Name format := " local_nonpersistent_flags+=(\"--%[1]s" + cbn if len(flag.NoOptDefVal) == 0 { format += " local_nonpersistent_flags+=(\"--%[1]s=" + cbn } WriteStringAndCheck(buf, fmt.Sprintf(format, name)) if len(flag.Shorthand) > 0 { WriteStringAndCheck(buf, fmt.Sprintf(" local_nonpersistent_flags+=(\"-%s\")\n", flag.Shorthand)) } } // Setup annotations for go completions for registered flags func prepareCustomAnnotationsForFlags(cmd *Command) { flagCompletionMutex.RLock() defer flagCompletionMutex.RUnlock() for flag := range flagCompletionFunctions { // Make sure the completion script calls the __*_go_custom_completion function for // every registered flag. We need to do this here (and not when the flag was registered // for completion) so that we can know the root command name for the prefix // of ___go_custom_completion if flag.Annotations == nil { flag.Annotations = map[string][]string{} } flag.Annotations[BashCompCustom] = []string{fmt.Sprintf("__%[1]s_handle_go_custom_completion", cmd.Root().Name())} } } func writeFlags(buf io.StringWriter, cmd *Command) { prepareCustomAnnotationsForFlags(cmd) WriteStringAndCheck(buf, ` flags=() two_word_flags=() local_nonpersistent_flags=() flags_with_completion=() flags_completion=() `) if cmd.DisableFlagParsing { WriteStringAndCheck(buf, " flag_parsing_disabled=1\n") } localNonPersistentFlags := cmd.LocalNonPersistentFlags() cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } writeFlag(buf, flag, cmd) if len(flag.Shorthand) > 0 { writeShortFlag(buf, flag, cmd) } // localNonPersistentFlags are used to stop the completion of subcommands when one is set // if TraverseChildren is true we should allow to complete subcommands if localNonPersistentFlags.Lookup(flag.Name) != nil && !cmd.Root().TraverseChildren { writeLocalNonPersistentFlag(buf, flag) } }) cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } writeFlag(buf, flag, cmd) if len(flag.Shorthand) > 0 { writeShortFlag(buf, flag, cmd) } }) WriteStringAndCheck(buf, "\n") } func writeRequiredFlag(buf io.StringWriter, cmd *Command) { WriteStringAndCheck(buf, " must_have_one_flag=()\n") flags := cmd.NonInheritedFlags() flags.VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return } for key := range flag.Annotations { switch key { case BashCompOneRequiredFlag: format := " must_have_one_flag+=(\"--%s" if flag.Value.Type() != "bool" { format += "=" } format += cbn WriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name)) if len(flag.Shorthand) > 0 { WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_flag+=(\"-%s"+cbn, flag.Shorthand)) } } } }) } func writeRequiredNouns(buf io.StringWriter, cmd *Command) { WriteStringAndCheck(buf, " must_have_one_noun=()\n") sort.Strings(cmd.ValidArgs) for _, value := range cmd.ValidArgs { // Remove any description that may be included following a tab character. // Descriptions are not supported by bash completion. value = strings.Split(value, "\t")[0] WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) } if cmd.ValidArgsFunction != nil { WriteStringAndCheck(buf, " has_completion_function=1\n") } } func writeCmdAliases(buf io.StringWriter, cmd *Command) { if len(cmd.Aliases) == 0 { return } sort.Strings(cmd.Aliases) WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then`, "\n")) for _, value := range cmd.Aliases { WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value)) WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) } WriteStringAndCheck(buf, ` fi`) WriteStringAndCheck(buf, "\n") } func writeArgAliases(buf io.StringWriter, cmd *Command) { WriteStringAndCheck(buf, " noun_aliases=()\n") sort.Strings(cmd.ArgAliases) for _, value := range cmd.ArgAliases { WriteStringAndCheck(buf, fmt.Sprintf(" noun_aliases+=(%q)\n", value)) } } func gen(buf io.StringWriter, cmd *Command) { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() && c != cmd.helpCommand { continue } gen(buf, c) } commandName := cmd.CommandPath() commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, ":", "__", -1) if cmd.Root() == cmd { WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName)) } else { WriteStringAndCheck(buf, fmt.Sprintf("_%s()\n{\n", commandName)) } WriteStringAndCheck(buf, fmt.Sprintf(" last_command=%q\n", commandName)) WriteStringAndCheck(buf, "\n") WriteStringAndCheck(buf, " command_aliases=()\n") WriteStringAndCheck(buf, "\n") writeCommands(buf, cmd) writeFlags(buf, cmd) writeRequiredFlag(buf, cmd) writeRequiredNouns(buf, cmd) writeArgAliases(buf, cmd) WriteStringAndCheck(buf, "}\n\n") } // GenBashCompletion generates bash completion file and writes to the passed writer. func (c *Command) GenBashCompletion(w io.Writer) error { buf := new(bytes.Buffer) writePreamble(buf, c.Name()) if len(c.BashCompletionFunction) > 0 { buf.WriteString(c.BashCompletionFunction + "\n") } gen(buf, c) writePostscript(buf, c.Name()) _, err := buf.WriteTo(w) return err } func nonCompletableFlag(flag *pflag.Flag) bool { return flag.Hidden || len(flag.Deprecated) > 0 } // GenBashCompletionFile generates bash completion file. func (c *Command) GenBashCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.GenBashCompletion(outFile) } cobra-1.3.0/bash_completions.md000066400000000000000000000073351415616037300164720ustar00rootroot00000000000000# Generating Bash Completions For Your cobra.Command Please refer to [Shell Completions](shell_completions.md) for details. ## Bash legacy dynamic completions For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the `ValidArgsFunction` solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side `ValidArgsFunction` and `RegisterFlagCompletionFunc()`, as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution. **Note**: Cobra's default `completion` command uses bash completion V2. If you are currently using Cobra's legacy dynamic completion solution, you should not use the default `completion` command but continue using your own. The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions. Some code that works in kubernetes: ```bash const ( bash_completion_func = `__kubectl_parse_get() { local kubectl_output out if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then out=($(echo "${kubectl_output}" | awk '{print $1}')) COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } __kubectl_get_resource() { if [[ ${#nouns[@]} -eq 0 ]]; then return 1 fi __kubectl_parse_get ${nouns[${#nouns[@]} -1]} if [[ $? -eq 0 ]]; then return 0 fi } __kubectl_custom_func() { case ${last_command} in kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) __kubectl_get_resource return ;; *) ;; esac } `) ``` And then I set that in my command definition: ```go cmds := &cobra.Command{ Use: "kubectl", Short: "kubectl controls the Kubernetes cluster manager", Long: `kubectl controls the Kubernetes cluster manager. Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, Run: runHelp, BashCompletionFunction: bash_completion_func, } ``` The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`___custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! Similarly, for flags: ```go annotation := make(map[string][]string) annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} flag := &pflag.Flag{ Name: "namespace", Usage: usage, Annotations: annotation, } cmd.Flags().AddFlag(flag) ``` In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction` value, e.g.: ```bash __kubectl_get_namespaces() { local template template="{{ range .items }}{{ .metadata.name }} {{ end }}" local kubectl_out if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) fi } ``` cobra-1.3.0/bash_completionsV2.go000066400000000000000000000250221415616037300167000ustar00rootroot00000000000000package cobra import ( "bytes" "fmt" "io" "os" ) func (c *Command) genBashCompletion(w io.Writer, includeDesc bool) error { buf := new(bytes.Buffer) genBashComp(buf, c.Name(), includeDesc) _, err := buf.WriteTo(w) return err } func genBashComp(buf io.StringWriter, name string, includeDesc bool) { compCmd := ShellCompRequestCmd if !includeDesc { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf(`# bash completion V2 for %-36[1]s -*- shell-script -*- __%[1]s_debug() { if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } # Macs have bash3 for which the bash-completion package doesn't include # _init_completion. This is a minimal version of that function. __%[1]s_init_completion() { COMPREPLY=() _get_comp_words_by_ref "$@" cur prev words cword } # This function calls the %[1]s program to obtain the completion # results and the directive. It fills the 'out' and 'directive' vars. __%[1]s_get_completion_results() { local requestComp lastParam lastChar args # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly %[1]s allows to handle aliases args=("${words[@]:1}") requestComp="${words[0]} %[2]s ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} __%[1]s_debug "lastParam ${lastParam}, lastChar ${lastChar}" if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" requestComp="${requestComp} ''" fi # When completing a flag with an = (e.g., %[1]s -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur if [[ "${cur}" == -*=* ]]; then cur="${cur#*=}" fi __%[1]s_debug "Calling ${requestComp}" # Use eval to handle any environment variables and such out=$(eval "${requestComp}" 2>/dev/null) # Extract the directive integer at the very end of the output following a colon (:) directive=${out##*:} # Remove the directive out=${out%%:*} if [ "${directive}" = "${out}" ]; then # There is not directive specified directive=0 fi __%[1]s_debug "The completion directive is: ${directive}" __%[1]s_debug "The completions are: ${out[*]}" } __%[1]s_process_completion_results() { local shellCompDirectiveError=%[3]d local shellCompDirectiveNoSpace=%[4]d local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. __%[1]s_debug "Received error from custom completion go code" return else if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __%[1]s_debug "Activating no space" compopt -o nospace else __%[1]s_debug "No space directive not supported in this version of bash" fi fi if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __%[1]s_debug "Activating no file completion" compopt +o default else __%[1]s_debug "No file completion directive not supported in this version of bash" fi fi fi if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local fullFilter filter filteringCmd # Do not use quotes around the $out variable or else newline # characters will be kept. for filter in ${out[*]}; do fullFilter+="$filter|" done filteringCmd="_filedir $fullFilter" __%[1]s_debug "File filtering command: $filteringCmd" $filteringCmd elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only # Use printf to strip any trailing newline local subdir subdir=$(printf "%%s" "${out[0]}") if [ -n "$subdir" ]; then __%[1]s_debug "Listing directories in $subdir" pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return else __%[1]s_debug "Listing directories in ." _filedir -d fi else __%[1]s_handle_completion_types fi __%[1]s_handle_special_char "$cur" : __%[1]s_handle_special_char "$cur" = } __%[1]s_handle_completion_types() { __%[1]s_debug "__%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE" case $COMP_TYPE in 37|42) # Type: menu-complete/menu-complete-backward and insert-completions # If the user requested inserting one completion at a time, or all # completions at once on the command-line we must remove the descriptions. # https://github.com/spf13/cobra/issues/1508 local tab comp tab=$(printf '\t') while IFS='' read -r comp; do # Strip any description comp=${comp%%%%$tab*} # Only consider the completions that match comp=$(compgen -W "$comp" -- "$cur") if [ -n "$comp" ]; then COMPREPLY+=("$comp") fi done < <(printf "%%s\n" "${out[@]}") ;; *) # Type: complete (normal completion) __%[1]s_handle_standard_completion_case ;; esac } __%[1]s_handle_standard_completion_case() { local tab comp tab=$(printf '\t') local longest=0 # Look for the longest completion so that we can format things nicely while IFS='' read -r comp; do # Strip any description before checking the length comp=${comp%%%%$tab*} # Only consider the completions that match comp=$(compgen -W "$comp" -- "$cur") if ((${#comp}>longest)); then longest=${#comp} fi done < <(printf "%%s\n" "${out[@]}") local completions=() while IFS='' read -r comp; do if [ -z "$comp" ]; then continue fi __%[1]s_debug "Original comp: $comp" comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")" __%[1]s_debug "Final comp: $comp" completions+=("$comp") done < <(printf "%%s\n" "${out[@]}") while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${completions[*]}" -- "$cur") # If there is a single completion left, remove the description text if [ ${#COMPREPLY[*]} -eq 1 ]; then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" comp="${COMPREPLY[0]%%%% *}" __%[1]s_debug "Removed description from single completion, which is now: ${comp}" COMPREPLY=() COMPREPLY+=("$comp") fi } __%[1]s_handle_special_char() { local comp="$1" local char=$2 if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then local word=${comp%%"${comp##*${char}}"} local idx=${#COMPREPLY[*]} while [[ $((--idx)) -ge 0 ]]; do COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} done fi } __%[1]s_format_comp_descriptions() { local tab tab=$(printf '\t') local comp="$1" local longest=$2 # Properly format the description string which follows a tab character if there is one if [[ "$comp" == *$tab* ]]; then desc=${comp#*$tab} comp=${comp%%%%$tab*} # $COLUMNS stores the current shell width. # Remove an extra 4 because we add 2 spaces and 2 parentheses. maxdesclength=$(( COLUMNS - longest - 4 )) # Make sure we can fit a description of at least 8 characters # if we are to align the descriptions. if [[ $maxdesclength -gt 8 ]]; then # Add the proper number of spaces to align the descriptions for ((i = ${#comp} ; i < longest ; i++)); do comp+=" " done else # Don't pad the descriptions so we can fit more text after the completion maxdesclength=$(( COLUMNS - ${#comp} - 4 )) fi # If there is enough space for any description text, # truncate the descriptions that are too long for the shell width if [ $maxdesclength -gt 0 ]; then if [ ${#desc} -gt $maxdesclength ]; then desc=${desc:0:$(( maxdesclength - 1 ))} desc+="…" fi comp+=" ($desc)" fi fi # Must use printf to escape all special characters printf "%%q" "${comp}" } __start_%[1]s() { local cur prev words cword split COMPREPLY=() # Call _init_completion from the bash-completion package # to prepare the arguments properly if declare -F _init_completion >/dev/null 2>&1; then _init_completion -n "=:" || return else __%[1]s_init_completion -n "=:" || return fi __%[1]s_debug __%[1]s_debug "========= starting completion logic ==========" __%[1]s_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" # The user could have moved the cursor backwards on the command-line. # We need to trigger completion from the $cword location, so we need # to truncate the command-line ($words) up to the $cword location. words=("${words[@]:0:$cword+1}") __%[1]s_debug "Truncated words[*]: ${words[*]}," local out directive __%[1]s_get_completion_results __%[1]s_process_completion_results } if [[ $(type -t compopt) = "builtin" ]]; then complete -o default -F __start_%[1]s %[1]s else complete -o default -o nospace -F __start_%[1]s %[1]s fi # ex: ts=4 sw=4 et filetype=sh `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } // GenBashCompletionFileV2 generates Bash completion version 2. func (c *Command) GenBashCompletionFileV2(filename string, includeDesc bool) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.GenBashCompletionV2(outFile, includeDesc) } // GenBashCompletionV2 generates Bash completion file version 2 // and writes it to the passed writer. func (c *Command) GenBashCompletionV2(w io.Writer, includeDesc bool) error { return c.genBashCompletion(w, includeDesc) } cobra-1.3.0/bash_completions_test.go000066400000000000000000000220751415616037300175340ustar00rootroot00000000000000package cobra import ( "bytes" "fmt" "os" "os/exec" "regexp" "strings" "testing" ) func checkOmit(t *testing.T, found, unexpected string) { if strings.Contains(found, unexpected) { t.Errorf("Got: %q\nBut should not have!\n", unexpected) } } func check(t *testing.T, found, expected string) { if !strings.Contains(found, expected) { t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found) } } func checkNumOccurrences(t *testing.T, found, expected string, expectedOccurrences int) { numOccurrences := strings.Count(found, expected) if numOccurrences != expectedOccurrences { t.Errorf("Expecting to contain %d occurrences of: \n %q\nGot %d:\n %q\n", expectedOccurrences, expected, numOccurrences, found) } } func checkRegex(t *testing.T, found, pattern string) { matched, err := regexp.MatchString(pattern, found) if err != nil { t.Errorf("Error thrown performing MatchString: \n %s\n", err) } if !matched { t.Errorf("Expecting to match: \n %q\nGot:\n %q\n", pattern, found) } } func runShellCheck(s string) error { cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", "SC2034", // PREFIX appears unused. Verify it or export it. ) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout stdin, err := cmd.StdinPipe() if err != nil { return err } go func() { _, err := stdin.Write([]byte(s)) CheckErr(err) stdin.Close() }() return cmd.Run() } // World worst custom function, just keep telling you to enter hello! const bashCompletionFunc = `__root_custom_func() { COMPREPLY=( "hello" ) } ` func TestBashCompletions(t *testing.T) { rootCmd := &Command{ Use: "root", ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}, ValidArgs: []string{"pod", "node", "service", "replicationcontroller"}, BashCompletionFunction: bashCompletionFunc, Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") assertNoErr(t, rootCmd.MarkFlagRequired("introot")) // Filename. rootCmd.Flags().String("filename", "", "Enter a filename") assertNoErr(t, rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) // Persistent filename. rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") assertNoErr(t, rootCmd.MarkPersistentFlagFilename("persistent-filename")) assertNoErr(t, rootCmd.MarkPersistentFlagRequired("persistent-filename")) // Filename extensions. rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") assertNoErr(t, rootCmd.MarkFlagFilename("filename-ext")) rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") assertNoErr(t, rootCmd.MarkFlagCustom("custom", "__complete_custom")) // Subdirectories in a given directory. rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") assertNoErr(t, rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})) // For two word flags check rootCmd.Flags().StringP("two", "t", "", "this is two word flags") rootCmd.Flags().BoolP("two-w-default", "T", false, "this is not two word flags") echoCmd := &Command{ Use: "echo [string to echo]", Aliases: []string{"say"}, Short: "Echo anything to the screen", Long: "an utterly useless command for testing.", Example: "Just run cobra-test echo", Run: emptyRun, } echoCmd.Flags().String("filename", "", "Enter a filename") assertNoErr(t, echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)") assertNoErr(t, echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"})) printCmd := &Command{ Use: "print [string to print]", Args: MinimumNArgs(1), Short: "Print anything to the screen", Long: "an absolutely utterly useless command for testing.", Run: emptyRun, } deprecatedCmd := &Command{ Use: "deprecated [can't do anything here]", Args: NoArgs, Short: "A command which is deprecated", Long: "an absolutely utterly useless command for testing deprecation!.", Deprecated: "Please use echo instead", Run: emptyRun, } colonCmd := &Command{ Use: "cmd:colon", Run: emptyRun, } timesCmd := &Command{ Use: "times [# times] [string to echo]", SuggestFor: []string{"counts"}, Args: OnlyValidArgs, ValidArgs: []string{"one", "two", "three", "four"}, Short: "Echo anything to the screen more times", Long: "a slightly useless command for testing.", Run: emptyRun, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenBashCompletion(buf)) output := buf.String() check(t, output, "_root") check(t, output, "_root_echo") check(t, output, "_root_echo_times") check(t, output, "_root_print") check(t, output, "_root_cmd__colon") // check for required flags check(t, output, `must_have_one_flag+=("--introot=")`) check(t, output, `must_have_one_flag+=("--persistent-filename=")`) // check for custom completion function with both qualified and unqualified name checkNumOccurrences(t, output, `__custom_func`, 2) // 1. check existence, 2. invoke checkNumOccurrences(t, output, `__root_custom_func`, 3) // 1. check existence, 2. invoke, 3. actual definition // check for custom completion function body check(t, output, `COMPREPLY=( "hello" )`) // check for required nouns check(t, output, `must_have_one_noun+=("pod")`) // check for noun aliases check(t, output, `noun_aliases+=("pods")`) check(t, output, `noun_aliases+=("rc")`) checkOmit(t, output, `must_have_one_noun+=("pods")`) // check for filename extension flags check(t, output, `flags_completion+=("_filedir")`) // check for filename extension flags check(t, output, `must_have_one_noun+=("three")`) // check for filename extension flags check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_filename_extension_flag json|yaml|yml")`, rootCmd.Name())) // check for filename extension flags in a subcommand checkRegex(t, output, fmt.Sprintf(`_root_echo\(\)\n{[^}]*flags_completion\+=\("__%s_handle_filename_extension_flag json\|yaml\|yml"\)`, rootCmd.Name())) // check for custom flags check(t, output, `flags_completion+=("__complete_custom")`) // check for subdirs_in_dir flags check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_subdirs_in_dir_flag themes")`, rootCmd.Name())) // check for subdirs_in_dir flags in a subcommand checkRegex(t, output, fmt.Sprintf(`_root_echo\(\)\n{[^}]*flags_completion\+=\("__%s_handle_subdirs_in_dir_flag config"\)`, rootCmd.Name())) // check two word flags check(t, output, `two_word_flags+=("--two")`) check(t, output, `two_word_flags+=("-t")`) checkOmit(t, output, `two_word_flags+=("--two-w-default")`) checkOmit(t, output, `two_word_flags+=("-T")`) // check local nonpersistent flag check(t, output, `local_nonpersistent_flags+=("--two")`) check(t, output, `local_nonpersistent_flags+=("--two=")`) check(t, output, `local_nonpersistent_flags+=("-t")`) check(t, output, `local_nonpersistent_flags+=("--two-w-default")`) check(t, output, `local_nonpersistent_flags+=("-T")`) checkOmit(t, output, deprecatedCmd.Name()) // If available, run shellcheck against the script. if err := exec.Command("which", "shellcheck").Run(); err != nil { return } if err := runShellCheck(output); err != nil { t.Fatalf("shellcheck failed: %v", err) } } func TestBashCompletionHiddenFlag(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} const flagName = "hiddenFlag" c.Flags().Bool(flagName, false, "") assertNoErr(t, c.Flags().MarkHidden(flagName)) buf := new(bytes.Buffer) assertNoErr(t, c.GenBashCompletion(buf)) output := buf.String() if strings.Contains(output, flagName) { t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output) } } func TestBashCompletionDeprecatedFlag(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} const flagName = "deprecated-flag" c.Flags().Bool(flagName, false, "") assertNoErr(t, c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead")) buf := new(bytes.Buffer) assertNoErr(t, c.GenBashCompletion(buf)) output := buf.String() if strings.Contains(output, flagName) { t.Errorf("expected completion to not include %q flag: Got %v", flagName, output) } } func TestBashCompletionTraverseChildren(t *testing.T) { c := &Command{Use: "c", Run: emptyRun, TraverseChildren: true} c.Flags().StringP("string-flag", "s", "", "string flag") c.Flags().BoolP("bool-flag", "b", false, "bool flag") buf := new(bytes.Buffer) assertNoErr(t, c.GenBashCompletion(buf)) output := buf.String() // check that local nonpersistent flag are not set since we have TraverseChildren set to true checkOmit(t, output, `local_nonpersistent_flags+=("--string-flag")`) checkOmit(t, output, `local_nonpersistent_flags+=("--string-flag=")`) checkOmit(t, output, `local_nonpersistent_flags+=("-s")`) checkOmit(t, output, `local_nonpersistent_flags+=("--bool-flag")`) checkOmit(t, output, `local_nonpersistent_flags+=("-b")`) } cobra-1.3.0/cobra.go000066400000000000000000000151211415616037300142240ustar00rootroot00000000000000// Copyright © 2013 Steve Francia . // // 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. // Commands similar to git, go tools and other modern CLI tools // inspired by go, go-Commander, gh and subcommand package cobra import ( "fmt" "io" "os" "reflect" "strconv" "strings" "text/template" "time" "unicode" ) var templateFuncs = template.FuncMap{ "trim": strings.TrimSpace, "trimRightSpace": trimRightSpace, "trimTrailingWhitespaces": trimRightSpace, "appendIfNotPresent": appendIfNotPresent, "rpad": rpad, "gt": Gt, "eq": Eq, } var initializers []func() // EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing // to automatically enable in CLI tools. // Set this to true to enable it. var EnablePrefixMatching = false // EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. // To disable sorting, set it to false. var EnableCommandSorting = true // MousetrapHelpText enables an information splash screen on Windows // if the CLI is started from explorer.exe. // To disable the mousetrap, just set this variable to blank string (""). // Works only on Microsoft Windows. var MousetrapHelpText = `This is a command line tool. You need to open cmd.exe and run it from there. ` // MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows // if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed. // To disable the mousetrap, just set MousetrapHelpText to blank string (""). // Works only on Microsoft Windows. var MousetrapDisplayDuration = 5 * time.Second // AddTemplateFunc adds a template function that's available to Usage and Help // template generation. func AddTemplateFunc(name string, tmplFunc interface{}) { templateFuncs[name] = tmplFunc } // AddTemplateFuncs adds multiple template functions that are available to Usage and // Help template generation. func AddTemplateFuncs(tmplFuncs template.FuncMap) { for k, v := range tmplFuncs { templateFuncs[k] = v } } // OnInitialize sets the passed functions to be run when each command's // Execute method is called. func OnInitialize(y ...func()) { initializers = append(initializers, y...) } // FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, // Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as // ints and then compared. func Gt(a interface{}, b interface{}) bool { var left, right int64 av := reflect.ValueOf(a) switch av.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: left = int64(av.Len()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: left = av.Int() case reflect.String: left, _ = strconv.ParseInt(av.String(), 10, 64) } bv := reflect.ValueOf(b) switch bv.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: right = int64(bv.Len()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: right = bv.Int() case reflect.String: right, _ = strconv.ParseInt(bv.String(), 10, 64) } return left > right } // FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. func Eq(a interface{}, b interface{}) bool { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: panic("Eq called on unsupported type") case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() == bv.Int() case reflect.String: return av.String() == bv.String() } return false } func trimRightSpace(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) } // FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. // appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. func appendIfNotPresent(s, stringToAppend string) string { if strings.Contains(s, stringToAppend) { return s } return s + " " + stringToAppend } // rpad adds padding to the right of a string. func rpad(s string, padding int) string { template := fmt.Sprintf("%%-%ds", padding) return fmt.Sprintf(template, s) } // tmpl executes the given template text on data, writing the result to w. func tmpl(w io.Writer, text string, data interface{}) error { t := template.New("top") t.Funcs(templateFuncs) template.Must(t.Parse(text)) return t.Execute(w, data) } // ld compares two strings and returns the levenshtein distance between them. func ld(s, t string, ignoreCase bool) int { if ignoreCase { s = strings.ToLower(s) t = strings.ToLower(t) } d := make([][]int, len(s)+1) for i := range d { d[i] = make([]int, len(t)+1) } for i := range d { d[i][0] = i } for j := range d[0] { d[0][j] = j } for j := 1; j <= len(t); j++ { for i := 1; i <= len(s); i++ { if s[i-1] == t[j-1] { d[i][j] = d[i-1][j-1] } else { min := d[i-1][j] if d[i][j-1] < min { min = d[i][j-1] } if d[i-1][j-1] < min { min = d[i-1][j-1] } d[i][j] = min + 1 } } } return d[len(s)][len(t)] } func stringInSlice(a string, list []string) bool { for _, b := range list { if b == a { return true } } return false } // CheckErr prints the msg with the prefix 'Error:' and exits with error code 1. If the msg is nil, it does nothing. func CheckErr(msg interface{}) { if msg != nil { fmt.Fprintln(os.Stderr, "Error:", msg) os.Exit(1) } } // WriteStringAndCheck writes a string into a buffer, and checks if the error is not nil. func WriteStringAndCheck(b io.StringWriter, s string) { _, err := b.WriteString(s) CheckErr(err) } cobra-1.3.0/cobra/000077500000000000000000000000001415616037300136755ustar00rootroot00000000000000cobra-1.3.0/cobra/Makefile000066400000000000000000000006101415616037300153320ustar00rootroot00000000000000XC_OS="linux darwin" XC_ARCH="amd64" XC_PARALLEL="2" BIN="../bin" SRC=$(shell find . -name "*.go") ifeq (, $(shell which gox)) $(warning "could not find gox in $(PATH), run: go get github.com/mitchellh/gox") endif .PHONY: all build default: all all: build build: gox \ -os=$(XC_OS) \ -arch=$(XC_ARCH) \ -parallel=$(XC_PARALLEL) \ -output=$(BIN)/{{.Dir}}_{{.OS}}_{{.Arch}} \ ; cobra-1.3.0/cobra/README.md000066400000000000000000000134101415616037300151530ustar00rootroot00000000000000# Cobra Generator Cobra provides its own program that will create your application and add any commands you want. It's the easiest way to incorporate Cobra into your application. Install the cobra generator with the command `go install github.com/spf13/cobra/cobra`. Go will automatically install it in your `$GOPATH/bin` directory which should be in your $PATH. Once installed you should have the `cobra` command available. Confirm by typing `cobra` at a command line. There are only two operations currently supported by the Cobra generator: ### cobra init The `cobra init [app]` command will create your initial application code for you. It is a very powerful application that will populate your program with the right structure so you can immediately enjoy all the benefits of Cobra. It can also apply the license you specify to your application. With the introduction of Go modules, the Cobra generator has been simplified to take advantage of modules. The Cobra generator works from within a Go module. #### Initalizing a module __If you already have a module, skip this step.__ If you want to initialize a new Go module: 1. Create a new directory 2. `cd` into that directory 3. run `go mod init ` e.g. ``` cd $HOME/code mkdir myapp cd myapp go mod init github.com/spf13/myapp ``` #### Initalizing an Cobra CLI application From within a Go module run `cobra init`. This will create a new barebones project for you to edit. You should be able to run your new application immediately. Try it with `go run main.go`. You will want to open up and edit 'cmd/root.go' and provide your own description and logic. e.g. ``` cd $HOME/code/myapp cobra init go run main.go ``` Cobra init can also be run from a subdirectory such as how the [cobra generator itself is organized](https://github.com/spf13/cobra). This is useful if you want to keep your application code separate from your library code. #### Optional flags: You can provide it your author name with the `--author` flag. e.g. `cobra init --author "Steve Francia spf@spf13.com"` You can provide a license to use with `--license` e.g. `cobra init --license apache` Use the `--viper` flag to automatically setup [viper](https://github.com/spf13/viper) Viper is a companion to Cobra intended to provide easy handling of environment variables and config files and seamlessly connecting them to the application flags. ### Add commands to a project Once a cobra application is initialized you can continue to use the Cobra generator to add additional commands to your application. The command to do this is `cobra add`. Let's say you created an app and you wanted the following commands for it: * app serve * app config * app config create In your project directory (where your main.go file is) you would run the following: ``` cobra add serve cobra add config cobra add create -p 'configCmd' ``` `cobra add` supports all the same optional flags as `cobra init` does (described above). You'll notice that this final command has a `-p` flag. This is used to assign a parent command to the newly added command. In this case, we want to assign the "create" command to the "config" command. All commands have a default parent of rootCmd if not specified. By default `cobra` will append `Cmd` to the name provided and uses this name for the internal variable name. When specifying a parent, be sure to match the variable name used in the code. *Note: Use camelCase (not snake_case/kebab-case) for command names. Otherwise, you will encounter errors. For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.* Once you have run these three commands you would have an app structure similar to the following: ``` ▾ app/ ▾ cmd/ config.go create.go serve.go root.go main.go ``` At this point you can run `go run main.go` and it would run your app. `go run main.go serve`, `go run main.go config`, `go run main.go config create` along with `go run main.go help serve`, etc. would all work. You now have a basic Cobra-based application up and running. Next step is to edit the files in cmd and customize them for your application. For complete details on using the Cobra library, please read the [The Cobra User Guide](https://github.com/spf13/cobra/blob/master/user_guide.md#using-the-cobra-library). Have fun! ### Configuring the cobra generator The Cobra generator will be easier to use if you provide a simple configuration file which will help you eliminate providing a bunch of repeated information in flags over and over. An example ~/.cobra.yaml file: ```yaml author: Steve Francia license: MIT viper: true ``` You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**, **AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**. You can specify no license by setting `license` to `none` or you can specify a custom license: ```yaml author: Steve Francia year: 2020 license: header: This file is part of CLI application foo. text: | {{ .copyright }} This is my license. There are many like it, but this one is mine. My license is my best friend. It is my life. I must master it as I must master my life. ``` In the above custom license configuration the `copyright` line in the License text is generated from the `author` and `year` properties. The content of the `LICENSE` file is ``` Copyright © 2020 Steve Francia This is my license. There are many like it, but this one is mine. My license is my best friend. It is my life. I must master it as I must master my life. ``` The `header` property is used as the license header files. No interpolation is done. This is the example of the go file header. ``` /* Copyright © 2020 Steve Francia This file is part of CLI application foo. */ ``` cobra-1.3.0/cobra/cmd/000077500000000000000000000000001415616037300144405ustar00rootroot00000000000000cobra-1.3.0/cobra/cmd/add.go000066400000000000000000000066021415616037300155230ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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 cmd import ( "fmt" "os" "unicode" "github.com/spf13/cobra" ) var ( packageName string parentName string addCmd = &cobra.Command{ Use: "add [command name]", Aliases: []string{"command"}, Short: "Add a command to a Cobra Application", Long: `Add (cobra add) will create a new command, with a license and the appropriate structure for a Cobra-based CLI application, and register it to its parent (default rootCmd). If you want your command to be public, pass in the command name with an initial uppercase letter. Example: cobra add server -> resulting in a new cmd/server.go`, Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { cobra.CheckErr(fmt.Errorf("add needs a name for the command")) } wd, err := os.Getwd() cobra.CheckErr(err) commandName := validateCmdName(args[0]) command := &Command{ CmdName: commandName, CmdParent: parentName, Project: &Project{ AbsolutePath: wd, Legal: getLicense(), Copyright: copyrightLine(), }, } cobra.CheckErr(command.Create()) fmt.Printf("%s created at %s\n", command.CmdName, command.AbsolutePath) }, } ) func init() { addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") cobra.CheckErr(addCmd.Flags().MarkDeprecated("package", "this operation has been removed.")) } // validateCmdName returns source without any dashes and underscore. // If there will be dash or underscore, next letter will be uppered. // It supports only ASCII (1-byte character) strings. // https://github.com/spf13/cobra/issues/269 func validateCmdName(source string) string { i := 0 l := len(source) // The output is initialized on demand, then first dash or underscore // occurs. var output string for i < l { if source[i] == '-' || source[i] == '_' { if output == "" { output = source[:i] } // If it's last rune and it's dash or underscore, // don't add it output and break the loop. if i == l-1 { break } // If next character is dash or underscore, // just skip the current character. if source[i+1] == '-' || source[i+1] == '_' { i++ continue } // If the current character is dash or underscore, // upper next letter and add to output. output += string(unicode.ToUpper(rune(source[i+1]))) // We know, what source[i] is dash or underscore and source[i+1] is // uppered character, so make i = i+2. i += 2 continue } // If the current character isn't dash or underscore, // just add it. if output != "" { output += string(source[i]) } i++ } if output == "" { return source // source is initially valid name. } return output } cobra-1.3.0/cobra/cmd/add_test.go000066400000000000000000000022441415616037300165600ustar00rootroot00000000000000package cmd import ( "fmt" "os" "testing" "github.com/spf13/viper" ) func TestGoldenAddCmd(t *testing.T) { viper.Set("useViper", true) viper.Set("license", "apache") command := &Command{ CmdName: "test", CmdParent: parentName, Project: getProject(), } defer os.RemoveAll(command.AbsolutePath) assertNoErr(t, command.Project.Create()) assertNoErr(t, command.Create()) generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName) goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName) err := compareFiles(generatedFile, goldenFile) if err != nil { t.Fatal(err) } } func TestValidateCmdName(t *testing.T) { testCases := []struct { input string expected string }{ {"cmdName", "cmdName"}, {"cmd_name", "cmdName"}, {"cmd-name", "cmdName"}, {"cmd______Name", "cmdName"}, {"cmd------Name", "cmdName"}, {"cmd______name", "cmdName"}, {"cmd------name", "cmdName"}, {"cmdName-----", "cmdName"}, {"cmdname-", "cmdname"}, } for _, testCase := range testCases { got := validateCmdName(testCase.input) if testCase.expected != got { t.Errorf("Expected %q, got %q", testCase.expected, got) } } } cobra-1.3.0/cobra/cmd/golden_test.go000066400000000000000000000026351415616037300173040ustar00rootroot00000000000000package cmd import ( "bytes" "errors" "fmt" "io/ioutil" "os/exec" ) func init() { // Mute commands. addCmd.SetOut(new(bytes.Buffer)) addCmd.SetErr(new(bytes.Buffer)) initCmd.SetOut(new(bytes.Buffer)) initCmd.SetErr(new(bytes.Buffer)) } // ensureLF converts any \r\n to \n func ensureLF(content []byte) []byte { return bytes.Replace(content, []byte("\r\n"), []byte("\n"), -1) } // compareFiles compares the content of files with pathA and pathB. // If contents are equal, it returns nil. // If not, it returns which files are not equal // and diff (if system has diff command) between these files. func compareFiles(pathA, pathB string) error { contentA, err := ioutil.ReadFile(pathA) if err != nil { return err } contentB, err := ioutil.ReadFile(pathB) if err != nil { return err } if !bytes.Equal(ensureLF(contentA), ensureLF(contentB)) { output := new(bytes.Buffer) output.WriteString(fmt.Sprintf("%q and %q are not equal!\n\n", pathA, pathB)) diffPath, err := exec.LookPath("diff") if err != nil { // Don't execute diff if it can't be found. return nil } diffCmd := exec.Command(diffPath, "-u", "--strip-trailing-cr", pathA, pathB) diffCmd.Stdout = output diffCmd.Stderr = output output.WriteString("$ diff -u " + pathA + " " + pathB + "\n") if err := diffCmd.Run(); err != nil { output.WriteString("\n" + err.Error()) } return errors.New(output.String()) } return nil } cobra-1.3.0/cobra/cmd/helpers.go000066400000000000000000000032331415616037300164320ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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 cmd import ( "os" "os/exec" "path/filepath" "strings" "github.com/spf13/cobra" ) var srcPaths []string func init() { // Initialize srcPaths. envGoPath := os.Getenv("GOPATH") goPaths := filepath.SplitList(envGoPath) if len(goPaths) == 0 { // Adapted from https://github.com/Masterminds/glide/pull/798/files. // As of Go 1.8 the GOPATH is no longer required to be set. Instead there // is a default value. If there is no GOPATH check for the default value. // Note, checking the GOPATH first to avoid invoking the go toolchain if // possible. goExecutable := os.Getenv("COBRA_GO_EXECUTABLE") if len(goExecutable) <= 0 { goExecutable = "go" } out, err := exec.Command(goExecutable, "env", "GOPATH").Output() cobra.CheckErr(err) toolchainGoPath := strings.TrimSpace(string(out)) goPaths = filepath.SplitList(toolchainGoPath) if len(goPaths) == 0 { cobra.CheckErr("$GOPATH is not set") } } srcPaths = make([]string, 0, len(goPaths)) for _, goPath := range goPaths { srcPaths = append(srcPaths, filepath.Join(goPath, "src")) } } cobra-1.3.0/cobra/cmd/helpers_test.go000066400000000000000000000001521415616037300174660ustar00rootroot00000000000000package cmd import "testing" func assertNoErr(t *testing.T, e error) { if e != nil { t.Error(e) } } cobra-1.3.0/cobra/cmd/init.go000066400000000000000000000057721415616037300157450ustar00rootroot00000000000000// Copyright © 2021 Steve Francia . // // 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 cmd import ( "encoding/json" "fmt" "os" "os/exec" "path" "path/filepath" "strings" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( initCmd = &cobra.Command{ Use: "init [path]", Aliases: []string{"initialize", "initialise", "create"}, Short: "Initialize a Cobra Application", Long: `Initialize (cobra init) will create a new application, with a license and the appropriate structure for a Cobra-based CLI application. Cobra init must be run inside of a go module (please run "go mod init " first) `, Run: func(_ *cobra.Command, args []string) { projectPath, err := initializeProject(args) cobra.CheckErr(err) cobra.CheckErr(goGet("github.com/spf13/cobra")) if viper.GetBool("useViper") { cobra.CheckErr(goGet("github.com/spf13/viper")) } fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath) }, } ) func initializeProject(args []string) (string, error) { wd, err := os.Getwd() if err != nil { return "", err } if len(args) > 0 { if args[0] != "." { wd = fmt.Sprintf("%s/%s", wd, args[0]) } } modName := getModImportPath() project := &Project{ AbsolutePath: wd, PkgName: modName, Legal: getLicense(), Copyright: copyrightLine(), Viper: viper.GetBool("useViper"), AppName: path.Base(modName), } if err := project.Create(); err != nil { return "", err } return project.AbsolutePath, nil } func getModImportPath() string { mod, cd := parseModInfo() return path.Join(mod.Path, fileToURL(strings.TrimPrefix(cd.Dir, mod.Dir))) } func fileToURL(in string) string { i := strings.Split(in, string(filepath.Separator)) return path.Join(i...) } func parseModInfo() (Mod, CurDir) { var mod Mod var dir CurDir m := modInfoJSON("-m") cobra.CheckErr(json.Unmarshal(m, &mod)) // Unsure why, but if no module is present Path is set to this string. if mod.Path == "command-line-arguments" { cobra.CheckErr("Please run `go mod init ` before `cobra init`") } e := modInfoJSON("-e") cobra.CheckErr(json.Unmarshal(e, &dir)) return mod, dir } type Mod struct { Path, Dir, GoMod string } type CurDir struct { Dir string } func goGet(mod string) error { return exec.Command("go", "get", mod).Run() } func modInfoJSON(args ...string) []byte { cmdArgs := append([]string{"list", "-json"}, args...) out, err := exec.Command("go", cmdArgs...).Output() cobra.CheckErr(err) return out } cobra-1.3.0/cobra/cmd/init_test.go000066400000000000000000000032531415616037300167740ustar00rootroot00000000000000package cmd import ( "fmt" "io/ioutil" "os" "path/filepath" "testing" "github.com/spf13/viper" ) func getProject() *Project { wd, _ := os.Getwd() return &Project{ AbsolutePath: fmt.Sprintf("%s/testproject", wd), Legal: getLicense(), Copyright: copyrightLine(), AppName: "cmd", PkgName: "github.com/spf13/cobra/cobra/cmd/cmd", Viper: true, } } func TestGoldenInitCmd(t *testing.T) { dir, err := ioutil.TempDir("", "cobra-init") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) tests := []struct { name string args []string pkgName string expectErr bool }{ { name: "successfully creates a project based on module", args: []string{"testproject"}, pkgName: "github.com/spf13/testproject", expectErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { viper.Set("useViper", true) viper.Set("license", "apache") projectPath, err := initializeProject(tt.args) defer func() { if projectPath != "" { os.RemoveAll(projectPath) } }() if !tt.expectErr && err != nil { t.Fatalf("did not expect an error, got %s", err) } if tt.expectErr { if err == nil { t.Fatal("expected an error but got none") } else { // got an expected error nothing more to do return } } expectedFiles := []string{"LICENSE", "main.go", "cmd/root.go"} for _, f := range expectedFiles { generatedFile := fmt.Sprintf("%s/%s", projectPath, f) goldenFile := fmt.Sprintf("testdata/%s.golden", filepath.Base(f)) err := compareFiles(generatedFile, goldenFile) if err != nil { t.Fatal(err) } } }) } } cobra-1.3.0/cobra/cmd/license_agpl.go000066400000000000000000001050561415616037300174230ustar00rootroot00000000000000package cmd func initAgpl() { Licenses["agpl"] = License{ Name: "GNU Affero General Public License", PossibleMatches: []string{"AGPL-3.0", "agpl", "affero gpl", "gnu agpl"}, Header: ` This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see .`, Text: ` GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . `, } } cobra-1.3.0/cobra/cmd/license_apache_2.go000066400000000000000000000307561415616037300201460ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initApache2() { Licenses["apache"] = License{ Name: "Apache 2.0", PossibleMatches: []string{"Apache-2.0", "apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"}, Header: ` 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.`, Text: ` 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. `, } } cobra-1.3.0/cobra/cmd/license_bsd_clause_2.go000066400000000000000000000066431415616037300210270ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initBsdClause2() { Licenses["freebsd"] = License{ Name: "Simplified BSD License", PossibleMatches: []string{"BSD-2-Clause", "freebsd", "simpbsd", "simple bsd", "2-clause bsd", "2 clause bsd", "simplified bsd license"}, Header: `All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`, Text: `{{ .copyright }} All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. `, } } cobra-1.3.0/cobra/cmd/license_bsd_clause_3.go000066400000000000000000000073661415616037300210330ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initBsdClause3() { Licenses["bsd"] = License{ Name: "NewBSD", PossibleMatches: []string{"BSD-3-Clause", "bsd", "newbsd", "3 clause bsd", "3-clause bsd"}, Header: `All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`, Text: `{{ .copyright }} All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. `, } } cobra-1.3.0/cobra/cmd/license_gpl_2.go000066400000000000000000000461751415616037300175110ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initGpl2() { Licenses["gpl2"] = License{ Name: "GNU General Public License 2.0", PossibleMatches: []string{"GPL-2.0", "gpl2", "gnu gpl2", "gplv2"}, Header: ` This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .`, Text: ` GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free software, and you are welcome to redistribute it under certain conditions; type 'show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program 'Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. `, } } cobra-1.3.0/cobra/cmd/license_gpl_3.go000066400000000000000000001074561415616037300175120ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initGpl3() { Licenses["gpl3"] = License{ Name: "GNU General Public License 3.0", PossibleMatches: []string{"GPL-3.0", "gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"}, Header: ` This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .`, Text: ` GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free software, and you are welcome to redistribute it under certain conditions; type 'show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . `, } } cobra-1.3.0/cobra/cmd/license_lgpl.go000066400000000000000000000204701415616037300174320ustar00rootroot00000000000000package cmd func initLgpl() { Licenses["lgpl"] = License{ Name: "GNU Lesser General Public License", PossibleMatches: []string{"LGPL-3.0", "lgpl", "lesser gpl", "gnu lgpl"}, Header: ` This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see .`, Text: ` GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.`, } } cobra-1.3.0/cobra/cmd/license_mit.go000066400000000000000000000055461415616037300172740ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd func initMit() { Licenses["mit"] = License{ Name: "MIT License", PossibleMatches: []string{"MIT", "mit"}, Header: ` Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.`, Text: `The MIT License (MIT) {{ .copyright }} Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. `, } } cobra-1.3.0/cobra/cmd/licenses.go000066400000000000000000000064071415616037300166030ustar00rootroot00000000000000// Copyright © 2021 Steve Francia . // // 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. // Parts inspired by https://github.com/ryanuber/go-license package cmd import ( "fmt" "strings" "time" "github.com/spf13/cobra" "github.com/spf13/viper" ) // Licenses contains all possible licenses a user can choose from. var Licenses = make(map[string]License) // License represents a software license agreement, containing the Name of // the license, its possible matches (on the command line as given to cobra), // the header to be used with each file on the file's creating, and the text // of the license type License struct { Name string // The type of license in use PossibleMatches []string // Similar names to guess Text string // License text data Header string // License header for source files } func init() { // Allows a user to not use a license. Licenses["none"] = License{"None", []string{"none", "false"}, "", ""} initApache2() initMit() initBsdClause3() initBsdClause2() initGpl2() initGpl3() initLgpl() initAgpl() } // getLicense returns license specified by user in flag or in config. // If user didn't specify the license, it returns none // // TODO: Inspect project for existing license func getLicense() License { // If explicitly flagged, use that. if userLicense != "" { return findLicense(userLicense) } // If user wants to have custom license, use that. if viper.IsSet("license.header") || viper.IsSet("license.text") { return License{Header: viper.GetString("license.header"), Text: viper.GetString("license.text")} } // If user wants to have built-in license, use that. if viper.IsSet("license") { return findLicense(viper.GetString("license")) } // If user didn't set any license, use none by default return Licenses["none"] } func copyrightLine() string { author := viper.GetString("author") year := viper.GetString("year") // For tests. if year == "" { year = time.Now().Format("2006") } return "Copyright © " + year + " " + author } // findLicense looks for License object of built-in licenses. // If it didn't find license, then the app will be terminated and // error will be printed. func findLicense(name string) License { found := matchLicense(name) if found == "" { cobra.CheckErr(fmt.Errorf("unknown license: " + name)) } return Licenses[found] } // matchLicense compares the given a license name // to PossibleMatches of all built-in licenses. // It returns blank string, if name is blank string or it didn't find // then appropriate match to name. func matchLicense(name string) string { if name == "" { return "" } for key, lic := range Licenses { for _, match := range lic.PossibleMatches { if strings.EqualFold(name, match) { return key } } } return "" } cobra-1.3.0/cobra/cmd/project.go000066400000000000000000000042431415616037300164400ustar00rootroot00000000000000package cmd import ( "fmt" "os" "text/template" "github.com/spf13/cobra" "github.com/spf13/cobra/cobra/tpl" ) // Project contains name, license and paths to projects. type Project struct { // v2 PkgName string Copyright string AbsolutePath string Legal License Viper bool AppName string } type Command struct { CmdName string CmdParent string *Project } func (p *Project) Create() error { // check if AbsolutePath exists if _, err := os.Stat(p.AbsolutePath); os.IsNotExist(err) { // create directory if err := os.Mkdir(p.AbsolutePath, 0754); err != nil { return err } } // create main.go mainFile, err := os.Create(fmt.Sprintf("%s/main.go", p.AbsolutePath)) if err != nil { return err } defer mainFile.Close() mainTemplate := template.Must(template.New("main").Parse(string(tpl.MainTemplate()))) err = mainTemplate.Execute(mainFile, p) if err != nil { return err } // create cmd/root.go if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) { cobra.CheckErr(os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751)) } rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath)) if err != nil { return err } defer rootFile.Close() rootTemplate := template.Must(template.New("root").Parse(string(tpl.RootTemplate()))) err = rootTemplate.Execute(rootFile, p) if err != nil { return err } // create license return p.createLicenseFile() } func (p *Project) createLicenseFile() error { data := map[string]interface{}{ "copyright": copyrightLine(), } licenseFile, err := os.Create(fmt.Sprintf("%s/LICENSE", p.AbsolutePath)) if err != nil { return err } defer licenseFile.Close() licenseTemplate := template.Must(template.New("license").Parse(p.Legal.Text)) return licenseTemplate.Execute(licenseFile, data) } func (c *Command) Create() error { cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdName)) if err != nil { return err } defer cmdFile.Close() commandTemplate := template.Must(template.New("sub").Parse(string(tpl.AddCommandTemplate()))) err = commandTemplate.Execute(cmdFile, c) if err != nil { return err } return nil } cobra-1.3.0/cobra/cmd/project_test.go000066400000000000000000000000451415616037300174730ustar00rootroot00000000000000package cmd /* todo: write tests */ cobra-1.3.0/cobra/cmd/root.go000066400000000000000000000045511415616037300157570ustar00rootroot00000000000000// Copyright © 2021 Steve Francia . // // 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 cmd import ( "fmt" "os" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( // Used for flags. cfgFile string userLicense string rootCmd = &cobra.Command{ Use: "cobra", Short: "A generator for Cobra based Applications", Long: `Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, } ) // Execute executes the root command. func Execute() error { return rootCmd.Execute() } func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") rootCmd.PersistentFlags().Bool("viper", false, "use Viper for configuration") cobra.CheckErr(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))) cobra.CheckErr(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))) viper.SetDefault("author", "NAME HERE ") viper.SetDefault("license", "none") rootCmd.AddCommand(addCmd) rootCmd.AddCommand(initCmd) } func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := os.UserHomeDir() cobra.CheckErr(err) // Search config in home directory with name ".cobra" (without extension). viper.AddConfigPath(home) viper.SetConfigType("yaml") viper.SetConfigName(".cobra") } viper.AutomaticEnv() if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) } } cobra-1.3.0/cobra/cmd/testdata/000077500000000000000000000000001415616037300162515ustar00rootroot00000000000000cobra-1.3.0/cobra/cmd/testdata/LICENSE.golden000066400000000000000000000261361415616037300205350ustar00rootroot00000000000000 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. cobra-1.3.0/cobra/cmd/testdata/main.go.golden000066400000000000000000000012331415616037300207720ustar00rootroot00000000000000/* Copyright © 2021 NAME HERE 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 main import "github.com/spf13/cobra/cobra/cmd/cmd" func main() { cmd.Execute() } cobra-1.3.0/cobra/cmd/testdata/root.go.golden000066400000000000000000000052071415616037300210360ustar00rootroot00000000000000/* Copyright © 2021 NAME HERE 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 cmd import ( "fmt" "os" "github.com/spf13/cobra" "github.com/spf13/viper" ) var cfgFile string // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "cmd", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { err := rootCmd.Execute() if err != nil { os.Exit(1) } } func init() { cobra.OnInitialize(initConfig) // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cmd.yaml)") // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := os.UserHomeDir() cobra.CheckErr(err) // Search config in home directory with name ".cmd" (without extension). viper.AddConfigPath(home) viper.SetConfigType("yaml") viper.SetConfigName(".cmd") } viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) } } cobra-1.3.0/cobra/cmd/testdata/test.go.golden000066400000000000000000000030641415616037300210310ustar00rootroot00000000000000/* Copyright © 2021 NAME HERE 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 cmd import ( "fmt" "github.com/spf13/cobra" ) // testCmd represents the test command var testCmd = &cobra.Command{ Use: "test", Short: "A brief description of your command", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your command. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("test called") }, } func init() { rootCmd.AddCommand(testCmd) // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command // and all subcommands, e.g.: // testCmd.PersistentFlags().String("foo", "", "A help for foo") // Cobra supports local flags which will only run when this command // is called directly, e.g.: // testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } cobra-1.3.0/cobra/main.go000066400000000000000000000013501415616037300151470ustar00rootroot00000000000000// Copyright © 2015 Steve Francia . // // 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 main import ( "os" "github.com/spf13/cobra/cobra/cmd" ) func main() { if err := cmd.Execute(); err != nil { os.Exit(1) } } cobra-1.3.0/cobra/tpl/000077500000000000000000000000001415616037300144745ustar00rootroot00000000000000cobra-1.3.0/cobra/tpl/main.go000066400000000000000000000111011415616037300157410ustar00rootroot00000000000000// Copyright © 2021 Steve Francia . // // 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 tpl func MainTemplate() []byte { return []byte(`/* {{ .Copyright }} {{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} */ package main import "{{ .PkgName }}/cmd" func main() { cmd.Execute() } `) } func RootTemplate() []byte { return []byte(`/* {{ .Copyright }} {{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} */ package cmd import ( {{- if .Viper }} "fmt"{{ end }} "os" "github.com/spf13/cobra" {{- if .Viper }} "github.com/spf13/viper"{{ end }} ) {{ if .Viper -}} var cfgFile string {{- end }} // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "{{ .AppName }}", Short: "A brief description of your application", Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.` + "`" + `, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { err := rootCmd.Execute() if err != nil { os.Exit(1) } } func init() { {{- if .Viper }} cobra.OnInitialize(initConfig) {{ end }} // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. {{ if .Viper }} rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") {{ else }} // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") {{ end }} // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } {{ if .Viper -}} // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := os.UserHomeDir() cobra.CheckErr(err) // Search config in home directory with name ".{{ .AppName }}" (without extension). viper.AddConfigPath(home) viper.SetConfigType("yaml") viper.SetConfigName(".{{ .AppName }}") } viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) } } {{- end }} `) } func AddCommandTemplate() []byte { return []byte(`/* {{ .Project.Copyright }} {{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} */ package cmd import ( "fmt" "github.com/spf13/cobra" ) // {{ .CmdName }}Cmd represents the {{ .CmdName }} command var {{ .CmdName }}Cmd = &cobra.Command{ Use: "{{ .CmdName }}", Short: "A brief description of your command", Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples and usage of using your command. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.` + "`" + `, Run: func(cmd *cobra.Command, args []string) { fmt.Println("{{ .CmdName }} called") }, } func init() { {{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd) // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command // and all subcommands, e.g.: // {{ .CmdName }}Cmd.PersistentFlags().String("foo", "", "A help for foo") // Cobra supports local flags which will only run when this command // is called directly, e.g.: // {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } `) } cobra-1.3.0/cobra_test.go000066400000000000000000000011571415616037300152670ustar00rootroot00000000000000package cobra import ( "testing" "text/template" ) func assertNoErr(t *testing.T, e error) { if e != nil { t.Error(e) } } func TestAddTemplateFunctions(t *testing.T) { AddTemplateFunc("t", func() bool { return true }) AddTemplateFuncs(template.FuncMap{ "f": func() bool { return false }, "h": func() string { return "Hello," }, "w": func() string { return "world." }}) c := &Command{} c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`) const expected = "Hello, world." if got := c.UsageString(); got != expected { t.Errorf("Expected UsageString: %v\nGot: %v", expected, got) } } cobra-1.3.0/command.go000066400000000000000000001361211415616037300145600ustar00rootroot00000000000000// Copyright © 2013 Steve Francia . // // 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 cobra is a commander providing a simple interface to create powerful modern CLI interfaces. // In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. package cobra import ( "bytes" "context" "fmt" "io" "os" "path/filepath" "sort" "strings" flag "github.com/spf13/pflag" ) // FParseErrWhitelist configures Flag parse errors to be ignored type FParseErrWhitelist flag.ParseErrorsWhitelist // Command is just that, a command for your application. // E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command // definition to ensure usability. type Command struct { // Use is the one-line usage message. // Recommended syntax is as follow: // [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required. // ... indicates that you can specify multiple values for the previous argument. // | indicates mutually exclusive information. You can use the argument to the left of the separator or the // argument to the right of the separator. You cannot use both arguments in a single use of the command. // { } delimits a set of mutually exclusive arguments when one of the arguments is required. If the arguments are // optional, they are enclosed in brackets ([ ]). // Example: add [-F file | -D dir]... [-f format] profile Use string // Aliases is an array of aliases that can be used instead of the first word in Use. Aliases []string // SuggestFor is an array of command names for which this command will be suggested - // similar to aliases but only suggests. SuggestFor []string // Short is the short description shown in the 'help' output. Short string // Long is the long message shown in the 'help ' output. Long string // Example is examples of how to use the command. Example string // ValidArgs is list of all valid non-flag arguments that are accepted in shell completions ValidArgs []string // ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. // It is a dynamic version of using ValidArgs. // Only one of ValidArgs and ValidArgsFunction can be used for a command. ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) // Expected arguments Args PositionalArgs // ArgAliases is List of aliases for ValidArgs. // These are not suggested to the user in the shell completion, // but accepted if entered manually. ArgAliases []string // BashCompletionFunction is custom bash functions used by the legacy bash autocompletion generator. // For portability with other shells, it is recommended to instead use ValidArgsFunction BashCompletionFunction string // Deprecated defines, if this command is deprecated and should print this string when used. Deprecated string // Annotations are key/value pairs that can be used by applications to identify or // group commands. Annotations map[string]string // Version defines the version for this command. If this value is non-empty and the command does not // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, // will print content of the "Version" variable. A shorthand "v" flag will also be added if the // command does not define one. Version string // The *Run functions are executed in the following order: // * PersistentPreRun() // * PreRun() // * Run() // * PostRun() // * PersistentPostRun() // All functions get the same args, the arguments after the command name. // // PersistentPreRun: children of this command will inherit and execute. PersistentPreRun func(cmd *Command, args []string) // PersistentPreRunE: PersistentPreRun but returns an error. PersistentPreRunE func(cmd *Command, args []string) error // PreRun: children of this command will not inherit. PreRun func(cmd *Command, args []string) // PreRunE: PreRun but returns an error. PreRunE func(cmd *Command, args []string) error // Run: Typically the actual work function. Most commands will only implement this. Run func(cmd *Command, args []string) // RunE: Run but returns an error. RunE func(cmd *Command, args []string) error // PostRun: run after the Run command. PostRun func(cmd *Command, args []string) // PostRunE: PostRun but returns an error. PostRunE func(cmd *Command, args []string) error // PersistentPostRun: children of this command will inherit and execute after PostRun. PersistentPostRun func(cmd *Command, args []string) // PersistentPostRunE: PersistentPostRun but returns an error. PersistentPostRunE func(cmd *Command, args []string) error // args is actual args parsed from flags. args []string // flagErrorBuf contains all error messages from pflag. flagErrorBuf *bytes.Buffer // flags is full set of flags. flags *flag.FlagSet // pflags contains persistent flags. pflags *flag.FlagSet // lflags contains local flags. lflags *flag.FlagSet // iflags contains inherited flags. iflags *flag.FlagSet // parentsPflags is all persistent flags of cmd's parents. parentsPflags *flag.FlagSet // globNormFunc is the global normalization function // that we can use on every pflag set and children commands globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName // usageFunc is usage func defined by user. usageFunc func(*Command) error // usageTemplate is usage template defined by user. usageTemplate string // flagErrorFunc is func defined by user and it's called when the parsing of // flags returns an error. flagErrorFunc func(*Command, error) error // helpTemplate is help template defined by user. helpTemplate string // helpFunc is help func defined by user. helpFunc func(*Command, []string) // helpCommand is command with usage 'help'. If it's not defined by user, // cobra uses default help command. helpCommand *Command // versionTemplate is the version template defined by user. versionTemplate string // inReader is a reader defined by the user that replaces stdin inReader io.Reader // outWriter is a writer defined by the user that replaces stdout outWriter io.Writer // errWriter is a writer defined by the user that replaces stderr errWriter io.Writer //FParseErrWhitelist flag parse errors to be ignored FParseErrWhitelist FParseErrWhitelist // CompletionOptions is a set of options to control the handling of shell completion CompletionOptions CompletionOptions // commandsAreSorted defines, if command slice are sorted or not. commandsAreSorted bool // commandCalledAs is the name or alias value used to call this command. commandCalledAs struct { name string called bool } ctx context.Context // commands is the list of commands supported by this program. commands []*Command // parent is a parent command for this command. parent *Command // Max lengths of commands' string lengths for use in padding. commandsMaxUseLen int commandsMaxCommandPathLen int commandsMaxNameLen int // TraverseChildren parses flags on all parents before executing child command. TraverseChildren bool // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. Hidden bool // SilenceErrors is an option to quiet errors down stream. SilenceErrors bool // SilenceUsage is an option to silence usage when an error occurs. SilenceUsage bool // DisableFlagParsing disables the flag parsing. // If this is true all flags will be passed to the command as arguments. DisableFlagParsing bool // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") // will be printed by generating docs for this command. DisableAutoGenTag bool // DisableFlagsInUseLine will disable the addition of [flags] to the usage // line of a command when printing help or generating docs DisableFlagsInUseLine bool // DisableSuggestions disables the suggestions based on Levenshtein distance // that go along with 'unknown command' messages. DisableSuggestions bool // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. // Must be > 0. SuggestionsMinimumDistance int } // Context returns underlying command context. If command wasn't // executed with ExecuteContext Context returns Background context. func (c *Command) Context() context.Context { return c.ctx } // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // particularly useful when testing. func (c *Command) SetArgs(a []string) { c.args = a } // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. // Deprecated: Use SetOut and/or SetErr instead func (c *Command) SetOutput(output io.Writer) { c.outWriter = output c.errWriter = output } // SetOut sets the destination for usage messages. // If newOut is nil, os.Stdout is used. func (c *Command) SetOut(newOut io.Writer) { c.outWriter = newOut } // SetErr sets the destination for error messages. // If newErr is nil, os.Stderr is used. func (c *Command) SetErr(newErr io.Writer) { c.errWriter = newErr } // SetIn sets the source for input data // If newIn is nil, os.Stdin is used. func (c *Command) SetIn(newIn io.Reader) { c.inReader = newIn } // SetUsageFunc sets usage function. Usage can be defined by application. func (c *Command) SetUsageFunc(f func(*Command) error) { c.usageFunc = f } // SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { c.usageTemplate = s } // SetFlagErrorFunc sets a function to generate an error when flag parsing // fails. func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { c.flagErrorFunc = f } // SetHelpFunc sets help function. Can be defined by Application. func (c *Command) SetHelpFunc(f func(*Command, []string)) { c.helpFunc = f } // SetHelpCommand sets help command. func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } // SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s } // SetVersionTemplate sets version template to be used. Application can use it to set custom template. func (c *Command) SetVersionTemplate(s string) { c.versionTemplate = s } // SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. // The user should not have a cyclic dependency on commands. func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { c.Flags().SetNormalizeFunc(n) c.PersistentFlags().SetNormalizeFunc(n) c.globNormFunc = n for _, command := range c.commands { command.SetGlobalNormalizationFunc(n) } } // OutOrStdout returns output to stdout. func (c *Command) OutOrStdout() io.Writer { return c.getOut(os.Stdout) } // OutOrStderr returns output to stderr func (c *Command) OutOrStderr() io.Writer { return c.getOut(os.Stderr) } // ErrOrStderr returns output to stderr func (c *Command) ErrOrStderr() io.Writer { return c.getErr(os.Stderr) } // InOrStdin returns input to stdin func (c *Command) InOrStdin() io.Reader { return c.getIn(os.Stdin) } func (c *Command) getOut(def io.Writer) io.Writer { if c.outWriter != nil { return c.outWriter } if c.HasParent() { return c.parent.getOut(def) } return def } func (c *Command) getErr(def io.Writer) io.Writer { if c.errWriter != nil { return c.errWriter } if c.HasParent() { return c.parent.getErr(def) } return def } func (c *Command) getIn(def io.Reader) io.Reader { if c.inReader != nil { return c.inReader } if c.HasParent() { return c.parent.getIn(def) } return def } // UsageFunc returns either the function set by SetUsageFunc for this command // or a parent, or it returns a default usage function. func (c *Command) UsageFunc() (f func(*Command) error) { if c.usageFunc != nil { return c.usageFunc } if c.HasParent() { return c.Parent().UsageFunc() } return func(c *Command) error { c.mergePersistentFlags() err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) if err != nil { c.PrintErrln(err) } return err } } // Usage puts out the usage for the command. // Used when a user provides invalid input. // Can be defined by user by overriding UsageFunc. func (c *Command) Usage() error { return c.UsageFunc()(c) } // HelpFunc returns either the function set by SetHelpFunc for this command // or a parent, or it returns a function with default help behavior. func (c *Command) HelpFunc() func(*Command, []string) { if c.helpFunc != nil { return c.helpFunc } if c.HasParent() { return c.Parent().HelpFunc() } return func(c *Command, a []string) { c.mergePersistentFlags() // The help should be sent to stdout // See https://github.com/spf13/cobra/issues/1002 err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) if err != nil { c.PrintErrln(err) } } } // Help puts out the help for the command. // Used when a user calls help [command]. // Can be defined by user by overriding HelpFunc. func (c *Command) Help() error { c.HelpFunc()(c, []string{}) return nil } // UsageString returns usage string. func (c *Command) UsageString() string { // Storing normal writers tmpOutput := c.outWriter tmpErr := c.errWriter bb := new(bytes.Buffer) c.outWriter = bb c.errWriter = bb CheckErr(c.Usage()) // Setting things back to normal c.outWriter = tmpOutput c.errWriter = tmpErr return bb.String() } // FlagErrorFunc returns either the function set by SetFlagErrorFunc for this // command or a parent, or it returns a function which returns the original // error. func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { if c.flagErrorFunc != nil { return c.flagErrorFunc } if c.HasParent() { return c.parent.FlagErrorFunc() } return func(c *Command, err error) error { return err } } var minUsagePadding = 25 // UsagePadding return padding for the usage. func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding } return c.parent.commandsMaxUseLen } var minCommandPathPadding = 11 // CommandPathPadding return padding for the command path. func (c *Command) CommandPathPadding() int { if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { return minCommandPathPadding } return c.parent.commandsMaxCommandPathLen } var minNamePadding = 11 // NamePadding returns padding for the name. func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding } return c.parent.commandsMaxNameLen } // UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { if c.usageTemplate != "" { return c.usageTemplate } if c.HasParent() { return c.parent.UsageTemplate() } return `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}} Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}}{{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}} ` } // HelpTemplate return help template for the command. func (c *Command) HelpTemplate() string { if c.helpTemplate != "" { return c.helpTemplate } if c.HasParent() { return c.parent.HelpTemplate() } return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` } // VersionTemplate return version template for the command. func (c *Command) VersionTemplate() string { if c.versionTemplate != "" { return c.versionTemplate } if c.HasParent() { return c.parent.VersionTemplate() } return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} ` } func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { flag := fs.Lookup(name) if flag == nil { return false } return flag.NoOptDefVal != "" } func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { if len(name) == 0 { return false } flag := fs.ShorthandLookup(name[:1]) if flag == nil { return false } return flag.NoOptDefVal != "" } func stripFlags(args []string, c *Command) []string { if len(args) == 0 { return args } c.mergePersistentFlags() commands := []string{} flags := c.Flags() Loop: for len(args) > 0 { s := args[0] args = args[1:] switch { case s == "--": // "--" terminates the flags break Loop case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): // If '--flag arg' then // delete arg from args. fallthrough // (do the same as below) case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): // If '-f arg' then // delete 'arg' from args or break the loop if len(args) <= 1. if len(args) <= 1 { break Loop } else { args = args[1:] continue } case s != "" && !strings.HasPrefix(s, "-"): commands = append(commands, s) } } return commands } // argsMinusFirstX removes only the first x from args. Otherwise, commands that look like // openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). func argsMinusFirstX(args []string, x string) []string { for i, y := range args { if x == y { ret := []string{} ret = append(ret, args[:i]...) ret = append(ret, args[i+1:]...) return ret } } return args } func isFlagArg(arg string) bool { return ((len(arg) >= 3 && arg[1] == '-') || (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) } // Find the target command given the args and command tree // Meant to be run on the highest node. Only searches down. func (c *Command) Find(args []string) (*Command, []string, error) { var innerfind func(*Command, []string) (*Command, []string) innerfind = func(c *Command, innerArgs []string) (*Command, []string) { argsWOflags := stripFlags(innerArgs, c) if len(argsWOflags) == 0 { return c, innerArgs } nextSubCmd := argsWOflags[0] cmd := c.findNext(nextSubCmd) if cmd != nil { return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) } return c, innerArgs } commandFound, a := innerfind(c, args) if commandFound.Args == nil { return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) } return commandFound, a, nil } func (c *Command) findSuggestions(arg string) string { if c.DisableSuggestions { return "" } if c.SuggestionsMinimumDistance <= 0 { c.SuggestionsMinimumDistance = 2 } suggestionsString := "" if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { suggestionsString += "\n\nDid you mean this?\n" for _, s := range suggestions { suggestionsString += fmt.Sprintf("\t%v\n", s) } } return suggestionsString } func (c *Command) findNext(next string) *Command { matches := make([]*Command, 0) for _, cmd := range c.commands { if cmd.Name() == next || cmd.HasAlias(next) { cmd.commandCalledAs.name = next return cmd } if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { matches = append(matches, cmd) } } if len(matches) == 1 { return matches[0] } return nil } // Traverse the command tree to find the command, and parse args for // each parent. func (c *Command) Traverse(args []string) (*Command, []string, error) { flags := []string{} inFlag := false for i, arg := range args { switch { // A long flag with a space separated value case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="): // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' inFlag = !hasNoOptDefVal(arg[2:], c.Flags()) flags = append(flags, arg) continue // A short flag with a space separated value case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()): inFlag = true flags = append(flags, arg) continue // The value for a flag case inFlag: inFlag = false flags = append(flags, arg) continue // A flag without a value, or with an `=` separated value case isFlagArg(arg): flags = append(flags, arg) continue } cmd := c.findNext(arg) if cmd == nil { return c, args, nil } if err := c.ParseFlags(flags); err != nil { return nil, args, err } return cmd.Traverse(args[i+1:]) } return c, args, nil } // SuggestionsFor provides suggestions for the typedName. func (c *Command) SuggestionsFor(typedName string) []string { suggestions := []string{} for _, cmd := range c.commands { if cmd.IsAvailableCommand() { levenshteinDistance := ld(typedName, cmd.Name(), true) suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) if suggestByLevenshtein || suggestByPrefix { suggestions = append(suggestions, cmd.Name()) } for _, explicitSuggestion := range cmd.SuggestFor { if strings.EqualFold(typedName, explicitSuggestion) { suggestions = append(suggestions, cmd.Name()) } } } } return suggestions } // VisitParents visits all parents of the command and invokes fn on each parent. func (c *Command) VisitParents(fn func(*Command)) { if c.HasParent() { fn(c.Parent()) c.Parent().VisitParents(fn) } } // Root finds root command. func (c *Command) Root() *Command { if c.HasParent() { return c.Parent().Root() } return c } // ArgsLenAtDash will return the length of c.Flags().Args at the moment // when a -- was found during args parsing. func (c *Command) ArgsLenAtDash() int { return c.Flags().ArgsLenAtDash() } func (c *Command) execute(a []string) (err error) { if c == nil { return fmt.Errorf("Called Execute() on a nil Command") } if len(c.Deprecated) > 0 { c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) } // initialize help and version flag at the last point possible to allow for user // overriding c.InitDefaultHelpFlag() c.InitDefaultVersionFlag() err = c.ParseFlags(a) if err != nil { return c.FlagErrorFunc()(c, err) } // If help is called, regardless of other flags, return we want help. // Also say we need help if the command isn't runnable. helpVal, err := c.Flags().GetBool("help") if err != nil { // should be impossible to get here as we always declare a help // flag in InitDefaultHelpFlag() c.Println("\"help\" flag declared as non-bool. Please correct your code") return err } if helpVal { return flag.ErrHelp } // for back-compat, only add version flag behavior if version is defined if c.Version != "" { versionVal, err := c.Flags().GetBool("version") if err != nil { c.Println("\"version\" flag declared as non-bool. Please correct your code") return err } if versionVal { err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) if err != nil { c.Println(err) } return err } } if !c.Runnable() { return flag.ErrHelp } c.preRun() argWoFlags := c.Flags().Args() if c.DisableFlagParsing { argWoFlags = a } if err := c.ValidateArgs(argWoFlags); err != nil { return err } for p := c; p != nil; p = p.Parent() { if p.PersistentPreRunE != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil { return err } break } else if p.PersistentPreRun != nil { p.PersistentPreRun(c, argWoFlags) break } } if c.PreRunE != nil { if err := c.PreRunE(c, argWoFlags); err != nil { return err } } else if c.PreRun != nil { c.PreRun(c, argWoFlags) } if err := c.validateRequiredFlags(); err != nil { return err } if c.RunE != nil { if err := c.RunE(c, argWoFlags); err != nil { return err } } else { c.Run(c, argWoFlags) } if c.PostRunE != nil { if err := c.PostRunE(c, argWoFlags); err != nil { return err } } else if c.PostRun != nil { c.PostRun(c, argWoFlags) } for p := c; p != nil; p = p.Parent() { if p.PersistentPostRunE != nil { if err := p.PersistentPostRunE(c, argWoFlags); err != nil { return err } break } else if p.PersistentPostRun != nil { p.PersistentPostRun(c, argWoFlags) break } } return nil } func (c *Command) preRun() { for _, x := range initializers { x() } } // ExecuteContext is the same as Execute(), but sets the ctx on the command. // Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs // functions. func (c *Command) ExecuteContext(ctx context.Context) error { c.ctx = ctx return c.Execute() } // Execute uses the args (os.Args[1:] by default) // and run through the command tree finding appropriate matches // for commands and then corresponding flags. func (c *Command) Execute() error { _, err := c.ExecuteC() return err } // ExecuteContextC is the same as ExecuteC(), but sets the ctx on the command. // Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs // functions. func (c *Command) ExecuteContextC(ctx context.Context) (*Command, error) { c.ctx = ctx return c.ExecuteC() } // ExecuteC executes the command. func (c *Command) ExecuteC() (cmd *Command, err error) { if c.ctx == nil { c.ctx = context.Background() } // Regardless of what command execute is called on, run on Root only if c.HasParent() { return c.Root().ExecuteC() } // windows hook if preExecHookFn != nil { preExecHookFn(c) } // initialize help at the last point to allow for user overriding c.InitDefaultHelpCmd() // initialize completion at the last point to allow for user overriding c.initDefaultCompletionCmd() args := c.args // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { args = os.Args[1:] } // initialize the hidden command to be used for shell completion c.initCompleteCmd(args) var flags []string if c.TraverseChildren { cmd, flags, err = c.Traverse(args) } else { cmd, flags, err = c.Find(args) } if err != nil { // If found parse to a subcommand and then failed, talk about the subcommand if cmd != nil { c = cmd } if !c.SilenceErrors { c.PrintErrln("Error:", err.Error()) c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath()) } return c, err } cmd.commandCalledAs.called = true if cmd.commandCalledAs.name == "" { cmd.commandCalledAs.name = cmd.Name() } // We have to pass global context to children command // if context is present on the parent command. if cmd.ctx == nil { cmd.ctx = c.ctx } err = cmd.execute(flags) if err != nil { // Always show help if requested, even if SilenceErrors is in // effect if err == flag.ErrHelp { cmd.HelpFunc()(cmd, args) return cmd, nil } // If root command has SilenceErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { c.PrintErrln("Error:", err.Error()) } // If root command has SilenceUsage flagged, // all subcommands should respect it if !cmd.SilenceUsage && !c.SilenceUsage { c.Println(cmd.UsageString()) } } return cmd, err } func (c *Command) ValidateArgs(args []string) error { if c.Args == nil { return nil } return c.Args(c, args) } func (c *Command) validateRequiredFlags() error { if c.DisableFlagParsing { return nil } flags := c.Flags() missingFlagNames := []string{} flags.VisitAll(func(pflag *flag.Flag) { requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag] if !found { return } if (requiredAnnotation[0] == "true") && !pflag.Changed { missingFlagNames = append(missingFlagNames, pflag.Name) } }) if len(missingFlagNames) > 0 { return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) } return nil } // InitDefaultHelpFlag adds default help flag to c. // It is called automatically by executing the c or by calling help and usage. // If c already has help flag, it will do nothing. func (c *Command) InitDefaultHelpFlag() { c.mergePersistentFlags() if c.Flags().Lookup("help") == nil { usage := "help for " if c.Name() == "" { usage += "this command" } else { usage += c.Name() } c.Flags().BoolP("help", "h", false, usage) } } // InitDefaultVersionFlag adds default version flag to c. // It is called automatically by executing the c. // If c already has a version flag, it will do nothing. // If c.Version is empty, it will do nothing. func (c *Command) InitDefaultVersionFlag() { if c.Version == "" { return } c.mergePersistentFlags() if c.Flags().Lookup("version") == nil { usage := "version for " if c.Name() == "" { usage += "this command" } else { usage += c.Name() } if c.Flags().ShorthandLookup("v") == nil { c.Flags().BoolP("version", "v", false, usage) } else { c.Flags().Bool("version", false, usage) } } } // InitDefaultHelpCmd adds default help command to c. // It is called automatically by executing the c or by calling help and usage. // If c already has help command or c has no subcommands, it will do nothing. func (c *Command) InitDefaultHelpCmd() { if !c.HasSubCommands() { return } if c.helpCommand == nil { c.helpCommand = &Command{ Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. Simply type ` + c.Name() + ` help [path to command] for full details.`, ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) { var completions []string cmd, _, e := c.Root().Find(args) if e != nil { return nil, ShellCompDirectiveNoFileComp } if cmd == nil { // Root help command. cmd = c.Root() } for _, subCmd := range cmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) } } } return completions, ShellCompDirectiveNoFileComp }, Run: func(c *Command, args []string) { cmd, _, e := c.Root().Find(args) if cmd == nil || e != nil { c.Printf("Unknown help topic %#q\n", args) CheckErr(c.Root().Usage()) } else { cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown CheckErr(cmd.Help()) } }, } } c.RemoveCommand(c.helpCommand) c.AddCommand(c.helpCommand) } // ResetCommands delete parent, subcommand and help command from c. func (c *Command) ResetCommands() { c.parent = nil c.commands = nil c.helpCommand = nil c.parentsPflags = nil } // Sorts commands by their names. type commandSorterByName []*Command func (c commandSorterByName) Len() int { return len(c) } func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } // Commands returns a sorted slice of child commands. func (c *Command) Commands() []*Command { // do not sort commands if it already sorted or sorting was disabled if EnableCommandSorting && !c.commandsAreSorted { sort.Sort(commandSorterByName(c.commands)) c.commandsAreSorted = true } return c.commands } // AddCommand adds one or more commands to this parent command. func (c *Command) AddCommand(cmds ...*Command) { for i, x := range cmds { if cmds[i] == c { panic("Command can't be a child of itself") } cmds[i].parent = c // update max lengths usageLen := len(x.Use) if usageLen > c.commandsMaxUseLen { c.commandsMaxUseLen = usageLen } commandPathLen := len(x.CommandPath()) if commandPathLen > c.commandsMaxCommandPathLen { c.commandsMaxCommandPathLen = commandPathLen } nameLen := len(x.Name()) if nameLen > c.commandsMaxNameLen { c.commandsMaxNameLen = nameLen } // If global normalization function exists, update all children if c.globNormFunc != nil { x.SetGlobalNormalizationFunc(c.globNormFunc) } c.commands = append(c.commands, x) c.commandsAreSorted = false } } // RemoveCommand removes one or more commands from a parent command. func (c *Command) RemoveCommand(cmds ...*Command) { commands := []*Command{} main: for _, command := range c.commands { for _, cmd := range cmds { if command == cmd { command.parent = nil continue main } } commands = append(commands, command) } c.commands = commands // recompute all lengths c.commandsMaxUseLen = 0 c.commandsMaxCommandPathLen = 0 c.commandsMaxNameLen = 0 for _, command := range c.commands { usageLen := len(command.Use) if usageLen > c.commandsMaxUseLen { c.commandsMaxUseLen = usageLen } commandPathLen := len(command.CommandPath()) if commandPathLen > c.commandsMaxCommandPathLen { c.commandsMaxCommandPathLen = commandPathLen } nameLen := len(command.Name()) if nameLen > c.commandsMaxNameLen { c.commandsMaxNameLen = nameLen } } } // Print is a convenience method to Print to the defined output, fallback to Stderr if not set. func (c *Command) Print(i ...interface{}) { fmt.Fprint(c.OutOrStderr(), i...) } // Println is a convenience method to Println to the defined output, fallback to Stderr if not set. func (c *Command) Println(i ...interface{}) { c.Print(fmt.Sprintln(i...)) } // Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. func (c *Command) Printf(format string, i ...interface{}) { c.Print(fmt.Sprintf(format, i...)) } // PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. func (c *Command) PrintErr(i ...interface{}) { fmt.Fprint(c.ErrOrStderr(), i...) } // PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. func (c *Command) PrintErrln(i ...interface{}) { c.PrintErr(fmt.Sprintln(i...)) } // PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. func (c *Command) PrintErrf(format string, i ...interface{}) { c.PrintErr(fmt.Sprintf(format, i...)) } // CommandPath returns the full path to this command. func (c *Command) CommandPath() string { if c.HasParent() { return c.Parent().CommandPath() + " " + c.Name() } return c.Name() } // UseLine puts out the full usage for a given command (including parents). func (c *Command) UseLine() string { var useline string if c.HasParent() { useline = c.parent.CommandPath() + " " + c.Use } else { useline = c.Use } if c.DisableFlagsInUseLine { return useline } if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { useline += " [flags]" } return useline } // DebugFlags used to determine which flags have been assigned to which commands // and which persist. func (c *Command) DebugFlags() { c.Println("DebugFlags called on", c.Name()) var debugflags func(*Command) debugflags = func(x *Command) { if x.HasFlags() || x.HasPersistentFlags() { c.Println(x.Name()) } if x.HasFlags() { x.flags.VisitAll(func(f *flag.Flag) { if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") } else { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") } }) } if x.HasPersistentFlags() { x.pflags.VisitAll(func(f *flag.Flag) { if x.HasFlags() { if x.flags.Lookup(f.Name) == nil { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") } } else { c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") } }) } c.Println(x.flagErrorBuf) if x.HasSubCommands() { for _, y := range x.commands { debugflags(y) } } } debugflags(c) } // Name returns the command's name: the first word in the use line. func (c *Command) Name() string { name := c.Use i := strings.Index(name, " ") if i >= 0 { name = name[:i] } return name } // HasAlias determines if a given string is an alias of the command. func (c *Command) HasAlias(s string) bool { for _, a := range c.Aliases { if a == s { return true } } return false } // CalledAs returns the command name or alias that was used to invoke // this command or an empty string if the command has not been called. func (c *Command) CalledAs() string { if c.commandCalledAs.called { return c.commandCalledAs.name } return "" } // hasNameOrAliasPrefix returns true if the Name or any of aliases start // with prefix func (c *Command) hasNameOrAliasPrefix(prefix string) bool { if strings.HasPrefix(c.Name(), prefix) { c.commandCalledAs.name = c.Name() return true } for _, alias := range c.Aliases { if strings.HasPrefix(alias, prefix) { c.commandCalledAs.name = alias return true } } return false } // NameAndAliases returns a list of the command name and all aliases func (c *Command) NameAndAliases() string { return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") } // HasExample determines if the command has example. func (c *Command) HasExample() bool { return len(c.Example) > 0 } // Runnable determines if the command is itself runnable. func (c *Command) Runnable() bool { return c.Run != nil || c.RunE != nil } // HasSubCommands determines if the command has children commands. func (c *Command) HasSubCommands() bool { return len(c.commands) > 0 } // IsAvailableCommand determines if a command is available as a non-help command // (this includes all non deprecated/hidden commands). func (c *Command) IsAvailableCommand() bool { if len(c.Deprecated) != 0 || c.Hidden { return false } if c.HasParent() && c.Parent().helpCommand == c { return false } if c.Runnable() || c.HasAvailableSubCommands() { return true } return false } // IsAdditionalHelpTopicCommand determines if a command is an additional // help topic command; additional help topic command is determined by the // fact that it is NOT runnable/hidden/deprecated, and has no sub commands that // are runnable/hidden/deprecated. // Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. func (c *Command) IsAdditionalHelpTopicCommand() bool { // if a command is runnable, deprecated, or hidden it is not a 'help' command if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { return false } // if any non-help sub commands are found, the command is not a 'help' command for _, sub := range c.commands { if !sub.IsAdditionalHelpTopicCommand() { return false } } // the command either has no sub commands, or no non-help sub commands return true } // HasHelpSubCommands determines if a command has any available 'help' sub commands // that need to be shown in the usage/help default template under 'additional help // topics'. func (c *Command) HasHelpSubCommands() bool { // return true on the first found available 'help' sub command for _, sub := range c.commands { if sub.IsAdditionalHelpTopicCommand() { return true } } // the command either has no sub commands, or no available 'help' sub commands return false } // HasAvailableSubCommands determines if a command has available sub commands that // need to be shown in the usage/help default template under 'available commands'. func (c *Command) HasAvailableSubCommands() bool { // return true on the first found available (non deprecated/help/hidden) // sub command for _, sub := range c.commands { if sub.IsAvailableCommand() { return true } } // the command either has no sub commands, or no available (non deprecated/help/hidden) // sub commands return false } // HasParent determines if the command is a child command. func (c *Command) HasParent() bool { return c.parent != nil } // GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { return c.globNormFunc } // Flags returns the complete FlagSet that applies // to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.flags.SetOutput(c.flagErrorBuf) } return c.flags } // LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { persistentFlags := c.PersistentFlags() out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.LocalFlags().VisitAll(func(f *flag.Flag) { if persistentFlags.Lookup(f.Name) == nil { out.AddFlag(f) } }) return out } // LocalFlags returns the local FlagSet specifically set in the current command. func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() if c.lflags == nil { c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.lflags.SetOutput(c.flagErrorBuf) } c.lflags.SortFlags = c.Flags().SortFlags if c.globNormFunc != nil { c.lflags.SetNormalizeFunc(c.globNormFunc) } addToLocal := func(f *flag.Flag) { if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { c.lflags.AddFlag(f) } } c.Flags().VisitAll(addToLocal) c.PersistentFlags().VisitAll(addToLocal) return c.lflags } // InheritedFlags returns all flags which were inherited from parent commands. func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() if c.iflags == nil { c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.iflags.SetOutput(c.flagErrorBuf) } local := c.LocalFlags() if c.globNormFunc != nil { c.iflags.SetNormalizeFunc(c.globNormFunc) } c.parentsPflags.VisitAll(func(f *flag.Flag) { if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { c.iflags.AddFlag(f) } }) return c.iflags } // NonInheritedFlags returns all flags which were not inherited from parent commands. func (c *Command) NonInheritedFlags() *flag.FlagSet { return c.LocalFlags() } // PersistentFlags returns the persistent FlagSet specifically set in the current command. func (c *Command) PersistentFlags() *flag.FlagSet { if c.pflags == nil { c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } c.pflags.SetOutput(c.flagErrorBuf) } return c.pflags } // ResetFlags deletes all flags from command. func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.flags.SetOutput(c.flagErrorBuf) c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.pflags.SetOutput(c.flagErrorBuf) c.lflags = nil c.iflags = nil c.parentsPflags = nil } // HasFlags checks if the command contains any flags (local plus persistent from the entire structure). func (c *Command) HasFlags() bool { return c.Flags().HasFlags() } // HasPersistentFlags checks if the command contains persistent flags. func (c *Command) HasPersistentFlags() bool { return c.PersistentFlags().HasFlags() } // HasLocalFlags checks if the command has flags specifically declared locally. func (c *Command) HasLocalFlags() bool { return c.LocalFlags().HasFlags() } // HasInheritedFlags checks if the command has flags inherited from its parent command. func (c *Command) HasInheritedFlags() bool { return c.InheritedFlags().HasFlags() } // HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire // structure) which are not hidden or deprecated. func (c *Command) HasAvailableFlags() bool { return c.Flags().HasAvailableFlags() } // HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. func (c *Command) HasAvailablePersistentFlags() bool { return c.PersistentFlags().HasAvailableFlags() } // HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden // or deprecated. func (c *Command) HasAvailableLocalFlags() bool { return c.LocalFlags().HasAvailableFlags() } // HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are // not hidden or deprecated. func (c *Command) HasAvailableInheritedFlags() bool { return c.InheritedFlags().HasAvailableFlags() } // Flag climbs up the command tree looking for matching flag. func (c *Command) Flag(name string) (flag *flag.Flag) { flag = c.Flags().Lookup(name) if flag == nil { flag = c.persistentFlag(name) } return } // Recursively find matching persistent flag. func (c *Command) persistentFlag(name string) (flag *flag.Flag) { if c.HasPersistentFlags() { flag = c.PersistentFlags().Lookup(name) } if flag == nil { c.updateParentsPflags() flag = c.parentsPflags.Lookup(name) } return } // ParseFlags parses persistent flag tree and local flags. func (c *Command) ParseFlags(args []string) error { if c.DisableFlagParsing { return nil } if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } beforeErrorBufLen := c.flagErrorBuf.Len() c.mergePersistentFlags() // do it here after merging all flags and just before parse c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) err := c.Flags().Parse(args) // Print warnings if they occurred (e.g. deprecated flag messages). if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { c.Print(c.flagErrorBuf.String()) } return err } // Parent returns a commands parent command. func (c *Command) Parent() *Command { return c.parent } // mergePersistentFlags merges c.PersistentFlags() to c.Flags() // and adds missing persistent flags of all parents. func (c *Command) mergePersistentFlags() { c.updateParentsPflags() c.Flags().AddFlagSet(c.PersistentFlags()) c.Flags().AddFlagSet(c.parentsPflags) } // updateParentsPflags updates c.parentsPflags by adding // new persistent flags of all parents. // If c.parentsPflags == nil, it makes new. func (c *Command) updateParentsPflags() { if c.parentsPflags == nil { c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.parentsPflags.SetOutput(c.flagErrorBuf) c.parentsPflags.SortFlags = false } if c.globNormFunc != nil { c.parentsPflags.SetNormalizeFunc(c.globNormFunc) } c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) c.VisitParents(func(parent *Command) { c.parentsPflags.AddFlagSet(parent.PersistentFlags()) }) } cobra-1.3.0/command_notwin.go000066400000000000000000000001301415616037300161440ustar00rootroot00000000000000//go:build !windows // +build !windows package cobra var preExecHookFn func(*Command) cobra-1.3.0/command_test.go000066400000000000000000001536471415616037300156330ustar00rootroot00000000000000package cobra import ( "bytes" "context" "fmt" "io/ioutil" "os" "reflect" "strings" "testing" "github.com/spf13/pflag" ) func emptyRun(*Command, []string) {} func executeCommand(root *Command, args ...string) (output string, err error) { _, output, err = executeCommandC(root, args...) return output, err } func executeCommandWithContext(ctx context.Context, root *Command, args ...string) (output string, err error) { buf := new(bytes.Buffer) root.SetOut(buf) root.SetErr(buf) root.SetArgs(args) err = root.ExecuteContext(ctx) return buf.String(), err } func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) { buf := new(bytes.Buffer) root.SetOut(buf) root.SetErr(buf) root.SetArgs(args) c, err = root.ExecuteC() return c, buf.String(), err } func executeCommandWithContextC(ctx context.Context, root *Command, args ...string) (c *Command, output string, err error) { buf := new(bytes.Buffer) root.SetOut(buf) root.SetErr(buf) root.SetArgs(args) c, err = root.ExecuteContextC(ctx) return c, buf.String(), err } func resetCommandLineFlagSet() { pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) } func checkStringContains(t *testing.T, got, expected string) { if !strings.Contains(got, expected) { t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) } } func checkStringOmits(t *testing.T, got, expected string) { if strings.Contains(got, expected) { t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) } } const onetwo = "one two" func TestSingleCommand(t *testing.T) { var rootCmdArgs []string rootCmd := &Command{ Use: "root", Args: ExactArgs(2), Run: func(_ *Command, args []string) { rootCmdArgs = args }, } aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun} bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(aCmd, bCmd) output, err := executeCommand(rootCmd, "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(rootCmdArgs, " ") if got != onetwo { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } func TestChildCommand(t *testing.T) { var child1CmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child1Cmd := &Command{ Use: "child1", Args: ExactArgs(2), Run: func(_ *Command, args []string) { child1CmdArgs = args }, } child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(child1Cmd, child2Cmd) output, err := executeCommand(rootCmd, "child1", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(child1CmdArgs, " ") if got != onetwo { t.Errorf("child1CmdArgs expected: %q, got: %q", onetwo, got) } } func TestCallCommandWithoutSubcommands(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} _, err := executeCommand(rootCmd) if err != nil { t.Errorf("Calling command without subcommands should not have error: %v", err) } } func TestRootExecuteUnknownCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(rootCmd, "unknown") expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n" if output != expected { t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output) } } func TestSubcommandExecuteC(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) c, output, err := executeCommandC(rootCmd, "child") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if c.Name() != "child" { t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name()) } } func TestExecuteContext(t *testing.T) { ctx := context.TODO() ctxRun := func(cmd *Command, args []string) { if cmd.Context() != ctx { t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use) } } rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun} childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun} granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun} childCmd.AddCommand(granchildCmd) rootCmd.AddCommand(childCmd) if _, err := executeCommandWithContext(ctx, rootCmd, ""); err != nil { t.Errorf("Root command must not fail: %+v", err) } if _, err := executeCommandWithContext(ctx, rootCmd, "child"); err != nil { t.Errorf("Subcommand must not fail: %+v", err) } if _, err := executeCommandWithContext(ctx, rootCmd, "child", "grandchild"); err != nil { t.Errorf("Command child must not fail: %+v", err) } } func TestExecuteContextC(t *testing.T) { ctx := context.TODO() ctxRun := func(cmd *Command, args []string) { if cmd.Context() != ctx { t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use) } } rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun} childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun} granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun} childCmd.AddCommand(granchildCmd) rootCmd.AddCommand(childCmd) if _, _, err := executeCommandWithContextC(ctx, rootCmd, ""); err != nil { t.Errorf("Root command must not fail: %+v", err) } if _, _, err := executeCommandWithContextC(ctx, rootCmd, "child"); err != nil { t.Errorf("Subcommand must not fail: %+v", err) } if _, _, err := executeCommandWithContextC(ctx, rootCmd, "child", "grandchild"); err != nil { t.Errorf("Command child must not fail: %+v", err) } } func TestExecute_NoContext(t *testing.T) { run := func(cmd *Command, args []string) { if cmd.Context() != context.Background() { t.Errorf("Command %s must have background context", cmd.Use) } } rootCmd := &Command{Use: "root", Run: run, PreRun: run} childCmd := &Command{Use: "child", Run: run, PreRun: run} granchildCmd := &Command{Use: "grandchild", Run: run, PreRun: run} childCmd.AddCommand(granchildCmd) rootCmd.AddCommand(childCmd) if _, err := executeCommand(rootCmd, ""); err != nil { t.Errorf("Root command must not fail: %+v", err) } if _, err := executeCommand(rootCmd, "child"); err != nil { t.Errorf("Subcommand must not fail: %+v", err) } if _, err := executeCommand(rootCmd, "child", "grandchild"); err != nil { t.Errorf("Command child must not fail: %+v", err) } } func TestRootUnknownCommandSilenced(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.SilenceErrors = true rootCmd.SilenceUsage = true rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(rootCmd, "unknown") if output != "" { t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output) } } func TestCommandAlias(t *testing.T) { var timesCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} echoCmd := &Command{ Use: "echo", Aliases: []string{"say", "tell"}, Args: NoArgs, Run: emptyRun, } timesCmd := &Command{ Use: "times", Args: ExactArgs(2), Run: func(_ *Command, args []string) { timesCmdArgs = args }, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd) output, err := executeCommand(rootCmd, "tell", "times", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(timesCmdArgs, " ") if got != onetwo { t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got) } } func TestEnablePrefixMatching(t *testing.T) { EnablePrefixMatching = true var aCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} aCmd := &Command{ Use: "aCmd", Args: ExactArgs(2), Run: func(_ *Command, args []string) { aCmdArgs = args }, } bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(aCmd, bCmd) output, err := executeCommand(rootCmd, "a", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(aCmdArgs, " ") if got != onetwo { t.Errorf("aCmdArgs expected: %q, got: %q", onetwo, got) } EnablePrefixMatching = false } func TestAliasPrefixMatching(t *testing.T) { EnablePrefixMatching = true var timesCmdArgs []string rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} echoCmd := &Command{ Use: "echo", Aliases: []string{"say", "tell"}, Args: NoArgs, Run: emptyRun, } timesCmd := &Command{ Use: "times", Args: ExactArgs(2), Run: func(_ *Command, args []string) { timesCmdArgs = args }, } echoCmd.AddCommand(timesCmd) rootCmd.AddCommand(echoCmd) output, err := executeCommand(rootCmd, "sa", "times", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(timesCmdArgs, " ") if got != onetwo { t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got) } EnablePrefixMatching = false } // TestChildSameName checks the correct behaviour of cobra in cases, // when an application with name "foo" and with subcommand "foo" // is executed with args "foo foo". func TestChildSameName(t *testing.T) { var fooCmdArgs []string rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} fooCmd := &Command{ Use: "foo", Args: ExactArgs(2), Run: func(_ *Command, args []string) { fooCmdArgs = args }, } barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} rootCmd.AddCommand(fooCmd, barCmd) output, err := executeCommand(rootCmd, "foo", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(fooCmdArgs, " ") if got != onetwo { t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got) } } // TestGrandChildSameName checks the correct behaviour of cobra in cases, // when user has a root command and a grand child // with the same name. func TestGrandChildSameName(t *testing.T) { var fooCmdArgs []string rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} fooCmd := &Command{ Use: "foo", Args: ExactArgs(2), Run: func(_ *Command, args []string) { fooCmdArgs = args }, } barCmd.AddCommand(fooCmd) rootCmd.AddCommand(barCmd) output, err := executeCommand(rootCmd, "bar", "foo", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(fooCmdArgs, " ") if got != onetwo { t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got) } } func TestFlagLong(t *testing.T) { var cArgs []string c := &Command{ Use: "c", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { cArgs = args }, } var intFlagValue int var stringFlagValue string c.Flags().IntVar(&intFlagValue, "intf", -1, "") c.Flags().StringVar(&stringFlagValue, "sf", "", "") output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if c.ArgsLenAtDash() != 1 { t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash()) } if intFlagValue != 7 { t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue) } if stringFlagValue != "abc" { t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) } got := strings.Join(cArgs, " ") if got != onetwo { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } func TestFlagShort(t *testing.T) { var cArgs []string c := &Command{ Use: "c", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { cArgs = args }, } var intFlagValue int var stringFlagValue string c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "") output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } if stringFlagValue != "abc" { t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) } got := strings.Join(cArgs, " ") if got != onetwo { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } func TestChildFlag(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var intFlagValue int childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") output, err := executeCommand(rootCmd, "child", "-i7") if output != "" { t.Errorf("Unexpected output: %v", err) } if err != nil { t.Errorf("Unexpected error: %v", err) } if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } } func TestChildFlagWithParentLocalFlag(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var intFlagValue int rootCmd.Flags().StringP("sf", "s", "", "") childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") _, err := executeCommand(rootCmd, "child", "-i7", "-sabc") if err == nil { t.Errorf("Invalid flag should generate error") } checkStringContains(t, err.Error(), "unknown shorthand") if intFlagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) } } func TestFlagInvalidInput(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd.Flags().IntP("intf", "i", -1, "") _, err := executeCommand(rootCmd, "-iabc") if err == nil { t.Errorf("Invalid flag value should generate error") } checkStringContains(t, err.Error(), "invalid syntax") } func TestFlagBeforeCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) var flagValue int childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "") // With short flag. _, err := executeCommand(rootCmd, "-i7", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 7 { t.Errorf("Expected flag value: %v, got %v", 7, flagValue) } // With long flag. _, err = executeCommand(rootCmd, "--intf=8", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 8 { t.Errorf("Expected flag value: %v, got %v", 9, flagValue) } } func TestStripFlags(t *testing.T) { tests := []struct { input []string output []string }{ { []string{"foo", "bar"}, []string{"foo", "bar"}, }, { []string{"foo", "--str", "-s"}, []string{"foo"}, }, { []string{"-s", "foo", "--str", "bar"}, []string{}, }, { []string{"-i10", "echo"}, []string{"echo"}, }, { []string{"-i=10", "echo"}, []string{"echo"}, }, { []string{"--int=100", "echo"}, []string{"echo"}, }, { []string{"-ib", "echo", "-sfoo", "baz"}, []string{"echo", "baz"}, }, { []string{"-i=baz", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"--int=baz", "-sbar", "-i", "foo", "blah"}, []string{"blah"}, }, { []string{"--bool", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"-b", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { []string{"--persist", "bar"}, []string{"bar"}, }, { []string{"-p", "bar"}, []string{"bar"}, }, } c := &Command{Use: "c", Run: emptyRun} c.PersistentFlags().BoolP("persist", "p", false, "") c.Flags().IntP("int", "i", -1, "") c.Flags().StringP("str", "s", "", "") c.Flags().BoolP("bool", "b", false, "") for i, test := range tests { got := stripFlags(test.input, c) if !reflect.DeepEqual(test.output, got) { t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got) } } } func TestDisableFlagParsing(t *testing.T) { var cArgs []string c := &Command{ Use: "c", DisableFlagParsing: true, Run: func(_ *Command, args []string) { cArgs = args }, } args := []string{"cmd", "-v", "-race", "-file", "foo.go"} output, err := executeCommand(c, args...) if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if !reflect.DeepEqual(args, cArgs) { t.Errorf("Expected: %v, got: %v", args, cArgs) } } func TestPersistentFlagsOnSameCommand(t *testing.T) { var rootCmdArgs []string rootCmd := &Command{ Use: "root", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { rootCmdArgs = args }, } var flagValue int rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "") output, err := executeCommand(rootCmd, "-i7", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(rootCmdArgs, " ") if got != onetwo { t.Errorf("rootCmdArgs expected: %q, got %q", onetwo, got) } if flagValue != 7 { t.Errorf("flagValue expected: %v, got %v", 7, flagValue) } } // TestEmptyInputs checks, // if flags correctly parsed with blank strings in args. func TestEmptyInputs(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} var flagValue int c.Flags().IntVarP(&flagValue, "intf", "i", -1, "") output, err := executeCommand(c, "", "-i7", "") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if flagValue != 7 { t.Errorf("flagValue expected: %v, got %v", 7, flagValue) } } func TestOverwrittenFlag(t *testing.T) { // TODO: This test fails, but should work. t.Skip() parent := &Command{Use: "parent", Run: emptyRun} child := &Command{Use: "child", Run: emptyRun} parent.PersistentFlags().Bool("boolf", false, "") parent.PersistentFlags().Int("intf", -1, "") child.Flags().String("strf", "", "") child.Flags().Int("intf", -1, "") parent.AddCommand(child) childInherited := child.InheritedFlags() childLocal := child.LocalFlags() if childLocal.Lookup("strf") == nil { t.Error(`LocalFlags expected to contain "strf", got "nil"`) } if childInherited.Lookup("boolf") == nil { t.Error(`InheritedFlags expected to contain "boolf", got "nil"`) } if childInherited.Lookup("intf") != nil { t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`) } if childLocal.Lookup("intf") == nil { t.Error(`LocalFlags expected to contain "intf", got "nil"`) } } func TestPersistentFlagsOnChild(t *testing.T) { var childCmdArgs []string rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{ Use: "child", Args: ArbitraryArgs, Run: func(_ *Command, args []string) { childCmdArgs = args }, } rootCmd.AddCommand(childCmd) var parentFlagValue int var childFlagValue int rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "") childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "") output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } got := strings.Join(childCmdArgs, " ") if got != onetwo { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } if parentFlagValue != 8 { t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) } if childFlagValue != 7 { t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue) } } func TestRequiredFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().String("foo1", "", "") assertNoErr(t, c.MarkFlagRequired("foo1")) c.Flags().String("foo2", "", "") assertNoErr(t, c.MarkFlagRequired("foo2")) c.Flags().String("bar", "", "") expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") _, err := executeCommand(c) got := err.Error() if got != expected { t.Errorf("Expected error: %q, got: %q", expected, got) } } func TestPersistentRequiredFlags(t *testing.T) { parent := &Command{Use: "parent", Run: emptyRun} parent.PersistentFlags().String("foo1", "", "") assertNoErr(t, parent.MarkPersistentFlagRequired("foo1")) parent.PersistentFlags().String("foo2", "", "") assertNoErr(t, parent.MarkPersistentFlagRequired("foo2")) parent.Flags().String("foo3", "", "") child := &Command{Use: "child", Run: emptyRun} child.Flags().String("bar1", "", "") assertNoErr(t, child.MarkFlagRequired("bar1")) child.Flags().String("bar2", "", "") assertNoErr(t, child.MarkFlagRequired("bar2")) child.Flags().String("bar3", "", "") parent.AddCommand(child) expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2") _, err := executeCommand(parent, "child") if err.Error() != expected { t.Errorf("Expected %q, got %q", expected, err.Error()) } } func TestPersistentRequiredFlagsWithDisableFlagParsing(t *testing.T) { // Make sure a required persistent flag does not break // commands that disable flag parsing parent := &Command{Use: "parent", Run: emptyRun} parent.PersistentFlags().Bool("foo", false, "") flag := parent.PersistentFlags().Lookup("foo") assertNoErr(t, parent.MarkPersistentFlagRequired("foo")) child := &Command{Use: "child", Run: emptyRun} child.DisableFlagParsing = true parent.AddCommand(child) if _, err := executeCommand(parent, "--foo", "child"); err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag or else it will remember the state from the previous command flag.Changed = false if _, err := executeCommand(parent, "child", "--foo"); err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag or else it will remember the state from the previous command flag.Changed = false if _, err := executeCommand(parent, "child"); err != nil { t.Errorf("Unexpected error: %v", err) } } func TestInitHelpFlagMergesFlags(t *testing.T) { usage := "custom flag" rootCmd := &Command{Use: "root"} rootCmd.PersistentFlags().Bool("help", false, "custom flag") childCmd := &Command{Use: "child"} rootCmd.AddCommand(childCmd) childCmd.InitDefaultHelpFlag() got := childCmd.Flags().Lookup("help").Usage if got != usage { t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got) } } func TestHelpCommandExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) output, err := executeCommand(rootCmd, "help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, rootCmd.Long) } func TestHelpCommandExecutedOnChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "help", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } func TestSetHelpCommand(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.AddCommand(&Command{Use: "empty", Run: emptyRun}) expected := "WORKS" c.SetHelpCommand(&Command{ Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. Simply type ` + c.Name() + ` help [path to command] for full details.`, Run: func(c *Command, _ []string) { c.Print(expected) }, }) got, err := executeCommand(c, "help") if err != nil { t.Errorf("Unexpected error: %v", err) } if got != expected { t.Errorf("Expected to contain %q, got %q", expected, got) } } func TestHelpFlagExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, rootCmd.Long) } func TestHelpFlagExecutedOnChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child", "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } // TestHelpFlagInHelp checks, // if '--help' flag is shown in help for child (executing `parent help child`), // that has no other flags. // Related to https://github.com/spf13/cobra/issues/302. func TestHelpFlagInHelp(t *testing.T) { parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}} childCmd := &Command{Use: "child", Run: func(*Command, []string) {}} parentCmd.AddCommand(childCmd) output, err := executeCommand(parentCmd, "help", "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "[flags]") } func TestFlagsInUsage(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}} output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "[flags]") } func TestHelpExecutedOnNonRunnableChild(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Long: "Long description"} rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, childCmd.Long) } func TestVersionFlagExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} output, err := executeCommand(rootCmd, "--version", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestVersionFlagExecutedWithNoName(t *testing.T) { rootCmd := &Command{Version: "1.0.0", Run: emptyRun} output, err := executeCommand(rootCmd, "--version", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "version 1.0.0") } func TestShortAndLongVersionFlagInHelp(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "-v, --version") } func TestLongVersionFlagOnlyInHelpWhenShortPredefined(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.Flags().StringP("foo", "v", "", "not a version flag") output, err := executeCommand(rootCmd, "--help") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringOmits(t, output, "-v, --version") checkStringContains(t, output, "--version") } func TestShorthandVersionFlagExecuted(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} output, err := executeCommand(rootCmd, "-v", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestVersionTemplate(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) output, err := executeCommand(rootCmd, "--version", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "customized version: 1.0.0") } func TestShorthandVersionTemplate(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) output, err := executeCommand(rootCmd, "-v", "arg1") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "customized version: 1.0.0") } func TestVersionFlagExecutedOnSubcommand(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0"} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) output, err := executeCommand(rootCmd, "--version", "sub") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestShorthandVersionFlagExecutedOnSubcommand(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0"} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) output, err := executeCommand(rootCmd, "-v", "sub") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, "root version 1.0.0") } func TestVersionFlagOnlyAddedToRoot(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) _, err := executeCommand(rootCmd, "sub", "--version") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown flag: --version") } func TestShortVersionFlagOnlyAddedToRoot(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) _, err := executeCommand(rootCmd, "sub", "-v") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") } func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} _, err := executeCommand(rootCmd, "--version") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown flag: --version") } func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} _, err := executeCommand(rootCmd, "-v") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") } func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"} rootCmd.Flags().StringP("notversion", "v", "", "not a version flag") _, err := executeCommand(rootCmd, "-v") if err == nil { t.Errorf("Expected error") } check(t, rootCmd.Flags().ShorthandLookup("v").Name, "notversion") checkStringContains(t, err.Error(), "flag needs an argument: 'v' in -v") } func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"} rootCmd.Flags().Bool("version", false, "a different kind of version flag") _, err := executeCommand(rootCmd, "-v") if err == nil { t.Errorf("Expected error") } checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") } func TestUsageIsNotPrintedTwice(t *testing.T) { var cmd = &Command{Use: "root"} var sub = &Command{Use: "sub"} cmd.AddCommand(sub) output, _ := executeCommand(cmd, "") if strings.Count(output, "Usage:") != 1 { t.Error("Usage output is not printed exactly once") } } func TestVisitParents(t *testing.T) { c := &Command{Use: "app"} sub := &Command{Use: "sub"} dsub := &Command{Use: "dsub"} sub.AddCommand(dsub) c.AddCommand(sub) total := 0 add := func(x *Command) { total++ } sub.VisitParents(add) if total != 1 { t.Errorf("Should have visited 1 parent but visited %d", total) } total = 0 dsub.VisitParents(add) if total != 2 { t.Errorf("Should have visited 2 parents but visited %d", total) } total = 0 c.VisitParents(add) if total != 0 { t.Errorf("Should have visited no parents but visited %d", total) } } func TestSuggestions(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} timesCmd := &Command{ Use: "times", SuggestFor: []string{"counts"}, Run: emptyRun, } rootCmd.AddCommand(timesCmd) templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n" templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n" tests := map[string]string{ "time": "times", "tiems": "times", "tims": "times", "timeS": "times", "rimes": "times", "ti": "times", "t": "times", "timely": "times", "ri": "", "timezone": "", "foo": "", "counts": "times", } for typo, suggestion := range tests { for _, suggestionsDisabled := range []bool{true, false} { rootCmd.DisableSuggestions = suggestionsDisabled var expected string output, _ := executeCommand(rootCmd, typo) if suggestion == "" || suggestionsDisabled { expected = fmt.Sprintf(templateWithoutSuggestions, typo) } else { expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion) } if output != expected { t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output) } } } } func TestRemoveCommand(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) rootCmd.RemoveCommand(childCmd) _, err := executeCommand(rootCmd, "child") if err == nil { t.Error("Expected error on calling removed command. Got nil.") } } func TestReplaceCommandWithRemove(t *testing.T) { childUsed := 0 rootCmd := &Command{Use: "root", Run: emptyRun} child1Cmd := &Command{ Use: "child", Run: func(*Command, []string) { childUsed = 1 }, } child2Cmd := &Command{ Use: "child", Run: func(*Command, []string) { childUsed = 2 }, } rootCmd.AddCommand(child1Cmd) rootCmd.RemoveCommand(child1Cmd) rootCmd.AddCommand(child2Cmd) output, err := executeCommand(rootCmd, "child") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if childUsed == 1 { t.Error("Removed command shouldn't be called") } if childUsed != 2 { t.Error("Replacing command should have been called but didn't") } } func TestDeprecatedCommand(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} deprecatedCmd := &Command{ Use: "deprecated", Deprecated: "This command is deprecated", Run: emptyRun, } rootCmd.AddCommand(deprecatedCmd) output, err := executeCommand(rootCmd, "deprecated") if err != nil { t.Errorf("Unexpected error: %v", err) } checkStringContains(t, output, deprecatedCmd.Deprecated) } func TestHooks(t *testing.T) { var ( persPreArgs string preArgs string runArgs string postArgs string persPostArgs string ) c := &Command{ Use: "c", PersistentPreRun: func(_ *Command, args []string) { persPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { preArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { runArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { postArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { persPostArgs = strings.Join(args, " ") }, } output, err := executeCommand(c, "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } for _, v := range []struct { name string got string }{ {"persPreArgs", persPreArgs}, {"preArgs", preArgs}, {"runArgs", runArgs}, {"postArgs", postArgs}, {"persPostArgs", persPostArgs}, } { if v.got != onetwo { t.Errorf("Expected %s %q, got %q", v.name, onetwo, v.got) } } } func TestPersistentHooks(t *testing.T) { var ( parentPersPreArgs string parentPreArgs string parentRunArgs string parentPostArgs string parentPersPostArgs string ) var ( childPersPreArgs string childPreArgs string childRunArgs string childPostArgs string childPersPostArgs string ) parentCmd := &Command{ Use: "parent", PersistentPreRun: func(_ *Command, args []string) { parentPersPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { parentPreArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { parentRunArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { parentPostArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { parentPersPostArgs = strings.Join(args, " ") }, } childCmd := &Command{ Use: "child", PersistentPreRun: func(_ *Command, args []string) { childPersPreArgs = strings.Join(args, " ") }, PreRun: func(_ *Command, args []string) { childPreArgs = strings.Join(args, " ") }, Run: func(_ *Command, args []string) { childRunArgs = strings.Join(args, " ") }, PostRun: func(_ *Command, args []string) { childPostArgs = strings.Join(args, " ") }, PersistentPostRun: func(_ *Command, args []string) { childPersPostArgs = strings.Join(args, " ") }, } parentCmd.AddCommand(childCmd) output, err := executeCommand(parentCmd, "child", "one", "two") if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } for _, v := range []struct { name string got string }{ // TODO: currently PersistentPreRun* defined in parent does not // run if the matching child subcommand has PersistentPreRun. // If the behavior changes (https://github.com/spf13/cobra/issues/252) // this test must be fixed. {"parentPersPreArgs", parentPersPreArgs}, {"parentPreArgs", parentPreArgs}, {"parentRunArgs", parentRunArgs}, {"parentPostArgs", parentPostArgs}, // TODO: currently PersistentPostRun* defined in parent does not // run if the matching child subcommand has PersistentPostRun. // If the behavior changes (https://github.com/spf13/cobra/issues/252) // this test must be fixed. {"parentPersPostArgs", parentPersPostArgs}, } { if v.got != "" { t.Errorf("Expected blank %s, got %q", v.name, v.got) } } for _, v := range []struct { name string got string }{ {"childPersPreArgs", childPersPreArgs}, {"childPreArgs", childPreArgs}, {"childRunArgs", childRunArgs}, {"childPostArgs", childPostArgs}, {"childPersPostArgs", childPersPostArgs}, } { if v.got != onetwo { t.Errorf("Expected %s %q, got %q", v.name, onetwo, v.got) } } } // Related to https://github.com/spf13/cobra/issues/521. func TestGlobalNormFuncPropagation(t *testing.T) { normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(name) } rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun} rootCmd.AddCommand(childCmd) rootCmd.SetGlobalNormalizationFunc(normFunc) if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { t.Error("rootCmd seems to have a wrong normalization function") } if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() { t.Error("childCmd should have had the normalization function of rootCmd") } } // Related to https://github.com/spf13/cobra/issues/521. func TestNormPassedOnLocal(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } c := &Command{} c.Flags().Bool("flagname", true, "this is a dummy flag") c.SetGlobalNormalizationFunc(toUpper) if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to Local flag set") } } // Related to https://github.com/spf13/cobra/issues/521. func TestNormPassedOnInherited(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } c := &Command{} c.SetGlobalNormalizationFunc(toUpper) child1 := &Command{} c.AddCommand(child1) c.PersistentFlags().Bool("flagname", true, "") child2 := &Command{} c.AddCommand(child2) inherited := child1.InheritedFlags() if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to inherited flag set in command added before flag") } inherited = child2.InheritedFlags() if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { t.Error("Normalization function should be passed on to inherited flag set in command added after flag") } } // Related to https://github.com/spf13/cobra/issues/521. func TestConsistentNormalizedName(t *testing.T) { toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(strings.ToUpper(name)) } n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(name) } c := &Command{} c.Flags().Bool("flagname", true, "") c.SetGlobalNormalizationFunc(toUpper) c.SetGlobalNormalizationFunc(n) if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") { t.Error("Normalizing flag names should not result in duplicate flags") } } func TestFlagOnPflagCommandLine(t *testing.T) { flagName := "flagOnCommandLine" pflag.String(flagName, "", "about my flag") c := &Command{Use: "c", Run: emptyRun} c.AddCommand(&Command{Use: "child", Run: emptyRun}) output, _ := executeCommand(c, "--help") checkStringContains(t, output, flagName) resetCommandLineFlagSet() } // TestHiddenCommandExecutes checks, // if hidden commands run as intended. func TestHiddenCommandExecutes(t *testing.T) { executed := false c := &Command{ Use: "c", Hidden: true, Run: func(*Command, []string) { executed = true }, } output, err := executeCommand(c) if output != "" { t.Errorf("Unexpected output: %v", output) } if err != nil { t.Errorf("Unexpected error: %v", err) } if !executed { t.Error("Hidden command should have been executed") } } // test to ensure hidden commands do not show up in usage/help text func TestHiddenCommandIsHidden(t *testing.T) { c := &Command{Use: "c", Hidden: true, Run: emptyRun} if c.IsAvailableCommand() { t.Errorf("Hidden command should be unavailable") } } func TestCommandsAreSorted(t *testing.T) { EnableCommandSorting = true originalNames := []string{"middle", "zlast", "afirst"} expectedNames := []string{"afirst", "middle", "zlast"} var rootCmd = &Command{Use: "root"} for _, name := range originalNames { rootCmd.AddCommand(&Command{Use: name}) } for i, c := range rootCmd.Commands() { got := c.Name() if expectedNames[i] != got { t.Errorf("Expected: %s, got: %s", expectedNames[i], got) } } EnableCommandSorting = true } func TestEnableCommandSortingIsDisabled(t *testing.T) { EnableCommandSorting = false originalNames := []string{"middle", "zlast", "afirst"} var rootCmd = &Command{Use: "root"} for _, name := range originalNames { rootCmd.AddCommand(&Command{Use: name}) } for i, c := range rootCmd.Commands() { got := c.Name() if originalNames[i] != got { t.Errorf("expected: %s, got: %s", originalNames[i], got) } } EnableCommandSorting = true } func TestSetOutput(t *testing.T) { c := &Command{} c.SetOutput(nil) if out := c.OutOrStdout(); out != os.Stdout { t.Errorf("Expected setting output to nil to revert back to stdout") } } func TestSetOut(t *testing.T) { c := &Command{} c.SetOut(nil) if out := c.OutOrStdout(); out != os.Stdout { t.Errorf("Expected setting output to nil to revert back to stdout") } } func TestSetErr(t *testing.T) { c := &Command{} c.SetErr(nil) if out := c.ErrOrStderr(); out != os.Stderr { t.Errorf("Expected setting error to nil to revert back to stderr") } } func TestSetIn(t *testing.T) { c := &Command{} c.SetIn(nil) if out := c.InOrStdin(); out != os.Stdin { t.Errorf("Expected setting input to nil to revert back to stdin") } } func TestUsageStringRedirected(t *testing.T) { c := &Command{} c.usageFunc = func(cmd *Command) error { cmd.Print("[stdout1]") cmd.PrintErr("[stderr2]") cmd.Print("[stdout3]") return nil } expected := "[stdout1][stderr2][stdout3]" if got := c.UsageString(); got != expected { t.Errorf("Expected usage string to consider both stdout and stderr") } } func TestCommandPrintRedirection(t *testing.T) { errBuff, outBuff := bytes.NewBuffer(nil), bytes.NewBuffer(nil) root := &Command{ Run: func(cmd *Command, args []string) { cmd.PrintErr("PrintErr") cmd.PrintErrln("PrintErr", "line") cmd.PrintErrf("PrintEr%s", "r") cmd.Print("Print") cmd.Println("Print", "line") cmd.Printf("Prin%s", "t") }, } root.SetErr(errBuff) root.SetOut(outBuff) if err := root.Execute(); err != nil { t.Error(err) } gotErrBytes, err := ioutil.ReadAll(errBuff) if err != nil { t.Error(err) } gotOutBytes, err := ioutil.ReadAll(outBuff) if err != nil { t.Error(err) } if wantErr := []byte("PrintErrPrintErr line\nPrintErr"); !bytes.Equal(gotErrBytes, wantErr) { t.Errorf("got: '%s' want: '%s'", gotErrBytes, wantErr) } if wantOut := []byte("PrintPrint line\nPrint"); !bytes.Equal(gotOutBytes, wantOut) { t.Errorf("got: '%s' want: '%s'", gotOutBytes, wantOut) } } func TestFlagErrorFunc(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} expectedFmt := "This is expected: %v" c.SetFlagErrorFunc(func(_ *Command, err error) error { return fmt.Errorf(expectedFmt, err) }) _, err := executeCommand(c, "--unknown-flag") got := err.Error() expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag") if got != expected { t.Errorf("Expected %v, got %v", expected, got) } } // TestSortedFlags checks, // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false. // Related to https://github.com/spf13/cobra/issues/404. func TestSortedFlags(t *testing.T) { c := &Command{} c.Flags().SortFlags = false names := []string{"C", "B", "A", "D"} for _, name := range names { c.Flags().Bool(name, false, "") } i := 0 c.LocalFlags().VisitAll(func(f *pflag.Flag) { if i == len(names) { return } if stringInSlice(f.Name, names) { if names[i] != f.Name { t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) } i++ } }) } // TestMergeCommandLineToFlags checks, // if pflag.CommandLine is correctly merged to c.Flags() after first call // of c.mergePersistentFlags. // Related to https://github.com/spf13/cobra/issues/443. func TestMergeCommandLineToFlags(t *testing.T) { pflag.Bool("boolflag", false, "") c := &Command{Use: "c", Run: emptyRun} c.mergePersistentFlags() if c.Flags().Lookup("boolflag") == nil { t.Fatal("Expecting to have flag from CommandLine in c.Flags()") } resetCommandLineFlagSet() } // TestUseDeprecatedFlags checks, // if cobra.Execute() prints a message, if a deprecated flag is used. // Related to https://github.com/spf13/cobra/issues/463. func TestUseDeprecatedFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().BoolP("deprecated", "d", false, "deprecated flag") assertNoErr(t, c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")) output, err := executeCommand(c, "c", "-d") if err != nil { t.Error("Unexpected error:", err) } checkStringContains(t, output, "This flag is deprecated") } func TestTraverseWithParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("str", "", "") rootCmd.Flags().BoolP("bool", "b", false, "") childCmd := &Command{Use: "child"} childCmd.Flags().Int("int", -1, "") rootCmd.AddCommand(childCmd) c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 1 && args[0] != "--add" { t.Errorf("Wrong args: %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseNoParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("foo", "", "foo things") childCmd := &Command{Use: "child"} childCmd.Flags().String("str", "", "") rootCmd.AddCommand(childCmd) c, args, err := rootCmd.Traverse([]string{"child"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 0 { t.Errorf("Wrong args %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithBadParentFlags(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} childCmd := &Command{Use: "child"} childCmd.Flags().String("str", "", "") rootCmd.AddCommand(childCmd) expected := "unknown flag: --str" c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"}) if err == nil || !strings.Contains(err.Error(), expected) { t.Errorf("Expected error, %q, got %q", expected, err) } if c != nil { t.Errorf("Expected nil command") } } func TestTraverseWithBadChildFlag(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} rootCmd.Flags().String("str", "", "") childCmd := &Command{Use: "child"} rootCmd.AddCommand(childCmd) // Expect no error because the last commands args shouldn't be parsed in // Traverse. c, args, err := rootCmd.Traverse([]string{"child", "--str"}) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(args) != 1 && args[0] != "--str" { t.Errorf("Wrong args: %v", args) } if c.Name() != childCmd.Name() { t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithTwoSubcommands(t *testing.T) { rootCmd := &Command{Use: "root", TraverseChildren: true} subCmd := &Command{Use: "sub", TraverseChildren: true} rootCmd.AddCommand(subCmd) subsubCmd := &Command{ Use: "subsub", } subCmd.AddCommand(subsubCmd) c, _, err := rootCmd.Traverse([]string{"sub", "subsub"}) if err != nil { t.Fatalf("Unexpected error: %v", err) } if c.Name() != subsubCmd.Name() { t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name()) } } // TestUpdateName checks if c.Name() updates on changed c.Use. // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343. func TestUpdateName(t *testing.T) { c := &Command{Use: "name xyz"} originalName := c.Name() c.Use = "changedName abc" if originalName == c.Name() || c.Name() != "changedName" { t.Error("c.Name() should be updated on changed c.Use") } } type calledAsTestcase struct { args []string call string want string epm bool } func (tc *calledAsTestcase) test(t *testing.T) { defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching) EnablePrefixMatching = tc.epm var called *Command run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c } parent := &Command{Use: "parent", Run: run} child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}} child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}} parent.AddCommand(child1) parent.AddCommand(child2) parent.SetArgs(tc.args) output := new(bytes.Buffer) parent.SetOut(output) parent.SetErr(output) _ = parent.Execute() if called == nil { if tc.call != "" { t.Errorf("missing expected call to command: %s", tc.call) } return } if called.Name() != tc.call { t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call) } else if got := called.CalledAs(); got != tc.want { t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want) } } func TestCalledAs(t *testing.T) { tests := map[string]calledAsTestcase{ "find/no-args": {nil, "parent", "parent", false}, "find/real-name": {[]string{"child1"}, "child1", "child1", false}, "find/full-alias": {[]string{"that"}, "child2", "that", false}, "find/part-no-prefix": {[]string{"thi"}, "", "", false}, "find/part-alias": {[]string{"thi"}, "child1", "this", true}, "find/conflict": {[]string{"th"}, "", "", true}, "traverse/no-args": {nil, "parent", "parent", false}, "traverse/real-name": {[]string{"child1"}, "child1", "child1", false}, "traverse/full-alias": {[]string{"that"}, "child2", "that", false}, "traverse/part-no-prefix": {[]string{"thi"}, "", "", false}, "traverse/part-alias": {[]string{"thi"}, "child1", "this", true}, "traverse/conflict": {[]string{"th"}, "", "", true}, } for name, tc := range tests { t.Run(name, tc.test) } } func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().BoolP("boola", "a", false, "a boolean flag") output, err := executeCommand(c, "c", "-a", "--unknown", "flag") if err == nil { t.Error("expected unknown flag error") } checkStringContains(t, output, "unknown flag: --unknown") } func TestFParseErrWhitelistSameCommand(t *testing.T) { c := &Command{ Use: "c", Run: emptyRun, FParseErrWhitelist: FParseErrWhitelist{ UnknownFlags: true, }, } c.Flags().BoolP("boola", "a", false, "a boolean flag") _, err := executeCommand(c, "c", "-a", "--unknown", "flag") if err != nil { t.Error("unexpected error: ", err) } } func TestFParseErrWhitelistParentCommand(t *testing.T) { root := &Command{ Use: "root", Run: emptyRun, FParseErrWhitelist: FParseErrWhitelist{ UnknownFlags: true, }, } c := &Command{ Use: "child", Run: emptyRun, } c.Flags().BoolP("boola", "a", false, "a boolean flag") root.AddCommand(c) output, err := executeCommand(root, "child", "-a", "--unknown", "flag") if err == nil { t.Error("expected unknown flag error") } checkStringContains(t, output, "unknown flag: --unknown") } func TestFParseErrWhitelistChildCommand(t *testing.T) { root := &Command{ Use: "root", Run: emptyRun, } c := &Command{ Use: "child", Run: emptyRun, FParseErrWhitelist: FParseErrWhitelist{ UnknownFlags: true, }, } c.Flags().BoolP("boola", "a", false, "a boolean flag") root.AddCommand(c) _, err := executeCommand(root, "child", "-a", "--unknown", "flag") if err != nil { t.Error("unexpected error: ", err.Error()) } } func TestFParseErrWhitelistSiblingCommand(t *testing.T) { root := &Command{ Use: "root", Run: emptyRun, } c := &Command{ Use: "child", Run: emptyRun, FParseErrWhitelist: FParseErrWhitelist{ UnknownFlags: true, }, } c.Flags().BoolP("boola", "a", false, "a boolean flag") s := &Command{ Use: "sibling", Run: emptyRun, } s.Flags().BoolP("boolb", "b", false, "a boolean flag") root.AddCommand(c) root.AddCommand(s) output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag") if err == nil { t.Error("expected unknown flag error") } checkStringContains(t, output, "unknown flag: --unknown") } cobra-1.3.0/command_win.go000066400000000000000000000007041415616037300154320ustar00rootroot00000000000000//go:build windows // +build windows package cobra import ( "fmt" "os" "time" "github.com/inconshreveable/mousetrap" ) var preExecHookFn = preExecHook func preExecHook(c *Command) { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { c.Print(MousetrapHelpText) if MousetrapDisplayDuration > 0 { time.Sleep(MousetrapDisplayDuration) } else { c.Println("Press return to continue...") fmt.Scanln() } os.Exit(1) } } cobra-1.3.0/completions.go000066400000000000000000000735341415616037300155060ustar00rootroot00000000000000package cobra import ( "fmt" "os" "strings" "sync" "github.com/spf13/pflag" ) const ( // ShellCompRequestCmd is the name of the hidden command that is used to request // completion results from the program. It is used by the shell completion scripts. ShellCompRequestCmd = "__complete" // ShellCompNoDescRequestCmd is the name of the hidden command that is used to request // completion results without their description. It is used by the shell completion scripts. ShellCompNoDescRequestCmd = "__completeNoDesc" ) // Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it. var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){} // lock for reading and writing from flagCompletionFunctions var flagCompletionMutex = &sync.RWMutex{} // ShellCompDirective is a bit map representing the different behaviors the shell // can be instructed to have once completions have been provided. type ShellCompDirective int type flagCompError struct { subCommand string flagName string } func (e *flagCompError) Error() string { return "Subcommand '" + e.subCommand + "' does not support flag '" + e.flagName + "'" } const ( // ShellCompDirectiveError indicates an error occurred and completions should be ignored. ShellCompDirectiveError ShellCompDirective = 1 << iota // ShellCompDirectiveNoSpace indicates that the shell should not add a space // after the completion even if there is a single completion provided. ShellCompDirectiveNoSpace // ShellCompDirectiveNoFileComp indicates that the shell should not provide // file completion even when no completion is provided. ShellCompDirectiveNoFileComp // ShellCompDirectiveFilterFileExt indicates that the provided completions // should be used as file extension filters. // For flags, using Command.MarkFlagFilename() and Command.MarkPersistentFlagFilename() // is a shortcut to using this directive explicitly. The BashCompFilenameExt // annotation can also be used to obtain the same behavior for flags. ShellCompDirectiveFilterFileExt // ShellCompDirectiveFilterDirs indicates that only directory names should // be provided in file completion. To request directory names within another // directory, the returned completions should specify the directory within // which to search. The BashCompSubdirsInDir annotation can be used to // obtain the same behavior but only for flags. ShellCompDirectiveFilterDirs // =========================================================================== // All directives using iota should be above this one. // For internal use. shellCompDirectiveMaxValue // ShellCompDirectiveDefault indicates to let the shell perform its default // behavior after completions have been provided. // This one must be last to avoid messing up the iota count. ShellCompDirectiveDefault ShellCompDirective = 0 ) const ( // Constants for the completion command compCmdName = "completion" compCmdNoDescFlagName = "no-descriptions" compCmdNoDescFlagDesc = "disable completion descriptions" compCmdNoDescFlagDefault = false ) // CompletionOptions are the options to control shell completion type CompletionOptions struct { // DisableDefaultCmd prevents Cobra from creating a default 'completion' command DisableDefaultCmd bool // DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag // for shells that support completion descriptions DisableNoDescFlag bool // DisableDescriptions turns off all completion descriptions for shells // that support them DisableDescriptions bool // HiddenDefaultCmd makes the default 'completion' command hidden HiddenDefaultCmd bool } // NoFileCompletions can be used to disable file completion for commands that should // not trigger file completions. func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return nil, ShellCompDirectiveNoFileComp } // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { flag := c.Flag(flagName) if flag == nil { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) } flagCompletionMutex.Lock() defer flagCompletionMutex.Unlock() if _, exists := flagCompletionFunctions[flag]; exists { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName) } flagCompletionFunctions[flag] = f return nil } // Returns a string listing the different directive enabled in the specified parameter func (d ShellCompDirective) string() string { var directives []string if d&ShellCompDirectiveError != 0 { directives = append(directives, "ShellCompDirectiveError") } if d&ShellCompDirectiveNoSpace != 0 { directives = append(directives, "ShellCompDirectiveNoSpace") } if d&ShellCompDirectiveNoFileComp != 0 { directives = append(directives, "ShellCompDirectiveNoFileComp") } if d&ShellCompDirectiveFilterFileExt != 0 { directives = append(directives, "ShellCompDirectiveFilterFileExt") } if d&ShellCompDirectiveFilterDirs != 0 { directives = append(directives, "ShellCompDirectiveFilterDirs") } if len(directives) == 0 { directives = append(directives, "ShellCompDirectiveDefault") } if d >= shellCompDirectiveMaxValue { return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d) } return strings.Join(directives, ", ") } // Adds a special hidden command that can be used to request custom completions. func (c *Command) initCompleteCmd(args []string) { completeCmd := &Command{ Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd), Aliases: []string{ShellCompNoDescRequestCmd}, DisableFlagsInUseLine: true, Hidden: true, DisableFlagParsing: true, Args: MinimumNArgs(1), Short: "Request shell completion choices for the specified command-line", Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s", "to request completion choices for the specified command-line.", ShellCompRequestCmd), Run: func(cmd *Command, args []string) { finalCmd, completions, directive, err := cmd.getCompletions(args) if err != nil { CompErrorln(err.Error()) // Keep going for multiple reasons: // 1- There could be some valid completions even though there was an error // 2- Even without completions, we need to print the directive } noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd) for _, comp := range completions { if noDescriptions { // Remove any description that may be included following a tab character. comp = strings.Split(comp, "\t")[0] } // Make sure we only write the first line to the output. // This is needed if a description contains a linebreak. // Otherwise the shell scripts will interpret the other lines as new flags // and could therefore provide a wrong completion. comp = strings.Split(comp, "\n")[0] // Finally trim the completion. This is especially important to get rid // of a trailing tab when there are no description following it. // For example, a sub-command without a description should not be completed // with a tab at the end (or else zsh will show a -- following it // although there is no description). comp = strings.TrimSpace(comp) // Print each possible completion to stdout for the completion script to consume. fmt.Fprintln(finalCmd.OutOrStdout(), comp) } // As the last printout, print the completion directive for the completion script to parse. // The directive integer must be that last character following a single colon (:). // The completion script expects : fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive) // Print some helpful info to stderr for the user to understand. // Output from stderr must be ignored by the completion script. fmt.Fprintf(finalCmd.ErrOrStderr(), "Completion ended with directive: %s\n", directive.string()) }, } c.AddCommand(completeCmd) subCmd, _, err := c.Find(args) if err != nil || subCmd.Name() != ShellCompRequestCmd { // Only create this special command if it is actually being called. // This reduces possible side-effects of creating such a command; // for example, having this command would cause problems to a // cobra program that only consists of the root command, since this // command would cause the root command to suddenly have a subcommand. c.RemoveCommand(completeCmd) } } func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) { // The last argument, which is not completely typed by the user, // should not be part of the list of arguments toComplete := args[len(args)-1] trimmedArgs := args[:len(args)-1] var finalCmd *Command var finalArgs []string var err error // Find the real command for which completion must be performed // check if we need to traverse here to parse local flags on parent commands if c.Root().TraverseChildren { finalCmd, finalArgs, err = c.Root().Traverse(trimmedArgs) } else { // For Root commands that don't specify any value for their Args fields, when we call // Find(), if those Root commands don't have any sub-commands, they will accept arguments. // However, because we have added the __complete sub-command in the current code path, the // call to Find() -> legacyArgs() will return an error if there are any arguments. // To avoid this, we first remove the __complete command to get back to having no sub-commands. rootCmd := c.Root() if len(rootCmd.Commands()) == 1 { rootCmd.RemoveCommand(c) } finalCmd, finalArgs, err = rootCmd.Find(trimmedArgs) } if err != nil { // Unable to find the real command. E.g., someInvalidCmd return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) } finalCmd.ctx = c.ctx // Check if we are doing flag value completion before parsing the flags. // This is important because if we are completing a flag value, we need to also // remove the flag name argument from the list of finalArgs or else the parsing // could fail due to an invalid value (incomplete) for the flag. flag, finalArgs, toComplete, flagErr := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) // Check if interspersed is false or -- was set on a previous arg. // This works by counting the arguments. Normally -- is not counted as arg but // if -- was already set or interspersed is false and there is already one arg then // the extra added -- is counted as arg. flagCompletion := true _ = finalCmd.ParseFlags(append(finalArgs, "--")) newArgCount := finalCmd.Flags().NArg() // Parse the flags early so we can check if required flags are set if err = finalCmd.ParseFlags(finalArgs); err != nil { return finalCmd, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) } realArgCount := finalCmd.Flags().NArg() if newArgCount > realArgCount { // don't do flag completion (see above) flagCompletion = false } // Error while attempting to parse flags if flagErr != nil { // If error type is flagCompError and we don't want flagCompletion we should ignore the error if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr } } // We only remove the flags from the arguments if DisableFlagParsing is not set. // This is important for commands which have requested to do their own flag completion. if !finalCmd.DisableFlagParsing { finalArgs = finalCmd.Flags().Args() } if flag != nil && flagCompletion { // Check if we are completing a flag value subject to annotations if validExts, present := flag.Annotations[BashCompFilenameExt]; present { if len(validExts) != 0 { // File completion filtered by extensions return finalCmd, validExts, ShellCompDirectiveFilterFileExt, nil } // The annotation requests simple file completion. There is no reason to do // that since it is the default behavior anyway. Let's ignore this annotation // in case the program also registered a completion function for this flag. // Even though it is a mistake on the program's side, let's be nice when we can. } if subDir, present := flag.Annotations[BashCompSubdirsInDir]; present { if len(subDir) == 1 { // Directory completion from within a directory return finalCmd, subDir, ShellCompDirectiveFilterDirs, nil } // Directory completion return finalCmd, []string{}, ShellCompDirectiveFilterDirs, nil } } var completions []string var directive ShellCompDirective // Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true; // doing this allows for completion of persistant flag names even for commands that disable flag parsing. // // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as it requires // the flag name to be complete if flag == nil && len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") && flagCompletion { // First check for required flags completions = completeRequireFlags(finalCmd, toComplete) // If we have not found any required flags, only then can we show regular flags if len(completions) == 0 { doCompleteFlags := func(flag *pflag.Flag) { if !flag.Changed || strings.Contains(flag.Value.Type(), "Slice") || strings.Contains(flag.Value.Type(), "Array") { // If the flag is not already present, or if it can be specified multiple times (Array or Slice) // we suggest it as a completion completions = append(completions, getFlagNameCompletions(flag, toComplete)...) } } // We cannot use finalCmd.Flags() because we may not have called ParsedFlags() for commands // that have set DisableFlagParsing; it is ParseFlags() that merges the inherited and // non-inherited flags. finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteFlags(flag) }) finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteFlags(flag) }) } directive = ShellCompDirectiveNoFileComp if len(completions) == 1 && strings.HasSuffix(completions[0], "=") { // If there is a single completion, the shell usually adds a space // after the completion. We don't want that if the flag ends with an = directive = ShellCompDirectiveNoSpace } if !finalCmd.DisableFlagParsing { // If DisableFlagParsing==false, we have completed the flags as known by Cobra; // we can return what we found. // If DisableFlagParsing==true, Cobra may not be aware of all flags, so we // let the logic continue to see if ValidArgsFunction needs to be called. return finalCmd, completions, directive, nil } } else { directive = ShellCompDirectiveDefault if flag == nil { foundLocalNonPersistentFlag := false // If TraverseChildren is true on the root command we don't check for // local flags because we can use a local flag on a parent command if !finalCmd.Root().TraverseChildren { // Check if there are any local, non-persistent flags on the command-line localNonPersistentFlags := finalCmd.LocalNonPersistentFlags() finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed { foundLocalNonPersistentFlag = true } }) } // Complete subcommand names, including the help command if len(finalArgs) == 0 && !foundLocalNonPersistentFlag { // We only complete sub-commands if: // - there are no arguments on the command-line and // - there are no local, non-persistent flags on the command-line or TraverseChildren is true for _, subCmd := range finalCmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) } directive = ShellCompDirectiveNoFileComp } } } // Complete required flags even without the '-' prefix completions = append(completions, completeRequireFlags(finalCmd, toComplete)...) // Always complete ValidArgs, even if we are completing a subcommand name. // This is for commands that have both subcommands and ValidArgs. if len(finalCmd.ValidArgs) > 0 { if len(finalArgs) == 0 { // ValidArgs are only for the first argument for _, validArg := range finalCmd.ValidArgs { if strings.HasPrefix(validArg, toComplete) { completions = append(completions, validArg) } } directive = ShellCompDirectiveNoFileComp // If no completions were found within commands or ValidArgs, // see if there are any ArgAliases that should be completed. if len(completions) == 0 { for _, argAlias := range finalCmd.ArgAliases { if strings.HasPrefix(argAlias, toComplete) { completions = append(completions, argAlias) } } } } // If there are ValidArgs specified (even if they don't match), we stop completion. // Only one of ValidArgs or ValidArgsFunction can be used for a single command. return finalCmd, completions, directive, nil } // Let the logic continue so as to add any ValidArgsFunction completions, // even if we already found sub-commands. // This is for commands that have subcommands but also specify a ValidArgsFunction. } } // Find the completion function for the flag or command var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) if flag != nil && flagCompletion { flagCompletionMutex.RLock() completionFn = flagCompletionFunctions[flag] flagCompletionMutex.RUnlock() } else { completionFn = finalCmd.ValidArgsFunction } if completionFn != nil { // Go custom completion defined for this flag or command. // Call the registered completion function to get the completions. var comps []string comps, directive = completionFn(finalCmd, finalArgs, toComplete) completions = append(completions, comps...) } return finalCmd, completions, directive, nil } func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { if nonCompletableFlag(flag) { return []string{} } var completions []string flagName := "--" + flag.Name if strings.HasPrefix(flagName, toComplete) { // Flag without the = completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) // Why suggest both long forms: --flag and --flag= ? // This forces the user to *always* have to type either an = or a space after the flag name. // Let's be nice and avoid making users have to do that. // Since boolean flags and shortname flags don't show the = form, let's go that route and never show it. // The = form will still work, we just won't suggest it. // This also makes the list of suggested flags shorter as we avoid all the = forms. // // if len(flag.NoOptDefVal) == 0 { // // Flag requires a value, so it can be suffixed with = // flagName += "=" // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) // } } flagName = "-" + flag.Shorthand if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) { completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) } return completions } func completeRequireFlags(finalCmd *Command, toComplete string) []string { var completions []string doCompleteRequiredFlags := func(flag *pflag.Flag) { if _, present := flag.Annotations[BashCompOneRequiredFlag]; present { if !flag.Changed { // If the flag is not already present, we suggest it as a completion completions = append(completions, getFlagNameCompletions(flag, toComplete)...) } } } // We cannot use finalCmd.Flags() because we may not have called ParsedFlags() for commands // that have set DisableFlagParsing; it is ParseFlags() that merges the inherited and // non-inherited flags. finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteRequiredFlags(flag) }) finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteRequiredFlags(flag) }) return completions } func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { if finalCmd.DisableFlagParsing { // We only do flag completion if we are allowed to parse flags // This is important for commands which have requested to do their own flag completion. return nil, args, lastArg, nil } var flagName string trimmedArgs := args flagWithEqual := false orgLastArg := lastArg // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as that function // requires the flag name to be complete if len(lastArg) > 0 && lastArg[0] == '-' { if index := strings.Index(lastArg, "="); index >= 0 { // Flag with an = if strings.HasPrefix(lastArg[:index], "--") { // Flag has full name flagName = lastArg[2:index] } else { // Flag is shorthand // We have to get the last shorthand flag name // e.g. `-asd` => d to provide the correct completion // https://github.com/spf13/cobra/issues/1257 flagName = lastArg[index-1 : index] } lastArg = lastArg[index+1:] flagWithEqual = true } else { // Normal flag completion return nil, args, lastArg, nil } } if len(flagName) == 0 { if len(args) > 0 { prevArg := args[len(args)-1] if isFlagArg(prevArg) { // Only consider the case where the flag does not contain an =. // If the flag contains an = it means it has already been fully processed, // so we don't need to deal with it here. if index := strings.Index(prevArg, "="); index < 0 { if strings.HasPrefix(prevArg, "--") { // Flag has full name flagName = prevArg[2:] } else { // Flag is shorthand // We have to get the last shorthand flag name // e.g. `-asd` => d to provide the correct completion // https://github.com/spf13/cobra/issues/1257 flagName = prevArg[len(prevArg)-1:] } // Remove the uncompleted flag or else there could be an error created // for an invalid value for that flag trimmedArgs = args[:len(args)-1] } } } } if len(flagName) == 0 { // Not doing flag completion return nil, trimmedArgs, lastArg, nil } flag := findFlag(finalCmd, flagName) if flag == nil { // Flag not supported by this command, the interspersed option might be set so return the original args return nil, args, orgLastArg, &flagCompError{subCommand: finalCmd.Name(), flagName: flagName} } if !flagWithEqual { if len(flag.NoOptDefVal) != 0 { // We had assumed dealing with a two-word flag but the flag is a boolean flag. // In that case, there is no value following it, so we are not really doing flag completion. // Reset everything to do noun completion. trimmedArgs = args flag = nil } } return flag, trimmedArgs, lastArg, nil } // initDefaultCompletionCmd adds a default 'completion' command to c. // This function will do nothing if any of the following is true: // 1- the feature has been explicitly disabled by the program, // 2- c has no subcommands (to avoid creating one), // 3- c already has a 'completion' command provided by the program. func (c *Command) initDefaultCompletionCmd() { if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { return } for _, cmd := range c.commands { if cmd.Name() == compCmdName || cmd.HasAlias(compCmdName) { // A completion command is already available return } } haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions completionCmd := &Command{ Use: compCmdName, Short: "Generate the autocompletion script for the specified shell", Long: fmt.Sprintf(`Generate the autocompletion script for %[1]s for the specified shell. See each sub-command's help for details on how to use the generated script. `, c.Root().Name()), Args: NoArgs, ValidArgsFunction: NoFileCompletions, Hidden: c.CompletionOptions.HiddenDefaultCmd, } c.AddCommand(completionCmd) out := c.OutOrStdout() noDesc := c.CompletionOptions.DisableDescriptions shortDesc := "Generate the autocompletion script for %s" bash := &Command{ Use: "bash", Short: fmt.Sprintf(shortDesc, "bash"), Long: fmt.Sprintf(`Generate the autocompletion script for the bash shell. This script depends on the 'bash-completion' package. If it is not installed already, you can install it via your OS's package manager. To load completions in your current shell session: source <(%[1]s completion bash) To load completions for every new session, execute once: #### Linux: %[1]s completion bash > /etc/bash_completion.d/%[1]s #### macOS: %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s You will need to start a new shell for this setup to take effect. `, c.Root().Name()), Args: NoArgs, DisableFlagsInUseLine: true, ValidArgsFunction: NoFileCompletions, RunE: func(cmd *Command, args []string) error { return cmd.Root().GenBashCompletionV2(out, !noDesc) }, } if haveNoDescFlag { bash.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } zsh := &Command{ Use: "zsh", Short: fmt.Sprintf(shortDesc, "zsh"), Long: fmt.Sprintf(`Generate the autocompletion script for the zsh shell. If shell completion is not already enabled in your environment you will need to enable it. You can execute the following once: echo "autoload -U compinit; compinit" >> ~/.zshrc To load completions for every new session, execute once: #### Linux: %[1]s completion zsh > "${fpath[1]}/_%[1]s" #### macOS: %[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s You will need to start a new shell for this setup to take effect. `, c.Root().Name()), Args: NoArgs, ValidArgsFunction: NoFileCompletions, RunE: func(cmd *Command, args []string) error { if noDesc { return cmd.Root().GenZshCompletionNoDesc(out) } return cmd.Root().GenZshCompletion(out) }, } if haveNoDescFlag { zsh.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } fish := &Command{ Use: "fish", Short: fmt.Sprintf(shortDesc, "fish"), Long: fmt.Sprintf(`Generate the autocompletion script for the fish shell. To load completions in your current shell session: %[1]s completion fish | source To load completions for every new session, execute once: %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish You will need to start a new shell for this setup to take effect. `, c.Root().Name()), Args: NoArgs, ValidArgsFunction: NoFileCompletions, RunE: func(cmd *Command, args []string) error { return cmd.Root().GenFishCompletion(out, !noDesc) }, } if haveNoDescFlag { fish.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } powershell := &Command{ Use: "powershell", Short: fmt.Sprintf(shortDesc, "powershell"), Long: fmt.Sprintf(`Generate the autocompletion script for powershell. To load completions in your current shell session: %[1]s completion powershell | Out-String | Invoke-Expression To load completions for every new session, add the output of the above command to your powershell profile. `, c.Root().Name()), Args: NoArgs, ValidArgsFunction: NoFileCompletions, RunE: func(cmd *Command, args []string) error { if noDesc { return cmd.Root().GenPowerShellCompletion(out) } return cmd.Root().GenPowerShellCompletionWithDesc(out) }, } if haveNoDescFlag { powershell.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } completionCmd.AddCommand(bash, zsh, fish, powershell) } func findFlag(cmd *Command, name string) *pflag.Flag { flagSet := cmd.Flags() if len(name) == 1 { // First convert the short flag into a long flag // as the cmd.Flag() search only accepts long flags if short := flagSet.ShorthandLookup(name); short != nil { name = short.Name } else { set := cmd.InheritedFlags() if short = set.ShorthandLookup(name); short != nil { name = short.Name } else { return nil } } } return cmd.Flag(name) } // CompDebug prints the specified string to the same file as where the // completion script prints its logs. // Note that completion printouts should never be on stdout as they would // be wrongly interpreted as actual completion choices by the completion script. func CompDebug(msg string, printToStdErr bool) { msg = fmt.Sprintf("[Debug] %s", msg) // Such logs are only printed when the user has set the environment // variable BASH_COMP_DEBUG_FILE to the path of some file to be used. if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" { f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err == nil { defer f.Close() WriteStringAndCheck(f, msg) } } if printToStdErr { // Must print to stderr for this not to be read by the completion script. fmt.Fprint(os.Stderr, msg) } } // CompDebugln prints the specified string with a newline at the end // to the same file as where the completion script prints its logs. // Such logs are only printed when the user has set the environment // variable BASH_COMP_DEBUG_FILE to the path of some file to be used. func CompDebugln(msg string, printToStdErr bool) { CompDebug(fmt.Sprintf("%s\n", msg), printToStdErr) } // CompError prints the specified completion message to stderr. func CompError(msg string) { msg = fmt.Sprintf("[Error] %s", msg) CompDebug(msg, true) } // CompErrorln prints the specified completion message to stderr with a newline at the end. func CompErrorln(msg string) { CompError(fmt.Sprintf("%s\n", msg)) } cobra-1.3.0/completions_test.go000066400000000000000000002237651415616037300165500ustar00rootroot00000000000000package cobra import ( "bytes" "context" "strings" "testing" ) func validArgsFunc(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { if len(args) != 0 { return nil, ShellCompDirectiveNoFileComp } var completions []string for _, comp := range []string{"one\tThe first", "two\tThe second"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveDefault } func validArgsFunc2(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { if len(args) != 0 { return nil, ShellCompDirectiveNoFileComp } var completions []string for _, comp := range []string{"three\tThe third", "four\tThe fourth"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveDefault } func TestCmdNameCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd1 := &Command{ Use: "firstChild", Short: "First command", Run: emptyRun, } childCmd2 := &Command{ Use: "secondChild", Run: emptyRun, } hiddenCmd := &Command{ Use: "testHidden", Hidden: true, // Not completed Run: emptyRun, } deprecatedCmd := &Command{ Use: "testDeprecated", Deprecated: "deprecated", // Not completed Run: emptyRun, } aliasedCmd := &Command{ Use: "aliased", Short: "A command with aliases", Aliases: []string{"testAlias", "testSynonym"}, // Not completed Run: emptyRun, } rootCmd.AddCommand(childCmd1, childCmd2, hiddenCmd, deprecatedCmd, aliasedCmd) // Test that sub-command names are completed output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "aliased", "completion", "firstChild", "help", "secondChild", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are completed with prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "s") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "secondChild", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that even with no valid sub-command matches, hidden, deprecated and // aliases are not completed output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "test") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are completed with description output, err = executeCommand(rootCmd, ShellCompRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "aliased\tA command with aliases", "completion\tGenerate the autocompletion script for the specified shell", "firstChild\tFirst command", "help\tHelp about any command", "secondChild", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestNoCmdNameCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } rootCmd.Flags().String("localroot", "", "local root flag") childCmd1 := &Command{ Use: "childCmd1", Short: "First command", Args: MinimumNArgs(0), Run: emptyRun, } rootCmd.AddCommand(childCmd1) childCmd1.PersistentFlags().StringP("persistent", "p", "", "persistent flag") persistentFlag := childCmd1.PersistentFlags().Lookup("persistent") childCmd1.Flags().StringP("nonPersistent", "n", "", "non-persistent flag") nonPersistentFlag := childCmd1.Flags().Lookup("nonPersistent") childCmd2 := &Command{ Use: "childCmd2", Run: emptyRun, } childCmd1.AddCommand(childCmd2) // Test that sub-command names are not completed if there is an argument already output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "arg1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are not completed if a local non-persistent flag is present output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--nonPersistent", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command nonPersistentFlag.Changed = false expected = strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are completed if a local non-persistent flag is present and TraverseChildren is set to true // set TraverseChildren to true on the root cmd rootCmd.TraverseChildren = true output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset TraverseChildren for next command rootCmd.TraverseChildren = false expected = strings.Join([]string{ "childCmd1", "completion", "help", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names from a child cmd are completed if a local non-persistent flag is present // and TraverseChildren is set to true on the root cmd rootCmd.TraverseChildren = true output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "--nonPersistent", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset TraverseChildren for next command rootCmd.TraverseChildren = false // Reset the flag for the next command nonPersistentFlag.Changed = false expected = strings.Join([]string{ "childCmd2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that we don't use Traverse when we shouldn't. // This command should not return a completion since the command line is invalid without TraverseChildren. output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are not completed if a local non-persistent short flag is present output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-n", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command nonPersistentFlag.Changed = false expected = strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are completed with a persistent flag output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--persistent", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command persistentFlag.Changed = false expected = strings.Join([]string{ "childCmd2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that sub-command names are completed with a persistent short flag output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-p", "value", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command persistentFlag.Changed = false expected = strings.Join([]string{ "childCmd2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgs: []string{"one", "two", "three"}, Args: MinimumNArgs(1), } // Test that validArgs are completed output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", "three", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that validArgs are completed with prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "o") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "one", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that validArgs don't repeat output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "one", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsAndCmdCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgs: []string{"one", "two"}, Run: emptyRun, } childCmd := &Command{ Use: "thechild", Run: emptyRun, } rootCmd.AddCommand(childCmd) // Test that both sub-commands and validArgs are completed output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "completion", "help", "thechild", "one", "two", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that both sub-commands and validArgs are completed with prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "thechild", "two", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncAndCmdCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgsFunction: validArgsFunc, Run: emptyRun, } childCmd := &Command{ Use: "thechild", Short: "The child command", Run: emptyRun, } rootCmd.AddCommand(childCmd) // Test that both sub-commands and validArgsFunction are completed output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "completion", "help", "thechild", "one", "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that both sub-commands and validArgs are completed with prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "thechild", "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that both sub-commands and validArgs are completed with description output, err = executeCommand(rootCmd, ShellCompRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "thechild\tThe child command", "two\tThe second", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagNameCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "childCmd", Run: emptyRun, } rootCmd.AddCommand(childCmd) rootCmd.Flags().IntP("first", "f", -1, "first flag") rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag") childCmd.Flags().String("subFlag", "", "sub flag") // Test that flag names are not shown if the user has not given the '-' prefix output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "childCmd", "completion", "help", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--first", "-f", "--second", "-s", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed when a prefix is given output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--f") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--first", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed in a sub-cmd output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--second", "-s", "--subFlag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagNameCompletionInGoWithDesc(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "childCmd", Short: "first command", Run: emptyRun, } rootCmd.AddCommand(childCmd) rootCmd.Flags().IntP("first", "f", -1, "first flag\nlonger description for flag") rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag") childCmd.Flags().String("subFlag", "", "sub flag") // Test that flag names are not shown if the user has not given the '-' prefix output, err := executeCommand(rootCmd, ShellCompRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "childCmd\tfirst command", "completion\tGenerate the autocompletion script for the specified shell", "help\tHelp about any command", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed output, err = executeCommand(rootCmd, ShellCompRequestCmd, "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--first\tfirst flag", "-f\tfirst flag", "--second\tsecond flag", "-s\tsecond flag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed when a prefix is given output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--f") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--first\tfirst flag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are completed in a sub-cmd output, err = executeCommand(rootCmd, ShellCompRequestCmd, "childCmd", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--second\tsecond flag", "-s\tsecond flag", "--subFlag\tsub flag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagNameCompletionRepeat(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "childCmd", Short: "first command", Run: emptyRun, } rootCmd.AddCommand(childCmd) rootCmd.Flags().IntP("first", "f", -1, "first flag") firstFlag := rootCmd.Flags().Lookup("first") rootCmd.Flags().BoolP("second", "s", false, "second flag") secondFlag := rootCmd.Flags().Lookup("second") rootCmd.Flags().StringArrayP("array", "a", nil, "array flag") arrayFlag := rootCmd.Flags().Lookup("array") rootCmd.Flags().IntSliceP("slice", "l", nil, "slice flag") sliceFlag := rootCmd.Flags().Lookup("slice") rootCmd.Flags().BoolSliceP("bslice", "b", nil, "bool slice flag") bsliceFlag := rootCmd.Flags().Lookup("bslice") // Test that flag names are not repeated unless they are an array or slice output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command firstFlag.Changed = false expected := strings.Join([]string{ "--array", "--bslice", "--second", "--slice", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are not repeated unless they are an array or slice output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--second=false", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command firstFlag.Changed = false secondFlag.Changed = false expected = strings.Join([]string{ "--array", "--bslice", "--slice", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are not repeated unless they are an array or slice output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--slice", "1", "--slice=2", "--array", "val", "--bslice", "true", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command sliceFlag.Changed = false arrayFlag.Changed = false bsliceFlag.Changed = false expected = strings.Join([]string{ "--array", "--bslice", "--first", "--second", "--slice", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are not repeated unless they are an array or slice, using shortname output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command sliceFlag.Changed = false arrayFlag.Changed = false expected = strings.Join([]string{ "--array", "-a", "--bslice", "-b", "--first", "-f", "--second", "-s", "--slice", "-l", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that flag names are not repeated unless they are an array or slice, using shortname with prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-a") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command sliceFlag.Changed = false arrayFlag.Changed = false expected = strings.Join([]string{ "-a", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestRequiredFlagNameCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgs: []string{"realArg"}, Run: emptyRun, } childCmd := &Command{ Use: "childCmd", ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"subArg"}, ShellCompDirectiveNoFileComp }, Run: emptyRun, } rootCmd.AddCommand(childCmd) rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag") assertNoErr(t, rootCmd.MarkFlagRequired("requiredFlag")) requiredFlag := rootCmd.Flags().Lookup("requiredFlag") rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent") assertNoErr(t, rootCmd.MarkPersistentFlagRequired("requiredPersistent")) requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent") rootCmd.Flags().StringP("release", "R", "", "Release name") childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag") assertNoErr(t, childCmd.MarkFlagRequired("subRequired")) childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag") // Test that a required flag is suggested even without the - prefix output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "childCmd", "completion", "help", "--requiredFlag", "-r", "--requiredPersistent", "-p", "realArg", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that a required flag is suggested without other flags when using the '-' prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--requiredFlag", "-r", "--requiredPersistent", "-p", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that if no required flag matches, the normal flags are suggested output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--relea") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--release", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test required flags for sub-commands output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--requiredPersistent", "-p", "--subRequired", "-s", "subArg", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--requiredPersistent", "-p", "--subRequired", "-s", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "--subNot") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--subNotRequired", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that when a required flag is present, it is not suggested anymore output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command requiredFlag.Changed = false expected = strings.Join([]string{ "--requiredPersistent", "-p", "realArg", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that when a persistent required flag is present, it is not suggested anymore output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredPersistent", "1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flag for the next command requiredPersistent.Changed = false expected = strings.Join([]string{ "childCmd", "completion", "help", "--requiredFlag", "-r", "realArg", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that when all required flags are present, normal completion is done output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "--requiredPersistent", "1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } // Reset the flags for the next command requiredFlag.Changed = false requiredPersistent.Changed = false expected = strings.Join([]string{ "realArg", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagFileExtFilterCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } // No extensions. Should be ignored. rootCmd.Flags().StringP("file", "f", "", "file flag") assertNoErr(t, rootCmd.MarkFlagFilename("file")) // Single extension rootCmd.Flags().StringP("log", "l", "", "log flag") assertNoErr(t, rootCmd.MarkFlagFilename("log", "log")) // Multiple extensions rootCmd.Flags().StringP("yaml", "y", "", "yaml flag") assertNoErr(t, rootCmd.MarkFlagFilename("yaml", "yaml", "yml")) // Directly using annotation rootCmd.Flags().StringP("text", "t", "", "text flag") assertNoErr(t, rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"})) // Test that the completion logic returns the proper info for the completion // script to handle the file filtering output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--file", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--log", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "log", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "yaml", "yml", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml=") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "yaml", "yml", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "yaml", "yml", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y=") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "yaml", "yml", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--text", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "txt", ":8", "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagDirFilterCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } // Filter directories rootCmd.Flags().StringP("dir", "d", "", "dir flag") assertNoErr(t, rootCmd.MarkFlagDirname("dir")) // Filter directories within a directory rootCmd.Flags().StringP("subdir", "s", "", "subdir") assertNoErr(t, rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"})) // Multiple directory specification get ignored rootCmd.Flags().StringP("manydir", "m", "", "manydir") assertNoErr(t, rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"})) // Test that the completion logic returns the proper info for the completion // script to handle the directory filtering output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--dir", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-d", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "themes", ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir=") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "themes", ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "themes", ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s=") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "themes", ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--manydir", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":16", "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncCmdContext(t *testing.T) { validArgsFunc := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { ctx := cmd.Context() if ctx == nil { t.Error("Received nil context in completion func") } else if ctx.Value("testKey") != "123" { t.Error("Received invalid context") } return nil, ShellCompDirectiveDefault } rootCmd := &Command{ Use: "root", Run: emptyRun, } childCmd := &Command{ Use: "childCmd", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(childCmd) //nolint:golint,staticcheck // We can safely use a basic type as key in tests. ctx := context.WithValue(context.Background(), "testKey", "123") // Test completing an empty string on the childCmd _, output, err := executeCommandWithContextC(ctx, rootCmd, ShellCompNoDescRequestCmd, "childCmd", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncSingleCmd(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgsFunction: validArgsFunc, Run: emptyRun, } // Test completing an empty string output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncSingleCmdInvalidArg(t *testing.T) { rootCmd := &Command{ Use: "root", // If we don't specify a value for Args, this test fails. // This is only true for a root command without any subcommands, and is caused // by the fact that the __complete command becomes a subcommand when there should not be one. // The problem is in the implementation of legacyArgs(). Args: MinimumNArgs(1), ValidArgsFunction: validArgsFunc, Run: emptyRun, } // Check completing with wrong number of args output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncChildCmds(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child1Cmd := &Command{ Use: "child1", ValidArgsFunction: validArgsFunc, Run: emptyRun, } child2Cmd := &Command{ Use: "child2", ValidArgsFunction: validArgsFunc2, Run: emptyRun, } rootCmd.AddCommand(child1Cmd, child2Cmd) // Test completion of first sub-command with empty argument output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completion of first sub-command with a prefix to complete output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with wrong number of args output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completion of second sub-command with empty argument output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "three", "four", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "three", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with wrong number of args output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncAliases(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", Aliases: []string{"son", "daughter"}, ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) // Test completion of first sub-command with empty argument output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completion of first sub-command with a prefix to complete output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "daughter", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with wrong number of args output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncInBashScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenBashCompletion(buf)) output := buf.String() check(t, output, "has_completion_function=1") } func TestNoValidArgsFuncInBashScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenBashCompletion(buf)) output := buf.String() checkOmit(t, output, "has_completion_function=1") } func TestCompleteCmdInBashScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenBashCompletion(buf)) output := buf.String() check(t, output, ShellCompNoDescRequestCmd) } func TestCompleteNoDesCmdInZshScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenZshCompletionNoDesc(buf)) output := buf.String() check(t, output, ShellCompNoDescRequestCmd) } func TestCompleteCmdInZshScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenZshCompletion(buf)) output := buf.String() check(t, output, ShellCompRequestCmd) checkOmit(t, output, ShellCompNoDescRequestCmd) } func TestFlagCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { completions := []string{} for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveDefault })) rootCmd.Flags().String("filename", "", "Enter a filename") assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { completions := []string{} for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp })) // Test completing an empty string output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "1", "2", "10", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "1") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "1", "10", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completing an empty string output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "file.yaml", "myfile.json", "file.xml", ":6", "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "f") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "file.yaml", "file.xml", ":6", "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsFuncChildCmdsWithDesc(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child1Cmd := &Command{ Use: "child1", ValidArgsFunction: validArgsFunc, Run: emptyRun, } child2Cmd := &Command{ Use: "child2", ValidArgsFunction: validArgsFunc2, Run: emptyRun, } rootCmd.AddCommand(child1Cmd, child2Cmd) // Test completion of first sub-command with empty argument output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one\tThe first", "two\tThe second", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completion of first sub-command with a prefix to complete output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two\tThe second", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with wrong number of args output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completion of second sub-command with empty argument output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "three\tThe third", "four\tThe fourth", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "three\tThe third", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with wrong number of args output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagCompletionWithNotInterspersedArgs(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{ Use: "child", Run: emptyRun, ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"--validarg", "test"}, ShellCompDirectiveDefault }, } childCmd2 := &Command{ Use: "child2", Run: emptyRun, ValidArgs: []string{"arg1", "arg2"}, } rootCmd.AddCommand(childCmd, childCmd2) childCmd.Flags().Bool("bool", false, "test bool flag") childCmd.Flags().String("string", "", "test string flag") _ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"myval"}, ShellCompDirectiveDefault }) // Test flag completion with no argument output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "--bool\ttest bool flag", "--string\ttest string flag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that no flags are completed after the -- arg output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that no flags are completed after the -- arg with a flag set output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--bool", "--", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // set Interspersed to false which means that no flags should be completed after the first arg childCmd.Flags().SetInterspersed(false) // Test that no flags are completed after the first arg output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that no flags are completed after the fist arg with a flag set output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "t", "arg", "--") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that args are still completed after -- output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that args are still completed even if flagname with ValidArgsFunction exists output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--string", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that args are still completed even if flagname with ValidArgsFunction exists output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "--", "a") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "arg1", "arg2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that --validarg is not parsed as flag after -- output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that --validarg is not parsed as flag after an arg output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--validarg", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "test", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that --validarg is added to args for the ValidArgsFunction childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return args, ShellCompDirectiveDefault } output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check that --validarg is added to args for the ValidArgsFunction and toComplete is also set correctly childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return append(args, toComplete), ShellCompDirectiveDefault } output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "--toComp=ab") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "--validarg", "--toComp=ab", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagCompletionWorksRootCommandAddedAfterFlags(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} childCmd := &Command{ Use: "child", Run: emptyRun, ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"--validarg", "test"}, ShellCompDirectiveDefault }, } childCmd.Flags().Bool("bool", false, "test bool flag") childCmd.Flags().String("string", "", "test string flag") _ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"myval"}, ShellCompDirectiveDefault }) // Important: This is a test for https://github.com/spf13/cobra/issues/1437 // Only add the subcommand after RegisterFlagCompletionFunc was called, do not change this order! rootCmd.AddCommand(childCmd) // Test that flag completion works for the subcmd output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "myval", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestFlagCompletionInGoWithDesc(t *testing.T) { rootCmd := &Command{ Use: "root", Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { completions := []string{} for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveDefault })) rootCmd.Flags().String("filename", "", "Enter a filename") assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { completions := []string{} for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { if strings.HasPrefix(comp, toComplete) { completions = append(completions, comp) } } return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp })) // Test completing an empty string output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "1\tThe first", "2\tThe second", "10\tThe tenth", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "1\tThe first", "10\tThe tenth", ":0", "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test completing an empty string output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format", ":6", "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "file.yaml\tYAML format", "file.xml\tXML format", ":6", "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestValidArgsNotValidArgsFunc(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgs: []string{"one", "two"}, ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"three", "four"}, ShellCompDirectiveNoFileComp }, Run: emptyRun, } // Test that if both ValidArgs and ValidArgsFunction are present // only ValidArgs is considered output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Check completing with a prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestArgAliasesCompletionInGo(t *testing.T) { rootCmd := &Command{ Use: "root", Args: OnlyValidArgs, ValidArgs: []string{"one", "two", "three"}, ArgAliases: []string{"un", "deux", "trois"}, Run: emptyRun, } // Test that argaliases are not completed when there are validargs that match output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "one", "two", "three", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that argaliases are not completed when there are validargs that match using a prefix output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "two", "three", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that argaliases are completed when there are no validargs that match output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "tr") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "trois", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestCompleteHelp(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child1Cmd := &Command{ Use: "child1", Run: emptyRun, } child2Cmd := &Command{ Use: "child2", Run: emptyRun, } rootCmd.AddCommand(child1Cmd, child2Cmd) child3Cmd := &Command{ Use: "child3", Run: emptyRun, } child1Cmd.AddCommand(child3Cmd) // Test that completion includes the help command output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "child1", "child2", "completion", "help", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test sub-commands are completed on first level of help command output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "child1", "child2", "completion", "help", // " help help" is a valid command, so should be completed ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test sub-commands are completed on first level of help command output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "child1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "child3", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func removeCompCmd(rootCmd *Command) { // Remove completion command for the next test for _, cmd := range rootCmd.commands { if cmd.Name() == compCmdName { rootCmd.RemoveCommand(cmd) return } } } func TestDefaultCompletionCmd(t *testing.T) { rootCmd := &Command{ Use: "root", Args: NoArgs, Run: emptyRun, } // Test that no completion command is created if there are not other sub-commands assertNoErr(t, rootCmd.Execute()) for _, cmd := range rootCmd.commands { if cmd.Name() == compCmdName { t.Errorf("Should not have a 'completion' command when there are no other sub-commands of root") break } } subCmd := &Command{ Use: "sub", Run: emptyRun, } rootCmd.AddCommand(subCmd) // Test that a completion command is created if there are other sub-commands found := false assertNoErr(t, rootCmd.Execute()) for _, cmd := range rootCmd.commands { if cmd.Name() == compCmdName { found = true break } } if !found { t.Errorf("Should have a 'completion' command when there are other sub-commands of root") } // Remove completion command for the next test removeCompCmd(rootCmd) // Test that the default completion command can be disabled rootCmd.CompletionOptions.DisableDefaultCmd = true assertNoErr(t, rootCmd.Execute()) for _, cmd := range rootCmd.commands { if cmd.Name() == compCmdName { t.Errorf("Should not have a 'completion' command when the feature is disabled") break } } // Re-enable for next test rootCmd.CompletionOptions.DisableDefaultCmd = false // Test that completion descriptions are enabled by default output, err := executeCommand(rootCmd, compCmdName, "zsh") if err != nil { t.Errorf("Unexpected error: %v", err) } check(t, output, ShellCompRequestCmd) checkOmit(t, output, ShellCompNoDescRequestCmd) // Remove completion command for the next test removeCompCmd(rootCmd) // Test that completion descriptions can be disabled completely rootCmd.CompletionOptions.DisableDescriptions = true output, err = executeCommand(rootCmd, compCmdName, "zsh") if err != nil { t.Errorf("Unexpected error: %v", err) } check(t, output, ShellCompNoDescRequestCmd) // Re-enable for next test rootCmd.CompletionOptions.DisableDescriptions = false // Remove completion command for the next test removeCompCmd(rootCmd) var compCmd *Command // Test that the --no-descriptions flag is present on all shells assertNoErr(t, rootCmd.Execute()) for _, shell := range []string{"bash", "fish", "powershell", "zsh"} { if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil { t.Errorf("Unexpected error: %v", err) } if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag == nil { t.Errorf("Missing --%s flag for %s shell", compCmdNoDescFlagName, shell) } } // Remove completion command for the next test removeCompCmd(rootCmd) // Test that the '--no-descriptions' flag can be disabled rootCmd.CompletionOptions.DisableNoDescFlag = true assertNoErr(t, rootCmd.Execute()) for _, shell := range []string{"fish", "zsh", "bash", "powershell"} { if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil { t.Errorf("Unexpected error: %v", err) } if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil { t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell) } } // Re-enable for next test rootCmd.CompletionOptions.DisableNoDescFlag = false // Remove completion command for the next test removeCompCmd(rootCmd) // Test that the '--no-descriptions' flag is disabled when descriptions are disabled rootCmd.CompletionOptions.DisableDescriptions = true assertNoErr(t, rootCmd.Execute()) for _, shell := range []string{"fish", "zsh", "bash", "powershell"} { if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil { t.Errorf("Unexpected error: %v", err) } if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil { t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell) } } // Re-enable for next test rootCmd.CompletionOptions.DisableDescriptions = false // Remove completion command for the next test removeCompCmd(rootCmd) // Test that the 'completion' command can be hidden rootCmd.CompletionOptions.HiddenDefaultCmd = true assertNoErr(t, rootCmd.Execute()) compCmd, _, err = rootCmd.Find([]string{compCmdName}) if err != nil { t.Errorf("Unexpected error: %v", err) } if compCmd.Hidden == false { t.Error("Default 'completion' command should be hidden but it is not") } // Re-enable for next test rootCmd.CompletionOptions.HiddenDefaultCmd = false // Remove completion command for the next test removeCompCmd(rootCmd) } func TestCompleteCompletion(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} subCmd := &Command{ Use: "sub", Run: emptyRun, } rootCmd.AddCommand(subCmd) // Test sub-commands of the completion command output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "bash", "fish", "powershell", "zsh", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test there are no completions for the sub-commands of the completion command var compCmd *Command for _, cmd := range rootCmd.Commands() { if cmd.Name() == compCmdName { compCmd = cmd break } } for _, shell := range compCmd.Commands() { output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, compCmdName, shell.Name(), "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } } func TestMultipleShorthandFlagCompletion(t *testing.T) { rootCmd := &Command{ Use: "root", ValidArgs: []string{"foo", "bar"}, Run: emptyRun, } f := rootCmd.Flags() f.BoolP("short", "s", false, "short flag 1") f.BoolP("short2", "d", false, "short flag 2") f.StringP("short3", "f", "", "short flag 3") _ = rootCmd.RegisterFlagCompletionFunc("short3", func(*Command, []string, string) ([]string, ShellCompDirective) { return []string{"works"}, ShellCompDirectiveNoFileComp }) // Test that a single shorthand flag works output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "foo", "bar", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that multiple boolean shorthand flags work output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sd", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "foo", "bar", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that multiple boolean + string shorthand flags work output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "works", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that multiple boolean + string with equal sign shorthand flags work output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "works", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that multiple boolean + string with equal sign with value shorthand flags work output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=abc", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "foo", "bar", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestCompleteWithDisableFlagParsing(t *testing.T) { flagValidArgs := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"--flag", "-f"}, ShellCompDirectiveNoFileComp } rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} childCmd := &Command{ Use: "child", Run: emptyRun, DisableFlagParsing: true, ValidArgsFunction: flagValidArgs, } rootCmd.AddCommand(childCmd) rootCmd.PersistentFlags().StringP("persistent", "p", "", "persistent flag") childCmd.Flags().StringP("nonPersistent", "n", "", "non-persistent flag") // Test that when DisableFlagParsing==true, ValidArgsFunction is called to complete flag names, // after Cobra tried to complete the flags it knows about. childCmd.DisableFlagParsing = true output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "--persistent", "-p", "--nonPersistent", "-n", "--flag", "-f", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Test that when DisableFlagParsing==false, Cobra completes the flags itself and ValidArgsFunction is not called childCmd.DisableFlagParsing = false output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-") if err != nil { t.Errorf("Unexpected error: %v", err) } // Cobra was not told of any flags, so it returns nothing expected = strings.Join([]string{ "--persistent", "-p", "--nonPersistent", "-n", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } func TestCompleteWithRootAndLegacyArgs(t *testing.T) { // Test a lonely root command which uses legacyArgs(). In such a case, the root // command should accept any number of arguments and completion should behave accordingly. rootCmd := &Command{ Use: "root", Args: nil, // Args must be nil to trigger the legacyArgs() function Run: emptyRun, ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { return []string{"arg1", "arg2"}, ShellCompDirectiveNoFileComp }, } // Make sure the first arg is completed output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected := strings.Join([]string{ "arg1", "arg2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } // Make sure the completion of arguments continues output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "arg1", "") if err != nil { t.Errorf("Unexpected error: %v", err) } expected = strings.Join([]string{ "arg1", "arg2", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") if output != expected { t.Errorf("expected: %q, got: %q", expected, output) } } cobra-1.3.0/doc/000077500000000000000000000000001415616037300133545ustar00rootroot00000000000000cobra-1.3.0/doc/README.md000066400000000000000000000005311415616037300146320ustar00rootroot00000000000000# Documentation generation - [Man page docs](./man_docs.md) - [Markdown docs](./md_docs.md) - [Rest docs](./rest_docs.md) - [Yaml docs](./yaml_docs.md) ## Options ### `DisableAutoGenTag` You may set `cmd.DisableAutoGenTag = true` to _entirely_ remove the auto generated string "Auto generated by spf13/cobra..." from any documentation source. cobra-1.3.0/doc/cmd_test.go000066400000000000000000000055721415616037300155160ustar00rootroot00000000000000package doc import ( "strings" "testing" "github.com/spf13/cobra" ) func emptyRun(*cobra.Command, []string) {} func init() { rootCmd.PersistentFlags().StringP("rootflag", "r", "two", "") rootCmd.PersistentFlags().StringP("strtwo", "t", "two", "help message for parent flag strtwo") echoCmd.PersistentFlags().StringP("strone", "s", "one", "help message for flag strone") echoCmd.PersistentFlags().BoolP("persistentbool", "p", false, "help message for flag persistentbool") echoCmd.Flags().IntP("intone", "i", 123, "help message for flag intone") echoCmd.Flags().BoolP("boolone", "b", true, "help message for flag boolone") timesCmd.PersistentFlags().StringP("strtwo", "t", "2", "help message for child flag strtwo") timesCmd.Flags().IntP("inttwo", "j", 234, "help message for flag inttwo") timesCmd.Flags().BoolP("booltwo", "c", false, "help message for flag booltwo") printCmd.PersistentFlags().StringP("strthree", "s", "three", "help message for flag strthree") printCmd.Flags().IntP("intthree", "i", 345, "help message for flag intthree") printCmd.Flags().BoolP("boolthree", "b", true, "help message for flag boolthree") echoCmd.AddCommand(timesCmd, echoSubCmd, deprecatedCmd) rootCmd.AddCommand(printCmd, echoCmd, dummyCmd) } var rootCmd = &cobra.Command{ Use: "root", Short: "Root short description", Long: "Root long description", Run: emptyRun, } var echoCmd = &cobra.Command{ Use: "echo [string to echo]", Aliases: []string{"say"}, Short: "Echo anything to the screen", Long: "an utterly useless command for testing", Example: "Just run cobra-test echo", } var echoSubCmd = &cobra.Command{ Use: "echosub [string to print]", Short: "second sub command for echo", Long: "an absolutely utterly useless command for testing gendocs!.", Run: emptyRun, } var timesCmd = &cobra.Command{ Use: "times [# times] [string to echo]", SuggestFor: []string{"counts"}, Short: "Echo anything to the screen more times", Long: `a slightly useless command for testing.`, Run: emptyRun, } var deprecatedCmd = &cobra.Command{ Use: "deprecated [can't do anything here]", Short: "A command which is deprecated", Long: `an absolutely utterly useless command for testing deprecation!.`, Deprecated: "Please use echo instead", } var printCmd = &cobra.Command{ Use: "print [string to print]", Short: "Print anything to the screen", Long: `an absolutely utterly useless command for testing.`, } var dummyCmd = &cobra.Command{ Use: "dummy [action]", Short: "Performs a dummy action", } func checkStringContains(t *testing.T, got, expected string) { if !strings.Contains(got, expected) { t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) } } func checkStringOmits(t *testing.T, got, expected string) { if strings.Contains(got, expected) { t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) } } cobra-1.3.0/doc/man_docs.go000066400000000000000000000163271415616037300154770ustar00rootroot00000000000000// Copyright 2015 Red Hat 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 doc import ( "bytes" "fmt" "io" "os" "path/filepath" "sort" "strconv" "strings" "time" "github.com/cpuguy83/go-md2man/v2/md2man" "github.com/spf13/cobra" "github.com/spf13/pflag" ) // GenManTree will generate a man page for this command and all descendants // in the directory given. The header may be nil. This function may not work // correctly if your command names have `-` in them. If you have `cmd` with two // subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third` // it is undefined which help output will be in the file `cmd-sub-third.1`. func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return GenManTreeFromOpts(cmd, GenManTreeOptions{ Header: header, Path: dir, CommandSeparator: "-", }) } // GenManTreeFromOpts generates a man page for the command and all descendants. // The pages are written to the opts.Path directory. func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { header := opts.Header if header == nil { header = &GenManHeader{} } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenManTreeFromOpts(c, opts); err != nil { return err } } section := "1" if header.Section != "" { section = header.Section } separator := "_" if opts.CommandSeparator != "" { separator = opts.CommandSeparator } basename := strings.Replace(cmd.CommandPath(), " ", separator, -1) filename := filepath.Join(opts.Path, basename+"."+section) f, err := os.Create(filename) if err != nil { return err } defer f.Close() headerCopy := *header return GenMan(cmd, &headerCopy, f) } // GenManTreeOptions is the options for generating the man pages. // Used only in GenManTreeFromOpts. type GenManTreeOptions struct { Header *GenManHeader Path string CommandSeparator string } // GenManHeader is a lot like the .TH header at the start of man pages. These // include the title, section, date, source, and manual. We will use the // current time if Date is unset and will use "Auto generated by spf13/cobra" // if the Source is unset. type GenManHeader struct { Title string Section string Date *time.Time date string Source string Manual string } // GenMan will generate a man page for the given command and write it to // w. The header argument may be nil, however obviously w may not. func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { if header == nil { header = &GenManHeader{} } if err := fillHeader(header, cmd.CommandPath(), cmd.DisableAutoGenTag); err != nil { return err } b := genMan(cmd, header) _, err := w.Write(md2man.Render(b)) return err } func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error { if header.Title == "" { header.Title = strings.ToUpper(strings.Replace(name, " ", "\\-", -1)) } if header.Section == "" { header.Section = "1" } if header.Date == nil { now := time.Now() if epoch := os.Getenv("SOURCE_DATE_EPOCH"); epoch != "" { unixEpoch, err := strconv.ParseInt(epoch, 10, 64) if err != nil { return fmt.Errorf("invalid SOURCE_DATE_EPOCH: %v", err) } now = time.Unix(unixEpoch, 0) } header.Date = &now } header.date = (*header.Date).Format("Jan 2006") if header.Source == "" && !disableAutoGen { header.Source = "Auto generated by spf13/cobra" } return nil } func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) { description := cmd.Long if len(description) == 0 { description = cmd.Short } cobra.WriteStringAndCheck(buf, fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s" # NAME `, header.Title, header.Section, header.date, header.Source, header.Manual)) cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short)) cobra.WriteStringAndCheck(buf, "# SYNOPSIS\n") cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine())) cobra.WriteStringAndCheck(buf, "# DESCRIPTION\n") cobra.WriteStringAndCheck(buf, description+"\n\n") } func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) { flags.VisitAll(func(flag *pflag.Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { return } format := "" if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { format = fmt.Sprintf("**-%s**, **--%s**", flag.Shorthand, flag.Name) } else { format = fmt.Sprintf("**--%s**", flag.Name) } if len(flag.NoOptDefVal) > 0 { format += "[" } if flag.Value.Type() == "string" { // put quotes on the value format += "=%q" } else { format += "=%s" } if len(flag.NoOptDefVal) > 0 { format += "]" } format += "\n\t%s\n\n" cobra.WriteStringAndCheck(buf, fmt.Sprintf(format, flag.DefValue, flag.Usage)) }) } func manPrintOptions(buf io.StringWriter, command *cobra.Command) { flags := command.NonInheritedFlags() if flags.HasAvailableFlags() { cobra.WriteStringAndCheck(buf, "# OPTIONS\n") manPrintFlags(buf, flags) cobra.WriteStringAndCheck(buf, "\n") } flags = command.InheritedFlags() if flags.HasAvailableFlags() { cobra.WriteStringAndCheck(buf, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") manPrintFlags(buf, flags) cobra.WriteStringAndCheck(buf, "\n") } } func genMan(cmd *cobra.Command, header *GenManHeader) []byte { cmd.InitDefaultHelpCmd() cmd.InitDefaultHelpFlag() // something like `rootcmd-subcmd1-subcmd2` dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1) buf := new(bytes.Buffer) manPreamble(buf, header, cmd, dashCommandName) manPrintOptions(buf, cmd) if len(cmd.Example) > 0 { buf.WriteString("# EXAMPLE\n") buf.WriteString(fmt.Sprintf("```\n%s\n```\n", cmd.Example)) } if hasSeeAlso(cmd) { buf.WriteString("# SEE ALSO\n") seealsos := make([]string, 0) if cmd.HasParent() { parentPath := cmd.Parent().CommandPath() dashParentPath := strings.Replace(parentPath, " ", "-", -1) seealso := fmt.Sprintf("**%s(%s)**", dashParentPath, header.Section) seealsos = append(seealsos, seealso) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag } }) } children := cmd.Commands() sort.Sort(byName(children)) for _, c := range children { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) seealsos = append(seealsos, seealso) } buf.WriteString(strings.Join(seealsos, ", ") + "\n") } if !cmd.DisableAutoGenTag { buf.WriteString(fmt.Sprintf("# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006"))) } return buf.Bytes() } cobra-1.3.0/doc/man_docs.md000066400000000000000000000010071415616037300154570ustar00rootroot00000000000000# Generating Man Pages For Your Own cobra.Command Generating man pages from a cobra command is incredibly easy. An example is as follows: ```go package main import ( "log" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func main() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } header := &doc.GenManHeader{ Title: "MINE", Section: "3", } err := doc.GenManTree(cmd, header, "/tmp") if err != nil { log.Fatal(err) } } ``` That will get you a man page `/tmp/test.3` cobra-1.3.0/doc/man_docs_test.go000066400000000000000000000137421415616037300165340ustar00rootroot00000000000000package doc import ( "bufio" "bytes" "fmt" "io/ioutil" "os" "path/filepath" "strings" "testing" "github.com/spf13/cobra" ) func assertNoErr(t *testing.T, e error) { if e != nil { t.Error(e) } } func translate(in string) string { return strings.Replace(in, "-", "\\-", -1) } func TestGenManDoc(t *testing.T) { header := &GenManHeader{ Title: "Project", Section: "2", } // We generate on a subcommand so we have both subcommands and parents buf := new(bytes.Buffer) if err := GenMan(echoCmd, header, buf); err != nil { t.Fatal(err) } output := buf.String() // Make sure parent has - in CommandPath() in SEE ALSO: parentPath := echoCmd.Parent().CommandPath() dashParentPath := strings.Replace(parentPath, " ", "-", -1) expected := translate(dashParentPath) expected = expected + "(" + header.Section + ")" checkStringContains(t, output, expected) checkStringContains(t, output, translate(echoCmd.Name())) checkStringContains(t, output, translate(echoCmd.Name())) checkStringContains(t, output, "boolone") checkStringContains(t, output, "rootflag") checkStringContains(t, output, translate(rootCmd.Name())) checkStringContains(t, output, translate(echoSubCmd.Name())) checkStringOmits(t, output, translate(deprecatedCmd.Name())) checkStringContains(t, output, translate("Auto generated")) } func TestGenManNoHiddenParents(t *testing.T) { header := &GenManHeader{ Title: "Project", Section: "2", } // We generate on a subcommand so we have both subcommands and parents for _, name := range []string{"rootflag", "strtwo"} { f := rootCmd.PersistentFlags().Lookup(name) f.Hidden = true defer func() { f.Hidden = false }() } buf := new(bytes.Buffer) if err := GenMan(echoCmd, header, buf); err != nil { t.Fatal(err) } output := buf.String() // Make sure parent has - in CommandPath() in SEE ALSO: parentPath := echoCmd.Parent().CommandPath() dashParentPath := strings.Replace(parentPath, " ", "-", -1) expected := translate(dashParentPath) expected = expected + "(" + header.Section + ")" checkStringContains(t, output, expected) checkStringContains(t, output, translate(echoCmd.Name())) checkStringContains(t, output, translate(echoCmd.Name())) checkStringContains(t, output, "boolone") checkStringOmits(t, output, "rootflag") checkStringContains(t, output, translate(rootCmd.Name())) checkStringContains(t, output, translate(echoSubCmd.Name())) checkStringOmits(t, output, translate(deprecatedCmd.Name())) checkStringContains(t, output, translate("Auto generated")) checkStringOmits(t, output, "OPTIONS INHERITED FROM PARENT COMMANDS") } func TestGenManNoGenTag(t *testing.T) { echoCmd.DisableAutoGenTag = true defer func() { echoCmd.DisableAutoGenTag = false }() header := &GenManHeader{ Title: "Project", Section: "2", } // We generate on a subcommand so we have both subcommands and parents buf := new(bytes.Buffer) if err := GenMan(echoCmd, header, buf); err != nil { t.Fatal(err) } output := buf.String() unexpected := translate("#HISTORY") checkStringOmits(t, output, unexpected) unexpected = translate("Auto generated by spf13/cobra") checkStringOmits(t, output, unexpected) } func TestGenManSeeAlso(t *testing.T) { rootCmd := &cobra.Command{Use: "root", Run: emptyRun} aCmd := &cobra.Command{Use: "aaa", Run: emptyRun, Hidden: true} // #229 bCmd := &cobra.Command{Use: "bbb", Run: emptyRun} cCmd := &cobra.Command{Use: "ccc", Run: emptyRun} rootCmd.AddCommand(aCmd, bCmd, cCmd) buf := new(bytes.Buffer) header := &GenManHeader{} if err := GenMan(rootCmd, header, buf); err != nil { t.Fatal(err) } scanner := bufio.NewScanner(buf) if err := assertLineFound(scanner, ".SH SEE ALSO"); err != nil { t.Fatalf("Couldn't find SEE ALSO section header: %v", err) } if err := assertNextLineEquals(scanner, ".PP"); err != nil { t.Fatalf("First line after SEE ALSO wasn't break-indent: %v", err) } if err := assertNextLineEquals(scanner, `\fBroot-bbb(1)\fP, \fBroot-ccc(1)\fP`); err != nil { t.Fatalf("Second line after SEE ALSO wasn't correct: %v", err) } } func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { c := &cobra.Command{} c.Flags().StringP("foo", "f", "default", "Foo flag") assertNoErr(t, c.Flags().MarkShorthandDeprecated("foo", "don't use it no more")) buf := new(bytes.Buffer) manPrintFlags(buf, c.Flags()) got := buf.String() expected := "**--foo**=\"default\"\n\tFoo flag\n\n" if got != expected { t.Errorf("Expected %v, got %v", expected, got) } } func TestGenManTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} header := &GenManHeader{Section: "2"} tmpdir, err := ioutil.TempDir("", "test-gen-man-tree") if err != nil { t.Fatalf("Failed to create tmpdir: %s", err.Error()) } defer os.RemoveAll(tmpdir) if err := GenManTree(c, header, tmpdir); err != nil { t.Fatalf("GenManTree failed: %s", err.Error()) } if _, err := os.Stat(filepath.Join(tmpdir, "do.2")); err != nil { t.Fatalf("Expected file 'do.2' to exist") } if header.Title != "" { t.Fatalf("Expected header.Title to be unmodified") } } func assertLineFound(scanner *bufio.Scanner, expectedLine string) error { for scanner.Scan() { line := scanner.Text() if line == expectedLine { return nil } } if err := scanner.Err(); err != nil { return fmt.Errorf("scan failed: %s", err) } return fmt.Errorf("hit EOF before finding %v", expectedLine) } func assertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error { if scanner.Scan() { line := scanner.Text() if line == expectedLine { return nil } return fmt.Errorf("got %v, not %v", line, expectedLine) } if err := scanner.Err(); err != nil { return fmt.Errorf("scan failed: %v", err) } return fmt.Errorf("hit EOF before finding %v", expectedLine) } func BenchmarkGenManToFile(b *testing.B) { file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() b.ResetTimer() for i := 0; i < b.N; i++ { if err := GenMan(rootCmd, nil, file); err != nil { b.Fatal(err) } } } cobra-1.3.0/doc/man_examples_test.go000066400000000000000000000011141415616037300174100ustar00rootroot00000000000000package doc_test import ( "bytes" "fmt" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func ExampleGenManTree() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } header := &doc.GenManHeader{ Title: "MINE", Section: "3", } cobra.CheckErr(doc.GenManTree(cmd, header, "/tmp")) } func ExampleGenMan() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } header := &doc.GenManHeader{ Title: "MINE", Section: "3", } out := new(bytes.Buffer) cobra.CheckErr(doc.GenMan(cmd, header, out)) fmt.Print(out.String()) } cobra-1.3.0/doc/md_docs.go000066400000000000000000000110421415616037300153110ustar00rootroot00000000000000//Copyright 2015 Red Hat 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 doc import ( "bytes" "fmt" "io" "os" "path/filepath" "sort" "strings" "time" "github.com/spf13/cobra" ) func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) if flags.HasAvailableFlags() { buf.WriteString("### Options\n\n```\n") flags.PrintDefaults() buf.WriteString("```\n\n") } parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) if parentFlags.HasAvailableFlags() { buf.WriteString("### Options inherited from parent commands\n\n```\n") parentFlags.PrintDefaults() buf.WriteString("```\n\n") } return nil } // GenMarkdown creates markdown output. func GenMarkdown(cmd *cobra.Command, w io.Writer) error { return GenMarkdownCustom(cmd, w, func(s string) string { return s }) } // GenMarkdownCustom creates custom markdown output. func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { cmd.InitDefaultHelpCmd() cmd.InitDefaultHelpFlag() buf := new(bytes.Buffer) name := cmd.CommandPath() buf.WriteString("## " + name + "\n\n") buf.WriteString(cmd.Short + "\n\n") if len(cmd.Long) > 0 { buf.WriteString("### Synopsis\n\n") buf.WriteString(cmd.Long + "\n\n") } if cmd.Runnable() { buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine())) } if len(cmd.Example) > 0 { buf.WriteString("### Examples\n\n") buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example)) } if err := printOptions(buf, cmd, name); err != nil { return err } if hasSeeAlso(cmd) { buf.WriteString("### SEE ALSO\n\n") if cmd.HasParent() { parent := cmd.Parent() pname := parent.CommandPath() link := pname + ".md" link = strings.Replace(link, " ", "_", -1) buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short)) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag } }) } children := cmd.Commands() sort.Sort(byName(children)) for _, child := range children { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } cname := name + " " + child.Name() link := cname + ".md" link = strings.Replace(link, " ", "_", -1) buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short)) } buf.WriteString("\n") } if !cmd.DisableAutoGenTag { buf.WriteString("###### Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "\n") } _, err := buf.WriteTo(w) return err } // GenMarkdownTree will generate a markdown page for this command and all // descendants in the directory given. The header may be nil. // This function may not work correctly if your command names have `-` in them. // If you have `cmd` with two subcmds, `sub` and `sub-third`, // and `sub` has a subcommand called `third`, it is undefined which // help output will be in the file `cmd-sub-third.1`. func GenMarkdownTree(cmd *cobra.Command, dir string) error { identity := func(s string) string { return s } emptyStr := func(s string) string { return "" } return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity) } // GenMarkdownTreeCustom is the the same as GenMarkdownTree, but // with custom filePrepender and linkHandler. func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { return err } } basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".md" filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { return err } defer f.Close() if _, err := io.WriteString(f, filePrepender(filename)); err != nil { return err } if err := GenMarkdownCustom(cmd, f, linkHandler); err != nil { return err } return nil } cobra-1.3.0/doc/md_docs.md000066400000000000000000000053701415616037300153130ustar00rootroot00000000000000# Generating Markdown Docs For Your Own cobra.Command Generating Markdown pages from a cobra command is incredibly easy. An example is as follows: ```go package main import ( "log" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func main() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } err := doc.GenMarkdownTree(cmd, "/tmp") if err != nil { log.Fatal(err) } } ``` That will get you a Markdown document `/tmp/test.md` ## Generate markdown docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project ```go package main import ( "log" "io/ioutil" "os" "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra/doc" ) func main() { kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) err := doc.GenMarkdownTree(kubectl, "./") if err != nil { log.Fatal(err) } } ``` This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") ## Generate markdown docs for a single command You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenMarkdown` instead of `GenMarkdownTree` ```go out := new(bytes.Buffer) err := doc.GenMarkdown(cmd, out) if err != nil { log.Fatal(err) } ``` This will write the markdown doc for ONLY "cmd" into the out, buffer. ## Customize the output Both `GenMarkdown` and `GenMarkdownTree` have alternate versions with callbacks to get some control of the output: ```go func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error { //... } ``` ```go func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error { //... } ``` The `filePrepender` will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with [Hugo](http://gohugo.io/): ```go const fmTemplate = `--- date: %s title: "%s" slug: %s url: %s --- ` filePrepender := func(filename string) string { now := time.Now().Format(time.RFC3339) name := filepath.Base(filename) base := strings.TrimSuffix(name, path.Ext(name)) url := "/commands/" + strings.ToLower(base) + "/" return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url) } ``` The `linkHandler` can be used to customize the rendered internal links to the commands, given a filename: ```go linkHandler := func(name string) string { base := strings.TrimSuffix(name, path.Ext(name)) return "/commands/" + strings.ToLower(base) + "/" } ``` cobra-1.3.0/doc/md_docs_test.go000066400000000000000000000057521415616037300163630ustar00rootroot00000000000000package doc import ( "bytes" "io/ioutil" "os" "path/filepath" "testing" "github.com/spf13/cobra" ) func TestGenMdDoc(t *testing.T) { // We generate on subcommand so we have both subcommands and parents. buf := new(bytes.Buffer) if err := GenMarkdown(echoCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, echoCmd.Long) checkStringContains(t, output, echoCmd.Example) checkStringContains(t, output, "boolone") checkStringContains(t, output, "rootflag") checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) checkStringOmits(t, output, deprecatedCmd.Short) checkStringContains(t, output, "Options inherited from parent commands") } func TestGenMdDocWithNoLongOrSynopsis(t *testing.T) { // We generate on subcommand so we have both subcommands and parents. buf := new(bytes.Buffer) if err := GenMarkdown(dummyCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, dummyCmd.Example) checkStringContains(t, output, dummyCmd.Short) checkStringContains(t, output, "Options inherited from parent commands") checkStringOmits(t, output, "### Synopsis") } func TestGenMdNoHiddenParents(t *testing.T) { // We generate on subcommand so we have both subcommands and parents. for _, name := range []string{"rootflag", "strtwo"} { f := rootCmd.PersistentFlags().Lookup(name) f.Hidden = true defer func() { f.Hidden = false }() } buf := new(bytes.Buffer) if err := GenMarkdown(echoCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, echoCmd.Long) checkStringContains(t, output, echoCmd.Example) checkStringContains(t, output, "boolone") checkStringOmits(t, output, "rootflag") checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) checkStringOmits(t, output, deprecatedCmd.Short) checkStringOmits(t, output, "Options inherited from parent commands") } func TestGenMdNoTag(t *testing.T) { rootCmd.DisableAutoGenTag = true defer func() { rootCmd.DisableAutoGenTag = false }() buf := new(bytes.Buffer) if err := GenMarkdown(rootCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringOmits(t, output, "Auto generated") } func TestGenMdTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} tmpdir, err := ioutil.TempDir("", "test-gen-md-tree") if err != nil { t.Fatalf("Failed to create tmpdir: %v", err) } defer os.RemoveAll(tmpdir) if err := GenMarkdownTree(c, tmpdir); err != nil { t.Fatalf("GenMarkdownTree failed: %v", err) } if _, err := os.Stat(filepath.Join(tmpdir, "do.md")); err != nil { t.Fatalf("Expected file 'do.md' to exist") } } func BenchmarkGenMarkdownToFile(b *testing.B) { file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() b.ResetTimer() for i := 0; i < b.N; i++ { if err := GenMarkdown(rootCmd, file); err != nil { b.Fatal(err) } } } cobra-1.3.0/doc/rest_docs.go000066400000000000000000000123241415616037300156720ustar00rootroot00000000000000//Copyright 2015 Red Hat 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 doc import ( "bytes" "fmt" "io" "os" "path/filepath" "sort" "strings" "time" "github.com/spf13/cobra" ) func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) if flags.HasAvailableFlags() { buf.WriteString("Options\n") buf.WriteString("~~~~~~~\n\n::\n\n") flags.PrintDefaults() buf.WriteString("\n") } parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) if parentFlags.HasAvailableFlags() { buf.WriteString("Options inherited from parent commands\n") buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n") parentFlags.PrintDefaults() buf.WriteString("\n") } return nil } // linkHandler for default ReST hyperlink markup func defaultLinkHandler(name, ref string) string { return fmt.Sprintf("`%s <%s.rst>`_", name, ref) } // GenReST creates reStructured Text output. func GenReST(cmd *cobra.Command, w io.Writer) error { return GenReSTCustom(cmd, w, defaultLinkHandler) } // GenReSTCustom creates custom reStructured Text output. func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, string) string) error { cmd.InitDefaultHelpCmd() cmd.InitDefaultHelpFlag() buf := new(bytes.Buffer) name := cmd.CommandPath() short := cmd.Short long := cmd.Long if len(long) == 0 { long = short } ref := strings.Replace(name, " ", "_", -1) buf.WriteString(".. _" + ref + ":\n\n") buf.WriteString(name + "\n") buf.WriteString(strings.Repeat("-", len(name)) + "\n\n") buf.WriteString(short + "\n\n") buf.WriteString("Synopsis\n") buf.WriteString("~~~~~~~~\n\n") buf.WriteString("\n" + long + "\n\n") if cmd.Runnable() { buf.WriteString(fmt.Sprintf("::\n\n %s\n\n", cmd.UseLine())) } if len(cmd.Example) > 0 { buf.WriteString("Examples\n") buf.WriteString("~~~~~~~~\n\n") buf.WriteString(fmt.Sprintf("::\n\n%s\n\n", indentString(cmd.Example, " "))) } if err := printOptionsReST(buf, cmd, name); err != nil { return err } if hasSeeAlso(cmd) { buf.WriteString("SEE ALSO\n") buf.WriteString("~~~~~~~~\n\n") if cmd.HasParent() { parent := cmd.Parent() pname := parent.CommandPath() ref = strings.Replace(pname, " ", "_", -1) buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(pname, ref), parent.Short)) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag } }) } children := cmd.Commands() sort.Sort(byName(children)) for _, child := range children { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } cname := name + " " + child.Name() ref = strings.Replace(cname, " ", "_", -1) buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(cname, ref), child.Short)) } buf.WriteString("\n") } if !cmd.DisableAutoGenTag { buf.WriteString("*Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "*\n") } _, err := buf.WriteTo(w) return err } // GenReSTTree will generate a ReST page for this command and all // descendants in the directory given. // This function may not work correctly if your command names have `-` in them. // If you have `cmd` with two subcmds, `sub` and `sub-third`, // and `sub` has a subcommand called `third`, it is undefined which // help output will be in the file `cmd-sub-third.1`. func GenReSTTree(cmd *cobra.Command, dir string) error { emptyStr := func(s string) string { return "" } return GenReSTTreeCustom(cmd, dir, emptyStr, defaultLinkHandler) } // GenReSTTreeCustom is the the same as GenReSTTree, but // with custom filePrepender and linkHandler. func GenReSTTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenReSTTreeCustom(c, dir, filePrepender, linkHandler); err != nil { return err } } basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".rst" filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { return err } defer f.Close() if _, err := io.WriteString(f, filePrepender(filename)); err != nil { return err } if err := GenReSTCustom(cmd, f, linkHandler); err != nil { return err } return nil } // adapted from: https://github.com/kr/text/blob/main/indent.go func indentString(s, p string) string { var res []byte b := []byte(s) prefix := []byte(p) bol := true for _, c := range b { if bol && c != '\n' { res = append(res, prefix...) } res = append(res, c) bol = c == '\n' } return string(res) } cobra-1.3.0/doc/rest_docs.md000066400000000000000000000055451415616037300156740ustar00rootroot00000000000000# Generating ReStructured Text Docs For Your Own cobra.Command Generating ReST pages from a cobra command is incredibly easy. An example is as follows: ```go package main import ( "log" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func main() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } err := doc.GenReSTTree(cmd, "/tmp") if err != nil { log.Fatal(err) } } ``` That will get you a ReST document `/tmp/test.rst` ## Generate ReST docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project ```go package main import ( "log" "io/ioutil" "os" "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra/doc" ) func main() { kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) err := doc.GenReSTTree(kubectl, "./") if err != nil { log.Fatal(err) } } ``` This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") ## Generate ReST docs for a single command You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenReST` instead of `GenReSTTree` ```go out := new(bytes.Buffer) err := doc.GenReST(cmd, out) if err != nil { log.Fatal(err) } ``` This will write the ReST doc for ONLY "cmd" into the out, buffer. ## Customize the output Both `GenReST` and `GenReSTTree` have alternate versions with callbacks to get some control of the output: ```go func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error { //... } ``` ```go func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error { //... } ``` The `filePrepender` will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with [Hugo](http://gohugo.io/): ```go const fmTemplate = `--- date: %s title: "%s" slug: %s url: %s --- ` filePrepender := func(filename string) string { now := time.Now().Format(time.RFC3339) name := filepath.Base(filename) base := strings.TrimSuffix(name, path.Ext(name)) url := "/commands/" + strings.ToLower(base) + "/" return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url) } ``` The `linkHandler` can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where `:ref:` is used: ```go // Sphinx cross-referencing format linkHandler := func(name, ref string) string { return fmt.Sprintf(":ref:`%s <%s>`", name, ref) } ``` cobra-1.3.0/doc/rest_docs_test.go000066400000000000000000000047461415616037300167420ustar00rootroot00000000000000package doc import ( "bytes" "io/ioutil" "os" "path/filepath" "testing" "github.com/spf13/cobra" ) func TestGenRSTDoc(t *testing.T) { // We generate on a subcommand so we have both subcommands and parents buf := new(bytes.Buffer) if err := GenReST(echoCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, echoCmd.Long) checkStringContains(t, output, echoCmd.Example) checkStringContains(t, output, "boolone") checkStringContains(t, output, "rootflag") checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) checkStringOmits(t, output, deprecatedCmd.Short) } func TestGenRSTNoHiddenParents(t *testing.T) { // We generate on a subcommand so we have both subcommands and parents for _, name := range []string{"rootflag", "strtwo"} { f := rootCmd.PersistentFlags().Lookup(name) f.Hidden = true defer func() { f.Hidden = false }() } buf := new(bytes.Buffer) if err := GenReST(echoCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, echoCmd.Long) checkStringContains(t, output, echoCmd.Example) checkStringContains(t, output, "boolone") checkStringOmits(t, output, "rootflag") checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) checkStringOmits(t, output, deprecatedCmd.Short) checkStringOmits(t, output, "Options inherited from parent commands") } func TestGenRSTNoTag(t *testing.T) { rootCmd.DisableAutoGenTag = true defer func() { rootCmd.DisableAutoGenTag = false }() buf := new(bytes.Buffer) if err := GenReST(rootCmd, buf); err != nil { t.Fatal(err) } output := buf.String() unexpected := "Auto generated" checkStringOmits(t, output, unexpected) } func TestGenRSTTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} tmpdir, err := ioutil.TempDir("", "test-gen-rst-tree") if err != nil { t.Fatalf("Failed to create tmpdir: %s", err.Error()) } defer os.RemoveAll(tmpdir) if err := GenReSTTree(c, tmpdir); err != nil { t.Fatalf("GenReSTTree failed: %s", err.Error()) } if _, err := os.Stat(filepath.Join(tmpdir, "do.rst")); err != nil { t.Fatalf("Expected file 'do.rst' to exist") } } func BenchmarkGenReSTToFile(b *testing.B) { file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() b.ResetTimer() for i := 0; i < b.N; i++ { if err := GenReST(rootCmd, file); err != nil { b.Fatal(err) } } } cobra-1.3.0/doc/util.go000066400000000000000000000030271415616037300146620ustar00rootroot00000000000000// Copyright 2015 Red Hat 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 doc import ( "strings" "github.com/spf13/cobra" ) // Test to see if we have a reason to print See Also information in docs // Basically this is a test for a parent command or a subcommand which is // both not deprecated and not the autogenerated help command. func hasSeeAlso(cmd *cobra.Command) bool { if cmd.HasParent() { return true } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } return true } return false } // Temporary workaround for yaml lib generating incorrect yaml with long strings // that do not contain \n. func forceMultiLine(s string) string { if len(s) > 60 && !strings.Contains(s, "\n") { s = s + "\n" } return s } type byName []*cobra.Command func (s byName) Len() int { return len(s) } func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } cobra-1.3.0/doc/yaml_docs.go000066400000000000000000000115151415616037300156600ustar00rootroot00000000000000// Copyright 2016 French Ben. 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 doc import ( "fmt" "io" "os" "path/filepath" "sort" "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" "gopkg.in/yaml.v2" ) type cmdOption struct { Name string Shorthand string `yaml:",omitempty"` DefaultValue string `yaml:"default_value,omitempty"` Usage string `yaml:",omitempty"` } type cmdDoc struct { Name string Synopsis string `yaml:",omitempty"` Description string `yaml:",omitempty"` Usage string `yaml:",omitempty"` Options []cmdOption `yaml:",omitempty"` InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"` Example string `yaml:",omitempty"` SeeAlso []string `yaml:"see_also,omitempty"` } // GenYamlTree creates yaml structured ref files for this command and all descendants // in the directory given. This function may not work // correctly if your command names have `-` in them. If you have `cmd` with two // subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third` // it is undefined which help output will be in the file `cmd-sub-third.1`. func GenYamlTree(cmd *cobra.Command, dir string) error { identity := func(s string) string { return s } emptyStr := func(s string) string { return "" } return GenYamlTreeCustom(cmd, dir, emptyStr, identity) } // GenYamlTreeCustom creates yaml structured ref files. func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil { return err } } basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".yaml" filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { return err } defer f.Close() if _, err := io.WriteString(f, filePrepender(filename)); err != nil { return err } if err := GenYamlCustom(cmd, f, linkHandler); err != nil { return err } return nil } // GenYaml creates yaml output. func GenYaml(cmd *cobra.Command, w io.Writer) error { return GenYamlCustom(cmd, w, func(s string) string { return s }) } // GenYamlCustom creates custom yaml output. func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { cmd.InitDefaultHelpCmd() cmd.InitDefaultHelpFlag() yamlDoc := cmdDoc{} yamlDoc.Name = cmd.CommandPath() yamlDoc.Synopsis = forceMultiLine(cmd.Short) yamlDoc.Description = forceMultiLine(cmd.Long) if cmd.Runnable() { yamlDoc.Usage = cmd.UseLine() } if len(cmd.Example) > 0 { yamlDoc.Example = cmd.Example } flags := cmd.NonInheritedFlags() if flags.HasFlags() { yamlDoc.Options = genFlagResult(flags) } flags = cmd.InheritedFlags() if flags.HasFlags() { yamlDoc.InheritedOptions = genFlagResult(flags) } if hasSeeAlso(cmd) { result := []string{} if cmd.HasParent() { parent := cmd.Parent() result = append(result, parent.CommandPath()+" - "+parent.Short) } children := cmd.Commands() sort.Sort(byName(children)) for _, child := range children { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } result = append(result, child.Name()+" - "+child.Short) } yamlDoc.SeeAlso = result } final, err := yaml.Marshal(&yamlDoc) if err != nil { fmt.Println(err) os.Exit(1) } if _, err := w.Write(final); err != nil { return err } return nil } func genFlagResult(flags *pflag.FlagSet) []cmdOption { var result []cmdOption flags.VisitAll(func(flag *pflag.Flag) { // Todo, when we mark a shorthand is deprecated, but specify an empty message. // The flag.ShorthandDeprecated is empty as the shorthand is deprecated. // Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok. if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 { opt := cmdOption{ flag.Name, flag.Shorthand, flag.DefValue, forceMultiLine(flag.Usage), } result = append(result, opt) } else { opt := cmdOption{ Name: flag.Name, DefaultValue: forceMultiLine(flag.DefValue), Usage: forceMultiLine(flag.Usage), } result = append(result, opt) } }) return result } cobra-1.3.0/doc/yaml_docs.md000066400000000000000000000052161415616037300156540ustar00rootroot00000000000000# Generating Yaml Docs For Your Own cobra.Command Generating yaml files from a cobra command is incredibly easy. An example is as follows: ```go package main import ( "log" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func main() { cmd := &cobra.Command{ Use: "test", Short: "my test program", } err := doc.GenYamlTree(cmd, "/tmp") if err != nil { log.Fatal(err) } } ``` That will get you a Yaml document `/tmp/test.yaml` ## Generate yaml docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project ```go package main import ( "io/ioutil" "log" "os" "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra/doc" ) func main() { kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) err := doc.GenYamlTree(kubectl, "./") if err != nil { log.Fatal(err) } } ``` This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./") ## Generate yaml docs for a single command You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenYaml` instead of `GenYamlTree` ```go out := new(bytes.Buffer) doc.GenYaml(cmd, out) ``` This will write the yaml doc for ONLY "cmd" into the out, buffer. ## Customize the output Both `GenYaml` and `GenYamlTree` have alternate versions with callbacks to get some control of the output: ```go func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error { //... } ``` ```go func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error { //... } ``` The `filePrepender` will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with [Hugo](http://gohugo.io/): ```go const fmTemplate = `--- date: %s title: "%s" slug: %s url: %s --- ` filePrepender := func(filename string) string { now := time.Now().Format(time.RFC3339) name := filepath.Base(filename) base := strings.TrimSuffix(name, path.Ext(name)) url := "/commands/" + strings.ToLower(base) + "/" return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url) } ``` The `linkHandler` can be used to customize the rendered internal links to the commands, given a filename: ```go linkHandler := func(name string) string { base := strings.TrimSuffix(name, path.Ext(name)) return "/commands/" + strings.ToLower(base) + "/" } ``` cobra-1.3.0/doc/yaml_docs_test.go000066400000000000000000000036401415616037300167170ustar00rootroot00000000000000package doc import ( "bytes" "io/ioutil" "os" "path/filepath" "testing" "github.com/spf13/cobra" ) func TestGenYamlDoc(t *testing.T) { // We generate on s subcommand so we have both subcommands and parents buf := new(bytes.Buffer) if err := GenYaml(echoCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, echoCmd.Long) checkStringContains(t, output, echoCmd.Example) checkStringContains(t, output, "boolone") checkStringContains(t, output, "rootflag") checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) } func TestGenYamlNoTag(t *testing.T) { rootCmd.DisableAutoGenTag = true defer func() { rootCmd.DisableAutoGenTag = false }() buf := new(bytes.Buffer) if err := GenYaml(rootCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringOmits(t, output, "Auto generated") } func TestGenYamlTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} tmpdir, err := ioutil.TempDir("", "test-gen-yaml-tree") if err != nil { t.Fatalf("Failed to create tmpdir: %s", err.Error()) } defer os.RemoveAll(tmpdir) if err := GenYamlTree(c, tmpdir); err != nil { t.Fatalf("GenYamlTree failed: %s", err.Error()) } if _, err := os.Stat(filepath.Join(tmpdir, "do.yaml")); err != nil { t.Fatalf("Expected file 'do.yaml' to exist") } } func TestGenYamlDocRunnable(t *testing.T) { // Testing a runnable command: should contain the "usage" field buf := new(bytes.Buffer) if err := GenYaml(rootCmd, buf); err != nil { t.Fatal(err) } output := buf.String() checkStringContains(t, output, "usage: "+rootCmd.Use) } func BenchmarkGenYamlToFile(b *testing.B) { file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() b.ResetTimer() for i := 0; i < b.N; i++ { if err := GenYaml(rootCmd, file); err != nil { b.Fatal(err) } } } cobra-1.3.0/fish_completions.go000066400000000000000000000177041415616037300165140ustar00rootroot00000000000000package cobra import ( "bytes" "fmt" "io" "os" "strings" ) func genFishComp(buf io.StringWriter, name string, includeDesc bool) { // Variables should not contain a '-' or ':' character nameForVar := name nameForVar = strings.Replace(nameForVar, "-", "_", -1) nameForVar = strings.Replace(nameForVar, ":", "_", -1) compCmd := ShellCompRequestCmd if !includeDesc { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(` function __%[1]s_debug set -l file "$BASH_COMP_DEBUG_FILE" if test -n "$file" echo "$argv" >> $file end end function __%[1]s_perform_completion __%[1]s_debug "Starting __%[1]s_perform_completion" # Extract all args except the last one set -l args (commandline -opc) # Extract the last arg and escape it in case it is a space set -l lastArg (string escape -- (commandline -ct)) __%[1]s_debug "args: $args" __%[1]s_debug "last arg: $lastArg" set -l requestComp "$args[1] %[3]s $args[2..-1] $lastArg" __%[1]s_debug "Calling $requestComp" set -l results (eval $requestComp 2> /dev/null) # Some programs may output extra empty lines after the directive. # Let's ignore them or else it will break completion. # Ref: https://github.com/spf13/cobra/issues/1279 for line in $results[-1..1] if test (string trim -- $line) = "" # Found an empty line, remove it set results $results[1..-2] else # Found non-empty line, we have our proper output break end end set -l comps $results[1..-2] set -l directiveLine $results[-1] # For Fish, when completing a flag with an = (e.g., -n=) # completions must be prefixed with the flag set -l flagPrefix (string match -r -- '-.*=' "$lastArg") __%[1]s_debug "Comps: $comps" __%[1]s_debug "DirectiveLine: $directiveLine" __%[1]s_debug "flagPrefix: $flagPrefix" for comp in $comps printf "%%s%%s\n" "$flagPrefix" "$comp" end printf "%%s\n" "$directiveLine" end # This function does two things: # - Obtain the completions and store them in the global __%[1]s_comp_results # - Return false if file completion should be performed function __%[1]s_prepare_completions __%[1]s_debug "" __%[1]s_debug "========= starting completion logic ==========" # Start fresh set --erase __%[1]s_comp_results set -l results (__%[1]s_perform_completion) __%[1]s_debug "Completion results: $results" if test -z "$results" __%[1]s_debug "No completion, probably due to a failure" # Might as well do file completion, in case it helps return 1 end set -l directive (string sub --start 2 $results[-1]) set --global __%[1]s_comp_results $results[1..-2] __%[1]s_debug "Completions are: $__%[1]s_comp_results" __%[1]s_debug "Directive is: $directive" set -l shellCompDirectiveError %[4]d set -l shellCompDirectiveNoSpace %[5]d set -l shellCompDirectiveNoFileComp %[6]d set -l shellCompDirectiveFilterFileExt %[7]d set -l shellCompDirectiveFilterDirs %[8]d if test -z "$directive" set directive 0 end set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) %% 2) if test $compErr -eq 1 __%[1]s_debug "Received error directive: aborting." # Might as well do file completion, in case it helps return 1 end set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) %% 2) set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) %% 2) if test $filefilter -eq 1; or test $dirfilter -eq 1 __%[1]s_debug "File extension filtering or directory filtering not supported" # Do full file completion instead return 1 end set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) %% 2) set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) %% 2) __%[1]s_debug "nospace: $nospace, nofiles: $nofiles" # If we want to prevent a space, or if file completion is NOT disabled, # we need to count the number of valid completions. # To do so, we will filter on prefix as the completions we have received # may not already be filtered so as to allow fish to match on different # criteria than the prefix. if test $nospace -ne 0; or test $nofiles -eq 0 set -l prefix (commandline -t | string escape --style=regex) __%[1]s_debug "prefix: $prefix" set -l completions (string match -r -- "^$prefix.*" $__%[1]s_comp_results) set --global __%[1]s_comp_results $completions __%[1]s_debug "Filtered completions are: $__%[1]s_comp_results" # Important not to quote the variable for count to work set -l numComps (count $__%[1]s_comp_results) __%[1]s_debug "numComps: $numComps" if test $numComps -eq 1; and test $nospace -ne 0 # We must first split on \t to get rid of the descriptions to be # able to check what the actual completion will be. # We don't need descriptions anyway since there is only a single # real completion which the shell will expand immediately. set -l split (string split --max 1 \t $__%[1]s_comp_results[1]) # Fish won't add a space if the completion ends with any # of the following characters: @=/:., set -l lastChar (string sub -s -1 -- $split) if not string match -r -q "[@=/:.,]" -- "$lastChar" # In other cases, to support the "nospace" directive we trick the shell # by outputting an extra, longer completion. __%[1]s_debug "Adding second completion to perform nospace directive" set --global __%[1]s_comp_results $split[1] $split[1]. __%[1]s_debug "Completions are now: $__%[1]s_comp_results" end end if test $numComps -eq 0; and test $nofiles -eq 0 # To be consistent with bash and zsh, we only trigger file # completion when there are no other completions __%[1]s_debug "Requesting file completion" return 1 end end return 0 end # Since Fish completions are only loaded once the user triggers them, we trigger them ourselves # so we can properly delete any completions provided by another script. # Only do this if the program can be found, or else fish may print some errors; besides, # the existing completions will only be loaded if the program can be found. if type -q "%[2]s" # The space after the program name is essential to trigger completion for the program # and not completion of the program name itself. # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. complete --do-complete "%[2]s " > /dev/null 2>&1 end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c %[2]s -e # The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results # which provides the program's completion choices. complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' `, nameForVar, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } // GenFishCompletion generates fish completion file and writes to the passed writer. func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error { buf := new(bytes.Buffer) genFishComp(buf, c.Name(), includeDesc) _, err := buf.WriteTo(w) return err } // GenFishCompletionFile generates fish completion file. func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.GenFishCompletion(outFile, includeDesc) } cobra-1.3.0/fish_completions.md000066400000000000000000000001771415616037300165030ustar00rootroot00000000000000## Generating Fish Completions For Your cobra.Command Please refer to [Shell Completions](shell_completions.md) for details. cobra-1.3.0/fish_completions_test.go000066400000000000000000000036011415616037300175420ustar00rootroot00000000000000package cobra import ( "bytes" "testing" ) func TestCompleteNoDesCmdInFishScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) output := buf.String() check(t, output, ShellCompNoDescRequestCmd) } func TestCompleteCmdInFishScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ Use: "child", ValidArgsFunction: validArgsFunc, Run: emptyRun, } rootCmd.AddCommand(child) buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenFishCompletion(buf, true)) output := buf.String() check(t, output, ShellCompRequestCmd) checkOmit(t, output, ShellCompNoDescRequestCmd) } func TestProgWithDash(t *testing.T) { rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun} buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) output := buf.String() // Functions name should have replace the '-' check(t, output, "__root_dash_perform_completion") checkOmit(t, output, "__root-dash_perform_completion") // The command name should not have replaced the '-' check(t, output, "-c root-dash") checkOmit(t, output, "-c root_dash") } func TestProgWithColon(t *testing.T) { rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun} buf := new(bytes.Buffer) assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) output := buf.String() // Functions name should have replace the ':' check(t, output, "__root_colon_perform_completion") checkOmit(t, output, "__root:colon_perform_completion") // The command name should not have replaced the ':' check(t, output, "-c root:colon") checkOmit(t, output, "-c root_colon") } cobra-1.3.0/go.mod000066400000000000000000000003421415616037300137140ustar00rootroot00000000000000module github.com/spf13/cobra go 1.15 require ( github.com/cpuguy83/go-md2man/v2 v2.0.1 github.com/inconshreveable/mousetrap v1.0.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.10.0 gopkg.in/yaml.v2 v2.4.0 ) cobra-1.3.0/go.sum000066400000000000000000002272351415616037300137550ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= cobra-1.3.0/powershell_completions.go000066400000000000000000000247111415616037300177430ustar00rootroot00000000000000// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but // can be downloaded separately for windows 7 or 8.1). package cobra import ( "bytes" "fmt" "io" "os" ) func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) { compCmd := ShellCompRequestCmd if !includeDesc { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*- function __%[1]s_debug { if ($env:BASH_COMP_DEBUG_FILE) { "$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE" } } filter __%[1]s_escapeStringWithSpecialChars { `+" $_ -replace '\\s|#|@|\\$|;|,|''|\\{|\\}|\\(|\\)|\"|`|\\||<|>|&','`$&'"+` } Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { param( $WordToComplete, $CommandAst, $CursorPosition ) # Get the current command line and convert into a string $Command = $CommandAst.CommandElements $Command = "$Command" __%[1]s_debug "" __%[1]s_debug "========= starting completion logic ==========" __%[1]s_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition" # The user could have moved the cursor backwards on the command-line. # We need to trigger completion from the $CursorPosition location, so we need # to truncate the command-line ($Command) up to the $CursorPosition location. # Make sure the $Command is longer then the $CursorPosition before we truncate. # This happens because the $Command does not include the last space. if ($Command.Length -gt $CursorPosition) { $Command=$Command.Substring(0,$CursorPosition) } __%[1]s_debug "Truncated command: $Command" $ShellCompDirectiveError=%[3]d $ShellCompDirectiveNoSpace=%[4]d $ShellCompDirectiveNoFileComp=%[5]d $ShellCompDirectiveFilterFileExt=%[6]d $ShellCompDirectiveFilterDirs=%[7]d # Prepare the command to request completions for the program. # Split the command at the first space to separate the program and arguments. $Program,$Arguments = $Command.Split(" ",2) $RequestComp="$Program %[2]s $Arguments" __%[1]s_debug "RequestComp: $RequestComp" # we cannot use $WordToComplete because it # has the wrong values if the cursor was moved # so use the last argument if ($WordToComplete -ne "" ) { $WordToComplete = $Arguments.Split(" ")[-1] } __%[1]s_debug "New WordToComplete: $WordToComplete" # Check for flag with equal sign $IsEqualFlag = ($WordToComplete -Like "--*=*" ) if ( $IsEqualFlag ) { __%[1]s_debug "Completing equal sign flag" # Remove the flag part $Flag,$WordToComplete = $WordToComplete.Split("=",2) } if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) { # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" `+" # We need to use `\"`\" to pass an empty argument a \"\" or '' does not work!!!"+` `+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` } __%[1]s_debug "Calling $RequestComp" #call the command store the output in $out and redirect stderr and stdout to null # $Out is an array contains each line per element Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null # get directive from last line [int]$Directive = $Out[-1].TrimStart(':') if ($Directive -eq "") { # There is no directive specified $Directive = 0 } __%[1]s_debug "The completion directive is: $Directive" # remove directive (last element) from out $Out = $Out | Where-Object { $_ -ne $Out[-1] } __%[1]s_debug "The completions are: $Out" if (($Directive -band $ShellCompDirectiveError) -ne 0 ) { # Error code. No completion. __%[1]s_debug "Received error from custom completion go code" return } $Longest = 0 $Values = $Out | ForEach-Object { #Split the output in name and description `+" $Name, $Description = $_.Split(\"`t\",2)"+` __%[1]s_debug "Name: $Name Description: $Description" # Look for the longest completion so that we can format things nicely if ($Longest -lt $Name.Length) { $Longest = $Name.Length } # Set the description to a one space string if there is none set. # This is needed because the CompletionResult does not accept an empty string as argument if (-Not $Description) { $Description = " " } @{Name="$Name";Description="$Description"} } $Space = " " if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) { # remove the space here __%[1]s_debug "ShellCompDirectiveNoSpace is called" $Space = "" } if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) { __%[1]s_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported" # return here to prevent the completion of the extensions return } $Values = $Values | Where-Object { # filter the result $_.Name -like "$WordToComplete*" # Join the flag back if we have an equal sign flag if ( $IsEqualFlag ) { __%[1]s_debug "Join the equal sign flag back to the completion value" $_.Name = $Flag + "=" + $_.Name } } if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { __%[1]s_debug "ShellCompDirectiveNoFileComp is called" if ($Values.Length -eq 0) { # Just print an empty string here so the # shell does not start to complete paths. # We cannot use CompletionResult here because # it does not accept an empty string as argument. "" return } } # Get the current mode $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function __%[1]s_debug "Mode: $Mode" $Values | ForEach-Object { # store temporary because switch will overwrite $_ $comp = $_ # PowerShell supports three different completion modes # - TabCompleteNext (default windows style - on each key press the next option is displayed) # - Complete (works like bash) # - MenuComplete (works like zsh) # You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function # CompletionResult Arguments: # 1) CompletionText text to be used as the auto completion result # 2) ListItemText text to be displayed in the suggestion list # 3) ResultType type of completion result # 4) ToolTip text for the tooltip with details about the object switch ($Mode) { # bash like "Complete" { if ($Values.Length -eq 1) { __%[1]s_debug "Only one completion left" # insert space after value [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } else { # Add the proper number of spaces to align the descriptions while($comp.Name.Length -lt $Longest) { $comp.Name = $comp.Name + " " } # Check for empty description and only add parentheses if needed if ($($comp.Description) -eq " " ) { $Description = "" } else { $Description = " ($($comp.Description))" } [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)") } } # zsh like "MenuComplete" { # insert space after value # MenuComplete will automatically show the ToolTip of # the highlighted value at the bottom of the suggestions. [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } # TabCompleteNext and in case we get something unknown Default { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. # Description will not be shown because that's not possible with TabCompleteNext [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } } } } `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error { buf := new(bytes.Buffer) genPowerShellComp(buf, c.Name(), includeDesc) _, err := buf.WriteTo(w) return err } func (c *Command) genPowerShellCompletionFile(filename string, includeDesc bool) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.genPowerShellCompletion(outFile, includeDesc) } // GenPowerShellCompletionFile generates powershell completion file without descriptions. func (c *Command) GenPowerShellCompletionFile(filename string) error { return c.genPowerShellCompletionFile(filename, false) } // GenPowerShellCompletion generates powershell completion file without descriptions // and writes it to the passed writer. func (c *Command) GenPowerShellCompletion(w io.Writer) error { return c.genPowerShellCompletion(w, false) } // GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions. func (c *Command) GenPowerShellCompletionFileWithDesc(filename string) error { return c.genPowerShellCompletionFile(filename, true) } // GenPowerShellCompletionWithDesc generates powershell completion file with descriptions // and writes it to the passed writer. func (c *Command) GenPowerShellCompletionWithDesc(w io.Writer) error { return c.genPowerShellCompletion(w, true) } cobra-1.3.0/powershell_completions.md000066400000000000000000000002361415616037300177320ustar00rootroot00000000000000# Generating PowerShell Completions For Your Own cobra.Command Please refer to [Shell Completions](shell_completions.md#powershell-completions) for details. cobra-1.3.0/projects_using_cobra.md000066400000000000000000000046031415616037300173400ustar00rootroot00000000000000## Projects using Cobra - [Arduino CLI](https://github.com/arduino/arduino-cli) - [Bleve](http://www.blevesearch.com/) - [CockroachDB](http://www.cockroachlabs.com/) - [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) - [Datree](https://github.com/datreeio/datree) - [Delve](https://github.com/derekparker/delve) - [Docker (distribution)](https://github.com/docker/distribution) - [Etcd](https://etcd.io/) - [Gardener](https://github.com/gardener/gardenctl) - [Giant Swarm's gsctl](https://github.com/giantswarm/gsctl) - [Git Bump](https://github.com/erdaltsksn/git-bump) - [Github CLI](https://github.com/cli/cli) - [GitHub Labeler](https://github.com/erdaltsksn/gh-label) - [Golangci-lint](https://golangci-lint.run) - [GopherJS](http://www.gopherjs.org/) - [GoReleaser](https://goreleaser.com) - [Helm](https://helm.sh) - [Hugo](https://gohugo.io) - [Infracost](https://github.com/infracost/infracost) - [Istio](https://istio.io) - [Kool](https://github.com/kool-dev/kool) - [Kubernetes](http://kubernetes.io/) - [Linkerd](https://linkerd.io/) - [Mattermost-server](https://github.com/mattermost/mattermost-server) - [Mercure](https://mercure.rocks/) - [Meroxa CLI](https://github.com/meroxa/cli) - [Metal Stack CLI](https://github.com/metal-stack/metalctl) - [Moby (former Docker)](https://github.com/moby/moby) - [Moldy](https://github.com/Moldy-Community/moldy) - [Multi-gitter](https://github.com/lindell/multi-gitter) - [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) - [nFPM](https://nfpm.goreleaser.com) - [OpenShift](https://www.openshift.com/) - [Ory Hydra](https://github.com/ory/hydra) - [Ory Kratos](https://github.com/ory/kratos) - [Pouch](https://github.com/alibaba/pouch) - [ProjectAtomic (enterprise)](http://www.projectatomic.io/) - [Prototool](https://github.com/uber/prototool) - [QRcp](https://github.com/claudiodangelis/qrcp) - [Random](https://github.com/erdaltsksn/random) - [Rclone](https://rclone.org/) - [Scaleway CLI](https://github.com/scaleway/scaleway-cli) - [Skaffold](https://skaffold.dev/) - [Tendermint](https://github.com/tendermint/tendermint) - [Twitch CLI](https://github.com/twitchdev/twitch-cli) - [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli) - VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework) - [Werf](https://werf.io/) cobra-1.3.0/shell_completions.go000066400000000000000000000072441415616037300166700ustar00rootroot00000000000000package cobra import ( "github.com/spf13/pflag" ) // MarkFlagRequired instructs the various shell completion implementations to // prioritize the named flag when performing completion, // and causes your command to report an error if invoked without the flag. func (c *Command) MarkFlagRequired(name string) error { return MarkFlagRequired(c.Flags(), name) } // MarkPersistentFlagRequired instructs the various shell completion implementations to // prioritize the named persistent flag when performing completion, // and causes your command to report an error if invoked without the flag. func (c *Command) MarkPersistentFlagRequired(name string) error { return MarkFlagRequired(c.PersistentFlags(), name) } // MarkFlagRequired instructs the various shell completion implementations to // prioritize the named flag when performing completion, // and causes your command to report an error if invoked without the flag. func MarkFlagRequired(flags *pflag.FlagSet, name string) error { return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) } // MarkFlagFilename instructs the various shell completion implementations to // limit completions for the named flag to the specified file extensions. func (c *Command) MarkFlagFilename(name string, extensions ...string) error { return MarkFlagFilename(c.Flags(), name, extensions...) } // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. // The bash completion script will call the bash function f for the flag. // // This will only work for bash completion. // It is recommended to instead use c.RegisterFlagCompletionFunc(...) which allows // to register a Go function which will work across all shells. func (c *Command) MarkFlagCustom(name string, f string) error { return MarkFlagCustom(c.Flags(), name, f) } // MarkPersistentFlagFilename instructs the various shell completion // implementations to limit completions for the named persistent flag to the // specified file extensions. func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { return MarkFlagFilename(c.PersistentFlags(), name, extensions...) } // MarkFlagFilename instructs the various shell completion implementations to // limit completions for the named flag to the specified file extensions. func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { return flags.SetAnnotation(name, BashCompFilenameExt, extensions) } // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. // The bash completion script will call the bash function f for the flag. // // This will only work for bash completion. // It is recommended to instead use c.RegisterFlagCompletionFunc(...) which allows // to register a Go function which will work across all shells. func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { return flags.SetAnnotation(name, BashCompCustom, []string{f}) } // MarkFlagDirname instructs the various shell completion implementations to // limit completions for the named flag to directory names. func (c *Command) MarkFlagDirname(name string) error { return MarkFlagDirname(c.Flags(), name) } // MarkPersistentFlagDirname instructs the various shell completion // implementations to limit completions for the named persistent flag to // directory names. func (c *Command) MarkPersistentFlagDirname(name string) error { return MarkFlagDirname(c.PersistentFlags(), name) } // MarkFlagDirname instructs the various shell completion implementations to // limit completions for the named flag to directory names. func MarkFlagDirname(flags *pflag.FlagSet, name string) error { return flags.SetAnnotation(name, BashCompSubdirsInDir, []string{}) } cobra-1.3.0/shell_completions.md000066400000000000000000000601121415616037300166540ustar00rootroot00000000000000# Generating shell completions Cobra can generate shell completions for multiple shells. The currently supported shells are: - Bash - Zsh - fish - PowerShell Cobra will automatically provide your program with a fully functional `completion` command, similarly to how it provides the `help` command. ## Creating your own completion command If you do not wish to use the default `completion` command, you can choose to provide your own, which will take precedence over the default one. (This also provides backwards-compatibility with programs that already have their own `completion` command.) If you are using the generator, you can create a completion command by running ```bash cobra add completion ``` and then modifying the generated `cmd/completion.go` file to look something like this (writing the shell script to stdout allows the most flexible use): ```go var completionCmd = &cobra.Command{ Use: "completion [bash|zsh|fish|powershell]", Short: "Generate completion script", Long: fmt.Sprintf(`To load completions: Bash: $ source <(%[1]s completion bash) # To load completions for each session, execute once: # Linux: $ %[1]s completion bash > /etc/bash_completion.d/%[1]s # macOS: $ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s Zsh: # If shell completion is not already enabled in your environment, # you will need to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc # To load completions for each session, execute once: $ %[1]s completion zsh > "${fpath[1]}/_%[1]s" # You will need to start a new shell for this setup to take effect. fish: $ %[1]s completion fish | source # To load completions for each session, execute once: $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish PowerShell: PS> %[1]s completion powershell | Out-String | Invoke-Expression # To load completions for every new session, run: PS> %[1]s completion powershell > %[1]s.ps1 # and source this file from your PowerShell profile. `,cmd.Root().Name()), DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.ExactValidArgs(1), Run: func(cmd *cobra.Command, args []string) { switch args[0] { case "bash": cmd.Root().GenBashCompletion(os.Stdout) case "zsh": cmd.Root().GenZshCompletion(os.Stdout) case "fish": cmd.Root().GenFishCompletion(os.Stdout, true) case "powershell": cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) } }, } ``` **Note:** The cobra generator may include messages printed to stdout, for example, if the config file is loaded; this will break the auto-completion script so must be removed. ## Adapting the default completion command Cobra provides a few options for the default `completion` command. To configure such options you must set the `CompletionOptions` field on the *root* command. To tell Cobra *not* to provide the default `completion` command: ``` rootCmd.CompletionOptions.DisableDefaultCmd = true ``` To tell Cobra *not* to provide the user with the `--no-descriptions` flag to the completion sub-commands: ``` rootCmd.CompletionOptions.DisableNoDescFlag = true ``` To tell Cobra to completely disable descriptions for completions: ``` rootCmd.CompletionOptions.DisableDescriptions = true ``` # Customizing completions The generated completion scripts will automatically handle completing commands and flags. However, you can make your completions much more powerful by providing information to complete your program's nouns and flag values. ## Completion of nouns ### Static completion of nouns Cobra allows you to provide a pre-defined list of completion choices for your nouns using the `ValidArgs` field. For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Some simplified code from `kubectl get` looks like: ```go validArgs []string = { "pod", "node", "service", "replicationcontroller" } cmd := &cobra.Command{ Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", Short: "Display one or many resources", Long: get_long, Example: get_example, Run: func(cmd *cobra.Command, args []string) { cobra.CheckErr(RunGet(f, out, cmd, args)) }, ValidArgs: validArgs, } ``` Notice we put the `ValidArgs` field on the `get` sub-command. Doing so will give results like: ```bash $ kubectl get [tab][tab] node pod replicationcontroller service ``` #### Aliases for nouns If your nouns have aliases, you can define them alongside `ValidArgs` using `ArgAliases`: ```go argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } cmd := &cobra.Command{ ... ValidArgs: validArgs, ArgAliases: argAliases } ``` The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by the completion algorithm if entered manually, e.g. in: ```bash $ kubectl get rc [tab][tab] backend frontend database ``` Note that without declaring `rc` as an alias, the completion algorithm would not know to show the list of replication controllers following `rc`. ### Dynamic completion of nouns In some cases it is not possible to provide a list of completions in advance. Instead, the list of completions must be determined at execution-time. In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command. Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both. Simplified code from `helm status` looks like: ```go cmd := &cobra.Command{ Use: "status RELEASE_NAME", Short: "Display the status of the named release", Long: status_long, RunE: func(cmd *cobra.Command, args []string) { RunGet(args[0]) }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp }, } ``` Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster. Notice we put the `ValidArgsFunction` on the `status` sub-command. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like: ```bash $ helm status [tab][tab] harbor notary rook thanos ``` You may have noticed the use of `cobra.ShellCompDirective`. These directives are bit fields allowing to control some shell completion behaviors for your particular completion. You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp` ```go // Indicates that the shell will perform its default behavior after completions // have been provided (this implies none of the other directives). ShellCompDirectiveDefault // Indicates an error occurred and completions should be ignored. ShellCompDirectiveError // Indicates that the shell should not add a space after the completion, // even if there is a single completion provided. ShellCompDirectiveNoSpace // Indicates that the shell should not provide file completion even when // no completion is provided. ShellCompDirectiveNoFileComp // Indicates that the returned completions should be used as file extension filters. // For example, to complete only files of the form *.json or *.yaml: // return []string{"yaml", "json"}, ShellCompDirectiveFilterFileExt // For flags, using MarkFlagFilename() and MarkPersistentFlagFilename() // is a shortcut to using this directive explicitly. // ShellCompDirectiveFilterFileExt // Indicates that only directory names should be provided in file completion. // For example: // return nil, ShellCompDirectiveFilterDirs // For flags, using MarkFlagDirname() is a shortcut to using this directive explicitly. // // To request directory names within another directory, the returned completions // should specify a single directory name within which to search. For example, // to complete directories within "themes/": // return []string{"themes"}, ShellCompDirectiveFilterDirs // ShellCompDirectiveFilterDirs ``` ***Note***: When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function. #### Debugging Cobra achieves dynamic completion through the use of a hidden command called by the completion script. To debug your Go completion code, you can call this hidden command directly: ```bash $ helm __complete status har harbor :4 Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr ``` ***Important:*** If the noun to complete is empty (when the user has not yet typed any letters of that noun), you must pass an empty parameter to the `__complete` command: ```bash $ helm __complete status "" harbor notary rook thanos :4 Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr ``` Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code. You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code: ```go // Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE // is set to a file path) and optionally prints to stderr. cobra.CompDebug(msg string, printToStdErr bool) { cobra.CompDebugln(msg string, printToStdErr bool) // Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE // is set to a file path) and to stderr. cobra.CompError(msg string) cobra.CompErrorln(msg string) ``` ***Important:*** You should **not** leave traces that print directly to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned above. ## Completions for flags ### Mark flags as required Most of the time completions will only show sub-commands. But if a flag is required to make a sub-command work, you probably want it to show up when the user types [tab][tab]. You can mark a flag as 'Required' like so: ```go cmd.MarkFlagRequired("pod") cmd.MarkFlagRequired("container") ``` and you'll get something like ```bash $ kubectl exec [tab][tab] -c --container= -p --pod= ``` ### Specify dynamic flag completion As for nouns, Cobra provides a way of defining dynamic completion of flags. To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function using the `command.RegisterFlagCompletionFunc()` function. ```go flagName := "output" cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault }) ``` Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated. In our example this dynamic completion will give results like so: ```bash $ helm status --output [tab][tab] json table yaml ``` #### Debugging You can also easily debug your Go completion code for flags: ```bash $ helm __complete status --output "" json table yaml :4 Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr ``` ***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned further above. ### Specify valid filename extensions for flags that take a filename To limit completions of flag values to file names with certain extensions you can either use the different `MarkFlagFilename()` functions or a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterFileExt`, like so: ```go flagName := "output" cmd.MarkFlagFilename(flagName, "yaml", "json") ``` or ```go flagName := "output" cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"yaml", "json"}, ShellCompDirectiveFilterFileExt}) ``` ### Limit flag completions to directory names To limit completions of flag values to directory names you can either use the `MarkFlagDirname()` functions or a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterDirs`, like so: ```go flagName := "output" cmd.MarkFlagDirname(flagName) ``` or ```go flagName := "output" cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveFilterDirs }) ``` To limit completions of flag values to directory names *within another directory* you can use a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterDirs` like so: ```go flagName := "output" cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"themes"}, cobra.ShellCompDirectiveFilterDirs }) ``` ### Descriptions for completions Cobra provides support for completion descriptions. Such descriptions are supported for each shell (however, for bash, it is only available in the [completion V2 version](#bash-completion-v2)). For commands and flags, Cobra will provide the descriptions automatically, based on usage information. For example, using zsh: ``` $ helm s[tab] search -- search for a keyword in charts show -- show information of a chart status -- displays the status of the named release ``` while using fish: ``` $ helm s[tab] search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) ``` Cobra allows you to add descriptions to your own completions. Simply add the description text after each completion, following a `\t` separator. This technique applies to completions returned by `ValidArgs`, `ValidArgsFunction` and `RegisterFlagCompletionFunc()`. For example: ```go ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"harbor\tAn image registry", "thanos\tLong-term metrics"}, cobra.ShellCompDirectiveNoFileComp }} ``` or ```go ValidArgs: []string{"bash\tCompletions for bash", "zsh\tCompletions for zsh"} ``` ## Bash completions ### Dependencies The bash completion script generated by Cobra requires the `bash_completion` package. You should update the help text of your completion command to show how to install the `bash_completion` package ([Kubectl docs](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)) ### Aliases You can also configure `bash` aliases for your program and they will also support completions. ```bash alias aliasname=origcommand complete -o default -F __start_origcommand aliasname # and now when you run `aliasname` completion will make # suggestions as it did for `origcommand`. $ aliasname completion firstcommand secondcommand ``` ### Bash legacy dynamic completions For backward compatibility, Cobra still supports its bash legacy dynamic completion solution. Please refer to [Bash Completions](bash_completions.md) for details. ### Bash completion V2 Cobra provides two versions for bash completion. The original bash completion (which started it all!) can be used by calling `GenBashCompletion()` or `GenBashCompletionFile()`. A new V2 bash completion version is also available. This version can be used by calling `GenBashCompletionV2()` or `GenBashCompletionFileV2()`. The V2 version does **not** support the legacy dynamic completion (see [Bash Completions](bash_completions.md)) but instead works only with the Go dynamic completion solution described in this document. Unless your program already uses the legacy dynamic completion solution, it is recommended that you use the bash completion V2 solution which provides the following extra features: - Supports completion descriptions (like the other shells) - Small completion script of less than 300 lines (v1 generates scripts of thousands of lines; `kubectl` for example has a bash v1 completion script of over 13K lines) - Streamlined user experience thanks to a completion behavior aligned with the other shells `Bash` completion V2 supports descriptions for completions. When calling `GenBashCompletionV2()` or `GenBashCompletionFileV2()` you must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. ``` # With descriptions $ helm s[tab][tab] search (search for a keyword in charts) status (display the status of the named release) show (show information of a chart) # Without descriptions $ helm s[tab][tab] search show status ``` **Note**: Cobra's default `completion` command uses bash completion V2. If for some reason you need to use bash completion V1, you will need to implement your own `completion` command. ## Zsh completions Cobra supports native zsh completion generated from the root `cobra.Command`. The generated completion script should be put somewhere in your `$fpath` and be named `_`. You will need to start a new shell for the completions to become available. Zsh supports descriptions for completions. Cobra will provide the description automatically, based on usage information. Cobra provides a way to completely disable such descriptions by using `GenZshCompletionNoDesc()` or `GenZshCompletionFileNoDesc()`. You can choose to make this a configurable option to your users. ``` # With descriptions $ helm s[tab] search -- search for a keyword in charts show -- show information of a chart status -- displays the status of the named release # Without descriptions $ helm s[tab] search show status ``` *Note*: Because of backward-compatibility requirements, we were forced to have a different API to disable completion descriptions between `zsh` and `fish`. ### Limitations * Custom completions implemented in Bash scripting (legacy) are not supported and will be ignored for `zsh` (including the use of the `BashCompCustom` flag annotation). * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). * The function `MarkFlagCustom()` is not supported and will be ignored for `zsh`. * You should instead use `RegisterFlagCompletionFunc()`. ### Zsh completions standardization Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backward-compatible, some small changes in behavior were introduced. Please refer to [Zsh Completions](zsh_completions.md) for details. ## fish completions Cobra supports native fish completions generated from the root `cobra.Command`. You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. ``` # With descriptions $ helm s[tab] search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) # Without descriptions $ helm s[tab] search show status ``` *Note*: Because of backward-compatibility requirements, we were forced to have a different API to disable completion descriptions between `zsh` and `fish`. ### Limitations * Custom completions implemented in bash scripting (legacy) are not supported and will be ignored for `fish` (including the use of the `BashCompCustom` flag annotation). * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). * The function `MarkFlagCustom()` is not supported and will be ignored for `fish`. * You should instead use `RegisterFlagCompletionFunc()`. * The following flag completion annotations are not supported and will be ignored for `fish`: * `BashCompFilenameExt` (filtering by file extension) * `BashCompSubdirsInDir` (filtering by directory) * The functions corresponding to the above annotations are consequently not supported and will be ignored for `fish`: * `MarkFlagFilename()` and `MarkPersistentFlagFilename()` (filtering by file extension) * `MarkFlagDirname()` and `MarkPersistentFlagDirname()` (filtering by directory) * Similarly, the following completion directives are not supported and will be ignored for `fish`: * `ShellCompDirectiveFilterFileExt` (filtering by file extension) * `ShellCompDirectiveFilterDirs` (filtering by directory) ## PowerShell completions Cobra supports native PowerShell completions generated from the root `cobra.Command`. You can use the `command.GenPowerShellCompletion()` or `command.GenPowerShellCompletionFile()` functions. To include descriptions use `command.GenPowerShellCompletionWithDesc()` and `command.GenPowerShellCompletionFileWithDesc()`. Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. The script is designed to support all three PowerShell completion modes: * TabCompleteNext (default windows style - on each key press the next option is displayed) * Complete (works like bash) * MenuComplete (works like zsh) You set the mode with `Set-PSReadLineKeyHandler -Key Tab -Function `. Descriptions are only displayed when using the `Complete` or `MenuComplete` mode. Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles. ``` # With descriptions and Mode 'Complete' $ helm s[tab] search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) # With descriptions and Mode 'MenuComplete' The description of the current selected value will be displayed below the suggestions. $ helm s[tab] search show status search for a keyword in charts # Without descriptions $ helm s[tab] search show status ``` ### Limitations * Custom completions implemented in bash scripting (legacy) are not supported and will be ignored for `powershell` (including the use of the `BashCompCustom` flag annotation). * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). * The function `MarkFlagCustom()` is not supported and will be ignored for `powershell`. * You should instead use `RegisterFlagCompletionFunc()`. * The following flag completion annotations are not supported and will be ignored for `powershell`: * `BashCompFilenameExt` (filtering by file extension) * `BashCompSubdirsInDir` (filtering by directory) * The functions corresponding to the above annotations are consequently not supported and will be ignored for `powershell`: * `MarkFlagFilename()` and `MarkPersistentFlagFilename()` (filtering by file extension) * `MarkFlagDirname()` and `MarkPersistentFlagDirname()` (filtering by directory) * Similarly, the following completion directives are not supported and will be ignored for `powershell`: * `ShellCompDirectiveFilterFileExt` (filtering by file extension) * `ShellCompDirectiveFilterDirs` (filtering by directory) cobra-1.3.0/user_guide.md000066400000000000000000000450161415616037300152720ustar00rootroot00000000000000# User Guide While you are welcome to provide your own organization, typically a Cobra-based application will follow the following organizational structure: ``` ▾ appName/ ▾ cmd/ add.go your.go commands.go here.go main.go ``` In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. ```go package main import ( "{pathToYourApp}/cmd" ) func main() { cmd.Execute() } ``` ## Using the Cobra Generator Cobra provides its own program that will create your application and add any commands you want. It's the easiest way to incorporate Cobra into your application. For complete details on using the Cobra generator, please read [The Cobra Generator README](https://github.com/spf13/cobra/blob/master/cobra/README.md) ## Using the Cobra Library To manually implement Cobra you need to create a bare main.go file and a rootCmd file. You will optionally provide additional commands as you see fit. ### Create rootCmd Cobra doesn't require any special constructors. Simply create your commands. Ideally you place this in app/cmd/root.go: ```go var rootCmd = &cobra.Command{ Use: "hugo", Short: "Hugo is a very fast static site generator", Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://hugo.spf13.com`, Run: func(cmd *cobra.Command, args []string) { // Do Stuff Here }, } func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } ``` You will additionally define flags and handle configuration in your init() function. For example cmd/root.go: ```go package cmd import ( "fmt" "os" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( // Used for flags. cfgFile string userLicense string rootCmd = &cobra.Command{ Use: "cobra", Short: "A generator for Cobra based Applications", Long: `Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, } ) // Execute executes the root command. func Execute() error { return rootCmd.Execute() } func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) viper.SetDefault("author", "NAME HERE ") viper.SetDefault("license", "apache") rootCmd.AddCommand(addCmd) rootCmd.AddCommand(initCmd) } func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := os.UserHomeDir() cobra.CheckErr(err) // Search config in home directory with name ".cobra" (without extension). viper.AddConfigPath(home) viper.SetConfigType("yaml") viper.SetConfigName(".cobra") } viper.AutomaticEnv() if err := viper.ReadInConfig(); err == nil { fmt.Println("Using config file:", viper.ConfigFileUsed()) } } ``` ### Create your main.go With the root command you need to have your main function execute it. Execute should be run on the root for clarity, though it can be called on any command. In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra. ```go package main import ( "{pathToYourApp}/cmd" ) func main() { cmd.Execute() } ``` ### Create additional commands Additional commands can be defined and typically are each given their own file inside of the cmd/ directory. If you wanted to create a version command you would create cmd/version.go and populate it with the following: ```go package cmd import ( "fmt" "github.com/spf13/cobra" ) func init() { rootCmd.AddCommand(versionCmd) } var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of Hugo", Long: `All software has versions. This is Hugo's`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") }, } ``` ### Returning and handling errors If you wish to return an error to the caller of a command, `RunE` can be used. ```go package cmd import ( "fmt" "github.com/spf13/cobra" ) func init() { rootCmd.AddCommand(tryCmd) } var tryCmd = &cobra.Command{ Use: "try", Short: "Try and possibly fail at something", RunE: func(cmd *cobra.Command, args []string) error { if err := someFunc(); err != nil { return err } return nil }, } ``` The error can then be caught at the execute function call. ## Working with Flags Flags provide modifiers to control how the action command operates. ### Assign flags to a command Since the flags are defined and used in different locations, we need to define a variable outside with the correct scope to assign the flag to work with. ```go var Verbose bool var Source string ``` There are two different approaches to assign a flag. ### Persistent Flags A flag can be 'persistent', meaning that this flag will be available to the command it's assigned to as well as every command under that command. For global flags, assign a flag as a persistent flag on the root. ```go rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") ``` ### Local Flags A flag can also be assigned locally, which will only apply to that specific command. ```go localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` ### Local Flag on Parent Commands By default, Cobra only parses local flags on the target command, and any local flags on parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will parse local flags on each command before executing the target command. ```go command := cobra.Command{ Use: "print [OPTIONS] [COMMANDS]", TraverseChildren: true, } ``` ### Bind Flags with Config You can also bind your flags with [viper](https://github.com/spf13/viper): ```go var author string func init() { rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) } ``` In this example, the persistent flag `author` is bound with `viper`. **Note**: the variable `author` will not be set to the value from config, when the `--author` flag is provided by user. More in [viper documentation](https://github.com/spf13/viper#working-with-flags). ### Required flags Flags are optional by default. If instead you wish your command to report an error when a flag has not been set, mark it as required: ```go rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") rootCmd.MarkFlagRequired("region") ``` Or, for persistent flags: ```go rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") rootCmd.MarkPersistentFlagRequired("region") ``` ## Positional and Custom Arguments Validation of positional arguments can be specified using the `Args` field of `Command`. The following validators are built in: - `NoArgs` - the command will report an error if there are any positional args. - `ArbitraryArgs` - the command will accept any args. - `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. - `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. - `MatchAll(pargs ...PositionalArgs)` - enables combining existing checks with arbitrary other checks (e.g. you want to check the ExactArgs length along with other qualities). An example of setting the custom validator: ```go var cmd = &cobra.Command{ Short: "hello", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { return errors.New("requires a color argument") } if myapp.IsValidColor(args[0]) { return nil } return fmt.Errorf("invalid color specified: %s", args[0]) }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hello, World!") }, } ``` ## Example In the example below, we have defined three commands. Two are at the top level and one (cmdTimes) is a child of one of the top commands. In this case the root is not executable, meaning that a subcommand is required. This is accomplished by not providing a 'Run' for the 'rootCmd'. We have only defined one flag for a single command. More documentation about flags is available at https://github.com/spf13/pflag ```go package main import ( "fmt" "strings" "github.com/spf13/cobra" ) func main() { var echoTimes int var cmdPrint = &cobra.Command{ Use: "print [string to print]", Short: "Print anything to the screen", Long: `print is for printing anything back to the screen. For many years people have printed back to the screen.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdEcho = &cobra.Command{ Use: "echo [string to echo]", Short: "Echo anything to the screen", Long: `echo is for echoing anything back. Echo works a lot like print, except it has a child command.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Echo: " + strings.Join(args, " ")) }, } var cmdTimes = &cobra.Command{ Use: "times [string to echo]", Short: "Echo anything to the screen more times", Long: `echo things multiple times back to the user by providing a count and a string.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { for i := 0; i < echoTimes; i++ { fmt.Println("Echo: " + strings.Join(args, " ")) } }, } cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") var rootCmd = &cobra.Command{Use: "app"} rootCmd.AddCommand(cmdPrint, cmdEcho) cmdEcho.AddCommand(cmdTimes) rootCmd.Execute() } ``` For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). ## Help Command Cobra automatically adds a help command to your application when you have subcommands. This will be called when a user runs 'app help'. Additionally, help will also support all other commands as input. Say, for instance, you have a command called 'create' without any additional configuration; Cobra will work when 'app help create' is called. Every command will automatically have the '--help' flag added. ### Example The following output is automatically generated by Cobra. Nothing beyond the command and flag definitions are needed. $ cobra help Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application. Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, --author string author name for copyright attribution (default "YOUR NAME") --config string config file (default is $HOME/.cobra.yaml) -h, --help help for cobra -l, --license string name of license for the project --viper use Viper for configuration (default true) Use "cobra [command] --help" for more information about a command. Help is just a command like any other. There is no special logic or behavior around it. In fact, you can provide your own if you want. ### Defining your own help You can provide your own Help command or your own template for the default command to use with following functions: ```go cmd.SetHelpCommand(cmd *Command) cmd.SetHelpFunc(f func(*Command, []string)) cmd.SetHelpTemplate(s string) ``` The latter two will also apply to any children commands. ## Usage Message When the user provides an invalid flag or invalid command, Cobra responds by showing the user the 'usage'. ### Example You may recognize this from the help above. That's because the default help embeds the usage as part of its output. $ cobra --invalid Error: unknown flag: --invalid Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, --author string author name for copyright attribution (default "YOUR NAME") --config string config file (default is $HOME/.cobra.yaml) -h, --help help for cobra -l, --license string name of license for the project --viper use Viper for configuration (default true) Use "cobra [command] --help" for more information about a command. ### Defining your own usage You can provide your own usage function or template for Cobra to use. Like help, the function and template are overridable through public methods: ```go cmd.SetUsageFunc(f func(*Command) error) cmd.SetUsageTemplate(s string) ``` ## Version Flag Cobra adds a top-level '--version' flag if the Version field is set on the root command. Running an application with the '--version' flag will print the version to stdout using the version template. The template can be customized using the `cmd.SetVersionTemplate(s string)` function. ## PreRun and PostRun Hooks It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - `PersistentPreRun` - `PreRun` - `Run` - `PostRun` - `PersistentPostRun` An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: ```go package main import ( "fmt" "github.com/spf13/cobra" ) func main() { var rootCmd = &cobra.Command{ Use: "root [sub]", Short: "My root command", PersistentPreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) }, PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) }, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd Run with args: %v\n", args) }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) }, } var subCmd = &cobra.Command{ Use: "sub [no options!]", Short: "My subcommand", PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PreRun with args: %v\n", args) }, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd Run with args: %v\n", args) }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PostRun with args: %v\n", args) }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) }, } rootCmd.AddCommand(subCmd) rootCmd.SetArgs([]string{""}) rootCmd.Execute() fmt.Println() rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) rootCmd.Execute() } ``` Output: ``` Inside rootCmd PersistentPreRun with args: [] Inside rootCmd PreRun with args: [] Inside rootCmd Run with args: [] Inside rootCmd PostRun with args: [] Inside rootCmd PersistentPostRun with args: [] Inside rootCmd PersistentPreRun with args: [arg1 arg2] Inside subCmd PreRun with args: [arg1 arg2] Inside subCmd Run with args: [arg1 arg2] Inside subCmd PostRun with args: [arg1 arg2] Inside subCmd PersistentPostRun with args: [arg1 arg2] ``` ## Suggestions when "unknown command" happens Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: ``` $ hugo srever Error: unknown command "srever" for "hugo" Did you mean this? server Run 'hugo --help' for usage. ``` Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. If you need to disable suggestions or tweak the string distance in your command, use: ```go command.DisableSuggestions = true ``` or ```go command.SuggestionsMinimumDistance = 1 ``` You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: ``` $ kubectl remove Error: unknown command "remove" for "kubectl" Did you mean this? delete Run 'kubectl help' for usage. ``` ## Generating documentation for your command Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md). ## Generating shell completions Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md). cobra-1.3.0/zsh_completions.go000066400000000000000000000215021415616037300163560ustar00rootroot00000000000000package cobra import ( "bytes" "fmt" "io" "os" ) // GenZshCompletionFile generates zsh completion file including descriptions. func (c *Command) GenZshCompletionFile(filename string) error { return c.genZshCompletionFile(filename, true) } // GenZshCompletion generates zsh completion file including descriptions // and writes it to the passed writer. func (c *Command) GenZshCompletion(w io.Writer) error { return c.genZshCompletion(w, true) } // GenZshCompletionFileNoDesc generates zsh completion file without descriptions. func (c *Command) GenZshCompletionFileNoDesc(filename string) error { return c.genZshCompletionFile(filename, false) } // GenZshCompletionNoDesc generates zsh completion file without descriptions // and writes it to the passed writer. func (c *Command) GenZshCompletionNoDesc(w io.Writer) error { return c.genZshCompletion(w, false) } // MarkZshCompPositionalArgumentFile only worked for zsh and its behavior was // not consistent with Bash completion. It has therefore been disabled. // Instead, when no other completion is specified, file completion is done by // default for every argument. One can disable file completion on a per-argument // basis by using ValidArgsFunction and ShellCompDirectiveNoFileComp. // To achieve file extension filtering, one can use ValidArgsFunction and // ShellCompDirectiveFilterFileExt. // // Deprecated func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error { return nil } // MarkZshCompPositionalArgumentWords only worked for zsh. It has therefore // been disabled. // To achieve the same behavior across all shells, one can use // ValidArgs (for the first argument only) or ValidArgsFunction for // any argument (can include the first one also). // // Deprecated func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error { return nil } func (c *Command) genZshCompletionFile(filename string, includeDesc bool) error { outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() return c.genZshCompletion(outFile, includeDesc) } func (c *Command) genZshCompletion(w io.Writer, includeDesc bool) error { buf := new(bytes.Buffer) genZshComp(buf, c.Name(), includeDesc) _, err := buf.WriteTo(w) return err } func genZshComp(buf io.StringWriter, name string, includeDesc bool) { compCmd := ShellCompRequestCmd if !includeDesc { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s # zsh completion for %-36[1]s -*- shell-script -*- __%[1]s_debug() { local file="$BASH_COMP_DEBUG_FILE" if [[ -n ${file} ]]; then echo "$*" >> "${file}" fi } _%[1]s() { local shellCompDirectiveError=%[3]d local shellCompDirectiveNoSpace=%[4]d local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace local -a completions __%[1]s_debug "\n========= starting completion logic ==========" __%[1]s_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}" # The user could have moved the cursor backwards on the command-line. # We need to trigger completion from the $CURRENT location, so we need # to truncate the command-line ($words) up to the $CURRENT location. # (We cannot use $CURSOR as its value does not work when a command is an alias.) words=("${=words[1,CURRENT]}") __%[1]s_debug "Truncated words[*]: ${words[*]}," lastParam=${words[-1]} lastChar=${lastParam[-1]} __%[1]s_debug "lastParam: ${lastParam}, lastChar: ${lastChar}" # For zsh, when completing a flag with an = (e.g., %[1]s -n=) # completions must be prefixed with the flag setopt local_options BASH_REMATCH if [[ "${lastParam}" =~ '-.*=' ]]; then # We are dealing with a flag with an = flagPrefix="-P ${BASH_REMATCH}" fi # Prepare the command to obtain completions requestComp="${words[1]} %[2]s ${words[2,-1]}" if [ "${lastChar}" = "" ]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go completion code. __%[1]s_debug "Adding extra empty parameter" requestComp="${requestComp} \"\"" fi __%[1]s_debug "About to call: eval ${requestComp}" # Use eval to handle any environment variables and such out=$(eval ${requestComp} 2>/dev/null) __%[1]s_debug "completion output: ${out}" # Extract the directive integer following a : from the last line local lastLine while IFS='\n' read -r line; do lastLine=${line} done < <(printf "%%s\n" "${out[@]}") __%[1]s_debug "last line: ${lastLine}" if [ "${lastLine[1]}" = : ]; then directive=${lastLine[2,-1]} # Remove the directive including the : and the newline local suffix (( suffix=${#lastLine}+2)) out=${out[1,-$suffix]} else # There is no directive specified. Leave $out as is. __%[1]s_debug "No directive found. Setting do default" directive=0 fi __%[1]s_debug "directive: ${directive}" __%[1]s_debug "completions: ${out}" __%[1]s_debug "flagPrefix: ${flagPrefix}" if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then __%[1]s_debug "Completion received error. Ignoring completions." return fi while IFS='\n' read -r comp; do if [ -n "$comp" ]; then # If requested, completions are returned with a description. # The description is preceded by a TAB character. # For zsh's _describe, we need to use a : instead of a TAB. # We first need to escape any : as part of the completion itself. comp=${comp//:/\\:} local tab=$(printf '\t') comp=${comp//$tab/:} __%[1]s_debug "Adding completion: ${comp}" completions+=${comp} lastComp=$comp fi done < <(printf "%%s\n" "${out[@]}") if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then __%[1]s_debug "Activating nospace." noSpace="-S ''" fi if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local filteringCmd filteringCmd='_files' for filter in ${completions[@]}; do if [ ${filter[1]} != '*' ]; then # zsh requires a glob pattern to do file filtering filter="\*.$filter" fi filteringCmd+=" -g $filter" done filteringCmd+=" ${flagPrefix}" __%[1]s_debug "File filtering command: $filteringCmd" _arguments '*:filename:'"$filteringCmd" elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only local subdir subdir="${completions[1]}" if [ -n "$subdir" ]; then __%[1]s_debug "Listing directories in $subdir" pushd "${subdir}" >/dev/null 2>&1 else __%[1]s_debug "Listing directories in ." fi local result _arguments '*:dirname:_files -/'" ${flagPrefix}" result=$? if [ -n "$subdir" ]; then popd >/dev/null 2>&1 fi return $result else __%[1]s_debug "Calling _describe" if eval _describe "completions" completions $flagPrefix $noSpace; then __%[1]s_debug "_describe found some completions" # Return the success of having called _describe return 0 else __%[1]s_debug "_describe did not find completions." __%[1]s_debug "Checking if we should do file completion." if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then __%[1]s_debug "deactivating file completion" # We must return an error code here to let zsh know that there were no # completions found by _describe; this is what will trigger other # matching algorithms to attempt to find completions. # For example zsh can match letters in the middle of words. return 1 else # Perform file completion __%[1]s_debug "Activating file completion" # We must return the result of this command, so it must be the # last command, or else we must store its result to return it. _arguments '*:filename:_files'" ${flagPrefix}" fi fi fi } # don't run the completion function when being source-ed or eval-ed if [ "$funcstack[1]" = "_%[1]s" ]; then _%[1]s fi `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } cobra-1.3.0/zsh_completions.md000066400000000000000000000070771415616037300163640ustar00rootroot00000000000000## Generating Zsh Completion For Your cobra.Command Please refer to [Shell Completions](shell_completions.md) for details. ## Zsh completions standardization Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced. ### Deprecation summary See further below for more details on these deprecations. * `cmd.MarkZshCompPositionalArgumentFile(pos, []string{})` is no longer needed. It is therefore **deprecated** and silently ignored. * `cmd.MarkZshCompPositionalArgumentFile(pos, glob[])` is **deprecated** and silently ignored. * Instead use `ValidArgsFunction` with `ShellCompDirectiveFilterFileExt`. * `cmd.MarkZshCompPositionalArgumentWords()` is **deprecated** and silently ignored. * Instead use `ValidArgsFunction`. ### Behavioral changes **Noun completion** |Old behavior|New behavior| |---|---| |No file completion by default (opposite of bash)|File completion by default; use `ValidArgsFunction` with `ShellCompDirectiveNoFileComp` to turn off file completion on a per-argument basis| |Completion of flag names without the `-` prefix having been typed|Flag names are only completed if the user has typed the first `-`| `cmd.MarkZshCompPositionalArgumentFile(pos, []string{})` used to turn on file completion on a per-argument position basis|File completion for all arguments by default; `cmd.MarkZshCompPositionalArgumentFile()` is **deprecated** and silently ignored| |`cmd.MarkZshCompPositionalArgumentFile(pos, glob[])` used to turn on file completion **with glob filtering** on a per-argument position basis (zsh-specific)|`cmd.MarkZshCompPositionalArgumentFile()` is **deprecated** and silently ignored; use `ValidArgsFunction` with `ShellCompDirectiveFilterFileExt` for file **extension** filtering (not full glob filtering)| |`cmd.MarkZshCompPositionalArgumentWords(pos, words[])` used to provide completion choices on a per-argument position basis (zsh-specific)|`cmd.MarkZshCompPositionalArgumentWords()` is **deprecated** and silently ignored; use `ValidArgsFunction` to achieve the same behavior| **Flag-value completion** |Old behavior|New behavior| |---|---| |No file completion by default (opposite of bash)|File completion by default; use `RegisterFlagCompletionFunc()` with `ShellCompDirectiveNoFileComp` to turn off file completion| |`cmd.MarkFlagFilename(flag, []string{})` and similar used to turn on file completion|File completion by default; `cmd.MarkFlagFilename(flag, []string{})` no longer needed in this context and silently ignored| |`cmd.MarkFlagFilename(flag, glob[])` used to turn on file completion **with glob filtering** (syntax of `[]string{"*.yaml", "*.yml"}` incompatible with bash)|Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells (`[]string{"yaml", "yml"}`)| |`cmd.MarkFlagDirname(flag)` only completes directories (zsh-specific)|Has been added for all shells| |Completion of a flag name does not repeat, unless flag is of type `*Array` or `*Slice` (not supported by bash)|Retained for `zsh` and added to `fish`| |Completion of a flag name does not provide the `=` form (unlike bash)|Retained for `zsh` and added to `fish`| **Improvements** * Custom completion support (`ValidArgsFunction` and `RegisterFlagCompletionFunc()`) * File completion by default if no other completions found * Handling of required flags * File extension filtering no longer mutually exclusive with bash usage * Completion of directory names *within* another directory * Support for `=` form of flags