A few fixes

* CLI properly formats the IP addresses in runner show
  * LXD provider now waits for an IP address before returning on Create
  * Added a few mocks for testing

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2022-07-10 14:52:15 +00:00
parent afb1d31394
commit 5566cde77f
46 changed files with 8829 additions and 6 deletions

View file

@ -218,7 +218,7 @@ func formatSingleInstance(instance params.Instance) {
if len(instance.Addresses) > 0 { if len(instance.Addresses) > 0 {
for _, addr := range instance.Addresses { for _, addr := range instance.Addresses {
t.AppendRow(table.Row{"Addresses", addr}, table.RowConfig{AutoMerge: true}) t.AppendRow(table.Row{"Addresses", addr.Address}, table.RowConfig{AutoMerge: true})
} }
} }

6
go.mod
View file

@ -11,6 +11,8 @@ require (
github.com/gorilla/handlers v1.5.1 github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/jedib0t/go-pretty/v6 v6.3.1 github.com/jedib0t/go-pretty/v6 v6.3.1
github.com/juju/clock v0.0.0-20220704231616-a2b96c8eeb27
github.com/juju/retry v0.0.0-20220204093819-62423bf33287
github.com/lxc/lxd v0.0.0-20220415052741-1170f2806124 github.com/lxc/lxd v0.0.0-20220415052741-1170f2806124
github.com/manifoldco/promptui v0.9.0 github.com/manifoldco/promptui v0.9.0
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
@ -41,6 +43,7 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/juju/errors v0.0.0-20220328032053-6664a20db930 // indirect
github.com/juju/webbrowser v1.0.0 // indirect github.com/juju/webbrowser v1.0.0 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
@ -56,11 +59,12 @@ require (
github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/errgo.v1 v1.0.1 // indirect gopkg.in/errgo.v1 v1.0.1 // indirect
gopkg.in/httprequest.v1 v1.2.1 // indirect gopkg.in/httprequest.v1 v1.2.1 // indirect
gopkg.in/macaroon-bakery.v2 v2.3.0 // indirect gopkg.in/macaroon-bakery.v2 v2.3.0 // indirect

20
go.sum
View file

@ -156,12 +156,26 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/juju/clock v0.0.0-20220704231616-a2b96c8eeb27 h1:tzBYJiWEx2HcWUSdfBzdj9+FTQGWzsuSiiYgutZl2kA=
github.com/juju/clock v0.0.0-20220704231616-a2b96c8eeb27/go.mod h1:GZ/FY8Cqw3KHG6DwRVPUKbSPTAwyrU28xFi5cqZnLsc=
github.com/juju/collections v0.0.0-20220203020748-febd7cad8a7a h1:d7eZO8OS/ZXxdP0uq3E8CdoA1qNFaecAv90UxrxaY2k=
github.com/juju/errors v0.0.0-20220328032053-6664a20db930 h1:NavIEjCH2y/svEZ8mOSnFofpFeiAQTzUpByc28R6Hhc=
github.com/juju/errors v0.0.0-20220328032053-6664a20db930/go.mod h1:jMGj9DWF/qbo91ODcfJq6z/RYc3FX3taCBZMCcpI4Ls=
github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 h1:NO5tuyw++EGLnz56Q8KMyDZRwJwWO8jQnj285J3FOmY=
github.com/juju/mgo/v2 v2.0.0-20220111072304-f200228f1090 h1:zX5GoH3Jp8k1EjUFkApu/YZAYEn0PYQfg/U6IDyNyYs=
github.com/juju/mgotest v1.0.1/go.mod h1:vTaDufYul+Ps8D7bgseHjq87X8eu0ivlKLp9mVc/Bfc= github.com/juju/mgotest v1.0.1/go.mod h1:vTaDufYul+Ps8D7bgseHjq87X8eu0ivlKLp9mVc/Bfc=
github.com/juju/postgrestest v1.1.0/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM= github.com/juju/postgrestest v1.1.0/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM=
github.com/juju/qthttptest v0.0.1/go.mod h1://LCf/Ls22/rPw2u1yWukUJvYtfPY4nYpWUl2uZhryo= github.com/juju/qthttptest v0.0.1/go.mod h1://LCf/Ls22/rPw2u1yWukUJvYtfPY4nYpWUl2uZhryo=
github.com/juju/qthttptest v0.1.1 h1:JPju5P5CDMCy8jmBJV2wGLjDItUsx2KKL514EfOYueM= github.com/juju/qthttptest v0.1.1 h1:JPju5P5CDMCy8jmBJV2wGLjDItUsx2KKL514EfOYueM=
github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4= github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4=
github.com/juju/retry v0.0.0-20220204093819-62423bf33287 h1:U+7oMWEglXfiikIppNexButZRwKPlzLBGKYSNCXzXf8=
github.com/juju/retry v0.0.0-20220204093819-62423bf33287/go.mod h1:SssN1eYeK3A2qjnFGTiVMbdzGJ2BfluaJblJXvuvgqA=
github.com/juju/schema v1.0.0/go.mod h1:Y+ThzXpUJ0E7NYYocAbuvJ7vTivXfrof/IfRPq/0abI= github.com/juju/schema v1.0.0/go.mod h1:Y+ThzXpUJ0E7NYYocAbuvJ7vTivXfrof/IfRPq/0abI=
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 h1:XEDzpuZb8Ma7vLja3+5hzUqVTvAqm5Y+ygvnDs5iTMM=
github.com/juju/utils v0.0.0-20200604140309-9d78121a29e0 h1:4XlJ/Wj/bH3zGa2GU+Us72FgtmL1n3dwjP7LW7+TF/o=
github.com/juju/utils/v3 v3.0.0-20220203023959-c3fbc78a33b0 h1:bn+2Adl1yWqYjm3KSFlFqsvfLg2eq+XNL7GGMYApdVw=
github.com/juju/version v0.0.0-20210303051006-2015802527a8 h1:BTo6HzRR0zPBcXbs1Sy08aQNfvdm3ey8O+mBTiO3g00=
github.com/juju/version/v2 v2.0.0-20211007103408-2e8da085dc23 h1:wtEPbidt1VyHlb8RSztU6ySQj29FLsOQiI9XiJhXDM4=
github.com/juju/webbrowser v0.0.0-20160309143629-54b8c57083b4/go.mod h1:G6PCelgkM6cuvyD10iYJsjLBsSadVXtJ+nBxFAxE2BU= github.com/juju/webbrowser v0.0.0-20160309143629-54b8c57083b4/go.mod h1:G6PCelgkM6cuvyD10iYJsjLBsSadVXtJ+nBxFAxE2BU=
github.com/juju/webbrowser v1.0.0 h1:JLdmbFtCGY6Qf2jmS6bVaenJFGIFkdF1/BjUm76af78= github.com/juju/webbrowser v1.0.0 h1:JLdmbFtCGY6Qf2jmS6bVaenJFGIFkdF1/BjUm76af78=
github.com/juju/webbrowser v1.0.0/go.mod h1:RwVlbBcF91Q4vS+iwlkJ6bZTE3EwlrjbYlM3WMVD6Bc= github.com/juju/webbrowser v1.0.0/go.mod h1:RwVlbBcF91Q4vS+iwlkJ6bZTE3EwlrjbYlM3WMVD6Bc=
@ -225,6 +239,7 @@ github.com/spf13/cobra v1.4.1-0.20220504202302-9e88759b19cd/go.mod h1:Wo4iy3BUC+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -233,6 +248,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -371,6 +388,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -504,7 +523,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso= gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=

View file

@ -0,0 +1,268 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
context "context"
github "github.com/google/go-github/v43/github"
mock "github.com/stretchr/testify/mock"
)
// GithubClient is an autogenerated mock type for the GithubClient type
type GithubClient struct {
mock.Mock
}
// CreateOrganizationRegistrationToken provides a mock function with given fields: ctx, owner
func (_m *GithubClient) CreateOrganizationRegistrationToken(ctx context.Context, owner string) (*github.RegistrationToken, *github.Response, error) {
ret := _m.Called(ctx, owner)
var r0 *github.RegistrationToken
if rf, ok := ret.Get(0).(func(context.Context, string) *github.RegistrationToken); ok {
r0 = rf(ctx, owner)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.RegistrationToken)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok {
r1 = rf(ctx, owner)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
r2 = rf(ctx, owner)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// CreateRegistrationToken provides a mock function with given fields: ctx, owner, repo
func (_m *GithubClient) CreateRegistrationToken(ctx context.Context, owner string, repo string) (*github.RegistrationToken, *github.Response, error) {
ret := _m.Called(ctx, owner, repo)
var r0 *github.RegistrationToken
if rf, ok := ret.Get(0).(func(context.Context, string, string) *github.RegistrationToken); ok {
r0 = rf(ctx, owner, repo)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.RegistrationToken)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string, string) *github.Response); ok {
r1 = rf(ctx, owner, repo)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok {
r2 = rf(ctx, owner, repo)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// ListOrganizationRunnerApplicationDownloads provides a mock function with given fields: ctx, owner
func (_m *GithubClient) ListOrganizationRunnerApplicationDownloads(ctx context.Context, owner string) ([]*github.RunnerApplicationDownload, *github.Response, error) {
ret := _m.Called(ctx, owner)
var r0 []*github.RunnerApplicationDownload
if rf, ok := ret.Get(0).(func(context.Context, string) []*github.RunnerApplicationDownload); ok {
r0 = rf(ctx, owner)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*github.RunnerApplicationDownload)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok {
r1 = rf(ctx, owner)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
r2 = rf(ctx, owner)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// ListOrganizationRunners provides a mock function with given fields: ctx, owner, opts
func (_m *GithubClient) ListOrganizationRunners(ctx context.Context, owner string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
ret := _m.Called(ctx, owner, opts)
var r0 *github.Runners
if rf, ok := ret.Get(0).(func(context.Context, string, *github.ListOptions) *github.Runners); ok {
r0 = rf(ctx, owner, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.Runners)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string, *github.ListOptions) *github.Response); ok {
r1 = rf(ctx, owner, opts)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, *github.ListOptions) error); ok {
r2 = rf(ctx, owner, opts)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// ListRunnerApplicationDownloads provides a mock function with given fields: ctx, owner, repo
func (_m *GithubClient) ListRunnerApplicationDownloads(ctx context.Context, owner string, repo string) ([]*github.RunnerApplicationDownload, *github.Response, error) {
ret := _m.Called(ctx, owner, repo)
var r0 []*github.RunnerApplicationDownload
if rf, ok := ret.Get(0).(func(context.Context, string, string) []*github.RunnerApplicationDownload); ok {
r0 = rf(ctx, owner, repo)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*github.RunnerApplicationDownload)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string, string) *github.Response); ok {
r1 = rf(ctx, owner, repo)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok {
r2 = rf(ctx, owner, repo)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// ListRunners provides a mock function with given fields: ctx, owner, repo, opts
func (_m *GithubClient) ListRunners(ctx context.Context, owner string, repo string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
ret := _m.Called(ctx, owner, repo, opts)
var r0 *github.Runners
if rf, ok := ret.Get(0).(func(context.Context, string, string, *github.ListOptions) *github.Runners); ok {
r0 = rf(ctx, owner, repo, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.Runners)
}
}
var r1 *github.Response
if rf, ok := ret.Get(1).(func(context.Context, string, string, *github.ListOptions) *github.Response); ok {
r1 = rf(ctx, owner, repo, opts)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*github.Response)
}
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, string, *github.ListOptions) error); ok {
r2 = rf(ctx, owner, repo, opts)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// RemoveOrganizationRunner provides a mock function with given fields: ctx, owner, runnerID
func (_m *GithubClient) RemoveOrganizationRunner(ctx context.Context, owner string, runnerID int64) (*github.Response, error) {
ret := _m.Called(ctx, owner, runnerID)
var r0 *github.Response
if rf, ok := ret.Get(0).(func(context.Context, string, int64) *github.Response); ok {
r0 = rf(ctx, owner, runnerID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.Response)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
r1 = rf(ctx, owner, runnerID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RemoveRunner provides a mock function with given fields: ctx, owner, repo, runnerID
func (_m *GithubClient) RemoveRunner(ctx context.Context, owner string, repo string, runnerID int64) (*github.Response, error) {
ret := _m.Called(ctx, owner, repo, runnerID)
var r0 *github.Response
if rf, ok := ret.Get(0).(func(context.Context, string, string, int64) *github.Response); ok {
r0 = rf(ctx, owner, repo, runnerID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*github.Response)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, string, int64) error); ok {
r1 = rf(ctx, owner, repo, runnerID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
type mockConstructorTestingTNewGithubClient interface {
mock.TestingT
Cleanup(func())
}
// NewGithubClient creates a new instance of GithubClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewGithubClient(t mockConstructorTestingTNewGithubClient) *GithubClient {
mock := &GithubClient{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -0,0 +1,141 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
params "garm/params"
mock "github.com/stretchr/testify/mock"
)
// PoolManager is an autogenerated mock type for the PoolManager type
type PoolManager struct {
mock.Mock
}
// ForceDeleteRunner provides a mock function with given fields: runner
func (_m *PoolManager) ForceDeleteRunner(runner params.Instance) error {
ret := _m.Called(runner)
var r0 error
if rf, ok := ret.Get(0).(func(params.Instance) error); ok {
r0 = rf(runner)
} else {
r0 = ret.Error(0)
}
return r0
}
// HandleWorkflowJob provides a mock function with given fields: job
func (_m *PoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
ret := _m.Called(job)
var r0 error
if rf, ok := ret.Get(0).(func(params.WorkflowJob) error); ok {
r0 = rf(job)
} else {
r0 = ret.Error(0)
}
return r0
}
// ID provides a mock function with given fields:
func (_m *PoolManager) ID() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// RefreshState provides a mock function with given fields: param
func (_m *PoolManager) RefreshState(param params.UpdatePoolStateParams) error {
ret := _m.Called(param)
var r0 error
if rf, ok := ret.Get(0).(func(params.UpdatePoolStateParams) error); ok {
r0 = rf(param)
} else {
r0 = ret.Error(0)
}
return r0
}
// Start provides a mock function with given fields:
func (_m *PoolManager) Start() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Stop provides a mock function with given fields:
func (_m *PoolManager) Stop() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Wait provides a mock function with given fields:
func (_m *PoolManager) Wait() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// WebhookSecret provides a mock function with given fields:
func (_m *PoolManager) WebhookSecret() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
type mockConstructorTestingTNewPoolManager interface {
mock.TestingT
Cleanup(func())
}
// NewPoolManager creates a new instance of PoolManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPoolManager(t mockConstructorTestingTNewPoolManager) *PoolManager {
mock := &PoolManager{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -0,0 +1,165 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
context "context"
params "garm/params"
mock "github.com/stretchr/testify/mock"
)
// Provider is an autogenerated mock type for the Provider type
type Provider struct {
mock.Mock
}
// AsParams provides a mock function with given fields:
func (_m *Provider) AsParams() params.Provider {
ret := _m.Called()
var r0 params.Provider
if rf, ok := ret.Get(0).(func() params.Provider); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(params.Provider)
}
return r0
}
// CreateInstance provides a mock function with given fields: ctx, bootstrapParams
func (_m *Provider) CreateInstance(ctx context.Context, bootstrapParams params.BootstrapInstance) (params.Instance, error) {
ret := _m.Called(ctx, bootstrapParams)
var r0 params.Instance
if rf, ok := ret.Get(0).(func(context.Context, params.BootstrapInstance) params.Instance); ok {
r0 = rf(ctx, bootstrapParams)
} else {
r0 = ret.Get(0).(params.Instance)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, params.BootstrapInstance) error); ok {
r1 = rf(ctx, bootstrapParams)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// DeleteInstance provides a mock function with given fields: ctx, instance
func (_m *Provider) DeleteInstance(ctx context.Context, instance string) error {
ret := _m.Called(ctx, instance)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, instance)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetInstance provides a mock function with given fields: ctx, instance
func (_m *Provider) GetInstance(ctx context.Context, instance string) (params.Instance, error) {
ret := _m.Called(ctx, instance)
var r0 params.Instance
if rf, ok := ret.Get(0).(func(context.Context, string) params.Instance); ok {
r0 = rf(ctx, instance)
} else {
r0 = ret.Get(0).(params.Instance)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, instance)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ListInstances provides a mock function with given fields: ctx, poolID
func (_m *Provider) ListInstances(ctx context.Context, poolID string) ([]params.Instance, error) {
ret := _m.Called(ctx, poolID)
var r0 []params.Instance
if rf, ok := ret.Get(0).(func(context.Context, string) []params.Instance); ok {
r0 = rf(ctx, poolID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]params.Instance)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, poolID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RemoveAllInstances provides a mock function with given fields: ctx
func (_m *Provider) RemoveAllInstances(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// Start provides a mock function with given fields: ctx, instance
func (_m *Provider) Start(ctx context.Context, instance string) error {
ret := _m.Called(ctx, instance)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, instance)
} else {
r0 = ret.Error(0)
}
return r0
}
// Stop provides a mock function with given fields: ctx, instance, force
func (_m *Provider) Stop(ctx context.Context, instance string, force bool) error {
ret := _m.Called(ctx, instance, force)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, bool) error); ok {
r0 = rf(ctx, instance, force)
} else {
r0 = ret.Error(0)
}
return r0
}
type mockConstructorTestingTNewProvider interface {
mock.TestingT
Cleanup(func())
}
// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewProvider(t mockConstructorTestingTNewProvider) *Provider {
mock := &Provider{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -298,7 +298,7 @@ func (l *LXD) CreateInstance(ctx context.Context, bootstrapParams params.Bootstr
return params.Instance{}, errors.Wrap(err, "creating instance") return params.Instance{}, errors.Wrap(err, "creating instance")
} }
ret, err := l.GetInstance(ctx, args.Name) ret, err := l.waitInstanceHasIP(ctx, args.Name)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching instance") return params.Instance{}, errors.Wrap(err, "fetching instance")
} }

View file

@ -20,15 +20,19 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time"
"garm/config" "garm/config"
"garm/params" "garm/params"
"garm/runner/providers/common" "garm/runner/providers/common"
"garm/util" "garm/util"
"github.com/juju/clock"
"github.com/juju/retry"
lxd "github.com/lxc/lxd/client" lxd "github.com/lxc/lxd/client"
"github.com/lxc/lxd/shared/api" "github.com/lxc/lxd/shared/api"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -177,3 +181,39 @@ func resolveArchitecture(osArch config.OSArch) (string, error) {
} }
return arch, nil return arch, nil
} }
// waitDeviceActive is a function capable of figuring out when a Equinix Metal
// device is active
func (l *LXD) waitInstanceHasIP(ctx context.Context, instanceName string) (params.Instance, error) {
var p params.Instance
var errIPNotFound error = fmt.Errorf("ip not found")
err := retry.Call(retry.CallArgs{
Func: func() error {
var err error
p, err = l.GetInstance(ctx, instanceName)
if err != nil {
return errors.Wrap(err, "fetching instance")
}
for _, addr := range p.Addresses {
ip := net.ParseIP(addr.Address)
if ip == nil {
continue
}
if ip.To4() == nil {
continue
}
return nil
}
return errIPNotFound
},
Attempts: 20,
Delay: 5 * time.Second,
Clock: clock.WallClock,
})
if err != nil && err != errIPNotFound {
return params.Instance{}, err
}
return p, nil
}

191
vendor/github.com/juju/clock/LICENSE generated vendored Normal file
View file

@ -0,0 +1,191 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

20
vendor/github.com/juju/clock/Makefile generated vendored Normal file
View file

@ -0,0 +1,20 @@
PROJECT := github.com/juju/clock
.PHONY: check-licence check-go check
check: check-licence check-go
go test $(PROJECT)/...
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" --exclude *.s .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" --exclude *.s .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check-go:
$(eval GOFMT := $(strip $(shell gofmt -l .| sed -e "s/^/ /g")))
@(if [ x$(GOFMT) != x"" ]; then \
echo go fmt is sad: $(GOFMT); \
exit 1; \
fi )
@(go vet -all -composites=false -copylocks=false .)

7
vendor/github.com/juju/clock/README.md generated vendored Normal file
View file

@ -0,0 +1,7 @@
# clock
An interface definition for a fully defined clock.
An WallClock implementation of that interface using the time package.
A testing clock.

53
vendor/github.com/juju/clock/clock.go generated vendored Normal file
View file

@ -0,0 +1,53 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package clock
import "time"
// Clock provides an interface for dealing with clocks.
type Clock interface {
// Now returns the current clock time.
Now() time.Time
// After waits for the duration to elapse and then sends the
// current time on the returned channel.
After(time.Duration) <-chan time.Time
// AfterFunc waits for the duration to elapse and then calls f in its own goroutine.
// It returns a Timer that can be used to cancel the call using its Stop method.
AfterFunc(d time.Duration, f func()) Timer
// NewTimer creates a new Timer that will send the current time
// on its channel after at least duration d.
NewTimer(d time.Duration) Timer
}
// Alarm returns a channel that will have the time sent on it at some point
// after the supplied time occurs.
//
// This is short for c.After(t.Sub(c.Now())).
func Alarm(c Clock, t time.Time) <-chan time.Time {
return c.After(t.Sub(c.Now()))
}
// The Timer type represents a single event.
// A Timer must be created with AfterFunc.
// This interface follows time.Timer's methods but provides easier mocking.
type Timer interface {
// When the Timer expires, the current time will be sent on the
// channel returned from Chan, unless the Timer was created by
// AfterFunc.
Chan() <-chan time.Time
// Reset changes the timer to expire after duration d.
// It returns true if the timer had been active, false if
// the timer had expired or been stopped.
Reset(time.Duration) bool
// Stop prevents the Timer from firing. It returns true if
// the call stops the timer, false if the timer has already expired or been stopped.
// Stop does not close the channel, to prevent a read
// from the channel succeeding incorrectly.
Stop() bool
}

47
vendor/github.com/juju/clock/wall.go generated vendored Normal file
View file

@ -0,0 +1,47 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package clock
import (
"time"
)
// WallClock exposes wall-clock time via the Clock interface.
var WallClock wallClock
// ensure that WallClock does actually implement the Clock interface.
var _ Clock = WallClock
// WallClock exposes wall-clock time as returned by time.Now.
type wallClock struct{}
// Now is part of the Clock interface.
func (wallClock) Now() time.Time {
return time.Now()
}
// After implements Clock.After.
func (wallClock) After(d time.Duration) <-chan time.Time {
return time.After(d)
}
// AfterFunc implements Clock.AfterFunc.
func (wallClock) AfterFunc(d time.Duration, f func()) Timer {
return wallTimer{time.AfterFunc(d, f)}
}
// NewTimer implements Clock.NewTimer.
func (wallClock) NewTimer(d time.Duration) Timer {
return wallTimer{time.NewTimer(d)}
}
// wallTimer implements the Timer interface.
type wallTimer struct {
*time.Timer
}
// Chan implements Timer.Chan.
func (t wallTimer) Chan() <-chan time.Time {
return t.C
}

23
vendor/github.com/juju/errors/.gitignore generated vendored Normal file
View file

@ -0,0 +1,23 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

191
vendor/github.com/juju/errors/LICENSE generated vendored Normal file
View file

@ -0,0 +1,191 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

24
vendor/github.com/juju/errors/Makefile generated vendored Normal file
View file

@ -0,0 +1,24 @@
PROJECT := github.com/juju/errors
.PHONY: check-licence check-go check docs
check: check-licence check-go
go test $(PROJECT)/...
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" --exclude *.s .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" --exclude *.s .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check-go:
$(eval GOFMT := $(strip $(shell gofmt -l .| sed -e "s/^/ /g")))
@(if [ x$(GOFMT) != x"" ]; then \
echo go fmt is sad: $(GOFMT); \
exit 1; \
fi )
@(go vet -all -composites=false -copylocks=false .)
docs:
godoc2md github.com/juju/errors > README.md
sed -i '5i[\[GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)' README.md

707
vendor/github.com/juju/errors/README.md generated vendored Normal file
View file

@ -0,0 +1,707 @@
# errors
import "github.com/juju/errors"
[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)
The juju/errors provides an easy way to annotate errors without losing the
original error context.
The exported `New` and `Errorf` functions are designed to replace the
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
error is there, but the package also records the location at which the error
was created.
A primary use case for this library is to add extra context any time an
error is returned from a function.
if err := SomeFunc(); err != nil {
return err
}
This instead becomes:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
which just records the file and line number of the Trace call, or
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "more context")
}
which also adds an annotation to the error.
When you want to check to see if an error is of a particular type, a helper
function is normally exported by the package that returned the error, like the
`os` package does. The underlying cause of the error is available using the
`Cause` function.
os.IsNotExist(errors.Cause(err))
The result of the `Error()` call on an annotated error is the annotations joined
with colons, then the result of the `Error()` method for the underlying error
that was the cause.
err := errors.Errorf("original")
err = errors.Annotatef(err, "context")
err = errors.Annotatef(err, "more context")
err.Error() -> "more context: context: original"
Obviously recording the file, line and functions is not very useful if you
cannot get them back out again.
errors.ErrorStack(err)
will return something like:
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
The first error was generated by an external system, so there was no location
associated. The second, fourth, and last lines were generated with Trace calls,
and the other two through Annotate.
Sometimes when responding to an error you want to return a more specific error
for the situation.
if err := FindField(field); err != nil {
return errors.Wrap(err, errors.NotFoundf(field))
}
This returns an error where the complete error stack is still available, and
`errors.Cause()` will return the `NotFound` error.
## func AlreadyExistsf
``` go
func AlreadyExistsf(format string, args ...interface{}) error
```
AlreadyExistsf returns an error which satisfies IsAlreadyExists().
## func Annotate
``` go
func Annotate(other error, message string) error
```
Annotate is used to add extra context to an existing error. The location of
the Annotate call is recorded with the annotations. The file, line and
function are also recorded.
For example:
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "failed to frombulate")
}
## func Annotatef
``` go
func Annotatef(other error, format string, args ...interface{}) error
```
Annotatef is used to add extra context to an existing error. The location of
the Annotate call is recorded with the annotations. The file, line and
function are also recorded.
For example:
if err := SomeFunc(); err != nil {
return errors.Annotatef(err, "failed to frombulate the %s", arg)
}
## func BadRequestf
``` go
func BadRequestf(format string, args ...interface{}) error
```
BadRequestf returns an error which satisfies IsBadRequest().
## func Cause
``` go
func Cause(err error) error
```
Cause returns the cause of the given error. This will be either the
original error, or the result of a Wrap or Mask call.
Cause is the usual way to diagnose errors that may have been wrapped by
the other errors functions.
## func DeferredAnnotatef
``` go
func DeferredAnnotatef(err *error, format string, args ...interface{})
```
DeferredAnnotatef annotates the given error (when it is not nil) with the given
format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
does nothing. This method is used in a defer statement in order to annotate any
resulting error with the same message.
For example:
defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
## func Details
``` go
func Details(err error) string
```
Details returns information about the stack of errors wrapped by err, in
the format:
[{filename:99: error one} {otherfile:55: cause of error one}]
This is a terse alternative to ErrorStack as it returns a single line.
## func ErrorStack
``` go
func ErrorStack(err error) string
```
ErrorStack returns a string representation of the annotated error. If the
error passed as the parameter is not an annotated error, the result is
simply the result of the Error() method on that error.
If the error is an annotated error, a multi-line string is returned where
each line represents one entry in the annotation stack. The full filename
from the call stack is used in the output.
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
## func Errorf
``` go
func Errorf(format string, args ...interface{}) error
```
Errorf creates a new annotated error and records the location that the
error is created. This should be a drop in replacement for fmt.Errorf.
For example:
return errors.Errorf("validation failed: %s", message)
## func Forbiddenf
``` go
func Forbiddenf(format string, args ...interface{}) error
```
Forbiddenf returns an error which satistifes IsForbidden()
## func IsAlreadyExists
``` go
func IsAlreadyExists(err error) bool
```
IsAlreadyExists reports whether the error was created with
AlreadyExistsf() or NewAlreadyExists().
## func IsBadRequest
``` go
func IsBadRequest(err error) bool
```
IsBadRequest reports whether err was created with BadRequestf() or
NewBadRequest().
## func IsForbidden
``` go
func IsForbidden(err error) bool
```
IsForbidden reports whether err was created with Forbiddenf() or
NewForbidden().
## func IsMethodNotAllowed
``` go
func IsMethodNotAllowed(err error) bool
```
IsMethodNotAllowed reports whether err was created with MethodNotAllowedf() or
NewMethodNotAllowed().
## func IsNotAssigned
``` go
func IsNotAssigned(err error) bool
```
IsNotAssigned reports whether err was created with NotAssignedf() or
NewNotAssigned().
## func IsNotFound
``` go
func IsNotFound(err error) bool
```
IsNotFound reports whether err was created with NotFoundf() or
NewNotFound().
## func IsNotImplemented
``` go
func IsNotImplemented(err error) bool
```
IsNotImplemented reports whether err was created with
NotImplementedf() or NewNotImplemented().
## func IsNotProvisioned
``` go
func IsNotProvisioned(err error) bool
```
IsNotProvisioned reports whether err was created with NotProvisionedf() or
NewNotProvisioned().
## func IsNotSupported
``` go
func IsNotSupported(err error) bool
```
IsNotSupported reports whether the error was created with
NotSupportedf() or NewNotSupported().
## func IsNotValid
``` go
func IsNotValid(err error) bool
```
IsNotValid reports whether the error was created with NotValidf() or
NewNotValid().
## func IsUnauthorized
``` go
func IsUnauthorized(err error) bool
```
IsUnauthorized reports whether err was created with Unauthorizedf() or
NewUnauthorized().
## func IsUserNotFound
``` go
func IsUserNotFound(err error) bool
```
IsUserNotFound reports whether err was created with UserNotFoundf() or
NewUserNotFound().
## func Mask
``` go
func Mask(other error) error
```
Mask hides the underlying error type, and records the location of the masking.
## func Maskf
``` go
func Maskf(other error, format string, args ...interface{}) error
```
Mask masks the given error with the given format string and arguments (like
fmt.Sprintf), returning a new error that maintains the error stack, but
hides the underlying error type. The error string still contains the full
annotations. If you want to hide the annotations, call Wrap.
## func MethodNotAllowedf
``` go
func MethodNotAllowedf(format string, args ...interface{}) error
```
MethodNotAllowedf returns an error which satisfies IsMethodNotAllowed().
## func New
``` go
func New(message string) error
```
New is a drop in replacement for the standard library errors module that records
the location that the error is created.
For example:
return errors.New("validation failed")
## func NewAlreadyExists
``` go
func NewAlreadyExists(err error, msg string) error
```
NewAlreadyExists returns an error which wraps err and satisfies
IsAlreadyExists().
## func NewBadRequest
``` go
func NewBadRequest(err error, msg string) error
```
NewBadRequest returns an error which wraps err that satisfies
IsBadRequest().
## func NewForbidden
``` go
func NewForbidden(err error, msg string) error
```
NewForbidden returns an error which wraps err that satisfies
IsForbidden().
## func NewMethodNotAllowed
``` go
func NewMethodNotAllowed(err error, msg string) error
```
NewMethodNotAllowed returns an error which wraps err that satisfies
IsMethodNotAllowed().
## func NewNotAssigned
``` go
func NewNotAssigned(err error, msg string) error
```
NewNotAssigned returns an error which wraps err that satisfies
IsNotAssigned().
## func NewNotFound
``` go
func NewNotFound(err error, msg string) error
```
NewNotFound returns an error which wraps err that satisfies
IsNotFound().
## func NewNotImplemented
``` go
func NewNotImplemented(err error, msg string) error
```
NewNotImplemented returns an error which wraps err and satisfies
IsNotImplemented().
## func NewNotProvisioned
``` go
func NewNotProvisioned(err error, msg string) error
```
NewNotProvisioned returns an error which wraps err that satisfies
IsNotProvisioned().
## func NewNotSupported
``` go
func NewNotSupported(err error, msg string) error
```
NewNotSupported returns an error which wraps err and satisfies
IsNotSupported().
## func NewNotValid
``` go
func NewNotValid(err error, msg string) error
```
NewNotValid returns an error which wraps err and satisfies IsNotValid().
## func NewUnauthorized
``` go
func NewUnauthorized(err error, msg string) error
```
NewUnauthorized returns an error which wraps err and satisfies
IsUnauthorized().
## func NewUserNotFound
``` go
func NewUserNotFound(err error, msg string) error
```
NewUserNotFound returns an error which wraps err and satisfies
IsUserNotFound().
## func NotAssignedf
``` go
func NotAssignedf(format string, args ...interface{}) error
```
NotAssignedf returns an error which satisfies IsNotAssigned().
## func NotFoundf
``` go
func NotFoundf(format string, args ...interface{}) error
```
NotFoundf returns an error which satisfies IsNotFound().
## func NotImplementedf
``` go
func NotImplementedf(format string, args ...interface{}) error
```
NotImplementedf returns an error which satisfies IsNotImplemented().
## func NotProvisionedf
``` go
func NotProvisionedf(format string, args ...interface{}) error
```
NotProvisionedf returns an error which satisfies IsNotProvisioned().
## func NotSupportedf
``` go
func NotSupportedf(format string, args ...interface{}) error
```
NotSupportedf returns an error which satisfies IsNotSupported().
## func NotValidf
``` go
func NotValidf(format string, args ...interface{}) error
```
NotValidf returns an error which satisfies IsNotValid().
## func Trace
``` go
func Trace(other error) error
```
Trace adds the location of the Trace call to the stack. The Cause of the
resulting error is the same as the error parameter. If the other error is
nil, the result will be nil.
For example:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
## func Unauthorizedf
``` go
func Unauthorizedf(format string, args ...interface{}) error
```
Unauthorizedf returns an error which satisfies IsUnauthorized().
## func UserNotFoundf
``` go
func UserNotFoundf(format string, args ...interface{}) error
```
UserNotFoundf returns an error which satisfies IsUserNotFound().
## func Wrap
``` go
func Wrap(other, newDescriptive error) error
```
Wrap changes the Cause of the error. The location of the Wrap call is also
stored in the error stack.
For example:
if err := SomeFunc(); err != nil {
newErr := &packageError{"more context", private_value}
return errors.Wrap(err, newErr)
}
## func Wrapf
``` go
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error
```
Wrapf changes the Cause of the error, and adds an annotation. The location
of the Wrap call is also stored in the error stack.
For example:
if err := SomeFunc(); err != nil {
return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
}
## type Err
``` go
type Err struct {
// contains filtered or unexported fields
}
```
Err holds a description of an error along with information about
where the error was created.
It may be embedded in custom error types to add extra information that
this errors package can understand.
### func NewErr
``` go
func NewErr(format string, args ...interface{}) Err
```
NewErr is used to return an Err for the purpose of embedding in other
structures. The location is not specified, and needs to be set with a call
to SetLocation.
For example:
type FooError struct {
errors.Err
code int
}
func NewFooError(code int) error {
err := &FooError{errors.NewErr("foo"), code}
err.SetLocation(1)
return err
}
### func NewErrWithCause
``` go
func NewErrWithCause(other error, format string, args ...interface{}) Err
```
NewErrWithCause is used to return an Err with cause by other error for the purpose of embedding in other
structures. The location is not specified, and needs to be set with a call
to SetLocation.
For example:
type FooError struct {
errors.Err
code int
}
func (e *FooError) Annotate(format string, args ...interface{}) error {
err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
err.SetLocation(1)
return err
})
### func (\*Err) Cause
``` go
func (e *Err) Cause() error
```
The Cause of an error is the most recent error in the error stack that
meets one of these criteria: the original error that was raised; the new
error that was passed into the Wrap function; the most recently masked
error; or nil if the error itself is considered the Cause. Normally this
method is not invoked directly, but instead through the Cause stand alone
function.
### func (\*Err) Error
``` go
func (e *Err) Error() string
```
Error implements error.Error.
### func (\*Err) Format
``` go
func (e *Err) Format(s fmt.State, verb rune)
```
Format implements fmt.Formatter
When printing errors with %+v it also prints the stack trace.
%#v unsurprisingly will print the real underlying type.
### func (\*Err) Location
``` go
func (e *Err) Location() (filename string, line int)
```
Location is the file and line of where the error was most recently
created or annotated.
### func (\*Err) Message
``` go
func (e *Err) Message() string
```
Message returns the message stored with the most recent location. This is
the empty string if the most recent call was Trace, or the message stored
with Annotate or Mask.
### func (\*Err) SetLocation
``` go
func (e *Err) SetLocation(callDepth int)
```
SetLocation records the source location of the error at callDepth stack
frames above the call.
### func (\*Err) StackTrace
``` go
func (e *Err) StackTrace() []string
```
StackTrace returns one string for each location recorded in the stack of
errors. The first value is the originating error, with a line for each
other annotation or tracing of the error.
### func (\*Err) Underlying
``` go
func (e *Err) Underlying() error
```
Underlying returns the previous error in the error stack, if any. A client
should not ever really call this method. It is used to build the error
stack and should not be introspected by client calls. Or more
specifically, clients should not depend on anything but the `Cause` of an
error.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

79
vendor/github.com/juju/errors/doc.go generated vendored Normal file
View file

@ -0,0 +1,79 @@
// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
/*
Package errors provides an easy way to annotate errors without losing the
original error context.
The exported `New` and `Errorf` functions are designed to replace the
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
error is there, but the package also records the location at which the error
was created.
A primary use case for this library is to add extra context any time an
error is returned from a function.
if err := SomeFunc(); err != nil {
return err
}
This instead becomes:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
which just records the file and line number of the Trace call, or
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "more context")
}
which also adds an annotation to the error.
When you want to check to see if an error is of a particular type, a helper
function is normally exported by the package that returned the error, like the
`os` package does. The underlying cause of the error is available using the
`Cause` function.
os.IsNotExist(errors.Cause(err))
The result of the `Error()` call on an annotated error is the annotations joined
with colons, then the result of the `Error()` method for the underlying error
that was the cause.
err := errors.Errorf("original")
err = errors.Annotatef(err, "context")
err = errors.Annotatef(err, "more context")
err.Error() -> "more context: context: original"
Obviously recording the file, line and functions is not very useful if you
cannot get them back out again.
errors.ErrorStack(err)
will return something like:
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
The first error was generated by an external system, so there was no location
associated. The second, fourth, and last lines were generated with Trace calls,
and the other two through Annotate.
Sometimes when responding to an error you want to return a more specific error
for the situation.
if err := FindField(field); err != nil {
return errors.Wrap(err, errors.NotFoundf(field))
}
This returns an error where the complete error stack is still available, and
`errors.Cause()` will return the `NotFound` error.
*/
package errors

227
vendor/github.com/juju/errors/error.go generated vendored Normal file
View file

@ -0,0 +1,227 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
"fmt"
"reflect"
)
// Err holds a description of an error along with information about
// where the error was created.
//
// It may be embedded in custom error types to add extra information that
// this errors package can understand.
type Err struct {
// message holds an annotation of the error.
message string
// cause holds the cause of the error as returned
// by the Cause method.
cause error
// previous holds the previous error in the error stack, if any.
previous error
// function is the package path-qualified function name where the
// error was created.
function string
// line is the line number the error was created on inside of function
line int
}
// Locationer is an interface that represents a certain class of errors that
// contain the location information from where they were raised.
type Locationer interface {
// Location returns the path-qualified function name where the error was
// created and the line number
Location() (function string, line int)
}
// locationError is the internal implementation of the Locationer interface.
type locationError struct {
error
// function is the package path-qualified function name where the
// error was created.
function string
// line is the line number the error was created on inside of function
line int
}
// newLocationError constructs a new Locationer error from the supplied error
// with the location set to callDepth in the stack. If a nill error is provided
// to this function then a new empty error is constructed.
func newLocationError(err error, callDepth int) *locationError {
le := &locationError{error: err}
le.function, le.line = getLocation(callDepth + 1)
return le
}
// Error implementes the error interface.
func (l *locationError) Error() string {
if l.error == nil {
return ""
}
return l.error.Error()
}
// *locationError implements Locationer.Location interface
func (l *locationError) Location() (string, int) {
return l.function, l.line
}
func (l *locationError) Unwrap() error {
return l.error
}
// NewErr is used to return an Err for the purpose of embedding in other
// structures. The location is not specified, and needs to be set with a call
// to SetLocation.
//
// For example:
// type FooError struct {
// errors.Err
// code int
// }
//
// func NewFooError(code int) error {
// err := &FooError{errors.NewErr("foo"), code}
// err.SetLocation(1)
// return err
// }
func NewErr(format string, args ...interface{}) Err {
return Err{
message: fmt.Sprintf(format, args...),
}
}
// NewErrWithCause is used to return an Err with cause by other error for the purpose of embedding in other
// structures. The location is not specified, and needs to be set with a call
// to SetLocation.
//
// For example:
// type FooError struct {
// errors.Err
// code int
// }
//
// func (e *FooError) Annotate(format string, args ...interface{}) error {
// err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
// err.SetLocation(1)
// return err
// })
func NewErrWithCause(other error, format string, args ...interface{}) Err {
return Err{
message: fmt.Sprintf(format, args...),
cause: Cause(other),
previous: other,
}
}
// Location returns the package path-qualified function name and line of where
// the error was most recently created or annotated.
func (e *Err) Location() (function string, line int) {
return e.function, e.line
}
// Underlying returns the previous error in the error stack, if any. A client
// should not ever really call this method. It is used to build the error
// stack and should not be introspected by client calls. Or more
// specifically, clients should not depend on anything but the `Cause` of an
// error.
func (e *Err) Underlying() error {
return e.previous
}
// Cause returns the most recent error in the error stack that
// meets one of these criteria: the original error that was raised; the new
// error that was passed into the Wrap function; the most recently masked
// error; or nil if the error itself is considered the Cause. Normally this
// method is not invoked directly, but instead through the Cause stand alone
// function.
func (e *Err) Cause() error {
return e.cause
}
// Message returns the message stored with the most recent location. This is
// the empty string if the most recent call was Trace, or the message stored
// with Annotate or Mask.
func (e *Err) Message() string {
return e.message
}
// Error implements error.Error.
func (e *Err) Error() string {
// We want to walk up the stack of errors showing the annotations
// as long as the cause is the same.
err := e.previous
if !sameError(Cause(err), e.cause) && e.cause != nil {
err = e.cause
}
switch {
case err == nil:
return e.message
case e.message == "":
return err.Error()
}
return fmt.Sprintf("%s: %v", e.message, err)
}
// Format implements fmt.Formatter
// When printing errors with %+v it also prints the stack trace.
// %#v unsurprisingly will print the real underlying type.
func (e *Err) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
fmt.Fprintf(s, "%s", ErrorStack(e))
return
case s.Flag('#'):
// avoid infinite recursion by wrapping e into a type
// that doesn't implement Formatter.
fmt.Fprintf(s, "%#v", (*unformatter)(e))
return
}
fallthrough
case 's':
fmt.Fprintf(s, "%s", e.Error())
case 'q':
fmt.Fprintf(s, "%q", e.Error())
default:
fmt.Fprintf(s, "%%!%c(%T=%s)", verb, e, e.Error())
}
}
// helper for Format
type unformatter Err
func (unformatter) Format() { /* break the fmt.Formatter interface */ }
// SetLocation records the package path-qualified function name of the error at
// callDepth stack frames above the call.
func (e *Err) SetLocation(callDepth int) {
e.function, e.line = getLocation(callDepth + 1)
}
// StackTrace returns one string for each location recorded in the stack of
// errors. The first value is the originating error, with a line for each
// other annotation or tracing of the error.
func (e *Err) StackTrace() []string {
return errorStack(e)
}
// Ideally we'd have a way to check identity, but deep equals will do.
func sameError(e1, e2 error) bool {
return reflect.DeepEqual(e1, e2)
}
// Unwrap is a synonym for Underlying, which allows Err to be used with the
// Unwrap, Is and As functions in Go's standard `errors` library.
func (e *Err) Unwrap() error {
return e.previous
}

463
vendor/github.com/juju/errors/errortypes.go generated vendored Normal file
View file

@ -0,0 +1,463 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
stderror "errors"
"fmt"
"strings"
)
// a ConstError is a prototype for a certain type of error
type ConstError string
// ConstError implements error
func (e ConstError) Error() string {
return string(e)
}
// Different types of errors
const (
// Timeout represents an error on timeout.
Timeout = ConstError("timeout")
// NotFound represents an error when something has not been found.
NotFound = ConstError("not found")
// UserNotFound represents an error when a non-existent user is looked up.
UserNotFound = ConstError("user not found")
// Unauthorized represents an error when an operation is unauthorized.
Unauthorized = ConstError("unauthorized")
// NotImplemented represents an error when something is not
// implemented.
NotImplemented = ConstError("not implemented")
// AlreadyExists represents and error when something already exists.
AlreadyExists = ConstError("already exists")
// NotSupported represents an error when something is not supported.
NotSupported = ConstError("not supported")
// NotValid represents an error when something is not valid.
NotValid = ConstError("not valid")
// NotProvisioned represents an error when something is not yet provisioned.
NotProvisioned = ConstError("not provisioned")
// NotAssigned represents an error when something is not yet assigned to
// something else.
NotAssigned = ConstError("not assigned")
// BadRequest represents an error when a request has bad parameters.
BadRequest = ConstError("bad request")
// MethodNotAllowed represents an error when an HTTP request
// is made with an inappropriate method.
MethodNotAllowed = ConstError("method not allowed")
// Forbidden represents an error when a request cannot be completed because of
// missing privileges.
Forbidden = ConstError("forbidden")
// QuotaLimitExceeded is emitted when an action failed due to a quota limit check.
QuotaLimitExceeded = ConstError("quota limit exceeded")
// NotYetAvailable is the error returned when a resource is not yet available
// but it might be in the future.
NotYetAvailable = ConstError("not yet available")
)
// constSuppressor is a small type wrapper for ConstError to surpress the error
// value from returning an error value. This allows us to maintain backwards
// compatibility.
type constSuppressor ConstError
func (c constSuppressor) Error() string { return "" }
func (c constSuppressor) Unwrap() error { return ConstError(c) }
// errWithType is an Err bundled with its error type (a ConstError)
type errWithType struct {
error
errType ConstError
}
// Is compares `target` with e's error type
func (e *errWithType) Is(target error) bool {
if &e.errType == nil {
return false
}
return target == e.errType
}
// Unwrap an errWithType gives the underlying Err
func (e *errWithType) Unwrap() error {
return e.error
}
func wrapErrorWithMsg(err error, msg string) error {
if err == nil {
return stderror.New(msg)
}
if msg == "" {
return err
}
return fmt.Errorf("%s: %w", msg, err)
}
func makeWrappedConstError(err error, format string, args ...interface{}) error {
separator := " "
if err.Error() == "" {
separator = ""
}
return fmt.Errorf(strings.Join([]string{format, "%w"}, separator), append(args, err)...)
}
// Timeoutf returns an error which satisfies Is(err, Timeout) and the Locationer
// interface.
func Timeoutf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Timeout, format, args...),
1,
)
}
// NewTimeout returns an error which wraps err and satisfies Is(err, Timeout)
// and the Locationer interface.
func NewTimeout(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Timeout,
}
}
// Deprecated: IsTimeout reports whether err is a Timeout error. Use
// Is(err, Timeout).
func IsTimeout(err error) bool {
return Is(err, Timeout)
}
// NotFoundf returns an error which satisfies Is(err, NotFound) and the
// Locationer interface.
func NotFoundf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotFound, format, args...),
1,
)
}
// NewNotFound returns an error which wraps err and satisfies Is(err, NotFound)
// and the Locationer interface.
func NewNotFound(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotFound,
}
}
// Deprecated: IsNotFound reports whether err is a NotFound error. Use
// Is(err, NotFound).
func IsNotFound(err error) bool {
return Is(err, NotFound)
}
// UserNotFoundf returns an error which satisfies Is(err, UserNotFound) and the
// Locationer interface.
func UserNotFoundf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(UserNotFound, format, args...),
1,
)
}
// NewUserNotFound returns an error which wraps err and satisfies
// Is(err, UserNotFound) and the Locationer interface.
func NewUserNotFound(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: UserNotFound,
}
}
// Deprecated: IsUserNotFound reports whether err is a UserNotFound error. Use
// Is(err, UserNotFound).
func IsUserNotFound(err error) bool {
return Is(err, UserNotFound)
}
// Unauthorizedf returns an error that satisfies Is(err, Unauthorized) and
// the Locationer interface.
func Unauthorizedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(Unauthorized), format, args...),
1,
)
}
// NewUnauthorized returns an error which wraps err and satisfies
// Is(err, Unathorized) and the Locationer interface.
func NewUnauthorized(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Unauthorized,
}
}
// Deprecated: IsUnauthorized reports whether err is a Unauthorized error. Use
// Is(err, Unauthorized).
func IsUnauthorized(err error) bool {
return Is(err, Unauthorized)
}
// NotImplementedf returns an error which satisfies Is(err, NotImplemented) and
// the Locationer interface.
func NotImplementedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotImplemented, format, args...),
1,
)
}
// NewNotImplemented returns an error which wraps err and satisfies
// Is(err, NotImplemented) and the Locationer interface.
func NewNotImplemented(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotImplemented,
}
}
// Deprecated: IsNotImplemented reports whether err is a NotImplemented error.
// Use Is(err, NotImplemented).
func IsNotImplemented(err error) bool {
return Is(err, NotImplemented)
}
// AlreadyExistsf returns an error which satisfies Is(err, AlreadyExists) and
// the Locationer interface.
func AlreadyExistsf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(AlreadyExists, format, args...),
1,
)
}
// NewAlreadyExists returns an error which wraps err and satisfies
// Is(err, AlreadyExists) and the Locationer interface.
func NewAlreadyExists(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: AlreadyExists,
}
}
// Deprecated: IsAlreadyExists reports whether the err is a AlreadyExists
// error. Use Is(err, AlreadyExists).
func IsAlreadyExists(err error) bool {
return Is(err, AlreadyExists)
}
// NotSupportedf returns an error which satisfies Is(err, NotSupported) and the
// Locationer interface.
func NotSupportedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotSupported, format, args...),
1,
)
}
// NewNotSupported returns an error which satisfies Is(err, NotSupported) and
// the Locationer interface.
func NewNotSupported(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotSupported,
}
}
// Deprecated: IsNotSupported reports whether err is a NotSupported error. Use
// Is(err, NotSupported).
func IsNotSupported(err error) bool {
return Is(err, NotSupported)
}
// NotValidf returns an error which satisfies Is(err, NotValid) and the
// Locationer interface.
func NotValidf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotValid, format, args...),
1,
)
}
// NewNotValid returns an error which wraps err and satisfies Is(err, NotValid)
// and the Locationer interface.
func NewNotValid(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotValid,
}
}
// Deprecated: IsNotValid reports whether err is a NotValid error. Use
// Is(err, NotValid).
func IsNotValid(err error) bool {
return Is(err, NotValid)
}
// NotProvisionedf returns an error which satisfies Is(err, NotProvisioned) and
// the Locationer interface.
func NotProvisionedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotProvisioned, format, args...),
1,
)
}
// NewNotProvisioned returns an error which wraps err and satisfies
// Is(err, NotProvisioned) and the Locationer interface.
func NewNotProvisioned(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotProvisioned,
}
}
// Deprecated: IsNotProvisioned reports whether err is a NotProvisioned error.
// Use Is(err, NotProvisioned).
func IsNotProvisioned(err error) bool {
return Is(err, NotProvisioned)
}
// NotAssignedf returns an error which satisfies Is(err, NotAssigned) and the
// Locationer interface.
func NotAssignedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotAssigned, format, args...),
1,
)
}
// NewNotAssigned returns an error which wraps err and satisfies
// Is(err, NotAssigned) and the Locationer interface.
func NewNotAssigned(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotAssigned,
}
}
// Deprecated: IsNotAssigned reports whether err is a NotAssigned error.
// Use Is(err, NotAssigned)
func IsNotAssigned(err error) bool {
return Is(err, NotAssigned)
}
// BadRequestf returns an error which satisfies Is(err, BadRequest) and the
// Locationer interface.
func BadRequestf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(BadRequest), format, args...),
1,
)
}
// NewBadRequest returns an error which wraps err and satisfies
// Is(err, BadRequest) and the Locationer interface.
func NewBadRequest(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: BadRequest,
}
}
// Deprecated: IsBadRequest reports whether err is a BadRequest error.
// Use Is(err, BadRequest)
func IsBadRequest(err error) bool {
return Is(err, BadRequest)
}
// MethodNotAllowedf returns an error which satisfies Is(err, MethodNotAllowed)
// and the Locationer interface.
func MethodNotAllowedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(MethodNotAllowed), format, args...),
1,
)
}
// NewMethodNotAllowed returns an error which wraps err and satisfies
// Is(err, MethodNotAllowed) and the Locationer interface.
func NewMethodNotAllowed(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: MethodNotAllowed,
}
}
// Deprecated: IsMethodNotAllowed reports whether err is a MethodNotAllowed
// error. Use Is(err, MethodNotAllowed)
func IsMethodNotAllowed(err error) bool {
return Is(err, MethodNotAllowed)
}
// Forbiddenf returns an error which satistifes Is(err, Forbidden) and the
// Locationer interface.
func Forbiddenf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(Forbidden), format, args...),
1,
)
}
// NewForbidden returns an error which wraps err and satisfies
// Is(err, Forbidden) and the Locationer interface.
func NewForbidden(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Forbidden,
}
}
// Deprecated: IsForbidden reports whether err is a Forbidden error. Use
// Is(err, Forbidden).
func IsForbidden(err error) bool {
return Is(err, Forbidden)
}
// QuotaLimitExceededf returns an error which satisfies
// Is(err, QuotaLimitExceeded) and the Locationer interface.
func QuotaLimitExceededf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(QuotaLimitExceeded), format, args...),
1,
)
}
// NewQuotaLimitExceeded returns an error which wraps err and satisfies
// Is(err, QuotaLimitExceeded) and the Locationer interface.
func NewQuotaLimitExceeded(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: QuotaLimitExceeded,
}
}
// Deprecated: IsQuotaLimitExceeded reports whether err is a QuoteLimitExceeded
// err. Use Is(err, QuotaLimitExceeded).
func IsQuotaLimitExceeded(err error) bool {
return Is(err, QuotaLimitExceeded)
}
// NotYetAvailablef returns an error which satisfies Is(err, NotYetAvailable)
// and the Locationer interface.
func NotYetAvailablef(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(constSuppressor(NotYetAvailable), format, args...),
1,
)
}
// NewNotYetAvailable returns an error which wraps err and satisfies
// Is(err, NotYetAvailable) and the Locationer interface.
func NewNotYetAvailable(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotYetAvailable,
}
}
// Deprecated: IsNotYetAvailable reports whether err is a NotYetAvailable err.
// Use Is(err, NotYetAvailable)
func IsNotYetAvailable(err error) bool {
return Is(err, NotYetAvailable)
}

357
vendor/github.com/juju/errors/functions.go generated vendored Normal file
View file

@ -0,0 +1,357 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
stderrors "errors"
"fmt"
"runtime"
"strings"
)
// New is a drop in replacement for the standard library errors module that records
// the location that the error is created.
//
// For example:
// return errors.New("validation failed")
//
func New(message string) error {
err := &Err{message: message}
err.SetLocation(1)
return err
}
// Errorf creates a new annotated error and records the location that the
// error is created. This should be a drop in replacement for fmt.Errorf.
//
// For example:
// return errors.Errorf("validation failed: %s", message)
//
func Errorf(format string, args ...interface{}) error {
err := &Err{message: fmt.Sprintf(format, args...)}
err.SetLocation(1)
return err
}
// getLocation records the package path-qualified function name of the error at
// callDepth stack frames above the call.
func getLocation(callDepth int) (string, int) {
rpc := make([]uintptr, 1)
n := runtime.Callers(callDepth+2, rpc[:])
if n < 1 {
return "", 0
}
frame, _ := runtime.CallersFrames(rpc).Next()
return frame.Function, frame.Line
}
// Trace adds the location of the Trace call to the stack. The Cause of the
// resulting error is the same as the error parameter. If the other error is
// nil, the result will be nil.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Trace(err)
// }
//
func Trace(other error) error {
if other == nil {
return nil
}
err := &Err{previous: other, cause: Cause(other)}
err.SetLocation(1)
return err
}
// Annotate is used to add extra context to an existing error. The location of
// the Annotate call is recorded with the annotations. The file, line and
// function are also recorded.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Annotate(err, "failed to frombulate")
// }
//
func Annotate(other error, message string) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
cause: Cause(other),
message: message,
}
err.SetLocation(1)
return err
}
// Annotatef is used to add extra context to an existing error. The location of
// the Annotate call is recorded with the annotations. The file, line and
// function are also recorded.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Annotatef(err, "failed to frombulate the %s", arg)
// }
//
func Annotatef(other error, format string, args ...interface{}) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
cause: Cause(other),
message: fmt.Sprintf(format, args...),
}
err.SetLocation(1)
return err
}
// DeferredAnnotatef annotates the given error (when it is not nil) with the given
// format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
// does nothing. This method is used in a defer statement in order to annotate any
// resulting error with the same message.
//
// For example:
//
// defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
//
func DeferredAnnotatef(err *error, format string, args ...interface{}) {
if *err == nil {
return
}
newErr := &Err{
message: fmt.Sprintf(format, args...),
cause: Cause(*err),
previous: *err,
}
newErr.SetLocation(1)
*err = newErr
}
// Wrap changes the Cause of the error. The location of the Wrap call is also
// stored in the error stack.
//
// For example:
// if err := SomeFunc(); err != nil {
// newErr := &packageError{"more context", private_value}
// return errors.Wrap(err, newErr)
// }
//
func Wrap(other, newDescriptive error) error {
err := &Err{
previous: other,
cause: newDescriptive,
}
err.SetLocation(1)
return err
}
// Wrapf changes the Cause of the error, and adds an annotation. The location
// of the Wrap call is also stored in the error stack.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
// }
//
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error {
err := &Err{
message: fmt.Sprintf(format, args...),
previous: other,
cause: newDescriptive,
}
err.SetLocation(1)
return err
}
// Maskf masks the given error with the given format string and arguments (like
// fmt.Sprintf), returning a new error that maintains the error stack, but
// hides the underlying error type. The error string still contains the full
// annotations. If you want to hide the annotations, call Wrap.
func Maskf(other error, format string, args ...interface{}) error {
if other == nil {
return nil
}
err := &Err{
message: fmt.Sprintf(format, args...),
previous: other,
}
err.SetLocation(1)
return err
}
// Mask hides the underlying error type, and records the location of the masking.
func Mask(other error) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
}
err.SetLocation(1)
return err
}
// Cause returns the cause of the given error. This will be either the
// original error, or the result of a Wrap or Mask call.
//
// Cause is the usual way to diagnose errors that may have been wrapped by
// the other errors functions.
func Cause(err error) error {
var diag error
if err, ok := err.(causer); ok {
diag = err.Cause()
}
if diag != nil {
return diag
}
return err
}
type causer interface {
Cause() error
}
type wrapper interface {
// Message returns the top level error message,
// not including the message from the Previous
// error.
Message() string
// Underlying returns the Previous error, or nil
// if there is none.
Underlying() error
}
var (
_ wrapper = (*Err)(nil)
_ Locationer = (*Err)(nil)
_ causer = (*Err)(nil)
)
// Details returns information about the stack of errors wrapped by err, in
// the format:
//
// [{filename:99: error one} {otherfile:55: cause of error one}]
//
// This is a terse alternative to ErrorStack as it returns a single line.
func Details(err error) string {
if err == nil {
return "[]"
}
var s []byte
s = append(s, '[')
for {
s = append(s, '{')
if err, ok := err.(Locationer); ok {
file, line := err.Location()
if file != "" {
s = append(s, fmt.Sprintf("%s:%d", file, line)...)
s = append(s, ": "...)
}
}
if cerr, ok := err.(wrapper); ok {
s = append(s, cerr.Message()...)
err = cerr.Underlying()
} else {
s = append(s, err.Error()...)
err = nil
}
s = append(s, '}')
if err == nil {
break
}
s = append(s, ' ')
}
s = append(s, ']')
return string(s)
}
// ErrorStack returns a string representation of the annotated error. If the
// error passed as the parameter is not an annotated error, the result is
// simply the result of the Error() method on that error.
//
// If the error is an annotated error, a multi-line string is returned where
// each line represents one entry in the annotation stack. The full filename
// from the call stack is used in the output.
//
// first error
// github.com/juju/errors/annotation_test.go:193:
// github.com/juju/errors/annotation_test.go:194: annotation
// github.com/juju/errors/annotation_test.go:195:
// github.com/juju/errors/annotation_test.go:196: more context
// github.com/juju/errors/annotation_test.go:197:
func ErrorStack(err error) string {
return strings.Join(errorStack(err), "\n")
}
func errorStack(err error) []string {
if err == nil {
return nil
}
// We want the first error first
var lines []string
for {
var buff []byte
if err, ok := err.(Locationer); ok {
file, line := err.Location()
// Strip off the leading GOPATH/src path elements.
if file != "" {
buff = append(buff, fmt.Sprintf("%s:%d", file, line)...)
buff = append(buff, ": "...)
}
}
if cerr, ok := err.(wrapper); ok {
message := cerr.Message()
buff = append(buff, message...)
// If there is a cause for this error, and it is different to the cause
// of the underlying error, then output the error string in the stack trace.
var cause error
if err1, ok := err.(causer); ok {
cause = err1.Cause()
}
err = cerr.Underlying()
if cause != nil && !sameError(Cause(err), cause) {
if message != "" {
buff = append(buff, ": "...)
}
buff = append(buff, cause.Error()...)
}
} else {
buff = append(buff, err.Error()...)
err = nil
}
lines = append(lines, string(buff))
if err == nil {
break
}
}
// reverse the lines to get the original error, which was at the end of
// the list, back to the start.
var result []string
for i := len(lines); i > 0; i-- {
result = append(result, lines[i-1])
}
return result
}
// Unwrap is a proxy for the Unwrap function in Go's standard `errors` library
// (pkg.go.dev/errors).
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}
// Is is a proxy for the Is function in Go's standard `errors` library
// (pkg.go.dev/errors).
func Is(err, target error) bool {
return stderrors.Is(err, target)
}
// As is a proxy for the As function in Go's standard `errors` library
// (pkg.go.dev/errors).
func As(err error, target interface{}) bool {
return stderrors.As(err, target)
}

1
vendor/github.com/juju/retry/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
*.test

191
vendor/github.com/juju/retry/LICENSE generated vendored Normal file
View file

@ -0,0 +1,191 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

15
vendor/github.com/juju/retry/Makefile generated vendored Normal file
View file

@ -0,0 +1,15 @@
PROJECT := github.com/juju/retry
default: check
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check: check-licence
go test $(PROJECT)/...
docs:
godoc2md $(PROJECT) > README.md

277
vendor/github.com/juju/retry/README.md generated vendored Normal file
View file

@ -0,0 +1,277 @@
# retry
import "github.com/juju/retry"
The retry package encapsulates the mechanism around retrying commands.
The simple use is to call retry.Call with a function closure.
```go
err := retry.Call(retry.CallArgs{
Func: func() error { ... },
Attempts: 5,
Delay: time.Minute,
Clock: clock.WallClock,
})
```
The bare minimum arguments that need to be specified are:
* Func - the function to call
* Attempts - the number of times to try Func before giving up, or a negative number for unlimited attempts (`retry.UnlimitedAttempts`)
* Delay - how long to wait between each try that returns an error
* Clock - either the wall clock, or some testing clock
Any error that is returned from the `Func` is considered transient.
In order to identify some errors as fatal, pass in a function for the
`IsFatalError` CallArgs value.
In order to have the `Delay` change for each iteration, a `BackoffFunc`
needs to be set on the CallArgs. A simple doubling delay function is
provided by `DoubleDelay`.
An example of a more complex `BackoffFunc` could be a stepped function such
as:
```go
func StepDelay(last time.Duration, attempt int) time.Duration {
switch attempt{
case 1:
return time.Second
case 2:
return 5 * time.Second
case 3:
return 20 * time.Second
case 4:
return time.Minute
case 5:
return 5 * time.Minute
default:
return 2 * last
}
}
```
Consider some package `foo` that has a `TryAgainError`, which looks something
like this:
```go
type TryAgainError struct {
After time.Duration
}
```
and we create something that looks like this:
```go
type TryAgainHelper struct {
next time.Duration
}
func (h *TryAgainHelper) notify(lastError error, attempt int) {
if tryAgain, ok := lastError.(*foo.TryAgainError); ok {
h.next = tryAgain.After
} else {
h.next = 0
}
}
func (h *TryAgainHelper) next(last time.Duration) time.Duration {
if h.next != 0 {
return h.next
}
return last
}
```
Then we could do this:
```go
helper := TryAgainHelper{}
retry.Call(retry.CallArgs{
Func: func() error {
return foo.SomeFunc()
},
NotifyFunc: helper.notify,
BackoffFunc: helper.next,
Attempts: 20,
Delay: 100 * time.Millisecond,
Clock: clock.WallClock,
})
```
## Constants
``` go
const (
// UnlimitedAttempts can be used as a value for `Attempts` to clearly
// show to the reader that there is no limit to the number of attempts.
UnlimitedAttempts = -1
)
```
## func Call
``` go
func Call(args CallArgs) error
```
Call will repeatedly execute the Func until either the function returns no
error, the retry count is exceeded or the stop channel is closed.
## func DoubleDelay
``` go
func DoubleDelay(delay time.Duration, attempt int) time.Duration
```
DoubleDelay provides a simple function that doubles the duration passed in.
This can then be easily used as the `BackoffFunc` in the `CallArgs`
structure.
## func ExpBackoff
``` go
func ExpBackoff(minDelay, maxDelay time.Duration, exp float64, applyJitter bool) func(time.Duration, int) time.Duration {
```
ExpBackoff returns a function a which generates time.Duration values using an
exponential back-off algorithm with the specified parameters. The returned value
can then be easily used as the `BackoffFunc` in the `CallArgs` structure.
The next delay value is calculated using the following formula:
`newDelay = min(minDelay * exp^attempt, maxDelay)`
If `applyJitter` is set to `true`, the function will randomly select and return
back a value in the `[minDelay, newDelay]` range.
## func IsAttemptsExceeded
``` go
func IsAttemptsExceeded(err error) bool
```
IsAttemptsExceeded returns true if the error is the result of the `Call`
function finishing due to hitting the requested number of `Attempts`.
## func IsDurationExceeded
``` go
func IsDurationExceeded(err error) bool
```
IsDurationExceeded returns true if the error is the result of the `Call`
function finishing due to the total duration exceeding the specified
`MaxDuration` value.
## func IsRetryStopped
``` go
func IsRetryStopped(err error) bool
```
IsRetryStopped returns true if the error is the result of the `Call`
function finishing due to the stop channel being closed.
## func LastError
``` go
func LastError(err error) error
```
LastError retrieves the last error returned from `Func` before iteration
was terminated due to the attempt count being exceeded, the maximum
duration being exceeded, or the stop channel being closed.
## type CallArgs
``` go
type CallArgs struct {
// Func is the function that will be retried if it returns an error result.
Func func() error
// IsFatalError is a function that, if set, will be called for every non-
// nil error result from `Func`. If `IsFatalError` returns true, the error
// is immediately returned breaking out from any further retries.
IsFatalError func(error) bool
// NotifyFunc is a function that is called if Func fails, and the attempt
// number. The first time this function is called attempt is 1, the second
// time, attempt is 2 and so on.
NotifyFunc func(lastError error, attempt int)
// Attempts specifies the number of times Func should be retried before
// giving up and returning the `AttemptsExceeded` error. If a negative
// value is specified, the `Call` will retry forever.
Attempts int
// Delay specifies how long to wait between retries.
Delay time.Duration
// MaxDelay specifies how longest time to wait between retries. If no
// value is specified there is no maximum delay.
MaxDelay time.Duration
// MaxDuration specifies the maximum time the `Call` function should spend
// iterating over `Func`. The duration is calculated from the start of the
// `Call` function. If the next delay time would take the total duration
// of the call over MaxDuration, then a DurationExceeded error is
// returned. If no value is specified, Call will continue until the number
// of attempts is complete.
MaxDuration time.Duration
// BackoffFunc allows the caller to provide a function that alters the
// delay each time through the loop. If this function is not provided the
// delay is the same each iteration. Alternatively a function such as
// `retry.DoubleDelay` can be used that will provide an exponential
// backoff. The first time this function is called attempt is 1, the
// second time, attempt is 2 and so on.
BackoffFunc func(delay time.Duration, attempt int) time.Duration
// Clock provides the mechanism for waiting. Normal program execution is
// expected to use something like clock.WallClock, and tests can override
// this to not actually sleep in tests.
Clock clock.Clock
// Stop is a channel that can be used to indicate that the waiting should
// be interrupted. If Stop is nil, then the Call function cannot be interrupted.
// If the channel is closed prior to the Call function being executed, the
// Func is still attempted once.
Stop <-chan struct{}
}
```
CallArgs is a simple structure used to define the behaviour of the Call
function.
### func (\*CallArgs) Validate
``` go
func (args *CallArgs) Validate() error
```
Validate the values are valid. The ensures that the Func, Delay, Attempts
and Clock have been specified.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

16
vendor/github.com/juju/retry/clock.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package retry
import "time"
// Clock provides an interface for dealing with clocks.
type Clock interface {
// Now returns the current clock time.
Now() time.Time
// After waits for the duration to elapse and then sends the
// current time on the returned channel.
After(time.Duration) <-chan time.Time
}

91
vendor/github.com/juju/retry/doc.go generated vendored Normal file
View file

@ -0,0 +1,91 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
// The retry package encapsulates the mechanism around retrying commands.
//
// The simple use is to call retry.Call with a function closure.
//
// err := retry.Call(retry.CallArgs{
// Func: func() error { ... },
// Attempts: 5,
// Delay: time.Minute,
// Clock: clock.WallClock,
// })
//
// The bare minimum arguments that need to be specified are:
// * Func - the function to call
// * Attempts - the number of times to try Func before giving up, or a negative number for unlimited attempts (`retry.UnlimitedAttempts`)
// * Delay - how long to wait between each try that returns an error
// * Clock - either the wall clock, or some testing clock
//
// Any error that is returned from the Func is considered transient.
// In order to identify some errors as fatal, pass in a function for the
// IsFatalError CallArgs value.
//
// In order to have the Delay change for each iteration, a BackoffFunc
// needs to be set on the CallArgs. A simple doubling delay function is
// provided by DoubleDelay.
//
// An example of a more complex BackoffFunc could be a stepped function such
// as:
//
// func StepDelay(last time.Duration, attempt int) time.Duration {
// switch attempt{
// case 1:
// return time.Second
// case 2:
// return 5 * time.Second
// case 3:
// return 20 * time.Second
// case 4:
// return time.Minute
// case 5:
// return 5 * time.Minute
// default:
// return 2 * last
// }
// }
//
// Consider some package foo that has a TryAgainError, which looks something
// like this:
//
// type TryAgainError struct {
// After time.Duration
// }
//
// and we create something that looks like this:
//
// type TryAgainHelper struct {
// next time.Duration
// }
//
// func (h *TryAgainHelper) notify(lastError error, attempt int) {
// if tryAgain, ok := lastError.(*foo.TryAgainError); ok {
// h.next = tryAgain.After
// } else {
// h.next = 0
// }
// }
//
// func (h *TryAgainHelper) next(last time.Duration) time.Duration {
// if h.next != 0 {
// return h.next
// }
// return last
// }
//
// Then we could do this:
//
// helper := TryAgainHelper{}
// retry.Call(retry.CallArgs{
// Func: func() error {
// return foo.SomeFunc()
// },
// NotifyFunc: helper.notify,
// BackoffFunc: helper.next,
// Attempts: 20,
// Delay: 100 * time.Millisecond,
// Clock: clock.WallClock,
// })
//
package retry

258
vendor/github.com/juju/retry/retry.go generated vendored Normal file
View file

@ -0,0 +1,258 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package retry
import (
"fmt"
"math"
"math/rand"
"time"
"github.com/juju/errors"
)
const (
// UnlimitedAttempts can be used as a value for Attempts to clearly
// show to the reader that there is no limit to the number of attempts.
UnlimitedAttempts = -1
)
// retryStopped is the error that is returned from the Call function
// when the stop channel has been closed.
type retryStopped struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *retryStopped) Error() string {
return fmt.Sprintf("retry stopped")
}
// attemptsExceeded is the error that is returned when the retry count has
// been hit without the function returning a nil error result. The last error
// returned from the function being retried is available as the LastError
// attribute.
type attemptsExceeded struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *attemptsExceeded) Error() string {
return fmt.Sprintf("attempt count exceeded: %s", e.lastError)
}
// durationExceeded is the error that is returned when the total time that the
// Call function would have executed exceeds the MaxDuration specified.
// The last error returned from the function being retried is available as the
// LastError attribute.
type durationExceeded struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *durationExceeded) Error() string {
return fmt.Sprintf("max duration exceeded: %s", e.lastError)
}
// LastError retrieves the last error returned from Func before iteration
// was terminated due to the attempt count being exceeded, the maximum
// duration being exceeded, or the stop channel being closed.
func LastError(err error) error {
cause := errors.Cause(err)
switch err := cause.(type) {
case *attemptsExceeded:
return err.lastError
case *retryStopped:
return err.lastError
case *durationExceeded:
return err.lastError
}
return errors.Errorf("unexpected error type: %T, %s", cause, cause)
}
// IsAttemptsExceeded returns true if the error is the result of the Call
// function finishing due to hitting the requested number of Attempts.
func IsAttemptsExceeded(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*attemptsExceeded)
return ok
}
// IsDurationExceeded returns true if the error is the result of the Call
// function finishing due to the total duration exceeding the specified
// MaxDuration value.
func IsDurationExceeded(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*durationExceeded)
return ok
}
// IsRetryStopped returns true if the error is the result of the Call
// function finishing due to the stop channel being closed.
func IsRetryStopped(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*retryStopped)
return ok
}
// CallArgs is a simple structure used to define the behaviour of the Call
// function.
type CallArgs struct {
// Func is the function that will be retried if it returns an error result.
Func func() error
// IsFatalError is a function that, if set, will be called for every non-
// nil error result from Func. If IsFatalError returns true, the error
// is immediately returned breaking out from any further retries.
IsFatalError func(error) bool
// NotifyFunc is a function that is called if Func fails, and the attempt
// number. The first time this function is called attempt is 1, the second
// time, attempt is 2 and so on.
NotifyFunc func(lastError error, attempt int)
// Attempts specifies the number of times Func should be retried before
// giving up and returning the AttemptsExceeded error. If a negative
// value is specified, the Call will retry forever.
Attempts int
// Delay specifies how long to wait between retries.
Delay time.Duration
// MaxDelay specifies how longest time to wait between retries. If no
// value is specified there is no maximum delay.
MaxDelay time.Duration
// MaxDuration specifies the maximum time the Call function should spend
// iterating over Func. The duration is calculated from the start of the
// Call function. If the next delay time would take the total duration
// of the call over MaxDuration, then a DurationExceeded error is
// returned. If no value is specified, Call will continue until the number
// of attempts is complete.
MaxDuration time.Duration
// BackoffFunc allows the caller to provide a function that alters the
// delay each time through the loop. If this function is not provided the
// delay is the same each iteration. Alternatively a function such as
// retry.DoubleDelay can be used that will provide an exponential
// backoff. The first time this function is called attempt is 1, the
// second time, attempt is 2 and so on.
BackoffFunc func(delay time.Duration, attempt int) time.Duration
// Clock provides the mechanism for waiting. Normal program execution is
// expected to use something like clock.WallClock, and tests can override
// this to not actually sleep in tests.
Clock Clock
// Stop is a channel that can be used to indicate that the waiting should
// be interrupted. If Stop is nil, then the Call function cannot be interrupted.
// If the channel is closed prior to the Call function being executed, the
// Func is still attempted once.
Stop <-chan struct{}
}
// Validate the values are valid. The ensures that the Func, Delay, Attempts
// and Clock have been specified.
func (args *CallArgs) Validate() error {
if args.Func == nil {
return errors.NotValidf("missing Func")
}
if args.Delay == 0 {
return errors.NotValidf("missing Delay")
}
if args.Clock == nil {
return errors.NotValidf("missing Clock")
}
// One of Attempts or MaxDuration need to be specified
if args.Attempts == 0 && args.MaxDuration == 0 {
return errors.NotValidf("missing Attempts or MaxDuration")
}
return nil
}
// Call will repeatedly execute the Func until either the function returns no
// error, the retry count is exceeded or the stop channel is closed.
func Call(args CallArgs) error {
err := args.Validate()
if err != nil {
return errors.Trace(err)
}
start := args.Clock.Now()
for i := 1; args.Attempts <= 0 || i <= args.Attempts; i++ {
err = args.Func()
if err == nil {
return nil
}
if args.IsFatalError != nil && args.IsFatalError(err) {
return errors.Trace(err)
}
if args.NotifyFunc != nil {
args.NotifyFunc(err, i)
}
if i == args.Attempts && args.Attempts > 0 {
break // don't wait before returning the error
}
if args.BackoffFunc != nil {
delay := args.BackoffFunc(args.Delay, i)
if delay > args.MaxDelay && args.MaxDelay > 0 {
delay = args.MaxDelay
}
args.Delay = delay
}
elapsedTime := args.Clock.Now().Sub(start)
if args.MaxDuration > 0 && (elapsedTime+args.Delay) > args.MaxDuration {
return errors.Wrap(err, &durationExceeded{err})
}
// Wait for the delay, and retry
select {
case <-args.Clock.After(args.Delay):
case <-args.Stop:
return errors.Wrap(err, &retryStopped{err})
}
}
return errors.Wrap(err, &attemptsExceeded{err})
}
// DoubleDelay provides a simple function that doubles the duration passed in.
// This can then be easily used as the BackoffFunc in the CallArgs
// structure.
func DoubleDelay(delay time.Duration, attempt int) time.Duration {
if attempt == 1 {
return delay
}
return delay * 2
}
// ExpBackoff returns a function a which generates time.Duration values using
// an exponential back-off algorithm with the specified parameters. The
// returned value can then be easily used as the BackoffFunc in the CallArgs
// structure.
//
// The next delay value is calculated using the following formula:
// newDelay = min(minDelay * exp^attempt, maxDelay)
//
// If applyJitter is set to true, the function will randomly select and return
// back a value in the [minDelay, newDelay] range.
func ExpBackoff(minDelay, maxDelay time.Duration, exp float64, applyJitter bool) func(time.Duration, int) time.Duration {
minDelayF := float64(minDelay)
maxDelayF := float64(maxDelay)
return func(_ time.Duration, attempt int) time.Duration {
newDelay := minDelayF * math.Pow(exp, float64(attempt))
if newDelay > maxDelayF {
newDelay = maxDelayF
}
// Return a random value in the [minDelay, newDelay) range.
if applyJitter {
newDelay = rand.Float64() * newDelay
if newDelay < minDelayF {
newDelay = minDelayF
}
}
return time.Duration(newDelay).Round(time.Millisecond)
}
}

21
vendor/github.com/stretchr/objx/.codeclimate.yml generated vendored Normal file
View file

@ -0,0 +1,21 @@
engines:
gofmt:
enabled: true
golint:
enabled: true
govet:
enabled: true
exclude_patterns:
- ".github/"
- "vendor/"
- "codegen/"
- "*.yml"
- ".*.yml"
- "*.md"
- "Gopkg.*"
- "doc.go"
- "type_specific_codegen_test.go"
- "type_specific_codegen.go"
- ".gitignore"
- "LICENSE"

11
vendor/github.com/stretchr/objx/.gitignore generated vendored Normal file
View file

@ -0,0 +1,11 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

22
vendor/github.com/stretchr/objx/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2014 Stretchr, Inc.
Copyright (c) 2017-2018 objx contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

80
vendor/github.com/stretchr/objx/README.md generated vendored Normal file
View file

@ -0,0 +1,80 @@
# Objx
[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx)
[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx)
[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage)
[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx)
[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx)
Objx - Go package for dealing with maps, slices, JSON and other data.
Get started:
- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date)
- Check out the API Documentation http://godoc.org/github.com/stretchr/objx
## Overview
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc.
### Pattern
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going:
m, err := objx.FromJSON(json)
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking.
Use `Get` to access the value you're interested in. You can use dot and array
notation too:
m.Get("places[0].latlng")
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
if m.Get("code").IsStr() { // Your code... }
Or you can just assume the type, and use one of the strong type methods to extract the real value:
m.Get("code").Int()
If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value.
Get("code").Int(-1)
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below.
### Reading data
A simple example of how to use Objx:
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
### Ranging
Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect:
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
## Installation
To install Objx, use go get:
go get github.com/stretchr/objx
### Staying up to date
To update Objx to the latest version, run:
go get -u github.com/stretchr/objx
### Supported go versions
We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment.
## Contributing
Please feel free to submit issues, fork the repository and send pull requests!

30
vendor/github.com/stretchr/objx/Taskfile.yml generated vendored Normal file
View file

@ -0,0 +1,30 @@
version: '2'
env:
GOFLAGS: -mod=vendor
tasks:
default:
deps: [test]
lint:
desc: Checks code style
cmds:
- gofmt -d -s *.go
- go vet ./...
silent: true
lint-fix:
desc: Fixes code style
cmds:
- gofmt -w -s *.go
test:
desc: Runs go tests
cmds:
- go test -race ./...
test-coverage:
desc: Runs go tests and calucates test coverage
cmds:
- go test -race -coverprofile=c.out ./...

197
vendor/github.com/stretchr/objx/accessors.go generated vendored Normal file
View file

@ -0,0 +1,197 @@
package objx
import (
"reflect"
"regexp"
"strconv"
"strings"
)
const (
// PathSeparator is the character used to separate the elements
// of the keypath.
//
// For example, `location.address.city`
PathSeparator string = "."
// arrayAccesRegexString is the regex used to extract the array number
// from the access path
arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
// mapAccessRegexString is the regex used to extract the map key
// from the access path
mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$`
)
// arrayAccesRegex is the compiled arrayAccesRegexString
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
// mapAccessRegex is the compiled mapAccessRegexString
var mapAccessRegex = regexp.MustCompile(mapAccessRegexString)
// Get gets the value using the specified selector and
// returns it inside a new Obj object.
//
// If it cannot find the value, Get will return a nil
// value inside an instance of Obj.
//
// Get can only operate directly on map[string]interface{} and []interface.
//
// Example
//
// To access the title of the third chapter of the second book, do:
//
// o.Get("books[1].chapters[2].title")
func (m Map) Get(selector string) *Value {
rawObj := access(m, selector, nil, false)
return &Value{data: rawObj}
}
// Set sets the value using the specified selector and
// returns the object on which Set was called.
//
// Set can only operate directly on map[string]interface{} and []interface
//
// Example
//
// To set the title of the third chapter of the second book, do:
//
// o.Set("books[1].chapters[2].title","Time to Go")
func (m Map) Set(selector string, value interface{}) Map {
access(m, selector, value, true)
return m
}
// getIndex returns the index, which is hold in s by two braches.
// It also returns s withour the index part, e.g. name[1] will return (1, name).
// If no index is found, -1 is returned
func getIndex(s string) (int, string) {
arrayMatches := arrayAccesRegex.FindStringSubmatch(s)
if len(arrayMatches) > 0 {
// Get the key into the map
selector := arrayMatches[1]
// Get the index into the array at the key
// We know this cannt fail because arrayMatches[2] is an int for sure
index, _ := strconv.Atoi(arrayMatches[2])
return index, selector
}
return -1, s
}
// getKey returns the key which is held in s by two brackets.
// It also returns the next selector.
func getKey(s string) (string, string) {
selSegs := strings.SplitN(s, PathSeparator, 2)
thisSel := selSegs[0]
nextSel := ""
if len(selSegs) > 1 {
nextSel = selSegs[1]
}
mapMatches := mapAccessRegex.FindStringSubmatch(s)
if len(mapMatches) > 0 {
if _, err := strconv.Atoi(mapMatches[2]); err != nil {
thisSel = mapMatches[1]
nextSel = "[" + mapMatches[2] + "]" + mapMatches[3]
if thisSel == "" {
thisSel = mapMatches[2]
nextSel = mapMatches[3]
}
if nextSel == "" {
selSegs = []string{"", ""}
} else if nextSel[0] == '.' {
nextSel = nextSel[1:]
}
}
}
return thisSel, nextSel
}
// access accesses the object using the selector and performs the
// appropriate action.
func access(current interface{}, selector string, value interface{}, isSet bool) interface{} {
thisSel, nextSel := getKey(selector)
indexes := []int{}
for strings.Contains(thisSel, "[") {
prevSel := thisSel
index := -1
index, thisSel = getIndex(thisSel)
indexes = append(indexes, index)
if prevSel == thisSel {
break
}
}
if curMap, ok := current.(Map); ok {
current = map[string]interface{}(curMap)
}
// get the object in question
switch current.(type) {
case map[string]interface{}:
curMSI := current.(map[string]interface{})
if nextSel == "" && isSet {
curMSI[thisSel] = value
return nil
}
_, ok := curMSI[thisSel].(map[string]interface{})
if !ok {
_, ok = curMSI[thisSel].(Map)
}
if (curMSI[thisSel] == nil || !ok) && len(indexes) == 0 && isSet {
curMSI[thisSel] = map[string]interface{}{}
}
current = curMSI[thisSel]
default:
current = nil
}
// do we need to access the item of an array?
if len(indexes) > 0 {
num := len(indexes)
for num > 0 {
num--
index := indexes[num]
indexes = indexes[:num]
if array, ok := interSlice(current); ok {
if index < len(array) {
current = array[index]
} else {
current = nil
break
}
}
}
}
if nextSel != "" {
current = access(current, nextSel, value, isSet)
}
return current
}
func interSlice(slice interface{}) ([]interface{}, bool) {
if array, ok := slice.([]interface{}); ok {
return array, ok
}
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
return nil, false
}
ret := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
return ret, true
}

280
vendor/github.com/stretchr/objx/conversions.go generated vendored Normal file
View file

@ -0,0 +1,280 @@
package objx
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/url"
"strconv"
)
// SignatureSeparator is the character that is used to
// separate the Base64 string from the security signature.
const SignatureSeparator = "_"
// URLValuesSliceKeySuffix is the character that is used to
// specify a suffic for slices parsed by URLValues.
// If the suffix is set to "[i]", then the index of the slice
// is used in place of i
// Ex: Suffix "[]" would have the form a[]=b&a[]=c
// OR Suffix "[i]" would have the form a[0]=b&a[1]=c
// OR Suffix "" would have the form a=b&a=c
var urlValuesSliceKeySuffix = "[]"
const (
URLValuesSliceKeySuffixEmpty = ""
URLValuesSliceKeySuffixArray = "[]"
URLValuesSliceKeySuffixIndex = "[i]"
)
// SetURLValuesSliceKeySuffix sets the character that is used to
// specify a suffic for slices parsed by URLValues.
// If the suffix is set to "[i]", then the index of the slice
// is used in place of i
// Ex: Suffix "[]" would have the form a[]=b&a[]=c
// OR Suffix "[i]" would have the form a[0]=b&a[1]=c
// OR Suffix "" would have the form a=b&a=c
func SetURLValuesSliceKeySuffix(s string) error {
if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex {
urlValuesSliceKeySuffix = s
return nil
}
return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.")
}
// JSON converts the contained object to a JSON string
// representation
func (m Map) JSON() (string, error) {
for k, v := range m {
m[k] = cleanUp(v)
}
result, err := json.Marshal(m)
if err != nil {
err = errors.New("objx: JSON encode failed with: " + err.Error())
}
return string(result), err
}
func cleanUpInterfaceArray(in []interface{}) []interface{} {
result := make([]interface{}, len(in))
for i, v := range in {
result[i] = cleanUp(v)
}
return result
}
func cleanUpInterfaceMap(in map[interface{}]interface{}) Map {
result := Map{}
for k, v := range in {
result[fmt.Sprintf("%v", k)] = cleanUp(v)
}
return result
}
func cleanUpStringMap(in map[string]interface{}) Map {
result := Map{}
for k, v := range in {
result[k] = cleanUp(v)
}
return result
}
func cleanUpMSIArray(in []map[string]interface{}) []Map {
result := make([]Map, len(in))
for i, v := range in {
result[i] = cleanUpStringMap(v)
}
return result
}
func cleanUpMapArray(in []Map) []Map {
result := make([]Map, len(in))
for i, v := range in {
result[i] = cleanUpStringMap(v)
}
return result
}
func cleanUp(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case []map[string]interface{}:
return cleanUpMSIArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
case Map:
return cleanUpStringMap(v)
case []Map:
return cleanUpMapArray(v)
default:
return v
}
}
// MustJSON converts the contained object to a JSON string
// representation and panics if there is an error
func (m Map) MustJSON() string {
result, err := m.JSON()
if err != nil {
panic(err.Error())
}
return result
}
// Base64 converts the contained object to a Base64 string
// representation of the JSON string representation
func (m Map) Base64() (string, error) {
var buf bytes.Buffer
jsonData, err := m.JSON()
if err != nil {
return "", err
}
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
_, _ = encoder.Write([]byte(jsonData))
_ = encoder.Close()
return buf.String(), nil
}
// MustBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and panics
// if there is an error
func (m Map) MustBase64() string {
result, err := m.Base64()
if err != nil {
panic(err.Error())
}
return result
}
// SignedBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and signs it
// using the provided key.
func (m Map) SignedBase64(key string) (string, error) {
base64, err := m.Base64()
if err != nil {
return "", err
}
sig := HashWithKey(base64, key)
return base64 + SignatureSeparator + sig, nil
}
// MustSignedBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and signs it
// using the provided key and panics if there is an error
func (m Map) MustSignedBase64(key string) string {
result, err := m.SignedBase64(key)
if err != nil {
panic(err.Error())
}
return result
}
/*
URL Query
------------------------------------------------
*/
// URLValues creates a url.Values object from an Obj. This
// function requires that the wrapped object be a map[string]interface{}
func (m Map) URLValues() url.Values {
vals := make(url.Values)
m.parseURLValues(m, vals, "")
return vals
}
func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) {
useSliceIndex := false
if urlValuesSliceKeySuffix == "[i]" {
useSliceIndex = true
}
for k, v := range queryMap {
val := &Value{data: v}
switch {
case val.IsObjxMap():
if key == "" {
m.parseURLValues(val.ObjxMap(), vals, k)
} else {
m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]")
}
case val.IsObjxMapSlice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.MustObjxMapSlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
m.parseURLValues(sv, vals, sk)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
for _, sv := range val.MustObjxMapSlice() {
m.parseURLValues(sv, vals, sliceKey)
}
}
case val.IsMSISlice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.MustMSISlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
m.parseURLValues(New(sv), vals, sk)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
for _, sv := range val.MustMSISlice() {
m.parseURLValues(New(sv), vals, sliceKey)
}
}
case val.IsStrSlice(), val.IsBoolSlice(),
val.IsFloat32Slice(), val.IsFloat64Slice(),
val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(),
val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.StringSlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
vals.Set(sk, sv)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
vals[sliceKey] = val.StringSlice()
}
default:
if key == "" {
vals.Set(k, val.String())
} else {
vals.Set(key+"["+k+"]", val.String())
}
}
}
}
// URLQuery gets an encoded URL query representing the given
// Obj. This function requires that the wrapped object be a
// map[string]interface{}
func (m Map) URLQuery() (string, error) {
return m.URLValues().Encode(), nil
}

66
vendor/github.com/stretchr/objx/doc.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
/*
Objx - Go package for dealing with maps, slices, JSON and other data.
Overview
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
a powerful `Get` method (among others) that allows you to easily and quickly get
access to data within the map, without having to worry too much about type assertions,
missing data, default values etc.
Pattern
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy.
Call one of the `objx.` functions to create your `objx.Map` to get going:
m, err := objx.FromJSON(json)
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
the rest will be optimistic and try to figure things out without panicking.
Use `Get` to access the value you're interested in. You can use dot and array
notation too:
m.Get("places[0].latlng")
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
if m.Get("code").IsStr() { // Your code... }
Or you can just assume the type, and use one of the strong type methods to extract the real value:
m.Get("code").Int()
If there's no value there (or if it's the wrong type) then a default value will be returned,
or you can be explicit about the default value.
Get("code").Int(-1)
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating,
manipulating and selecting that data. You can find out more by exploring the index below.
Reading data
A simple example of how to use Objx:
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
Ranging
Since `objx.Map` is a `map[string]interface{}` you can treat it as such.
For example, to `range` the data, do what you would expect:
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
*/
package objx

215
vendor/github.com/stretchr/objx/map.go generated vendored Normal file
View file

@ -0,0 +1,215 @@
package objx
import (
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/url"
"strings"
)
// MSIConvertable is an interface that defines methods for converting your
// custom types to a map[string]interface{} representation.
type MSIConvertable interface {
// MSI gets a map[string]interface{} (msi) representing the
// object.
MSI() map[string]interface{}
}
// Map provides extended functionality for working with
// untyped data, in particular map[string]interface (msi).
type Map map[string]interface{}
// Value returns the internal value instance
func (m Map) Value() *Value {
return &Value{data: m}
}
// Nil represents a nil Map.
var Nil = New(nil)
// New creates a new Map containing the map[string]interface{} in the data argument.
// If the data argument is not a map[string]interface, New attempts to call the
// MSI() method on the MSIConvertable interface to create one.
func New(data interface{}) Map {
if _, ok := data.(map[string]interface{}); !ok {
if converter, ok := data.(MSIConvertable); ok {
data = converter.MSI()
} else {
return nil
}
}
return Map(data.(map[string]interface{}))
}
// MSI creates a map[string]interface{} and puts it inside a new Map.
//
// The arguments follow a key, value pattern.
//
//
// Returns nil if any key argument is non-string or if there are an odd number of arguments.
//
// Example
//
// To easily create Maps:
//
// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
//
// // creates an Map equivalent to
// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}}
func MSI(keyAndValuePairs ...interface{}) Map {
newMap := Map{}
keyAndValuePairsLen := len(keyAndValuePairs)
if keyAndValuePairsLen%2 != 0 {
return nil
}
for i := 0; i < keyAndValuePairsLen; i = i + 2 {
key := keyAndValuePairs[i]
value := keyAndValuePairs[i+1]
// make sure the key is a string
keyString, keyStringOK := key.(string)
if !keyStringOK {
return nil
}
newMap[keyString] = value
}
return newMap
}
// ****** Conversion Constructors
// MustFromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Panics if the JSON is invalid.
func MustFromJSON(jsonString string) Map {
o, err := FromJSON(jsonString)
if err != nil {
panic("objx: MustFromJSON failed with error: " + err.Error())
}
return o
}
// MustFromJSONSlice creates a new slice of Map containing the data specified in the
// jsonString. Works with jsons with a top level array
//
// Panics if the JSON is invalid.
func MustFromJSONSlice(jsonString string) []Map {
slice, err := FromJSONSlice(jsonString)
if err != nil {
panic("objx: MustFromJSONSlice failed with error: " + err.Error())
}
return slice
}
// FromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Returns an error if the JSON is invalid.
func FromJSON(jsonString string) (Map, error) {
var m Map
err := json.Unmarshal([]byte(jsonString), &m)
if err != nil {
return Nil, err
}
return m, nil
}
// FromJSONSlice creates a new slice of Map containing the data specified in the
// jsonString. Works with jsons with a top level array
//
// Returns an error if the JSON is invalid.
func FromJSONSlice(jsonString string) ([]Map, error) {
var slice []Map
err := json.Unmarshal([]byte(jsonString), &slice)
if err != nil {
return nil, err
}
return slice, nil
}
// FromBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by Base64
func FromBase64(base64String string) (Map, error) {
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
decoded, err := ioutil.ReadAll(decoder)
if err != nil {
return nil, err
}
return FromJSON(string(decoded))
}
// MustFromBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromBase64(base64String string) Map {
result, err := FromBase64(base64String)
if err != nil {
panic("objx: MustFromBase64 failed with error: " + err.Error())
}
return result
}
// FromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by SignedBase64
func FromSignedBase64(base64String, key string) (Map, error) {
parts := strings.Split(base64String, SignatureSeparator)
if len(parts) != 2 {
return nil, errors.New("objx: Signed base64 string is malformed")
}
sig := HashWithKey(parts[0], key)
if parts[1] != sig {
return nil, errors.New("objx: Signature for base64 data does not match")
}
return FromBase64(parts[0])
}
// MustFromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromSignedBase64(base64String, key string) Map {
result, err := FromSignedBase64(base64String, key)
if err != nil {
panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
}
return result
}
// FromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
func FromURLQuery(query string) (Map, error) {
vals, err := url.ParseQuery(query)
if err != nil {
return nil, err
}
m := Map{}
for k, vals := range vals {
m[k] = vals[0]
}
return m, nil
}
// MustFromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
//
// Panics if it encounters an error
func MustFromURLQuery(query string) Map {
o, err := FromURLQuery(query)
if err != nil {
panic("objx: MustFromURLQuery failed with error: " + err.Error())
}
return o
}

77
vendor/github.com/stretchr/objx/mutations.go generated vendored Normal file
View file

@ -0,0 +1,77 @@
package objx
// Exclude returns a new Map with the keys in the specified []string
// excluded.
func (m Map) Exclude(exclude []string) Map {
excluded := make(Map)
for k, v := range m {
if !contains(exclude, k) {
excluded[k] = v
}
}
return excluded
}
// Copy creates a shallow copy of the Obj.
func (m Map) Copy() Map {
copied := Map{}
for k, v := range m {
copied[k] = v
}
return copied
}
// Merge blends the specified map with a copy of this map and returns the result.
//
// Keys that appear in both will be selected from the specified map.
// This method requires that the wrapped object be a map[string]interface{}
func (m Map) Merge(merge Map) Map {
return m.Copy().MergeHere(merge)
}
// MergeHere blends the specified map with this map and returns the current map.
//
// Keys that appear in both will be selected from the specified map. The original map
// will be modified. This method requires that
// the wrapped object be a map[string]interface{}
func (m Map) MergeHere(merge Map) Map {
for k, v := range merge {
m[k] = v
}
return m
}
// Transform builds a new Obj giving the transformer a chance
// to change the keys and values as it goes. This method requires that
// the wrapped object be a map[string]interface{}
func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
newMap := Map{}
for k, v := range m {
modifiedKey, modifiedVal := transformer(k, v)
newMap[modifiedKey] = modifiedVal
}
return newMap
}
// TransformKeys builds a new map using the specified key mapping.
//
// Unspecified keys will be unaltered.
// This method requires that the wrapped object be a map[string]interface{}
func (m Map) TransformKeys(mapping map[string]string) Map {
return m.Transform(func(key string, value interface{}) (string, interface{}) {
if newKey, ok := mapping[key]; ok {
return newKey, value
}
return key, value
})
}
// Checks if a string slice contains a string
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

12
vendor/github.com/stretchr/objx/security.go generated vendored Normal file
View file

@ -0,0 +1,12 @@
package objx
import (
"crypto/sha1"
"encoding/hex"
)
// HashWithKey hashes the specified string using the security key
func HashWithKey(data, key string) string {
d := sha1.Sum([]byte(data + ":" + key))
return hex.EncodeToString(d[:])
}

17
vendor/github.com/stretchr/objx/tests.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
package objx
// Has gets whether there is something at the specified selector
// or not.
//
// If m is nil, Has will always return false.
func (m Map) Has(selector string) bool {
if m == nil {
return false
}
return !m.Get(selector).IsNil()
}
// IsNil gets whether the data is nil or not.
func (v *Value) IsNil() bool {
return v == nil || v.data == nil
}

346
vendor/github.com/stretchr/objx/type_specific.go generated vendored Normal file
View file

@ -0,0 +1,346 @@
package objx
/*
MSI (map[string]interface{} and []map[string]interface{})
*/
// MSI gets the value as a map[string]interface{}, returns the optionalDefault
// value or a system default object if the value is the wrong type.
func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
if s, ok := v.data.(Map); ok {
return map[string]interface{}(s)
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
// MustMSI gets the value as a map[string]interface{}.
//
// Panics if the object is not a map[string]interface{}.
func (v *Value) MustMSI() map[string]interface{} {
if s, ok := v.data.(Map); ok {
return map[string]interface{}(s)
}
return v.data.(map[string]interface{})
}
// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
// value or nil if the value is not a []map[string]interface{}.
func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
if s, ok := v.data.([]map[string]interface{}); ok {
return s
}
s := v.ObjxMapSlice()
if s == nil {
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
result := make([]map[string]interface{}, len(s))
for i := range s {
result[i] = s[i].Value().MSI()
}
return result
}
// MustMSISlice gets the value as a []map[string]interface{}.
//
// Panics if the object is not a []map[string]interface{}.
func (v *Value) MustMSISlice() []map[string]interface{} {
if s := v.MSISlice(); s != nil {
return s
}
return v.data.([]map[string]interface{})
}
// IsMSI gets whether the object contained is a map[string]interface{} or not.
func (v *Value) IsMSI() bool {
_, ok := v.data.(map[string]interface{})
if !ok {
_, ok = v.data.(Map)
}
return ok
}
// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
func (v *Value) IsMSISlice() bool {
_, ok := v.data.([]map[string]interface{})
if !ok {
_, ok = v.data.([]Map)
if !ok {
s, ok := v.data.([]interface{})
if ok {
for i := range s {
switch s[i].(type) {
case Map:
case map[string]interface{}:
default:
return false
}
}
return true
}
}
}
return ok
}
// EachMSI calls the specified callback for each object
// in the []map[string]interface{}.
//
// Panics if the object is the wrong type.
func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
for index, val := range v.MustMSISlice() {
carryon := callback(index, val)
if !carryon {
break
}
}
return v
}
// WhereMSI uses the specified decider function to select items
// from the []map[string]interface{}. The object contained in the result will contain
// only the selected items.
func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
var selected []map[string]interface{}
v.EachMSI(func(index int, val map[string]interface{}) bool {
shouldSelect := decider(index, val)
if !shouldSelect {
selected = append(selected, val)
}
return true
})
return &Value{data: selected}
}
// GroupMSI uses the specified grouper function to group the items
// keyed by the return of the grouper. The object contained in the
// result will contain a map[string][]map[string]interface{}.
func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
groups := make(map[string][]map[string]interface{})
v.EachMSI(func(index int, val map[string]interface{}) bool {
group := grouper(index, val)
if _, ok := groups[group]; !ok {
groups[group] = make([]map[string]interface{}, 0)
}
groups[group] = append(groups[group], val)
return true
})
return &Value{data: groups}
}
// ReplaceMSI uses the specified function to replace each map[string]interface{}s
// by iterating each item. The data in the returned result will be a
// []map[string]interface{} containing the replaced items.
func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
arr := v.MustMSISlice()
replaced := make([]map[string]interface{}, len(arr))
v.EachMSI(func(index int, val map[string]interface{}) bool {
replaced[index] = replacer(index, val)
return true
})
return &Value{data: replaced}
}
// CollectMSI uses the specified collector function to collect a value
// for each of the map[string]interface{}s in the slice. The data returned will be a
// []interface{}.
func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
arr := v.MustMSISlice()
collected := make([]interface{}, len(arr))
v.EachMSI(func(index int, val map[string]interface{}) bool {
collected[index] = collector(index, val)
return true
})
return &Value{data: collected}
}
/*
ObjxMap ((Map) and [](Map))
*/
// ObjxMap gets the value as a (Map), returns the optionalDefault
// value or a system default object if the value is the wrong type.
func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
if s, ok := v.data.((Map)); ok {
return s
}
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return New(nil)
}
// MustObjxMap gets the value as a (Map).
//
// Panics if the object is not a (Map).
func (v *Value) MustObjxMap() Map {
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
return v.data.((Map))
}
// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
// value or nil if the value is not a [](Map).
func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
if s, ok := v.data.([]Map); ok {
return s
}
if s, ok := v.data.([]map[string]interface{}); ok {
result := make([]Map, len(s))
for i := range s {
result[i] = s[i]
}
return result
}
s, ok := v.data.([]interface{})
if !ok {
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
result := make([]Map, len(s))
for i := range s {
switch s[i].(type) {
case Map:
result[i] = s[i].(Map)
case map[string]interface{}:
result[i] = New(s[i])
default:
return nil
}
}
return result
}
// MustObjxMapSlice gets the value as a [](Map).
//
// Panics if the object is not a [](Map).
func (v *Value) MustObjxMapSlice() [](Map) {
if s := v.ObjxMapSlice(); s != nil {
return s
}
return v.data.([](Map))
}
// IsObjxMap gets whether the object contained is a (Map) or not.
func (v *Value) IsObjxMap() bool {
_, ok := v.data.((Map))
if !ok {
_, ok = v.data.(map[string]interface{})
}
return ok
}
// IsObjxMapSlice gets whether the object contained is a [](Map) or not.
func (v *Value) IsObjxMapSlice() bool {
_, ok := v.data.([](Map))
if !ok {
_, ok = v.data.([]map[string]interface{})
if !ok {
s, ok := v.data.([]interface{})
if ok {
for i := range s {
switch s[i].(type) {
case Map:
case map[string]interface{}:
default:
return false
}
}
return true
}
}
}
return ok
}
// EachObjxMap calls the specified callback for each object
// in the [](Map).
//
// Panics if the object is the wrong type.
func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
for index, val := range v.MustObjxMapSlice() {
carryon := callback(index, val)
if !carryon {
break
}
}
return v
}
// WhereObjxMap uses the specified decider function to select items
// from the [](Map). The object contained in the result will contain
// only the selected items.
func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
var selected [](Map)
v.EachObjxMap(func(index int, val Map) bool {
shouldSelect := decider(index, val)
if !shouldSelect {
selected = append(selected, val)
}
return true
})
return &Value{data: selected}
}
// GroupObjxMap uses the specified grouper function to group the items
// keyed by the return of the grouper. The object contained in the
// result will contain a map[string][](Map).
func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
groups := make(map[string][](Map))
v.EachObjxMap(func(index int, val Map) bool {
group := grouper(index, val)
if _, ok := groups[group]; !ok {
groups[group] = make([](Map), 0)
}
groups[group] = append(groups[group], val)
return true
})
return &Value{data: groups}
}
// ReplaceObjxMap uses the specified function to replace each (Map)s
// by iterating each item. The data in the returned result will be a
// [](Map) containing the replaced items.
func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
arr := v.MustObjxMapSlice()
replaced := make([](Map), len(arr))
v.EachObjxMap(func(index int, val Map) bool {
replaced[index] = replacer(index, val)
return true
})
return &Value{data: replaced}
}
// CollectObjxMap uses the specified collector function to collect a value
// for each of the (Map)s in the slice. The data returned will be a
// []interface{}.
func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
arr := v.MustObjxMapSlice()
collected := make([]interface{}, len(arr))
v.EachObjxMap(func(index int, val Map) bool {
collected[index] = collector(index, val)
return true
})
return &Value{data: collected}
}

2261
vendor/github.com/stretchr/objx/type_specific_codegen.go generated vendored Normal file

File diff suppressed because it is too large Load diff

159
vendor/github.com/stretchr/objx/value.go generated vendored Normal file
View file

@ -0,0 +1,159 @@
package objx
import (
"fmt"
"strconv"
)
// Value provides methods for extracting interface{} data in various
// types.
type Value struct {
// data contains the raw data being managed by this Value
data interface{}
}
// Data returns the raw data contained by this Value
func (v *Value) Data() interface{} {
return v.data
}
// String returns the value always as a string
func (v *Value) String() string {
switch {
case v.IsNil():
return ""
case v.IsStr():
return v.Str()
case v.IsBool():
return strconv.FormatBool(v.Bool())
case v.IsFloat32():
return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32)
case v.IsFloat64():
return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
case v.IsInt():
return strconv.FormatInt(int64(v.Int()), 10)
case v.IsInt8():
return strconv.FormatInt(int64(v.Int8()), 10)
case v.IsInt16():
return strconv.FormatInt(int64(v.Int16()), 10)
case v.IsInt32():
return strconv.FormatInt(int64(v.Int32()), 10)
case v.IsInt64():
return strconv.FormatInt(v.Int64(), 10)
case v.IsUint():
return strconv.FormatUint(uint64(v.Uint()), 10)
case v.IsUint8():
return strconv.FormatUint(uint64(v.Uint8()), 10)
case v.IsUint16():
return strconv.FormatUint(uint64(v.Uint16()), 10)
case v.IsUint32():
return strconv.FormatUint(uint64(v.Uint32()), 10)
case v.IsUint64():
return strconv.FormatUint(v.Uint64(), 10)
}
return fmt.Sprintf("%#v", v.Data())
}
// StringSlice returns the value always as a []string
func (v *Value) StringSlice(optionalDefault ...[]string) []string {
switch {
case v.IsStrSlice():
return v.MustStrSlice()
case v.IsBoolSlice():
slice := v.MustBoolSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatBool(iv)
}
return vals
case v.IsFloat32Slice():
slice := v.MustFloat32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32)
}
return vals
case v.IsFloat64Slice():
slice := v.MustFloat64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatFloat(iv, 'f', -1, 64)
}
return vals
case v.IsIntSlice():
slice := v.MustIntSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt8Slice():
slice := v.MustInt8Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt16Slice():
slice := v.MustInt16Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt32Slice():
slice := v.MustInt32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt64Slice():
slice := v.MustInt64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(iv, 10)
}
return vals
case v.IsUintSlice():
slice := v.MustUintSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint8Slice():
slice := v.MustUint8Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint16Slice():
slice := v.MustUint16Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint32Slice():
slice := v.MustUint32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint64Slice():
slice := v.MustUint64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(iv, 10)
}
return vals
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return []string{}
}

44
vendor/github.com/stretchr/testify/mock/doc.go generated vendored Normal file
View file

@ -0,0 +1,44 @@
// Package mock provides a system by which it is possible to mock your objects
// and verify calls are happening as expected.
//
// Example Usage
//
// The mock package provides an object, Mock, that tracks activity on another object. It is usually
// embedded into a test object as shown below:
//
// type MyTestObject struct {
// // add a Mock object instance
// mock.Mock
//
// // other fields go here as normal
// }
//
// When implementing the methods of an interface, you wire your functions up
// to call the Mock.Called(args...) method, and return the appropriate values.
//
// For example, to mock a method that saves the name and age of a person and returns
// the year of their birth or an error, you might write this:
//
// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
// args := o.Called(firstname, lastname, age)
// return args.Int(0), args.Error(1)
// }
//
// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
// index position. Given this argument list:
//
// (12, true, "Something")
//
// You could read them out strongly typed like this:
//
// args.Int(0)
// args.Bool(1)
// args.String(2)
//
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
//
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
//
// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
// cases you should check for nil first.
package mock

1098
vendor/github.com/stretchr/testify/mock/mock.go generated vendored Normal file

File diff suppressed because it is too large Load diff

17
vendor/modules.txt vendored
View file

@ -60,6 +60,15 @@ github.com/jinzhu/inflection
# github.com/jinzhu/now v1.1.5 # github.com/jinzhu/now v1.1.5
## explicit; go 1.12 ## explicit; go 1.12
github.com/jinzhu/now github.com/jinzhu/now
# github.com/juju/clock v0.0.0-20220704231616-a2b96c8eeb27
## explicit; go 1.17
github.com/juju/clock
# github.com/juju/errors v0.0.0-20220328032053-6664a20db930
## explicit; go 1.17
github.com/juju/errors
# github.com/juju/retry v0.0.0-20220204093819-62423bf33287
## explicit; go 1.17
github.com/juju/retry
# github.com/juju/webbrowser v1.0.0 # github.com/juju/webbrowser v1.0.0
## explicit; go 1.11 ## explicit; go 1.11
github.com/juju/webbrowser github.com/juju/webbrowser
@ -150,10 +159,16 @@ github.com/spf13/cobra
# github.com/spf13/pflag v1.0.5 # github.com/spf13/pflag v1.0.5
## explicit; go 1.12 ## explicit; go 1.12
github.com/spf13/pflag github.com/spf13/pflag
# github.com/stretchr/objx v0.4.0
## explicit; go 1.12
github.com/stretchr/objx
# github.com/stretchr/testify v1.8.0 # github.com/stretchr/testify v1.8.0
## explicit; go 1.13 ## explicit; go 1.13
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
github.com/stretchr/testify/require github.com/stretchr/testify/require
# github.com/xdg-go/stringprep v1.0.3
## explicit; go 1.11
# golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 # golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
## explicit; go 1.17 ## explicit; go 1.17
golang.org/x/crypto/bcrypt golang.org/x/crypto/bcrypt
@ -237,8 +252,6 @@ google.golang.org/protobuf/reflect/protoregistry
google.golang.org/protobuf/runtime/protoiface google.golang.org/protobuf/runtime/protoiface
google.golang.org/protobuf/runtime/protoimpl google.golang.org/protobuf/runtime/protoimpl
google.golang.org/protobuf/types/descriptorpb google.golang.org/protobuf/types/descriptorpb
# gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
## explicit; go 1.11
# gopkg.in/errgo.v1 v1.0.1 # gopkg.in/errgo.v1 v1.0.1
## explicit ## explicit
gopkg.in/errgo.v1 gopkg.in/errgo.v1