├── .github └── workflows │ ├── main.yml │ └── test ├── .gitignore ├── .idea ├── .gitignore ├── fenix-cli.iml ├── modules.xml └── vcs.xml ├── .travis.yml ├── LICENSE ├── README.md ├── README_CN.md ├── assets ├── 1.gif ├── 10.gif ├── 3.gif ├── 4.gif ├── 5.gif ├── 7.gif ├── 8.gif └── 9.gif ├── build └── build.sh ├── data ├── docker.xlsx ├── istio.xlsx └── kubernets.xlsx ├── go.mod ├── go.sum ├── lib ├── go-ansi │ ├── LICENSE.txt │ ├── README.md │ ├── cursor.go │ ├── cursor_windows.go │ ├── display.go │ ├── display_windows.go │ ├── output.go │ ├── output_windows.go │ ├── print.go │ └── syscall_windows.go ├── go-prompt │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── _example │ │ ├── README.md │ │ ├── build.sh │ │ ├── exec-command │ │ │ └── main.go │ │ ├── http-prompt │ │ │ ├── api.py │ │ │ └── main.go │ │ ├── live-prefix │ │ │ └── main.go │ │ └── simple-echo │ │ │ ├── cjk-cyrillic │ │ │ └── main.go │ │ │ └── main.go │ ├── _tools │ │ ├── README.md │ │ ├── complete_file │ │ │ └── main.go │ │ ├── sigwinch │ │ │ └── main.go │ │ └── vt100_debug │ │ │ └── main.go │ ├── buffer.go │ ├── buffer_test.go │ ├── completer │ │ └── file.go │ ├── completion.go │ ├── completion_test.go │ ├── document.go │ ├── document_test.go │ ├── emacs.go │ ├── emacs_test.go │ ├── filter.go │ ├── filter_test.go │ ├── go.mod │ ├── go.sum │ ├── history.go │ ├── history_test.go │ ├── input.go │ ├── input_posix.go │ ├── input_test.go │ ├── input_windows.go │ ├── internal │ │ ├── bisect │ │ │ ├── bisect.go │ │ │ └── bisect_test.go │ │ ├── debug │ │ │ ├── assert.go │ │ │ └── log.go │ │ └── strings │ │ │ ├── strings.go │ │ │ └── strings_test.go │ ├── key.go │ ├── key_bind.go │ ├── key_bind_func.go │ ├── key_string.go │ ├── option.go │ ├── output.go │ ├── output_posix.go │ ├── output_vt100.go │ ├── output_vt100_test.go │ ├── output_windows.go │ ├── prompt.go │ ├── render.go │ ├── render_test.go │ ├── shortcut.go │ ├── signal_posix.go │ ├── signal_windows.go │ └── term │ │ └── term.go ├── krew │ ├── .dockerignore │ ├── .gitignore │ ├── .golangci.yml │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── OWNERS │ ├── OWNERS_ALIASES │ ├── README.md │ ├── SECURITY_CONTACTS │ ├── assets │ │ └── logo │ │ │ ├── horizontal │ │ │ ├── black │ │ │ │ ├── krew-horizontal-black.png │ │ │ │ └── krew-horizontal-black.svg │ │ │ ├── color │ │ │ │ ├── krew-horizontal-color.png │ │ │ │ └── krew-horizontal-color.svg │ │ │ └── white │ │ │ │ ├── krew-horizontal-white.png │ │ │ │ └── krew-horizontal-white.svg │ │ │ ├── icon │ │ │ ├── black │ │ │ │ ├── krew-icon-black.png │ │ │ │ └── krew-icon-black.svg │ │ │ ├── color │ │ │ │ ├── krew-icon-color.png │ │ │ │ └── krew-icon-color.svg │ │ │ └── white │ │ │ │ ├── krew-icon-white.png │ │ │ │ └── krew-icon-white.svg │ │ │ └── stacked │ │ │ ├── black │ │ │ ├── krew-stacked-black.png │ │ │ └── krew-stacked-black.svg │ │ │ ├── color │ │ │ ├── krew-stacked-color.png │ │ │ └── krew-stacked-color.svg │ │ │ └── white │ │ │ ├── krew-stacked-white.png │ │ │ └── krew-stacked-white.svg │ ├── cmd │ │ ├── krew │ │ │ ├── cmd │ │ │ │ ├── hack.go │ │ │ │ ├── index.go │ │ │ │ ├── info.go │ │ │ │ ├── install.go │ │ │ │ ├── install_test.go │ │ │ │ ├── internal │ │ │ │ │ ├── fetch_tag.go │ │ │ │ │ ├── fetch_tag_test.go │ │ │ │ │ ├── security_notice.go │ │ │ │ │ ├── setup_check.go │ │ │ │ │ ├── setup_check_test.go │ │ │ │ │ └── warning.go │ │ │ │ ├── list.go │ │ │ │ ├── namingutils.go │ │ │ │ ├── namingutils_test.go │ │ │ │ ├── root.go │ │ │ │ ├── search.go │ │ │ │ ├── uninstall.go │ │ │ │ ├── update.go │ │ │ │ ├── upgrade.go │ │ │ │ └── version.go │ │ │ └── main.go │ │ └── validate-krew-manifest │ │ │ ├── main.go │ │ │ └── main_test.go │ ├── code-of-conduct.md │ ├── docs │ │ ├── CONTRIBUTOR_GUIDE.md │ │ ├── DEVELOPER_GUIDE.md │ │ ├── KREW_ARCHITECTURE.md │ │ ├── KREW_LOGO.md │ │ ├── NAMING_GUIDE.md │ │ ├── PLUGIN_LIFECYCLE.md │ │ ├── RELEASING_KREW.md │ │ ├── USER_GUIDE.md │ │ └── src │ │ │ ├── krew_general.svg │ │ │ ├── krew_installation.svg │ │ │ ├── krew_upgrade.svg │ │ │ └── krew_upgrade_self.svg │ ├── go.mod │ ├── go.sum │ ├── hack │ │ ├── boilerplate │ │ │ ├── boilerplate.Dockerfile.txt │ │ │ ├── boilerplate.Makefile.txt │ │ │ ├── boilerplate.go.txt │ │ │ ├── boilerplate.py │ │ │ ├── boilerplate.py.txt │ │ │ └── boilerplate.sh.txt │ │ ├── ensure-kubectl-installed.sh │ │ ├── install-gox.sh │ │ ├── krew.yaml │ │ ├── make-all.sh │ │ ├── make-binaries.sh │ │ ├── make-binary.sh │ │ ├── make-release-artifacts.sh │ │ ├── make-release-notes.sh │ │ ├── run-in-docker.sh │ │ ├── run-integration-tests.sh │ │ ├── run-lint.sh │ │ ├── run-tests.sh │ │ ├── sandboxed.Dockerfile │ │ ├── verify-boilerplate.sh │ │ ├── verify-code-patterns.sh │ │ ├── verify-index-migration.sh │ │ └── verify-installation.sh │ ├── integration_test │ │ ├── commandline_test.go │ │ ├── help_test.go │ │ ├── index_test.go │ │ ├── info_test.go │ │ ├── install_test.go │ │ ├── list_test.go │ │ ├── migration_test.go │ │ ├── search_test.go │ │ ├── testdata │ │ │ ├── ctx.yaml │ │ │ ├── foo.tar.gz │ │ │ └── foo.yaml │ │ ├── testutil_test.go │ │ ├── uninstall_test.go │ │ ├── update_test.go │ │ ├── upgrade_test.go │ │ └── version_test.go │ ├── internal │ │ ├── download │ │ │ ├── downloader.go │ │ │ ├── downloader_test.go │ │ │ ├── fetch.go │ │ │ ├── testdata │ │ │ │ ├── bash-ascii-file │ │ │ │ ├── bash-utf8-file │ │ │ │ ├── null-file │ │ │ │ ├── test-with-directory.zip │ │ │ │ ├── test-with-nesting-with-directory-entries.tar.gz │ │ │ │ ├── test-with-nesting-without-directory-entries.tar.gz │ │ │ │ ├── test-without-directory.tar.gz │ │ │ │ └── test-without-directory.zip │ │ │ ├── verifier.go │ │ │ └── verifier_test.go │ │ ├── environment │ │ │ ├── environment.go │ │ │ └── environment_test.go │ │ ├── gitutil │ │ │ └── git.go │ │ ├── index │ │ │ ├── indexoperations │ │ │ │ ├── index.go │ │ │ │ └── index_test.go │ │ │ ├── indexscanner │ │ │ │ ├── scanner.go │ │ │ │ ├── scanner_test.go │ │ │ │ └── testdata │ │ │ │ │ └── testindex │ │ │ │ │ ├── dontscan.yaml │ │ │ │ │ └── plugins │ │ │ │ │ ├── badplugin.yaml │ │ │ │ │ ├── badplugin2.yaml │ │ │ │ │ ├── bar.yaml │ │ │ │ │ ├── foo.yaml │ │ │ │ │ ├── notyaml.txt │ │ │ │ │ └── wrongname.yaml │ │ │ └── validation │ │ │ │ ├── validate.go │ │ │ │ └── validate_test.go │ │ ├── indexmigration │ │ │ ├── migration.go │ │ │ └── migration_test.go │ │ ├── installation │ │ │ ├── install.go │ │ │ ├── install_test.go │ │ │ ├── move.go │ │ │ ├── move_test.go │ │ │ ├── platform.go │ │ │ ├── platform_test.go │ │ │ ├── receipt │ │ │ │ ├── receipt.go │ │ │ │ └── receipt_test.go │ │ │ ├── semver │ │ │ │ ├── version.go │ │ │ │ └── version_test.go │ │ │ ├── testdata │ │ │ │ ├── bin │ │ │ │ │ └── kubectl-foo │ │ │ │ ├── index │ │ │ │ │ └── foo │ │ │ │ │ │ ├── AAAnotplugin │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ │ └── deadbeef │ │ │ │ │ │ ├── .gitkeep │ │ │ │ │ │ └── kubectl-foo │ │ │ │ ├── plugin-foo │ │ │ │ │ └── kubectl-foo │ │ │ │ ├── testdir_A │ │ │ │ │ ├── .secret │ │ │ │ │ └── notsecret │ │ │ │ └── testdir_B │ │ │ │ │ └── .gitkeep │ │ │ ├── upgrade.go │ │ │ ├── util.go │ │ │ └── util_test.go │ │ ├── pathutil │ │ │ ├── pathutil.go │ │ │ └── pathutil_test.go │ │ ├── receiptsmigration │ │ │ ├── migration.go │ │ │ └── migration_test.go │ │ ├── testutil │ │ │ ├── plugin.go │ │ │ ├── receipt.go │ │ │ └── tempdir.go │ │ └── version │ │ │ ├── version.go │ │ │ └── version_test.go │ ├── netlify.toml │ ├── pkg │ │ ├── constants │ │ │ └── constants.go │ │ └── index │ │ │ ├── types.go │ │ │ ├── util.go │ │ │ └── util_test.go │ └── site │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── config.yaml │ │ ├── content │ │ ├── _index.md │ │ ├── docs │ │ │ ├── _index.md │ │ │ ├── developer-guide │ │ │ │ ├── _index.md │ │ │ │ ├── custom-indexes.md │ │ │ │ ├── develop │ │ │ │ │ ├── _index.md │ │ │ │ │ ├── best-practices.md │ │ │ │ │ ├── naming-guide.md │ │ │ │ │ └── plugin-development.md │ │ │ │ ├── distributing-with-krew.md │ │ │ │ ├── example-plugin-manifests.md │ │ │ │ ├── installing-locally.md │ │ │ │ ├── plugin-manifest.md │ │ │ │ ├── plugin-stats.md │ │ │ │ └── release │ │ │ │ │ ├── _index.md │ │ │ │ │ ├── plugin-updates.md │ │ │ │ │ ├── release-automation.md │ │ │ │ │ └── submitting-to-krew.md │ │ │ └── user-guide │ │ │ │ ├── _index.md │ │ │ │ ├── configuration.md │ │ │ │ ├── install.md │ │ │ │ ├── list.md │ │ │ │ ├── quickstart.md │ │ │ │ ├── search.md │ │ │ │ ├── setup │ │ │ │ ├── _index.md │ │ │ │ ├── install.md │ │ │ │ ├── uninstall.md │ │ │ │ └── updates.md │ │ │ │ ├── uninstall.md │ │ │ │ ├── upgrade.md │ │ │ │ └── using-custom-indexes.md │ │ └── plugins.md │ │ ├── functions │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ └── server │ │ │ └── main.go │ │ ├── layouts │ │ ├── 404.html │ │ ├── _default │ │ │ └── single.html │ │ ├── docs │ │ │ └── section.html │ │ ├── index.html │ │ ├── partials │ │ │ ├── backbutton.html │ │ │ ├── footer.html │ │ │ ├── header.html │ │ │ ├── navbar.html │ │ │ └── toc.html │ │ ├── robots.txt │ │ └── shortcodes │ │ │ ├── output.html │ │ │ ├── prompt.html │ │ │ └── toc.html │ │ └── static │ │ ├── css │ │ └── style.css │ │ └── img │ │ ├── favicon.svg │ │ └── krew-logo.svg └── throttle │ └── throttle.go ├── main.go └── src ├── environments ├── commands.go ├── completer.go ├── composite_env.go ├── docker │ ├── commands.go │ ├── completer.go │ ├── docker_env.go │ ├── providers.go │ ├── remote_image_provider.go │ └── suggestion.go ├── executor.go ├── istio │ ├── commands.go │ ├── completer.go │ ├── istio_env.go │ └── suggestion.go ├── kubernetes │ ├── commands.go │ ├── completer.go │ ├── k8s_resources_providers.go │ ├── kube_env.go │ ├── providers.go │ └── suggestion.go └── version.go ├── internal ├── debug │ └── log.go ├── krew │ └── wrapper.go ├── template │ └── template.go └── util │ ├── cast.go │ ├── string.go │ └── term.go └── suggestions ├── generic_completer.go ├── generic_provider.go ├── static_provider.go └── types.go /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Create Fenix-CLI Release 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | tags: 7 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 8 | 9 | jobs: 10 | build: 11 | name: Create Release 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: actions/setup-go@v2 17 | with: 18 | go-version: '^1.16' 19 | 20 | - name: Build Fenix-CLI 21 | run: bash ./build/build.sh 22 | 23 | - name: Create Release 24 | uses: softprops/action-gh-release@v1 25 | if: startsWith(github.ref, 'refs/tags/') 26 | with: 27 | files: fenix-cli 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/.github/workflows/test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | main 3 | fenix-cli 4 | *.exe 5 | *.exe~ 6 | *.dll 7 | *.so 8 | *.dylib 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/fenix-cli.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.16" 5 | 6 | script: 7 | - bash ./build/build.sh 8 | 9 | deploy: 10 | provider: releases 11 | api_key: $GITHUB_TOKEN 12 | file: fenix-cli 13 | skip_cleanup: true 14 | on: 15 | tags: true -------------------------------------------------------------------------------- /assets/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/1.gif -------------------------------------------------------------------------------- /assets/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/10.gif -------------------------------------------------------------------------------- /assets/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/3.gif -------------------------------------------------------------------------------- /assets/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/4.gif -------------------------------------------------------------------------------- /assets/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/5.gif -------------------------------------------------------------------------------- /assets/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/7.gif -------------------------------------------------------------------------------- /assets/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/8.gif -------------------------------------------------------------------------------- /assets/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/assets/9.gif -------------------------------------------------------------------------------- /build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=$(git describe --tags --always) 4 | LDFLAGS="-s -w -X github.com/fenixsoft/fenix-cli/src/environments.Version=$VERSION" 5 | 6 | go build -ldflags "${LDFLAGS}" 7 | -------------------------------------------------------------------------------- /data/docker.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/data/docker.xlsx -------------------------------------------------------------------------------- /data/istio.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/data/istio.xlsx -------------------------------------------------------------------------------- /data/kubernets.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/data/kubernets.xlsx -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fenixsoft/fenix-cli 2 | 3 | require ( 4 | cloud.google.com/go v0.54.0 // indirect 5 | docker.io/go-docker v1.0.0 6 | github.com/AlecAivazis/survey/v2 v2.2.12 7 | github.com/Azure/go-autorest/autorest v0.11.12 // indirect 8 | github.com/Microsoft/go-winio v0.4.14 // indirect 9 | github.com/c-bata/go-prompt v0.2.6 10 | github.com/docker/distribution v2.7.1+incompatible // indirect 11 | github.com/docker/go-connections v0.4.0 // indirect 12 | github.com/docker/go-units v0.4.0 // indirect 13 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect 14 | github.com/hashicorp/go-hclog v0.9.2 // indirect 15 | github.com/hashicorp/go-retryablehttp v0.6.4 16 | github.com/imdario/mergo v0.3.5 // indirect 17 | github.com/mattn/go-runewidth v0.0.13 // indirect 18 | github.com/mattn/go-tty v0.0.3 // indirect 19 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect 20 | github.com/olekukonko/tablewriter v0.0.5 21 | github.com/opencontainers/go-digest v1.0.0-rc1 // indirect 22 | github.com/opencontainers/image-spec v1.0.1 // indirect 23 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 24 | github.com/peterbourgon/diskv v2.0.1+incompatible // indirect 25 | github.com/pkg/errors v0.9.1 // indirect 26 | github.com/schollz/progressbar/v3 v3.8.1 // indirect 27 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect 28 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 29 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect 30 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect 31 | k8s.io/api v0.21.1 32 | k8s.io/apimachinery v0.21.1 33 | k8s.io/client-go v0.21.1 34 | k8s.io/klog v1.0.0 35 | k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect 36 | sigs.k8s.io/krew v0.4.1 // indirect 37 | ) 38 | 39 | // hack for feature & bugfix 40 | replace github.com/c-bata/go-prompt v0.2.6 => ./lib/go-prompt 41 | 42 | replace sigs.k8s.io/krew v0.4.1 => ./lib/krew 43 | 44 | go 1.16 45 | -------------------------------------------------------------------------------- /lib/go-ansi/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Takashi Kokubun 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/go-ansi/cursor.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package ansi 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // Move the cursor n cells to up. 10 | func CursorUp(n int) { 11 | fmt.Printf("\x1b[%dA", n) 12 | } 13 | 14 | // Move the cursor n cells to down. 15 | func CursorDown(n int) { 16 | fmt.Printf("\x1b[%dB", n) 17 | } 18 | 19 | // Move the cursor n cells to right. 20 | func CursorForward(n int) { 21 | fmt.Printf("\x1b[%dC", n) 22 | } 23 | 24 | // Move the cursor n cells to left. 25 | func CursorBack(n int) { 26 | fmt.Printf("\x1b[%dD", n) 27 | } 28 | 29 | // Move cursor to beginning of the line n lines down. 30 | func CursorNextLine(n int) { 31 | fmt.Printf("\x1b[%dE", n) 32 | } 33 | 34 | // Move cursor to beginning of the line n lines up. 35 | func CursorPreviousLine(n int) { 36 | fmt.Printf("\x1b[%dF", n) 37 | } 38 | 39 | // Move cursor horizontally to x. 40 | func CursorHorizontalAbsolute(x int) { 41 | fmt.Printf("\x1b[%dG", x) 42 | } 43 | 44 | // Show the cursor. 45 | func CursorShow() { 46 | fmt.Print("\x1b[?25h") 47 | } 48 | 49 | // Hide the cursor. 50 | func CursorHide() { 51 | fmt.Print("\x1b[?25l") 52 | } 53 | -------------------------------------------------------------------------------- /lib/go-ansi/cursor_windows.go: -------------------------------------------------------------------------------- 1 | package ansi 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | func CursorUp(n int) { 10 | cursorMove(0, -n) 11 | } 12 | 13 | func CursorDown(n int) { 14 | cursorMove(0, n) 15 | } 16 | 17 | func CursorForward(n int) { 18 | cursorMove(n, 0) 19 | } 20 | 21 | func CursorBack(n int) { 22 | cursorMove(-n, 0) 23 | } 24 | 25 | func cursorMove(x int, y int) { 26 | handle := syscall.Handle(os.Stdout.Fd()) 27 | 28 | var csbi consoleScreenBufferInfo 29 | procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 30 | 31 | var cursor coord 32 | cursor.x = csbi.cursorPosition.x + short(x) 33 | cursor.y = csbi.cursorPosition.y + short(y) 34 | 35 | procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) 36 | } 37 | 38 | func CursorNextLine(n int) { 39 | CursorUp(n) 40 | CursorHorizontalAbsolute(0) 41 | } 42 | 43 | func CursorPreviousLine(n int) { 44 | CursorDown(n) 45 | CursorHorizontalAbsolute(0) 46 | } 47 | 48 | func CursorHorizontalAbsolute(x int) { 49 | handle := syscall.Handle(os.Stdout.Fd()) 50 | 51 | var csbi consoleScreenBufferInfo 52 | procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 53 | 54 | var cursor coord 55 | cursor.x = short(x) 56 | cursor.y = csbi.cursorPosition.y 57 | 58 | if csbi.size.x < cursor.x { 59 | cursor.x = csbi.size.x 60 | } 61 | 62 | procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) 63 | } 64 | 65 | func CursorShow() { 66 | handle := syscall.Handle(os.Stdout.Fd()) 67 | 68 | var cci consoleCursorInfo 69 | procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 70 | cci.visible = 1 71 | 72 | procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 73 | } 74 | 75 | func CursorHide() { 76 | handle := syscall.Handle(os.Stdout.Fd()) 77 | 78 | var cci consoleCursorInfo 79 | procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 80 | cci.visible = 0 81 | 82 | procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) 83 | } 84 | -------------------------------------------------------------------------------- /lib/go-ansi/display.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package ansi 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func EraseInLine(mode int) { 10 | fmt.Printf("\x1b[%dK", mode) 11 | } 12 | -------------------------------------------------------------------------------- /lib/go-ansi/display_windows.go: -------------------------------------------------------------------------------- 1 | package ansi 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | func EraseInLine(mode int) { 10 | handle := syscall.Handle(os.Stdout.Fd()) 11 | 12 | var csbi consoleScreenBufferInfo 13 | procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) 14 | 15 | var w uint32 16 | var x short 17 | cursor := csbi.cursorPosition 18 | switch mode { 19 | case 1: 20 | x = csbi.size.x 21 | case 2: 22 | x = 0 23 | case 3: 24 | cursor.x = 0 25 | x = csbi.size.x 26 | } 27 | procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w))) 28 | } 29 | -------------------------------------------------------------------------------- /lib/go-ansi/output.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package ansi 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | // Returns special stdout, which converts escape sequences to Windows API calls 11 | // on Windows environment. 12 | func NewAnsiStdout() io.Writer { 13 | return os.Stdout 14 | } 15 | 16 | // Returns special stderr, which converts escape sequences to Windows API calls 17 | // on Windows environment. 18 | func NewAnsiStderr() io.Writer { 19 | return os.Stderr 20 | } 21 | -------------------------------------------------------------------------------- /lib/go-ansi/print.go: -------------------------------------------------------------------------------- 1 | package ansi 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var ( 8 | ansiStdout = NewAnsiStdout() 9 | ) 10 | 11 | // Print prints given arguments with escape sequence conversion for windows. 12 | func Print(a ...interface{}) (n int, err error) { 13 | return fmt.Fprint(ansiStdout, a...) 14 | } 15 | 16 | // Printf prints a given format with escape sequence conversion for windows. 17 | func Printf(format string, a ...interface{}) (n int, err error) { 18 | return fmt.Fprintf(ansiStdout, format, a...) 19 | } 20 | 21 | // Println prints given arguments with newline and escape sequence conversion 22 | // for windows. 23 | func Println(a ...interface{}) (n int, err error) { 24 | return fmt.Fprintln(ansiStdout, a...) 25 | } 26 | -------------------------------------------------------------------------------- /lib/go-ansi/syscall_windows.go: -------------------------------------------------------------------------------- 1 | package ansi 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | var ( 8 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 9 | procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 10 | procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") 11 | procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") 12 | procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") 13 | procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") 14 | procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") 15 | ) 16 | 17 | type wchar uint16 18 | type short int16 19 | type dword uint32 20 | type word uint16 21 | 22 | type coord struct { 23 | x short 24 | y short 25 | } 26 | 27 | type smallRect struct { 28 | left short 29 | top short 30 | right short 31 | bottom short 32 | } 33 | 34 | type consoleScreenBufferInfo struct { 35 | size coord 36 | cursorPosition coord 37 | attributes word 38 | window smallRect 39 | maximumWindowSize coord 40 | } 41 | 42 | type consoleCursorInfo struct { 43 | size dword 44 | visible int32 45 | } 46 | -------------------------------------------------------------------------------- /lib/go-prompt/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | bin/ 6 | 7 | # Folders 8 | pkg/ 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.cgo1.go 14 | *.cgo2.c 15 | _cgo_defun.c 16 | _cgo_gotypes.go 17 | _cgo_export.* 18 | 19 | _testmain.go 20 | 21 | *.exe 22 | *.test 23 | *.prof 24 | 25 | # Glide 26 | vendor/ 27 | -------------------------------------------------------------------------------- /lib/go-prompt/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Masashi SHIBATA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/go-prompt/Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := help 2 | 3 | SOURCES := $(shell find . -prune -o -name "*.go" -not -name '*_test.go' -print) 4 | 5 | GOIMPORTS ?= goimports 6 | GOCILINT ?= golangci-lint 7 | 8 | .PHONY: setup 9 | setup: ## Setup for required tools. 10 | go get -u golang.org/x/tools/cmd/goimports 11 | go get -u github.com/golangci/golangci-lint/cmd/golangci-lint 12 | go get -u golang.org/x/tools/cmd/stringer 13 | 14 | .PHONY: fmt 15 | fmt: $(SOURCES) ## Formatting source codes. 16 | @$(GOIMPORTS) -w $^ 17 | 18 | .PHONY: lint 19 | lint: ## Run golangci-lint. 20 | @$(GOCILINT) run --no-config --disable-all --enable=goimports --enable=misspell ./... 21 | 22 | .PHONY: test 23 | test: ## Run tests with race condition checking. 24 | @go test -race ./... 25 | 26 | .PHONY: bench 27 | bench: ## Run benchmarks. 28 | @go test -bench=. -run=- -benchmem ./... 29 | 30 | .PHONY: coverage 31 | cover: ## Run the tests. 32 | @go test -coverprofile=coverage.o 33 | @go tool cover -func=coverage.o 34 | 35 | .PHONY: generate 36 | generate: ## Run go generate 37 | @go generate ./... 38 | 39 | .PHONY: build 40 | build: ## Build example command lines. 41 | ./_example/build.sh 42 | 43 | .PHONY: help 44 | help: ## Show help text 45 | @echo "Commands:" 46 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-10s\033[0m %s\n", $$1, $$2}' 47 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/README.md: -------------------------------------------------------------------------------- 1 | # Examples of go-prompt 2 | 3 | This directory includes some examples using go-prompt. 4 | These examples are useful to know the usage of go-prompt and check behavior for development. 5 | 6 | ## simple-echo 7 | 8 | ![simple-input](https://github.com/c-bata/assets/raw/master/go-prompt/examples/input.gif) 9 | 10 | A simple echo example using `prompt.Input`. 11 | 12 | ## http-prompt 13 | 14 | ![http-prompt](https://github.com/c-bata/assets/raw/master/go-prompt/examples/http-prompt.gif) 15 | 16 | A simple [http-prompt](https://github.com/eliangcs/http-prompt) implementation using go-prompt in less than 200 lines of Go. 17 | 18 | ## live-prefix 19 | 20 | ![live-prefix](https://github.com/c-bata/assets/raw/master/go-prompt/examples/live-prefix.gif) 21 | 22 | A example application which changes a prefix string dynamically. 23 | This feature is used like [ktr0731/evans](https://github.com/ktr0731/evans) which is interactive gRPC client using go-prompt. 24 | 25 | ## exec-command 26 | 27 | Run another CLI tool via `os/exec` package. 28 | More practical example is [a source code of kube-prompt](https://github.com/c-bata/kube-prompt). 29 | I recommend you to look this if you want to create tools like kube-prompt. 30 | 31 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export GO111MODULE=on 4 | DIR=$(cd $(dirname $0); pwd) 5 | BIN_DIR=$(cd $(dirname $(dirname $0)); pwd)/bin 6 | 7 | mkdir -p ${BIN_DIR} 8 | go build -o ${BIN_DIR}/exec-command ${DIR}/exec-command/main.go 9 | go build -o ${BIN_DIR}/http-prompt ${DIR}/http-prompt/main.go 10 | go build -o ${BIN_DIR}/live-prefix ${DIR}/live-prefix/main.go 11 | go build -o ${BIN_DIR}/simple-echo ${DIR}/simple-echo/main.go 12 | go build -o ${BIN_DIR}/simple-echo-cjk-cyrillic ${DIR}/simple-echo/cjk-cyrillic/main.go 13 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/exec-command/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | 7 | prompt "github.com/c-bata/go-prompt" 8 | ) 9 | 10 | func executor(t string) { 11 | if t == "bash" { 12 | cmd := exec.Command("bash") 13 | cmd.Stdin = os.Stdin 14 | cmd.Stdout = os.Stdout 15 | cmd.Stderr = os.Stderr 16 | cmd.Run() 17 | } 18 | return 19 | } 20 | 21 | func completer(t prompt.Document) []prompt.Suggest { 22 | return []prompt.Suggest{ 23 | {Text: "bash"}, 24 | } 25 | } 26 | 27 | func main() { 28 | p := prompt.New( 29 | executor, 30 | completer, 31 | ) 32 | p.Run() 33 | } 34 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/http-prompt/api.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run, request 2 | 3 | @route('/') 4 | def hello(): 5 | return "Hello World!" 6 | 7 | @route('/ping') 8 | def hello(): 9 | return "pong!" 10 | 11 | @route('/register', method='POST') 12 | def register(): 13 | name = request.json.get("name") 14 | return "Hello %s!" % name 15 | 16 | if __name__ == "__main__": 17 | run(host='localhost', port=8000, debug=True) 18 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/live-prefix/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | prompt "github.com/c-bata/go-prompt" 7 | ) 8 | 9 | var LivePrefixState struct { 10 | LivePrefix string 11 | IsEnable bool 12 | } 13 | 14 | func executor(in string) { 15 | fmt.Println("Your input: " + in) 16 | if in == "" { 17 | LivePrefixState.IsEnable = false 18 | LivePrefixState.LivePrefix = in 19 | return 20 | } 21 | LivePrefixState.LivePrefix = in + "> " 22 | LivePrefixState.IsEnable = true 23 | } 24 | 25 | func completer(in prompt.Document) []prompt.Suggest { 26 | s := []prompt.Suggest{ 27 | {Text: "users", Description: "Store the username and age"}, 28 | {Text: "articles", Description: "Store the article text posted by user"}, 29 | {Text: "comments", Description: "Store the text commented to articles"}, 30 | {Text: "groups", Description: "Combine users with specific rules"}, 31 | } 32 | return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true) 33 | } 34 | 35 | func changeLivePrefix() (string, bool) { 36 | return LivePrefixState.LivePrefix, LivePrefixState.IsEnable 37 | } 38 | 39 | func main() { 40 | p := prompt.New( 41 | executor, 42 | completer, 43 | prompt.OptionPrefix(">>> "), 44 | prompt.OptionLivePrefix(changeLivePrefix), 45 | prompt.OptionTitle("live-prefix-example"), 46 | ) 47 | p.Run() 48 | } 49 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/simple-echo/cjk-cyrillic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | prompt "github.com/c-bata/go-prompt" 7 | ) 8 | 9 | func executor(in string) { 10 | fmt.Println("Your input: " + in) 11 | } 12 | 13 | func completer(in prompt.Document) []prompt.Suggest { 14 | s := []prompt.Suggest{ 15 | {Text: "こんにちは", Description: "'こんにちは' means 'Hello' in Japanese"}, 16 | {Text: "감사합니다", Description: "'안녕하세요' means 'Hello' in Korean."}, 17 | {Text: "您好", Description: "'您好' means 'Hello' in Chinese."}, 18 | {Text: "Добрый день", Description: "'Добрый день' means 'Hello' in Russian."}, 19 | } 20 | return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true) 21 | } 22 | 23 | func main() { 24 | p := prompt.New( 25 | executor, 26 | completer, 27 | prompt.OptionPrefix(">>> "), 28 | prompt.OptionTitle("sql-prompt for multi width characters"), 29 | ) 30 | p.Run() 31 | } 32 | -------------------------------------------------------------------------------- /lib/go-prompt/_example/simple-echo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | prompt "github.com/c-bata/go-prompt" 7 | ) 8 | 9 | func completer(in prompt.Document) []prompt.Suggest { 10 | s := []prompt.Suggest{ 11 | {Text: "users", Description: "Store the username and age"}, 12 | {Text: "articles", Description: "Store the article text posted by user"}, 13 | {Text: "comments", Description: "Store the text commented to articles"}, 14 | {Text: "groups", Description: "Combine users with specific rules"}, 15 | } 16 | return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true) 17 | } 18 | 19 | func main() { 20 | in := prompt.Input(">>> ", completer, 21 | prompt.OptionTitle("sql-prompt"), 22 | prompt.OptionHistory([]string{"SELECT * FROM users;"}), 23 | prompt.OptionPrefixTextColor(prompt.Yellow), 24 | prompt.OptionPreviewSuggestionTextColor(prompt.Blue), 25 | prompt.OptionSelectedSuggestionBGColor(prompt.LightGray), 26 | prompt.OptionSuggestionBGColor(prompt.DarkGray)) 27 | fmt.Println("Your input: " + in) 28 | } 29 | -------------------------------------------------------------------------------- /lib/go-prompt/_tools/README.md: -------------------------------------------------------------------------------- 1 | ## Tools of go-prompt 2 | 3 | ### vt100_debug 4 | 5 | ![vt100_debug](https://github.com/c-bata/assets/raw/master/go-prompt/tools/vt100_debug.gif) 6 | 7 | ### sigwinch 8 | 9 | ![sigwinch](https://github.com/c-bata/assets/raw/master/go-prompt/tools/sigwinch.gif) 10 | 11 | -------------------------------------------------------------------------------- /lib/go-prompt/_tools/complete_file/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | 8 | prompt "github.com/c-bata/go-prompt" 9 | "github.com/c-bata/go-prompt/completer" 10 | ) 11 | 12 | var filePathCompleter = completer.FilePathCompleter{ 13 | IgnoreCase: true, 14 | Filter: func(fi os.FileInfo) bool { 15 | return fi.IsDir() || strings.HasSuffix(fi.Name(), ".go") 16 | }, 17 | } 18 | 19 | func executor(in string) { 20 | fmt.Println("Your input: " + in) 21 | } 22 | 23 | func completerFunc(d prompt.Document) []prompt.Suggest { 24 | t := d.GetWordBeforeCursor() 25 | if strings.HasPrefix(t, "--") { 26 | return []prompt.Suggest{ 27 | {"--foo", ""}, 28 | {"--bar", ""}, 29 | {"--baz", ""}, 30 | } 31 | } 32 | return filePathCompleter.Complete(d) 33 | } 34 | 35 | func main() { 36 | p := prompt.New( 37 | executor, 38 | completerFunc, 39 | prompt.OptionPrefix(">>> "), 40 | prompt.OptionCompletionWordSeparator(completer.FilePathCompletionSeparator), 41 | ) 42 | p.Run() 43 | } 44 | -------------------------------------------------------------------------------- /lib/go-prompt/_tools/sigwinch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | // Winsize is winsize struct got from the ioctl(2) system call. 12 | type Winsize struct { 13 | Row uint16 14 | Col uint16 15 | X uint16 // pixel value 16 | Y uint16 // pixel value 17 | } 18 | 19 | // GetWinSize returns winsize struct which is the response of ioctl(2). 20 | func GetWinSize(fd int) *Winsize { 21 | ws := &Winsize{} 22 | retCode, _, errno := syscall.Syscall( 23 | syscall.SYS_IOCTL, 24 | uintptr(fd), 25 | uintptr(syscall.TIOCGWINSZ), 26 | uintptr(unsafe.Pointer(ws))) 27 | 28 | if int(retCode) == -1 { 29 | panic(errno) 30 | } 31 | return ws 32 | } 33 | 34 | func main() { 35 | signalChan := make(chan os.Signal, 1) 36 | signal.Notify( 37 | signalChan, 38 | syscall.SIGHUP, 39 | syscall.SIGINT, 40 | syscall.SIGTERM, 41 | syscall.SIGQUIT, 42 | syscall.SIGWINCH, 43 | ) 44 | ws := GetWinSize(syscall.Stdin) 45 | fmt.Printf("Row %d : Col %d\n", ws.Row, ws.Col) 46 | 47 | exitChan := make(chan int) 48 | go func() { 49 | for { 50 | s := <-signalChan 51 | switch s { 52 | // kill -SIGHUP XXXX 53 | case syscall.SIGHUP: 54 | exitChan <- 0 55 | 56 | // kill -SIGINT XXXX or Ctrl+c 57 | case syscall.SIGINT: 58 | exitChan <- 0 59 | 60 | // kill -SIGTERM XXXX 61 | case syscall.SIGTERM: 62 | exitChan <- 0 63 | 64 | // kill -SIGQUIT XXXX 65 | case syscall.SIGQUIT: 66 | exitChan <- 0 67 | 68 | case syscall.SIGWINCH: 69 | ws := GetWinSize(syscall.Stdin) 70 | fmt.Printf("Row %d : Col %d\n", ws.Row, ws.Col) 71 | 72 | default: 73 | exitChan <- 1 74 | } 75 | } 76 | }() 77 | 78 | code := <-exitChan 79 | os.Exit(code) 80 | } 81 | -------------------------------------------------------------------------------- /lib/go-prompt/_tools/vt100_debug/main.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "syscall" 8 | 9 | prompt "github.com/c-bata/go-prompt" 10 | "github.com/c-bata/go-prompt/term" 11 | ) 12 | 13 | func main() { 14 | if err := term.SetRaw(syscall.Stdin); err != nil { 15 | fmt.Println(err) 16 | return 17 | } 18 | defer term.Restore() 19 | 20 | bufCh := make(chan []byte, 128) 21 | go readBuffer(bufCh) 22 | fmt.Print("> ") 23 | 24 | for { 25 | b := <-bufCh 26 | if key := prompt.GetKey(b); key == prompt.NotDefined { 27 | fmt.Printf("Key '%s' data:'%#v'\n", string(b), b) 28 | } else { 29 | if key == prompt.ControlC { 30 | fmt.Println("exit.") 31 | return 32 | } 33 | fmt.Printf("Key '%s' data:'%#v'\n", key, b) 34 | } 35 | fmt.Print("> ") 36 | } 37 | } 38 | 39 | func readBuffer(bufCh chan []byte) { 40 | buf := make([]byte, 1024) 41 | 42 | for { 43 | if n, err := syscall.Read(syscall.Stdin, buf); err == nil { 44 | bufCh <- buf[:n] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/go-prompt/emacs_test.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | import "testing" 4 | 5 | func TestEmacsKeyBindings(t *testing.T) { 6 | buf := NewBuffer() 7 | buf.InsertText("abcde", false, true) 8 | if buf.cursorPosition != len("abcde") { 9 | t.Errorf("Want %d, but got %d", len("abcde"), buf.cursorPosition) 10 | } 11 | 12 | // Go to the beginning of the line 13 | applyEmacsKeyBind(buf, ControlA) 14 | if buf.cursorPosition != 0 { 15 | t.Errorf("Want %d, but got %d", 0, buf.cursorPosition) 16 | } 17 | 18 | // Go to the end of the line 19 | applyEmacsKeyBind(buf, ControlE) 20 | if buf.cursorPosition != len("abcde") { 21 | t.Errorf("Want %d, but got %d", len("abcde"), buf.cursorPosition) 22 | } 23 | } 24 | 25 | func applyEmacsKeyBind(buf *Buffer, key Key) { 26 | for i := range emacsKeyBindings { 27 | kb := emacsKeyBindings[i] 28 | if kb.Key == key { 29 | kb.Fn(buf) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/go-prompt/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/c-bata/go-prompt 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/mattn/go-colorable v0.1.7 7 | github.com/mattn/go-runewidth v0.0.9 8 | github.com/mattn/go-tty v0.0.3 9 | github.com/pkg/term v1.2.0-beta.2 10 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff 11 | ) 12 | -------------------------------------------------------------------------------- /lib/go-prompt/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 2 | github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= 3 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 4 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 5 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 6 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 7 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 8 | github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 9 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 10 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 11 | github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= 12 | github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= 13 | github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= 14 | github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= 15 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 16 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 17 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 18 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 19 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 20 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 21 | golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 22 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= 23 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 24 | -------------------------------------------------------------------------------- /lib/go-prompt/history.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | // History stores the texts that are entered. 4 | type History struct { 5 | histories []string 6 | tmp []string 7 | selected int 8 | } 9 | 10 | // Add to add text in history. 11 | func (h *History) Add(input string) { 12 | h.histories = append(h.histories, input) 13 | h.Clear() 14 | } 15 | 16 | // Clear to clear the history. 17 | func (h *History) Clear() { 18 | h.tmp = make([]string, len(h.histories)) 19 | for i := range h.histories { 20 | h.tmp[i] = h.histories[i] 21 | } 22 | h.tmp = append(h.tmp, "") 23 | h.selected = len(h.tmp) - 1 24 | } 25 | 26 | // Older saves a buffer of current line and get a buffer of previous line by up-arrow. 27 | // The changes of line buffers are stored until new history is created. 28 | func (h *History) Older(buf *Buffer) (new *Buffer, changed bool) { 29 | if len(h.tmp) == 1 || h.selected == 0 { 30 | return buf, false 31 | } 32 | h.tmp[h.selected] = buf.Text() 33 | 34 | h.selected-- 35 | new = NewBuffer() 36 | new.InsertText(h.tmp[h.selected], false, true) 37 | return new, true 38 | } 39 | 40 | // Newer saves a buffer of current line and get a buffer of next line by up-arrow. 41 | // The changes of line buffers are stored until new history is created. 42 | func (h *History) Newer(buf *Buffer) (new *Buffer, changed bool) { 43 | if h.selected >= len(h.tmp)-1 { 44 | return buf, false 45 | } 46 | h.tmp[h.selected] = buf.Text() 47 | 48 | h.selected++ 49 | new = NewBuffer() 50 | new.InsertText(h.tmp[h.selected], false, true) 51 | return new, true 52 | } 53 | 54 | // NewHistory returns new history object. 55 | func NewHistory() *History { 56 | return &History{ 57 | histories: []string{}, 58 | tmp: []string{""}, 59 | selected: 0, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/go-prompt/history_test.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestHistoryClear(t *testing.T) { 9 | h := NewHistory() 10 | h.Add("foo") 11 | h.Clear() 12 | expected := &History{ 13 | histories: []string{"foo"}, 14 | tmp: []string{"foo", ""}, 15 | selected: 1, 16 | } 17 | if !reflect.DeepEqual(expected, h) { 18 | t.Errorf("Should be %#v, but got %#v", expected, h) 19 | } 20 | } 21 | 22 | func TestHistoryAdd(t *testing.T) { 23 | h := NewHistory() 24 | h.Add("echo 1") 25 | expected := &History{ 26 | histories: []string{"echo 1"}, 27 | tmp: []string{"echo 1", ""}, 28 | selected: 1, 29 | } 30 | if !reflect.DeepEqual(h, expected) { 31 | t.Errorf("Should be %v, but got %v", expected, h) 32 | } 33 | } 34 | 35 | func TestHistoryOlder(t *testing.T) { 36 | h := NewHistory() 37 | h.Add("echo 1") 38 | 39 | // Prepare buffer 40 | buf := NewBuffer() 41 | buf.InsertText("echo 2", false, true) 42 | 43 | // [1 time] Call Older function 44 | buf1, changed := h.Older(buf) 45 | if !changed { 46 | t.Error("Should be changed history but not changed.") 47 | } 48 | if buf1.Text() != "echo 1" { 49 | t.Errorf("Should be %#v, but got %#v", "echo 1", buf1.Text()) 50 | } 51 | 52 | // [2 times] Call Older function 53 | buf = NewBuffer() 54 | buf.InsertText("echo 1", false, true) 55 | buf2, changed := h.Older(buf) 56 | if changed { 57 | t.Error("Should be not changed history but changed.") 58 | } 59 | if !reflect.DeepEqual("echo 1", buf2.Text()) { 60 | t.Errorf("Should be %#v, but got %#v", "echo 1", buf2.Text()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/go-prompt/input_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | 9 | "github.com/c-bata/go-prompt/term" 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | const maxReadBytes = 1024 14 | 15 | // PosixParser is a ConsoleParser implementation for POSIX environment. 16 | type PosixParser struct { 17 | fd int 18 | origTermios syscall.Termios 19 | } 20 | 21 | // Setup should be called before starting input 22 | func (t *PosixParser) Setup() error { 23 | // Set NonBlocking mode because if syscall.Read block this goroutine, it cannot receive data from stopCh. 24 | if err := syscall.SetNonblock(t.fd, true); err != nil { 25 | return err 26 | } 27 | term.GetOriginalTermios(t.fd) 28 | if err := term.SetRaw(t.fd); err != nil { 29 | return err 30 | } 31 | return nil 32 | } 33 | 34 | // TearDown should be called after stopping input 35 | func (t *PosixParser) TearDown() error { 36 | if err := syscall.SetNonblock(t.fd, false); err != nil { 37 | return err 38 | } 39 | if err := term.Restore(t.fd); err != nil { 40 | return err 41 | } 42 | return nil 43 | } 44 | 45 | // Read returns byte array. 46 | func (t *PosixParser) Read() ([]byte, error) { 47 | buf := make([]byte, maxReadBytes) 48 | n, err := syscall.Read(t.fd, buf) 49 | if err != nil { 50 | return []byte{}, err 51 | } 52 | return buf[:n], nil 53 | } 54 | 55 | // GetWinSize returns WinSize object to represent width and height of terminal. 56 | func (t *PosixParser) GetWinSize() *WinSize { 57 | ws, err := unix.IoctlGetWinsize(t.fd, unix.TIOCGWINSZ) 58 | if err != nil { 59 | // If this errors, we simply return the default window size as 60 | // it's our best guess. 61 | return &WinSize{ 62 | Row: 25, 63 | Col: 80, 64 | } 65 | } 66 | return &WinSize{ 67 | Row: ws.Row, 68 | Col: ws.Col, 69 | } 70 | } 71 | 72 | var _ ConsoleParser = &PosixParser{} 73 | 74 | // NewStandardInputParser returns ConsoleParser object to read from stdin. 75 | func NewStandardInputParser() *PosixParser { 76 | in, err := syscall.Open("/dev/tty", syscall.O_RDONLY, 0) 77 | if os.IsNotExist(err) { 78 | in = syscall.Stdin 79 | } else if err != nil { 80 | panic(err) 81 | } 82 | 83 | return &PosixParser{ 84 | fd: in, 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/go-prompt/input_test.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestPosixParserGetKey(t *testing.T) { 8 | scenarioTable := []struct { 9 | name string 10 | input []byte 11 | expected Key 12 | }{ 13 | { 14 | name: "escape", 15 | input: []byte{0x1b}, 16 | expected: Escape, 17 | }, 18 | { 19 | name: "undefined", 20 | input: []byte{'a'}, 21 | expected: NotDefined, 22 | }, 23 | } 24 | 25 | for _, s := range scenarioTable { 26 | t.Run(s.name, func(t *testing.T) { 27 | key := GetKey(s.input) 28 | if key != s.expected { 29 | t.Errorf("Should be %s, but got %s", key, s.expected) 30 | } 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/go-prompt/input_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "errors" 7 | "syscall" 8 | "unicode/utf8" 9 | "unsafe" 10 | 11 | tty "github.com/mattn/go-tty" 12 | ) 13 | 14 | const maxReadBytes = 1024 15 | 16 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 17 | 18 | var procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents") 19 | 20 | // WindowsParser is a ConsoleParser implementation for Win32 console. 21 | type WindowsParser struct { 22 | tty *tty.TTY 23 | } 24 | 25 | // Setup should be called before starting input 26 | func (p *WindowsParser) Setup() error { 27 | t, err := tty.Open() 28 | if err != nil { 29 | return err 30 | } 31 | p.tty = t 32 | return nil 33 | } 34 | 35 | // TearDown should be called after stopping input 36 | func (p *WindowsParser) TearDown() error { 37 | return p.tty.Close() 38 | } 39 | 40 | // Read returns byte array. 41 | func (p *WindowsParser) Read() ([]byte, error) { 42 | var ev uint32 43 | r0, _, err := procGetNumberOfConsoleInputEvents.Call(p.tty.Input().Fd(), uintptr(unsafe.Pointer(&ev))) 44 | if r0 == 0 { 45 | return nil, err 46 | } 47 | if ev == 0 { 48 | return nil, errors.New("EAGAIN") 49 | } 50 | 51 | r, err := p.tty.ReadRune() 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | buf := make([]byte, maxReadBytes) 57 | n := utf8.EncodeRune(buf[:], r) 58 | for p.tty.Buffered() && n < maxReadBytes { 59 | r, err := p.tty.ReadRune() 60 | if err != nil { 61 | break 62 | } 63 | n += utf8.EncodeRune(buf[n:], r) 64 | } 65 | return buf[:n], nil 66 | } 67 | 68 | // GetWinSize returns WinSize object to represent width and height of terminal. 69 | func (p *WindowsParser) GetWinSize() *WinSize { 70 | w, h, err := p.tty.Size() 71 | if err != nil { 72 | panic(err) 73 | } 74 | return &WinSize{ 75 | Row: uint16(h), 76 | Col: uint16(w), 77 | } 78 | } 79 | 80 | // NewStandardInputParser returns ConsoleParser object to read from stdin. 81 | func NewStandardInputParser() *WindowsParser { 82 | return &WindowsParser{} 83 | } 84 | -------------------------------------------------------------------------------- /lib/go-prompt/internal/bisect/bisect.go: -------------------------------------------------------------------------------- 1 | package bisect 2 | 3 | import "sort" 4 | 5 | // Right to locate the insertion point for v in a to maintain sorted order. 6 | func Right(a []int, v int) int { 7 | return bisectRightRange(a, v, 0, len(a)) 8 | } 9 | 10 | func bisectRightRange(a []int, v int, lo, hi int) int { 11 | s := a[lo:hi] 12 | return sort.Search(len(s), func(i int) bool { 13 | return s[i] > v 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /lib/go-prompt/internal/bisect/bisect_test.go: -------------------------------------------------------------------------------- 1 | package bisect_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/c-bata/go-prompt/internal/bisect" 6 | "math/rand" 7 | "testing" 8 | ) 9 | 10 | func Example() { 11 | in := []int{1, 2, 3, 3, 3, 6, 7} 12 | fmt.Println("Insertion position for 0 in the slice is", bisect.Right(in, 0)) 13 | fmt.Println("Insertion position for 4 in the slice is", bisect.Right(in, 4)) 14 | 15 | // Output: 16 | // Insertion position for 0 in the slice is 0 17 | // Insertion position for 4 in the slice is 5 18 | } 19 | 20 | func TestBisectRight(t *testing.T) { 21 | // Thanks!! https://play.golang.org/p/y9NRj_XVIW 22 | in := []int{1, 2, 3, 3, 3, 6, 7} 23 | 24 | r := bisect.Right(in, 0) 25 | if r != 0 { 26 | t.Errorf("number 0 should inserted at 0 position, but got %d", r) 27 | } 28 | 29 | r = bisect.Right(in, 4) 30 | if r != 5 { 31 | t.Errorf("number 4 should inserted at 5 position, but got %d", r) 32 | } 33 | } 34 | 35 | func BenchmarkRight(b *testing.B) { 36 | rand.Seed(0) 37 | 38 | for _, l := range []int{10, 1e2, 1e3, 1e4} { 39 | x := rand.Perm(l) 40 | insertion := rand.Int() 41 | 42 | b.Run(fmt.Sprintf("arrayLength=%d", l), func(b *testing.B) { 43 | b.ResetTimer() 44 | for n := 0; n < b.N; n++ { 45 | bisect.Right(x, insertion) 46 | } 47 | }) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/go-prompt/internal/debug/assert.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | const ( 9 | envAssertPanic = "GO_PROMPT_ENABLE_ASSERT" 10 | ) 11 | 12 | var ( 13 | enableAssert bool 14 | ) 15 | 16 | func init() { 17 | if e := os.Getenv(envAssertPanic); e == "true" || e == "1" { 18 | enableAssert = true 19 | } 20 | } 21 | 22 | // Assert ensures expected condition. 23 | func Assert(cond bool, msg interface{}) { 24 | if cond { 25 | return 26 | } 27 | if enableAssert { 28 | panic(msg) 29 | } 30 | writeWithSync(2, "[ASSERT] "+toString(msg)) 31 | } 32 | 33 | func toString(v interface{}) string { 34 | switch a := v.(type) { 35 | case func() string: 36 | return a() 37 | case string: 38 | return a 39 | case fmt.Stringer: 40 | return a.String() 41 | default: 42 | return fmt.Sprintf("unexpected type, %t", v) 43 | } 44 | } 45 | 46 | // AssertNoError ensures err is nil. 47 | func AssertNoError(err error) { 48 | if err == nil { 49 | return 50 | } 51 | if enableAssert { 52 | panic(err) 53 | } 54 | writeWithSync(2, "[ASSERT] "+err.Error()) 55 | } 56 | -------------------------------------------------------------------------------- /lib/go-prompt/internal/debug/log.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | ) 8 | 9 | const ( 10 | envEnableLog = "GO_PROMPT_ENABLE_LOG" 11 | logFileName = "go-prompt.log" 12 | ) 13 | 14 | var ( 15 | logfile *os.File 16 | logger *log.Logger 17 | ) 18 | 19 | func init() { 20 | if e := os.Getenv(envEnableLog); e == "true" || e == "1" { 21 | var err error 22 | logfile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 23 | if err == nil { 24 | logger = log.New(logfile, "", log.Llongfile) 25 | return 26 | } 27 | } 28 | logger = log.New(ioutil.Discard, "", log.Llongfile) 29 | } 30 | 31 | // Teardown to close logfile 32 | func Teardown() { 33 | if logfile == nil { 34 | return 35 | } 36 | _ = logfile.Close() 37 | } 38 | 39 | func writeWithSync(calldepth int, msg string) { 40 | calldepth++ 41 | if logfile == nil { 42 | return 43 | } 44 | _ = logger.Output(calldepth, msg) 45 | _ = logfile.Sync() // immediately write msg 46 | } 47 | 48 | // Log to output message 49 | func Log(msg string) { 50 | calldepth := 2 51 | writeWithSync(calldepth, msg) 52 | } 53 | -------------------------------------------------------------------------------- /lib/go-prompt/internal/strings/strings_test.go: -------------------------------------------------------------------------------- 1 | package strings_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/c-bata/go-prompt/internal/strings" 6 | ) 7 | 8 | func ExampleIndexNotByte() { 9 | fmt.Println(strings.IndexNotByte("golang", 'g')) 10 | fmt.Println(strings.IndexNotByte("golang", 'x')) 11 | fmt.Println(strings.IndexNotByte("gggggg", 'g')) 12 | // Output: 13 | // 1 14 | // 0 15 | // -1 16 | } 17 | 18 | func ExampleLastIndexNotByte() { 19 | fmt.Println(strings.LastIndexNotByte("golang", 'g')) 20 | fmt.Println(strings.LastIndexNotByte("golang", 'x')) 21 | fmt.Println(strings.LastIndexNotByte("gggggg", 'g')) 22 | // Output: 23 | // 4 24 | // 5 25 | // -1 26 | } 27 | 28 | func ExampleIndexNotAny() { 29 | fmt.Println(strings.IndexNotAny("golang", "glo")) 30 | fmt.Println(strings.IndexNotAny("golang", "gl")) 31 | fmt.Println(strings.IndexNotAny("golang", "golang")) 32 | // Output: 33 | // 3 34 | // 1 35 | // -1 36 | } 37 | 38 | func ExampleLastIndexNotAny() { 39 | fmt.Println(strings.LastIndexNotAny("golang", "agn")) 40 | fmt.Println(strings.LastIndexNotAny("golang", "an")) 41 | fmt.Println(strings.LastIndexNotAny("golang", "golang")) 42 | // Output: 43 | // 2 44 | // 5 45 | // -1 46 | } 47 | -------------------------------------------------------------------------------- /lib/go-prompt/key_bind.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | // KeyBindFunc receives buffer and processed it. 4 | type KeyBindFunc func(*Buffer) 5 | 6 | // KeyBind represents which key should do what operation. 7 | type KeyBind struct { 8 | Key Key 9 | Fn KeyBindFunc 10 | } 11 | 12 | // ASCIICodeBind represents which []byte should do what operation 13 | type ASCIICodeBind struct { 14 | ASCIICode []byte 15 | Fn KeyBindFunc 16 | } 17 | 18 | // KeyBindMode to switch a key binding flexibly. 19 | type KeyBindMode string 20 | 21 | const ( 22 | // CommonKeyBind is a mode without any keyboard shortcut 23 | CommonKeyBind KeyBindMode = "common" 24 | // EmacsKeyBind is a mode to use emacs-like keyboard shortcut 25 | EmacsKeyBind KeyBindMode = "emacs" 26 | ) 27 | 28 | var commonKeyBindings = []KeyBind{ 29 | // Go to the End of the line 30 | { 31 | Key: End, 32 | Fn: GoLineEnd, 33 | }, 34 | // Go to the beginning of the line 35 | { 36 | Key: Home, 37 | Fn: GoLineBeginning, 38 | }, 39 | // Delete character under the cursor 40 | { 41 | Key: Delete, 42 | Fn: DeleteChar, 43 | }, 44 | // Backspace 45 | { 46 | Key: Backspace, 47 | Fn: DeleteBeforeChar, 48 | }, 49 | // Right allow: Forward one character 50 | { 51 | Key: Right, 52 | Fn: GoRightChar, 53 | }, 54 | // Left allow: Backward one character 55 | { 56 | Key: Left, 57 | Fn: GoLeftChar, 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /lib/go-prompt/key_bind_func.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | // GoLineEnd Go to the End of the line 4 | func GoLineEnd(buf *Buffer) { 5 | x := []rune(buf.Document().TextAfterCursor()) 6 | buf.CursorRight(len(x)) 7 | } 8 | 9 | // GoLineBeginning Go to the beginning of the line 10 | func GoLineBeginning(buf *Buffer) { 11 | x := []rune(buf.Document().TextBeforeCursor()) 12 | buf.CursorLeft(len(x)) 13 | } 14 | 15 | // DeleteChar Delete character under the cursor 16 | func DeleteChar(buf *Buffer) { 17 | buf.Delete(1) 18 | } 19 | 20 | // DeleteWord Delete word before the cursor 21 | func DeleteWord(buf *Buffer) { 22 | buf.DeleteBeforeCursor(len([]rune(buf.Document().TextBeforeCursor())) - buf.Document().FindStartOfPreviousWordWithSpace()) 23 | } 24 | 25 | // DeleteBeforeChar Go to Backspace 26 | func DeleteBeforeChar(buf *Buffer) { 27 | buf.DeleteBeforeCursor(1) 28 | } 29 | 30 | // GoRightChar Forward one character 31 | func GoRightChar(buf *Buffer) { 32 | buf.CursorRight(1) 33 | } 34 | 35 | // GoLeftChar Backward one character 36 | func GoLeftChar(buf *Buffer) { 37 | buf.CursorLeft(1) 38 | } 39 | 40 | // GoRightWord Forward one word 41 | func GoRightWord(buf *Buffer) { 42 | buf.CursorRight(buf.Document().FindEndOfCurrentWordWithSpace()) 43 | } 44 | 45 | // GoLeftWord Backward one word 46 | func GoLeftWord(buf *Buffer) { 47 | buf.CursorLeft(len([]rune(buf.Document().TextBeforeCursor())) - buf.Document().FindStartOfPreviousWordWithSpace()) 48 | } 49 | -------------------------------------------------------------------------------- /lib/go-prompt/key_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Key"; DO NOT EDIT. 2 | 3 | package prompt 4 | 5 | import "strconv" 6 | 7 | const _Key_name = "EscapeControlAControlBControlCControlDControlEControlFControlGControlHControlIControlJControlKControlLControlMControlNControlOControlPControlQControlRControlSControlTControlUControlVControlWControlXControlYControlZControlSpaceControlBackslashControlSquareCloseControlCircumflexControlUnderscoreControlLeftControlRightControlUpControlDownUpDownRightLeftShiftLeftShiftUpShiftDownShiftRightHomeEndDeleteShiftDeleteControlDeletePageUpPageDownBackTabInsertBackspaceTabEnterF1F2F3F4F5F6F7F8F9F10F11F12F13F14F15F16F17F18F19F20F21F22F23F24AnyCPRResponseVt100MouseEventWindowsMouseEventBracketedPasteIgnoreNotDefined" 8 | 9 | var _Key_index = [...]uint16{0, 6, 14, 22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 142, 150, 158, 166, 174, 182, 190, 198, 206, 214, 226, 242, 260, 277, 294, 305, 317, 326, 337, 339, 343, 348, 352, 361, 368, 377, 387, 391, 394, 400, 411, 424, 430, 438, 445, 451, 460, 463, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 516, 519, 522, 525, 528, 531, 534, 545, 560, 577, 591, 597, 607} 10 | 11 | func (i Key) String() string { 12 | if i < 0 || i >= Key(len(_Key_index)-1) { 13 | return "Key(" + strconv.FormatInt(int64(i), 10) + ")" 14 | } 15 | return _Key_name[_Key_index[i]:_Key_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /lib/go-prompt/output_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | const flushMaxRetryCount = 3 10 | 11 | // PosixWriter is a ConsoleWriter implementation for POSIX environment. 12 | // To control terminal emulator, this outputs VT100 escape sequences. 13 | type PosixWriter struct { 14 | VT100Writer 15 | fd int 16 | } 17 | 18 | // Flush to flush buffer 19 | func (w *PosixWriter) Flush() error { 20 | l := len(w.buffer) 21 | offset := 0 22 | retry := 0 23 | for { 24 | n, err := syscall.Write(w.fd, w.buffer[offset:]) 25 | if err != nil { 26 | if retry < flushMaxRetryCount { 27 | retry++ 28 | continue 29 | } 30 | return err 31 | } 32 | offset += n 33 | if offset == l { 34 | break 35 | } 36 | } 37 | w.buffer = []byte{} 38 | return nil 39 | } 40 | 41 | var _ ConsoleWriter = &PosixWriter{} 42 | 43 | var ( 44 | // NewStandardOutputWriter returns ConsoleWriter object to write to stdout. 45 | // This generates VT100 escape sequences because almost terminal emulators 46 | // in POSIX OS built on top of a VT100 specification. 47 | // Deprecated: Please use NewStdoutWriter 48 | NewStandardOutputWriter = NewStdoutWriter 49 | ) 50 | 51 | // NewStdoutWriter returns ConsoleWriter object to write to stdout. 52 | // This generates VT100 escape sequences because almost terminal emulators 53 | // in POSIX OS built on top of a VT100 specification. 54 | func NewStdoutWriter() ConsoleWriter { 55 | return &PosixWriter{ 56 | fd: syscall.Stdout, 57 | } 58 | } 59 | 60 | // NewStderrWriter returns ConsoleWriter object to write to stderr. 61 | // This generates VT100 escape sequences because almost terminal emulators 62 | // in POSIX OS built on top of a VT100 specification. 63 | func NewStderrWriter() ConsoleWriter { 64 | return &PosixWriter{ 65 | fd: syscall.Stderr, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/go-prompt/output_vt100_test.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestVT100WriterWrite(t *testing.T) { 9 | scenarioTable := []struct { 10 | input []byte 11 | expected []byte 12 | }{ 13 | { 14 | input: []byte{0x1b}, 15 | expected: []byte{'?'}, 16 | }, 17 | { 18 | input: []byte{'a'}, 19 | expected: []byte{'a'}, 20 | }, 21 | } 22 | 23 | for _, s := range scenarioTable { 24 | pw := &VT100Writer{} 25 | pw.Write(s.input) 26 | 27 | if !bytes.Equal(pw.buffer, s.expected) { 28 | t.Errorf("Should be %+#v, but got %+#v", pw.buffer, s.expected) 29 | } 30 | } 31 | } 32 | 33 | func TestVT100WriterWriteStr(t *testing.T) { 34 | scenarioTable := []struct { 35 | input string 36 | expected []byte 37 | }{ 38 | { 39 | input: "\x1b", 40 | expected: []byte{'?'}, 41 | }, 42 | { 43 | input: "a", 44 | expected: []byte{'a'}, 45 | }, 46 | } 47 | 48 | for _, s := range scenarioTable { 49 | pw := &VT100Writer{} 50 | pw.WriteStr(s.input) 51 | 52 | if !bytes.Equal(pw.buffer, s.expected) { 53 | t.Errorf("Should be %+#v, but got %+#v", pw.buffer, s.expected) 54 | } 55 | } 56 | } 57 | 58 | func TestVT100WriterWriteRawStr(t *testing.T) { 59 | scenarioTable := []struct { 60 | input string 61 | expected []byte 62 | }{ 63 | { 64 | input: "\x1b", 65 | expected: []byte{0x1b}, 66 | }, 67 | { 68 | input: "a", 69 | expected: []byte{'a'}, 70 | }, 71 | } 72 | 73 | for _, s := range scenarioTable { 74 | pw := &VT100Writer{} 75 | pw.WriteRawStr(s.input) 76 | 77 | if !bytes.Equal(pw.buffer, s.expected) { 78 | t.Errorf("Should be %+#v, but got %+#v", pw.buffer, s.expected) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/go-prompt/output_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "io" 7 | 8 | colorable "github.com/mattn/go-colorable" 9 | ) 10 | 11 | // WindowsWriter is a ConsoleWriter implementation for Win32 console. 12 | // Output is converted from VT100 escape sequences by mattn/go-colorable. 13 | type WindowsWriter struct { 14 | VT100Writer 15 | out io.Writer 16 | } 17 | 18 | // Flush to flush buffer 19 | func (w *WindowsWriter) Flush() error { 20 | _, err := w.out.Write(w.buffer) 21 | if err != nil { 22 | return err 23 | } 24 | w.buffer = []byte{} 25 | return nil 26 | } 27 | 28 | var _ ConsoleWriter = &WindowsWriter{} 29 | 30 | var ( 31 | // NewStandardOutputWriter is Deprecated: Please use NewStdoutWriter 32 | NewStandardOutputWriter = NewStdoutWriter 33 | ) 34 | 35 | // NewStdoutWriter returns ConsoleWriter object to write to stdout. 36 | // This generates win32 control sequences. 37 | func NewStdoutWriter() ConsoleWriter { 38 | return &WindowsWriter{ 39 | out: colorable.NewColorableStdout(), 40 | } 41 | } 42 | 43 | // NewStderrWriter returns ConsoleWriter object to write to stderr. 44 | // This generates win32 control sequences. 45 | func NewStderrWriter() ConsoleWriter { 46 | return &WindowsWriter{ 47 | out: colorable.NewColorableStderr(), 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/go-prompt/shortcut.go: -------------------------------------------------------------------------------- 1 | package prompt 2 | 3 | func dummyExecutor(in string) {} 4 | 5 | // Input get the input data from the user and return it. 6 | func Input(prefix string, completer Completer, opts ...Option) string { 7 | pt := New(dummyExecutor, completer) 8 | pt.renderer.prefixTextColor = DefaultColor 9 | pt.renderer.prefix = prefix 10 | 11 | for _, opt := range opts { 12 | if err := opt(pt); err != nil { 13 | panic(err) 14 | } 15 | } 16 | return pt.Input() 17 | } 18 | 19 | // Choose to the shortcut of input function to select from string array. 20 | // Deprecated: Maybe anyone want to use this. 21 | func Choose(prefix string, choices []string, opts ...Option) string { 22 | completer := newChoiceCompleter(choices, FilterHasPrefix) 23 | pt := New(dummyExecutor, completer) 24 | pt.renderer.prefixTextColor = DefaultColor 25 | pt.renderer.prefix = prefix 26 | 27 | for _, opt := range opts { 28 | if err := opt(pt); err != nil { 29 | panic(err) 30 | } 31 | } 32 | return pt.Input() 33 | } 34 | 35 | func newChoiceCompleter(choices []string, filter Filter) Completer { 36 | s := make([]Suggest, len(choices)) 37 | for i := range choices { 38 | s[i] = Suggest{Text: choices[i]} 39 | } 40 | return func(x Document) []Suggest { 41 | return filter(s, x.GetWordBeforeCursor(), true) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/go-prompt/signal_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | 10 | "github.com/c-bata/go-prompt/internal/debug" 11 | ) 12 | 13 | func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) { 14 | in := p.in 15 | sigCh := make(chan os.Signal, 1) 16 | signal.Notify( 17 | sigCh, 18 | syscall.SIGINT, 19 | syscall.SIGTERM, 20 | syscall.SIGQUIT, 21 | syscall.SIGWINCH, 22 | ) 23 | 24 | for { 25 | select { 26 | case <-stop: 27 | debug.Log("stop handleSignals") 28 | return 29 | case s := <-sigCh: 30 | switch s { 31 | case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c 32 | debug.Log("Catch SIGINT") 33 | exitCh <- 0 34 | 35 | case syscall.SIGTERM: // kill -SIGTERM XXXX 36 | debug.Log("Catch SIGTERM") 37 | exitCh <- 1 38 | 39 | case syscall.SIGQUIT: // kill -SIGQUIT XXXX 40 | debug.Log("Catch SIGQUIT") 41 | exitCh <- 0 42 | 43 | case syscall.SIGWINCH: 44 | debug.Log("Catch SIGWINCH") 45 | winSizeCh <- in.GetWinSize() 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/go-prompt/signal_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package prompt 4 | 5 | import ( 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | 10 | "github.com/c-bata/go-prompt/internal/debug" 11 | ) 12 | 13 | func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) { 14 | sigCh := make(chan os.Signal, 1) 15 | signal.Notify( 16 | sigCh, 17 | syscall.SIGINT, 18 | syscall.SIGTERM, 19 | syscall.SIGQUIT, 20 | ) 21 | 22 | for { 23 | select { 24 | case <-stop: 25 | debug.Log("stop handleSignals") 26 | return 27 | case s := <-sigCh: 28 | switch s { 29 | 30 | case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c 31 | debug.Log("Catch SIGINT") 32 | exitCh <- 0 33 | 34 | case syscall.SIGTERM: // kill -SIGTERM XXXX 35 | debug.Log("Catch SIGTERM") 36 | exitCh <- 1 37 | 38 | case syscall.SIGQUIT: // kill -SIGQUIT XXXX 39 | debug.Log("Catch SIGQUIT") 40 | exitCh <- 0 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/go-prompt/term/term.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package term 4 | 5 | import ( 6 | "sync" 7 | "syscall" 8 | 9 | "github.com/pkg/term/termios" 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | var ( 14 | saveTermios *unix.Termios 15 | saveTermiosFD int 16 | saveTermiosOnce sync.Once 17 | ) 18 | 19 | func GetSaveTermiosFD() int { 20 | return saveTermiosFD 21 | } 22 | 23 | func GetOriginalTermios(fd int) (*unix.Termios, error) { 24 | var err error 25 | saveTermiosOnce.Do(func() { 26 | saveTermiosFD = fd 27 | saveTermios, err = termios.Tcgetattr(uintptr(fd)) 28 | }) 29 | return saveTermios, err 30 | } 31 | 32 | // Restore terminal's mode. 33 | func Restore(fd int) error { 34 | o, err := GetOriginalTermios(fd) 35 | if err != nil { 36 | return err 37 | } 38 | return termios.Tcsetattr(uintptr(fd), termios.TCSANOW, o) 39 | } 40 | 41 | // SetRaw put terminal into a raw mode 42 | func SetRaw(fd int) error { 43 | n, err := termios.Tcgetattr(uintptr(fd)) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | n.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | 49 | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | 50 | syscall.ICRNL | syscall.IXON 51 | n.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG | syscall.ECHONL 52 | n.Cflag &^= syscall.CSIZE | syscall.PARENB 53 | n.Cflag |= syscall.CS8 // Set to 8-bit wide. Typical value for displaying characters. 54 | n.Cc[syscall.VMIN] = 1 55 | n.Cc[syscall.VTIME] = 0 56 | 57 | return termios.Tcsetattr(uintptr(fd), termios.TCSANOW, (*unix.Termios)(n)) 58 | } 59 | -------------------------------------------------------------------------------- /lib/krew/.dockerignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /hack/ 3 | /out/ 4 | /OWNERS 5 | /OWNERS_ALIASES 6 | /CONTRIBUTING.md 7 | /SECURITY_CONTACTS 8 | /.travis.yml 9 | /code-of-conduct.md 10 | -------------------------------------------------------------------------------- /lib/krew/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | out/ 15 | build/ 16 | -------------------------------------------------------------------------------- /lib/krew/.golangci.yml: -------------------------------------------------------------------------------- 1 | # all available settings of specific linters 2 | linters-settings: 3 | gocritic: 4 | enabled-tags: 5 | - performance 6 | - diagnostic 7 | - style 8 | - experimental 9 | - opinionated 10 | disabled-checks: 11 | - hugeParam 12 | - rangeValCopy 13 | - unnamedResult 14 | gofmt: 15 | simplify: true 16 | goimports: 17 | # put imports beginning with prefix after 3rd-party packages; 18 | # it's a comma-separated list of prefixes 19 | local-prefixes: sigs.k8s.io/krew 20 | errcheck: 21 | check-type-assertions: false 22 | check-blank: false 23 | 24 | # options for analysis running 25 | run: 26 | # which dirs to skip: they won't be analyzed; 27 | # can use regexp here: generated.*, regexp is applied on full path; 28 | # default value is empty list, but next dirs are always skipped independently 29 | # from this option's value: 30 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ 31 | skip-dirs: 32 | - hack 33 | - docs 34 | 35 | # include test files 36 | tests: true 37 | 38 | linters: 39 | disable-all: true 40 | enable: 41 | - deadcode 42 | - errcheck 43 | - gci 44 | - gocritic 45 | - gofmt 46 | - goimports 47 | - golint 48 | - gosimple 49 | - govet 50 | - ineffassign 51 | - interfacer 52 | - maligned 53 | - misspell 54 | - prealloc 55 | - staticcheck 56 | - structcheck 57 | - stylecheck 58 | - unconvert 59 | - unparam 60 | - varcheck 61 | -------------------------------------------------------------------------------- /lib/krew/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://git.k8s.io/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: 4 | 5 | _As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ 6 | 7 | ## Getting Started 8 | 9 | We have full documentation on how to get started contributing here: 10 | 11 | 14 | 15 | - [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests 16 | - [Kubernetes Contributor Guide](https://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](https://git.k8s.io/community/contributors/guide#contributing) 17 | - [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers 18 | 19 | ## Mentorship 20 | 21 | - [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! 22 | 23 | ## Contact Information 24 | 25 | To discuss about this project, you can use the following channels. You can find 26 | Krew maintainers at: 27 | 28 | - Kubernetes Slack channel: 29 | [**#krew**](https://kubernetes.slack.com/messages/krew) or 30 | [#sig-cli](https://kubernetes.slack.com/messages/sig-cli) 31 | - [SIG CLI Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-cli) 32 | -------------------------------------------------------------------------------- /lib/krew/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - krew-maintainers 5 | -------------------------------------------------------------------------------- /lib/krew/OWNERS_ALIASES: -------------------------------------------------------------------------------- 1 | aliases: 2 | krew-maintainers: 3 | - ahmetb 4 | - chriskim06 5 | - corneliusweig 6 | - soltysh 7 | -------------------------------------------------------------------------------- /lib/krew/SECURITY_CONTACTS: -------------------------------------------------------------------------------- 1 | # Defined below are the security contacts for this repo. 2 | # 3 | # They are the contact point for the Product Security Committee to reach out 4 | # to for triaging and handling of incoming issues. 5 | # 6 | # The below names agree to abide by the 7 | # [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) 8 | # and will be removed and replaced if they violate that agreement. 9 | # 10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE 11 | # INSTRUCTIONS AT https://kubernetes.io/security/ 12 | 13 | ahmetb 14 | corneliusweig 15 | -------------------------------------------------------------------------------- /lib/krew/assets/logo/horizontal/black/krew-horizontal-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/horizontal/black/krew-horizontal-black.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/horizontal/color/krew-horizontal-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/horizontal/color/krew-horizontal-color.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/horizontal/white/krew-horizontal-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/horizontal/white/krew-horizontal-white.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/icon/black/krew-icon-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/icon/black/krew-icon-black.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/icon/color/krew-icon-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/icon/color/krew-icon-color.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/icon/white/krew-icon-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/icon/white/krew-icon-white.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/stacked/black/krew-stacked-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/stacked/black/krew-stacked-black.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/stacked/color/krew-stacked-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/stacked/color/krew-stacked-color.png -------------------------------------------------------------------------------- /lib/krew/assets/logo/stacked/white/krew-stacked-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/assets/logo/stacked/white/krew-stacked-white.png -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/hack.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "sigs.k8s.io/krew/internal/environment" 5 | "sigs.k8s.io/krew/internal/installation" 6 | "sigs.k8s.io/krew/pkg/index" 7 | ) 8 | 9 | func GetInstalledPlugin() ([]index.Receipt, error) { 10 | return installation.GetInstalledPluginReceipts(paths.InstallReceiptsPath()) 11 | } 12 | 13 | func GetPath() environment.Paths { 14 | return environment.MustGetKrewPaths() 15 | } 16 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/install_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cmd 16 | 17 | import ( 18 | "net/http" 19 | "net/http/httptest" 20 | "path/filepath" 21 | "testing" 22 | ) 23 | 24 | func Test_readPluginFromURL(t *testing.T) { 25 | server := httptest.NewServer(http.FileServer(http.Dir(filepath.FromSlash("../../../integration_test/testdata")))) 26 | defer server.Close() 27 | 28 | tests := []struct { 29 | name string 30 | url string 31 | wantName string 32 | wantErr bool 33 | }{ 34 | { 35 | name: "successful request", 36 | url: server.URL + "/ctx.yaml", 37 | wantName: "ctx", 38 | }, 39 | { 40 | name: "invalid server", 41 | url: "http://example.invalid:80/foo.yaml", 42 | wantErr: true, 43 | }, 44 | { 45 | name: "bad response", 46 | url: server.URL + "/404.yaml", 47 | wantErr: true, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | got, err := readPluginFromURL(tt.url) 53 | if (err != nil) != tt.wantErr { 54 | t.Fatalf("readPluginFromURL() error = %v, wantErr %v", err, tt.wantErr) 55 | return 56 | } 57 | if got.Name != tt.wantName { 58 | t.Fatalf("readPluginFromURL() returned name=%v; want=%v", got.Name, tt.wantName) 59 | } 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/internal/fetch_tag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package internal 16 | 17 | import ( 18 | "encoding/json" 19 | "net/http" 20 | 21 | "github.com/pkg/errors" 22 | "k8s.io/klog" 23 | ) 24 | 25 | const ( 26 | githubVersionURL = "https://api.github.com/repos/kubernetes-sigs/krew/releases/latest" 27 | ) 28 | 29 | // for testing 30 | var versionURL = githubVersionURL 31 | 32 | // FetchLatestTag fetches the tag name of the latest release from GitHub. 33 | func FetchLatestTag() (string, error) { 34 | klog.V(4).Infof("Fetching latest tag from GitHub") 35 | response, err := http.Get(versionURL) 36 | if err != nil { 37 | return "", errors.Wrapf(err, "could not GET the latest release") 38 | } 39 | defer response.Body.Close() 40 | if response.StatusCode != http.StatusOK { 41 | return "", errors.Errorf("expected HTTP status 200 OK, got %s", response.Status) 42 | } 43 | 44 | var res struct { 45 | Tag string `json:"tag_name"` 46 | } 47 | klog.V(4).Infof("Parsing response from GitHub") 48 | if err := json.NewDecoder(response.Body).Decode(&res); err != nil { 49 | return "", errors.Wrapf(err, "could not parse the response from GitHub") 50 | } 51 | klog.V(4).Infof("Fetched latest tag name (%s) from GitHub", res.Tag) 52 | return res.Tag, nil 53 | } 54 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/internal/security_notice.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package internal 16 | 17 | import ( 18 | "os" 19 | 20 | "sigs.k8s.io/krew/pkg/constants" 21 | ) 22 | 23 | const securityNoticeFmt = `You installed plugin %q from the krew-index plugin repository. 24 | These plugins are not audited for security by the Krew maintainers. 25 | Run them at your own risk.` 26 | 27 | func PrintSecurityNotice(plugin string) { 28 | if plugin == constants.KrewPluginName { 29 | return // do not warn for krew itself 30 | } 31 | PrintWarning(os.Stderr, securityNoticeFmt+"\n", plugin) 32 | } 33 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/internal/warning.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package internal 16 | 17 | import ( 18 | "fmt" 19 | "io" 20 | 21 | "github.com/fatih/color" 22 | ) 23 | 24 | func PrintWarning(w io.Writer, format string, a ...interface{}) { 25 | color.New(color.FgRed, color.Bold).Fprint(w, "WARNING: ") 26 | fmt.Fprintf(w, format, a...) 27 | } 28 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/namingutils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cmd 16 | 17 | import ( 18 | "regexp" 19 | 20 | "sigs.k8s.io/krew/pkg/constants" 21 | "sigs.k8s.io/krew/pkg/index" 22 | ) 23 | 24 | var canonicalNameRegex = regexp.MustCompile(`^[\w-]+/[\w-]+$`) 25 | 26 | // indexOf returns the index name of a receipt. 27 | func indexOf(r index.Receipt) string { 28 | if r.Status.Source.Name == "" { 29 | return constants.DefaultIndexName 30 | } 31 | return r.Status.Source.Name 32 | } 33 | 34 | // displayName returns the display name of a Plugin. 35 | // The index name is omitted if it is the default index. 36 | func displayName(p index.Plugin, indexName string) string { 37 | if isDefaultIndex(indexName) { 38 | return p.Name 39 | } 40 | return indexName + "/" + p.Name 41 | } 42 | 43 | func isDefaultIndex(name string) bool { 44 | return name == "" || name == constants.DefaultIndexName 45 | } 46 | 47 | // canonicalName returns INDEX/NAME value for a plugin, even if 48 | // it is in the default index. 49 | func canonicalName(p index.Plugin, indexName string) string { 50 | if isDefaultIndex(indexName) { 51 | indexName = constants.DefaultIndexName 52 | } 53 | return indexName + "/" + p.Name 54 | } 55 | 56 | func isCanonicalName(s string) bool { 57 | return canonicalNameRegex.MatchString(s) 58 | } 59 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/uninstall.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | 21 | "github.com/pkg/errors" 22 | "github.com/spf13/cobra" 23 | "k8s.io/klog" 24 | 25 | "sigs.k8s.io/krew/internal/index/validation" 26 | "sigs.k8s.io/krew/internal/installation" 27 | ) 28 | 29 | // uninstallCmd represents the uninstall command 30 | var uninstallCmd = &cobra.Command{ 31 | Use: "uninstall", 32 | Short: "Uninstall plugins", 33 | Long: `Uninstall one or more plugins. 34 | 35 | Example: 36 | kubectl krew uninstall NAME [NAME...] 37 | 38 | Remarks: 39 | Failure to uninstall a plugin will result in an error and exit immediately.`, 40 | RunE: func(cmd *cobra.Command, args []string) error { 41 | for _, name := range args { 42 | if isCanonicalName(name) { 43 | return errors.New("uninstall command does not support INDEX/PLUGIN syntax; just specify PLUGIN") 44 | } else if !validation.IsSafePluginName(name) { 45 | return unsafePluginNameErr(name) 46 | } 47 | klog.V(4).Infof("Going to uninstall plugin %s\n", name) 48 | if err := installation.Uninstall(paths, name); err != nil { 49 | return errors.Wrapf(err, "failed to uninstall plugin %s", name) 50 | } 51 | fmt.Fprintf(os.Stderr, "Uninstalled plugin: %s\n", name) 52 | } 53 | return nil 54 | }, 55 | PreRunE: checkIndex, 56 | Args: cobra.MinimumNArgs(1), 57 | Aliases: []string{"remove"}, 58 | } 59 | 60 | func unsafePluginNameErr(n string) error { return errors.Errorf("plugin name %q not allowed", n) } 61 | 62 | func init() { 63 | rootCmd.AddCommand(uninstallCmd) 64 | } 65 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/cmd/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cmd 16 | 17 | import ( 18 | "os" 19 | 20 | "github.com/spf13/cobra" 21 | 22 | "sigs.k8s.io/krew/internal/installation" 23 | "sigs.k8s.io/krew/internal/version" 24 | "sigs.k8s.io/krew/pkg/constants" 25 | "sigs.k8s.io/krew/pkg/index" 26 | ) 27 | 28 | // versionCmd represents the version command 29 | var versionCmd = &cobra.Command{ 30 | Use: "version", 31 | Short: "Show krew version and diagnostics", 32 | Long: `Show version information and diagnostics about krew itself. 33 | 34 | Remarks: 35 | - GitTag describes the release name krew is built from. 36 | - GitCommit describes the git revision ID which krew is built from. 37 | - DefaultIndexURI is the URI where the index is updated from. 38 | - BasePath is the root directory for krew installation. 39 | - IndexPath is the directory that stores the local copy of the index git repository. 40 | - InstallPath is the directory for plugin installations. 41 | - BinPath is the directory for the symbolic links to the installed plugin executables.`, 42 | RunE: func(cmd *cobra.Command, args []string) error { 43 | conf := [][]string{ 44 | {"GitTag", version.GitTag()}, 45 | {"GitCommit", version.GitCommit()}, 46 | {"IndexURI", index.DefaultIndex()}, 47 | {"BasePath", paths.BasePath()}, 48 | {"IndexPath", paths.IndexPath(constants.DefaultIndexName)}, 49 | {"InstallPath", paths.InstallPath()}, 50 | {"BinPath", paths.BinPath()}, 51 | {"DetectedPlatform", installation.OSArch().String()}, 52 | } 53 | return printTable(os.Stdout, []string{"OPTION", "VALUE"}, conf) 54 | }, 55 | } 56 | 57 | func init() { 58 | rootCmd.AddCommand(versionCmd) 59 | } 60 | -------------------------------------------------------------------------------- /lib/krew/cmd/krew/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "k8s.io/klog" 19 | 20 | "sigs.k8s.io/krew/cmd/krew/cmd" 21 | ) 22 | 23 | func main() { 24 | defer klog.Flush() 25 | cmd.Execute() 26 | } 27 | -------------------------------------------------------------------------------- /lib/krew/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Community Code of Conduct 2 | 3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /lib/krew/docs/DEVELOPER_GUIDE.md: -------------------------------------------------------------------------------- 1 | # Developer Guide 2 | 3 | This page has moved from GitHub to our website: 4 | https://krew.sigs.k8s.io/docs/developer-guide/ 5 | -------------------------------------------------------------------------------- /lib/krew/docs/NAMING_GUIDE.md: -------------------------------------------------------------------------------- 1 | # Plugin Naming Style Guide 2 | 3 | This page has moved to our website: 4 | https://krew.sigs.k8s.io/docs/developer-guide/develop/naming-guide/ 5 | -------------------------------------------------------------------------------- /lib/krew/docs/USER_GUIDE.md: -------------------------------------------------------------------------------- 1 | # User Guide 2 | 3 | This page has moved from GitHub to our website: 4 | https://krew.sigs.k8s.io/docs/user-guide/ 5 | -------------------------------------------------------------------------------- /lib/krew/go.mod: -------------------------------------------------------------------------------- 1 | module sigs.k8s.io/krew 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/fatih/color v1.10.0 7 | github.com/google/go-cmp v0.5.2 8 | github.com/kylelemons/godebug v1.1.0 // indirect 9 | github.com/mattn/go-isatty v0.0.12 10 | github.com/pkg/errors v0.9.1 11 | github.com/sahilm/fuzzy v0.1.0 12 | github.com/spf13/cobra v1.1.1 13 | github.com/spf13/pflag v1.0.5 14 | k8s.io/apimachinery v0.21.1 15 | k8s.io/client-go v0.21.1 16 | k8s.io/klog v1.0.0 17 | sigs.k8s.io/yaml v1.2.0 18 | ) 19 | -------------------------------------------------------------------------------- /lib/krew/hack/boilerplate/boilerplate.Dockerfile.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /lib/krew/hack/boilerplate/boilerplate.Makefile.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /lib/krew/hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright YEAR The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /lib/krew/hack/boilerplate/boilerplate.py.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright YEAR The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | -------------------------------------------------------------------------------- /lib/krew/hack/boilerplate/boilerplate.sh.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /lib/krew/hack/ensure-kubectl-installed.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | install_kubectl_if_needed() { 20 | if hash kubectl 2>/dev/null; then 21 | echo >&2 "using kubectl from the host system and not reinstalling" 22 | else 23 | local bin_dir 24 | bin_dir="$(go env GOPATH)/bin" 25 | local -r kubectl_version='v1.14.2' 26 | local -r kubectl_path="${bin_dir}/kubectl" 27 | local goos goarch kubectl_url 28 | goos="$(go env GOOS)" 29 | goarch="$(go env GOARCH)" 30 | kubectl_url="https://storage.googleapis.com/kubernetes-release/release/${kubectl_version}/bin/${goos}/${goarch}/kubectl" 31 | 32 | echo >&2 "kubectl not detected in environment, downloading ${kubectl_url}" 33 | mkdir -p "${bin_dir}" 34 | curl --fail --show-error --silent --location --output "$kubectl_path" "${kubectl_url}" 35 | chmod +x "$kubectl_path" 36 | echo >&2 "installed kubectl to ${kubectl_path}" 37 | fi 38 | } 39 | 40 | install_kubectl_if_needed 41 | -------------------------------------------------------------------------------- /lib/krew/hack/install-gox.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | [[ -n "${DEBUG:-}" ]] && set -x 19 | 20 | ensure_gox() { 21 | command -v "gox" &>/dev/null 22 | } 23 | 24 | go install github.com/mitchellh/gox@v1.0.1 25 | 26 | if ! ensure_gox; then 27 | echo >&2 "gox not in PATH" 28 | exit 1 29 | fi 30 | -------------------------------------------------------------------------------- /lib/krew/hack/make-all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e -o pipefail 18 | 19 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 20 | 21 | "${SCRIPTDIR}/make-binaries.sh" 22 | "${SCRIPTDIR}/make-release-artifacts.sh" 23 | -------------------------------------------------------------------------------- /lib/krew/hack/make-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script builds krew binaries for all supported platforms (or those os/arch 18 | # combinations specified via OSARCH variable). 19 | 20 | set -e -o pipefail 21 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 22 | 23 | if ! command -v "gox" &>/dev/null; then 24 | echo >&2 "gox not installed in PATH, run hack/install-gox.sh." 25 | exit 1 26 | fi 27 | 28 | supported_platforms="darwin/amd64 darwin/arm64 windows/amd64\ 29 | linux/amd64 linux/arm linux/arm64" 30 | version_pkg="sigs.k8s.io/krew/internal/version" 31 | 32 | cd "${SCRIPTDIR}/.." 33 | rm -rf -- "out/" 34 | 35 | # Builds 36 | echo >&2 "Building binaries for: ${OSARCH:-$supported_platforms}" 37 | git_rev="${SHORT_SHA:-$(git rev-parse --short HEAD)}" 38 | git_tag="${TAG_NAME:-$(git describe --tags --dirty --always)}" 39 | echo >&2 "(Stamping with git tag=${git_tag} rev=${git_rev})" 40 | 41 | env CGO_ENABLED=0 gox -osarch="${OSARCH:-$supported_platforms}" \ 42 | -tags netgo \ 43 | -mod readonly \ 44 | -ldflags="-w -X ${version_pkg}.gitCommit=${git_rev} \ 45 | -X ${version_pkg}.gitTag=${git_tag}" \ 46 | -output="out/bin/krew-{{.OS}}_{{.Arch}}" \ 47 | ./cmd/krew/... 48 | -------------------------------------------------------------------------------- /lib/krew/hack/make-binary.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script builds krew binary for the current OS/arch. 18 | 19 | set -e -o pipefail 20 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 21 | 22 | exec env OSARCH="$(go env GOOS)/$(go env GOARCH)" \ 23 | "${SCRIPTDIR}/make-binaries.sh" 24 | -------------------------------------------------------------------------------- /lib/krew/hack/run-in-docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script starts a development container by mounting the krew binary from 18 | # the local filesystem. 19 | 20 | set -euo pipefail 21 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 22 | log() { echo >&2 "$*"; } 23 | log_ok() { log "$(tput setaf 2)$*$(tput sgr0)"; } 24 | log_fail() { log "$(tput setaf 1)$*$(tput sgr0)"; } 25 | image="krew:sandbox" 26 | 27 | krew_bin="${SCRIPTDIR}/../out/bin/krew-linux_amd64" 28 | if [[ ! -f "${krew_bin}" ]]; then 29 | log "Building the ${krew_bin}." 30 | env OSARCH="linux/amd64" "${SCRIPTDIR}/make-binaries.sh" 31 | else 32 | log_ok "Using existing ${krew_bin}." 33 | fi 34 | 35 | docker build -f "${SCRIPTDIR}/sandboxed.Dockerfile" -q \ 36 | --tag "${image}" "${SCRIPTDIR}/.." 37 | log_ok "Sandbox image '${image}' built successfully." 38 | 39 | kubeconfig="${KUBECONFIG:-$HOME/.kube/config}" 40 | if [[ ! -f "${kubeconfig}" ]]; then 41 | log_fail "Warning: kubeconfig not found at ${kubeconfig}, using /dev/null" 42 | kubeconfig=/dev/null 43 | fi 44 | 45 | log_ok "Starting docker container with volume mounts:" 46 | log " kubeconfig=${kubeconfig}" 47 | log " kubectl-krew=${krew_bin}" 48 | log_ok "You can rebuild with the following command without restarting the container:" 49 | log " env OSARCH=linux/amd64 hack/make-binaries.sh" 50 | exec docker run --rm --tty --interactive \ 51 | --volume "${krew_bin}:/usr/local/bin/kubectl-krew" \ 52 | --volume "${kubeconfig}:/etc/kubeconfig" \ 53 | --env KUBECONFIG=/etc/kubeconfig \ 54 | --hostname krew \ 55 | "${image}" 56 | -------------------------------------------------------------------------------- /lib/krew/hack/run-integration-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | [[ -n "${DEBUG:-}" ]] && set -x 20 | 21 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 22 | BINDIR="${SCRIPTDIR}/../out/bin" 23 | goos="$(go env GOOS)" 24 | goarch="$(go env GOARCH)" 25 | krew_binary_default="${BINDIR}/krew-${goos}_${goarch}" 26 | 27 | if [[ "$#" -gt 0 && ("$1" == '-h' || "$1" == '--help') ]]; then 28 | cat <&2 "Could not find $KREW_BINARY. You need to build krew for ${goos}/${goarch} before running the integration tests." 45 | exit 1 46 | fi 47 | krew_binary_realpath="$(readlink -f "${KREW_BINARY}")" 48 | if [[ ! -x "${krew_binary_realpath}" ]]; then 49 | echo >&2 "krew binary at ${krew_binary_realpath} is not an executable" 50 | exit 1 51 | fi 52 | KREW_BINARY="${krew_binary_realpath}" 53 | export KREW_BINARY 54 | 55 | go test sigs.k8s.io/krew/integration_test "$@" 56 | -------------------------------------------------------------------------------- /lib/krew/hack/run-lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | [[ -n "${DEBUG:-}" ]] && set -x 20 | 21 | gopath="$(go env GOPATH)" 22 | 23 | if ! [[ -x "$gopath/bin/golangci-lint" ]]; then 24 | echo >&2 'Installing golangci-lint' 25 | curl --silent --fail --location \ 26 | https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b "$gopath/bin" v1.34.1 27 | fi 28 | 29 | # configured by .golangci.yml 30 | "$gopath/bin/golangci-lint" run 31 | 32 | # install shfmt that ensures consistent format in shell scripts 33 | if ! [[ -x "${gopath}/bin/shfmt" ]]; then 34 | echo >&2 'Installing shfmt' 35 | go install mvdan.cc/sh/v3/cmd/shfmt@v3.0.0 36 | fi 37 | 38 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 39 | shfmt_out="$($gopath/bin/shfmt -l -i=2 ${SCRIPTDIR})" 40 | if [[ -n "${shfmt_out}" ]]; then 41 | echo >&2 "The following shell scripts need to be formatted, run: 'shfmt -w -i=2 ${SCRIPTDIR}'" 42 | echo >&2 "${shfmt_out}" 43 | exit 1 44 | fi 45 | -------------------------------------------------------------------------------- /lib/krew/hack/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 20 | 21 | color_red="$(tput setaf 1)" 22 | color_green="$(tput setaf 2)" 23 | color_blue="$(tput setaf 4)" 24 | color_reset="$(tput sgr0)" 25 | 26 | print_with_color() { 27 | echo "${1}${*:2}${color_reset}" 28 | } 29 | 30 | print_status() { 31 | local result=$? # <- this must be the first action 32 | if [[ $result == 0 ]]; then 33 | print_with_color "$color_green" 'SUCCESS' 34 | else 35 | print_with_color "$color_red" 'FAILURE' 36 | fi 37 | } 38 | trap print_status EXIT 39 | 40 | print_with_color "$color_blue" 'Checking boilerplate' 41 | "$SCRIPTDIR"/verify-boilerplate.sh 42 | 43 | print_with_color "$color_blue" 'Running tests' 44 | go test -short -race sigs.k8s.io/krew/... 45 | 46 | print_with_color "$color_blue" 'Running linter' 47 | "$SCRIPTDIR"/run-lint.sh 48 | 49 | print_with_color "$color_blue" 'Check code patterns' 50 | "$SCRIPTDIR"/verify-code-patterns.sh 51 | -------------------------------------------------------------------------------- /lib/krew/hack/sandboxed.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM gcr.io/gcp-runtimes/ubuntu_16_0_4:latest 16 | RUN apt-get update -qqy # retain the apt cache 17 | RUN apt-get install -qqy git curl wget 18 | 19 | ARG KUBECTL_VERSION=v1.14.2 20 | RUN curl -fsSLo /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl && \ 21 | chmod +x /usr/bin/kubectl 22 | 23 | # initialize index ahead of time 24 | RUN mkdir -p $HOME/.krew/index && \ 25 | git clone https://github.com/kubernetes-sigs/krew-index $HOME/.krew/index 26 | 27 | ENTRYPOINT [ "/usr/bin/env", "bash" ] 28 | -------------------------------------------------------------------------------- /lib/krew/hack/verify-boilerplate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Notice: this script was imported from k8s.io/kubernetes/hack/verify-boilerplate.sh 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. 24 | 25 | boilerDir="${KUBE_ROOT}/hack/boilerplate" 26 | boiler="${boilerDir}/boilerplate.py" 27 | 28 | files_need_boilerplate=($(${boiler} "$@")) 29 | 30 | # Run boilerplate check 31 | if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then 32 | for file in "${files_need_boilerplate[@]}"; do 33 | echo "Boilerplate header is wrong for: ${file}" >&2 34 | done 35 | 36 | exit 1 37 | fi 38 | -------------------------------------------------------------------------------- /lib/krew/hack/verify-installation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script verifies that a krew build can be installed to a system using 18 | # itself as the documented installation method. 19 | 20 | set -euo pipefail 21 | 22 | [[ -n "${DEBUG:-}" ]] && set -x 23 | 24 | SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 25 | build_dir="${SCRIPTDIR}/../out" 26 | goos="$(go env GOOS)" 27 | goarch="$(go env GOARCH)" 28 | 29 | krew_manifest="${build_dir}/krew.yaml" 30 | if [[ ! -f "${krew_manifest}" ]]; then 31 | echo >&2 "Could not find manifest ${krew_manifest}." 32 | echo >&2 "Did you run hack/make-all.sh?" 33 | exit 1 34 | fi 35 | 36 | krew_archive="${build_dir}/krew-${goos}_${goarch}.tar.gz" 37 | if [[ ! -f "${krew_archive}" ]]; then 38 | echo >&2 "Could not find archive ${krew_archive}." 39 | echo >&2 "Did you run hack/make-all.sh?" 40 | exit 1 41 | fi 42 | 43 | temp_dir="$(mktemp -d)" 44 | trap 'rm -rf -- "${temp_dir}"' EXIT 45 | echo >&2 "Extracting krew from tarball." 46 | tar zxf "${krew_archive}" -C "${temp_dir}" 47 | krew_binary="${temp_dir}/krew-${goos}_${goarch}" 48 | 49 | krew_root="$(mktemp -d)" 50 | trap 'rm -rf -- "${krew_root}"' EXIT 51 | system_path="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin" 52 | 53 | echo >&2 "Installing the krew build to a temporary directory." 54 | env -i KREW_ROOT="${krew_root}" \ 55 | "${krew_binary}" install \ 56 | --manifest="${krew_manifest}" \ 57 | --archive "${krew_archive}" 58 | 59 | echo >&2 "Verifying krew installation (symlink)." 60 | env -i PATH="${krew_root}/bin:${system_path}" /bin/bash -c \ 61 | "which kubectl-krew 1>/dev/null" 62 | -------------------------------------------------------------------------------- /lib/krew/integration_test/commandline_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package integrationtest 16 | 17 | import "testing" 18 | 19 | func TestUnknownCommand(t *testing.T) { 20 | skipShort(t) 21 | 22 | test := NewTest(t) 23 | 24 | if _, err := test.Krew("foobar").Run(); err == nil { 25 | t.Errorf("Expected `krew foobar` to fail") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/krew/integration_test/help_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package integrationtest 16 | 17 | import ( 18 | "regexp" 19 | "testing" 20 | ) 21 | 22 | func TestKrewHelp(t *testing.T) { 23 | skipShort(t) 24 | 25 | test := NewTest(t) 26 | 27 | test.Krew().RunOrFail() // no args 28 | test.Krew("help").RunOrFail() 29 | test.Krew("-h").RunOrFail() 30 | test.Krew("--help").RunOrFail() 31 | } 32 | 33 | func TestRootHelpShowsKubectlPrefix(t *testing.T) { 34 | skipShort(t) 35 | test := NewTest(t) 36 | 37 | out := string(test.Krew("help").RunOrFailOutput()) 38 | 39 | expect := []*regexp.Regexp{ 40 | regexp.MustCompile(`(?m)Usage:\s+kubectl krew`), 41 | regexp.MustCompile(`(?m)Use "kubectl krew`), 42 | } 43 | 44 | for _, e := range expect { 45 | if !e.MatchString(out) { 46 | t.Errorf("output does not have matching string to pattern %s ; output=%s", e, out) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/krew/integration_test/info_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package integrationtest 16 | 17 | import ( 18 | "strings" 19 | "testing" 20 | ) 21 | 22 | func TestKrewInfo(t *testing.T) { 23 | skipShort(t) 24 | 25 | test := NewTest(t) 26 | 27 | out := string(test.WithDefaultIndex().Krew("info", validPlugin).RunOrFailOutput()) 28 | expected := `INDEX: default` 29 | if !strings.Contains(out, expected) { 30 | t.Fatalf("info output doesn't have %q. output=%q", expected, out) 31 | } 32 | } 33 | 34 | func TestKrewInfoInvalidPlugin(t *testing.T) { 35 | skipShort(t) 36 | 37 | test := NewTest(t) 38 | 39 | plugin := "invalid-plugin" 40 | _, err := test.WithDefaultIndex().Krew("info", plugin).Run() 41 | if err == nil { 42 | t.Errorf("Expected `krew info %s` to fail", plugin) 43 | } 44 | } 45 | 46 | func TestKrewInfoCustomIndex(t *testing.T) { 47 | skipShort(t) 48 | 49 | test := NewTest(t) 50 | 51 | test = test.WithDefaultIndex().WithCustomIndexFromDefault("foo") 52 | test.Krew("install", "foo/"+validPlugin).RunOrFail() 53 | 54 | out := string(test.Krew("info", "foo/"+validPlugin).RunOrFailOutput()) 55 | expected := `INDEX: foo` 56 | if !strings.Contains(out, expected) { 57 | t.Fatalf("info output doesn't have %q. output=%q", expected, out) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/krew/integration_test/testdata/ctx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 2 | kind: Plugin 3 | metadata: 4 | name: ctx 5 | spec: 6 | homepage: https://github.com/ahmetb/kubectx 7 | shortDescription: Switch between contexts in your kubeconfig 8 | version: v0.7.0 9 | description: | 10 | Also known as "kubectx", a utility to switch between context entries in 11 | your kubeconfig file efficiently. 12 | caveats: | 13 | If fzf is installed on your machine, you can interactively choose 14 | between the entries using the arrow keys, or by fuzzy searching 15 | as you type. 16 | See https://github.com/ahmetb/kubectx for customization and details. 17 | platforms: 18 | - selector: 19 | matchExpressions: 20 | - key: os 21 | operator: In 22 | values: 23 | - darwin 24 | - linux 25 | uri: https://github.com/ahmetb/kubectx/archive/v0.7.1.tar.gz 26 | sha256: 6df4def2caf5a9c291310124098ad6c4c3123936ddd4080b382b9f7930a233ec 27 | bin: kubectx 28 | files: 29 | - from: kubectx-*/kubectx 30 | to: . 31 | - from: kubectx-*/LICENSE 32 | to: . 33 | -------------------------------------------------------------------------------- /lib/krew/integration_test/testdata/foo.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/integration_test/testdata/foo.tar.gz -------------------------------------------------------------------------------- /lib/krew/integration_test/testdata/foo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 2 | kind: Plugin 3 | metadata: 4 | name: foo 5 | spec: 6 | version: "v0.1.0" 7 | shortDescription: A valid plugin for integration tests 8 | platforms: 9 | - uri: https://foo.bar/foo.tar.gz 10 | sha256: 354bad230cdd0966fc8c919476c4e6c7f2078b04a6ff7dead6a811cdc101d31e 11 | bin: foo.sh 12 | files: 13 | - from: ./foo.sh 14 | to: "." 15 | selector: 16 | matchExpressions: 17 | - key: os 18 | operator: In 19 | values: ["darwin", "linux"] 20 | - uri: https://foo.bar/foo.tar.gz 21 | sha256: 354bad230cdd0966fc8c919476c4e6c7f2078b04a6ff7dead6a811cdc101d31e 22 | bin: foo.bat 23 | files: 24 | - from: ./foo.bat 25 | to: "." 26 | selector: 27 | matchLabels: 28 | os: windows 29 | -------------------------------------------------------------------------------- /lib/krew/internal/download/fetch.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package download 16 | 17 | import ( 18 | "io" 19 | "net/http" 20 | "os" 21 | 22 | "github.com/pkg/errors" 23 | "k8s.io/klog" 24 | ) 25 | 26 | // Fetcher is used to get files from a URI. 27 | type Fetcher interface { 28 | // Get gets the file and returns an stream to read the file. 29 | Get(uri string) (io.ReadCloser, error) 30 | } 31 | 32 | var _ Fetcher = HTTPFetcher{} 33 | 34 | // HTTPFetcher is used to get a file from a http:// or https:// schema path. 35 | type HTTPFetcher struct{} 36 | 37 | // Get gets the file and returns an stream to read the file. 38 | func (HTTPFetcher) Get(uri string) (io.ReadCloser, error) { 39 | klog.V(2).Infof("Fetching %q", uri) 40 | resp, err := http.Get(uri) 41 | if err != nil { 42 | return nil, errors.Wrapf(err, "failed to download %q", uri) 43 | } 44 | return resp.Body, nil 45 | } 46 | 47 | var _ Fetcher = fileFetcher{} 48 | 49 | type fileFetcher struct{ f string } 50 | 51 | func (f fileFetcher) Get(_ string) (io.ReadCloser, error) { 52 | klog.V(2).Infof("Reading %q", f.f) 53 | file, err := os.Open(f.f) 54 | return file, errors.Wrapf(err, "failed to open archive file %q for reading", f.f) 55 | } 56 | 57 | // NewFileFetcher returns a local file reader. 58 | func NewFileFetcher(path string) Fetcher { return fileFetcher{f: path} } 59 | -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/bash-ascii-file: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "test" -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/bash-utf8-file: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "test 😀 " -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/null-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/null-file -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/test-with-directory.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/test-with-directory.zip -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/test-with-nesting-with-directory-entries.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/test-with-nesting-with-directory-entries.tar.gz -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/test-with-nesting-without-directory-entries.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/test-with-nesting-without-directory-entries.tar.gz -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/test-without-directory.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/test-without-directory.tar.gz -------------------------------------------------------------------------------- /lib/krew/internal/download/testdata/test-without-directory.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/fenix-cli/445aaa2f896cb91b3541576c996fe2f1cb6fe557/lib/krew/internal/download/testdata/test-without-directory.zip -------------------------------------------------------------------------------- /lib/krew/internal/download/verifier.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package download 16 | 17 | import ( 18 | "bytes" 19 | "crypto/sha256" 20 | "encoding/hex" 21 | "hash" 22 | "io" 23 | 24 | "github.com/pkg/errors" 25 | "k8s.io/klog" 26 | ) 27 | 28 | // Verifier can check a reader against it's correctness. 29 | type Verifier interface { 30 | io.Writer 31 | Verify() error 32 | } 33 | 34 | var _ Verifier = sha256Verifier{} 35 | 36 | type sha256Verifier struct { 37 | hash.Hash 38 | wantedHash []byte 39 | } 40 | 41 | // NewSha256Verifier creates a Verifier that tests against the given hash. 42 | func NewSha256Verifier(hashed string) Verifier { 43 | raw, _ := hex.DecodeString(hashed) 44 | return sha256Verifier{ 45 | Hash: sha256.New(), 46 | wantedHash: raw, 47 | } 48 | } 49 | 50 | func (v sha256Verifier) Verify() error { 51 | klog.V(1).Infof("Compare sha256 (%s) signed version", hex.EncodeToString(v.wantedHash)) 52 | if bytes.Equal(v.wantedHash, v.Sum(nil)) { 53 | return nil 54 | } 55 | return errors.Errorf("checksum does not match, want: %x, got %x", v.wantedHash, v.Sum(nil)) 56 | } 57 | -------------------------------------------------------------------------------- /lib/krew/internal/download/verifier_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package download 16 | 17 | import ( 18 | "bytes" 19 | "io" 20 | "testing" 21 | ) 22 | 23 | func TestSha256Verifier(t *testing.T) { 24 | type args struct { 25 | hash string 26 | } 27 | tests := []struct { 28 | name string 29 | args args 30 | write []byte 31 | wantError bool 32 | }{ 33 | { 34 | name: "test okay hash", 35 | args: args{ 36 | hash: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", 37 | }, 38 | write: []byte("hello world"), 39 | wantError: false, 40 | }, 41 | { 42 | name: "test wrong hash", 43 | args: args{ 44 | hash: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", 45 | }, 46 | write: []byte("HELLO WORLD"), 47 | wantError: true, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | v := NewSha256Verifier(tt.args.hash) 53 | _, _ = io.Copy(v, bytes.NewReader(tt.write)) 54 | if err := v.Verify(); (err != nil) != tt.wantError { 55 | t.Errorf("NewSha256Verifier().Write(%x).Verify() = %v, wantReader %v", tt.write, err, tt.wantError) 56 | return 57 | } 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/dontscan.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: dontscan 19 | spec: 20 | platforms: 21 | - files: 22 | - from: "*" 23 | to: "." 24 | uri: https://example.com 25 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 26 | selector: 27 | matchExpressions: 28 | - {key: os, operator: In, values: [macos, linux]} 29 | - files: 30 | - from: "*" 31 | to: "." 32 | uri: https://example.com 33 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 34 | selector: 35 | matchLabels: 36 | os: "windows" 37 | shortDescription: "exists" 38 | 39 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/badplugin.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: badplugin 19 | BADKEYFIELD: {} # Unknown key should throw error. 20 | 21 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/badplugin2.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: badplugin 19 | spec: 20 | platforms: 21 | - BADKEYFIELD: {} 22 | 23 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/bar.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: bar 19 | spec: 20 | version: v1.0.0 21 | platforms: 22 | - files: 23 | - from: "*" 24 | to: "." 25 | uri: https://example.com 26 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 27 | bin: kubectl-bar 28 | selector: 29 | matchLabels: 30 | os: windows 31 | - files: 32 | - from: "*" 33 | to: "." 34 | uri: https://example.com 35 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 36 | bin: kubectl-bar 37 | selector: 38 | matchLabels: 39 | os: linux 40 | shortDescription: "exists" 41 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/foo.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: foo 19 | spec: 20 | version: v1.0.0 21 | platforms: 22 | - files: 23 | - from: "*" 24 | to: "." 25 | uri: https://example.com 26 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 27 | bin: kubectl-foo 28 | selector: 29 | matchExpressions: 30 | - {key: os, operator: In, values: [macos, linux]} 31 | - files: 32 | - from: "*" 33 | to: "." 34 | uri: https://example.com 35 | sha256: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 36 | bin: kubectl-foo 37 | selector: 38 | matchLabels: 39 | os: "windows" 40 | shortDescription: "exists" 41 | homepage: "https://example.com/foo" 42 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/notyaml.txt: -------------------------------------------------------------------------------- 1 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 2 | kind: Plugin 3 | metadata: 4 | name: notyaml-plugin 5 | -------------------------------------------------------------------------------- /lib/krew/internal/index/indexscanner/testdata/testindex/plugins/wrongname.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 16 | kind: Plugin 17 | metadata: 18 | name: mismatchedname 19 | -------------------------------------------------------------------------------- /lib/krew/internal/indexmigration/migration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package indexmigration 16 | 17 | import ( 18 | "os" 19 | "path/filepath" 20 | 21 | "github.com/pkg/errors" 22 | "k8s.io/klog" 23 | 24 | "sigs.k8s.io/krew/internal/environment" 25 | ) 26 | 27 | // Done checks if the krew installation requires a migration to support multiple indexes. 28 | // A migration is necessary when the index directory contains a ".git" directory. 29 | func Done(paths environment.Paths) (bool, error) { 30 | klog.V(2).Info("Checking if index migration is needed.") 31 | _, err := os.Stat(filepath.Join(paths.IndexBase(), ".git")) 32 | if err != nil && os.IsNotExist(err) { 33 | klog.V(2).Infoln("Index already migrated.") 34 | return true, nil 35 | } 36 | return false, err 37 | } 38 | 39 | // Migrate moves the index directory to the new default index path. 40 | func Migrate(paths environment.Paths) error { 41 | klog.Info("Migrating krew index layout.") 42 | indexPath := paths.IndexBase() 43 | tmpPath := filepath.Join(paths.BasePath(), "tmp_index_migration") 44 | newPath := filepath.Join(paths.IndexBase(), "default") 45 | 46 | if err := os.Rename(indexPath, tmpPath); err != nil { 47 | return errors.Wrapf(err, "could not move index directory %q to temporary location %q", indexPath, tmpPath) 48 | } 49 | 50 | if err := os.Mkdir(indexPath, os.ModePerm); err != nil { 51 | return errors.Wrapf(err, "could not create index directory %q", indexPath) 52 | } 53 | 54 | if err := os.Rename(tmpPath, newPath); err != nil { 55 | return errors.Wrapf(err, "could not move temporary index directory %q to new location %q", tmpPath, newPath) 56 | } 57 | 58 | klog.Info("Migration completed successfully.") 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /lib/krew/internal/indexmigration/migration_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package indexmigration 16 | 17 | import ( 18 | "os" 19 | "testing" 20 | 21 | "sigs.k8s.io/krew/internal/environment" 22 | "sigs.k8s.io/krew/internal/testutil" 23 | ) 24 | 25 | func TestIsMigrated(t *testing.T) { 26 | tests := []struct { 27 | name string 28 | dirPath string 29 | expected bool 30 | }{ 31 | { 32 | name: "Already migrated", 33 | dirPath: "index/default/.git", 34 | expected: true, 35 | }, 36 | { 37 | name: "Not migrated", 38 | dirPath: "index/.git", 39 | expected: false, 40 | }, 41 | } 42 | 43 | for _, test := range tests { 44 | t.Run(test.name, func(t *testing.T) { 45 | tmpDir := testutil.NewTempDir(t) 46 | 47 | err := os.MkdirAll(tmpDir.Path(test.dirPath), os.ModePerm) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | 52 | newPaths := environment.NewPaths(tmpDir.Root()) 53 | actual, err := Done(newPaths) 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | if actual != test.expected { 58 | t.Errorf("Expected %v but found %v", test.expected, actual) 59 | } 60 | }) 61 | } 62 | } 63 | 64 | func TestMigrate(t *testing.T) { 65 | tmpDir := testutil.NewTempDir(t) 66 | 67 | tmpDir.Write("index/.git", nil) 68 | 69 | newPaths := environment.NewPaths(tmpDir.Root()) 70 | err := Migrate(newPaths) 71 | if err != nil { 72 | t.Fatal(err) 73 | } 74 | done, err := Done(newPaths) 75 | if err != nil || !done { 76 | t.Errorf("expected migration to be done: %s", err) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/krew/internal/installation/receipt/receipt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package receipt 16 | 17 | import ( 18 | "io/ioutil" 19 | 20 | "github.com/pkg/errors" 21 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | "sigs.k8s.io/yaml" 23 | 24 | "sigs.k8s.io/krew/internal/index/indexscanner" 25 | "sigs.k8s.io/krew/pkg/index" 26 | ) 27 | 28 | // Store saves the given receipt at the destination. 29 | // The caller has to ensure that the destination directory exists. 30 | func Store(receipt index.Receipt, dest string) error { 31 | yamlBytes, err := yaml.Marshal(receipt) 32 | if err != nil { 33 | return errors.Wrapf(err, "convert to yaml") 34 | } 35 | 36 | err = ioutil.WriteFile(dest, yamlBytes, 0644) 37 | return errors.Wrapf(err, "write plugin receipt %q", dest) 38 | } 39 | 40 | // Load reads the plugin receipt at the specified destination. 41 | // If not found, it returns os.IsNotExist error. 42 | func Load(path string) (index.Receipt, error) { 43 | return indexscanner.ReadReceiptFromFile(path) 44 | } 45 | 46 | // New returns a new receipt with the given plugin and index name. 47 | func New(plugin index.Plugin, indexName string, timestamp metav1.Time) index.Receipt { 48 | plugin.CreationTimestamp = timestamp 49 | return index.Receipt{ 50 | Plugin: plugin, 51 | Status: index.ReceiptStatus{ 52 | Source: index.SourceIndex{ 53 | Name: indexName, 54 | }, 55 | }, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/krew/internal/installation/semver/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package semver is a wrapper for handling of semantic version 16 | // (https://semver.org) values. 17 | package semver 18 | 19 | import ( 20 | "strings" 21 | 22 | "github.com/pkg/errors" 23 | k8sver "k8s.io/apimachinery/pkg/util/version" 24 | ) 25 | 26 | // Version is in-memory representation of a semantic version 27 | // (https://semver.org) value. 28 | type Version k8sver.Version 29 | 30 | // String returns string representation of a semantic version value with a 31 | // leading 'v' character. 32 | func (v Version) String() string { 33 | vv := k8sver.Version(v) 34 | s := (&vv).String() 35 | if !strings.HasPrefix(s, "v") { 36 | s = "v" + s 37 | } 38 | return s 39 | } 40 | 41 | // Parse parses a semantic version value with a leading 'v' character. 42 | func Parse(s string) (Version, error) { 43 | var vv Version 44 | if !strings.HasPrefix(s, "v") { 45 | return vv, errors.Errorf("version string %q not starting with 'v'", s) 46 | } 47 | v, err := k8sver.ParseSemantic(s) 48 | if err != nil { 49 | return vv, err 50 | } 51 | return Version(*v), nil 52 | } 53 | 54 | // Less checks if a is strictly less than b (a d/b/c 40 | func ReplaceBase(path, old, replacement string) (string, error) { 41 | extendingPath, ok := IsSubPath(old, path) 42 | if !ok { 43 | return "", errors.Errorf("can't replace %q in %q, it is not a subpath", old, path) 44 | } 45 | return filepath.Join(replacement, extendingPath), nil 46 | } 47 | 48 | // CanonicalPluginName resolves a plugin's index and name from input string. 49 | // If an index is not specified, the default index name is assumed. 50 | func CanonicalPluginName(in string) (string, string) { 51 | if strings.Count(in, "/") == 0 { 52 | return constants.DefaultIndexName, in 53 | } 54 | p := strings.SplitN(in, "/", 2) 55 | return p[0], p[1] 56 | } 57 | -------------------------------------------------------------------------------- /lib/krew/internal/receiptsmigration/migration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // todo(corneliusweig) remove migration code with v0.4 16 | package receiptsmigration 17 | 18 | import ( 19 | "io/ioutil" 20 | 21 | "sigs.k8s.io/krew/internal/environment" 22 | ) 23 | 24 | // Done checks if the krew installation requires a migration. 25 | // It considers a migration necessary when plugins are installed, but no receipts are present. 26 | func Done(newPaths environment.Paths) (bool, error) { 27 | receipts, err := ioutil.ReadDir(newPaths.InstallReceiptsPath()) 28 | if err != nil { 29 | return false, err 30 | } 31 | plugins, err := ioutil.ReadDir(newPaths.BinPath()) 32 | if err != nil { 33 | return false, err 34 | } 35 | 36 | hasInstalledPlugins := len(plugins) > 0 37 | hasNoReceipts := len(receipts) == 0 38 | 39 | return !(hasInstalledPlugins && hasNoReceipts), nil 40 | } 41 | -------------------------------------------------------------------------------- /lib/krew/internal/testutil/receipt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package testutil 16 | 17 | import ( 18 | "sigs.k8s.io/krew/pkg/constants" 19 | "sigs.k8s.io/krew/pkg/index" 20 | ) 21 | 22 | type Receipt struct{ v index.Receipt } 23 | 24 | // NewReceipt builds an index.Receipt that is valid. 25 | func NewReceipt() *Receipt { 26 | return &Receipt{v: index.Receipt{ 27 | Status: index.ReceiptStatus{ 28 | Source: index.SourceIndex{ 29 | Name: constants.DefaultIndexName, 30 | }, 31 | }, 32 | }} 33 | } 34 | 35 | func (r *Receipt) WithPlugin(p index.Plugin) *Receipt { r.v.Plugin = p; return r } 36 | func (r *Receipt) WithStatus(s index.ReceiptStatus) *Receipt { r.v.Status = s; return r } 37 | func (r *Receipt) V() index.Receipt { return r.v } 38 | -------------------------------------------------------------------------------- /lib/krew/internal/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package version contains the version information of the krew binary. 16 | package version 17 | 18 | var ( 19 | // gitCommit contains the git commit identifier. 20 | gitCommit string 21 | 22 | // gitTag contains the git tag or describe output. 23 | gitTag string 24 | ) 25 | 26 | // GitCommit returns the value stamped into the binary at compile-time or a 27 | // default "unknown" value. 28 | func GitCommit() string { 29 | if gitCommit == "" { 30 | return "unknown" 31 | } 32 | return gitCommit 33 | } 34 | 35 | // GitTag returns the value stamped into the binary at compile-time or a 36 | // default "unknown" value. 37 | func GitTag() string { 38 | if gitTag == "" { 39 | return "unknown" 40 | } 41 | return gitTag 42 | } 43 | -------------------------------------------------------------------------------- /lib/krew/internal/version/version_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package version 16 | 17 | import "testing" 18 | 19 | func TestGitCommit(t *testing.T) { 20 | orig := gitCommit 21 | defer func() { gitCommit = orig }() 22 | 23 | gitCommit = "" 24 | if v := GitCommit(); v != "unknown" { 25 | t.Errorf("empty gitCommit, expected=\"unknown\" got=%q", v) 26 | } 27 | 28 | gitCommit = "abcdef" 29 | if v := GitCommit(); v != "abcdef" { 30 | t.Errorf("empty gitCommit, expected=\"abcdef\" got=%q", v) 31 | } 32 | } 33 | 34 | func TestGitTag(t *testing.T) { 35 | orig := gitTag 36 | defer func() { gitTag = orig }() 37 | 38 | gitTag = "" 39 | if v := GitTag(); v != "unknown" { 40 | t.Errorf("empty gitTag, expected=\"unknown\" got=%q", v) 41 | } 42 | 43 | gitTag = "abcdef" 44 | if v := GitTag(); v != "abcdef" { 45 | t.Errorf("empty gitTag, expected=\"abcdef\" got=%q", v) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/krew/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "site/" 3 | publish = "public/" 4 | command = "hugo && cd ./functions && go build -o api ./server" 5 | functions = "functions/" 6 | 7 | [build.environment] 8 | HUGO_VERSION = "0.65.1" 9 | 10 | [context.production.environment] 11 | HUGO_ENV = "production" 12 | 13 | [context.deploy-preview] 14 | command = "hugo --buildFuture -b $DEPLOY_PRIME_URL && cd ./functions && go build -o api ./server" 15 | 16 | 17 | [context.branch-deploy] 18 | command = "hugo --buildFuture -b $DEPLOY_PRIME_URL && cd ./functions && go build -o api ./server" 19 | 20 | -------------------------------------------------------------------------------- /lib/krew/pkg/constants/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package constants 16 | 17 | const ( 18 | CurrentAPIVersion = "krew.googlecontainertools.github.com/v1alpha2" 19 | PluginKind = "Plugin" 20 | ManifestExtension = ".yaml" 21 | KrewPluginName = "krew" // plugin name of krew itself 22 | 23 | // DefaultIndexURI points to the upstream index. 24 | DefaultIndexURI = "https://github.com/kubernetes-sigs/krew-index.git" 25 | // DefaultIndexName is a magic string that's used for a plugin name specified without an index. 26 | DefaultIndexName = "default" 27 | ) 28 | -------------------------------------------------------------------------------- /lib/krew/pkg/index/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package index 16 | 17 | import ( 18 | "os" 19 | 20 | "sigs.k8s.io/krew/pkg/constants" 21 | ) 22 | 23 | func DefaultIndex() string { 24 | if uri := os.Getenv("KREW_DEFAULT_INDEX_URI"); uri != "" { 25 | return uri 26 | } 27 | return constants.DefaultIndexURI 28 | } 29 | -------------------------------------------------------------------------------- /lib/krew/pkg/index/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Kubernetes Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package index 16 | 17 | import ( 18 | "os" 19 | "testing" 20 | 21 | "sigs.k8s.io/krew/pkg/constants" 22 | ) 23 | 24 | func TestDefaultIndex(t *testing.T) { 25 | if got := DefaultIndex(); got != constants.DefaultIndexURI { 26 | t.Errorf("DefaultIndex() = %q, want %q", got, constants.DefaultIndexURI) 27 | } 28 | 29 | want := "foo" 30 | os.Setenv("KREW_DEFAULT_INDEX_URI", want) 31 | defer os.Unsetenv("KREW_DEFAULT_INDEX_URI") 32 | 33 | if got := DefaultIndex(); got != want { 34 | t.Errorf("DefaultIndex() = %q, want %q", got, want) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/krew/site/.gitignore: -------------------------------------------------------------------------------- 1 | public/ 2 | resources/ 3 | -------------------------------------------------------------------------------- /lib/krew/site/config.yaml: -------------------------------------------------------------------------------- 1 | title: "Krew – kubectl plugin manager" 2 | baseURL: "https://krew.sigs.k8s.io/" 3 | languageCode: "en-us" 4 | enableGitInfo: true 5 | enableRobotsTXT: true 6 | disableKinds: 7 | - taxonomy 8 | - taxonomyTerm 9 | markup: 10 | highlight: 11 | style: dracula 12 | goldmark: 13 | renderer: 14 | unsafe: true # required for dynamic JS content editing 15 | -------------------------------------------------------------------------------- /lib/krew/site/content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | --- 4 | 5 | ## What is Krew? 6 | 7 | Krew is the plugin manager for `kubectl` command-line tool. 8 | 9 | Krew helps you: 10 | - discover [kubectl plugins][kpl], 11 | - install them on your machine, 12 | - and keep the installed plugins up-to-date. 13 | 14 | There are [ kubectl plugins][list] 15 | currently distributed on Krew. 16 | 17 | Krew works across all major platforms, like macOS, Linux and Windows. 18 | 19 | Krew also helps kubectl plugin developers: You can package and distribute your 20 | plugins on multiple platforms easily and makes them discoverable through a 21 | centralized plugin repository with Krew. 22 | 23 | [kpl]: https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ 24 | [list]: {{< relref "plugins.md" >}} 25 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Documentation 3 | slug: docs 4 | --- 5 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Developer Guide 3 | weight: 300 4 | --- 5 | 6 | This guide is for `kubectl` plugin developers looking to distribute their 7 | plugins with Krew. 8 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/custom-indexes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hosting Custom Plugin Indexes 3 | slug: custom-indexes 4 | weight: 500 5 | --- 6 | 7 | Krew comes with a plugin index named `default` that points to the 8 | [`krew-index` repository](https://github.com/kubernetes-sigs/krew), which allows 9 | centralized discovery through community curation. 10 | 11 | However, you can host your own plugin indexes (and possibly remove or replace the 12 | `default` index). Hosting your own plugin index is not recommended, unless you 13 | have a use case that specifically calls for it, such as: 14 | 15 | - Your plugin is not accepted to `krew-index` 16 | - You want full control over the distribution lifecycle of your own plugin 17 | - You want to run a _private_ plugin index in your organization (e.g. 18 | for installations on developer machines) 19 | 20 | Hosting your own custom index is simple: 21 | 22 | - Custom index repositories must be `git` repositories. 23 | - Your clients should have read access to the repository. If the repository 24 | is not public, users can still authenticate to it with SSH keys or other 25 | [gitremote-helpers](https://git-scm.com/docs/gitremote-helpers) installed 26 | on the client machine. 27 | - The repository must contain a `plugins/` directory at the root, with at least 28 | one plugin manifest in it. Plugin manifests should be directly in this 29 | directory (not in a subdirectory). 30 | - Ensure plugin manifests are valid YAML and pass Krew manifest validation 31 | (optionally, you can use the 32 | [validate-krew-manifest](https://github.com/kubernetes-sigs/krew/tree/master/cmd/validate-krew-manifest) 33 | tool for static analysis). 34 | 35 | Example plugin repository layout: 36 | 37 | ```text 38 | . 39 | └── plugins/ 40 | ├── plugin-a.yaml 41 | ├── plugin-b.yaml 42 | └── plugin-c.yaml 43 | ``` 44 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/develop/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Developing kubectl plugins 3 | weight: 100 4 | --- 5 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/develop/plugin-development.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction to plugin development 3 | weight: 100 4 | --- 5 | 6 | If you are looking to start developing plugins for `kubectl`, read the 7 | [Kubernetes 8 | documentation](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/) 9 | on this topic. 10 | 11 | To summarize the documentation, the procedure is to: 12 | 13 | - Create an executable binary, named `kubectl-foo` (for example) to have a plugin that can be 14 | invoked as `kubectl foo`. 15 | - Place the executable in a directory that is listed in the user’s `PATH` environment 16 | variable. (You don't have to do this for plugins distributed with Krew). 17 | - You can't overwrite a built-in `kubectl` command with a plugin. 18 | 19 | > **Note:** If you are writing a plugin in Go, consider using the [cli-runtime] project, 20 | > which is designed to provide the same command-line arguments, kubeconfig 21 | > parser, Kubernetes API REST client, and printing logic. Look at 22 | > [sample-cli-plugin] for an example of a kubectl plugin. 23 | > 24 | > Also, see the unofficial [GitHub template 25 | > repo](https://github.com/replicatedhq/krew-plugin-template) for a Krew plugin 26 | > in Go that implements some best practices covered later in this guide, and helps 27 | > you automate releases using GoReleaser to create a release when a tag is pushed. 28 | 29 | [cli-runtime]: https://github.com/kubernetes/cli-runtime/ 30 | [sample-cli-plugin]: https://github.com/kubernetes/sample-cli-plugin 31 | 32 | When developing your own plugins, make sure you check out: 33 | 34 | - [Plugin naming guide]({{}}) to choose a good name 35 | for your plugin 36 | - [Plugin development best practices]({{}}) guide 37 | for a brief checklist of what we're looking for in the submitted plugins. 38 | 39 | After you develop a plugin with a good name following the best practices, you 40 | can [develop a Krew plugin manifest]({{}}) and 41 | [submit your plugin to Krew]({{}}). 42 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/distributing-with-krew.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Distributing plugins on Krew 3 | weight: 110 4 | --- 5 | 6 | ## Why use Krew for distribution? {#why} 7 | 8 | On the surface, installing a kubectl plugin seems simple enough -- all you need to do is to place 9 | an executable in the user’s `PATH` prefixed with `kubectl-` -- that you may be 10 | considering some other alternatives to Krew, such as: 11 | 12 | - Having the user manually download the plugin executable and move it to some directory in 13 | the `PATH` 14 | - Distributing the plugin executable using an OS package manager, like Homebrew 15 | (macOS), apt/yum (Linux), or Chocolatey (Windows) 16 | - Distributing the plugin executable using a language package manager (e.g. npm or 17 | go get) 18 | 19 | While these approaches are not necessarily unworkable, potential drawbacks to consider include: 20 | 21 | - How to get updates to users (in the case of manual installation) 22 | - How to package a plugin for multiple platforms (macOS, Linux, and Windows) 23 | - How to ensure your users have the appropriate language package manager (go, npm) 24 | - How to handle a change to the implementation language (e.g. a move from npm to another package manager) 25 | 26 | Krew solves these problems cleanly for all kubectl plugins, since it's designed 27 | **specifically to address these shortcomings**. With Krew, after you write a plugin 28 | manifest once your plugin can be installed on all platforms 29 | without having to deal with their package managers. 30 | 31 | ## Steps to get started 32 | 33 | Once you [develop]({{< ref "develop/plugin-development.md" >}}) a `kubectl` 34 | plugin, follow these steps to distribute your plugin on Krew: 35 | 36 | 1. Package your plugin into an archive file (`.tar.gz` or `.zip`). 37 | 1. Make the archive file publicly available (e.g. as GitHub release files). 38 | 1. Write a [Krew plugin manifest]({{< ref "plugin-manifest.md" >}}) file. 39 | 1. [Submit your plugin to krew-index]({{< ref "release/../release/submitting-to-krew.md" >}}). 40 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/example-plugin-manifests.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Example plugin manifests 3 | slug: example-manifests 4 | weight: 200 5 | --- 6 | 7 | Learning how to [write plugin manifests]({{< ref "plugin-manifest.md" >}}) 8 | can be a time-consuming task. 9 | 10 | The Krew team encourages you to copy and adapt plugin manifests of [existing 11 | plugins][list]. Since these are already reviewed and approved, your plugin is 12 | likely to be accepted more quickly. 13 | 14 | * **Go:** 15 | - [tree](https://github.com/kubernetes-sigs/krew-index/blob/master/plugins/tree.yaml): 16 | supports Windows/Linux/macOS, per-OS builds, extracts all files from the 17 | archive 18 | - [sort-manifests](https://github.com/kubernetes-sigs/krew-index/blob/master/plugins/sort-manifests.yaml): 19 | Linux/macOS only, extracting specific files 20 | 21 | * **Bash:** 22 | - [ctx](https://github.com/kubernetes-sigs/krew-index/blob/master/plugins/ctx.yaml): 23 | Linux/macOS only, downloads GitHub tag tarball, extracts using wildcards 24 | 25 | * **Rust:** 26 | - [view-allocations](https://github.com/kubernetes-sigs/krew-index/blob/master/plugins/view-allocations.yaml): 27 | Linux/macOS only, implicitly extracts all files from the archive 28 | 29 | [list]: https://github.com/kubernetes-sigs/krew-index/tree/master/plugins 30 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/installing-locally.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing plugin installation locally 3 | slug: testing-locally 4 | weight: 300 5 | --- 6 | 7 | After you have written your [plugin manifest]({{< ref "plugin-manifest.md" >}}) 8 | and archived your plugin into a `.zip` or `.tar.gz` file, you can verify that 9 | your plugin installs correctly with Krew by running: 10 | 11 | ```sh 12 | {{}}kubectl krew install --manifest=foo.yaml --archive=foo.tar.gz 13 | ``` 14 | 15 | - The `--manifest` flag specifies a custom manifest rather than using 16 | the default [krew index][index] 17 | - `--archive` overrides the download `uri:` specified in the plugin manifest and 18 | uses a local `.zip` or `.tar.gz` file instead. 19 | 20 | If the installation **fails**, run the command again with `-v=4` flag to see the 21 | verbose logs and examine what went wrong. 22 | 23 | If the installation **succeeds**, you should now be able to run your plugin. 24 | 25 | If you made your archive file available for download on the Internet, run the 26 | same command without the `--archive` option and actually test downloading the 27 | file from the specified `uri` and validate its `sha256` sum is correct. 28 | 29 | After you have tested your plugin installation, uninstall it with `kubectl krew uninstall foo`. 30 | 31 | ### Testing other platforms 32 | 33 | If you need to test other `platforms` definitions that don't match your current machine, 34 | you can use the `KREW_OS` and `KREW_ARCH` environment variables to override the 35 | OS and architecture that Krew thinks it's running on. 36 | 37 | For example, if you're on a Linux machine, you can test Windows installation 38 | with: 39 | 40 | ```sh 41 | {{}}KREW_OS=windows KREW_ARCH=amd64 krew install --manifest=[...] 42 | ``` 43 | 44 | [index]: https://github.com/kubernetes-sigs/krew-index 45 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/plugin-stats.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Plugin usage analytics 3 | slug: plugin-stats 4 | weight: 600 5 | --- 6 | 7 | Krew does not track user behavior. However, for plugins that distribute their 8 | packages as assets on [GitHub 9 | releases], 10 | Krew offers some statistics to track download analytics for your plugins over 11 | time. 12 | 13 | To see your plugin’s download statistics over time: 14 | 15 | 1. Visit the [stats.krew.dev] dashboard. 16 | 2. Click the “Individual Plugin Stats” report. 17 | 3. Choose your plugin from the dropdown and browse the data for your plugin. 18 | 19 | This data is obtained by scraping the downloads count of your plugin assets via 20 | the [GitHub API] regularly. Since Krew does not track its users, this data: 21 | 22 | - does not reflect active installations 23 | - does not distinguish between installs, reinstalls, and upgrades 24 | - is purely a tracking of download counts of your release assets over time 25 | 26 | > **Note:** The Krew plugin stats dashboard is provided as a best effort by Krew 27 | > maintainers to measure the success of Krew and its plugins. We cannot guarantee 28 | > its availability and accuracy. 29 | > 30 | > The scraping code can be found 31 | > [here](https://github.com/corneliusweig/krew-index-tracker). 32 | 33 | [GitHub releases]: https://help.github.com/en/github/administering-a-repository/managing-releases-in-a-repository 34 | [stats.krew.dev]: https://datastudio.google.com/c/reporting/f74370a0-adcf-4cec-b7bd-a58c638948f5/page/Ufl7 35 | [GitHub API]: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release 36 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/release/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Releasing 3 | weight: 400 4 | --- 5 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/release/plugin-updates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Releasing plugin updates 3 | slug: updating-plugins 4 | weight: 200 5 | --- 6 | 7 | When you have a newer version of your plugin, you can update your plugin 8 | manifest at the [krew-index] repository to distribute this new version to your users. 9 | 10 | This manual operation looks like: 11 | 12 | 1. Update the `version`, `uri`, and `sha256` fields of the plugin manifest file. 13 | 1. [Test plugin installation locally]({{< ref "../installing-locally.md" >}}) 14 | 1. Make a pull request to [krew-index] to update the plugin manifest file. 15 | 16 | > **Note:** Ideally, the specified `version:` field should match the release tag 17 | of the plugin. This helps users and maintainers to easily identify which 18 | version of the plugin they have installed. 19 | 20 | If you only change the `version`, `uri` and `sha256` fields of your plugin manifest, 21 | your pull request will be automatically approved, tested, and merged ([see an 22 | example](https://github.com/kubernetes-sigs/krew-index/pull/508)). 23 | 24 | You can [**automate releasing plugin updates**]({{< ref 25 | "release-automation.md" >}}) if you're publishing your plugins on GitHub. 26 | 27 | [krew-index]: https://sigs.k8s.io/krew-index 28 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/release/release-automation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Automating plugin updates 3 | slug: automating-updates 4 | weight: 300 5 | --- 6 | 7 | Normally, [releasing a new version]({{< ref "plugin-updates.md" >}}) requires manual 8 | work and creating a pull request every time you have a new version. 9 | 10 | However, you can use a **Github Action** to publish new releases of your Krew plugin. 11 | 12 | Specifically, `krew-release-bot` is a Github Action to automatically bump the version in 13 | `krew-index` repo every time you push a new git tag to your repository: 14 | 15 | - It requires no secrets (e.g. `GITHUB_TOKEN`) to operate. 16 | - It creates your plugin manifest dynamically from a template you write. 17 | - It makes pull requests on your behalf to the `krew-index` repository. 18 | 19 | Refer to the [krew-release-bot](https://github.com/rajatjindal/krew-release-bot) 20 | documentation for details. 21 | 22 | The Krew team **strongly recommends** automating your plugin's releases. Trivial 23 | version bumps are automatically tested and merged without human intervention, 24 | usually under five minutes ([see an example of bots talking to each 25 | other](https://github.com/kubernetes-sigs/krew-index/pull/490)). 26 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/developer-guide/release/submitting-to-krew.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Submitting plugins to Krew 3 | slug: new-plugin 4 | weight: 100 5 | --- 6 | 7 | Krew maintains a centralized plugin index at the [krew-index] repository. 8 | This repository is cloned on each Krew user’s machine to help them find 9 | existing plugins. 10 | 11 | ## Pre-submit checklist 12 | 13 | 1. Review the [Krew plugin naming guide]({{< ref 14 | "../develop/naming-guide.md" >}}). 15 | 1. Read the [plugin development best practices]({{< ref 16 | "../develop/best-practices.md" >}}). 17 | 1. Make sure your plugin’s source code is available as open source. 18 | 1. Adopt an open source license, and add it to your plugin archive file. 19 | 1. Make sure to extract the LICENSE file during the plugin installation. 20 | 1. Tag a git release with a [semantic 21 | version](https://semver.org) (e.g. `v1.0.0`). 22 | 1. [Test your plugin installation locally]({{< ref "../installing-locally.md" >}}). 23 | 24 | ## Submitting a plugin to krew-index 25 | 26 | Once you've run through the checklist above, create a **pull request** to the 27 | [krew-index] repository with your plugin manifest file (e.g. `example.yaml`) to 28 | the `plugins/` directory. 29 | 30 | After your pull request is merged, users will be able to find and [install]({{< ref 31 | "../../user-guide/install.md" >}}) your plugin through Krew. 32 | 33 | [krew-index]: https://sigs.k8s.io/krew-index 34 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: User Guide 3 | weight: 200 4 | --- 5 | 6 | Learn how to use Krew to its full extent. 7 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Advanced Configuration 3 | slug: advanced-configuration 4 | weight: 900 5 | --- 6 | 7 | {{< toc >}} 8 | 9 | ## Customize installation directory {#custom-install-dir} 10 | 11 | By default, Krew installs itself and plugins to `$HOME/.krew`. This means 12 | Krew itself and the installed plugins will be visible only to the user who 13 | installed it. 14 | 15 | To customize this installation path, set the `KREW_ROOT` environment variable 16 | while [installing Krew]({{< relref "setup/install.md" >}}). After Krew is 17 | installed, you still need to set `KREW_ROOT` in your environment for Krew 18 | to be able to find its installation directory. 19 | 20 | For example, add this to your `~/.bashrc` or `~/.zshrc` file: 21 | 22 | ```shell 23 | export KREW_ROOT="/usr/local/krew" 24 | ``` 25 | 26 | Note that you still need to add `$KREW_ROOT/bin` to your `PATH` variable 27 | for `kubectl` to be able to find installed plugins. 28 | 29 | ## Use a different default index {#custom-default-index} 30 | 31 | When Krew is installed, it automatically initializes an index named `default` 32 | pointing to the [krew-index][ki] repository. You can force Krew to use a 33 | different repository by setting `KREW_DEFAULT_INDEX_URI` before running the 34 | [installation instructions]({{}}) or after [removing the 35 | default index]({{}}). 36 | `KREW_DEFAULT_INDEX_URI` must point to a git repository URI that uses a valid 37 | git remote protocol. 38 | 39 | To use a different default index, set the `KREW_DEFAULT_INDEX_URI` environment 40 | variable in your `~/.bashrc`, `~/.bash_profile`, or `~/.zshrc`: 41 | 42 | ```shell 43 | export KREW_DEFAULT_INDEX_URI='git@github.com:foo/custom-index.git' 44 | ``` 45 | 46 | [ki]: https://github.com/kubernetes-sigs/krew-index 47 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installing Plugins 3 | slug: installing-plugins 4 | weight: 400 5 | --- 6 | 7 | Plugins can be installed with the `kubectl krew install` command: 8 | 9 | ```text 10 | {{}}kubectl krew install ca-cert 11 | {{}}Installing plugin: ca-cert 12 | Installed plugin: ca-cert{{}} 13 | ``` 14 | 15 | This command downloads the plugin and verifies the integrity of the downloaded 16 | file. 17 | 18 | After installing a plugin, you can start using it by running `kubectl `: 19 | 20 | ```sh 21 | {{}}kubectl ca-cert 22 | ``` 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/list.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Listing Installed Plugins 3 | slug: list 4 | weight: 500 5 | --- 6 | 7 | To list all plugins installed via Krew, run: 8 | 9 | ```sh 10 | {{}}kubectl krew list 11 | ``` 12 | 13 | You can list all installed `kubectl` plugins (including those not installed via 14 | Krew) using: 15 | 16 | ```sh 17 | {{}}kubectl plugin list 18 | ``` 19 | 20 | ### Backing up plugin list 21 | 22 | When you pipe or redirect the `kubectl krew list` command’s output to another file 23 | or command, it will return a list of plugin names installed, e.g.: 24 | 25 | ```sh 26 | {{}}kubectl krew list | tee backup.txt 27 | access-matrix 28 | whoami 29 | tree 30 | ``` 31 | 32 | You can then [install]({{}}) the list of plugins from the file 33 | (on another machine, for example) by feeding the file to the `install` command over 34 | standard input (stdin): 35 | 36 | ```sh 37 | {{}}kubectl krew install < backup.txt 38 | ``` 39 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/quickstart.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quickstart 3 | slug: quickstart 4 | weight: 100 5 | --- 6 | 7 | Krew helps you discover and install [`kubectl` plugins][kpl] on your machine. 8 | 9 | You can install and use [a wide variety of][list] `kubectl` plugins to enhance 10 | your Kubernetes experience. 11 | 12 | Let's get started: 13 | 14 | 1. [Install and set up]({{}}) Krew on your machine. 15 | 16 | 1. Download the plugin list: 17 | 18 | ```sh 19 | {{}}kubectl krew update 20 | ``` 21 | 22 | 1. Discover plugins available on Krew: 23 | 24 | ```sh 25 | {{}}kubectl krew search 26 | {{}}NAME DESCRIPTION INSTALLED 27 | access-matrix Show an RBAC access matrix for server resources no 28 | advise-psp Suggests PodSecurityPolicies for cluster. no 29 | auth-proxy Authentication proxy to a pod or service no 30 | [...]{{}} 31 | ``` 32 | 33 | 1. Choose a plugin from the list and install it: 34 | 35 | ```sh 36 | {{}}kubectl krew install access-matrix 37 | ``` 38 | 39 | 1. Use the installed plugin: 40 | 41 | ```sh 42 | {{}}kubectl access-matrix 43 | ``` 44 | 45 | 1. Keep your plugins up-to-date: 46 | 47 | ```sh 48 | {{}}kubectl krew upgrade 49 | ``` 50 | 51 | 1. Uninstall a plugin you no longer use: 52 | 53 | ```sh 54 | {{}}kubectl krew uninstall access-matrix 55 | ``` 56 | 57 | This is practically all you need to know to start using Krew. 58 | 59 | [kpl]: https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ 60 | [list]: {{< relref "plugins.md" >}} 61 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Discovering Plugins 3 | slug: discovering-plugins 4 | weight: 300 5 | --- 6 | 7 | You can find a list of `kubectl` plugins distributed via Krew [here][list]. 8 | However, you can find plugins using the command line as well. 9 | 10 | ## Search available plugins 11 | 12 | First, refresh your local copy of the plugin index: 13 | 14 | ```sh 15 | {{}}kubectl krew update 16 | ``` 17 | 18 | To list all plugins available, run: 19 | 20 | ```text 21 | {{}}kubectl krew search 22 | {{}} 23 | NAME DESCRIPTION INSTALLED 24 | access-matrix Show an RBAC access matrix for server resources no 25 | advise-psp Suggests PodSecurityPolicies for cluster. no 26 | auth-proxy Authentication proxy to a pod or service no 27 | bulk-action Do bulk actions on Kubernetes resources. no 28 | ca-cert Print the PEM CA certificate of the current clu... no 29 | ...{{}} 30 | ``` 31 | 32 | You can specify search keywords as arguments: 33 | 34 | ```sh 35 | {{}}kubectl krew search pod 36 | {{}} 37 | NAME DESCRIPTION INSTALLED 38 | evict-pod Evicts the given pod no 39 | pod-dive Shows a pod's workload tree and info inside a node no 40 | pod-logs Display a list of pods to get logs from no 41 | pod-shell Display a list of pods to execute a shell in no 42 | rm-standalone-pods Remove all pods without owner references no 43 | support-bundle Creates support bundles for off-cluster analysis no{{}} 44 | ``` 45 | 46 | ## Learn more about a plugin 47 | 48 | To get more information on a plugin, run `kubectl krew info `: 49 | 50 | ```sh 51 | {{}} kubectl krew info tree 52 | {{}} 53 | NAME: tree 54 | VERSION: v0.4.0 55 | DESCRIPTION: 56 | This plugin shows sub-resources of a specified Kubernetes API object in a 57 | tree view in the command-line. The parent-child relationship is discovered 58 | using ownerReferences on the child object. 59 | ...{{}} 60 | ``` 61 | 62 | [list]: {{< relref "plugins.md" >}} 63 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/setup/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setup 3 | weight: 200 4 | --- 5 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/setup/uninstall.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uninstalling Krew 3 | slug: uninstall 4 | weight: 200 5 | --- 6 | 7 | To remove Krew and its associated plugins altogether, run this command on your Linux or macOS machine: 8 | 9 | ```sh 10 | {{}}rm -rf -- ~/.krew 11 | ``` 12 | 13 | On Windows, remove the `%USERPROFILE%\.krew` directory. 14 | 15 | > **Note:** If you installed Krew with another package manager (e.g. Homebrew), 16 | > follow their instructions for uninstalling in addition to the instructions above. 17 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/setup/updates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Update checks 3 | slug: update 4 | weight: 300 5 | --- 6 | 7 | Krew will occasionally check if a new version is available and remind you to 8 | upgrade to a newer version. 9 | 10 | This is done by calling the GitHub API, and the process does not collect any data from your 11 | machine. 12 | 13 | If you want to disable the update checks, set the `KREW_NO_UPGRADE_CHECK` 14 | environment variable. To permanently disable this feature, add the following to your 15 | `~/.bashrc`, `~/.bash_profile`, or `~/.zshrc`: 16 | 17 | ```shell 18 | export KREW_NO_UPGRADE_CHECK=1 19 | ``` 20 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/uninstall.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uninstalling Plugins 3 | slug: uninstalling-plugins 4 | weight: 700 5 | --- 6 | 7 | When you don't need a plugin anymore you can uninstall it with: 8 | 9 | ```sh 10 | {{}}kubectl krew uninstall 11 | ``` 12 | -------------------------------------------------------------------------------- /lib/krew/site/content/docs/user-guide/upgrade.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrading Plugins 3 | slug: upgrading-plugins 4 | weight: 600 5 | --- 6 | 7 | To upgrade all plugins that you have installed to their latest versions, run: 8 | 9 | ```sh 10 | {{}}kubectl krew upgrade 11 | ``` 12 | 13 | Since Krew itself is a plugin also managed through Krew, running the upgrade 14 | command will also upgrade your `krew` setup to the latest version. 15 | 16 | To upgrade only certain plugins, you can explicitly specify their names: 17 | 18 | ```sh 19 | {{}}kubectl krew upgrade 20 | ``` 21 | -------------------------------------------------------------------------------- /lib/krew/site/content/plugins.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kubectl plugins available 3 | slug: plugins 4 | --- 5 | 6 | Below you will find the list of kubectl plugins distributed on the centralized 7 | [krew-index](https://sigs.k8s.io/krew-index). To install these plugins on 8 | your machine: 9 | 10 | 1. [Install Krew]({{< relref "docs/user-guide/setup/install.md" >}}) 11 | 2. Run `kubectl krew install ` to install a plugin via Krew. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
NameDescriptionRepository
Loading...
28 | -------------------------------------------------------------------------------- /lib/krew/site/functions/README.md: -------------------------------------------------------------------------------- 1 | # Dynamic functions on Krew documentation 2 | 3 | Krew site makes use of Netlify Functions (lambdas) to fetch plugin list 4 | dynamically from `krew-index` repository using GitHub API. 5 | 6 | ## Set up on Netlify 7 | 8 | Functions require a one-time set up in the Netlify console. 9 | 10 | Regarding **GitHub API rate limits**: 11 | 12 | - In production, make **sure to set a `GITHUB_ACCESS_TOKEN` environment 13 | variable** with a permissionless "personal access token" to elevate the rate 14 | limits for our functions. 15 | 16 | Dynamic responses from the functions are cached on 17 | Netlify’s CDN for a long time, so this is not a huge problem and a single 18 | token is very likely to suffice a long period of time. 19 | 20 | - During local development, you can hit the GitHub API rate limit as well. 21 | You should set the `GITHUB_ACCESS_TOKEN` environment variable as needed. 22 | 23 | ## Local development 24 | 25 | Start `hugo` local iteration server on port 1313: 26 | 27 | ``` 28 | cd ./site 29 | hugo serve 30 | ``` 31 | 32 | In another terminal window, build and start the functions server on port 8080: 33 | 34 | ``` 35 | cd ./functions 36 | go run ./server -port=8080 37 | ``` 38 | 39 | Now, you can reach the website at http://localhost:8080 and the functions at 40 | paths defined in the code e.g. 41 | http://localhost:8080/.netlify/functions/api/plugins. 42 | -------------------------------------------------------------------------------- /lib/krew/site/functions/go.mod: -------------------------------------------------------------------------------- 1 | module sigs.k8s.io/krew/site/functions 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/apex/gateway v1.1.1 7 | github.com/aws/aws-lambda-go v1.19.1 8 | github.com/google/go-github/v32 v32.1.0 9 | github.com/pkg/errors v0.9.1 10 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be 11 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 12 | gopkg.in/yaml.v2 v2.2.8 13 | sigs.k8s.io/krew v0.4.0 14 | sigs.k8s.io/yaml v1.2.0 15 | ) 16 | 17 | // replace sigs.k8s.io/krew => ../../ 18 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ partial "header.html" . }} 2 | 3 |

Not found

4 | 5 |

6 | Sorry, this URL cannot be found. Maybe it’s moved. 7 |

8 | 9 | ← Home 10 | 11 | {{ partial "footer.html" . }} 12 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ partial "header.html" . }} 2 |
3 |

{{.Title}}

4 | {{ with .Content }} 5 | {{.}} 6 | {{ else }} 7 |
This page is not yet written.
8 | {{ end }} 9 |
10 | 11 | {{ partial "backbutton.html" .}} 12 | {{ partial "footer.html" . }} 13 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/docs/section.html: -------------------------------------------------------------------------------- 1 | {{ $isDocsHome := (eq .Slug "docs") }} 2 | {{ partial "header.html" . }} 3 |
4 |

5 | {{ if $isDocsHome }} 6 | Documentation 7 | {{else}} 8 | {{ .Title}} 9 | {{end}} 10 |

11 | 12 | {{ with .Content }} 13 | 14 | {{ end }} 15 | 16 | {{ partial "toc.html" . }} 17 | 18 | {{ if not $isDocsHome }} 19 | {{ partial "backbutton.html" .}} 20 | {{ end }} 21 |
22 | {{ partial "footer.html" . }} 23 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/index.html: -------------------------------------------------------------------------------- 1 | {{ partial "header.html" . }} 2 | 3 | 15 | 16 | {{ partial "footer.html" . }} 17 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/partials/backbutton.html: -------------------------------------------------------------------------------- 1 | {{ $docsHome := "/docs" }} 2 | {{ $userGuide := "/docs/user-guide" }} 3 | {{ $devGuide := "/docs/developer-guide" }} 4 | 5 | {{ $isUserGuide := .Parent.IsDescendant (.Site.GetPage "section" $userGuide) }} 6 | {{ $isDevGuide := .Parent.IsDescendant (.Site.GetPage "section" $devGuide) }} 7 | 8 | {{ $parent := "" }} 9 | {{ if $isUserGuide }} 10 | {{ $parent = $userGuide }} 11 | {{ else if $isDevGuide }} 12 | {{ $parent = $devGuide }} 13 | {{ else }} 14 | {{ $parent = $docsHome }} 15 | {{ end }} 16 | 17 | {{ $parent := .Site.GetPage "section" $parent }} 18 | 19 | 20 | ← {{ $parent.Title }} 21 | 22 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ if .IsHome }} 9 | {{ .Site.Title }} 10 | {{ else }} 11 | {{ .Title }} · Krew 12 | {{ end }} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {{ partial "navbar.html" . }} 25 | 26 |
30 | 31 |
32 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/partials/navbar.html: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/partials/toc.html: -------------------------------------------------------------------------------- 1 | {{ with .Pages}} 2 |
    3 | {{ range . }} 4 | {{ if .Pages }} 5 |
  • {{.Name}}
  • 6 | {{ partial "toc.html" .}} 7 | {{ else }} 8 |
  • 9 | {{.Name}} 10 |
  • 11 | {{ end }} 12 | {{ end }} 13 |
14 | {{ end }} 15 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | {{ if ne ( getenv "HUGO_ENV" ) "production" -}} 3 | Disallow: / 4 | {{- end -}} 5 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/shortcodes/output.html: -------------------------------------------------------------------------------- 1 | {{- .Inner -}}{{- /* 2 | */ -}} 3 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/shortcodes/prompt.html: -------------------------------------------------------------------------------- 1 | $ {{- /* 2 | */ -}} 3 | -------------------------------------------------------------------------------- /lib/krew/site/layouts/shortcodes/toc.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /lib/krew/site/static/css/style.css: -------------------------------------------------------------------------------- 1 | div.top-level-container { 2 | max-width: 960px; 3 | } 4 | 5 | blockquote, .blockquote { 6 | margin-left: 12px; 7 | color: #555; 8 | max-width: 520px; 9 | border-left: 2px solid #ddd; 10 | padding-left: 12px; 11 | } 12 | 13 | article h1, article h2, article h3, article h4 { 14 | font-weight: 300; 15 | } 16 | 17 | pre { 18 | padding: 12px; 19 | overflow: auto 20 | } 21 | 22 | .noselect { 23 | -webkit-touch-callout: none; 24 | -webkit-user-select: none; 25 | -khtml-user-select: none; 26 | -moz-user-select: none; 27 | -ms-user-select: none; 28 | user-select: none; 29 | } 30 | 31 | .cliprompt { 32 | color: orange; 33 | } 34 | 35 | pre .cmdoutput { 36 | color: #aaa; 37 | } 38 | 39 | .lead { 40 | letter-spacing: -0.4px; 41 | font-weight: 300; 42 | } 43 | 44 | article aside.toc { 45 | background-color: #f8f8f8;; 46 | font-size: 1rem; 47 | } 48 | -------------------------------------------------------------------------------- /lib/krew/site/static/img/favicon.svg: -------------------------------------------------------------------------------- 1 | ../../../assets/logo/icon/color/krew-icon-color.svg -------------------------------------------------------------------------------- /lib/krew/site/static/img/krew-logo.svg: -------------------------------------------------------------------------------- 1 | ../../../assets/logo/horizontal/color/krew-horizontal-color.svg -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt" 5 | "github.com/fenixsoft/fenix-cli/src/environments" 6 | "github.com/fenixsoft/fenix-cli/src/environments/docker" 7 | "github.com/fenixsoft/fenix-cli/src/environments/istio" 8 | "github.com/fenixsoft/fenix-cli/src/environments/kubernetes" 9 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 10 | _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" 11 | _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" 12 | "os" 13 | ) 14 | 15 | func main() { 16 | // init environment providers and select the active one 17 | environments.Registers = map[environments.Environment]environments.Register{ 18 | environments.Docker: docker.RegisterEnv, 19 | environments.Kubernetes: kubernetes.RegisterEnv, 20 | environments.Istio: istio.RegisterEnv, 21 | } 22 | 23 | environments.Logo(nil, os.Stdout) 24 | 25 | environments.Initialize() 26 | environments.SelectCurrentEnvironment() 27 | 28 | // start go-prompt as console 29 | p := prompt.New( 30 | environments.GetActiveExecutor(), 31 | environments.GetActiveCompleter(), 32 | // register hot key for select active env 33 | prompt.OptionAddKeyBind(environments.BuildPromptKeyBinds()...), 34 | // register live prefix that will be change automatically when env changed 35 | prompt.OptionLivePrefix(environments.LivePrefix), 36 | prompt.OptionTitle("Fenix-CLI: Interactive Cloud-Native Environment KubeClient"), 37 | prompt.OptionInputTextColor(prompt.Yellow), 38 | prompt.OptionCompletionOnDown(), 39 | prompt.OptionMaxSuggestion(8), 40 | prompt.OptionSuggestionTextColor(prompt.Black), 41 | prompt.OptionDescriptionTextColor(prompt.Black), 42 | prompt.OptionSuggestionBGColor(prompt.LightGray), 43 | prompt.OptionDescriptionBGColor(prompt.DarkGray), 44 | prompt.OptionSelectedSuggestionTextColor(prompt.White), 45 | prompt.OptionSelectedDescriptionTextColor(prompt.White), 46 | prompt.OptionSelectedSuggestionBGColor(prompt.Blue), 47 | prompt.OptionSelectedDescriptionBGColor(prompt.DarkBlue), 48 | prompt.OptionScrollbarBGColor(prompt.LightGray), 49 | prompt.OptionScrollbarThumbColor(prompt.Blue), 50 | ) 51 | 52 | p.Run() 53 | } 54 | -------------------------------------------------------------------------------- /src/environments/completer.go: -------------------------------------------------------------------------------- 1 | package environments 2 | 3 | import "github.com/fenixsoft/fenix-cli/src/suggestions" 4 | 5 | type RuntimeCompleter struct { 6 | *suggestions.GenericCompleter 7 | *Runtime 8 | } 9 | -------------------------------------------------------------------------------- /src/environments/docker/completer.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "context" 5 | "docker.io/go-docker" 6 | "github.com/fenixsoft/fenix-cli/src/suggestions" 7 | "time" 8 | ) 9 | 10 | func New() (*suggestions.GenericCompleter, error) { 11 | // Determine if docker is running 12 | dockerClient, _ = docker.NewEnvClient() 13 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 14 | defer cancel() 15 | 16 | if _, err := dockerClient.Ping(ctx); err != nil { 17 | return nil, err 18 | } 19 | 20 | return suggestions.NewGenericCompleter(arguments, options, func(c *suggestions.GenericCompleter) { 21 | c.SuggestionProviders.Add(suggestions.Argument, suggestions.BuildStaticCompletionProvider(c.Arguments, suggestions.LengthFilter)) 22 | c.SuggestionProviders.Add(suggestions.Option, suggestions.BuildStaticCompletionProvider(c.Options, suggestions.BestEffortFilter)) 23 | 24 | suggestions.RegisterSharedProvider(Image, provideImagesSuggestion) 25 | suggestions.RegisterSharedProvider(RemoteImage, provideRemoteImageSuggestion) 26 | suggestions.RegisterSharedProvider(Container, provideContainerSuggestion) 27 | suggestions.RegisterSharedProvider(Port, providePortSuggestion) 28 | suggestions.RegisterSharedProvider(Orchestrator, suggestions.BuildFixedSelectionProvider("swarm", "kubernetes", "all")) 29 | suggestions.RegisterSharedProvider(DockerType, suggestions.BuildFixedSelectionProvider(Image, Container)) 30 | }), nil 31 | } 32 | -------------------------------------------------------------------------------- /src/environments/docker/docker_env.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "docker.io/go-docker" 5 | "github.com/c-bata/go-prompt" 6 | "github.com/fenixsoft/fenix-cli/src/environments" 7 | ) 8 | 9 | var dockerClient *docker.Client 10 | 11 | func RegisterEnv() (*environments.Runtime, error) { 12 | if c, err := New(); err != nil { 13 | return nil, err 14 | } else { 15 | return &environments.Runtime{ 16 | Prefix: "docker", 17 | Completer: c, 18 | Commands: ExtraCommands, 19 | Executor: environments.GetDefaultExecutor("docker", func() { 20 | lastQueryResult = []prompt.Suggest{} 21 | }), 22 | }, nil 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/environments/executor.go: -------------------------------------------------------------------------------- 1 | package environments 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/c-bata/go-prompt" 7 | "os" 8 | "os/exec" 9 | "strings" 10 | ) 11 | 12 | func GetDefaultExecutor(runtime string, callback func(), env ...string) prompt.Executor { 13 | return func(s string) { 14 | Executor(runtime, s, env...) 15 | if callback != nil { 16 | callback() 17 | } 18 | } 19 | } 20 | 21 | func Executor(program string, args string, env ...string) { 22 | args = strings.TrimSpace(args) 23 | if args == "" { 24 | return 25 | } 26 | 27 | cmds := DefaultCommands 28 | for _, env := range Environments { 29 | cmds = append(cmds, env.Commands...) 30 | } 31 | for _, cmd := range cmds { 32 | if cmd.MatchAndExecute(args, os.Stdout) { 33 | return 34 | } 35 | } 36 | 37 | cmd := exec.Command("/bin/sh", "-c", program+" "+args) 38 | cmd.Env = os.Environ() 39 | cmd.Env = append(cmd.Env, env...) 40 | cmd.Stdin = os.Stdin 41 | cmd.Stdout = os.Stdout 42 | cmd.Stderr = os.Stderr 43 | 44 | if err := cmd.Run(); err != nil { 45 | fmt.Println(err.Error()) 46 | } 47 | return 48 | } 49 | 50 | func ExecuteAndGetResult(program string, args string, env ...string) (int, string) { 51 | args = strings.TrimSpace(args) 52 | if args == "" { 53 | return -1, "" 54 | } 55 | 56 | out := &bytes.Buffer{} 57 | cmd := exec.Command("/bin/sh", "-c", program+" "+args) 58 | cmd.Env = os.Environ() 59 | cmd.Env = append(cmd.Env, env...) 60 | cmd.Stdin = os.Stdin 61 | cmd.Stdout = out 62 | if err := cmd.Run(); err != nil { 63 | if exitError, ok := err.(*exec.ExitError); ok { 64 | return exitError.ExitCode(), string(out.Bytes()) 65 | } 66 | return -1, err.Error() 67 | } 68 | return 0, string(out.Bytes()) 69 | } 70 | -------------------------------------------------------------------------------- /src/environments/istio/commands.go: -------------------------------------------------------------------------------- 1 | package istio 2 | -------------------------------------------------------------------------------- /src/environments/istio/completer.go: -------------------------------------------------------------------------------- 1 | package istio 2 | 3 | import ( 4 | "errors" 5 | "github.com/fenixsoft/fenix-cli/src/environments" 6 | "github.com/fenixsoft/fenix-cli/src/environments/kubernetes" 7 | "github.com/fenixsoft/fenix-cli/src/suggestions" 8 | ) 9 | 10 | func New() (*suggestions.GenericCompleter, error) { 11 | // only support Istio over Kubernetes 12 | // so that must already installed Kubernetes Env 13 | if _, err := kubernetes.NewClient(); err != nil { 14 | return nil, err 15 | } 16 | // check if istioctl is valid in PATH 17 | code, msg := environments.ExecuteAndGetResult("istioctl", "version") 18 | if code != 0 { 19 | return nil, errors.New(msg) 20 | } 21 | 22 | completer := suggestions.NewGenericCompleter(arguments, options, func(c *suggestions.GenericCompleter) { 23 | c.SuggestionProviders.Add(suggestions.Argument, suggestions.BuildStaticCompletionProvider(c.Arguments, suggestions.LengthFilter)) 24 | c.SuggestionProviders.Add(suggestions.Option, suggestions.BuildStaticCompletionProvider(c.Options, suggestions.BestEffortFilter)) 25 | }) 26 | 27 | return completer, nil 28 | } 29 | -------------------------------------------------------------------------------- /src/environments/istio/istio_env.go: -------------------------------------------------------------------------------- 1 | package istio 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fenixsoft/fenix-cli/src/environments" 6 | "github.com/fenixsoft/fenix-cli/src/environments/kubernetes" 7 | "github.com/fenixsoft/fenix-cli/src/internal/krew" 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | // MUST register AFTER Kubernetes environment 12 | func RegisterEnv() (*environments.Runtime, error) { 13 | if c, err := New(); err != nil { 14 | return nil, err 15 | } else if !krew.IsIstiocltAvailable() { 16 | return nil, errors.New("istio is not available") 17 | } else { 18 | return &environments.Runtime{ 19 | Prefix: "istioctl", 20 | Completer: c, 21 | Executor: environments.GetDefaultExecutor("istioctl", nil), 22 | LivePrefix: func() (prefix string, useLivePrefix bool) { 23 | return fmt.Sprintf("%v > istioctl ", kubernetes.Client.Namespace), true 24 | }, 25 | }, nil 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/environments/kubernetes/kube_env.go: -------------------------------------------------------------------------------- 1 | package kubernetes 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fenixsoft/fenix-cli/src/environments" 6 | "github.com/fenixsoft/fenix-cli/src/internal/krew" 7 | ) 8 | 9 | func RegisterEnv() (*environments.Runtime, error) { 10 | if c, err := New(); err != nil { 11 | return nil, err 12 | } else { 13 | return &environments.Runtime{ 14 | Prefix: "kubectl", 15 | Completer: c, 16 | Executor: environments.GetDefaultExecutor("kubectl", nil, krew.GetBinPath()...), 17 | Commands: ExtraCommands, 18 | LivePrefix: func() (prefix string, useLivePrefix bool) { 19 | return fmt.Sprintf("%v > kubectl ", Client.Namespace), true 20 | }, 21 | }, nil 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/environments/version.go: -------------------------------------------------------------------------------- 1 | package environments 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mitchellh/colorstring" 6 | "io" 7 | ) 8 | 9 | // DO NOT modify this, will inject form Git tags by CI/CD 10 | var Version = "Development Build" 11 | 12 | func Logo(args []string, out io.Writer) { 13 | logo := "\n" + 14 | "[dark_gray] ________ ________ ____ _____ _____ ____ ____ ______ _____ _____ \n" + 15 | "[dark_gray]|_ __ ||_ __ ||_ \\|_ _||_ _||_ _||_ _| .' ___ ||_ _| |_ _| \n" + 16 | "[light_gray] | |_ \\_| | |_ \\_| | \\ | | | | \\ \\ / /______ / .' \\_| | | | | \n" + 17 | "[light_gray] | _| | _| _ | |\\ \\| | | | > `' <|______|| | | | _ | | \n" + 18 | "[reset] _| |_ _| |__/ | _| |_\\ |_ _| |_ _/ /'`\\ \\_ \\ `.___.'\\ _| |__/ | _| |_ \n" + 19 | "[white]|_____| |________||_____|\\____||_____||____||____| `.____ .'|________||_____|\n[reset]" 20 | 21 | logo += fmt.Sprintf("%84v\n", Version) + 22 | " [blue][underline]https://github.com/fenixsoft/fenix-cli[reset]\n" + 23 | " Press key [yellow][reset] to get help information\n" + 24 | " \n" 25 | _, _ = colorstring.Println(logo) 26 | } 27 | -------------------------------------------------------------------------------- /src/internal/debug/log.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | ) 8 | 9 | const ( 10 | envEnableLog = "KUBE_PROMPT_ENABLE_LOG" 11 | logFileName = "kube-prompt.log" 12 | ) 13 | 14 | var ( 15 | logfile *os.File 16 | logger *log.Logger 17 | ) 18 | 19 | func init() { 20 | enableLog := os.Getenv(envEnableLog) 21 | if enableLog == "true" || enableLog == "1" { 22 | var err error 23 | logfile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 24 | if err == nil { 25 | logger = log.New(logfile, "", log.Llongfile) 26 | return 27 | } 28 | } 29 | logger = log.New(ioutil.Discard, "", log.Llongfile) 30 | } 31 | 32 | // Teardown to close logfile 33 | func Teardown() { 34 | if logfile == nil { 35 | return 36 | } 37 | _ = logfile.Close() 38 | } 39 | 40 | func writeWithSync(calldepth int, msg string) { 41 | calldepth++ 42 | if logfile == nil { 43 | return 44 | } 45 | _ = logger.Output(calldepth, msg) 46 | _ = logfile.Sync() // immediately write msg 47 | } 48 | 49 | // Log to output message 50 | func Log(msg string) { 51 | calldepth := 2 52 | writeWithSync(calldepth, msg) 53 | } 54 | 55 | func AssertNoError(err error) { 56 | if err == nil { 57 | return 58 | } 59 | panic(err) 60 | } 61 | -------------------------------------------------------------------------------- /src/internal/krew/wrapper.go: -------------------------------------------------------------------------------- 1 | package krew 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "sigs.k8s.io/krew/cmd/krew/cmd" 8 | "strings" 9 | ) 10 | 11 | func RunAction(args []string) { 12 | rootCmd := cmd.GetRootCmd() 13 | rootCmd.SetArgs(args) 14 | _ = rootCmd.Execute() 15 | } 16 | 17 | func IsInstallPlugin(name string) bool { 18 | ret, _ := cmd.GetInstalledPlugin() 19 | for _, v := range ret { 20 | if strings.EqualFold(v.Name, name) { 21 | return true 22 | } 23 | } 24 | return false 25 | 26 | } 27 | 28 | func CheckAndInstall(name string) { 29 | if !IsInstallPlugin(name) { 30 | fmt.Printf("Fetching plugin: %v \n", name) 31 | RunAction([]string{"install", name}) 32 | } 33 | } 34 | 35 | func GetBinPath() []string { 36 | path := cmd.GetPath().BinPath() + ":" + os.Getenv("PATH") 37 | return []string{"PATH=" + path} 38 | } 39 | 40 | func IsTSharkAvailable() bool { 41 | cmd := exec.Command("tshark", "-v") 42 | if err := cmd.Run(); err != nil { 43 | return false 44 | } 45 | return true 46 | } 47 | 48 | func IsXDGAvailable() bool { 49 | cmd := exec.Command("xdg-open", "--version") 50 | if err := cmd.Run(); err != nil { 51 | return false 52 | } 53 | return true 54 | } 55 | 56 | func IsIstiocltAvailable() bool { 57 | cmd := exec.Command("istioctl", "version") 58 | if err := cmd.Run(); err != nil { 59 | return false 60 | } 61 | return true 62 | } 63 | -------------------------------------------------------------------------------- /src/internal/util/cast.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | func Slice(slice interface{}, newSliceType reflect.Type) interface{} { 10 | sv := reflect.ValueOf(slice) 11 | if sv.Kind() != reflect.Slice { 12 | panic(fmt.Sprintf("Slice called with non-slice value of type %T", slice)) 13 | } 14 | if newSliceType.Kind() != reflect.Slice { 15 | panic(fmt.Sprintf("Slice called with non-slice type of type %T", newSliceType)) 16 | } 17 | newSlice := reflect.New(newSliceType) 18 | hdr := (*reflect.SliceHeader)(unsafe.Pointer(newSlice.Pointer())) 19 | hdr.Cap = sv.Cap() * int(sv.Type().Elem().Size()) / int(newSliceType.Elem().Size()) 20 | hdr.Len = sv.Len() * int(sv.Type().Elem().Size()) / int(newSliceType.Elem().Size()) 21 | hdr.Data = uintptr(sv.Pointer()) 22 | return newSlice.Elem().Interface() 23 | } 24 | -------------------------------------------------------------------------------- /src/internal/util/string.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "strings" 4 | 5 | func SubString(source string, start int, end int) string { 6 | var r = []rune(source) 7 | length := len(r) 8 | 9 | if start < 0 || end < 0 || start > end { 10 | return "" 11 | } 12 | if start == 0 && end >= length { 13 | return source 14 | } 15 | return string(r[start:end]) + "..." 16 | } 17 | 18 | func HasPrefixIgnoreCase(s string, prefix string) bool { 19 | return strings.HasPrefix(strings.ToLower(s), strings.ToLower(prefix)) 20 | } 21 | -------------------------------------------------------------------------------- /src/internal/util/term.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt/term" 5 | "golang.org/x/sys/unix" 6 | ) 7 | 8 | func GetWindowWidth() uint16 { 9 | ws, err := unix.IoctlGetWinsize(term.GetSaveTermiosFD(), unix.TIOCGWINSZ) 10 | if err != nil { 11 | return 80 12 | } 13 | return ws.Col 14 | } 15 | 16 | func GetWindowHeight() uint16 { 17 | ws, err := unix.IoctlGetWinsize(term.GetSaveTermiosFD(), unix.TIOCGWINSZ) 18 | if err != nil { 19 | return 25 20 | } 21 | return ws.Row 22 | } 23 | -------------------------------------------------------------------------------- /src/suggestions/generic_provider.go: -------------------------------------------------------------------------------- 1 | package suggestions 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt" 5 | "path/filepath" 6 | "strings" 7 | ) 8 | 9 | const ( 10 | Path = "path" 11 | Output = "output" 12 | Loglevel = "Loglevel" 13 | ) 14 | 15 | // The providePathSuggestion provide filesystem completion 16 | func providePathSuggestion(args ...string) []prompt.Suggest { 17 | l := len(args) 18 | if l == 0 { 19 | return []prompt.Suggest{} 20 | } 21 | path := args[l-1] 22 | if !strings.HasSuffix(path, "*") { 23 | path = path + "*" 24 | } 25 | files, _ := filepath.Glob(path) 26 | var ret []prompt.Suggest 27 | for i, file := range files { 28 | if i > 16 { 29 | return ret 30 | } else { 31 | ret = append(ret, prompt.Suggest{Text: file}) 32 | } 33 | } 34 | return ret 35 | } 36 | -------------------------------------------------------------------------------- /src/suggestions/static_provider.go: -------------------------------------------------------------------------------- 1 | package suggestions 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt" 5 | "github.com/fenixsoft/fenix-cli/src/internal/util" 6 | "strings" 7 | ) 8 | 9 | // Build fixed selection (eg: json|yaml|xml) Provider 10 | func BuildFixedSelectionProvider(selections ...string) Provider { 11 | var ret []prompt.Suggest 12 | for _, v := range selections { 13 | ret = append(ret, prompt.Suggest{Text: v}) 14 | } 15 | return func(args ...string) []prompt.Suggest { 16 | return ret 17 | } 18 | } 19 | 20 | // Build static completion (Arguments \ Options) Provider 21 | func BuildStaticCompletionProvider(options []prompt.Suggest, fn SuggestionFilter) Provider { 22 | // setup index 23 | suggestions := make(map[string][]prompt.Suggest) 24 | for _, v := range options { 25 | if _, ok := suggestions[v.Argument]; !ok { 26 | suggestions[v.Argument] = []prompt.Suggest{} 27 | } 28 | suggestions[v.Argument] = append(suggestions[v.Argument], v) 29 | } 30 | // build provider 31 | return func(args ...string) []prompt.Suggest { 32 | return fn(args, suggestions) 33 | } 34 | } 35 | 36 | // The BestEffortFilter is to find mostly match suggestion, common use for Options 37 | // eg: 38 | // input: istio admin log --Options 39 | // "istio admin log"'s option is better than "istio admin" 40 | func BestEffortFilter(args []string, suggestions map[string][]prompt.Suggest) []prompt.Suggest { 41 | cmd := strings.ToLower(strings.Join(args, " ")) 42 | var sug []prompt.Suggest 43 | var arg string 44 | for key := range suggestions { 45 | if strings.HasPrefix(cmd, key) { 46 | if len(key) >= len(arg) { 47 | arg = key 48 | sug = suggestions[key] 49 | } 50 | } 51 | } 52 | return sug 53 | } 54 | 55 | // The LengthFilter must make sure the each Arguments is in the right place, common use for Arguments 56 | // eg: 57 | // input: istio admin log 58 | // only "istio admin log " will match 59 | func LengthFilter(args []string, suggestions map[string][]prompt.Suggest) []prompt.Suggest { 60 | l := len(args) 61 | s := suggestions[strings.ToLower(strings.Join(args[:l-1], " "))] 62 | var ret []prompt.Suggest 63 | for _, v := range s { 64 | if util.HasPrefixIgnoreCase(v.Text, args[l-1]) || util.HasPrefixIgnoreCase(v.Alias, args[l-1]) { 65 | ret = append(ret, v) 66 | } 67 | } 68 | return ret 69 | } 70 | -------------------------------------------------------------------------------- /src/suggestions/types.go: -------------------------------------------------------------------------------- 1 | package suggestions 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt" 5 | ) 6 | 7 | // The Completer interface is a collection of functions for the user to perform 8 | // intelligent completion when entering the command line 9 | type Completer interface { 10 | Complete(doc prompt.Document) []prompt.Suggest 11 | } 12 | 13 | // The Provider is data source for different types of Suggestions 14 | type Provider func(...string) []prompt.Suggest 15 | 16 | // The SuggestionFilter determines how to map user input information to Suggestion 17 | type SuggestionFilter func([]string, map[string][]prompt.Suggest) []prompt.Suggest 18 | 19 | // The Repository is a set of Provider 20 | type Repository struct { 21 | privateProviders map[string]Provider 22 | } 23 | 24 | // Adding a Provider to Repository 25 | func (r *Repository) Add(id string, provider Provider) { 26 | r.privateProviders[id] = provider 27 | } 28 | 29 | // Providing suggestion by a specified Provider 30 | func (r *Repository) Provide(id string, args ...string) []prompt.Suggest { 31 | if v, ok := r.privateProviders[id]; ok { 32 | return v(args...) 33 | } else if v, ok := sharedProviders[id]; ok { 34 | return v(args...) 35 | } else { 36 | return []prompt.Suggest{} 37 | } 38 | } 39 | 40 | // The sharedProviders are registered in different environments with universality 41 | // and can be handed over to providers used by other environments 42 | var sharedProviders map[string]Provider 43 | 44 | func init() { 45 | sharedProviders = make(map[string]Provider) 46 | RegisterSharedProvider(Path, providePathSuggestion) 47 | RegisterSharedProvider(Output, BuildFixedSelectionProvider("yaml", "json", "table", "short")) 48 | RegisterSharedProvider(Loglevel, BuildFixedSelectionProvider("trace", "debug", "info", "warn", "error", "fatal")) 49 | } 50 | 51 | func RegisterSharedProvider(id string, provider Provider) { 52 | sharedProviders[id] = provider 53 | } 54 | 55 | const ( 56 | Option = "option" 57 | Argument = "argument" 58 | ) 59 | --------------------------------------------------------------------------------