diff --git a/autocomplete/completion.go b/autocomplete/completion.go index f1001fd..64c833e 100644 --- a/autocomplete/completion.go +++ b/autocomplete/completion.go @@ -122,7 +122,7 @@ func getSubcommandDrivenRecommendation(spec model.Subcommand, persistentOptions } if len(spec.Args) != 0 { activeArg := spec.Args[0] - getGeneratorDrivenRecommendations(activeArg.Generator, &suggestions, partialToken, spec.FilterStrategy) + getGeneratorDrivenRecommendations(activeArg.Generator, &suggestions, partialToken, spec.FilterStrategy, acceptedTokens) getSuggestionDrivenRecommendations(activeArg.Suggestions, &suggestions, partialToken, spec.FilterStrategy) getTemplateDrivenRecommendations(activeArg.Templates, &suggestions, partialToken, spec.FilterStrategy) } @@ -146,7 +146,7 @@ func getArgDrivenRecommendation(args []model.Arg, spec model.Subcommand, persist partialToken = &partialCmd.token } - getGeneratorDrivenRecommendations(activeArg.Generator, &suggestions, partialToken, activeArg.FilterStrategy) + getGeneratorDrivenRecommendations(activeArg.Generator, &suggestions, partialToken, activeArg.FilterStrategy, acceptedTokens) getSuggestionDrivenRecommendations(activeArg.Suggestions, &suggestions, partialToken, activeArg.FilterStrategy) getTemplateDrivenRecommendations(activeArg.Templates, &suggestions, partialToken, activeArg.FilterStrategy) @@ -249,7 +249,7 @@ func handleArg(tokens []commandToken, args []model.Arg, spec model.Subcommand, p } return } - return handleArg(tokens[1:], args[1:], spec, persistentOptions, getPersistentTokens(acceptedTokens), fromOption) + return handleArg(tokens[1:], args[1:], spec, persistentOptions, acceptedTokens, fromOption) } func loadSuggestions(cmd string) (suggestions model.TermSuggestions, charsInLastCmd int) { diff --git a/autocomplete/generators/ai.go b/autocomplete/generators/ai.go index ec87758..551c2d0 100644 --- a/autocomplete/generators/ai.go +++ b/autocomplete/generators/ai.go @@ -140,7 +140,7 @@ func request(name, prompt, message, splitOn string) []model.TermSuggestion { func AI(name string, prompt PromptFunction, message MessageFunction, splitOn string) *model.Generator { return &model.Generator{ Id: uuid.New(), - Function: func() []model.TermSuggestion { + Function: func(_ []string) []model.TermSuggestion { suggestions := []model.TermSuggestion{} if !enabled() { return suggestions diff --git a/autocomplete/generators/azure/azure.go b/autocomplete/generators/azure/azure.go index f8de3e3..85e4547 100644 --- a/autocomplete/generators/azure/azure.go +++ b/autocomplete/generators/azure/azure.go @@ -1,68 +1,85 @@ package azure import ( - "context" "encoding/json" + "fmt" "log/slog" "os/exec" + "strings" - "github.com/Azure/azure-sdk-for-go/sdk/azidentity" - "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault" "github.com/cpendery/clac/autocomplete/model" "github.com/google/uuid" ) -type azShowAccountResponse struct { - SubscriptionName *string `json:"name,omitempty"` +type azListKeyvaultsResponse struct { + VaultName *string `json:"name,omitempty"` } -func getActiveSubscription() *string { - output, err := exec.Command("az", "show", "account", "-o", "json").Output() - if err != nil { - slog.Error("az account information command failed", slog.String("error", err.Error())) - return nil - } - var accountInfo azShowAccountResponse - if err := json.Unmarshal(output, &accountInfo); err != nil { - slog.Error("az account information command provided invalid output", slog.String("error", err.Error())) - return nil - } - return accountInfo.SubscriptionName +type azListKeyvaultKeysResponse struct { + KeyName *string `json:"name,omitempty"` } var ListKeyVaultsGenerator = &model.Generator{ - Id: uuid.New(), - Function: func() []model.TermSuggestion { + Id: uuid.New(), + Script: "az keyvault list -o json", + PostProcess: func(s string) []model.TermSuggestion { suggestions := []model.TermSuggestion{} - subscription := getActiveSubscription() - if subscription == nil { + + vaults := []azListKeyvaultsResponse{} + if err := json.Unmarshal([]byte(s), &vaults); err != nil { + slog.Error("unable to load list keyvault response", slog.String("error", err.Error())) return suggestions } - cred, err := azidentity.NewDefaultAzureCredential(nil) - if err != nil { - slog.Error("unable to load azure default credentials", slog.String("error", err.Error())) - return suggestions - } - client, err := armkeyvault.NewVaultsClient(*subscription, cred, nil) - if err != nil { - slog.Error("unable to create new azure vaults client", slog.String("error", err.Error())) - return suggestions - } - pager := client.NewListPager(nil) - for pager.More() { - page, err := pager.NextPage(context.Background()) - if err != nil { - slog.Error("unable to request new page of vaults", slog.String("error", err.Error())) - return suggestions - } - for _, vault := range page.Value { - if vault.Name != nil { - suggestions = append(suggestions, model.TermSuggestion{ - Name: *vault.Name, - Description: "Azure Key Vault", - }) - } + + for _, vault := range vaults { + if vault.VaultName == nil { + continue } + suggestions = append(suggestions, model.TermSuggestion{ + Name: `"` + *vault.VaultName + `"`, + Description: "Azure Key Vault", + }) + } + return suggestions + }, +} + +var ListKeyVaultsKeysGenerator = &model.Generator{ + Id: uuid.New(), + SkipCache: true, + Function: func(cmdTokens []string) []model.TermSuggestion { + suggestions := []model.TermSuggestion{} + var vaultName *string = nil + for idx, token := range cmdTokens { + if strings.TrimSpace(token) == "--vault-name" && idx+1 < len(cmdTokens) { + vaultName = &cmdTokens[idx+1] + } + } + + if vaultName == nil { + return suggestions + } + + output, err := exec.Command("az", fmt.Sprintf("keyvault key list --vault-name %s -o json", *vaultName)).Output() + if err != nil { + slog.Error("unable to request list keys", slog.String("error", err.Error())) + return suggestions + } + keys := []azListKeyvaultKeysResponse{} + + if err := json.Unmarshal([]byte(output), &keys); err != nil { + slog.Error("unable to load list keys response", slog.String("error", err.Error())) + return suggestions + } + + for _, key := range keys { + if key.KeyName == nil { + continue + } + suggestions = append(suggestions, model.TermSuggestion{ + Name: `"` + *key.KeyName + `"`, + Description: "Azure Key Vault", + }) } return suggestions }, diff --git a/autocomplete/generators/generator.go b/autocomplete/generators/generator.go index e1369a3..184f4cf 100644 --- a/autocomplete/generators/generator.go +++ b/autocomplete/generators/generator.go @@ -13,8 +13,8 @@ var ( generatorCache = make(map[uuid.UUID][]model.TermSuggestion) ) -func Run(g model.Generator) []model.TermSuggestion { - if cachedSuggestions, executed := generatorCache[g.Id]; executed { +func Run(g model.Generator, token []string) []model.TermSuggestion { + if cachedSuggestions, executed := generatorCache[g.Id]; executed && !g.SkipCache { return cachedSuggestions } suggestions := []model.TermSuggestion{} @@ -42,7 +42,7 @@ func Run(g model.Generator) []model.TermSuggestion { } if g.Function != nil { - suggestions = append(suggestions, g.Function()...) + suggestions = append(suggestions, g.Function(token)...) } suggestions = append(suggestions, RunTemplates(g.Template)...) diff --git a/autocomplete/model/model.go b/autocomplete/model/model.go index 4eaa6f3..31dd28b 100644 --- a/autocomplete/model/model.go +++ b/autocomplete/model/model.go @@ -67,10 +67,11 @@ type ProcessedToken struct { type Generator struct { Id uuid.UUID Script string - Function func() []TermSuggestion + Function func([]string) []TermSuggestion PostProcess func(string) []TermSuggestion Template []Template SplitOn string + SkipCache bool } type Template string diff --git a/autocomplete/specs/azure.go b/autocomplete/specs/azure.go index 90f422e..9c78daf 100644 --- a/autocomplete/specs/azure.go +++ b/autocomplete/specs/azure.go @@ -85,7 +85,7 @@ func init() { {Name: []string{"show"}, Description: "Get a key's attributes and, if it's an asymmetric key, its public material.", Options: []model.Option{ {Name: []string{"--id"}, Description: "Id of the key. If specified all other 'Id' arguments should be omitted."}, {Name: []string{"--name", "-n"}, Description: "Name of the key. Required if --id is not specified", Args: []model.Arg{ - {Name: "key name"}, + {Name: "key name", Generator: azure.ListKeyVaultsKeysGenerator}, }}, {Name: []string{"--vault-name"}, Description: "Name of the Vault.", Args: []model.Arg{ {Name: "vault name", Generator: azure.ListKeyVaultsGenerator}, diff --git a/autocomplete/suggestions.go b/autocomplete/suggestions.go index 17dfae1..0441400 100644 --- a/autocomplete/suggestions.go +++ b/autocomplete/suggestions.go @@ -91,11 +91,15 @@ func filterMatch[M matchable](items []M, suggestions *[]model.TermSuggestion, in } } -func getGeneratorDrivenRecommendations(g *model.Generator, suggestions *[]model.TermSuggestion, input *string, filterStrategy model.FilterStrategy) { +func getGeneratorDrivenRecommendations(g *model.Generator, suggestions *[]model.TermSuggestion, input *string, filterStrategy model.FilterStrategy, processedTokens []model.ProcessedToken) { if g == nil { return } - filterMatch[model.TermSuggestion](generators.Run(*g), suggestions, input, filterStrategy) + termTokens := []string{} + for _, t := range processedTokens { + termTokens = append(termTokens, t.Token) + } + filterMatch[model.TermSuggestion](generators.Run(*g, termTokens), suggestions, input, filterStrategy) } func getTemplateDrivenRecommendations(templates []model.Template, suggestions *[]model.TermSuggestion, input *string, filterStrategy model.FilterStrategy) { diff --git a/go.mod b/go.mod index 216ef4a..39afe04 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,6 @@ module github.com/cpendery/clac go 1.21.0 require ( - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0 github.com/adrg/xdg v0.4.0 github.com/charmbracelet/bubbles v0.16.1 github.com/charmbracelet/bubbletea v0.24.2 @@ -19,28 +17,20 @@ require ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.15.2 // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/go.sum b/go.sum index d8041b7..45c8d40 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,3 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0 h1:8d4U82r7ItT1Es91x3eUcAQweih36KWvUha8AZ9X0Rs= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0/go.mod h1:/1bkGperHinQbAHMWivoec/Ucu6//iXo6jn5mhmqCVU= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= @@ -30,16 +16,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -59,8 +39,6 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -78,16 +56,12 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -95,7 +69,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -123,8 +96,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=