├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── activate ├── config.toml.example ├── cosmk ├── README.md ├── go.mod ├── go.sum ├── src │ ├── config.go │ ├── doc.go │ ├── main.go │ ├── product.go │ ├── recipe.go │ ├── runtime.go │ ├── sdk.go │ ├── test.go │ └── utils.go ├── vendor │ ├── github.com │ │ ├── BurntSushi │ │ │ └── toml │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── COMPATIBLE │ │ │ │ ├── COPYING │ │ │ │ ├── Makefile │ │ │ │ ├── README.md │ │ │ │ ├── decode.go │ │ │ │ ├── decode_meta.go │ │ │ │ ├── doc.go │ │ │ │ ├── encode.go │ │ │ │ ├── encoding_types.go │ │ │ │ ├── encoding_types_1.1.go │ │ │ │ ├── lex.go │ │ │ │ ├── parse.go │ │ │ │ ├── session.vim │ │ │ │ ├── type_check.go │ │ │ │ └── type_fields.go │ │ ├── alecthomas │ │ │ └── kong │ │ │ │ ├── .gitignore │ │ │ │ ├── .golangci.yml │ │ │ │ ├── COPYING │ │ │ │ ├── README.md │ │ │ │ ├── build.go │ │ │ │ ├── callbacks.go │ │ │ │ ├── camelcase.go │ │ │ │ ├── context.go │ │ │ │ ├── defaults.go │ │ │ │ ├── doc.go │ │ │ │ ├── error.go │ │ │ │ ├── global.go │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ ├── guesswidth.go │ │ │ │ ├── guesswidth_unix.go │ │ │ │ ├── help.go │ │ │ │ ├── hooks.go │ │ │ │ ├── interpolate.go │ │ │ │ ├── kong.go │ │ │ │ ├── kong.png │ │ │ │ ├── kong.sketch │ │ │ │ ├── levenshtein.go │ │ │ │ ├── mapper.go │ │ │ │ ├── model.go │ │ │ │ ├── options.go │ │ │ │ ├── resolver.go │ │ │ │ ├── scanner.go │ │ │ │ ├── tag.go │ │ │ │ ├── util.go │ │ │ │ └── visit.go │ │ ├── hashicorp │ │ │ ├── errwrap │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── errwrap.go │ │ │ │ └── go.mod │ │ │ └── go-multierror │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── Makefile │ │ │ │ ├── README.md │ │ │ │ ├── append.go │ │ │ │ ├── flatten.go │ │ │ │ ├── format.go │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ ├── multierror.go │ │ │ │ ├── prefix.go │ │ │ │ └── sort.go │ │ ├── pkg │ │ │ └── errors │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── Makefile │ │ │ │ ├── README.md │ │ │ │ ├── appveyor.yml │ │ │ │ ├── errors.go │ │ │ │ ├── go113.go │ │ │ │ └── stack.go │ │ ├── posener │ │ │ └── complete │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── README.md │ │ │ │ ├── args.go │ │ │ │ ├── cmd │ │ │ │ ├── cmd.go │ │ │ │ └── install │ │ │ │ │ ├── bash.go │ │ │ │ │ ├── fish.go │ │ │ │ │ ├── install.go │ │ │ │ │ ├── utils.go │ │ │ │ │ └── zsh.go │ │ │ │ ├── command.go │ │ │ │ ├── complete.go │ │ │ │ ├── doc.go │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ ├── goreadme.json │ │ │ │ ├── log.go │ │ │ │ ├── predict.go │ │ │ │ ├── predict_files.go │ │ │ │ └── predict_set.go │ │ └── willabides │ │ │ └── kongplete │ │ │ ├── .gitignore │ │ │ ├── .golangci.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── bindown.yml │ │ │ ├── doc.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── internal │ │ │ └── positionalpredictor │ │ │ │ └── positional.go │ │ │ └── kongplete.go │ └── modules.txt └── version ├── helpers ├── README.md ├── check-lfs-repositories.sh ├── create-keyrings.sh ├── declare-upstreams.sh ├── eval-annotations.sh ├── fetch-upstreams.sh ├── filter-most.sh ├── get-cache-from-ci.sh ├── vendor-gentoo-stage3.sh ├── verify.sh └── yield-branches-from-remote.sh └── setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw? 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | develop-eggs/ 14 | eggs/ 15 | .eggs/ 16 | wheels/ 17 | *.egg-info/ 18 | *.egg 19 | 20 | # Environments 21 | venv/ 22 | 23 | # Mypy cache 24 | .mypy_cache/ 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Nicolas Godinho 2 | Timothée Ravier 3 | Thibaut Sautereau 4 | Mickaël Salaün 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CLIP OS project & build toolkit 2 | 3 | The full documentation for the CLIP OS project and this toolkit is available at 4 | . 5 | -------------------------------------------------------------------------------- /config.toml.example: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # Copyright © 2019 ANSSI. All rights reserved. 3 | 4 | [product] 5 | # Select which product to build (i.e. the collection of 6 | # recipes to use in the 'products' folder) 7 | name = "clipos" 8 | 9 | # Select which (if any) CI infrastructure to pull binaries from. Use empty 10 | # strings to ignore all CI integration. 11 | [ci] 12 | # Base URL for the GitLab instance to use 13 | url = "https://gitlab.com" 14 | # Container registry used to pull SDK images 15 | registry = "registry.gitlab.com/clipos/ci" 16 | # GitLab.com project ID for CLIPOS/ci. Can be retrieved with: 17 | # $ URL="https://gitlab.com/api/v4/projects" 18 | # $ NAME="$(echo -n 'CLIPOS/ci' | sed 's|/|%2F|g')" 19 | # $ curl "${URL}/${NAME}" | jq '.id' 20 | project_id = "14752889" 21 | # Base URL to retrieve artifacts (binary packages) from 22 | artifacts = "https://files.clip-os.org" 23 | 24 | [development] 25 | # Enable network access during development for 'bootstrap' and 'build' actions 26 | network = "yes" 27 | # By default, the project creates images intended for production use. To ease 28 | # development and debug, you can enable instrumentation features that alter the 29 | # behavior of all project actions launched with the cosmk tool. 30 | 31 | # Notice: If at least one instrumentation feature is enabled in this file, then 32 | # the product version will be tainted with an "instrumented" tag as a SemVer 33 | # build metadata (e.g. "X.Y.Z+instrumented"). 34 | # 35 | # For an in-depth reference of the effects of all instrumentation features 36 | # proposed below, please refer to the appropriate page of the CLIP OS product 37 | # documentation: 38 | # 39 | # The other products (i.e. CLIP OS derivatives) may implement or enhance those 40 | # product instrumentation features. 41 | instrumentation = [ 42 | #"instrumented-core", 43 | #"passwordless-root-login", 44 | #"allow-ssh-root-login", 45 | #"dev-friendly-bootloader", 46 | #"instrumented-initramfs", 47 | #"soften-kernel-configuration", 48 | #"initramfs-no-require-tpm", 49 | #"initramfs-no-tpm-lockout", 50 | #"debuggable-initramfs", 51 | #"breakpointed-initramfs", 52 | #"early-root-shell", 53 | #"debuggable-kernel", 54 | #"verbose-systemd", 55 | #"coredump-handler", 56 | #"test-update", 57 | ] 58 | 59 | # vim: set ts=4 sts=4 sw=4 et ft=toml: 60 | -------------------------------------------------------------------------------- /cosmk/README.md: -------------------------------------------------------------------------------- 1 | # CLIP OS project & build toolkit 2 | 3 | The full documentation for the CLIP OS project and this toolkit is available at 4 | . 5 | 6 | ## Build 7 | 8 | ``` 9 | $ go build -o cosmk -mod=vendor -ldflags "-X main.version=$(cat version | tr -d '\n')" ./src 10 | ``` 11 | 12 | ## Interactive shell completion 13 | 14 | Add `cosmk` to you PATH and the following to your shell startup script: 15 | 16 | ``` 17 | # Bash 18 | eval "$(cosmk --completion-script-bash)" 19 | 20 | # Zsh 21 | eval "$(cosmk --completion-script-zsh)" 22 | ``` 23 | 24 | ## Development 25 | 26 | Vendor Go modules with: 27 | 28 | ``` 29 | $ go mod vendor 30 | ``` 31 | -------------------------------------------------------------------------------- /cosmk/go.mod: -------------------------------------------------------------------------------- 1 | module cosmk 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/BurntSushi/toml v0.3.1 7 | github.com/alecthomas/kong v0.2.17 8 | github.com/posener/complete v1.2.3 9 | github.com/willabides/kongplete v0.2.0 10 | ) 11 | -------------------------------------------------------------------------------- /cosmk/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= 4 | github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0= 5 | github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 10 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 11 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 12 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 13 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 14 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 15 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 18 | github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= 19 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 20 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 21 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 22 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 23 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 24 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 25 | github.com/willabides/kongplete v0.2.0 h1:C6wYVn+IPyA8rAGRGLLkuxhhSQTEECX4t8u3gi+fuD0= 26 | github.com/willabides/kongplete v0.2.0/go.mod h1:kFVw+PkQsqkV7O4tfIBo6iJ9qY94PJC8sPfMgFG5AdM= 27 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 28 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 29 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 30 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 31 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 32 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 33 | -------------------------------------------------------------------------------- /cosmk/src/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | "path" 9 | 10 | "github.com/BurntSushi/toml" 11 | ) 12 | 13 | var rootConfig config 14 | 15 | type config struct { 16 | Product configProduct 17 | Ci configCi 18 | Development configDevelopment 19 | } 20 | 21 | type configProduct struct { 22 | Name string 23 | } 24 | 25 | type configCi struct { 26 | Url string 27 | Registry string 28 | Project_id string 29 | Artifacts string 30 | } 31 | 32 | type configDevelopment struct { 33 | Network string 34 | Instrumentation []string 35 | } 36 | 37 | // Must use default 'log' logger here as the log setup happens later 38 | func parseConfig() { 39 | content, err := ioutil.ReadFile(path.Join(repoRootPath, "config.toml")) 40 | if err != nil { 41 | log.Fatalln("Could not read 'config.toml':", err) 42 | } 43 | 44 | _, err = toml.Decode(string(content), &rootConfig) 45 | if err != nil { 46 | log.Fatalln("Could not parse 'config.toml':", err) 47 | } 48 | 49 | if rootConfig.Product.Name == "" { 50 | log.Fatalln("Please select a product to build in 'config.toml'.") 51 | } 52 | } 53 | 54 | // List enabled instrumentation features or test if selected feature is enabled 55 | func doInstrumentationFeatures() { 56 | // Has a specific feature been selected? 57 | if cosmk.InstrumentationFeatures.Feature != "" { 58 | // Test if selected feature is enabled 59 | for _, feat := range rootConfig.Development.Instrumentation { 60 | if cosmk.InstrumentationFeatures.Feature == feat { 61 | println("true") 62 | os.Exit(0) 63 | } 64 | } 65 | println("false") 66 | os.Exit(1) 67 | } else { 68 | // List enabled instrumentation features 69 | for _, feat := range rootConfig.Development.Instrumentation { 70 | println(feat) 71 | } 72 | } 73 | } 74 | 75 | func (c *config) env() []string { 76 | features := "" 77 | 78 | for _, v := range c.Development.Instrumentation { 79 | if features == "" { 80 | features += v 81 | } else { 82 | features += " " + v 83 | } 84 | } 85 | 86 | return []string{ 87 | "--env", 88 | fmt.Sprintf("COSMK_INSTRUMENTATION_FEATURES=%s", features), 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /cosmk/src/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "path" 7 | ) 8 | 9 | // Change current directory to "docs-src" and build the documentation 10 | func doBuildDoc() { 11 | docsDir := path.Join(repoRootPath, "docs-src") 12 | err := os.Chdir(docsDir) 13 | if err != nil { 14 | Error.Fatalf("Could not chdir to '%s': %s", docsDir, err) 15 | } 16 | 17 | command := "./build.sh" 18 | cmd := exec.Command(command) 19 | cmd.Stdout = os.Stdout 20 | cmd.Stderr = os.Stderr 21 | err = cmd.Run() 22 | if err != nil { 23 | Error.Fatalf("Running '%s' failed with: %s", command, err) 24 | } 25 | } 26 | 27 | // Build (if nothing as been build yet) and open the documentation in the default browser 28 | func doOpenDoc() { 29 | indexPath := path.Join(repoRootPath, "docs-src", "_build", "index.html") 30 | _, err := os.Stat(indexPath) 31 | if err != nil { 32 | doBuildDoc() 33 | } 34 | 35 | command := "xdg-open" 36 | cmd := exec.Command(command, indexPath) 37 | err = cmd.Run() 38 | if err != nil { 39 | Error.Fatalf("Running '%s' failed with: %s", command, err) 40 | } 41 | } 42 | 43 | // Remove documentation build folder 44 | func doCleanDoc() { 45 | buildPath := path.Join(repoRootPath, "docs-src", "_build") 46 | Info.Printf("Removing '%s'...", buildPath) 47 | err := os.RemoveAll(buildPath) 48 | if err != nil { 49 | Error.Fatalf("Error while removing '%s': %s", buildPath, err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cosmk/src/product.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "path" 7 | 8 | "github.com/BurntSushi/toml" 9 | ) 10 | 11 | type product struct { 12 | Version string 13 | Common_name string 14 | Short_name string 15 | Homepage string 16 | Recipes []string 17 | Environment map[string]string 18 | } 19 | 20 | func parseProductConfig() *product { 21 | content, err := ioutil.ReadFile(path.Join(repoRootPath, "products", rootConfig.Product.Name, "product.toml")) 22 | if err != nil { 23 | Error.Fatalln("Could not read 'product.toml':", err) 24 | } 25 | 26 | var p product 27 | _, err = toml.Decode(string(content), &p) 28 | if err != nil { 29 | Error.Fatalln("Could not parse 'product.toml':", err) 30 | } 31 | 32 | return &p 33 | } 34 | 35 | func (p *product) do() error { 36 | for _, recipe := range p.Recipes { 37 | r := parseRecipeConfig(recipe) 38 | err := r.do() 39 | if err != nil { 40 | return err 41 | } 42 | } 43 | return nil 44 | } 45 | 46 | func (p *product) reconfigure() error { 47 | for _, recipe := range p.Recipes { 48 | r := parseRecipeConfig(recipe) 49 | for _, action := range r.Actions { 50 | if (action != "build") && (action != "image") { 51 | err := r.action(action) 52 | if err != nil { 53 | return err 54 | } 55 | } 56 | } 57 | } 58 | return nil 59 | } 60 | 61 | func (p *product) env() []string { 62 | var env []string 63 | 64 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_VERSION=%s", p.Version)) 65 | var taintedVersion string 66 | if len(rootConfig.Development.Instrumentation) == 0 { 67 | taintedVersion = p.Version 68 | } else { 69 | taintedVersion = fmt.Sprintf("%s+%s", p.Version, "instrumented") 70 | } 71 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_TAINTED_VERSION=%s", taintedVersion)) 72 | 73 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_COMMON_NAME=%s", p.Common_name)) 74 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_SHORT_NAME=%s", p.Short_name)) 75 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT=%s", p.Short_name)) 76 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_HOMEPAGE=%s", p.Homepage)) 77 | 78 | for k, v := range p.Environment { 79 | env = append(env, "--env", fmt.Sprintf("COSMK_PRODUCT_ENV_%s=%s", k, v)) 80 | } 81 | 82 | return env 83 | } 84 | -------------------------------------------------------------------------------- /cosmk/src/recipe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | 9 | "github.com/BurntSushi/toml" 10 | ) 11 | 12 | type recipeToml struct { 13 | Sdk string 14 | Actions []string 15 | Environment map[string]string 16 | } 17 | 18 | type recipe struct { 19 | Name string 20 | Actions []string 21 | Environment map[string]string 22 | Sdk *sdk 23 | Product *product 24 | } 25 | 26 | func parseRecipeConfig(name string) recipe { 27 | product := parseProductConfig() 28 | 29 | content, err := ioutil.ReadFile(path.Join(repoRootPath, "products", rootConfig.Product.Name, name, "recipe.toml")) 30 | if err != nil { 31 | Error.Fatalln("Could not read 'recipe.toml':", err) 32 | } 33 | 34 | var r recipeToml 35 | _, err = toml.Decode(string(content), &r) 36 | if err != nil { 37 | Error.Fatalln("Could not parse 'recipe.toml':", err) 38 | } 39 | 40 | s := parseSdkConfig(r.Sdk) 41 | 42 | return recipe{ 43 | Name: name, 44 | Actions: r.Actions, 45 | Environment: r.Environment, 46 | Sdk: &s, 47 | Product: product, 48 | } 49 | } 50 | 51 | func (r *recipe) do() error { 52 | err := r.Sdk.bootstrap() 53 | if err != nil { 54 | return err 55 | } 56 | for _, action := range r.Actions { 57 | err = r.action(action) 58 | if err != nil { 59 | return err 60 | } 61 | } 62 | return nil 63 | } 64 | 65 | func (r *recipe) action(action string) error { 66 | err := r.Sdk.bootstrap() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | // Search for the action script in the recipe directory first and if not 72 | // found, use the default one from the SDK 73 | hostCommand := path.Join(repoRootPath, "products", r.Product.Short_name, 74 | r.Name, fmt.Sprintf("%s.sh", action)) 75 | sdkCommand := path.Join("/mnt", "products", r.Product.Short_name, r.Name, fmt.Sprintf("%s.sh", action)) 76 | _, err = os.Stat(hostCommand) 77 | if err != nil { 78 | if !os.IsNotExist(err) { 79 | Error.Fatalf("Could not access file '%s': %s", hostCommand, err) 80 | } 81 | sdkCommand = fmt.Sprintf("./%s.sh", action) 82 | } 83 | 84 | imageName := fmt.Sprintf("%s/%s", rootConfig.Product.Name, r.Sdk.Name) 85 | return runtime.run(fmt.Sprintf("%s:%s", imageName, r.Sdk.Tag), []string{sdkCommand}, action, r.Sdk, r) 86 | } 87 | 88 | func (r *recipe) env() []string { 89 | var env []string 90 | 91 | for k, v := range r.Environment { 92 | env = append(env, "--env", fmt.Sprintf("COSMK_RECIPE_ENV_%s=%s", k, v)) 93 | } 94 | 95 | return env 96 | } 97 | 98 | func (r *recipe) run(command []string) error { 99 | err := r.Sdk.bootstrap() 100 | if err != nil { 101 | return err 102 | } 103 | imageName := fmt.Sprintf("%s/%s", rootConfig.Product.Name, r.Sdk.Name) 104 | return runtime.run(fmt.Sprintf("%s:%s", imageName, r.Sdk.Tag), command, "run", r.Sdk, r) 105 | } 106 | -------------------------------------------------------------------------------- /cosmk/src/runtime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "os/user" 9 | "path" 10 | "strings" 11 | ) 12 | 13 | var runtime containerRuntime 14 | 15 | type containerRuntime struct { 16 | Cmd string 17 | Sudo bool 18 | } 19 | 20 | // Figure out which container runtime to use between: 21 | // * rootless podman 22 | // * privileged podman 23 | // * Docker 24 | func findContainerRuntime() { 25 | path, err := exec.LookPath("podman") 26 | if err == nil { 27 | Debug.Println("Found 'podman' at ", path) 28 | runtime = containerRuntime{Cmd: "podman", Sudo: true} 29 | 30 | // Are subuids configured? (Required for rootless) 31 | file, err := os.Open("/etc/subuid") 32 | if err != nil { 33 | return 34 | } 35 | defer file.Close() 36 | 37 | user, err := user.Current() 38 | if err != nil { 39 | return 40 | } 41 | username := user.Username 42 | 43 | scanner := bufio.NewScanner(file) 44 | for scanner.Scan() { 45 | split := strings.Split(scanner.Text(), ":") 46 | if len(split) != 0 && split[0] == username { 47 | runtime.Sudo = false 48 | return 49 | } 50 | } 51 | 52 | // Did not find any subuid for our current username. Running as root with sudo 53 | return 54 | } 55 | 56 | path, err = exec.LookPath("docker") 57 | if err == nil { 58 | Debug.Println("Found 'docker' at ", path) 59 | runtime = containerRuntime{Cmd: "docker", Sudo: true} 60 | return 61 | } 62 | 63 | Error.Fatalln("Could not find either 'podman' or 'docker in path!") 64 | runtime = containerRuntime{Cmd: "false", Sudo: false} 65 | } 66 | 67 | func (cr *containerRuntime) findCiImage(name string, version string) error { 68 | image := fmt.Sprintf("%s/%s:%s", rootConfig.Ci.Registry, name, version) 69 | Debug.Printf("Looking for image '%s' in local registry", image) 70 | 71 | cmd := cr.command() 72 | cmd.Args = append(cmd.Args, "inspect", image) 73 | err := cmd.Run() 74 | if err == nil { 75 | Debug.Printf("Found image '%s' in local registry", image) 76 | return nil 77 | } 78 | 79 | Info.Printf("Could not find image '%s' in local registry", image) 80 | 81 | return cr.pullImageFromCi(name, version) 82 | } 83 | 84 | func (cr *containerRuntime) findLocalImage(name string, version string) error { 85 | image := fmt.Sprintf("%s/%s:%s", "localhost", name, version) 86 | Debug.Printf("Looking for image '%s' in local registry", image) 87 | 88 | cmd := cr.command() 89 | cmd.Args = append(cmd.Args, "inspect", image) 90 | err := cmd.Run() 91 | if err == nil { 92 | Debug.Printf("Found image '%s' in local registry", image) 93 | return nil 94 | } 95 | 96 | Error.Printf("Could not find image '%s' in local registry", image) 97 | return err 98 | } 99 | 100 | func (cr *containerRuntime) pullImageFromCi(name string, version string) error { 101 | Info.Printf("Pulling image '%s:%s' from '%s'", name, version, rootConfig.Ci.Registry) 102 | cmd := cr.command() 103 | cmd.Args = append(cmd.Args, "pull", fmt.Sprintf("%s/%s:%s", rootConfig.Ci.Registry, name, version)) 104 | cmd.Stdout = os.Stdout 105 | cmd.Stderr = os.Stderr 106 | err := cmd.Run() 107 | if err != nil { 108 | Info.Printf("Could not pull '%s:%s' from '%s'", name, version, rootConfig.Ci.Registry) 109 | return err 110 | } 111 | Info.Printf("Pulled image '%s:%s' from '%s'", name, version, rootConfig.Ci.Registry) 112 | return nil 113 | } 114 | 115 | func (cr *containerRuntime) command() *exec.Cmd { 116 | var cmd *exec.Cmd 117 | if cr.Sudo { 118 | cmd = exec.Command("sudo") 119 | cmd.Args = []string{"sudo", cr.Cmd} 120 | 121 | } else { 122 | cmd = exec.Command(runtime.Cmd) 123 | cmd.Args = []string{cr.Cmd} 124 | } 125 | return cmd 126 | } 127 | 128 | func (cr *containerRuntime) run(image string, command []string, action string, s *sdk, r *recipe) error { 129 | cmd := cr.command() 130 | cmd.Stdout = os.Stdout 131 | cmd.Stderr = os.Stderr 132 | cmd.Stdin = os.Stdin 133 | 134 | cmd.Args = append(cmd.Args, "run") 135 | 136 | // Disable SELinux confinement to enable access to home directory content 137 | cmd.Args = append(cmd.Args, "--security-opt", "label=disable") 138 | 139 | cmd.Args = append(cmd.Args, "--tty", "--interactive") 140 | cmd.Args = append(cmd.Args, "--tmpfs", "/tmp:rw,exec,nodev,nosuid") 141 | cmd.Args = append(cmd.Args, "--tmpfs", "/var/tmp:rw,exec,dev,suid") 142 | 143 | cmd.Args = append(cmd.Args, "--workdir", fmt.Sprintf("/mnt/products/%s/%s", s.Product.Short_name, s.Name)) 144 | 145 | var recipeName string 146 | if r != nil { 147 | recipeName = r.Name 148 | } else { 149 | recipeName = s.Name 150 | } 151 | 152 | cmd.Args = append(cmd.Args, "--name", fmt.Sprintf("%s_%s.%s.working", s.Product.Short_name, recipeName, action)) 153 | cmd.Args = append(cmd.Args, "--hostname", fmt.Sprintf("%s-%s", s.Product.Short_name, recipeName)) 154 | 155 | cmd.Args = append(cmd.Args, "--env", fmt.Sprintf("COSMK_ACTION=%s", action)) 156 | cmd.Args = append(cmd.Args, "--env", fmt.Sprintf("COSMK_RECIPE=%s", recipeName)) 157 | 158 | // Ignore instrumentation features during SDK bootstrap to avoid hardcoding them in the image. 159 | if action != "bootstrap" { 160 | cmd.Args = append(cmd.Args, rootConfig.env()...) 161 | } 162 | cmd.Args = append(cmd.Args, s.Product.env()...) 163 | cmd.Args = append(cmd.Args, s.env()...) 164 | if r != nil { 165 | cmd.Args = append(cmd.Args, r.env()...) 166 | } 167 | 168 | if action == "run" { 169 | cmd.Args = append(cmd.Args, "--volume", fmt.Sprintf("%s:/mnt:rw", repoRootPath)) 170 | } else { 171 | cmd.Args = append(cmd.Args, "--volume", fmt.Sprintf("%s:/mnt:ro", repoRootPath)) 172 | } 173 | 174 | // Mount 'out' and 'cache' folder read-write 175 | for _, p := range []string{"out", "cache"} { 176 | pathHost := path.Join(repoRootPath, p, s.Product.Short_name, s.Product.Version, recipeName, action) 177 | pathSdk := path.Join("/mnt", p, s.Product.Short_name, s.Product.Version, recipeName, action) 178 | // Always start with an empty 'out' folder 179 | if p == "out" { 180 | os.RemoveAll(pathHost) 181 | } 182 | os.MkdirAll(pathHost, 0755) 183 | cmd.Args = append(cmd.Args, "--volume", fmt.Sprintf("%s:%s:rw", pathHost, pathSdk)) 184 | } 185 | 186 | // Additional capabilities and writable directory for 'build' & 'bootstrap' actions 187 | if action == "bootstrap" || action == "build" { 188 | for _, dir := range s.Build.Writable_assets { 189 | distfilesHost := path.Join(repoRootPath, "assets", dir) 190 | distfilesSdk := path.Join("/mnt", "assets", dir) 191 | cmd.Args = append(cmd.Args, "--volume", fmt.Sprintf("%s:%s:rw", distfilesHost, distfilesSdk)) 192 | } 193 | 194 | binpkgHost := path.Join(repoRootPath, "cache", s.Product.Short_name, s.Product.Version, recipeName, "binpkgs") 195 | binpkgSdk := path.Join("/mnt", "cache", s.Product.Short_name, s.Product.Version, recipeName, "binpkgs") 196 | os.MkdirAll(binpkgHost, 0755) 197 | cmd.Args = append(cmd.Args, "--volume", fmt.Sprintf("%s:%s:rw", binpkgHost, binpkgSdk)) 198 | 199 | for _, v := range s.Build.Capabilities { 200 | cmd.Args = append(cmd.Args, "--cap-add", v) 201 | } 202 | } 203 | 204 | // Network access is disabled by default. It can be re-enabled during 205 | // development for 'bootstrap', 'build' and 'run' actions. 206 | if rootConfig.Development.Network != "yes" { 207 | cmd.Args = append(cmd.Args, "--network=none") 208 | } else if !(action == "bootstrap" || action == "build" || action == "run") { 209 | cmd.Args = append(cmd.Args, "--network=none") 210 | } 211 | 212 | // Keep the resulting container image only for the 'bootstrap' action 213 | if action != "bootstrap" { 214 | cmd.Args = append(cmd.Args, "--rm") 215 | } 216 | 217 | cmd.Args = append(cmd.Args, image) 218 | cmd.Args = append(cmd.Args, command...) 219 | 220 | Debug.Printf("Will run: %s", cmd.Args) 221 | 222 | err := cmd.Run() 223 | if err != nil { 224 | Error.Printf("SDK exited with error code: %s", err) 225 | } 226 | return err 227 | } 228 | -------------------------------------------------------------------------------- /cosmk/src/sdk.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "strings" 9 | 10 | "github.com/BurntSushi/toml" 11 | ) 12 | 13 | type sdkToml struct { 14 | Tag string 15 | Bootstrap sdkBootstrap 16 | Build sdkBuild 17 | Environment map[string]string 18 | } 19 | 20 | type sdkBootstrap struct { 21 | Rootfs string 22 | Steps []string 23 | } 24 | 25 | type sdkBuild struct { 26 | Capabilities []string 27 | Writable_assets []string 28 | } 29 | 30 | type sdk struct { 31 | Name string 32 | Tag string 33 | Bootstrap sdkBootstrap 34 | Build sdkBuild 35 | Environment map[string]string 36 | Product *product 37 | } 38 | 39 | func parseSdkConfig(name string) sdk { 40 | product := parseProductConfig() 41 | 42 | name = strings.TrimPrefix(name, fmt.Sprintf("%s/", product.Short_name)) 43 | 44 | content, err := ioutil.ReadFile(path.Join(repoRootPath, "products", rootConfig.Product.Name, name, "sdk.toml")) 45 | if err != nil { 46 | Error.Fatalln("Could not read 'sdk.toml':", err) 47 | } 48 | 49 | var s sdkToml 50 | _, err = toml.Decode(string(content), &s) 51 | if err != nil { 52 | Error.Fatalln("Could not parse 'sdk.toml':", err) 53 | } 54 | 55 | return sdk{ 56 | Name: name, 57 | Tag: s.Tag, 58 | Bootstrap: s.Bootstrap, 59 | Build: s.Build, 60 | Environment: s.Environment, 61 | Product: product, 62 | } 63 | } 64 | 65 | func (s *sdk) env() []string { 66 | var env []string 67 | 68 | env = append(env, "--env", fmt.Sprintf("COSMK_SDK_PRODUCT=%s", s.Product.Short_name)) 69 | env = append(env, "--env", fmt.Sprintf("COSMK_SDK_RECIPE=%s", s.Name)) 70 | 71 | for k, v := range s.Environment { 72 | env = append(env, "--env", fmt.Sprintf("COSMK_SDK_ENV_%s=%s", k, v)) 73 | } 74 | return env 75 | } 76 | 77 | func (s *sdk) bootstrap() error { 78 | imageName := fmt.Sprintf("%s/%s", rootConfig.Product.Name, s.Name) 79 | Debug.Printf("Bootstrapping '%s:%s'", imageName, s.Tag) 80 | 81 | if rootConfig.Ci.Registry != "" { 82 | err := runtime.findCiImage(imageName, s.Tag) 83 | if err == nil { 84 | Debug.Printf("No need to bootstrap '%s:%s'", imageName, s.Tag) 85 | return nil 86 | } 87 | } 88 | 89 | err := runtime.findLocalImage(imageName, s.Tag) 90 | if err == nil { 91 | Debug.Printf("No need to bootstrap '%s:%s'", imageName, s.Tag) 92 | return nil 93 | } 94 | 95 | Info.Printf("No image found. Bootstrapping image '%s:%s' from scratch", imageName, s.Tag) 96 | 97 | bootstrapVersion := fmt.Sprintf("%s.bootstrap", s.Tag) 98 | err = runtime.findLocalImage(imageName, bootstrapVersion) 99 | if err != nil { 100 | rootfs := path.Join(repoRootPath, s.Bootstrap.Rootfs) 101 | Info.Printf("Importing rootfs from '%s'", s.Bootstrap.Rootfs) 102 | cmd := runtime.command() 103 | cmd.Args = append(cmd.Args, "import", rootfs, fmt.Sprintf("localhost/%s:%s", imageName, bootstrapVersion)) 104 | cmd.Stdout = os.Stdout 105 | cmd.Stderr = os.Stderr 106 | err = cmd.Run() 107 | if err != nil { 108 | Error.Fatalf("Could not import rootfs from '%s': %s", rootfs, err) 109 | } 110 | } 111 | 112 | workContainer := fmt.Sprintf("%s_%s.%s.working", s.Product.Short_name, s.Name, "bootstrap") 113 | Debug.Printf("Removing temporary container '%s'", workContainer) 114 | cmd := runtime.command() 115 | cmd.Args = append(cmd.Args, "rm", workContainer) 116 | err = cmd.Run() 117 | if err != nil { 118 | Debug.Printf("Could not remove temporary container '%s': %s", workContainer, err) 119 | } 120 | Debug.Printf("Removed temporary container '%s'", workContainer) 121 | 122 | Info.Printf("Running bootstrap step for '%s'", fmt.Sprintf("%s:%s", imageName, bootstrapVersion)) 123 | err = runtime.run(fmt.Sprintf("localhost/%s:%s", imageName, bootstrapVersion), []string{"./bootstrap.sh"}, "bootstrap", s, nil) 124 | if err != nil { 125 | return err 126 | } 127 | 128 | Info.Printf("Commiting final image '%s:%s'", imageName, s.Tag) 129 | cmd = runtime.command() 130 | cmd.Args = append(cmd.Args, "commit", workContainer, fmt.Sprintf("%s:%s", imageName, s.Tag)) 131 | cmd.Stdout = os.Stdout 132 | cmd.Stderr = os.Stderr 133 | err = cmd.Run() 134 | if err != nil { 135 | Error.Fatalf("Could not commit final SDK image: %s", err) 136 | } 137 | Info.Printf("Sucessfully commited final image '%s:%s '", imageName, s.Tag) 138 | 139 | Info.Printf("Removing temporary container '%s'", workContainer) 140 | cmd = runtime.command() 141 | cmd.Args = append(cmd.Args, "rm", workContainer) 142 | err = cmd.Run() 143 | if err != nil { 144 | Error.Fatalf("Could not remove temporary container '%s': %s", workContainer, err) 145 | } 146 | Info.Printf("Removed temporary container '%s'", workContainer) 147 | 148 | return nil 149 | } 150 | 151 | func (s *sdk) run(command []string) error { 152 | err := s.bootstrap() 153 | if err != nil { 154 | return err 155 | } 156 | imageName := fmt.Sprintf("%s/%s", rootConfig.Product.Name, s.Name) 157 | return runtime.run(fmt.Sprintf("%s:%s", imageName, s.Tag), command, "run", s, nil) 158 | } 159 | -------------------------------------------------------------------------------- /cosmk/src/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "path" 7 | ) 8 | 9 | func doTestbedSetup() { 10 | docsDir := path.Join(repoRootPath, "testbed") 11 | err := os.Chdir(docsDir) 12 | if err != nil { 13 | Error.Fatalf("Could not chdir to '%s': %s", docsDir, err) 14 | } 15 | 16 | command := "./setup_testbed.sh" 17 | cmd := exec.Command(command) 18 | cmd.Stdout = os.Stdout 19 | cmd.Stderr = os.Stderr 20 | err = cmd.Run() 21 | if err != nil { 22 | Error.Fatalf("Running '%s' failed with: %s", command, err) 23 | } 24 | } 25 | 26 | func doTestbedRun() { 27 | docsDir := path.Join(repoRootPath, "testbed") 28 | err := os.Chdir(docsDir) 29 | if err != nil { 30 | Error.Fatalf("Could not chdir to '%s': %s", docsDir, err) 31 | } 32 | 33 | product := parseProductConfig() 34 | command := "./run_with_libvirt.py" 35 | cmd := exec.Command(command, product.Short_name, product.Version) 36 | cmd.Stdout = os.Stdout 37 | cmd.Stderr = os.Stderr 38 | err = cmd.Run() 39 | if err != nil { 40 | Error.Fatalf("Running '%s' failed with: %s", command, err) 41 | } 42 | } 43 | 44 | func doTestbedQemu() { 45 | docsDir := path.Join(repoRootPath, "testbed") 46 | err := os.Chdir(docsDir) 47 | if err != nil { 48 | Error.Fatalf("Could not chdir to '%s': %s", docsDir, err) 49 | } 50 | 51 | product := parseProductConfig() 52 | command := "./create_qemu_image.sh" 53 | cmd := exec.Command(command, product.Short_name, product.Version) 54 | cmd.Stdout = os.Stdout 55 | cmd.Stderr = os.Stderr 56 | err = cmd.Run() 57 | if err != nil { 58 | Error.Fatalf("Running '%s' failed with: %s", command, err) 59 | } 60 | 61 | doTestbedRun() 62 | } 63 | -------------------------------------------------------------------------------- /cosmk/src/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "os" 10 | "os/exec" 11 | "path" 12 | "strings" 13 | ) 14 | 15 | var repoRootPath string 16 | var version string = "" 17 | 18 | // Must use default 'log' logger here as the log setup happens later 19 | func findRepoRootPath() string { 20 | currentPath, err := os.Getwd() 21 | if err != nil { 22 | log.Fatalf("Could not get current working directory: %s", err) 23 | } 24 | for { 25 | // log.Println("Looking at:", currentPath) 26 | if currentPath == "/" { 27 | log.Fatal("Could not find project repo root path") 28 | } 29 | fi, err := os.Lstat(path.Join(currentPath, ".repo")) 30 | if err == nil { 31 | if fi.IsDir() { 32 | // log.Println("Found repo root path at:", currentPath) 33 | return currentPath 34 | } 35 | } 36 | currentPath = path.Dir(currentPath) 37 | } 38 | } 39 | 40 | // TODO: Improve the version check logic 41 | // Must use default 'log' logger here as the log setup happens later 42 | func versionCheck(version string) { 43 | versionFile := path.Join(repoRootPath, "toolkit", "cosmk", "version") 44 | content, err := ioutil.ReadFile(versionFile) 45 | if err != nil { 46 | log.Fatalf("Could not open version file '%s': %s", versionFile, err) 47 | } 48 | 49 | versionFromFile := strings.TrimSuffix(string(content), "\n") 50 | if versionFromFile != version { 51 | log.Fatalf("Current cosmk is '%s' while repository version is '%s'. Please rebuild cosmk.", version, versionFromFile) 52 | } 53 | } 54 | 55 | // Must use default 'log' logger here as the log setup happens later 56 | func listGeneric(kind string) []string { 57 | productPath := path.Join(repoRootPath, "products", rootConfig.Product.Name) 58 | files, err := ioutil.ReadDir(productPath) 59 | if err != nil { 60 | log.Fatalf("Could not list directory '%s': %s", productPath, err) 61 | } 62 | 63 | var kinds []string 64 | for _, file := range files { 65 | // Ignore hidden files & directories 66 | if strings.HasPrefix(file.Name(), ".") { 67 | continue 68 | } 69 | if file.IsDir() { 70 | kindToml := path.Join(repoRootPath, "products", rootConfig.Product.Name, file.Name(), fmt.Sprintf("%s.toml", kind)) 71 | _, err := os.Stat(kindToml) 72 | if err != nil { 73 | // log.Printf("Could not open file '%s': %s", kindToml, err) 74 | continue 75 | } 76 | kinds = append(kinds, file.Name()) 77 | } 78 | } 79 | 80 | return kinds 81 | } 82 | 83 | func listSdks() []string { 84 | return listGeneric("sdk") 85 | } 86 | 87 | func listRecipes() []string { 88 | return listGeneric("recipe") 89 | } 90 | 91 | func listAll() []string { 92 | return append(listSdks(), listRecipes()...) 93 | } 94 | 95 | func doCache() { 96 | err := os.Chdir(repoRootPath) 97 | if err != nil { 98 | Error.Fatalf("Could not chdir to '%s': %s", repoRootPath, err) 99 | } 100 | 101 | cachePath := path.Join(repoRootPath, "cache") 102 | _, err = os.Stat(cachePath) 103 | if err == nil { 104 | Error.Fatalf("Remove the 'cache' folder before proceeding.") 105 | } else if !os.IsNotExist(err) { 106 | Error.Fatalf("Could not stat '%s': %s", cachePath, err) 107 | } 108 | 109 | // GitLab API URL to get the latest successful build 110 | url := fmt.Sprintf("%s/api/v4/projects/%s/pipelines?scope=finished&status=success", rootConfig.Ci.Url, rootConfig.Ci.Project_id) 111 | Debug.Printf("Requesting pipeline status from %s", url) 112 | resp, err := http.Get(url) 113 | if err != nil { 114 | Error.Fatalf("Could not get pipeline status: %s", err) 115 | } 116 | defer resp.Body.Close() 117 | 118 | body, err := ioutil.ReadAll(resp.Body) 119 | Debug.Printf("Received: %s", body) 120 | 121 | var pipeline []map[string]interface{} 122 | err = json.Unmarshal([]byte(body), &pipeline) 123 | if err != nil { 124 | Error.Fatalf("Could not parse received JSON from the GitLab API: %s", err) 125 | } 126 | 127 | Debug.Printf("Parsed json: %s", pipeline) 128 | 129 | buildID := 0. 130 | for _, build := range pipeline { 131 | buildID = build["id"].(float64) 132 | break 133 | } 134 | if buildID == 0. { 135 | Error.Fatalf("Could not find the latest successful pipeline.") 136 | } 137 | Debug.Printf("Retrieving binary packages from build ID: %d", int(buildID)) 138 | 139 | // TODO: Import get-cache-from-ci.sh logic here 140 | command := path.Join(repoRootPath, "toolkit", "helpers", "get-cache-from-ci.sh") 141 | cmd := exec.Command(command, fmt.Sprintf("https://files.clip-os.org/%d", int(buildID))) 142 | cmd.Stdout = os.Stdout 143 | cmd.Stderr = os.Stderr 144 | err = cmd.Run() 145 | if err != nil { 146 | Error.Fatalf("Running '%s' failed with: %s", command, err) 147 | } 148 | } 149 | 150 | // Logging helpers 151 | var ( 152 | Debug *log.Logger 153 | Info *log.Logger 154 | Error *log.Logger 155 | ) 156 | 157 | func initLogging(debug *bool) { 158 | if *debug { 159 | Debug = log.New(os.Stdout, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile) 160 | Info = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) 161 | Error = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) 162 | Debug.Println("Log level set to debug") 163 | } else { 164 | Debug = log.New(ioutil.Discard, "", 0) 165 | Info = log.New(os.Stdout, "[*] ", 0) 166 | Error = log.New(os.Stdout, "[!] ", 0) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/.gitignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | tags 3 | .*.swp 4 | tomlcheck/tomlcheck 5 | toml.test 6 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.1 4 | - 1.2 5 | - 1.3 6 | - 1.4 7 | - 1.5 8 | - 1.6 9 | - tip 10 | install: 11 | - go install ./... 12 | - go get github.com/BurntSushi/toml-test 13 | script: 14 | - export PATH="$PATH:$HOME/gopath/bin" 15 | - make test 16 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/COMPATIBLE: -------------------------------------------------------------------------------- 1 | Compatible with TOML version 2 | [v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md) 3 | 4 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | go install ./... 3 | 4 | test: install 5 | go test -v 6 | toml-test toml-test-decoder 7 | toml-test -encoder toml-test-encoder 8 | 9 | fmt: 10 | gofmt -w *.go */*.go 11 | colcheck *.go */*.go 12 | 13 | tags: 14 | find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS 15 | 16 | push: 17 | git push origin master 18 | git push github master 19 | 20 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/README.md: -------------------------------------------------------------------------------- 1 | ## TOML parser and encoder for Go with reflection 2 | 3 | TOML stands for Tom's Obvious, Minimal Language. This Go package provides a 4 | reflection interface similar to Go's standard library `json` and `xml` 5 | packages. This package also supports the `encoding.TextUnmarshaler` and 6 | `encoding.TextMarshaler` interfaces so that you can define custom data 7 | representations. (There is an example of this below.) 8 | 9 | Spec: https://github.com/toml-lang/toml 10 | 11 | Compatible with TOML version 12 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 13 | 14 | Documentation: https://godoc.org/github.com/BurntSushi/toml 15 | 16 | Installation: 17 | 18 | ```bash 19 | go get github.com/BurntSushi/toml 20 | ``` 21 | 22 | Try the toml validator: 23 | 24 | ```bash 25 | go get github.com/BurntSushi/toml/cmd/tomlv 26 | tomlv some-toml-file.toml 27 | ``` 28 | 29 | [![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml) 30 | 31 | ### Testing 32 | 33 | This package passes all tests in 34 | [toml-test](https://github.com/BurntSushi/toml-test) for both the decoder 35 | and the encoder. 36 | 37 | ### Examples 38 | 39 | This package works similarly to how the Go standard library handles `XML` 40 | and `JSON`. Namely, data is loaded into Go values via reflection. 41 | 42 | For the simplest example, consider some TOML file as just a list of keys 43 | and values: 44 | 45 | ```toml 46 | Age = 25 47 | Cats = [ "Cauchy", "Plato" ] 48 | Pi = 3.14 49 | Perfection = [ 6, 28, 496, 8128 ] 50 | DOB = 1987-07-05T05:45:00Z 51 | ``` 52 | 53 | Which could be defined in Go as: 54 | 55 | ```go 56 | type Config struct { 57 | Age int 58 | Cats []string 59 | Pi float64 60 | Perfection []int 61 | DOB time.Time // requires `import time` 62 | } 63 | ``` 64 | 65 | And then decoded with: 66 | 67 | ```go 68 | var conf Config 69 | if _, err := toml.Decode(tomlData, &conf); err != nil { 70 | // handle error 71 | } 72 | ``` 73 | 74 | You can also use struct tags if your struct field name doesn't map to a TOML 75 | key value directly: 76 | 77 | ```toml 78 | some_key_NAME = "wat" 79 | ``` 80 | 81 | ```go 82 | type TOML struct { 83 | ObscureKey string `toml:"some_key_NAME"` 84 | } 85 | ``` 86 | 87 | ### Using the `encoding.TextUnmarshaler` interface 88 | 89 | Here's an example that automatically parses duration strings into 90 | `time.Duration` values: 91 | 92 | ```toml 93 | [[song]] 94 | name = "Thunder Road" 95 | duration = "4m49s" 96 | 97 | [[song]] 98 | name = "Stairway to Heaven" 99 | duration = "8m03s" 100 | ``` 101 | 102 | Which can be decoded with: 103 | 104 | ```go 105 | type song struct { 106 | Name string 107 | Duration duration 108 | } 109 | type songs struct { 110 | Song []song 111 | } 112 | var favorites songs 113 | if _, err := toml.Decode(blob, &favorites); err != nil { 114 | log.Fatal(err) 115 | } 116 | 117 | for _, s := range favorites.Song { 118 | fmt.Printf("%s (%s)\n", s.Name, s.Duration) 119 | } 120 | ``` 121 | 122 | And you'll also need a `duration` type that satisfies the 123 | `encoding.TextUnmarshaler` interface: 124 | 125 | ```go 126 | type duration struct { 127 | time.Duration 128 | } 129 | 130 | func (d *duration) UnmarshalText(text []byte) error { 131 | var err error 132 | d.Duration, err = time.ParseDuration(string(text)) 133 | return err 134 | } 135 | ``` 136 | 137 | ### More complex usage 138 | 139 | Here's an example of how to load the example from the official spec page: 140 | 141 | ```toml 142 | # This is a TOML document. Boom. 143 | 144 | title = "TOML Example" 145 | 146 | [owner] 147 | name = "Tom Preston-Werner" 148 | organization = "GitHub" 149 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 150 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 151 | 152 | [database] 153 | server = "192.168.1.1" 154 | ports = [ 8001, 8001, 8002 ] 155 | connection_max = 5000 156 | enabled = true 157 | 158 | [servers] 159 | 160 | # You can indent as you please. Tabs or spaces. TOML don't care. 161 | [servers.alpha] 162 | ip = "10.0.0.1" 163 | dc = "eqdc10" 164 | 165 | [servers.beta] 166 | ip = "10.0.0.2" 167 | dc = "eqdc10" 168 | 169 | [clients] 170 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 171 | 172 | # Line breaks are OK when inside arrays 173 | hosts = [ 174 | "alpha", 175 | "omega" 176 | ] 177 | ``` 178 | 179 | And the corresponding Go types are: 180 | 181 | ```go 182 | type tomlConfig struct { 183 | Title string 184 | Owner ownerInfo 185 | DB database `toml:"database"` 186 | Servers map[string]server 187 | Clients clients 188 | } 189 | 190 | type ownerInfo struct { 191 | Name string 192 | Org string `toml:"organization"` 193 | Bio string 194 | DOB time.Time 195 | } 196 | 197 | type database struct { 198 | Server string 199 | Ports []int 200 | ConnMax int `toml:"connection_max"` 201 | Enabled bool 202 | } 203 | 204 | type server struct { 205 | IP string 206 | DC string 207 | } 208 | 209 | type clients struct { 210 | Data [][]interface{} 211 | Hosts []string 212 | } 213 | ``` 214 | 215 | Note that a case insensitive match will be tried if an exact match can't be 216 | found. 217 | 218 | A working example of the above can be found in `_examples/example.{go,toml}`. 219 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/decode_meta.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import "strings" 4 | 5 | // MetaData allows access to meta information about TOML data that may not 6 | // be inferrable via reflection. In particular, whether a key has been defined 7 | // and the TOML type of a key. 8 | type MetaData struct { 9 | mapping map[string]interface{} 10 | types map[string]tomlType 11 | keys []Key 12 | decoded map[string]bool 13 | context Key // Used only during decoding. 14 | } 15 | 16 | // IsDefined returns true if the key given exists in the TOML data. The key 17 | // should be specified hierarchially. e.g., 18 | // 19 | // // access the TOML key 'a.b.c' 20 | // IsDefined("a", "b", "c") 21 | // 22 | // IsDefined will return false if an empty key given. Keys are case sensitive. 23 | func (md *MetaData) IsDefined(key ...string) bool { 24 | if len(key) == 0 { 25 | return false 26 | } 27 | 28 | var hash map[string]interface{} 29 | var ok bool 30 | var hashOrVal interface{} = md.mapping 31 | for _, k := range key { 32 | if hash, ok = hashOrVal.(map[string]interface{}); !ok { 33 | return false 34 | } 35 | if hashOrVal, ok = hash[k]; !ok { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | 42 | // Type returns a string representation of the type of the key specified. 43 | // 44 | // Type will return the empty string if given an empty key or a key that 45 | // does not exist. Keys are case sensitive. 46 | func (md *MetaData) Type(key ...string) string { 47 | fullkey := strings.Join(key, ".") 48 | if typ, ok := md.types[fullkey]; ok { 49 | return typ.typeString() 50 | } 51 | return "" 52 | } 53 | 54 | // Key is the type of any TOML key, including key groups. Use (MetaData).Keys 55 | // to get values of this type. 56 | type Key []string 57 | 58 | func (k Key) String() string { 59 | return strings.Join(k, ".") 60 | } 61 | 62 | func (k Key) maybeQuotedAll() string { 63 | var ss []string 64 | for i := range k { 65 | ss = append(ss, k.maybeQuoted(i)) 66 | } 67 | return strings.Join(ss, ".") 68 | } 69 | 70 | func (k Key) maybeQuoted(i int) string { 71 | quote := false 72 | for _, c := range k[i] { 73 | if !isBareKeyChar(c) { 74 | quote = true 75 | break 76 | } 77 | } 78 | if quote { 79 | return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" 80 | } 81 | return k[i] 82 | } 83 | 84 | func (k Key) add(piece string) Key { 85 | newKey := make(Key, len(k)+1) 86 | copy(newKey, k) 87 | newKey[len(k)] = piece 88 | return newKey 89 | } 90 | 91 | // Keys returns a slice of every key in the TOML data, including key groups. 92 | // Each key is itself a slice, where the first element is the top of the 93 | // hierarchy and the last is the most specific. 94 | // 95 | // The list will have the same order as the keys appeared in the TOML data. 96 | // 97 | // All keys returned are non-empty. 98 | func (md *MetaData) Keys() []Key { 99 | return md.keys 100 | } 101 | 102 | // Undecoded returns all keys that have not been decoded in the order in which 103 | // they appear in the original TOML document. 104 | // 105 | // This includes keys that haven't been decoded because of a Primitive value. 106 | // Once the Primitive value is decoded, the keys will be considered decoded. 107 | // 108 | // Also note that decoding into an empty interface will result in no decoding, 109 | // and so no keys will be considered decoded. 110 | // 111 | // In this sense, the Undecoded keys correspond to keys in the TOML document 112 | // that do not have a concrete type in your representation. 113 | func (md *MetaData) Undecoded() []Key { 114 | undecoded := make([]Key, 0, len(md.keys)) 115 | for _, key := range md.keys { 116 | if !md.decoded[key.String()] { 117 | undecoded = append(undecoded, key) 118 | } 119 | } 120 | return undecoded 121 | } 122 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package toml provides facilities for decoding and encoding TOML configuration 3 | files via reflection. There is also support for delaying decoding with 4 | the Primitive type, and querying the set of keys in a TOML document with the 5 | MetaData type. 6 | 7 | The specification implemented: https://github.com/toml-lang/toml 8 | 9 | The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify 10 | whether a file is a valid TOML document. It can also be used to print the 11 | type of each key in a TOML document. 12 | 13 | Testing 14 | 15 | There are two important types of tests used for this package. The first is 16 | contained inside '*_test.go' files and uses the standard Go unit testing 17 | framework. These tests are primarily devoted to holistically testing the 18 | decoder and encoder. 19 | 20 | The second type of testing is used to verify the implementation's adherence 21 | to the TOML specification. These tests have been factored into their own 22 | project: https://github.com/BurntSushi/toml-test 23 | 24 | The reason the tests are in a separate project is so that they can be used by 25 | any implementation of TOML. Namely, it is language agnostic. 26 | */ 27 | package toml 28 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/encoding_types.go: -------------------------------------------------------------------------------- 1 | // +build go1.2 2 | 3 | package toml 4 | 5 | // In order to support Go 1.1, we define our own TextMarshaler and 6 | // TextUnmarshaler types. For Go 1.2+, we just alias them with the 7 | // standard library interfaces. 8 | 9 | import ( 10 | "encoding" 11 | ) 12 | 13 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 14 | // so that Go 1.1 can be supported. 15 | type TextMarshaler encoding.TextMarshaler 16 | 17 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 18 | // here so that Go 1.1 can be supported. 19 | type TextUnmarshaler encoding.TextUnmarshaler 20 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go: -------------------------------------------------------------------------------- 1 | // +build !go1.2 2 | 3 | package toml 4 | 5 | // These interfaces were introduced in Go 1.2, so we add them manually when 6 | // compiling for Go 1.1. 7 | 8 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 9 | // so that Go 1.1 can be supported. 10 | type TextMarshaler interface { 11 | MarshalText() (text []byte, err error) 12 | } 13 | 14 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 15 | // here so that Go 1.1 can be supported. 16 | type TextUnmarshaler interface { 17 | UnmarshalText(text []byte) error 18 | } 19 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/session.vim: -------------------------------------------------------------------------------- 1 | au BufWritePost *.go silent!make tags > /dev/null 2>&1 2 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/type_check.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // tomlType represents any Go type that corresponds to a TOML type. 4 | // While the first draft of the TOML spec has a simplistic type system that 5 | // probably doesn't need this level of sophistication, we seem to be militating 6 | // toward adding real composite types. 7 | type tomlType interface { 8 | typeString() string 9 | } 10 | 11 | // typeEqual accepts any two types and returns true if they are equal. 12 | func typeEqual(t1, t2 tomlType) bool { 13 | if t1 == nil || t2 == nil { 14 | return false 15 | } 16 | return t1.typeString() == t2.typeString() 17 | } 18 | 19 | func typeIsHash(t tomlType) bool { 20 | return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) 21 | } 22 | 23 | type tomlBaseType string 24 | 25 | func (btype tomlBaseType) typeString() string { 26 | return string(btype) 27 | } 28 | 29 | func (btype tomlBaseType) String() string { 30 | return btype.typeString() 31 | } 32 | 33 | var ( 34 | tomlInteger tomlBaseType = "Integer" 35 | tomlFloat tomlBaseType = "Float" 36 | tomlDatetime tomlBaseType = "Datetime" 37 | tomlString tomlBaseType = "String" 38 | tomlBool tomlBaseType = "Bool" 39 | tomlArray tomlBaseType = "Array" 40 | tomlHash tomlBaseType = "Hash" 41 | tomlArrayHash tomlBaseType = "ArrayHash" 42 | ) 43 | 44 | // typeOfPrimitive returns a tomlType of any primitive value in TOML. 45 | // Primitive values are: Integer, Float, Datetime, String and Bool. 46 | // 47 | // Passing a lexer item other than the following will cause a BUG message 48 | // to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. 49 | func (p *parser) typeOfPrimitive(lexItem item) tomlType { 50 | switch lexItem.typ { 51 | case itemInteger: 52 | return tomlInteger 53 | case itemFloat: 54 | return tomlFloat 55 | case itemDatetime: 56 | return tomlDatetime 57 | case itemString: 58 | return tomlString 59 | case itemMultilineString: 60 | return tomlString 61 | case itemRawString: 62 | return tomlString 63 | case itemRawMultilineString: 64 | return tomlString 65 | case itemBool: 66 | return tomlBool 67 | } 68 | p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) 69 | panic("unreachable") 70 | } 71 | 72 | // typeOfArray returns a tomlType for an array given a list of types of its 73 | // values. 74 | // 75 | // In the current spec, if an array is homogeneous, then its type is always 76 | // "Array". If the array is not homogeneous, an error is generated. 77 | func (p *parser) typeOfArray(types []tomlType) tomlType { 78 | // Empty arrays are cool. 79 | if len(types) == 0 { 80 | return tomlArray 81 | } 82 | 83 | theType := types[0] 84 | for _, t := range types[1:] { 85 | if !typeEqual(theType, t) { 86 | p.panicf("Array contains values of type '%s' and '%s', but "+ 87 | "arrays must be homogeneous.", theType, t) 88 | } 89 | } 90 | return tomlArray 91 | } 92 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/BurntSushi/toml/type_fields.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // Struct field handling is adapted from code in encoding/json: 4 | // 5 | // Copyright 2010 The Go Authors. All rights reserved. 6 | // Use of this source code is governed by a BSD-style 7 | // license that can be found in the Go distribution. 8 | 9 | import ( 10 | "reflect" 11 | "sort" 12 | "sync" 13 | ) 14 | 15 | // A field represents a single field found in a struct. 16 | type field struct { 17 | name string // the name of the field (`toml` tag included) 18 | tag bool // whether field has a `toml` tag 19 | index []int // represents the depth of an anonymous field 20 | typ reflect.Type // the type of the field 21 | } 22 | 23 | // byName sorts field by name, breaking ties with depth, 24 | // then breaking ties with "name came from toml tag", then 25 | // breaking ties with index sequence. 26 | type byName []field 27 | 28 | func (x byName) Len() int { return len(x) } 29 | 30 | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 31 | 32 | func (x byName) Less(i, j int) bool { 33 | if x[i].name != x[j].name { 34 | return x[i].name < x[j].name 35 | } 36 | if len(x[i].index) != len(x[j].index) { 37 | return len(x[i].index) < len(x[j].index) 38 | } 39 | if x[i].tag != x[j].tag { 40 | return x[i].tag 41 | } 42 | return byIndex(x).Less(i, j) 43 | } 44 | 45 | // byIndex sorts field by index sequence. 46 | type byIndex []field 47 | 48 | func (x byIndex) Len() int { return len(x) } 49 | 50 | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 51 | 52 | func (x byIndex) Less(i, j int) bool { 53 | for k, xik := range x[i].index { 54 | if k >= len(x[j].index) { 55 | return false 56 | } 57 | if xik != x[j].index[k] { 58 | return xik < x[j].index[k] 59 | } 60 | } 61 | return len(x[i].index) < len(x[j].index) 62 | } 63 | 64 | // typeFields returns a list of fields that TOML should recognize for the given 65 | // type. The algorithm is breadth-first search over the set of structs to 66 | // include - the top struct and then any reachable anonymous structs. 67 | func typeFields(t reflect.Type) []field { 68 | // Anonymous fields to explore at the current level and the next. 69 | current := []field{} 70 | next := []field{{typ: t}} 71 | 72 | // Count of queued names for current level and the next. 73 | count := map[reflect.Type]int{} 74 | nextCount := map[reflect.Type]int{} 75 | 76 | // Types already visited at an earlier level. 77 | visited := map[reflect.Type]bool{} 78 | 79 | // Fields found. 80 | var fields []field 81 | 82 | for len(next) > 0 { 83 | current, next = next, current[:0] 84 | count, nextCount = nextCount, map[reflect.Type]int{} 85 | 86 | for _, f := range current { 87 | if visited[f.typ] { 88 | continue 89 | } 90 | visited[f.typ] = true 91 | 92 | // Scan f.typ for fields to include. 93 | for i := 0; i < f.typ.NumField(); i++ { 94 | sf := f.typ.Field(i) 95 | if sf.PkgPath != "" && !sf.Anonymous { // unexported 96 | continue 97 | } 98 | opts := getOptions(sf.Tag) 99 | if opts.skip { 100 | continue 101 | } 102 | index := make([]int, len(f.index)+1) 103 | copy(index, f.index) 104 | index[len(f.index)] = i 105 | 106 | ft := sf.Type 107 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { 108 | // Follow pointer. 109 | ft = ft.Elem() 110 | } 111 | 112 | // Record found field and index sequence. 113 | if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 114 | tagged := opts.name != "" 115 | name := opts.name 116 | if name == "" { 117 | name = sf.Name 118 | } 119 | fields = append(fields, field{name, tagged, index, ft}) 120 | if count[f.typ] > 1 { 121 | // If there were multiple instances, add a second, 122 | // so that the annihilation code will see a duplicate. 123 | // It only cares about the distinction between 1 or 2, 124 | // so don't bother generating any more copies. 125 | fields = append(fields, fields[len(fields)-1]) 126 | } 127 | continue 128 | } 129 | 130 | // Record new anonymous struct to explore in next round. 131 | nextCount[ft]++ 132 | if nextCount[ft] == 1 { 133 | f := field{name: ft.Name(), index: index, typ: ft} 134 | next = append(next, f) 135 | } 136 | } 137 | } 138 | } 139 | 140 | sort.Sort(byName(fields)) 141 | 142 | // Delete all fields that are hidden by the Go rules for embedded fields, 143 | // except that fields with TOML tags are promoted. 144 | 145 | // The fields are sorted in primary order of name, secondary order 146 | // of field index length. Loop over names; for each name, delete 147 | // hidden fields by choosing the one dominant field that survives. 148 | out := fields[:0] 149 | for advance, i := 0, 0; i < len(fields); i += advance { 150 | // One iteration per name. 151 | // Find the sequence of fields with the name of this first field. 152 | fi := fields[i] 153 | name := fi.name 154 | for advance = 1; i+advance < len(fields); advance++ { 155 | fj := fields[i+advance] 156 | if fj.name != name { 157 | break 158 | } 159 | } 160 | if advance == 1 { // Only one field with this name 161 | out = append(out, fi) 162 | continue 163 | } 164 | dominant, ok := dominantField(fields[i : i+advance]) 165 | if ok { 166 | out = append(out, dominant) 167 | } 168 | } 169 | 170 | fields = out 171 | sort.Sort(byIndex(fields)) 172 | 173 | return fields 174 | } 175 | 176 | // dominantField looks through the fields, all of which are known to 177 | // have the same name, to find the single field that dominates the 178 | // others using Go's embedding rules, modified by the presence of 179 | // TOML tags. If there are multiple top-level fields, the boolean 180 | // will be false: This condition is an error in Go and we skip all 181 | // the fields. 182 | func dominantField(fields []field) (field, bool) { 183 | // The fields are sorted in increasing index-length order. The winner 184 | // must therefore be one with the shortest index length. Drop all 185 | // longer entries, which is easy: just truncate the slice. 186 | length := len(fields[0].index) 187 | tagged := -1 // Index of first tagged field. 188 | for i, f := range fields { 189 | if len(f.index) > length { 190 | fields = fields[:i] 191 | break 192 | } 193 | if f.tag { 194 | if tagged >= 0 { 195 | // Multiple tagged fields at the same level: conflict. 196 | // Return no field. 197 | return field{}, false 198 | } 199 | tagged = i 200 | } 201 | } 202 | if tagged >= 0 { 203 | return fields[tagged], true 204 | } 205 | // All remaining fields have the same length. If there's more than one, 206 | // we have a conflict (two fields named "X" at the same level) and we 207 | // return no field. 208 | if len(fields) > 1 { 209 | return field{}, false 210 | } 211 | return fields[0], true 212 | } 213 | 214 | var fieldCache struct { 215 | sync.RWMutex 216 | m map[reflect.Type][]field 217 | } 218 | 219 | // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 220 | func cachedTypeFields(t reflect.Type) []field { 221 | fieldCache.RLock() 222 | f := fieldCache.m[t] 223 | fieldCache.RUnlock() 224 | if f != nil { 225 | return f 226 | } 227 | 228 | // Compute fields without lock. 229 | // Might duplicate effort but won't hold other computations back. 230 | f = typeFields(t) 231 | if f == nil { 232 | f = []field{} 233 | } 234 | 235 | fieldCache.Lock() 236 | if fieldCache.m == nil { 237 | fieldCache.m = map[reflect.Type][]field{} 238 | } 239 | fieldCache.m[t] = f 240 | fieldCache.Unlock() 241 | return f 242 | } 243 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | tests: true 3 | 4 | output: 5 | print-issued-lines: false 6 | 7 | linters: 8 | enable-all: true 9 | disable: 10 | - maligned 11 | - lll 12 | - gochecknoglobals 13 | - wsl 14 | - funlen 15 | - gocognit 16 | - gomnd 17 | - goprintffuncname 18 | 19 | linters-settings: 20 | govet: 21 | check-shadowing: true 22 | dupl: 23 | threshold: 100 24 | goconst: 25 | min-len: 5 26 | min-occurrences: 3 27 | gocyclo: 28 | min-complexity: 20 29 | 30 | issues: 31 | max-per-linter: 0 32 | max-same: 0 33 | exclude-use-default: false 34 | exclude: 35 | - '^(G104|G204):' 36 | # Very commonly not checked. 37 | - 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked' 38 | - 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON) should have comment or be unexported' 39 | - 'composite literal uses unkeyed fields' 40 | - 'bad syntax for struct tag key' 41 | - 'bad syntax for struct tag pair' 42 | - 'result .* \(error\) is always nil' 43 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/build.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | // Plugins are dynamically embedded command-line structures. 10 | // 11 | // Each element in the Plugins list *must* be a pointer to a structure. 12 | type Plugins []interface{} 13 | 14 | func build(k *Kong, ast interface{}) (app *Application, err error) { 15 | defer catch(&err) 16 | v := reflect.ValueOf(ast) 17 | iv := reflect.Indirect(v) 18 | if v.Kind() != reflect.Ptr || iv.Kind() != reflect.Struct { 19 | return nil, fmt.Errorf("expected a pointer to a struct but got %T", ast) 20 | } 21 | 22 | app = &Application{} 23 | extraFlags := k.extraFlags() 24 | seenFlags := map[string]bool{} 25 | for _, flag := range extraFlags { 26 | seenFlags[flag.Name] = true 27 | } 28 | node := buildNode(k, iv, ApplicationNode, seenFlags) 29 | if len(node.Positional) > 0 && len(node.Children) > 0 { 30 | return nil, fmt.Errorf("can't mix positional arguments and branching arguments on %T", ast) 31 | } 32 | app.Node = node 33 | app.Node.Flags = append(extraFlags, app.Node.Flags...) 34 | app.Tag = newEmptyTag() 35 | app.Tag.Vars = k.vars 36 | return app, nil 37 | } 38 | 39 | func dashedString(s string) string { 40 | return strings.Join(camelCase(s), "-") 41 | } 42 | 43 | type flattenedField struct { 44 | field reflect.StructField 45 | value reflect.Value 46 | tag *Tag 47 | } 48 | 49 | func flattenedFields(v reflect.Value) (out []flattenedField) { 50 | v = reflect.Indirect(v) 51 | for i := 0; i < v.NumField(); i++ { 52 | ft := v.Type().Field(i) 53 | fv := v.Field(i) 54 | tag := parseTag(fv, ft) 55 | if tag.Ignored { 56 | continue 57 | } 58 | if !ft.Anonymous && !tag.Embed { 59 | if fv.CanSet() { 60 | out = append(out, flattenedField{field: ft, value: fv, tag: tag}) 61 | } 62 | continue 63 | } 64 | 65 | // Embedded type. 66 | if fv.Kind() == reflect.Interface { 67 | fv = fv.Elem() 68 | } else if fv.Type() == reflect.TypeOf(Plugins{}) { 69 | for i := 0; i < fv.Len(); i++ { 70 | out = append(out, flattenedFields(fv.Index(i).Elem())...) 71 | } 72 | continue 73 | } 74 | sub := flattenedFields(fv) 75 | for _, subf := range sub { 76 | // Assign parent if it's not already set. 77 | if subf.tag.Group == "" { 78 | subf.tag.Group = tag.Group 79 | } 80 | // Accumulate prefixes. 81 | subf.tag.Prefix = tag.Prefix + subf.tag.Prefix 82 | // Combine parent vars. 83 | subf.tag.Vars = tag.Vars.CloneWith(subf.tag.Vars) 84 | } 85 | out = append(out, sub...) 86 | } 87 | return out 88 | } 89 | 90 | func buildNode(k *Kong, v reflect.Value, typ NodeType, seenFlags map[string]bool) *Node { 91 | node := &Node{ 92 | Type: typ, 93 | Target: v, 94 | Tag: newEmptyTag(), 95 | } 96 | for _, field := range flattenedFields(v) { 97 | ft := field.field 98 | fv := field.value 99 | 100 | tag := field.tag 101 | name := tag.Name 102 | if name == "" { 103 | name = tag.Prefix + strings.ToLower(dashedString(ft.Name)) 104 | } else { 105 | name = tag.Prefix + name 106 | } 107 | 108 | // Nested structs are either commands or args, unless they implement the Mapper interface. 109 | if ft.Type.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) && k.registry.ForValue(fv) == nil { 110 | typ := CommandNode 111 | if tag.Arg { 112 | typ = ArgumentNode 113 | } 114 | buildChild(k, node, typ, v, ft, fv, tag, name, seenFlags) 115 | } else { 116 | buildField(k, node, v, ft, fv, tag, name, seenFlags) 117 | } 118 | } 119 | 120 | // "Unsee" flags. 121 | for _, flag := range node.Flags { 122 | delete(seenFlags, flag.Name) 123 | } 124 | 125 | // Scan through argument positionals to ensure optional is never before a required. 126 | last := true 127 | for i, p := range node.Positional { 128 | if !last && p.Required { 129 | fail("argument %q can not be required after an optional", p.Name) 130 | } 131 | 132 | last = p.Required 133 | p.Position = i 134 | } 135 | 136 | return node 137 | } 138 | 139 | func buildChild(k *Kong, node *Node, typ NodeType, v reflect.Value, ft reflect.StructField, fv reflect.Value, tag *Tag, name string, seenFlags map[string]bool) { 140 | child := buildNode(k, fv, typ, seenFlags) 141 | child.Tag = tag 142 | child.Parent = node 143 | child.Help = tag.Help 144 | child.Hidden = tag.Hidden 145 | child.Group = buildGroupForKey(k, tag.Group) 146 | child.Aliases = tag.Aliases 147 | 148 | if provider, ok := fv.Addr().Interface().(HelpProvider); ok { 149 | child.Detail = provider.Help() 150 | } 151 | 152 | // A branching argument. This is a bit hairy, as we let buildNode() do the parsing, then check that 153 | // a positional argument is provided to the child, and move it to the branching argument field. 154 | if tag.Arg { 155 | if len(child.Positional) == 0 { 156 | fail("positional branch %s.%s must have at least one child positional argument named %q", 157 | v.Type().Name(), ft.Name, name) 158 | } 159 | 160 | value := child.Positional[0] 161 | child.Positional = child.Positional[1:] 162 | if child.Help == "" { 163 | child.Help = value.Help 164 | } 165 | 166 | child.Name = value.Name 167 | if child.Name != name { 168 | fail("first field in positional branch %s.%s must have the same name as the parent field (%s).", 169 | v.Type().Name(), ft.Name, child.Name) 170 | } 171 | 172 | child.Argument = value 173 | } else { 174 | child.Name = name 175 | } 176 | node.Children = append(node.Children, child) 177 | 178 | if len(child.Positional) > 0 && len(child.Children) > 0 { 179 | fail("can't mix positional arguments and branching arguments on %s.%s", v.Type().Name(), ft.Name) 180 | } 181 | } 182 | 183 | func buildField(k *Kong, node *Node, v reflect.Value, ft reflect.StructField, fv reflect.Value, tag *Tag, name string, seenFlags map[string]bool) { 184 | mapper := k.registry.ForNamedValue(tag.Type, fv) 185 | if mapper == nil { 186 | fail("unsupported field type %s.%s (of type %s), perhaps missing a cmd:\"\" tag?", v.Type(), ft.Name, ft.Type) 187 | } 188 | 189 | value := &Value{ 190 | Name: name, 191 | Help: tag.Help, 192 | Default: tag.Default, 193 | DefaultValue: reflect.New(fv.Type()).Elem(), 194 | Mapper: mapper, 195 | Tag: tag, 196 | Target: fv, 197 | Enum: tag.Enum, 198 | Passthrough: tag.Passthrough, 199 | 200 | // Flags are optional by default, and args are required by default. 201 | Required: (!tag.Arg && tag.Required) || (tag.Arg && !tag.Optional), 202 | Format: tag.Format, 203 | } 204 | 205 | if tag.Arg { 206 | node.Positional = append(node.Positional, value) 207 | } else { 208 | if seenFlags[value.Name] { 209 | fail("duplicate flag --%s", value.Name) 210 | } 211 | seenFlags[value.Name] = true 212 | flag := &Flag{ 213 | Value: value, 214 | Short: tag.Short, 215 | PlaceHolder: tag.PlaceHolder, 216 | Env: tag.Env, 217 | Group: buildGroupForKey(k, tag.Group), 218 | Xor: tag.Xor, 219 | Hidden: tag.Hidden, 220 | } 221 | value.Flag = flag 222 | node.Flags = append(node.Flags, flag) 223 | } 224 | } 225 | 226 | func buildGroupForKey(k *Kong, key string) *Group { 227 | if key == "" { 228 | return nil 229 | } 230 | for _, group := range k.groups { 231 | if group.Key == key { 232 | return &group 233 | } 234 | } 235 | 236 | // No group provided with kong.ExplicitGroups. We create one ad-hoc for this key. 237 | return &Group{ 238 | Key: key, 239 | Title: key, 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/callbacks.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | type bindings map[reflect.Type]func() (reflect.Value, error) 10 | 11 | func (b bindings) String() string { 12 | out := []string{} 13 | for k := range b { 14 | out = append(out, k.String()) 15 | } 16 | return "bindings{" + strings.Join(out, ", ") + "}" 17 | } 18 | 19 | func (b bindings) add(values ...interface{}) bindings { 20 | for _, v := range values { 21 | v := v 22 | b[reflect.TypeOf(v)] = func() (reflect.Value, error) { return reflect.ValueOf(v), nil } 23 | } 24 | return b 25 | } 26 | 27 | // Clone and add values. 28 | func (b bindings) clone() bindings { 29 | out := make(bindings, len(b)) 30 | for k, v := range b { 31 | out[k] = v 32 | } 33 | return out 34 | } 35 | 36 | func (b bindings) merge(other bindings) bindings { 37 | for k, v := range other { 38 | b[k] = v 39 | } 40 | return b 41 | } 42 | 43 | func getMethod(value reflect.Value, name string) reflect.Value { 44 | method := value.MethodByName(name) 45 | if !method.IsValid() { 46 | if value.CanAddr() { 47 | method = value.Addr().MethodByName(name) 48 | } 49 | } 50 | return method 51 | } 52 | 53 | func callMethod(name string, v, f reflect.Value, bindings bindings) error { 54 | in := []reflect.Value{} 55 | t := f.Type() 56 | if t.NumOut() != 1 || t.Out(0) != callbackReturnSignature { 57 | return fmt.Errorf("return value of %T.%s() must be exactly \"error\"", v.Type(), name) 58 | } 59 | for i := 0; i < t.NumIn(); i++ { 60 | pt := t.In(i) 61 | if argf, ok := bindings[pt]; ok { 62 | argv, err := argf() 63 | if err != nil { 64 | return err 65 | } 66 | in = append(in, argv) 67 | } else { 68 | return fmt.Errorf("couldn't find binding of type %s for parameter %d of %s.%s(), use kong.Bind(%s)", pt, i, v.Type(), name, pt) 69 | } 70 | } 71 | out := f.Call(in) 72 | if out[0].IsNil() { 73 | return nil 74 | } 75 | return out[0].Interface().(error) 76 | } 77 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/camelcase.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | // NOTE: This code is from https://github.com/fatih/camelcase. MIT license. 4 | 5 | import ( 6 | "unicode" 7 | "unicode/utf8" 8 | ) 9 | 10 | // Split splits the camelcase word and returns a list of words. It also 11 | // supports digits. Both lower camel case and upper camel case are supported. 12 | // For more info please check: http://en.wikipedia.org/wiki/CamelCase 13 | // 14 | // Examples 15 | // 16 | // "" => [""] 17 | // "lowercase" => ["lowercase"] 18 | // "Class" => ["Class"] 19 | // "MyClass" => ["My", "Class"] 20 | // "MyC" => ["My", "C"] 21 | // "HTML" => ["HTML"] 22 | // "PDFLoader" => ["PDF", "Loader"] 23 | // "AString" => ["A", "String"] 24 | // "SimpleXMLParser" => ["Simple", "XML", "Parser"] 25 | // "vimRPCPlugin" => ["vim", "RPC", "Plugin"] 26 | // "GL11Version" => ["GL", "11", "Version"] 27 | // "99Bottles" => ["99", "Bottles"] 28 | // "May5" => ["May", "5"] 29 | // "BFG9000" => ["BFG", "9000"] 30 | // "BöseÜberraschung" => ["Böse", "Überraschung"] 31 | // "Two spaces" => ["Two", " ", "spaces"] 32 | // "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"] 33 | // 34 | // Splitting rules 35 | // 36 | // 1) If string is not valid UTF-8, return it without splitting as 37 | // single item array. 38 | // 2) Assign all unicode characters into one of 4 sets: lower case 39 | // letters, upper case letters, numbers, and all other characters. 40 | // 3) Iterate through characters of string, introducing splits 41 | // between adjacent characters that belong to different sets. 42 | // 4) Iterate through array of split strings, and if a given string 43 | // is upper case: 44 | // if subsequent string is lower case: 45 | // move last character of upper case string to beginning of 46 | // lower case string 47 | func camelCase(src string) (entries []string) { 48 | // don't split invalid utf8 49 | if !utf8.ValidString(src) { 50 | return []string{src} 51 | } 52 | entries = []string{} 53 | var runes [][]rune 54 | lastClass := 0 55 | // split into fields based on class of unicode character 56 | for _, r := range src { 57 | var class int 58 | switch { 59 | case unicode.IsLower(r): 60 | class = 1 61 | case unicode.IsUpper(r): 62 | class = 2 63 | case unicode.IsDigit(r): 64 | class = 3 65 | default: 66 | class = 4 67 | } 68 | if class == lastClass { 69 | runes[len(runes)-1] = append(runes[len(runes)-1], r) 70 | } else { 71 | runes = append(runes, []rune{r}) 72 | } 73 | lastClass = class 74 | } 75 | // handle upper case -> lower case sequences, e.g. 76 | // "PDFL", "oader" -> "PDF", "Loader" 77 | for i := 0; i < len(runes)-1; i++ { 78 | if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) { 79 | runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...) 80 | runes[i] = runes[i][:len(runes[i])-1] 81 | } 82 | } 83 | // construct []string from results 84 | for _, s := range runes { 85 | if len(s) > 0 { 86 | entries = append(entries, string(s)) 87 | } 88 | } 89 | return entries 90 | } 91 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/defaults.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | // ApplyDefaults if they are not already set. 4 | func ApplyDefaults(target interface{}, options ...Option) error { 5 | app, err := New(target, options...) 6 | if err != nil { 7 | return err 8 | } 9 | ctx, err := Trace(app, nil) 10 | if err != nil { 11 | return err 12 | } 13 | err = ctx.Resolve() 14 | if err != nil { 15 | return err 16 | } 17 | if err = ctx.ApplyDefaults(); err != nil { 18 | return err 19 | } 20 | return ctx.Validate() 21 | } 22 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/doc.go: -------------------------------------------------------------------------------- 1 | // Package kong aims to support arbitrarily complex command-line structures with as little developer effort as possible. 2 | // 3 | // Here's an example: 4 | // 5 | // shell rm [-f] [-r] ... 6 | // shell ls [ ...] 7 | // 8 | // This can be represented by the following command-line structure: 9 | // 10 | // package main 11 | // 12 | // import "github.com/alecthomas/kong" 13 | // 14 | // var CLI struct { 15 | // Rm struct { 16 | // Force bool `short:"f" help:"Force removal."` 17 | // Recursive bool `short:"r" help:"Recursively remove files."` 18 | // 19 | // Paths []string `arg help:"Paths to remove." type:"path"` 20 | // } `cmd help:"Remove files."` 21 | // 22 | // Ls struct { 23 | // Paths []string `arg optional help:"Paths to list." type:"path"` 24 | // } `cmd help:"List paths."` 25 | // } 26 | // 27 | // func main() { 28 | // kong.Parse(&CLI) 29 | // } 30 | // 31 | // See https://github.com/alecthomas/kong for details. 32 | package kong 33 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/error.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | // ParseError is the error type returned by Kong.Parse(). 4 | // 5 | // It contains the parse Context that triggered the error. 6 | type ParseError struct { 7 | error 8 | Context *Context 9 | } 10 | 11 | // Cause returns the original cause of the error. 12 | func (p *ParseError) Cause() error { return p.error } 13 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/global.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | // Parse constructs a new parser and parses the default command-line. 8 | func Parse(cli interface{}, options ...Option) *Context { 9 | parser, err := New(cli, options...) 10 | if err != nil { 11 | panic(err) 12 | } 13 | ctx, err := parser.Parse(os.Args[1:]) 14 | parser.FatalIfErrorf(err) 15 | return ctx 16 | } 17 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/alecthomas/kong 2 | 3 | require ( 4 | github.com/davecgh/go-spew v1.1.1 // indirect 5 | github.com/pkg/errors v0.9.1 6 | github.com/stretchr/testify v1.7.0 7 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 8 | ) 9 | 10 | go 1.13 11 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 5 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 8 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 9 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 10 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 14 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 15 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 16 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/guesswidth.go: -------------------------------------------------------------------------------- 1 | // +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd 2 | 3 | package kong 4 | 5 | import "io" 6 | 7 | func guessWidth(w io.Writer) int { 8 | return 80 9 | } 10 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/guesswidth_unix.go: -------------------------------------------------------------------------------- 1 | // +build !appengine,linux freebsd darwin dragonfly netbsd openbsd 2 | 3 | package kong 4 | 5 | import ( 6 | "io" 7 | "os" 8 | "strconv" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func guessWidth(w io.Writer) int { 14 | // check if COLUMNS env is set to comply with 15 | // http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html 16 | colsStr := os.Getenv("COLUMNS") 17 | if colsStr != "" { 18 | if cols, err := strconv.Atoi(colsStr); err == nil { 19 | return cols 20 | } 21 | } 22 | 23 | if t, ok := w.(*os.File); ok { 24 | fd := t.Fd() 25 | var dimensions [4]uint16 26 | 27 | if _, _, err := syscall.Syscall6( 28 | syscall.SYS_IOCTL, 29 | uintptr(fd), // nolint: unconvert 30 | uintptr(syscall.TIOCGWINSZ), 31 | uintptr(unsafe.Pointer(&dimensions)), // nolint: gas 32 | 0, 0, 0, 33 | ); err == 0 { 34 | if dimensions[1] == 0 { 35 | return 80 36 | } 37 | return int(dimensions[1]) 38 | } 39 | } 40 | return 80 41 | } 42 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/hooks.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | // BeforeResolve is a documentation-only interface describing hooks that run before resolvers are applied. 4 | type BeforeResolve interface { 5 | // This is not the correct signature - see README for details. 6 | BeforeResolve(args ...interface{}) error 7 | } 8 | 9 | // BeforeApply is a documentation-only interface describing hooks that run before values are set. 10 | type BeforeApply interface { 11 | // This is not the correct signature - see README for details. 12 | BeforeApply(args ...interface{}) error 13 | } 14 | 15 | // AfterApply is a documentation-only interface describing hooks that run after values are set. 16 | type AfterApply interface { 17 | // This is not the correct signature - see README for details. 18 | AfterApply(args ...interface{}) error 19 | } 20 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/interpolate.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | var interpolationRegex = regexp.MustCompile(`((?:\${([[:alpha:]_][[:word:]]*))(?:=([^}]+))?})|(\$)|([^$]+)`) 9 | 10 | // Interpolate variables from vars into s for substrings in the form ${var} or ${var=default}. 11 | func interpolate(s string, vars Vars, updatedVars map[string]string) (string, error) { 12 | out := "" 13 | matches := interpolationRegex.FindAllStringSubmatch(s, -1) 14 | if len(matches) == 0 { 15 | return s, nil 16 | } 17 | for key, val := range updatedVars { 18 | if vars[key] != val { 19 | vars = vars.CloneWith(updatedVars) 20 | break 21 | } 22 | } 23 | for _, match := range matches { 24 | if name := match[2]; name != "" { 25 | value, ok := vars[name] 26 | if !ok { 27 | // No default value. 28 | if match[3] == "" { 29 | return "", fmt.Errorf("undefined variable ${%s}", name) 30 | } 31 | value = match[3] 32 | } 33 | out += value 34 | } else { 35 | out += match[0] 36 | } 37 | } 38 | return out, nil 39 | } 40 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/kong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clipos/toolkit/4aac31211122a0260912e66b1a65f965aa43ad20/cosmk/vendor/github.com/alecthomas/kong/kong.png -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/kong.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clipos/toolkit/4aac31211122a0260912e66b1a65f965aa43ad20/cosmk/vendor/github.com/alecthomas/kong/kong.sketch -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/levenshtein.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import "unicode/utf8" 4 | 5 | // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Go 6 | // License: https://creativecommons.org/licenses/by-sa/3.0/ 7 | func levenshtein(a, b string) int { 8 | f := make([]int, utf8.RuneCountInString(b)+1) 9 | 10 | for j := range f { 11 | f[j] = j 12 | } 13 | 14 | for _, ca := range a { 15 | j := 1 16 | fj1 := f[0] // fj1 is the value of f[j - 1] in last iteration 17 | f[0]++ 18 | for _, cb := range b { 19 | mn := min(f[j]+1, f[j-1]+1) // delete & insert 20 | if cb != ca { 21 | mn = min(mn, fj1+1) // change 22 | } else { 23 | mn = min(mn, fj1) // matched 24 | } 25 | 26 | fj1, f[j] = f[j], mn // save f[j] to fj1(j is about to increase), update f[j] to mn 27 | j++ 28 | } 29 | } 30 | 31 | return f[len(f)-1] 32 | } 33 | 34 | func min(a, b int) int { 35 | if a <= b { 36 | return a 37 | } 38 | return b 39 | } 40 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/resolver.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "strings" 7 | ) 8 | 9 | // A Resolver resolves a Flag value from an external source. 10 | type Resolver interface { 11 | // Validate configuration against Application. 12 | // 13 | // This can be used to validate that all provided configuration is valid within this application. 14 | Validate(app *Application) error 15 | 16 | // Resolve the value for a Flag. 17 | Resolve(context *Context, parent *Path, flag *Flag) (interface{}, error) 18 | } 19 | 20 | // ResolverFunc is a convenience type for non-validating Resolvers. 21 | type ResolverFunc func(context *Context, parent *Path, flag *Flag) (interface{}, error) 22 | 23 | var _ Resolver = ResolverFunc(nil) 24 | 25 | func (r ResolverFunc) Resolve(context *Context, parent *Path, flag *Flag) (interface{}, error) { // nolint: golint 26 | return r(context, parent, flag) 27 | } 28 | func (r ResolverFunc) Validate(app *Application) error { return nil } // nolint: golint 29 | 30 | // JSON returns a Resolver that retrieves values from a JSON source. 31 | // 32 | // Hyphens in flag names are replaced with underscores. 33 | func JSON(r io.Reader) (Resolver, error) { 34 | values := map[string]interface{}{} 35 | err := json.NewDecoder(r).Decode(&values) 36 | if err != nil { 37 | return nil, err 38 | } 39 | var f ResolverFunc = func(context *Context, parent *Path, flag *Flag) (interface{}, error) { 40 | name := strings.Replace(flag.Name, "-", "_", -1) 41 | raw, ok := values[name] 42 | if !ok { 43 | return nil, nil 44 | } 45 | return raw, nil 46 | } 47 | 48 | return f, nil 49 | } 50 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/scanner.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // TokenType is the type of a token. 9 | type TokenType int 10 | 11 | // Token types. 12 | const ( 13 | UntypedToken TokenType = iota 14 | EOLToken 15 | FlagToken // -- 16 | FlagValueToken // = 17 | ShortFlagToken // -[ 19 | PositionalArgumentToken // 20 | ) 21 | 22 | func (t TokenType) String() string { 23 | switch t { 24 | case UntypedToken: 25 | return "untyped" 26 | case EOLToken: 27 | return "" 28 | case FlagToken: // -- 29 | return "long flag" 30 | case FlagValueToken: // = 31 | return "flag value" 32 | case ShortFlagToken: // -[ 35 | return "short flag remainder" 36 | case PositionalArgumentToken: // 37 | return "positional argument" 38 | } 39 | panic("unsupported type") 40 | } 41 | 42 | // Token created by Scanner. 43 | type Token struct { 44 | Value interface{} 45 | Type TokenType 46 | } 47 | 48 | func (t Token) String() string { 49 | switch t.Type { 50 | case FlagToken: 51 | return fmt.Sprintf("--%v", t.Value) 52 | 53 | case ShortFlagToken: 54 | return fmt.Sprintf("-%v", t.Value) 55 | 56 | case EOLToken: 57 | return "EOL" 58 | 59 | default: 60 | return fmt.Sprintf("%v", t.Value) 61 | } 62 | } 63 | 64 | // IsEOL returns true if this Token is past the end of the line. 65 | func (t Token) IsEOL() bool { 66 | return t.Type == EOLToken 67 | } 68 | 69 | // IsAny returns true if the token's type is any of those provided. 70 | func (t TokenType) IsAny(types ...TokenType) bool { 71 | for _, typ := range types { 72 | if t == typ { 73 | return true 74 | } 75 | } 76 | return false 77 | } 78 | 79 | // InferredType tries to infer the type of a token. 80 | func (t Token) InferredType() TokenType { 81 | if t.Type != UntypedToken { 82 | return t.Type 83 | } 84 | if v, ok := t.Value.(string); ok { 85 | if strings.HasPrefix(v, "--") { // nolint: gocritic 86 | return FlagToken 87 | } else if v == "-" { 88 | return PositionalArgumentToken 89 | } else if strings.HasPrefix(v, "-") { 90 | return ShortFlagToken 91 | } 92 | } 93 | return t.Type 94 | } 95 | 96 | // IsValue returns true if token is usable as a parseable value. 97 | // 98 | // A parseable value is either a value typed token, or an untyped token NOT starting with a hyphen. 99 | func (t Token) IsValue() bool { 100 | tt := t.InferredType() 101 | return tt.IsAny(FlagValueToken, ShortFlagTailToken, PositionalArgumentToken) || 102 | (tt == UntypedToken && !strings.HasPrefix(t.String(), "-")) 103 | } 104 | 105 | // Scanner is a stack-based scanner over command-line tokens. 106 | // 107 | // Initially all tokens are untyped. As the parser consumes tokens it assigns types, splits tokens, and pushes them back 108 | // onto the stream. 109 | // 110 | // For example, the token "--foo=bar" will be split into the following by the parser: 111 | // 112 | // [{FlagToken, "foo"}, {FlagValueToken, "bar"}] 113 | type Scanner struct { 114 | args []Token 115 | } 116 | 117 | // Scan creates a new Scanner from args with untyped tokens. 118 | func Scan(args ...string) *Scanner { 119 | s := &Scanner{} 120 | for _, arg := range args { 121 | s.args = append(s.args, Token{Value: arg}) 122 | } 123 | return s 124 | } 125 | 126 | // ScanFromTokens creates a new Scanner from a slice of tokens. 127 | func ScanFromTokens(tokens ...Token) *Scanner { 128 | return &Scanner{args: tokens} 129 | } 130 | 131 | // Len returns the number of input arguments. 132 | func (s *Scanner) Len() int { 133 | return len(s.args) 134 | } 135 | 136 | // Pop the front token off the Scanner. 137 | func (s *Scanner) Pop() Token { 138 | if len(s.args) == 0 { 139 | return Token{Type: EOLToken} 140 | } 141 | arg := s.args[0] 142 | s.args = s.args[1:] 143 | return arg 144 | } 145 | 146 | type expectedError struct { 147 | context string 148 | token Token 149 | } 150 | 151 | func (e *expectedError) Error() string { 152 | return fmt.Sprintf("expected %s value but got %q (%s)", e.context, e.token, e.token.InferredType()) 153 | } 154 | 155 | // PopValue pops a value token, or returns an error. 156 | // 157 | // "context" is used to assist the user if the value can not be popped, eg. "expected value but got " 158 | func (s *Scanner) PopValue(context string) (Token, error) { 159 | t := s.Pop() 160 | if !t.IsValue() { 161 | return t, &expectedError{context, t} 162 | } 163 | return t, nil 164 | } 165 | 166 | // PopValueInto pops a value token into target or returns an error. 167 | // 168 | // "context" is used to assist the user if the value can not be popped, eg. "expected value but got " 169 | func (s *Scanner) PopValueInto(context string, target interface{}) error { 170 | t, err := s.PopValue(context) 171 | if err != nil { 172 | return err 173 | } 174 | return jsonTranscode(t.Value, target) 175 | } 176 | 177 | // PopWhile predicate returns true. 178 | func (s *Scanner) PopWhile(predicate func(Token) bool) (values []Token) { 179 | for predicate(s.Peek()) { 180 | values = append(values, s.Pop()) 181 | } 182 | return 183 | } 184 | 185 | // PopUntil predicate returns true. 186 | func (s *Scanner) PopUntil(predicate func(Token) bool) (values []Token) { 187 | for !predicate(s.Peek()) { 188 | values = append(values, s.Pop()) 189 | } 190 | return 191 | } 192 | 193 | // Peek at the next Token or return an EOLToken. 194 | func (s *Scanner) Peek() Token { 195 | if len(s.args) == 0 { 196 | return Token{Type: EOLToken} 197 | } 198 | return s.args[0] 199 | } 200 | 201 | // Push an untyped Token onto the front of the Scanner. 202 | func (s *Scanner) Push(arg interface{}) *Scanner { 203 | s.PushToken(Token{Value: arg}) 204 | return s 205 | } 206 | 207 | // PushTyped pushes a typed token onto the front of the Scanner. 208 | func (s *Scanner) PushTyped(arg interface{}, typ TokenType) *Scanner { 209 | s.PushToken(Token{Value: arg, Type: typ}) 210 | return s 211 | } 212 | 213 | // PushToken pushes a preconstructed Token onto the front of the Scanner. 214 | func (s *Scanner) PushToken(token Token) *Scanner { 215 | s.args = append([]Token{token}, s.args...) 216 | return s 217 | } 218 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/tag.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strconv" 7 | "strings" 8 | "unicode/utf8" 9 | ) 10 | 11 | // Tag represents the parsed state of Kong tags in a struct field tag. 12 | type Tag struct { 13 | Ignored bool // Field is ignored by Kong. ie. kong:"-" 14 | Cmd bool 15 | Arg bool 16 | Required bool 17 | Optional bool 18 | Name string 19 | Help string 20 | Type string 21 | Default string 22 | Format string 23 | PlaceHolder string 24 | Env string 25 | Short rune 26 | Hidden bool 27 | Sep rune 28 | MapSep rune 29 | Enum string 30 | Group string 31 | Xor string 32 | Vars Vars 33 | Prefix string // Optional prefix on anonymous structs. All sub-flags will have this prefix. 34 | Embed bool 35 | Aliases []string 36 | Negatable bool 37 | Passthrough bool 38 | 39 | // Storage for all tag keys for arbitrary lookups. 40 | items map[string][]string 41 | } 42 | 43 | type tagChars struct { 44 | sep, quote, assign rune 45 | } 46 | 47 | var kongChars = tagChars{sep: ',', quote: '\'', assign: '='} 48 | var bareChars = tagChars{sep: ' ', quote: '"', assign: ':'} 49 | 50 | func parseTagItems(tagString string, chr tagChars) map[string][]string { 51 | d := map[string][]string{} 52 | key := []rune{} 53 | value := []rune{} 54 | quotes := false 55 | inKey := true 56 | 57 | add := func() { 58 | d[string(key)] = append(d[string(key)], string(value)) 59 | key = []rune{} 60 | value = []rune{} 61 | inKey = true 62 | } 63 | 64 | runes := []rune(tagString) 65 | for idx := 0; idx < len(runes); idx++ { 66 | r := runes[idx] 67 | next := rune(0) 68 | eof := false 69 | if idx < len(runes)-1 { 70 | next = runes[idx+1] 71 | } else { 72 | eof = true 73 | } 74 | if !quotes && r == chr.sep { 75 | add() 76 | continue 77 | } 78 | if r == chr.assign && inKey { 79 | inKey = false 80 | continue 81 | } 82 | if r == '\\' { 83 | if next == chr.quote { 84 | idx++ 85 | r = chr.quote 86 | } 87 | } else if r == chr.quote { 88 | if quotes { 89 | quotes = false 90 | if next == chr.sep || eof { 91 | continue 92 | } 93 | fail("%v has an unexpected char at pos %v", tagString, idx) 94 | } else { 95 | quotes = true 96 | continue 97 | } 98 | } 99 | if inKey { 100 | key = append(key, r) 101 | } else { 102 | value = append(value, r) 103 | } 104 | } 105 | if quotes { 106 | fail("%v is not quoted properly", tagString) 107 | } 108 | 109 | add() 110 | 111 | return d 112 | } 113 | 114 | func getTagInfo(ft reflect.StructField) (string, tagChars) { 115 | s, ok := ft.Tag.Lookup("kong") 116 | if ok { 117 | return s, kongChars 118 | } 119 | 120 | return string(ft.Tag), bareChars 121 | } 122 | 123 | func newEmptyTag() *Tag { 124 | return &Tag{items: map[string][]string{}} 125 | } 126 | 127 | func parseTag(fv reflect.Value, ft reflect.StructField) *Tag { 128 | if ft.Tag.Get("kong") == "-" { 129 | t := newEmptyTag() 130 | t.Ignored = true 131 | return t 132 | } 133 | t := &Tag{ 134 | items: parseTagItems(getTagInfo(ft)), 135 | } 136 | t.Cmd = t.Has("cmd") 137 | t.Arg = t.Has("arg") 138 | required := t.Has("required") 139 | optional := t.Has("optional") 140 | if required && optional { 141 | fail("can't specify both required and optional") 142 | } 143 | t.Required = required 144 | t.Optional = optional 145 | t.Default = t.Get("default") 146 | // Arguments with defaults are always optional. 147 | if t.Arg && t.Default != "" { 148 | t.Optional = true 149 | } 150 | t.Name = t.Get("name") 151 | t.Help = t.Get("help") 152 | t.Type = t.Get("type") 153 | t.Env = t.Get("env") 154 | t.Short, _ = t.GetRune("short") 155 | t.Hidden = t.Has("hidden") 156 | t.Format = t.Get("format") 157 | t.Sep, _ = t.GetSep("sep", ',') 158 | t.MapSep, _ = t.GetSep("mapsep", ';') 159 | t.Group = t.Get("group") 160 | t.Xor = t.Get("xor") 161 | t.Prefix = t.Get("prefix") 162 | t.Embed = t.Has("embed") 163 | negatable := t.Has("negatable") 164 | if negatable && ft.Type.Kind() != reflect.Bool { 165 | fail("negatable can only be set on booleans") 166 | } 167 | t.Negatable = negatable 168 | splitFn := func(r rune) bool { 169 | return r == ',' || r == ' ' 170 | } 171 | aliases := t.Get("aliases") 172 | if len(aliases) > 0 { 173 | t.Aliases = append(t.Aliases, strings.FieldsFunc(aliases, splitFn)...) 174 | } 175 | t.Vars = Vars{} 176 | for _, set := range t.GetAll("set") { 177 | parts := strings.SplitN(set, "=", 2) 178 | if len(parts) == 0 { 179 | fail("set should be in the form key=value but got %q", set) 180 | } 181 | t.Vars[parts[0]] = parts[1] 182 | } 183 | t.PlaceHolder = t.Get("placeholder") 184 | if t.PlaceHolder == "" { 185 | t.PlaceHolder = strings.ToUpper(dashedString(fv.Type().Name())) 186 | } 187 | t.Enum = t.Get("enum") 188 | passthrough := t.Has("passthrough") 189 | if passthrough && !t.Arg { 190 | fail("passthrough only makes sense for positional arguments") 191 | } 192 | t.Passthrough = passthrough 193 | return t 194 | } 195 | 196 | // Has returns true if the tag contained the given key. 197 | func (t *Tag) Has(k string) bool { 198 | _, ok := t.items[k] 199 | return ok 200 | } 201 | 202 | // Get returns the value of the given tag. 203 | // 204 | // Note that this will return the empty string if the tag is missing. 205 | func (t *Tag) Get(k string) string { 206 | values := t.items[k] 207 | if len(values) == 0 { 208 | return "" 209 | } 210 | return values[0] 211 | } 212 | 213 | // GetAll returns all encountered values for a tag, in the case of multiple occurrences. 214 | func (t *Tag) GetAll(k string) []string { 215 | return t.items[k] 216 | } 217 | 218 | // GetBool returns true if the given tag looks like a boolean truth string. 219 | func (t *Tag) GetBool(k string) (bool, error) { 220 | return strconv.ParseBool(t.Get(k)) 221 | } 222 | 223 | // GetFloat parses the given tag as a float64. 224 | func (t *Tag) GetFloat(k string) (float64, error) { 225 | return strconv.ParseFloat(t.Get(k), 64) 226 | } 227 | 228 | // GetInt parses the given tag as an int64. 229 | func (t *Tag) GetInt(k string) (int64, error) { 230 | return strconv.ParseInt(t.Get(k), 10, 64) 231 | } 232 | 233 | // GetRune parses the given tag as a rune. 234 | func (t *Tag) GetRune(k string) (rune, error) { 235 | r, _ := utf8.DecodeRuneInString(t.Get(k)) 236 | if r == utf8.RuneError { 237 | return 0, fmt.Errorf("%v has a rune error", t.Get(k)) 238 | } 239 | return r, nil 240 | } 241 | 242 | // GetSep parses the given tag as a rune separator, allowing for a default or none. 243 | // The separator is returned, or -1 if "none" is specified. If the tag value is an 244 | // invalid utf8 sequence, the default rune is returned as well as an error. If the 245 | // tag value is more than one rune, the first rune is returned as well as an error. 246 | func (t *Tag) GetSep(k string, dflt rune) (rune, error) { 247 | tv := t.Get(k) 248 | if tv == "none" { 249 | return -1, nil 250 | } else if tv == "" { 251 | return dflt, nil 252 | } 253 | r, size := utf8.DecodeRuneInString(tv) 254 | if r == utf8.RuneError { 255 | return dflt, fmt.Errorf(`%v:"%v" has a rune error`, k, tv) 256 | } else if size != len(tv) { 257 | return r, fmt.Errorf(`%v:"%v" is more than a single rune`, k, tv) 258 | } 259 | return r, nil 260 | } 261 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/util.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // ConfigFlag uses the configured (via kong.Configuration(loader)) configuration loader to load configuration 8 | // from a file specified by a flag. 9 | // 10 | // Use this as a flag value to support loading of custom configuration via a flag. 11 | type ConfigFlag string 12 | 13 | // BeforeResolve adds a resolver. 14 | func (c ConfigFlag) BeforeResolve(kong *Kong, ctx *Context, trace *Path) error { 15 | if kong.loader == nil { 16 | return fmt.Errorf("kong must be configured with kong.Configuration(...)") 17 | } 18 | path := string(ctx.FlagValue(trace.Flag).(ConfigFlag)) 19 | resolver, err := kong.LoadConfig(path) 20 | if err != nil { 21 | return err 22 | } 23 | ctx.AddResolver(resolver) 24 | return nil 25 | } 26 | 27 | // VersionFlag is a flag type that can be used to display a version number, stored in the "version" variable. 28 | type VersionFlag bool 29 | 30 | // BeforeApply writes the version variable and terminates with a 0 exit status. 31 | func (v VersionFlag) BeforeApply(app *Kong, vars Vars) error { 32 | fmt.Fprintln(app.Stdout, vars["version"]) 33 | app.Exit(0) 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/alecthomas/kong/visit.go: -------------------------------------------------------------------------------- 1 | package kong 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Next should be called by Visitor to proceed with the walk. 8 | // 9 | // The walk will terminate if "err" is non-nil. 10 | type Next func(err error) error 11 | 12 | // Visitor can be used to walk all nodes in the model. 13 | type Visitor func(node Visitable, next Next) error 14 | 15 | // Visit all nodes. 16 | func Visit(node Visitable, visitor Visitor) error { 17 | return visitor(node, func(err error) error { 18 | if err != nil { 19 | return err 20 | } 21 | switch node := node.(type) { 22 | case *Application: 23 | return visitNodeChildren(node.Node, visitor) 24 | case *Node: 25 | return visitNodeChildren(node, visitor) 26 | case *Value: 27 | case *Flag: 28 | return Visit(node.Value, visitor) 29 | default: 30 | panic(fmt.Sprintf("unsupported node type %T", node)) 31 | } 32 | return nil 33 | }) 34 | } 35 | 36 | func visitNodeChildren(node *Node, visitor Visitor) error { 37 | if node.Argument != nil { 38 | if err := Visit(node.Argument, visitor); err != nil { 39 | return err 40 | } 41 | } 42 | for _, flag := range node.Flags { 43 | if err := Visit(flag, visitor); err != nil { 44 | return err 45 | } 46 | } 47 | for _, pos := range node.Positional { 48 | if err := Visit(pos, visitor); err != nil { 49 | return err 50 | } 51 | } 52 | for _, child := range node.Children { 53 | if err := Visit(child, visitor); err != nil { 54 | return err 55 | } 56 | } 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/errwrap/README.md: -------------------------------------------------------------------------------- 1 | # errwrap 2 | 3 | `errwrap` is a package for Go that formalizes the pattern of wrapping errors 4 | and checking if an error contains another error. 5 | 6 | There is a common pattern in Go of taking a returned `error` value and 7 | then wrapping it (such as with `fmt.Errorf`) before returning it. The problem 8 | with this pattern is that you completely lose the original `error` structure. 9 | 10 | Arguably the _correct_ approach is that you should make a custom structure 11 | implementing the `error` interface, and have the original error as a field 12 | on that structure, such [as this example](http://golang.org/pkg/os/#PathError). 13 | This is a good approach, but you have to know the entire chain of possible 14 | rewrapping that happens, when you might just care about one. 15 | 16 | `errwrap` formalizes this pattern (it doesn't matter what approach you use 17 | above) by giving a single interface for wrapping errors, checking if a specific 18 | error is wrapped, and extracting that error. 19 | 20 | ## Installation and Docs 21 | 22 | Install using `go get github.com/hashicorp/errwrap`. 23 | 24 | Full documentation is available at 25 | http://godoc.org/github.com/hashicorp/errwrap 26 | 27 | ## Usage 28 | 29 | #### Basic Usage 30 | 31 | Below is a very basic example of its usage: 32 | 33 | ```go 34 | // A function that always returns an error, but wraps it, like a real 35 | // function might. 36 | func tryOpen() error { 37 | _, err := os.Open("/i/dont/exist") 38 | if err != nil { 39 | return errwrap.Wrapf("Doesn't exist: {{err}}", err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func main() { 46 | err := tryOpen() 47 | 48 | // We can use the Contains helpers to check if an error contains 49 | // another error. It is safe to do this with a nil error, or with 50 | // an error that doesn't even use the errwrap package. 51 | if errwrap.Contains(err, "does not exist") { 52 | // Do something 53 | } 54 | if errwrap.ContainsType(err, new(os.PathError)) { 55 | // Do something 56 | } 57 | 58 | // Or we can use the associated `Get` functions to just extract 59 | // a specific error. This would return nil if that specific error doesn't 60 | // exist. 61 | perr := errwrap.GetType(err, new(os.PathError)) 62 | } 63 | ``` 64 | 65 | #### Custom Types 66 | 67 | If you're already making custom types that properly wrap errors, then 68 | you can get all the functionality of `errwraps.Contains` and such by 69 | implementing the `Wrapper` interface with just one function. Example: 70 | 71 | ```go 72 | type AppError { 73 | Code ErrorCode 74 | Err error 75 | } 76 | 77 | func (e *AppError) WrappedErrors() []error { 78 | return []error{e.Err} 79 | } 80 | ``` 81 | 82 | Now this works: 83 | 84 | ```go 85 | err := &AppError{Err: fmt.Errorf("an error")} 86 | if errwrap.ContainsType(err, fmt.Errorf("")) { 87 | // This will work! 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/errwrap/errwrap.go: -------------------------------------------------------------------------------- 1 | // Package errwrap implements methods to formalize error wrapping in Go. 2 | // 3 | // All of the top-level functions that take an `error` are built to be able 4 | // to take any error, not just wrapped errors. This allows you to use errwrap 5 | // without having to type-check and type-cast everywhere. 6 | package errwrap 7 | 8 | import ( 9 | "errors" 10 | "reflect" 11 | "strings" 12 | ) 13 | 14 | // WalkFunc is the callback called for Walk. 15 | type WalkFunc func(error) 16 | 17 | // Wrapper is an interface that can be implemented by custom types to 18 | // have all the Contains, Get, etc. functions in errwrap work. 19 | // 20 | // When Walk reaches a Wrapper, it will call the callback for every 21 | // wrapped error in addition to the wrapper itself. Since all the top-level 22 | // functions in errwrap use Walk, this means that all those functions work 23 | // with your custom type. 24 | type Wrapper interface { 25 | WrappedErrors() []error 26 | } 27 | 28 | // Wrap defines that outer wraps inner, returning an error type that 29 | // can be cleanly used with the other methods in this package, such as 30 | // Contains, GetAll, etc. 31 | // 32 | // This function won't modify the error message at all (the outer message 33 | // will be used). 34 | func Wrap(outer, inner error) error { 35 | return &wrappedError{ 36 | Outer: outer, 37 | Inner: inner, 38 | } 39 | } 40 | 41 | // Wrapf wraps an error with a formatting message. This is similar to using 42 | // `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap 43 | // errors, you should replace it with this. 44 | // 45 | // format is the format of the error message. The string '{{err}}' will 46 | // be replaced with the original error message. 47 | func Wrapf(format string, err error) error { 48 | outerMsg := "" 49 | if err != nil { 50 | outerMsg = err.Error() 51 | } 52 | 53 | outer := errors.New(strings.Replace( 54 | format, "{{err}}", outerMsg, -1)) 55 | 56 | return Wrap(outer, err) 57 | } 58 | 59 | // Contains checks if the given error contains an error with the 60 | // message msg. If err is not a wrapped error, this will always return 61 | // false unless the error itself happens to match this msg. 62 | func Contains(err error, msg string) bool { 63 | return len(GetAll(err, msg)) > 0 64 | } 65 | 66 | // ContainsType checks if the given error contains an error with 67 | // the same concrete type as v. If err is not a wrapped error, this will 68 | // check the err itself. 69 | func ContainsType(err error, v interface{}) bool { 70 | return len(GetAllType(err, v)) > 0 71 | } 72 | 73 | // Get is the same as GetAll but returns the deepest matching error. 74 | func Get(err error, msg string) error { 75 | es := GetAll(err, msg) 76 | if len(es) > 0 { 77 | return es[len(es)-1] 78 | } 79 | 80 | return nil 81 | } 82 | 83 | // GetType is the same as GetAllType but returns the deepest matching error. 84 | func GetType(err error, v interface{}) error { 85 | es := GetAllType(err, v) 86 | if len(es) > 0 { 87 | return es[len(es)-1] 88 | } 89 | 90 | return nil 91 | } 92 | 93 | // GetAll gets all the errors that might be wrapped in err with the 94 | // given message. The order of the errors is such that the outermost 95 | // matching error (the most recent wrap) is index zero, and so on. 96 | func GetAll(err error, msg string) []error { 97 | var result []error 98 | 99 | Walk(err, func(err error) { 100 | if err.Error() == msg { 101 | result = append(result, err) 102 | } 103 | }) 104 | 105 | return result 106 | } 107 | 108 | // GetAllType gets all the errors that are the same type as v. 109 | // 110 | // The order of the return value is the same as described in GetAll. 111 | func GetAllType(err error, v interface{}) []error { 112 | var result []error 113 | 114 | var search string 115 | if v != nil { 116 | search = reflect.TypeOf(v).String() 117 | } 118 | Walk(err, func(err error) { 119 | var needle string 120 | if err != nil { 121 | needle = reflect.TypeOf(err).String() 122 | } 123 | 124 | if needle == search { 125 | result = append(result, err) 126 | } 127 | }) 128 | 129 | return result 130 | } 131 | 132 | // Walk walks all the wrapped errors in err and calls the callback. If 133 | // err isn't a wrapped error, this will be called once for err. If err 134 | // is a wrapped error, the callback will be called for both the wrapper 135 | // that implements error as well as the wrapped error itself. 136 | func Walk(err error, cb WalkFunc) { 137 | if err == nil { 138 | return 139 | } 140 | 141 | switch e := err.(type) { 142 | case *wrappedError: 143 | cb(e.Outer) 144 | Walk(e.Inner, cb) 145 | case Wrapper: 146 | cb(err) 147 | 148 | for _, err := range e.WrappedErrors() { 149 | Walk(err, cb) 150 | } 151 | default: 152 | cb(err) 153 | } 154 | } 155 | 156 | // wrappedError is an implementation of error that has both the 157 | // outer and inner errors. 158 | type wrappedError struct { 159 | Outer error 160 | Inner error 161 | } 162 | 163 | func (w *wrappedError) Error() string { 164 | return w.Outer.Error() 165 | } 166 | 167 | func (w *wrappedError) WrappedErrors() []error { 168 | return []error{w.Outer, w.Inner} 169 | } 170 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/errwrap/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hashicorp/errwrap 2 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - 1.x 7 | 8 | branches: 9 | only: 10 | - master 11 | 12 | script: make test testrace 13 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/Makefile: -------------------------------------------------------------------------------- 1 | TEST?=./... 2 | 3 | default: test 4 | 5 | # test runs the test suite and vets the code. 6 | test: generate 7 | @echo "==> Running tests..." 8 | @go list $(TEST) \ 9 | | grep -v "/vendor/" \ 10 | | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS} 11 | 12 | # testrace runs the race checker 13 | testrace: generate 14 | @echo "==> Running tests (race)..." 15 | @go list $(TEST) \ 16 | | grep -v "/vendor/" \ 17 | | xargs -n1 go test -timeout=60s -race ${TESTARGS} 18 | 19 | # updatedeps installs all the dependencies needed to run and build. 20 | updatedeps: 21 | @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'" 22 | 23 | # generate runs `go generate` to build the dynamically generated source files. 24 | generate: 25 | @echo "==> Generating..." 26 | @find . -type f -name '.DS_Store' -delete 27 | @go list ./... \ 28 | | grep -v "/vendor/" \ 29 | | xargs -n1 go generate 30 | 31 | .PHONY: default test testrace updatedeps generate 32 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/README.md: -------------------------------------------------------------------------------- 1 | # go-multierror 2 | 3 | [![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis] 4 | [![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] 5 | 6 | [travis]: https://travis-ci.org/hashicorp/go-multierror 7 | [godocs]: https://godoc.org/github.com/hashicorp/go-multierror 8 | 9 | `go-multierror` is a package for Go that provides a mechanism for 10 | representing a list of `error` values as a single `error`. 11 | 12 | This allows a function in Go to return an `error` that might actually 13 | be a list of errors. If the caller knows this, they can unwrap the 14 | list and access the errors. If the caller doesn't know, the error 15 | formats to a nice human-readable format. 16 | 17 | `go-multierror` implements the 18 | [errwrap](https://github.com/hashicorp/errwrap) interface so that it can 19 | be used with that library, as well. 20 | 21 | ## Installation and Docs 22 | 23 | Install using `go get github.com/hashicorp/go-multierror`. 24 | 25 | Full documentation is available at 26 | http://godoc.org/github.com/hashicorp/go-multierror 27 | 28 | ## Usage 29 | 30 | go-multierror is easy to use and purposely built to be unobtrusive in 31 | existing Go applications/libraries that may not be aware of it. 32 | 33 | **Building a list of errors** 34 | 35 | The `Append` function is used to create a list of errors. This function 36 | behaves a lot like the Go built-in `append` function: it doesn't matter 37 | if the first argument is nil, a `multierror.Error`, or any other `error`, 38 | the function behaves as you would expect. 39 | 40 | ```go 41 | var result error 42 | 43 | if err := step1(); err != nil { 44 | result = multierror.Append(result, err) 45 | } 46 | if err := step2(); err != nil { 47 | result = multierror.Append(result, err) 48 | } 49 | 50 | return result 51 | ``` 52 | 53 | **Customizing the formatting of the errors** 54 | 55 | By specifying a custom `ErrorFormat`, you can customize the format 56 | of the `Error() string` function: 57 | 58 | ```go 59 | var result *multierror.Error 60 | 61 | // ... accumulate errors here, maybe using Append 62 | 63 | if result != nil { 64 | result.ErrorFormat = func([]error) string { 65 | return "errors!" 66 | } 67 | } 68 | ``` 69 | 70 | **Accessing the list of errors** 71 | 72 | `multierror.Error` implements `error` so if the caller doesn't know about 73 | multierror, it will work just fine. But if you're aware a multierror might 74 | be returned, you can use type switches to access the list of errors: 75 | 76 | ```go 77 | if err := something(); err != nil { 78 | if merr, ok := err.(*multierror.Error); ok { 79 | // Use merr.Errors 80 | } 81 | } 82 | ``` 83 | 84 | **Returning a multierror only if there are errors** 85 | 86 | If you build a `multierror.Error`, you can use the `ErrorOrNil` function 87 | to return an `error` implementation only if there are errors to return: 88 | 89 | ```go 90 | var result *multierror.Error 91 | 92 | // ... accumulate errors here 93 | 94 | // Return the `error` only if errors were added to the multierror, otherwise 95 | // return nil since there are no errors. 96 | return result.ErrorOrNil() 97 | ``` 98 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/append.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | // Append is a helper function that will append more errors 4 | // onto an Error in order to create a larger multi-error. 5 | // 6 | // If err is not a multierror.Error, then it will be turned into 7 | // one. If any of the errs are multierr.Error, they will be flattened 8 | // one level into err. 9 | func Append(err error, errs ...error) *Error { 10 | switch err := err.(type) { 11 | case *Error: 12 | // Typed nils can reach here, so initialize if we are nil 13 | if err == nil { 14 | err = new(Error) 15 | } 16 | 17 | // Go through each error and flatten 18 | for _, e := range errs { 19 | switch e := e.(type) { 20 | case *Error: 21 | if e != nil { 22 | err.Errors = append(err.Errors, e.Errors...) 23 | } 24 | default: 25 | if e != nil { 26 | err.Errors = append(err.Errors, e) 27 | } 28 | } 29 | } 30 | 31 | return err 32 | default: 33 | newErrs := make([]error, 0, len(errs)+1) 34 | if err != nil { 35 | newErrs = append(newErrs, err) 36 | } 37 | newErrs = append(newErrs, errs...) 38 | 39 | return Append(&Error{}, newErrs...) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/flatten.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | // Flatten flattens the given error, merging any *Errors together into 4 | // a single *Error. 5 | func Flatten(err error) error { 6 | // If it isn't an *Error, just return the error as-is 7 | if _, ok := err.(*Error); !ok { 8 | return err 9 | } 10 | 11 | // Otherwise, make the result and flatten away! 12 | flatErr := new(Error) 13 | flatten(err, flatErr) 14 | return flatErr 15 | } 16 | 17 | func flatten(err error, flatErr *Error) { 18 | switch err := err.(type) { 19 | case *Error: 20 | for _, e := range err.Errors { 21 | flatten(e, flatErr) 22 | } 23 | default: 24 | flatErr.Errors = append(flatErr.Errors, err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/format.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // ErrorFormatFunc is a function callback that is called by Error to 9 | // turn the list of errors into a string. 10 | type ErrorFormatFunc func([]error) string 11 | 12 | // ListFormatFunc is a basic formatter that outputs the number of errors 13 | // that occurred along with a bullet point list of the errors. 14 | func ListFormatFunc(es []error) string { 15 | if len(es) == 1 { 16 | return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0]) 17 | } 18 | 19 | points := make([]string, len(es)) 20 | for i, err := range es { 21 | points[i] = fmt.Sprintf("* %s", err) 22 | } 23 | 24 | return fmt.Sprintf( 25 | "%d errors occurred:\n\t%s\n\n", 26 | len(es), strings.Join(points, "\n\t")) 27 | } 28 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hashicorp/go-multierror 2 | 3 | require github.com/hashicorp/errwrap v1.0.0 4 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/go.sum: -------------------------------------------------------------------------------- 1 | github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= 2 | github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 3 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 4 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 5 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/multierror.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Error is an error type to track multiple errors. This is used to 8 | // accumulate errors in cases and return them as a single "error". 9 | type Error struct { 10 | Errors []error 11 | ErrorFormat ErrorFormatFunc 12 | } 13 | 14 | func (e *Error) Error() string { 15 | fn := e.ErrorFormat 16 | if fn == nil { 17 | fn = ListFormatFunc 18 | } 19 | 20 | return fn(e.Errors) 21 | } 22 | 23 | // ErrorOrNil returns an error interface if this Error represents 24 | // a list of errors, or returns nil if the list of errors is empty. This 25 | // function is useful at the end of accumulation to make sure that the value 26 | // returned represents the existence of errors. 27 | func (e *Error) ErrorOrNil() error { 28 | if e == nil { 29 | return nil 30 | } 31 | if len(e.Errors) == 0 { 32 | return nil 33 | } 34 | 35 | return e 36 | } 37 | 38 | func (e *Error) GoString() string { 39 | return fmt.Sprintf("*%#v", *e) 40 | } 41 | 42 | // WrappedErrors returns the list of errors that this Error is wrapping. 43 | // It is an implementation of the errwrap.Wrapper interface so that 44 | // multierror.Error can be used with that library. 45 | // 46 | // This method is not safe to be called concurrently and is no different 47 | // than accessing the Errors field directly. It is implemented only to 48 | // satisfy the errwrap.Wrapper interface. 49 | func (e *Error) WrappedErrors() []error { 50 | return e.Errors 51 | } 52 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/prefix.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/errwrap" 7 | ) 8 | 9 | // Prefix is a helper function that will prefix some text 10 | // to the given error. If the error is a multierror.Error, then 11 | // it will be prefixed to each wrapped error. 12 | // 13 | // This is useful to use when appending multiple multierrors 14 | // together in order to give better scoping. 15 | func Prefix(err error, prefix string) error { 16 | if err == nil { 17 | return nil 18 | } 19 | 20 | format := fmt.Sprintf("%s {{err}}", prefix) 21 | switch err := err.(type) { 22 | case *Error: 23 | // Typed nils can reach here, so initialize if we are nil 24 | if err == nil { 25 | err = new(Error) 26 | } 27 | 28 | // Wrap each of the errors 29 | for i, e := range err.Errors { 30 | err.Errors[i] = errwrap.Wrapf(format, e) 31 | } 32 | 33 | return err 34 | default: 35 | return errwrap.Wrapf(format, err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/hashicorp/go-multierror/sort.go: -------------------------------------------------------------------------------- 1 | package multierror 2 | 3 | // Len implements sort.Interface function for length 4 | func (err Error) Len() int { 5 | return len(err.Errors) 6 | } 7 | 8 | // Swap implements sort.Interface function for swapping elements 9 | func (err Error) Swap(i, j int) { 10 | err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i] 11 | } 12 | 13 | // Less implements sort.Interface function for determining order 14 | func (err Error) Less(i, j int) bool { 15 | return err.Errors[i].Error() < err.Errors[j].Error() 16 | } 17 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go_import_path: github.com/pkg/errors 3 | go: 4 | - 1.11.x 5 | - 1.12.x 6 | - 1.13.x 7 | - tip 8 | 9 | script: 10 | - make check 11 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/Makefile: -------------------------------------------------------------------------------- 1 | PKGS := github.com/pkg/errors 2 | SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS)) 3 | GO := go 4 | 5 | check: test vet gofmt misspell unconvert staticcheck ineffassign unparam 6 | 7 | test: 8 | $(GO) test $(PKGS) 9 | 10 | vet: | test 11 | $(GO) vet $(PKGS) 12 | 13 | staticcheck: 14 | $(GO) get honnef.co/go/tools/cmd/staticcheck 15 | staticcheck -checks all $(PKGS) 16 | 17 | misspell: 18 | $(GO) get github.com/client9/misspell/cmd/misspell 19 | misspell \ 20 | -locale GB \ 21 | -error \ 22 | *.md *.go 23 | 24 | unconvert: 25 | $(GO) get github.com/mdempsky/unconvert 26 | unconvert -v $(PKGS) 27 | 28 | ineffassign: 29 | $(GO) get github.com/gordonklaus/ineffassign 30 | find $(SRCDIRS) -name '*.go' | xargs ineffassign 31 | 32 | pedantic: check errcheck 33 | 34 | unparam: 35 | $(GO) get mvdan.cc/unparam 36 | unparam ./... 37 | 38 | errcheck: 39 | $(GO) get github.com/kisielk/errcheck 40 | errcheck $(PKGS) 41 | 42 | gofmt: 43 | @echo Checking code is gofmted 44 | @test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)" 45 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/README.md: -------------------------------------------------------------------------------- 1 | # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) 2 | 3 | Package errors provides simple error handling primitives. 4 | 5 | `go get github.com/pkg/errors` 6 | 7 | The traditional error handling idiom in Go is roughly akin to 8 | ```go 9 | if err != nil { 10 | return err 11 | } 12 | ``` 13 | which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. 14 | 15 | ## Adding context to an error 16 | 17 | The errors.Wrap function returns a new error that adds context to the original error. For example 18 | ```go 19 | _, err := ioutil.ReadAll(r) 20 | if err != nil { 21 | return errors.Wrap(err, "read failed") 22 | } 23 | ``` 24 | ## Retrieving the cause of an error 25 | 26 | Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. 27 | ```go 28 | type causer interface { 29 | Cause() error 30 | } 31 | ``` 32 | `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: 33 | ```go 34 | switch err := errors.Cause(err).(type) { 35 | case *MyError: 36 | // handle specifically 37 | default: 38 | // unknown error 39 | } 40 | ``` 41 | 42 | [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). 43 | 44 | ## Roadmap 45 | 46 | With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows: 47 | 48 | - 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible) 49 | - 1.0. Final release. 50 | 51 | ## Contributing 52 | 53 | Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. 54 | 55 | Before sending a PR, please discuss your change by raising an issue. 56 | 57 | ## License 58 | 59 | BSD-2-Clause 60 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/go113.go: -------------------------------------------------------------------------------- 1 | // +build go1.13 2 | 3 | package errors 4 | 5 | import ( 6 | stderrors "errors" 7 | ) 8 | 9 | // Is reports whether any error in err's chain matches target. 10 | // 11 | // The chain consists of err itself followed by the sequence of errors obtained by 12 | // repeatedly calling Unwrap. 13 | // 14 | // An error is considered to match a target if it is equal to that target or if 15 | // it implements a method Is(error) bool such that Is(target) returns true. 16 | func Is(err, target error) bool { return stderrors.Is(err, target) } 17 | 18 | // As finds the first error in err's chain that matches target, and if so, sets 19 | // target to that error value and returns true. 20 | // 21 | // The chain consists of err itself followed by the sequence of errors obtained by 22 | // repeatedly calling Unwrap. 23 | // 24 | // An error matches target if the error's concrete value is assignable to the value 25 | // pointed to by target, or if the error has a method As(interface{}) bool such that 26 | // As(target) returns true. In the latter case, the As method is responsible for 27 | // setting target. 28 | // 29 | // As will panic if target is not a non-nil pointer to either a type that implements 30 | // error, or to any interface type. As returns false if err is nil. 31 | func As(err error, target interface{}) bool { return stderrors.As(err, target) } 32 | 33 | // Unwrap returns the result of calling the Unwrap method on err, if err's 34 | // type contains an Unwrap method returning error. 35 | // Otherwise, Unwrap returns nil. 36 | func Unwrap(err error) error { 37 | return stderrors.Unwrap(err) 38 | } 39 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/pkg/errors/stack.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "path" 7 | "runtime" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // Frame represents a program counter inside a stack frame. 13 | // For historical reasons if Frame is interpreted as a uintptr 14 | // its value represents the program counter + 1. 15 | type Frame uintptr 16 | 17 | // pc returns the program counter for this frame; 18 | // multiple frames may have the same PC value. 19 | func (f Frame) pc() uintptr { return uintptr(f) - 1 } 20 | 21 | // file returns the full path to the file that contains the 22 | // function for this Frame's pc. 23 | func (f Frame) file() string { 24 | fn := runtime.FuncForPC(f.pc()) 25 | if fn == nil { 26 | return "unknown" 27 | } 28 | file, _ := fn.FileLine(f.pc()) 29 | return file 30 | } 31 | 32 | // line returns the line number of source code of the 33 | // function for this Frame's pc. 34 | func (f Frame) line() int { 35 | fn := runtime.FuncForPC(f.pc()) 36 | if fn == nil { 37 | return 0 38 | } 39 | _, line := fn.FileLine(f.pc()) 40 | return line 41 | } 42 | 43 | // name returns the name of this function, if known. 44 | func (f Frame) name() string { 45 | fn := runtime.FuncForPC(f.pc()) 46 | if fn == nil { 47 | return "unknown" 48 | } 49 | return fn.Name() 50 | } 51 | 52 | // Format formats the frame according to the fmt.Formatter interface. 53 | // 54 | // %s source file 55 | // %d source line 56 | // %n function name 57 | // %v equivalent to %s:%d 58 | // 59 | // Format accepts flags that alter the printing of some verbs, as follows: 60 | // 61 | // %+s function name and path of source file relative to the compile time 62 | // GOPATH separated by \n\t (\n\t) 63 | // %+v equivalent to %+s:%d 64 | func (f Frame) Format(s fmt.State, verb rune) { 65 | switch verb { 66 | case 's': 67 | switch { 68 | case s.Flag('+'): 69 | io.WriteString(s, f.name()) 70 | io.WriteString(s, "\n\t") 71 | io.WriteString(s, f.file()) 72 | default: 73 | io.WriteString(s, path.Base(f.file())) 74 | } 75 | case 'd': 76 | io.WriteString(s, strconv.Itoa(f.line())) 77 | case 'n': 78 | io.WriteString(s, funcname(f.name())) 79 | case 'v': 80 | f.Format(s, 's') 81 | io.WriteString(s, ":") 82 | f.Format(s, 'd') 83 | } 84 | } 85 | 86 | // MarshalText formats a stacktrace Frame as a text string. The output is the 87 | // same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. 88 | func (f Frame) MarshalText() ([]byte, error) { 89 | name := f.name() 90 | if name == "unknown" { 91 | return []byte(name), nil 92 | } 93 | return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil 94 | } 95 | 96 | // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 97 | type StackTrace []Frame 98 | 99 | // Format formats the stack of Frames according to the fmt.Formatter interface. 100 | // 101 | // %s lists source files for each Frame in the stack 102 | // %v lists the source file and line number for each Frame in the stack 103 | // 104 | // Format accepts flags that alter the printing of some verbs, as follows: 105 | // 106 | // %+v Prints filename, function, and line number for each Frame in the stack. 107 | func (st StackTrace) Format(s fmt.State, verb rune) { 108 | switch verb { 109 | case 'v': 110 | switch { 111 | case s.Flag('+'): 112 | for _, f := range st { 113 | io.WriteString(s, "\n") 114 | f.Format(s, verb) 115 | } 116 | case s.Flag('#'): 117 | fmt.Fprintf(s, "%#v", []Frame(st)) 118 | default: 119 | st.formatSlice(s, verb) 120 | } 121 | case 's': 122 | st.formatSlice(s, verb) 123 | } 124 | } 125 | 126 | // formatSlice will format this StackTrace into the given buffer as a slice of 127 | // Frame, only valid when called with '%s' or '%v'. 128 | func (st StackTrace) formatSlice(s fmt.State, verb rune) { 129 | io.WriteString(s, "[") 130 | for i, f := range st { 131 | if i > 0 { 132 | io.WriteString(s, " ") 133 | } 134 | f.Format(s, verb) 135 | } 136 | io.WriteString(s, "]") 137 | } 138 | 139 | // stack represents a stack of program counters. 140 | type stack []uintptr 141 | 142 | func (s *stack) Format(st fmt.State, verb rune) { 143 | switch verb { 144 | case 'v': 145 | switch { 146 | case st.Flag('+'): 147 | for _, pc := range *s { 148 | f := Frame(pc) 149 | fmt.Fprintf(st, "\n%+v", f) 150 | } 151 | } 152 | } 153 | } 154 | 155 | func (s *stack) StackTrace() StackTrace { 156 | f := make([]Frame, len(*s)) 157 | for i := 0; i < len(f); i++ { 158 | f[i] = Frame((*s)[i]) 159 | } 160 | return f 161 | } 162 | 163 | func callers() *stack { 164 | const depth = 32 165 | var pcs [depth]uintptr 166 | n := runtime.Callers(3, pcs[:]) 167 | var st stack = pcs[0:n] 168 | return &st 169 | } 170 | 171 | // funcname removes the path prefix component of a function's name reported by func.Name(). 172 | func funcname(name string) string { 173 | i := strings.LastIndex(name, "/") 174 | name = name[i+1:] 175 | i = strings.Index(name, ".") 176 | return name[i+1:] 177 | } 178 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | coverage.txt 3 | gocomplete/gocomplete 4 | example/self/self 5 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - tip 4 | - 1.12.x 5 | - 1.11.x 6 | - 1.10.x 7 | 8 | script: 9 | - go test -race -coverprofile=coverage.txt -covermode=atomic ./... 10 | 11 | after_success: 12 | - bash <(curl -s https://codecov.io/bash) 13 | 14 | matrix: 15 | allow_failures: 16 | - go: tip -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Eyal Posener 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/README.md: -------------------------------------------------------------------------------- 1 | # complete 2 | 3 | [![Build Status](https://travis-ci.org/posener/complete.svg?branch=master)](https://travis-ci.org/posener/complete) 4 | [![codecov](https://codecov.io/gh/posener/complete/branch/master/graph/badge.svg)](https://codecov.io/gh/posener/complete) 5 | [![golangci](https://golangci.com/badges/github.com/posener/complete.svg)](https://golangci.com/r/github.com/posener/complete) 6 | [![GoDoc](https://godoc.org/github.com/posener/complete?status.svg)](http://godoc.org/github.com/posener/complete) 7 | [![goreadme](https://goreadme.herokuapp.com/badge/posener/complete.svg)](https://goreadme.herokuapp.com) 8 | 9 | Package complete provides a tool for bash writing bash completion in go, and bash completion for the go command line. 10 | 11 | Writing bash completion scripts is a hard work. This package provides an easy way 12 | to create bash completion scripts for any command, and also an easy way to install/uninstall 13 | the completion of the command. 14 | 15 | #### Go Command Bash Completion 16 | 17 | In [./cmd/gocomplete](./cmd/gocomplete) there is an example for bash completion for the `go` command line. 18 | 19 | This is an example that uses the `complete` package on the `go` command - the `complete` package 20 | can also be used to implement any completions, see #usage. 21 | 22 | #### Install 23 | 24 | 1. Type in your shell: 25 | 26 | ```go 27 | go get -u github.com/posener/complete/gocomplete 28 | gocomplete -install 29 | ``` 30 | 31 | 2. Restart your shell 32 | 33 | Uninstall by `gocomplete -uninstall` 34 | 35 | #### Features 36 | 37 | - Complete `go` command, including sub commands and all flags. 38 | - Complete packages names or `.go` files when necessary. 39 | - Complete test names after `-run` flag. 40 | 41 | #### Complete package 42 | 43 | Supported shells: 44 | 45 | - [x] bash 46 | - [x] zsh 47 | - [x] fish 48 | 49 | #### Usage 50 | 51 | Assuming you have program called `run` and you want to have bash completion 52 | for it, meaning, if you type `run` then space, then press the `Tab` key, 53 | the shell will suggest relevant complete options. 54 | 55 | In that case, we will create a program called `runcomplete`, a go program, 56 | with a `func main()` and so, that will make the completion of the `run` 57 | program. Once the `runcomplete` will be in a binary form, we could 58 | `runcomplete -install` and that will add to our shell all the bash completion 59 | options for `run`. 60 | 61 | So here it is: 62 | 63 | ```go 64 | import "github.com/posener/complete" 65 | 66 | func main() { 67 | 68 | // create a Command object, that represents the command we want 69 | // to complete. 70 | run := complete.Command{ 71 | 72 | // Sub defines a list of sub commands of the program, 73 | // this is recursive, since every command is of type command also. 74 | Sub: complete.Commands{ 75 | 76 | // add a build sub command 77 | "build": complete.Command { 78 | 79 | // define flags of the build sub command 80 | Flags: complete.Flags{ 81 | // build sub command has a flag '-cpus', which 82 | // expects number of cpus after it. in that case 83 | // anything could complete this flag. 84 | "-cpus": complete.PredictAnything, 85 | }, 86 | }, 87 | }, 88 | 89 | // define flags of the 'run' main command 90 | Flags: complete.Flags{ 91 | // a flag -o, which expects a file ending with .out after 92 | // it, the tab completion will auto complete for files matching 93 | // the given pattern. 94 | "-o": complete.PredictFiles("*.out"), 95 | }, 96 | 97 | // define global flags of the 'run' main command 98 | // those will show up also when a sub command was entered in the 99 | // command line 100 | GlobalFlags: complete.Flags{ 101 | 102 | // a flag '-h' which does not expects anything after it 103 | "-h": complete.PredictNothing, 104 | }, 105 | } 106 | 107 | // run the command completion, as part of the main() function. 108 | // this triggers the autocompletion when needed. 109 | // name must be exactly as the binary that we want to complete. 110 | complete.New("run", run).Run() 111 | } 112 | ``` 113 | 114 | #### Self completing program 115 | 116 | In case that the program that we want to complete is written in go we 117 | can make it self completing. 118 | Here is an example: [./example/self/main.go](./example/self/main.go) . 119 | 120 | ## Sub Packages 121 | 122 | * [cmd](./cmd): Package cmd used for command line options for the complete tool 123 | 124 | * [gocomplete](./gocomplete): Package main is complete tool for the go command line 125 | 126 | * [match](./match): Package match contains matchers that decide if to apply completion. 127 | 128 | 129 | --- 130 | 131 | Created by [goreadme](https://github.com/apps/goreadme) 132 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/args.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "strings" 7 | "unicode" 8 | ) 9 | 10 | // Args describes command line arguments 11 | type Args struct { 12 | // All lists of all arguments in command line (not including the command itself) 13 | All []string 14 | // Completed lists of all completed arguments in command line, 15 | // If the last one is still being typed - no space after it, 16 | // it won't appear in this list of arguments. 17 | Completed []string 18 | // Last argument in command line, the one being typed, if the last 19 | // character in the command line is a space, this argument will be empty, 20 | // otherwise this would be the last word. 21 | Last string 22 | // LastCompleted is the last argument that was fully typed. 23 | // If the last character in the command line is space, this would be the 24 | // last word, otherwise, it would be the word before that. 25 | LastCompleted string 26 | } 27 | 28 | // Directory gives the directory of the current written 29 | // last argument if it represents a file name being written. 30 | // in case that it is not, we fall back to the current directory. 31 | // 32 | // Deprecated. 33 | func (a Args) Directory() string { 34 | if info, err := os.Stat(a.Last); err == nil && info.IsDir() { 35 | return fixPathForm(a.Last, a.Last) 36 | } 37 | dir := filepath.Dir(a.Last) 38 | if info, err := os.Stat(dir); err != nil || !info.IsDir() { 39 | return "./" 40 | } 41 | return fixPathForm(a.Last, dir) 42 | } 43 | 44 | func newArgs(line string) Args { 45 | var ( 46 | all []string 47 | completed []string 48 | ) 49 | parts := splitFields(line) 50 | if len(parts) > 0 { 51 | all = parts[1:] 52 | completed = removeLast(parts[1:]) 53 | } 54 | return Args{ 55 | All: all, 56 | Completed: completed, 57 | Last: last(parts), 58 | LastCompleted: last(completed), 59 | } 60 | } 61 | 62 | // splitFields returns a list of fields from the given command line. 63 | // If the last character is space, it appends an empty field in the end 64 | // indicating that the field before it was completed. 65 | // If the last field is of the form "a=b", it splits it to two fields: "a", "b", 66 | // So it can be completed. 67 | func splitFields(line string) []string { 68 | parts := strings.Fields(line) 69 | 70 | // Add empty field if the last field was completed. 71 | if len(line) > 0 && unicode.IsSpace(rune(line[len(line)-1])) { 72 | parts = append(parts, "") 73 | } 74 | 75 | // Treat the last field if it is of the form "a=b" 76 | parts = splitLastEqual(parts) 77 | return parts 78 | } 79 | 80 | func splitLastEqual(line []string) []string { 81 | if len(line) == 0 { 82 | return line 83 | } 84 | parts := strings.Split(line[len(line)-1], "=") 85 | return append(line[:len(line)-1], parts...) 86 | } 87 | 88 | // from returns a copy of Args of all arguments after the i'th argument. 89 | func (a Args) from(i int) Args { 90 | if i >= len(a.All) { 91 | i = len(a.All) - 1 92 | } 93 | a.All = a.All[i+1:] 94 | 95 | if i >= len(a.Completed) { 96 | i = len(a.Completed) - 1 97 | } 98 | a.Completed = a.Completed[i+1:] 99 | return a 100 | } 101 | 102 | func removeLast(a []string) []string { 103 | if len(a) > 0 { 104 | return a[:len(a)-1] 105 | } 106 | return a 107 | } 108 | 109 | func last(args []string) string { 110 | if len(args) == 0 { 111 | return "" 112 | } 113 | return args[len(args)-1] 114 | } 115 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/cmd.go: -------------------------------------------------------------------------------- 1 | // Package cmd used for command line options for the complete tool 2 | package cmd 3 | 4 | import ( 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "strings" 10 | 11 | "github.com/posener/complete/cmd/install" 12 | ) 13 | 14 | // CLI for command line 15 | type CLI struct { 16 | Name string 17 | InstallName string 18 | UninstallName string 19 | 20 | install bool 21 | uninstall bool 22 | yes bool 23 | } 24 | 25 | const ( 26 | defaultInstallName = "install" 27 | defaultUninstallName = "uninstall" 28 | ) 29 | 30 | // Run is used when running complete in command line mode. 31 | // this is used when the complete is not completing words, but to 32 | // install it or uninstall it. 33 | func (f *CLI) Run() bool { 34 | err := f.validate() 35 | if err != nil { 36 | os.Stderr.WriteString(err.Error() + "\n") 37 | os.Exit(1) 38 | } 39 | 40 | switch { 41 | case f.install: 42 | f.prompt() 43 | err = install.Install(f.Name) 44 | case f.uninstall: 45 | f.prompt() 46 | err = install.Uninstall(f.Name) 47 | default: 48 | // non of the action flags matched, 49 | // returning false should make the real program execute 50 | return false 51 | } 52 | 53 | if err != nil { 54 | fmt.Printf("%s failed! %s\n", f.action(), err) 55 | os.Exit(3) 56 | } 57 | fmt.Println("Done!") 58 | return true 59 | } 60 | 61 | // prompt use for approval 62 | // exit if approval was not given 63 | func (f *CLI) prompt() { 64 | defer fmt.Println(f.action() + "ing...") 65 | if f.yes { 66 | return 67 | } 68 | fmt.Printf("%s completion for %s? ", f.action(), f.Name) 69 | var answer string 70 | fmt.Scanln(&answer) 71 | 72 | switch strings.ToLower(answer) { 73 | case "y", "yes": 74 | return 75 | default: 76 | fmt.Println("Cancelling...") 77 | os.Exit(1) 78 | } 79 | } 80 | 81 | // AddFlags adds the CLI flags to the flag set. 82 | // If flags is nil, the default command line flags will be taken. 83 | // Pass non-empty strings as installName and uninstallName to override the default 84 | // flag names. 85 | func (f *CLI) AddFlags(flags *flag.FlagSet) { 86 | if flags == nil { 87 | flags = flag.CommandLine 88 | } 89 | 90 | if f.InstallName == "" { 91 | f.InstallName = defaultInstallName 92 | } 93 | if f.UninstallName == "" { 94 | f.UninstallName = defaultUninstallName 95 | } 96 | 97 | if flags.Lookup(f.InstallName) == nil { 98 | flags.BoolVar(&f.install, f.InstallName, false, 99 | fmt.Sprintf("Install completion for %s command", f.Name)) 100 | } 101 | if flags.Lookup(f.UninstallName) == nil { 102 | flags.BoolVar(&f.uninstall, f.UninstallName, false, 103 | fmt.Sprintf("Uninstall completion for %s command", f.Name)) 104 | } 105 | if flags.Lookup("y") == nil { 106 | flags.BoolVar(&f.yes, "y", false, "Don't prompt user for typing 'yes' when installing completion") 107 | } 108 | } 109 | 110 | // validate the CLI 111 | func (f *CLI) validate() error { 112 | if f.install && f.uninstall { 113 | return errors.New("Install and uninstall are mutually exclusive") 114 | } 115 | return nil 116 | } 117 | 118 | // action name according to the CLI values. 119 | func (f *CLI) action() string { 120 | switch { 121 | case f.install: 122 | return "Install" 123 | case f.uninstall: 124 | return "Uninstall" 125 | default: 126 | return "unknown" 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/install/bash.go: -------------------------------------------------------------------------------- 1 | package install 2 | 3 | import "fmt" 4 | 5 | // (un)install in bash 6 | // basically adds/remove from .bashrc: 7 | // 8 | // complete -C 9 | type bash struct { 10 | rc string 11 | } 12 | 13 | func (b bash) IsInstalled(cmd, bin string) bool { 14 | completeCmd := b.cmd(cmd, bin) 15 | return lineInFile(b.rc, completeCmd) 16 | } 17 | 18 | func (b bash) Install(cmd, bin string) error { 19 | if b.IsInstalled(cmd, bin) { 20 | return fmt.Errorf("already installed in %s", b.rc) 21 | } 22 | completeCmd := b.cmd(cmd, bin) 23 | return appendToFile(b.rc, completeCmd) 24 | } 25 | 26 | func (b bash) Uninstall(cmd, bin string) error { 27 | if !b.IsInstalled(cmd, bin) { 28 | return fmt.Errorf("does not installed in %s", b.rc) 29 | } 30 | 31 | completeCmd := b.cmd(cmd, bin) 32 | return removeFromFile(b.rc, completeCmd) 33 | } 34 | 35 | func (bash) cmd(cmd, bin string) string { 36 | return fmt.Sprintf("complete -C %s %s", bin, cmd) 37 | } 38 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/install/fish.go: -------------------------------------------------------------------------------- 1 | package install 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "text/template" 9 | ) 10 | 11 | // (un)install in fish 12 | 13 | type fish struct { 14 | configDir string 15 | } 16 | 17 | func (f fish) IsInstalled(cmd, bin string) bool { 18 | completionFile := f.getCompletionFilePath(cmd) 19 | if _, err := os.Stat(completionFile); err == nil { 20 | return true 21 | } 22 | return false 23 | } 24 | 25 | func (f fish) Install(cmd, bin string) error { 26 | if f.IsInstalled(cmd, bin) { 27 | return fmt.Errorf("already installed at %s", f.getCompletionFilePath(cmd)) 28 | } 29 | 30 | completionFile := f.getCompletionFilePath(cmd) 31 | completeCmd, err := f.cmd(cmd, bin) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | return createFile(completionFile, completeCmd) 37 | } 38 | 39 | func (f fish) Uninstall(cmd, bin string) error { 40 | if !f.IsInstalled(cmd, bin) { 41 | return fmt.Errorf("does not installed in %s", f.configDir) 42 | } 43 | 44 | completionFile := f.getCompletionFilePath(cmd) 45 | return os.Remove(completionFile) 46 | } 47 | 48 | func (f fish) getCompletionFilePath(cmd string) string { 49 | return filepath.Join(f.configDir, "completions", fmt.Sprintf("%s.fish", cmd)) 50 | } 51 | 52 | func (f fish) cmd(cmd, bin string) (string, error) { 53 | var buf bytes.Buffer 54 | params := struct{ Cmd, Bin string }{cmd, bin} 55 | tmpl := template.Must(template.New("cmd").Parse(` 56 | function __complete_{{.Cmd}} 57 | set -lx COMP_LINE (commandline -cp) 58 | test -z (commandline -ct) 59 | and set COMP_LINE "$COMP_LINE " 60 | {{.Bin}} 61 | end 62 | complete -f -c {{.Cmd}} -a "(__complete_{{.Cmd}})" 63 | `)) 64 | err := tmpl.Execute(&buf, params) 65 | if err != nil { 66 | return "", err 67 | } 68 | return buf.String(), nil 69 | } 70 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/install/install.go: -------------------------------------------------------------------------------- 1 | package install 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "os/user" 7 | "path/filepath" 8 | "runtime" 9 | 10 | "github.com/hashicorp/go-multierror" 11 | ) 12 | 13 | type installer interface { 14 | IsInstalled(cmd, bin string) bool 15 | Install(cmd, bin string) error 16 | Uninstall(cmd, bin string) error 17 | } 18 | 19 | // Install complete command given: 20 | // cmd: is the command name 21 | func Install(cmd string) error { 22 | is := installers() 23 | if len(is) == 0 { 24 | return errors.New("Did not find any shells to install") 25 | } 26 | bin, err := getBinaryPath() 27 | if err != nil { 28 | return err 29 | } 30 | 31 | for _, i := range is { 32 | errI := i.Install(cmd, bin) 33 | if errI != nil { 34 | err = multierror.Append(err, errI) 35 | } 36 | } 37 | 38 | return err 39 | } 40 | 41 | // IsInstalled returns true if the completion 42 | // for the given cmd is installed. 43 | func IsInstalled(cmd string) bool { 44 | bin, err := getBinaryPath() 45 | if err != nil { 46 | return false 47 | } 48 | 49 | for _, i := range installers() { 50 | installed := i.IsInstalled(cmd, bin) 51 | if installed { 52 | return true 53 | } 54 | } 55 | 56 | return false 57 | } 58 | 59 | // Uninstall complete command given: 60 | // cmd: is the command name 61 | func Uninstall(cmd string) error { 62 | is := installers() 63 | if len(is) == 0 { 64 | return errors.New("Did not find any shells to uninstall") 65 | } 66 | bin, err := getBinaryPath() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | for _, i := range is { 72 | errI := i.Uninstall(cmd, bin) 73 | if errI != nil { 74 | err = multierror.Append(err, errI) 75 | } 76 | } 77 | 78 | return err 79 | } 80 | 81 | func installers() (i []installer) { 82 | // The list of bash config files candidates where it is 83 | // possible to install the completion command. 84 | var bashConfFiles []string 85 | switch runtime.GOOS { 86 | case "darwin": 87 | bashConfFiles = []string{".bash_profile"} 88 | default: 89 | bashConfFiles = []string{".bashrc", ".bash_profile", ".bash_login", ".profile"} 90 | } 91 | for _, rc := range bashConfFiles { 92 | if f := rcFile(rc); f != "" { 93 | i = append(i, bash{f}) 94 | break 95 | } 96 | } 97 | if f := rcFile(".zshrc"); f != "" { 98 | i = append(i, zsh{f}) 99 | } 100 | if d := fishConfigDir(); d != "" { 101 | i = append(i, fish{d}) 102 | } 103 | return 104 | } 105 | 106 | func fishConfigDir() string { 107 | configDir := filepath.Join(getConfigHomePath(), "fish") 108 | if configDir == "" { 109 | return "" 110 | } 111 | if info, err := os.Stat(configDir); err != nil || !info.IsDir() { 112 | return "" 113 | } 114 | return configDir 115 | } 116 | 117 | func getConfigHomePath() string { 118 | u, err := user.Current() 119 | if err != nil { 120 | return "" 121 | } 122 | 123 | configHome := os.Getenv("XDG_CONFIG_HOME") 124 | if configHome == "" { 125 | return filepath.Join(u.HomeDir, ".config") 126 | } 127 | return configHome 128 | } 129 | 130 | func getBinaryPath() (string, error) { 131 | bin, err := os.Executable() 132 | if err != nil { 133 | return "", err 134 | } 135 | return filepath.Abs(bin) 136 | } 137 | 138 | func rcFile(name string) string { 139 | u, err := user.Current() 140 | if err != nil { 141 | return "" 142 | } 143 | path := filepath.Join(u.HomeDir, name) 144 | if _, err := os.Stat(path); err != nil { 145 | return "" 146 | } 147 | return path 148 | } 149 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/install/utils.go: -------------------------------------------------------------------------------- 1 | package install 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | ) 11 | 12 | func lineInFile(name string, lookFor string) bool { 13 | f, err := os.Open(name) 14 | if err != nil { 15 | return false 16 | } 17 | defer f.Close() 18 | r := bufio.NewReader(f) 19 | prefix := []byte{} 20 | for { 21 | line, isPrefix, err := r.ReadLine() 22 | if err == io.EOF { 23 | return false 24 | } 25 | if err != nil { 26 | return false 27 | } 28 | if isPrefix { 29 | prefix = append(prefix, line...) 30 | continue 31 | } 32 | line = append(prefix, line...) 33 | if string(line) == lookFor { 34 | return true 35 | } 36 | prefix = prefix[:0] 37 | } 38 | } 39 | 40 | func createFile(name string, content string) error { 41 | // make sure file directory exists 42 | if err := os.MkdirAll(filepath.Dir(name), 0775); err != nil { 43 | return err 44 | } 45 | 46 | // create the file 47 | f, err := os.Create(name) 48 | if err != nil { 49 | return err 50 | } 51 | defer f.Close() 52 | 53 | // write file content 54 | _, err = f.WriteString(fmt.Sprintf("%s\n", content)) 55 | return err 56 | } 57 | 58 | func appendToFile(name string, content string) error { 59 | f, err := os.OpenFile(name, os.O_RDWR|os.O_APPEND, 0) 60 | if err != nil { 61 | return err 62 | } 63 | defer f.Close() 64 | _, err = f.WriteString(fmt.Sprintf("\n%s\n", content)) 65 | return err 66 | } 67 | 68 | func removeFromFile(name string, content string) error { 69 | backup := name + ".bck" 70 | err := copyFile(name, backup) 71 | if err != nil { 72 | return err 73 | } 74 | temp, err := removeContentToTempFile(name, content) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | err = copyFile(temp, name) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | return os.Remove(backup) 85 | } 86 | 87 | func removeContentToTempFile(name, content string) (string, error) { 88 | rf, err := os.Open(name) 89 | if err != nil { 90 | return "", err 91 | } 92 | defer rf.Close() 93 | wf, err := ioutil.TempFile("/tmp", "complete-") 94 | if err != nil { 95 | return "", err 96 | } 97 | defer wf.Close() 98 | 99 | r := bufio.NewReader(rf) 100 | prefix := []byte{} 101 | for { 102 | line, isPrefix, err := r.ReadLine() 103 | if err == io.EOF { 104 | break 105 | } 106 | if err != nil { 107 | return "", err 108 | } 109 | if isPrefix { 110 | prefix = append(prefix, line...) 111 | continue 112 | } 113 | line = append(prefix, line...) 114 | str := string(line) 115 | if str == content { 116 | continue 117 | } 118 | _, err = wf.WriteString(str + "\n") 119 | if err != nil { 120 | return "", err 121 | } 122 | prefix = prefix[:0] 123 | } 124 | return wf.Name(), nil 125 | } 126 | 127 | func copyFile(src string, dst string) error { 128 | in, err := os.Open(src) 129 | if err != nil { 130 | return err 131 | } 132 | defer in.Close() 133 | out, err := os.Create(dst) 134 | if err != nil { 135 | return err 136 | } 137 | defer out.Close() 138 | _, err = io.Copy(out, in) 139 | return err 140 | } 141 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/cmd/install/zsh.go: -------------------------------------------------------------------------------- 1 | package install 2 | 3 | import "fmt" 4 | 5 | // (un)install in zsh 6 | // basically adds/remove from .zshrc: 7 | // 8 | // autoload -U +X bashcompinit && bashcompinit" 9 | // complete -C 10 | type zsh struct { 11 | rc string 12 | } 13 | 14 | func (z zsh) IsInstalled(cmd, bin string) bool { 15 | completeCmd := z.cmd(cmd, bin) 16 | return lineInFile(z.rc, completeCmd) 17 | } 18 | 19 | func (z zsh) Install(cmd, bin string) error { 20 | if z.IsInstalled(cmd, bin) { 21 | return fmt.Errorf("already installed in %s", z.rc) 22 | } 23 | 24 | completeCmd := z.cmd(cmd, bin) 25 | bashCompInit := "autoload -U +X bashcompinit && bashcompinit" 26 | if !lineInFile(z.rc, bashCompInit) { 27 | completeCmd = bashCompInit + "\n" + completeCmd 28 | } 29 | 30 | return appendToFile(z.rc, completeCmd) 31 | } 32 | 33 | func (z zsh) Uninstall(cmd, bin string) error { 34 | if !z.IsInstalled(cmd, bin) { 35 | return fmt.Errorf("does not installed in %s", z.rc) 36 | } 37 | 38 | completeCmd := z.cmd(cmd, bin) 39 | return removeFromFile(z.rc, completeCmd) 40 | } 41 | 42 | func (zsh) cmd(cmd, bin string) string { 43 | return fmt.Sprintf("complete -o nospace -C %s %s", bin, cmd) 44 | } 45 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/command.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | // Command represents a command line 4 | // It holds the data that enables auto completion of command line 5 | // Command can also be a sub command. 6 | type Command struct { 7 | // Sub is map of sub commands of the current command 8 | // The key refer to the sub command name, and the value is it's 9 | // Command descriptive struct. 10 | Sub Commands 11 | 12 | // Flags is a map of flags that the command accepts. 13 | // The key is the flag name, and the value is it's predictions. 14 | Flags Flags 15 | 16 | // GlobalFlags is a map of flags that the command accepts. 17 | // Global flags that can appear also after a sub command. 18 | GlobalFlags Flags 19 | 20 | // Args are extra arguments that the command accepts, those who are 21 | // given without any flag before. 22 | Args Predictor 23 | } 24 | 25 | // Predict returns all possible predictions for args according to the command struct 26 | func (c *Command) Predict(a Args) []string { 27 | options, _ := c.predict(a) 28 | return options 29 | } 30 | 31 | // Commands is the type of Sub member, it maps a command name to a command struct 32 | type Commands map[string]Command 33 | 34 | // Predict completion of sub command names names according to command line arguments 35 | func (c Commands) Predict(a Args) (prediction []string) { 36 | for sub := range c { 37 | prediction = append(prediction, sub) 38 | } 39 | return 40 | } 41 | 42 | // Flags is the type Flags of the Flags member, it maps a flag name to the flag predictions. 43 | type Flags map[string]Predictor 44 | 45 | // Predict completion of flags names according to command line arguments 46 | func (f Flags) Predict(a Args) (prediction []string) { 47 | for flag := range f { 48 | // If the flag starts with a hyphen, we avoid emitting the prediction 49 | // unless the last typed arg contains a hyphen as well. 50 | flagHyphenStart := len(flag) != 0 && flag[0] == '-' 51 | lastHyphenStart := len(a.Last) != 0 && a.Last[0] == '-' 52 | if flagHyphenStart && !lastHyphenStart { 53 | continue 54 | } 55 | prediction = append(prediction, flag) 56 | } 57 | return 58 | } 59 | 60 | // predict options 61 | // only is set to true if no more options are allowed to be returned 62 | // those are in cases of special flag that has specific completion arguments, 63 | // and other flags or sub commands can't come after it. 64 | func (c *Command) predict(a Args) (options []string, only bool) { 65 | 66 | // search sub commands for predictions first 67 | subCommandFound := false 68 | for i, arg := range a.Completed { 69 | if cmd, ok := c.Sub[arg]; ok { 70 | subCommandFound = true 71 | 72 | // recursive call for sub command 73 | options, only = cmd.predict(a.from(i)) 74 | if only { 75 | return 76 | } 77 | 78 | // We matched so stop searching. Continuing to search can accidentally 79 | // match a subcommand with current set of commands, see issue #46. 80 | break 81 | } 82 | } 83 | 84 | // if last completed word is a global flag that we need to complete 85 | if predictor, ok := c.GlobalFlags[a.LastCompleted]; ok && predictor != nil { 86 | Log("Predicting according to global flag %s", a.LastCompleted) 87 | return predictor.Predict(a), true 88 | } 89 | 90 | options = append(options, c.GlobalFlags.Predict(a)...) 91 | 92 | // if a sub command was entered, we won't add the parent command 93 | // completions and we return here. 94 | if subCommandFound { 95 | return 96 | } 97 | 98 | // if last completed word is a command flag that we need to complete 99 | if predictor, ok := c.Flags[a.LastCompleted]; ok && predictor != nil { 100 | Log("Predicting according to flag %s", a.LastCompleted) 101 | return predictor.Predict(a), true 102 | } 103 | 104 | options = append(options, c.Sub.Predict(a)...) 105 | options = append(options, c.Flags.Predict(a)...) 106 | if c.Args != nil { 107 | options = append(options, c.Args.Predict(a)...) 108 | } 109 | 110 | return 111 | } 112 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/complete.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "os" 8 | "strconv" 9 | "strings" 10 | 11 | "github.com/posener/complete/cmd" 12 | ) 13 | 14 | const ( 15 | envLine = "COMP_LINE" 16 | envPoint = "COMP_POINT" 17 | envDebug = "COMP_DEBUG" 18 | ) 19 | 20 | // Complete structs define completion for a command with CLI options 21 | type Complete struct { 22 | Command Command 23 | cmd.CLI 24 | Out io.Writer 25 | } 26 | 27 | // New creates a new complete command. 28 | // name is the name of command we want to auto complete. 29 | // IMPORTANT: it must be the same name - if the auto complete 30 | // completes the 'go' command, name must be equal to "go". 31 | // command is the struct of the command completion. 32 | func New(name string, command Command) *Complete { 33 | return &Complete{ 34 | Command: command, 35 | CLI: cmd.CLI{Name: name}, 36 | Out: os.Stdout, 37 | } 38 | } 39 | 40 | // Run runs the completion and add installation flags beforehand. 41 | // The flags are added to the main flag CommandLine variable. 42 | func (c *Complete) Run() bool { 43 | c.AddFlags(nil) 44 | flag.Parse() 45 | return c.Complete() 46 | } 47 | 48 | // Complete a command from completion line in environment variable, 49 | // and print out the complete options. 50 | // returns success if the completion ran or if the cli matched 51 | // any of the given flags, false otherwise 52 | // For installation: it assumes that flags were added and parsed before 53 | // it was called. 54 | func (c *Complete) Complete() bool { 55 | line, point, ok := getEnv() 56 | if !ok { 57 | // make sure flags parsed, 58 | // in case they were not added in the main program 59 | return c.CLI.Run() 60 | } 61 | 62 | if point >= 0 && point < len(line) { 63 | line = line[:point] 64 | } 65 | 66 | Log("Completing phrase: %s", line) 67 | a := newArgs(line) 68 | Log("Completing last field: %s", a.Last) 69 | options := c.Command.Predict(a) 70 | Log("Options: %s", options) 71 | 72 | // filter only options that match the last argument 73 | matches := []string{} 74 | for _, option := range options { 75 | if strings.HasPrefix(option, a.Last) { 76 | matches = append(matches, option) 77 | } 78 | } 79 | Log("Matches: %s", matches) 80 | c.output(matches) 81 | return true 82 | } 83 | 84 | func getEnv() (line string, point int, ok bool) { 85 | line = os.Getenv(envLine) 86 | if line == "" { 87 | return 88 | } 89 | point, err := strconv.Atoi(os.Getenv(envPoint)) 90 | if err != nil { 91 | // If failed parsing point for some reason, set it to point 92 | // on the end of the line. 93 | Log("Failed parsing point %s: %v", os.Getenv(envPoint), err) 94 | point = len(line) 95 | } 96 | return line, point, true 97 | } 98 | 99 | func (c *Complete) output(options []string) { 100 | // stdout of program defines the complete options 101 | for _, option := range options { 102 | fmt.Fprintln(c.Out, option) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package complete provides a tool for bash writing bash completion in go, and bash completion for the go command line. 3 | 4 | Writing bash completion scripts is a hard work. This package provides an easy way 5 | to create bash completion scripts for any command, and also an easy way to install/uninstall 6 | the completion of the command. 7 | 8 | Go Command Bash Completion 9 | 10 | In ./cmd/gocomplete there is an example for bash completion for the `go` command line. 11 | 12 | This is an example that uses the `complete` package on the `go` command - the `complete` package 13 | can also be used to implement any completions, see #usage. 14 | 15 | Install 16 | 17 | 1. Type in your shell: 18 | 19 | go get -u github.com/posener/complete/gocomplete 20 | gocomplete -install 21 | 22 | 2. Restart your shell 23 | 24 | Uninstall by `gocomplete -uninstall` 25 | 26 | Features 27 | 28 | - Complete `go` command, including sub commands and all flags. 29 | - Complete packages names or `.go` files when necessary. 30 | - Complete test names after `-run` flag. 31 | 32 | Complete package 33 | 34 | Supported shells: 35 | 36 | - [x] bash 37 | - [x] zsh 38 | - [x] fish 39 | 40 | Usage 41 | 42 | Assuming you have program called `run` and you want to have bash completion 43 | for it, meaning, if you type `run` then space, then press the `Tab` key, 44 | the shell will suggest relevant complete options. 45 | 46 | In that case, we will create a program called `runcomplete`, a go program, 47 | with a `func main()` and so, that will make the completion of the `run` 48 | program. Once the `runcomplete` will be in a binary form, we could 49 | `runcomplete -install` and that will add to our shell all the bash completion 50 | options for `run`. 51 | 52 | So here it is: 53 | 54 | import "github.com/posener/complete" 55 | 56 | func main() { 57 | 58 | // create a Command object, that represents the command we want 59 | // to complete. 60 | run := complete.Command{ 61 | 62 | // Sub defines a list of sub commands of the program, 63 | // this is recursive, since every command is of type command also. 64 | Sub: complete.Commands{ 65 | 66 | // add a build sub command 67 | "build": complete.Command { 68 | 69 | // define flags of the build sub command 70 | Flags: complete.Flags{ 71 | // build sub command has a flag '-cpus', which 72 | // expects number of cpus after it. in that case 73 | // anything could complete this flag. 74 | "-cpus": complete.PredictAnything, 75 | }, 76 | }, 77 | }, 78 | 79 | // define flags of the 'run' main command 80 | Flags: complete.Flags{ 81 | // a flag -o, which expects a file ending with .out after 82 | // it, the tab completion will auto complete for files matching 83 | // the given pattern. 84 | "-o": complete.PredictFiles("*.out"), 85 | }, 86 | 87 | // define global flags of the 'run' main command 88 | // those will show up also when a sub command was entered in the 89 | // command line 90 | GlobalFlags: complete.Flags{ 91 | 92 | // a flag '-h' which does not expects anything after it 93 | "-h": complete.PredictNothing, 94 | }, 95 | } 96 | 97 | // run the command completion, as part of the main() function. 98 | // this triggers the autocompletion when needed. 99 | // name must be exactly as the binary that we want to complete. 100 | complete.New("run", run).Run() 101 | } 102 | 103 | Self completing program 104 | 105 | In case that the program that we want to complete is written in go we 106 | can make it self completing. 107 | Here is an example: ./example/self/main.go . 108 | 109 | */ 110 | package complete 111 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/posener/complete 2 | 3 | require ( 4 | github.com/hashicorp/go-multierror v1.0.0 5 | github.com/stretchr/testify v1.4.0 6 | ) 7 | 8 | go 1.13 9 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 4 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 5 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 6 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 11 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 14 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 15 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 16 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/goreadme.json: -------------------------------------------------------------------------------- 1 | { 2 | "badges": { 3 | "travis_ci": true, 4 | "code_cov": true, 5 | "golang_ci": true, 6 | "go_doc": true, 7 | "goreadme": true 8 | } 9 | } -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/log.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | ) 8 | 9 | // Log is used for debugging purposes 10 | // since complete is running on tab completion, it is nice to 11 | // have logs to the stderr (when writing your own completer) 12 | // to write logs, set the COMP_DEBUG environment variable and 13 | // use complete.Log in the complete program 14 | var Log = getLogger() 15 | 16 | func getLogger() func(format string, args ...interface{}) { 17 | var logfile = ioutil.Discard 18 | if os.Getenv(envDebug) != "" { 19 | logfile = os.Stderr 20 | } 21 | return log.New(logfile, "complete ", log.Flags()).Printf 22 | } 23 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/predict.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | // Predictor implements a predict method, in which given 4 | // command line arguments returns a list of options it predicts. 5 | type Predictor interface { 6 | Predict(Args) []string 7 | } 8 | 9 | // PredictOr unions two predicate functions, so that the result predicate 10 | // returns the union of their predication 11 | func PredictOr(predictors ...Predictor) Predictor { 12 | return PredictFunc(func(a Args) (prediction []string) { 13 | for _, p := range predictors { 14 | if p == nil { 15 | continue 16 | } 17 | prediction = append(prediction, p.Predict(a)...) 18 | } 19 | return 20 | }) 21 | } 22 | 23 | // PredictFunc determines what terms can follow a command or a flag 24 | // It is used for auto completion, given last - the last word in the already 25 | // in the command line, what words can complete it. 26 | type PredictFunc func(Args) []string 27 | 28 | // Predict invokes the predict function and implements the Predictor interface 29 | func (p PredictFunc) Predict(a Args) []string { 30 | if p == nil { 31 | return nil 32 | } 33 | return p(a) 34 | } 35 | 36 | // PredictNothing does not expect anything after. 37 | var PredictNothing Predictor 38 | 39 | // PredictAnything expects something, but nothing particular, such as a number 40 | // or arbitrary name. 41 | var PredictAnything = PredictFunc(func(Args) []string { return nil }) 42 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/predict_files.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | ) 9 | 10 | // PredictDirs will search for directories in the given started to be typed 11 | // path, if no path was started to be typed, it will complete to directories 12 | // in the current working directory. 13 | func PredictDirs(pattern string) Predictor { 14 | return files(pattern, false) 15 | } 16 | 17 | // PredictFiles will search for files matching the given pattern in the started to 18 | // be typed path, if no path was started to be typed, it will complete to files that 19 | // match the pattern in the current working directory. 20 | // To match any file, use "*" as pattern. To match go files use "*.go", and so on. 21 | func PredictFiles(pattern string) Predictor { 22 | return files(pattern, true) 23 | } 24 | 25 | func files(pattern string, allowFiles bool) PredictFunc { 26 | 27 | // search for files according to arguments, 28 | // if only one directory has matched the result, search recursively into 29 | // this directory to give more results. 30 | return func(a Args) (prediction []string) { 31 | prediction = predictFiles(a, pattern, allowFiles) 32 | 33 | // if the number of prediction is not 1, we either have many results or 34 | // have no results, so we return it. 35 | if len(prediction) != 1 { 36 | return 37 | } 38 | 39 | // only try deeper, if the one item is a directory 40 | if stat, err := os.Stat(prediction[0]); err != nil || !stat.IsDir() { 41 | return 42 | } 43 | 44 | a.Last = prediction[0] 45 | return predictFiles(a, pattern, allowFiles) 46 | } 47 | } 48 | 49 | func predictFiles(a Args, pattern string, allowFiles bool) []string { 50 | if strings.HasSuffix(a.Last, "/..") { 51 | return nil 52 | } 53 | 54 | dir := directory(a.Last) 55 | files := listFiles(dir, pattern, allowFiles) 56 | 57 | // add dir if match 58 | files = append(files, dir) 59 | 60 | return PredictFilesSet(files).Predict(a) 61 | } 62 | 63 | // directory gives the directory of the given partial path 64 | // in case that it is not, we fall back to the current directory. 65 | func directory(path string) string { 66 | if info, err := os.Stat(path); err == nil && info.IsDir() { 67 | return fixPathForm(path, path) 68 | } 69 | dir := filepath.Dir(path) 70 | if info, err := os.Stat(dir); err == nil && info.IsDir() { 71 | return fixPathForm(path, dir) 72 | } 73 | return "./" 74 | } 75 | 76 | // PredictFilesSet predict according to file rules to a given set of file names 77 | func PredictFilesSet(files []string) PredictFunc { 78 | return func(a Args) (prediction []string) { 79 | // add all matching files to prediction 80 | for _, f := range files { 81 | f = fixPathForm(a.Last, f) 82 | 83 | // test matching of file to the argument 84 | if matchFile(f, a.Last) { 85 | prediction = append(prediction, f) 86 | } 87 | } 88 | return 89 | } 90 | } 91 | 92 | func listFiles(dir, pattern string, allowFiles bool) []string { 93 | // set of all file names 94 | m := map[string]bool{} 95 | 96 | // list files 97 | if files, err := filepath.Glob(filepath.Join(dir, pattern)); err == nil { 98 | for _, f := range files { 99 | if stat, err := os.Stat(f); err != nil || stat.IsDir() || allowFiles { 100 | m[f] = true 101 | } 102 | } 103 | } 104 | 105 | // list directories 106 | if dirs, err := ioutil.ReadDir(dir); err == nil { 107 | for _, d := range dirs { 108 | if d.IsDir() { 109 | m[filepath.Join(dir, d.Name())] = true 110 | } 111 | } 112 | } 113 | 114 | list := make([]string, 0, len(m)) 115 | for k := range m { 116 | list = append(list, k) 117 | } 118 | return list 119 | } 120 | 121 | // MatchFile returns true if prefix can match the file 122 | func matchFile(file, prefix string) bool { 123 | // special case for current directory completion 124 | if file == "./" && (prefix == "." || prefix == "") { 125 | return true 126 | } 127 | if prefix == "." && strings.HasPrefix(file, ".") { 128 | return true 129 | } 130 | 131 | file = strings.TrimPrefix(file, "./") 132 | prefix = strings.TrimPrefix(prefix, "./") 133 | 134 | return strings.HasPrefix(file, prefix) 135 | } 136 | 137 | // fixPathForm changes a file name to a relative name 138 | func fixPathForm(last string, file string) string { 139 | // get wording directory for relative name 140 | workDir, err := os.Getwd() 141 | if err != nil { 142 | return file 143 | } 144 | 145 | abs, err := filepath.Abs(file) 146 | if err != nil { 147 | return file 148 | } 149 | 150 | // if last is absolute, return path as absolute 151 | if filepath.IsAbs(last) { 152 | return fixDirPath(abs) 153 | } 154 | 155 | rel, err := filepath.Rel(workDir, abs) 156 | if err != nil { 157 | return file 158 | } 159 | 160 | // fix ./ prefix of path 161 | if rel != "." && strings.HasPrefix(last, ".") { 162 | rel = "./" + rel 163 | } 164 | 165 | return fixDirPath(rel) 166 | } 167 | 168 | func fixDirPath(path string) string { 169 | info, err := os.Stat(path) 170 | if err == nil && info.IsDir() && !strings.HasSuffix(path, "/") { 171 | path += "/" 172 | } 173 | return path 174 | } 175 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/posener/complete/predict_set.go: -------------------------------------------------------------------------------- 1 | package complete 2 | 3 | // PredictSet expects specific set of terms, given in the options argument. 4 | func PredictSet(options ...string) Predictor { 5 | return predictSet(options) 6 | } 7 | 8 | type predictSet []string 9 | 10 | func (p predictSet) Predict(a Args) []string { 11 | return p 12 | } 13 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | tmp/ 3 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/.golangci.yml: -------------------------------------------------------------------------------- 1 | # configure golangci-lint 2 | # see https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml 3 | issues: 4 | exclude-use-default: false 5 | exclude-rules: 6 | - path: _test\.go 7 | linters: 8 | - dupl 9 | - gosec 10 | - goconst 11 | - maligned 12 | - text: package comment should be of the form 13 | linters: 14 | - golint 15 | linters: 16 | enable: 17 | - golint 18 | - gosec 19 | - interfacer 20 | - unconvert 21 | - gocyclo 22 | - goconst 23 | - goimports 24 | - maligned 25 | - gocritic 26 | linters-settings: 27 | errcheck: 28 | # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; 29 | # default is false: such cases aren't reported by default. 30 | check-blank: true 31 | govet: 32 | # report about shadowed variables 33 | check-shadowing: true 34 | gocyclo: 35 | # minimal code complexity to report, 30 by default 36 | min-complexity: 15 37 | maligned: 38 | # print struct with more effective memory layout or not, false by default 39 | suggest-new: true -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 WillAbides 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 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/Makefile: -------------------------------------------------------------------------------- 1 | GOCMD=go 2 | GOBUILD=$(GOCMD) build 3 | 4 | bin/bindown: 5 | ./script/bootstrap-bindown.sh -b bin 6 | 7 | bin/gobin: bin/bindown 8 | bin/bindown download $@ 9 | 10 | bin/golangci-lint: bin/bindown 11 | bin/bindown download $@ 12 | 13 | bin/goreadme: bin/gobin 14 | GOBIN=${CURDIR}/bin \ 15 | bin/gobin github.com/posener/goreadme/cmd/goreadme 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -rf ./bin 20 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/README.md: -------------------------------------------------------------------------------- 1 | # kongplete 2 | 3 | You kongplete me. 4 | 5 | kongplete lets you generate shell completions for your command-line programs using 6 | github.com/alecthomas/kong and github.com/posener/complete. 7 | 8 | ## Examples 9 | 10 | ```golang 11 | // This example is adapted from the shell example in github.com/alecthomas/kong 12 | 13 | package main 14 | 15 | import ( 16 | "fmt" 17 | "os" 18 | 19 | "github.com/alecthomas/kong" 20 | "github.com/posener/complete" 21 | "github.com/willabides/kongplete" 22 | ) 23 | 24 | var shellCli struct { 25 | Rm struct { 26 | User string `help:"Run as user." short:"u" default:"default"` 27 | Force bool `help:"Force removal." short:"f"` 28 | Recursive bool `help:"Recursively remove files." short:"r"` 29 | Hidden string `help:"A hidden flag" hidden:""` 30 | 31 | Paths []string `arg:"" help:"Paths to remove." type:"path" name:"path" predictor:"file"` 32 | } `cmd:"" help:"Remove files."` 33 | 34 | Ls struct { 35 | Paths []string `arg:"" optional:"" help:"Paths to list." type:"path" predictor:"file"` 36 | } `cmd:"" help:"List paths."` 37 | 38 | Hidden struct{} `cmd:"" help:"A hidden command" hidden:""` 39 | 40 | Debug bool `help:"Debug mode."` 41 | 42 | InstallCompletions kongplete.InstallCompletions `cmd:"" help:"install shell completions"` 43 | } 44 | 45 | func main() { 46 | // Create a kong parser as usual, but don't run Parse quite yet. 47 | parser := kong.Must(&shellCli, 48 | kong.Name("shell"), 49 | kong.Description("A shell-like example app."), 50 | kong.UsageOnError(), 51 | ) 52 | 53 | // Run kongplete.Complete to handle completion requests 54 | kongplete.Complete(parser, 55 | kongplete.WithPredictor("file", complete.PredictFiles("*")), 56 | ) 57 | 58 | // Proceed as normal after kongplete.Complete. 59 | ctx, err := parser.Parse(os.Args[1:]) 60 | parser.FatalIfErrorf(err) 61 | 62 | switch ctx.Command() { 63 | case "rm ": 64 | fmt.Println(shellCli.Rm.Paths, shellCli.Rm.Force, shellCli.Rm.Recursive) 65 | 66 | case "ls", "hidden": 67 | } 68 | } 69 | 70 | ``` 71 | 72 | --- 73 | Readme created from Go doc with [goreadme](https://github.com/posener/goreadme) 74 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/bindown.yml: -------------------------------------------------------------------------------- 1 | downloaders: 2 | gobin: 3 | - os: darwin 4 | arch: amd64 5 | url: https://github.com/myitcv/gobin/releases/download/v0.0.10/darwin-amd64 6 | checksum: 84ed966949e06bebd7d006bc343caf9d736932fd8b37df5cb5b268a28d07bd30 7 | archive_path: darwin-amd64 8 | - os: linux 9 | arch: amd64 10 | url: https://github.com/myitcv/gobin/releases/download/v0.0.10/linux-amd64 11 | checksum: 415266d9af98578067051653f5057ea267c51ebf085408df48b118a8b978bac6 12 | archive_path: linux-amd64 13 | golangci-lint: 14 | - os: darwin 15 | arch: amd64 16 | url: https://github.com/golangci/golangci-lint/releases/download/v1.35.2/golangci-lint-1.35.2-darwin-amd64.tar.gz 17 | checksum: 1f4666e6a303ba76f5c1ab0592390946668dc83607df96c6caba9c10d58e976f 18 | archive_path: golangci-lint-1.35.2-darwin-amd64/golangci-lint 19 | link: true 20 | - os: linux 21 | arch: amd64 22 | url: https://github.com/golangci/golangci-lint/releases/download/v1.35.2/golangci-lint-1.35.2-linux-amd64.tar.gz 23 | checksum: 8f9ede0ec40beca515b619e6aede57e59b86407e110882fbe3f947f1fa10032d 24 | archive_path: golangci-lint-1.35.2-linux-amd64/golangci-lint 25 | link: true 26 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/doc.go: -------------------------------------------------------------------------------- 1 | //nolint:golint 2 | 3 | /* 4 | You kongplete me. 5 | 6 | kongplete lets you generate shell completions for your command-line programs using 7 | github.com/alecthomas/kong and github.com/posener/complete. 8 | */ 9 | package kongplete 10 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/willabides/kongplete 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/alecthomas/kong v0.2.2 7 | github.com/posener/complete v1.2.3 8 | github.com/stretchr/testify v1.4.0 9 | ) 10 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/kong v0.2.2 h1:sk9ucwuUP/T4+byYEdNU13ZNYzoQRML4IsrMbbUUKLk= 2 | github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 7 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 8 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 9 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 10 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 11 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 12 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 13 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= 15 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 18 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 19 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 20 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 21 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 22 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 23 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 24 | -------------------------------------------------------------------------------- /cosmk/vendor/github.com/willabides/kongplete/internal/positionalpredictor/positional.go: -------------------------------------------------------------------------------- 1 | package positionalpredictor 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/posener/complete" 7 | ) 8 | 9 | // PositionalPredictor is a predictor for positional arguments 10 | type PositionalPredictor struct { 11 | Predictors []complete.Predictor 12 | ArgFlags []string 13 | BoolFlags []string 14 | } 15 | 16 | // Predict implements complete.Predict 17 | func (p *PositionalPredictor) Predict(a complete.Args) []string { 18 | predictor := p.predictor(a) 19 | if predictor == nil { 20 | return []string{} 21 | } 22 | return predictor.Predict(a) 23 | } 24 | 25 | func (p *PositionalPredictor) predictor(a complete.Args) complete.Predictor { 26 | position := p.predictorIndex(a) 27 | complete.Log("predicting positional argument(%d)", position) 28 | if position < 0 || position > len(p.Predictors)-1 { 29 | return nil 30 | } 31 | return p.Predictors[position] 32 | } 33 | 34 | // predictorIndex returns the index in predictors to use. Returns -1 if no predictor should be used. 35 | func (p *PositionalPredictor) predictorIndex(a complete.Args) int { 36 | idx := 0 37 | for i := 0; i < len(a.Completed); i++ { 38 | if !p.nonPredictorPos(a, i) { 39 | idx++ 40 | } 41 | } 42 | return idx 43 | } 44 | 45 | // nonPredictorPos returns true if the value at this position is either a flag or a flag's argument 46 | func (p *PositionalPredictor) nonPredictorPos(a complete.Args, pos int) bool { 47 | if pos < 0 || pos > len(a.All)-1 { 48 | return false 49 | } 50 | val := a.All[pos] 51 | if p.valIsFlag(val) { 52 | return true 53 | } 54 | if pos == 0 { 55 | return false 56 | } 57 | prev := a.All[pos-1] 58 | return p.nextValueIsFlagArg(prev) 59 | } 60 | 61 | // valIsFlag returns true if the value matches a flag from the configuration 62 | func (p *PositionalPredictor) valIsFlag(val string) bool { 63 | val = strings.Split(val, "=")[0] 64 | for _, flag := range p.BoolFlags { 65 | if flag == val { 66 | return true 67 | } 68 | } 69 | for _, flag := range p.ArgFlags { 70 | if flag == val { 71 | return true 72 | } 73 | } 74 | return false 75 | } 76 | 77 | // nextValueIsFlagArg returns true if the value matches an ArgFlag and doesn't contain an equal sign. 78 | func (p *PositionalPredictor) nextValueIsFlagArg(val string) bool { 79 | if strings.Contains(val, "=") { 80 | return false 81 | } 82 | for _, flag := range p.ArgFlags { 83 | if flag == val { 84 | return true 85 | } 86 | } 87 | return false 88 | } 89 | -------------------------------------------------------------------------------- /cosmk/vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/BurntSushi/toml v0.3.1 2 | github.com/BurntSushi/toml 3 | # github.com/alecthomas/kong v0.2.17 4 | github.com/alecthomas/kong 5 | # github.com/hashicorp/errwrap v1.0.0 6 | github.com/hashicorp/errwrap 7 | # github.com/hashicorp/go-multierror v1.0.0 8 | github.com/hashicorp/go-multierror 9 | # github.com/pkg/errors v0.9.1 10 | github.com/pkg/errors 11 | # github.com/posener/complete v1.2.3 12 | github.com/posener/complete 13 | github.com/posener/complete/cmd 14 | github.com/posener/complete/cmd/install 15 | # github.com/willabides/kongplete v0.2.0 16 | github.com/willabides/kongplete 17 | github.com/willabides/kongplete/internal/positionalpredictor 18 | -------------------------------------------------------------------------------- /cosmk/version: -------------------------------------------------------------------------------- 1 | 0.3.2 2 | -------------------------------------------------------------------------------- /helpers/README.md: -------------------------------------------------------------------------------- 1 | # Helper scripts for the CLIP OS project development common tasks 2 | 3 | * Bash/ZSH function helper command for improved `repo forall -c ` output 4 | (warning: `cmd` can not include arguments with spaces): 5 | 6 | ``` 7 | rfa() { 8 | cmd="${@}" 9 | repo forall -j 1 -c "echo \$REPO_PROJECT; ${cmd}; echo ''" 10 | } 11 | ``` 12 | 13 | Warning: 'cmd' can not include arguments with spaces 14 | 15 | * Bash/ZSH function helper command for pretty and selective `repo forall -c 16 | ` output (warning: `cmd` can not include arguments with spaces): 17 | 18 | ``` 19 | rfm() { 20 | cmd="${@}" 21 | repo forall -j 1 -c "${PWD}/toolkit/helpers/filter-most.sh ${cmd}" 22 | } 23 | ``` 24 | 25 | * Update Git remotes with the upstream defined in the manifest: 26 | 27 | ``` 28 | declare-upstreams() { 29 | repo forall "${@}" -c "${PWD}/toolkit/helpers/declare-upstreams.sh" 30 | } 31 | ``` 32 | 33 | * Fetch the Git references from upstream remotes defined with 34 | "declare-upstreams" 35 | 36 | ``` 37 | fetch-upstreams() { 38 | repo forall "${@}" -c "${PWD}/toolkit/helpers/fetch-upstreams.sh" 39 | } 40 | ``` 41 | 42 | * Switch to master branch for all projects: 43 | 44 | ``` 45 | master() {: 46 | repo start master --all 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /helpers/check-lfs-repositories.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | # This script checks that the Git LFS backed repositories (those repositories 6 | # must be part of the repo group "lfs", see the manifest file) have all the Git 7 | # LFS objects properly downloaded and checked out in the working tree. 8 | 9 | set -e -u -o pipefail 10 | 11 | # Do not run as root 12 | if [[ "${EUID}" == 0 ]]; then 13 | >&2 echo "[*] Do not run as root!" 14 | exit 1 15 | fi 16 | 17 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 18 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 19 | 20 | # The absolute path to the repo source tree root (this line depends on the 21 | # location of the script within the repo source tree): 22 | readonly REPOROOT="$(realpath "${SELFPATH}/../..")" 23 | 24 | main() { 25 | local mode='verbose' 26 | while [[ "$#" -gt 0 ]]; do 27 | case "$1" in 28 | -q|--quick) 29 | mode='quick' 30 | shift ;; 31 | -v|--verbose) 32 | mode='verbose' 33 | shift ;; 34 | --) shift; break ;; 35 | *) echo >&2 "ERROR: Unknown option $1"; return 1 ;; 36 | esac 37 | done 38 | 39 | case "${mode}" in 40 | quick) 41 | quick_but_silent_check 42 | ;; 43 | verbose) 44 | verbose_but_slow_check 45 | ;; 46 | *) 47 | echo >&2 "ERROR: Unexpected error" 48 | return 1;; 49 | esac 50 | } 51 | 52 | quick_but_silent_check() { 53 | # shellcheck disable=SC2016 54 | repo forall -g lfs -c 'git lfs ls-files | awk '"'"'($2 != "*") {exit(1)}'"'" 55 | } 56 | 57 | verbose_but_slow_check() { 58 | local return_code=0 59 | 60 | # Get the list of the repo project names that are part of the "lfs" group: 61 | local lfs_projects 62 | # shellcheck disable=SC2016 63 | read -ra lfs_projects <<< "$(repo forall -g lfs -c 'echo "${REPO_PROJECT}"' | xargs)" 64 | echo " [*] ${#lfs_projects[@]} projects in the \"lfs\" repo group:" 65 | echo " ${lfs_projects[*]}" 66 | 67 | local lfs_project 68 | for lfs_project in "${lfs_projects[@]}"; do 69 | # "git lfs ls-files" reports the status of all the Git LFS tracked objects 70 | # in the tree. An asterisk (*) means that the object has been properly 71 | # downloaded in the Git LFS store and checked out in the current working 72 | # tree: 73 | # shellcheck disable=SC2016 74 | if ! repo forall "${lfs_project}" -c 'git lfs ls-files | 75 | awk '"'"'($2 != "*") {exit(1)}'"'"; then 76 | return_code=1 77 | echo >&2 " [-] Missing LFS objects in repo project \"${lfs_project}\"." 78 | fi 79 | done 80 | 81 | if [[ "${return_code}" -ne 0 ]]; then 82 | echo >&2 " [!] Some Git LFS backed repositories are missing Git LFS objects." 83 | echo >&2 " Ensure Git LFS filters are enabled in your environment and fetch the missing" 84 | echo >&2 " files with the command \"git lfs pull\"." 85 | fi 86 | 87 | return "${return_code}" 88 | } 89 | 90 | main "$@" 91 | 92 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 93 | -------------------------------------------------------------------------------- /helpers/declare-upstreams.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | set -e -u -o pipefail 6 | 7 | # Do not run as root 8 | if [[ "${EUID}" == 0 ]]; then 9 | >&2 echo "[*] Do not run as root!" 10 | exit 1 11 | fi 12 | 13 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 14 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 15 | 16 | if [[ -z "${REPO_PATH:-}" ]]; then 17 | cat >&2 <...] -c '${0##*/} [...]' 23 | 24 | Make sure to either use absolute paths for the command to launch or to have 25 | activated the CLIP OS toolkit environment (see the "activate" file) to expose 26 | the CLIP OS toolkit helper scripts in your PATH. This requirement is explained 27 | by the fact that "repo forall" changes the current working directory before 28 | invoking the specified command (commands are invoked from within each repo 29 | project directory). 30 | 31 | See "repo help forall" for more details. The above example is not exhaustive. 32 | EOF 33 | exit 1 34 | fi 35 | 36 | main() { 37 | "${SELFPATH}/eval-annotations.sh" declare-upstreams "$@" 38 | } 39 | 40 | main "$@" 41 | 42 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 43 | -------------------------------------------------------------------------------- /helpers/fetch-upstreams.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | set -e -u -o pipefail 6 | 7 | # Do not run as root 8 | if [[ "${EUID}" == 0 ]]; then 9 | >&2 echo "[*] Do not run as root!" 10 | exit 1 11 | fi 12 | 13 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 14 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 15 | 16 | if [[ -z "${REPO_PATH:-}" ]]; then 17 | cat >&2 <...] -c '${0##*/} [...]' 23 | 24 | Make sure to either use absolute paths for the command to launch or to have 25 | activated the CLIP OS toolkit environment (see the "activate" file) to expose 26 | the CLIP OS toolkit helper scripts in your PATH. This requirement is explained 27 | by the fact that "repo forall" changes the current working directory before 28 | invoking the specified command (commands are invoked from within each repo 29 | project directory). 30 | 31 | See "repo help forall" for more details. The above example is not exhaustive. 32 | EOF 33 | exit 1 34 | fi 35 | 36 | main() { 37 | local return_status=0 38 | 39 | # ensure the remotes are properly declared according to the manifest file 40 | # at best, it ensure they are up-to-date by redeclaring them (it's cheap 41 | # anyway) 42 | "${SELFPATH}/eval-annotations.sh" declare-upstreams "$@" 43 | 44 | local remotes_str remotes 45 | remotes_str="$(git remote | awk '{printf $0" "}')" 46 | # use an array for homogeneity with the rest of the code 47 | read -ra remotes <<< "${remotes_str}" 48 | 49 | # getting the list of upstream remotes 50 | local remote upstream_remotes=() 51 | # shellcheck disable=SC2053 52 | for remote in "${remotes[@]}"; do 53 | if [[ "${remote}" =~ ^upstream[0-9]+$ ]]; then 54 | upstream_remotes+=("${remote}") 55 | fi 56 | done 57 | 58 | # and fetch those remotes 59 | local remote 60 | for remote in "${remotes[@]}"; do 61 | echo "[*] Fetching remote \"${remote}\"..." 62 | # The "--no-tags" option is there to prevent "git fetch" from fetching 63 | # the tags defined on the said remote, which is the default behavior 64 | # even if the tags are not requested in the refspecs for that remote. 65 | # Thus if we did not explicitely specify the tags refs (i.e. 66 | # "refs/tags/*") in the refspecs, the following command do not fetch 67 | # the tags. 68 | if git fetch --no-tags -- "${remote}"; then 69 | echo >&2 "[*] Remote \"${remote}\" successfully fetched for \"${REPO_PATH}\"." 70 | else 71 | echo >&2 "[!] Error has occured when fetching remote \"${remote}\" for \"${REPO_PATH}\" (\"git fetch\" returned $?)." 72 | return_status=1 73 | continue 74 | fi 75 | done 76 | 77 | return "${return_status}" 78 | } 79 | 80 | main "$@" 81 | 82 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 83 | -------------------------------------------------------------------------------- /helpers/filter-most.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | set -e -u -o pipefail 6 | 7 | # Do not run as root 8 | if [[ "${EUID}" == 0 ]]; then 9 | >&2 echo "[*] Do not run as root!" 10 | exit 1 11 | fi 12 | 13 | readonly default="\e[0m" 14 | readonly light_red="\e[91m" 15 | readonly light_green="\e[92m" 16 | readonly light_yellow="\e[93m" 17 | 18 | filter_most() { 19 | # Filter repositories we usually don't want to touch with this command 20 | if [[ "${REPO_PATH}" = "ci/"* 21 | || "${REPO_PATH}" = "manifest" 22 | || "${REPO_PATH}" = "src/external/"* 23 | || "${REPO_PATH}" = "assets/"* 24 | ]]; then 25 | return 26 | fi 27 | printf "${light_yellow}>>${default} ${light_red}%-60.60s${default} | ${light_green}%s${default}\n" \ 28 | "${REPO_PATH}" \ 29 | "$(git rev-parse --abbrev-ref HEAD)" 30 | ${@} 31 | echo 32 | } 33 | 34 | if [[ -z "${REPO_PATH:-}" ]]; then 35 | echo "ERROR: Missing environment variables" >&2 36 | echo "This script must be run with: repo forall [projects...] -c $0 " >&2 37 | exit 1 38 | fi 39 | 40 | filter_most ${@} 41 | 42 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 43 | -------------------------------------------------------------------------------- /helpers/get-cache-from-ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2019 ANSSI. All rights reserved. 4 | 5 | # Safety settings: do not remove! 6 | set -o errexit -o nounset -o pipefail 7 | 8 | # Do not run as root 9 | if [[ "${EUID}" == 0 ]]; then 10 | >&2 echo "[*] Do not run as root!" 11 | exit 1 12 | fi 13 | 14 | # Get build artifacts from CLIP OS CI 15 | 16 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 17 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 18 | 19 | # The absolute path to the repo source tree root (this line depends on the 20 | # location of the script within the repo source tree): 21 | readonly REPOROOT="$(realpath "${SELFPATH}/../..")" 22 | 23 | main() { 24 | if [[ "${#}" -ne 1 ]]; then 25 | >&2 echo "[!] You must specify the URL from which artifacts will be fetched!" 26 | return 1 27 | fi 28 | 29 | local -r url="${1}" 30 | echo "[*] Retrieving artifacts from: ${url}" 31 | 32 | if [[ -z "${CLIPOS_KEEP_ARTIFACTS+x}" ]]; then 33 | >&2 echo "[!] Downloaded artifacts archives will be removed once extracted." 34 | >&2 echo " To keep them, set the CLIPOS_KEEP_ARTIFACTS environment variable." 35 | fi 36 | 37 | # Make sure that we are at the repo root 38 | cd "${REPOROOT}" 39 | 40 | # List of artifacts to retrieve (Core & EFIboot packages) 41 | artifacts=( 42 | 'core_pkgs.tar.zst' 43 | 'efiboot_pkgs.tar.zst' 44 | ) 45 | 46 | # Retrieve artifacts 47 | for a in "${artifacts[@]}"; do 48 | echo "[*] Downloading ${a}..." 49 | curl --proto '=https' --tlsv1.2 -sSf -o "${a}" "${url}/${a}" 50 | done 51 | 52 | # Retrieve the SHA256SUMS file and check artifacts integrity 53 | curl --proto '=https' --tlsv1.2 -sSf -o 'SHA256SUMS.full' "${url}/SHA256SUMS" 54 | 55 | # Only keep relevant checksums to avoid issues 56 | > 'SHA256SUMS' 57 | for a in "${artifacts[@]}"; do 58 | grep "${a}" 'SHA256SUMS.full' >> 'SHA256SUMS' 59 | done 60 | rm 'SHA256SUMS.full' 61 | 62 | echo "[*] Verifying artifacts integrity..." 63 | sha256sum -c 'SHA256SUMS' 64 | 65 | # Extract artifacts 66 | for a in "${artifacts[@]}"; do 67 | echo "[*] Extracting ${a}..." 68 | tar --extract --file "${a}" --warning=no-unknown-keyword 69 | done 70 | 71 | if [[ -z "${CLIPOS_KEEP_ARTIFACTS+x}" ]]; then 72 | for a in "${artifacts[@]}"; do 73 | echo "[*] Removing ${a}..." 74 | rm ${a} 75 | done 76 | echo "[*] Removing SHA256SUMS..." 77 | rm SHA256SUMS 78 | else 79 | echo "[*] You may now remove all downloaded artifacts with:" 80 | echo " $ rm ${artifacts[@]} SHA256SUMS" 81 | fi 82 | 83 | echo "[*] Success!" 84 | } 85 | 86 | main "$@" 87 | 88 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 89 | -------------------------------------------------------------------------------- /helpers/vendor-gentoo-stage3.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2019 ANSSI. All rights reserved. 4 | 5 | # Safety settings: do not remove! 6 | set -o errexit -o nounset -o pipefail 7 | 8 | # Do not run as root 9 | if [[ "${EUID}" == 0 ]]; then 10 | >&2 echo "[*] Do not run as root!" 11 | exit 1 12 | fi 13 | 14 | main() { 15 | if [[ -z "$(command -v cosmk)" ]]; then 16 | >&2 echo "[!] Could not find \"cosmk\". Aborting." 17 | exit 1 18 | fi 19 | local -r repo_root="$(cosmk repo-root-path)" 20 | 21 | # Full path to the vendor dirs: 22 | local -r vendor="${repo_root}/assets/gentoo" 23 | 24 | local -r base_url='http://distfiles.gentoo.org/releases/amd64/autobuilds' 25 | 26 | local -r kind='stage3-amd64-hardened+nomultilib' 27 | local -r image='localhost/gentoo/hardened' 28 | 29 | local -r latest_url="${base_url}/latest-${kind}.txt" 30 | 31 | echo "[*] Looking for latest version for ${kind}..." 32 | local -r url="$(curl -sSf "${latest_url}" | grep -v "^#" | cut -d\ -f 1)" 33 | local -r version="$(echo ${url} | cut -d/ -f 1)" 34 | 35 | pushd "${vendor}" > /dev/null 36 | 37 | # Is this stage3 already available? 38 | local -r dest="${kind}-${version}.tar.xz" 39 | if [[ -f "${dest}" ]]; then 40 | echo "[*] ${kind} image for version ${version} already available" 41 | echo "[*] Done" 42 | exit 0 43 | fi 44 | 45 | echo "[*] Downloading ${kind} ${version}..." 46 | curl "${base_url}/${url}" --output "${dest}" 47 | curl "${base_url}/${url}.DIGESTS.asc" --output "${dest}.DIGESTS.asc" 48 | 49 | echo "[*] Verifying ${kind} ${version}..." 50 | gpg --verify "${dest}.tar.xz.DIGESTS.asc" "${dest}" 51 | # Ignore WHIRLPOOL hashes & check only the file that matter 52 | sed '/WHIRLPOOL/,+1 d' "${dest}.DIGESTS.asc" \ 53 | | grep "${dest}" \ 54 | | sha512sum -c --ignore-missing 55 | 56 | popd > /dev/null 57 | } 58 | 59 | main "${@}" 60 | 61 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 62 | -------------------------------------------------------------------------------- /helpers/verify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | set -e -u -o pipefail 6 | 7 | # Do not run as root 8 | if [[ "${EUID}" == 0 ]]; then 9 | >&2 echo "[*] Do not run as root!" 10 | exit 1 11 | fi 12 | 13 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 14 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 15 | 16 | if [[ -z "${REPO_PATH:-}" ]]; then 17 | cat >&2 <...] -c '${0##*/} [...]' 23 | 24 | Make sure to either use absolute paths for the command to launch or to have 25 | activated the CLIP OS toolkit environment (see the "activate" file) to expose 26 | the CLIP OS toolkit helper scripts in your PATH. This requirement is explained 27 | by the fact that "repo forall" changes the current working directory before 28 | invoking the specified command (commands are invoked from within each repo 29 | project directory). 30 | 31 | See "repo help forall" for more details. The above example is not exhaustive. 32 | EOF 33 | exit 1 34 | fi 35 | 36 | main() { 37 | "${SELFPATH}/eval-annotations.sh" verify "$@" 38 | } 39 | 40 | main "$@" 41 | 42 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 43 | -------------------------------------------------------------------------------- /helpers/yield-branches-from-remote.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | set -e -u -o pipefail 6 | 7 | # Do not run as root 8 | if [[ "${EUID}" == 0 ]]; then 9 | >&2 echo "[*] Do not run as root!" 10 | exit 1 11 | fi 12 | 13 | readonly SELFNAME="${BASH_SOURCE[0]##*/}" 14 | readonly SELFPATH="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" 15 | 16 | if [[ -z "${REPO_PATH:-}" ]]; then 17 | cat >&2 <...] -c '${0##*/} [...]' 23 | 24 | Make sure to either use absolute paths for the command to launch or to have 25 | activated the CLIP OS toolkit environment (see the "activate" file) to expose 26 | the CLIP OS toolkit helper scripts in your PATH. This requirement is explained 27 | by the fact that "repo forall" changes the current working directory before 28 | invoking the specified command (commands are invoked from within each repo 29 | project directory). 30 | 31 | See "repo help forall" for more details. The above example is not exhaustive. 32 | EOF 33 | exit 1 34 | fi 35 | 36 | main() { 37 | local return_status=0 38 | 39 | # This is the remote name declared in the manifest file for the current 40 | # project/repository: 41 | local default_remote="${REPO_REMOTE}" 42 | 43 | # Query Git to retrieve all the available refs into an array 44 | local all_refs_str all_refs 45 | all_refs_str="$(git show-ref | awk '{ printf $2" "}')" 46 | # use an array for homogeneity with the rest of the code 47 | read -ra all_refs <<< "${all_refs_str}" 48 | 49 | # Retrieve the names of the branches defined in the default remote from the 50 | # refs/remotes/* references (this is done automatically by Git and is the 51 | # default behavior): 52 | local branch_names_to_yield=() 53 | local ref 54 | for ref in "${all_refs[@]}"; do 55 | if [[ "${ref}" =~ ^"refs/remotes/${default_remote}/" ]]; then 56 | branch_names_to_yield+=("${ref#"refs/remotes/${default_remote}/"}") 57 | fi 58 | done 59 | local branch localbr remotebr 60 | for branch in "${branch_names_to_yield[@]}"; do 61 | # Take care to the behavior of "git rev-parse": this command may return 62 | # an invalid symbolic ref (with a non-null status code, which is 63 | # voluntarily discarded here) and create a bug with the test further 64 | # down. The option "--verify" is absolutely needed here. 65 | localbr="$(git rev-parse --verify --quiet "refs/heads/${branch}" || :)" 66 | remotebr="$(git rev-parse --verify --quiet "refs/remotes/${default_remote}/${branch}" || :)" 67 | # Do not attempt to recreate a branch that already exists and point to 68 | # the same revision (avoids useless noise in the output logs): 69 | if [[ -n "${localbr}" ]]; then 70 | if [[ "${localbr}" == "${remotebr}" ]]; then 71 | continue # all is good, skip over this branch name 72 | else 73 | echo >&2 "[!] Branch \"${branch}\" already exist on \"${REPO_PATH}\" and its revision does not match its equivalent on the remote \"${default_remote}\"." 74 | return_status=1 75 | continue 76 | fi 77 | else 78 | # Recreate the branches locally from the remotes branch refs. 79 | # Please note that according to git-branch(1), doing so 80 | # automatically sets the appropriate remote tracking branch to the 81 | # settings of the newly created local branch: 82 | if ! git branch "${branch}" "refs/remotes/${default_remote}/${branch}"; then 83 | echo >&2 "[!] Failed creating local branch \"${branch}\" for \"${REPO_PATH}\" (\"git branch\" returned $?)." 84 | return_status=1 85 | fi 86 | fi 87 | done 88 | 89 | return "${return_status}" 90 | } 91 | 92 | main "$@" 93 | 94 | # vim: set ts=4 sts=4 sw=4 et ft=sh: 95 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright © 2017 ANSSI. All rights reserved. 4 | 5 | # Little foolproof check to avoid messing up the interactive shell of the 6 | # inattentive user who does a "source toolkit/setup.sh" after a failed call to 7 | # "source toolkit/activate" that invited him/her to call (but NOT sourced!) 8 | # this present script before proceeding. 9 | if [[ "${BASH_SOURCE[0]:-}" != "${0:-}" ]]; then 10 | echo >&2 "Warning! This script is not meant to be sourced. Call it normally like any other executable shell script." 11 | return 1 12 | fi 13 | 14 | # Safety settings: do not remove! 15 | set -o errexit -o nounset -o pipefail 16 | 17 | # Get the basename of this program and the directory path to itself 18 | readonly PROGNAME="${BASH_SOURCE[0]##*/}" 19 | readonly PROGPATH="$(realpath "${BASH_SOURCE[0]%/*}")" 20 | 21 | # Check if not running as root 22 | if [[ "$(id -u)" -eq 0 ]]; then 23 | echo >&2 "You should not be running this as root. Aborting." 24 | exit 1 25 | fi 26 | 27 | main() { 28 | echo "[+] Building cosmk..." 29 | pushd "${PROGPATH}/cosmk" > /dev/null 30 | go build -o cosmk -mod=vendor -ldflags "-X main.version=$(cat version | tr -d '\n')" ./src 31 | popd > /dev/null 32 | 33 | local -r reporoot="$(realpath ${PROGPATH}/../)" 34 | 35 | pushd "${reporoot}" > /dev/null 36 | mkdir -p run/bin 37 | mv "toolkit/cosmk/cosmk" "run/bin/cosmk" 38 | popd > /dev/null 39 | 40 | # Symlink the helper scripts available in the toolkit's "helpers" directory 41 | # in the "run/bin" directory in order to make them appear via PATH. 42 | # This eases the ability to call those scripts for the user (espcially for 43 | # the scripts intended to be used with "repo forall" as repo changes the 44 | # CWD). 45 | echo "[*] Installing helpers..." 46 | for item in "${PROGPATH}/helpers/"*; do 47 | if [[ -x "${item}" ]]; then 48 | # Assuming GNU coreutils for the "--relative-to" option of realpath 49 | ln -snf \ 50 | "$(realpath --relative-to="${reporoot}/run/bin" "${item}")" \ 51 | "${reporoot}/run/bin/${item##*/}" 52 | fi 53 | done 54 | unset item 55 | 56 | cat >&2 <