This commit is contained in:
parent
77df394e57
commit
a375cd214c
10
go.mod
10
go.mod
@ -5,19 +5,21 @@ go 1.15
|
|||||||
require (
|
require (
|
||||||
github.com/antchfx/htmlquery v1.0.0
|
github.com/antchfx/htmlquery v1.0.0
|
||||||
github.com/antchfx/xpath v1.0.0 // indirect
|
github.com/antchfx/xpath v1.0.0 // indirect
|
||||||
github.com/gobuffalo/packr/v2 v2.8.0
|
github.com/gobuffalo/packr/v2 v2.8.1
|
||||||
|
github.com/karrick/godirwalk v1.16.1 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
||||||
github.com/labstack/echo/v4 v4.1.16
|
github.com/labstack/echo/v4 v4.1.16
|
||||||
github.com/lib/pq v1.6.0
|
github.com/lib/pq v1.6.0
|
||||||
github.com/markbates/pkger v0.14.0
|
github.com/markbates/pkger v0.14.0
|
||||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect
|
github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect
|
||||||
github.com/robfig/cron v1.2.0
|
github.com/robfig/cron v1.2.0
|
||||||
github.com/rogpeppe/go-internal v1.6.1 // indirect
|
github.com/rogpeppe/go-internal v1.6.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.6.0 // indirect
|
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
|
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
|
||||||
github.com/spf13/cobra v1.0.0 // indirect
|
github.com/spf13/cobra v1.0.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
|
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed // indirect
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7 // indirect
|
||||||
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3 // indirect
|
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3 // indirect
|
||||||
google.golang.org/appengine v1.6.2 // indirect
|
google.golang.org/appengine v1.6.2 // indirect
|
||||||
gopkg.in/ini.v1 v1.46.0
|
gopkg.in/ini.v1 v1.46.0
|
||||||
|
14
go.sum
14
go.sum
@ -54,6 +54,8 @@ github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM
|
|||||||
github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI=
|
github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI=
|
||||||
github.com/gobuffalo/packr/v2 v2.8.0 h1:IULGd15bQL59ijXLxEvA5wlMxsmx/ZkQv9T282zNVIY=
|
github.com/gobuffalo/packr/v2 v2.8.0 h1:IULGd15bQL59ijXLxEvA5wlMxsmx/ZkQv9T282zNVIY=
|
||||||
github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g=
|
github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g=
|
||||||
|
github.com/gobuffalo/packr/v2 v2.8.1 h1:tkQpju6i3EtMXJ9uoF5GT6kB+LMTimDWD8Xvbz6zDVA=
|
||||||
|
github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
@ -111,6 +113,9 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew=
|
github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew=
|
||||||
github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||||
|
github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||||
|
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||||
|
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -195,6 +200,8 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
||||||
@ -253,6 +260,8 @@ golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 h1:phUcVbl53swtrUN8kQEXFhUxPlIlWyBfKmidCu7P95o=
|
||||||
|
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@ -301,12 +310,17 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
||||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7 h1:Z991aAXPjz0tLnj74pVXW3eWJ5lHMIBvbRfMq4M2jHA=
|
||||||
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
3
packr.go
3
packr.go
@ -2,10 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gobuffalo/packr/v2"
|
"github.com/gobuffalo/packr/v2"
|
||||||
_ "github.com/gobuffalo/packr/v2/packr2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func run() {
|
func main() {
|
||||||
packr.New("static", "./static")
|
packr.New("static", "./static")
|
||||||
packr.New("templates", "./templates")
|
packr.New("templates", "./templates")
|
||||||
}
|
}
|
||||||
|
194
vendor/github.com/gobuffalo/packr/v2/SHOULDERS.md
generated
vendored
194
vendor/github.com/gobuffalo/packr/v2/SHOULDERS.md
generated
vendored
@ -1,222 +1,32 @@
|
|||||||
# github.com/gobuffalo/packr/v2 Stands on the Shoulders of Giants
|
# /Users/smichalak/dev/packr/v2 Stands on the Shoulders of Giants
|
||||||
|
|
||||||
github.com/gobuffalo/packr/v2 does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
|
/Users/smichalak/dev/packr/v2 does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
|
||||||
|
|
||||||
Thank you to the following **GIANTS**:
|
Thank you to the following **GIANTS**:
|
||||||
|
|
||||||
|
|
||||||
* [cloud.google.com/go](https://godoc.org/cloud.google.com/go)
|
|
||||||
|
|
||||||
* [github.com/BurntSushi/toml](https://godoc.org/github.com/BurntSushi/toml)
|
|
||||||
|
|
||||||
* [github.com/OneOfOne/xxhash](https://godoc.org/github.com/OneOfOne/xxhash)
|
|
||||||
|
|
||||||
* [github.com/alecthomas/template](https://godoc.org/github.com/alecthomas/template)
|
|
||||||
|
|
||||||
* [github.com/alecthomas/units](https://godoc.org/github.com/alecthomas/units)
|
|
||||||
|
|
||||||
* [github.com/armon/consul-api](https://godoc.org/github.com/armon/consul-api)
|
|
||||||
|
|
||||||
* [github.com/beorn7/perks](https://godoc.org/github.com/beorn7/perks)
|
|
||||||
|
|
||||||
* [github.com/cespare/xxhash](https://godoc.org/github.com/cespare/xxhash)
|
|
||||||
|
|
||||||
* [github.com/client9/misspell](https://godoc.org/github.com/client9/misspell)
|
|
||||||
|
|
||||||
* [github.com/coreos/bbolt](https://godoc.org/github.com/coreos/bbolt)
|
|
||||||
|
|
||||||
* [github.com/coreos/etcd](https://godoc.org/github.com/coreos/etcd)
|
|
||||||
|
|
||||||
* [github.com/coreos/go-semver](https://godoc.org/github.com/coreos/go-semver)
|
|
||||||
|
|
||||||
* [github.com/coreos/go-systemd](https://godoc.org/github.com/coreos/go-systemd)
|
|
||||||
|
|
||||||
* [github.com/coreos/pkg](https://godoc.org/github.com/coreos/pkg)
|
|
||||||
|
|
||||||
* [github.com/cpuguy83/go-md2man/v2](https://godoc.org/github.com/cpuguy83/go-md2man/v2)
|
|
||||||
|
|
||||||
* [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew)
|
|
||||||
|
|
||||||
* [github.com/dgrijalva/jwt-go](https://godoc.org/github.com/dgrijalva/jwt-go)
|
|
||||||
|
|
||||||
* [github.com/dgryski/go-sip13](https://godoc.org/github.com/dgryski/go-sip13)
|
|
||||||
|
|
||||||
* [github.com/fsnotify/fsnotify](https://godoc.org/github.com/fsnotify/fsnotify)
|
|
||||||
|
|
||||||
* [github.com/ghodss/yaml](https://godoc.org/github.com/ghodss/yaml)
|
|
||||||
|
|
||||||
* [github.com/go-kit/kit](https://godoc.org/github.com/go-kit/kit)
|
|
||||||
|
|
||||||
* [github.com/go-logfmt/logfmt](https://godoc.org/github.com/go-logfmt/logfmt)
|
|
||||||
|
|
||||||
* [github.com/go-stack/stack](https://godoc.org/github.com/go-stack/stack)
|
|
||||||
|
|
||||||
* [github.com/gobuffalo/logger](https://godoc.org/github.com/gobuffalo/logger)
|
* [github.com/gobuffalo/logger](https://godoc.org/github.com/gobuffalo/logger)
|
||||||
|
|
||||||
* [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
|
* [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
|
||||||
|
|
||||||
* [github.com/gogo/protobuf](https://godoc.org/github.com/gogo/protobuf)
|
|
||||||
|
|
||||||
* [github.com/golang/glog](https://godoc.org/github.com/golang/glog)
|
|
||||||
|
|
||||||
* [github.com/golang/groupcache](https://godoc.org/github.com/golang/groupcache)
|
|
||||||
|
|
||||||
* [github.com/golang/mock](https://godoc.org/github.com/golang/mock)
|
|
||||||
|
|
||||||
* [github.com/golang/protobuf](https://godoc.org/github.com/golang/protobuf)
|
|
||||||
|
|
||||||
* [github.com/google/btree](https://godoc.org/github.com/google/btree)
|
|
||||||
|
|
||||||
* [github.com/google/go-cmp](https://godoc.org/github.com/google/go-cmp)
|
|
||||||
|
|
||||||
* [github.com/gorilla/websocket](https://godoc.org/github.com/gorilla/websocket)
|
|
||||||
|
|
||||||
* [github.com/grpc-ecosystem/go-grpc-middleware](https://godoc.org/github.com/grpc-ecosystem/go-grpc-middleware)
|
|
||||||
|
|
||||||
* [github.com/grpc-ecosystem/go-grpc-prometheus](https://godoc.org/github.com/grpc-ecosystem/go-grpc-prometheus)
|
|
||||||
|
|
||||||
* [github.com/grpc-ecosystem/grpc-gateway](https://godoc.org/github.com/grpc-ecosystem/grpc-gateway)
|
|
||||||
|
|
||||||
* [github.com/hashicorp/hcl](https://godoc.org/github.com/hashicorp/hcl)
|
|
||||||
|
|
||||||
* [github.com/inconshreveable/mousetrap](https://godoc.org/github.com/inconshreveable/mousetrap)
|
|
||||||
|
|
||||||
* [github.com/jonboulle/clockwork](https://godoc.org/github.com/jonboulle/clockwork)
|
|
||||||
|
|
||||||
* [github.com/julienschmidt/httprouter](https://godoc.org/github.com/julienschmidt/httprouter)
|
|
||||||
|
|
||||||
* [github.com/karrick/godirwalk](https://godoc.org/github.com/karrick/godirwalk)
|
* [github.com/karrick/godirwalk](https://godoc.org/github.com/karrick/godirwalk)
|
||||||
|
|
||||||
* [github.com/kisielk/errcheck](https://godoc.org/github.com/kisielk/errcheck)
|
|
||||||
|
|
||||||
* [github.com/kisielk/gotool](https://godoc.org/github.com/kisielk/gotool)
|
|
||||||
|
|
||||||
* [github.com/konsorten/go-windows-terminal-sequences](https://godoc.org/github.com/konsorten/go-windows-terminal-sequences)
|
* [github.com/konsorten/go-windows-terminal-sequences](https://godoc.org/github.com/konsorten/go-windows-terminal-sequences)
|
||||||
|
|
||||||
* [github.com/kr/logfmt](https://godoc.org/github.com/kr/logfmt)
|
|
||||||
|
|
||||||
* [github.com/kr/pretty](https://godoc.org/github.com/kr/pretty)
|
|
||||||
|
|
||||||
* [github.com/kr/pty](https://godoc.org/github.com/kr/pty)
|
|
||||||
|
|
||||||
* [github.com/kr/text](https://godoc.org/github.com/kr/text)
|
|
||||||
|
|
||||||
* [github.com/magiconair/properties](https://godoc.org/github.com/magiconair/properties)
|
|
||||||
|
|
||||||
* [github.com/markbates/errx](https://godoc.org/github.com/markbates/errx)
|
* [github.com/markbates/errx](https://godoc.org/github.com/markbates/errx)
|
||||||
|
|
||||||
* [github.com/markbates/oncer](https://godoc.org/github.com/markbates/oncer)
|
* [github.com/markbates/oncer](https://godoc.org/github.com/markbates/oncer)
|
||||||
|
|
||||||
* [github.com/markbates/safe](https://godoc.org/github.com/markbates/safe)
|
* [github.com/markbates/safe](https://godoc.org/github.com/markbates/safe)
|
||||||
|
|
||||||
* [github.com/matttproud/golang_protobuf_extensions](https://godoc.org/github.com/matttproud/golang_protobuf_extensions)
|
|
||||||
|
|
||||||
* [github.com/mitchellh/go-homedir](https://godoc.org/github.com/mitchellh/go-homedir)
|
|
||||||
|
|
||||||
* [github.com/mitchellh/mapstructure](https://godoc.org/github.com/mitchellh/mapstructure)
|
|
||||||
|
|
||||||
* [github.com/mwitkow/go-conntrack](https://godoc.org/github.com/mwitkow/go-conntrack)
|
|
||||||
|
|
||||||
* [github.com/oklog/ulid](https://godoc.org/github.com/oklog/ulid)
|
|
||||||
|
|
||||||
* [github.com/pelletier/go-toml](https://godoc.org/github.com/pelletier/go-toml)
|
|
||||||
|
|
||||||
* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors)
|
|
||||||
|
|
||||||
* [github.com/pmezard/go-difflib](https://godoc.org/github.com/pmezard/go-difflib)
|
|
||||||
|
|
||||||
* [github.com/prometheus/client_golang](https://godoc.org/github.com/prometheus/client_golang)
|
|
||||||
|
|
||||||
* [github.com/prometheus/client_model](https://godoc.org/github.com/prometheus/client_model)
|
|
||||||
|
|
||||||
* [github.com/prometheus/common](https://godoc.org/github.com/prometheus/common)
|
|
||||||
|
|
||||||
* [github.com/prometheus/procfs](https://godoc.org/github.com/prometheus/procfs)
|
|
||||||
|
|
||||||
* [github.com/prometheus/tsdb](https://godoc.org/github.com/prometheus/tsdb)
|
|
||||||
|
|
||||||
* [github.com/rogpeppe/fastuuid](https://godoc.org/github.com/rogpeppe/fastuuid)
|
|
||||||
|
|
||||||
* [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
|
* [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
|
||||||
|
|
||||||
* [github.com/russross/blackfriday/v2](https://godoc.org/github.com/russross/blackfriday/v2)
|
|
||||||
|
|
||||||
* [github.com/shurcooL/sanitized_anchor_name](https://godoc.org/github.com/shurcooL/sanitized_anchor_name)
|
|
||||||
|
|
||||||
* [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus)
|
* [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus)
|
||||||
|
|
||||||
* [github.com/soheilhy/cmux](https://godoc.org/github.com/soheilhy/cmux)
|
|
||||||
|
|
||||||
* [github.com/spaolacci/murmur3](https://godoc.org/github.com/spaolacci/murmur3)
|
|
||||||
|
|
||||||
* [github.com/spf13/afero](https://godoc.org/github.com/spf13/afero)
|
|
||||||
|
|
||||||
* [github.com/spf13/cast](https://godoc.org/github.com/spf13/cast)
|
|
||||||
|
|
||||||
* [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra)
|
* [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra)
|
||||||
|
|
||||||
* [github.com/spf13/jwalterweatherman](https://godoc.org/github.com/spf13/jwalterweatherman)
|
|
||||||
|
|
||||||
* [github.com/spf13/pflag](https://godoc.org/github.com/spf13/pflag)
|
|
||||||
|
|
||||||
* [github.com/spf13/viper](https://godoc.org/github.com/spf13/viper)
|
|
||||||
|
|
||||||
* [github.com/stretchr/objx](https://godoc.org/github.com/stretchr/objx)
|
|
||||||
|
|
||||||
* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
|
* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
|
||||||
|
|
||||||
* [github.com/tmc/grpc-websocket-proxy](https://godoc.org/github.com/tmc/grpc-websocket-proxy)
|
|
||||||
|
|
||||||
* [github.com/ugorji/go](https://godoc.org/github.com/ugorji/go)
|
|
||||||
|
|
||||||
* [github.com/xiang90/probing](https://godoc.org/github.com/xiang90/probing)
|
|
||||||
|
|
||||||
* [github.com/xordataexchange/crypt](https://godoc.org/github.com/xordataexchange/crypt)
|
|
||||||
|
|
||||||
* [go.etcd.io/bbolt](https://godoc.org/go.etcd.io/bbolt)
|
|
||||||
|
|
||||||
* [go.uber.org/atomic](https://godoc.org/go.uber.org/atomic)
|
|
||||||
|
|
||||||
* [go.uber.org/multierr](https://godoc.org/go.uber.org/multierr)
|
|
||||||
|
|
||||||
* [go.uber.org/zap](https://godoc.org/go.uber.org/zap)
|
|
||||||
|
|
||||||
* [golang.org/x/crypto](https://godoc.org/golang.org/x/crypto)
|
|
||||||
|
|
||||||
* [golang.org/x/lint](https://godoc.org/golang.org/x/lint)
|
|
||||||
|
|
||||||
* [golang.org/x/mod](https://godoc.org/golang.org/x/mod)
|
|
||||||
|
|
||||||
* [golang.org/x/net](https://godoc.org/golang.org/x/net)
|
|
||||||
|
|
||||||
* [golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2)
|
|
||||||
|
|
||||||
* [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
|
* [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
|
||||||
|
|
||||||
* [golang.org/x/sys](https://godoc.org/golang.org/x/sys)
|
|
||||||
|
|
||||||
* [golang.org/x/text](https://godoc.org/golang.org/x/text)
|
|
||||||
|
|
||||||
* [golang.org/x/time](https://godoc.org/golang.org/x/time)
|
|
||||||
|
|
||||||
* [golang.org/x/tools](https://godoc.org/golang.org/x/tools)
|
* [golang.org/x/tools](https://godoc.org/golang.org/x/tools)
|
||||||
|
|
||||||
* [golang.org/x/xerrors](https://godoc.org/golang.org/x/xerrors)
|
|
||||||
|
|
||||||
* [google.golang.org/appengine](https://godoc.org/google.golang.org/appengine)
|
|
||||||
|
|
||||||
* [google.golang.org/genproto](https://godoc.org/google.golang.org/genproto)
|
|
||||||
|
|
||||||
* [google.golang.org/grpc](https://godoc.org/google.golang.org/grpc)
|
|
||||||
|
|
||||||
* [gopkg.in/alecthomas/kingpin.v2](https://godoc.org/gopkg.in/alecthomas/kingpin.v2)
|
|
||||||
|
|
||||||
* [gopkg.in/check.v1](https://godoc.org/gopkg.in/check.v1)
|
|
||||||
|
|
||||||
* [gopkg.in/errgo.v2](https://godoc.org/gopkg.in/errgo.v2)
|
|
||||||
|
|
||||||
* [gopkg.in/resty.v1](https://godoc.org/gopkg.in/resty.v1)
|
|
||||||
|
|
||||||
* [gopkg.in/yaml.v2](https://godoc.org/gopkg.in/yaml.v2)
|
|
||||||
|
|
||||||
* [honnef.co/go/tools](https://godoc.org/honnef.co/go/tools)
|
|
||||||
|
2
vendor/github.com/gobuffalo/packr/v2/go.mod
generated
vendored
2
vendor/github.com/gobuffalo/packr/v2/go.mod
generated
vendored
@ -5,7 +5,7 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
github.com/gobuffalo/logger v1.0.3
|
github.com/gobuffalo/logger v1.0.3
|
||||||
github.com/gobuffalo/packd v1.0.0
|
github.com/gobuffalo/packd v1.0.0
|
||||||
github.com/karrick/godirwalk v1.15.3
|
github.com/karrick/godirwalk v1.15.8
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/markbates/errx v1.1.0
|
github.com/markbates/errx v1.1.0
|
||||||
github.com/markbates/oncer v1.0.0
|
github.com/markbates/oncer v1.0.0
|
||||||
|
4
vendor/github.com/gobuffalo/packr/v2/go.sum
generated
vendored
4
vendor/github.com/gobuffalo/packr/v2/go.sum
generated
vendored
@ -47,8 +47,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
|
|||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew=
|
github.com/karrick/godirwalk v1.15.8 h1:7+rWAZPn9zuRxaIqqT8Ohs2Q2Ac0msBqwRdxNCr2VVs=
|
||||||
github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
|
37
vendor/github.com/gobuffalo/packr/v2/internal/envy.go
generated
vendored
37
vendor/github.com/gobuffalo/packr/v2/internal/envy.go
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mods returns true when go modules supports is enabled
|
|
||||||
func Mods() bool {
|
|
||||||
go111 := os.Getenv("GO111MODULE")
|
|
||||||
|
|
||||||
if !inGoPath() {
|
|
||||||
return go111 != "off"
|
|
||||||
}
|
|
||||||
|
|
||||||
return go111 == "on"
|
|
||||||
}
|
|
||||||
|
|
||||||
func inGoPath() bool {
|
|
||||||
pwd, _ := os.Getwd()
|
|
||||||
for _, p := range GoPaths() {
|
|
||||||
if strings.HasPrefix(pwd, p) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoPaths return the defined gopath list.
|
|
||||||
func GoPaths() []string {
|
|
||||||
gp := os.Getenv("GOPATH")
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return strings.Split(gp, ";") // Windows uses a different separator
|
|
||||||
}
|
|
||||||
return strings.Split(gp, ":")
|
|
||||||
}
|
|
113
vendor/github.com/gobuffalo/packr/v2/jam/pack.go
generated
vendored
113
vendor/github.com/gobuffalo/packr/v2/jam/pack.go
generated
vendored
@ -1,113 +0,0 @@
|
|||||||
package jam
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/store"
|
|
||||||
"github.com/gobuffalo/packr/v2/plog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PackOptions ...
|
|
||||||
type PackOptions struct {
|
|
||||||
IgnoreImports bool
|
|
||||||
Legacy bool
|
|
||||||
StoreCmd string
|
|
||||||
Roots []string
|
|
||||||
RootsOptions *parser.RootsOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pack the roots given + PWD
|
|
||||||
func Pack(opts PackOptions) error {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.Roots = append(opts.Roots, pwd)
|
|
||||||
if err := Clean(opts.Roots...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.RootsOptions == nil {
|
|
||||||
opts.RootsOptions = &parser.RootsOptions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.IgnoreImports {
|
|
||||||
opts.RootsOptions.IgnoreImports = true
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := parser.NewFromRoots(opts.Roots, opts.RootsOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
boxes, err := p.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// reduce boxes - remove ones we don't want
|
|
||||||
// MB: current assumption is we want all these
|
|
||||||
// boxes, just adding a comment suggesting they're
|
|
||||||
// might be a reason to exclude some
|
|
||||||
|
|
||||||
plog.Logger.Debugf("found %d boxes", len(boxes))
|
|
||||||
|
|
||||||
if len(opts.StoreCmd) != 0 {
|
|
||||||
return ShellPack(opts, boxes)
|
|
||||||
}
|
|
||||||
|
|
||||||
var st store.Store = store.NewDisk("", "")
|
|
||||||
|
|
||||||
if opts.Legacy {
|
|
||||||
st = store.NewLegacy()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range boxes {
|
|
||||||
if b.Name == store.DISK_GLOBAL_KEY {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := st.Pack(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cl, ok := st.(io.Closer); ok {
|
|
||||||
return cl.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShellPack ...
|
|
||||||
func ShellPack(opts PackOptions, boxes parser.Boxes) error {
|
|
||||||
b, err := json.Marshal(boxes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
c := exec.CommandContext(ctx, opts.StoreCmd, string(b))
|
|
||||||
c.Stdout = os.Stdout
|
|
||||||
c.Stderr = os.Stderr
|
|
||||||
return c.Run()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean ...
|
|
||||||
func Clean(args ...string) error {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
args = append(args, pwd)
|
|
||||||
for _, root := range args {
|
|
||||||
if err := store.Clean(root); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
75
vendor/github.com/gobuffalo/packr/v2/jam/store/clean.go
generated
vendored
75
vendor/github.com/gobuffalo/packr/v2/jam/store/clean.go
generated
vendored
@ -1,75 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Clean(root string) error {
|
|
||||||
defer func() {
|
|
||||||
packd := filepath.Join(root, "packrd")
|
|
||||||
os.RemoveAll(packd)
|
|
||||||
}()
|
|
||||||
|
|
||||||
p, err := parser.NewFromRoots([]string{root}, &parser.RootsOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
boxes, err := p.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d := NewDisk("", "")
|
|
||||||
for _, box := range boxes {
|
|
||||||
if err := d.Clean(box); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func clean(root string) error {
|
|
||||||
if len(root) == 0 {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
root = pwd
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(root); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
packd := filepath.Join(root, "packrd")
|
|
||||||
os.RemoveAll(packd)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
|
||||||
if filepath.Base(path) == "packrd" {
|
|
||||||
os.RemoveAll(path)
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(path, "-packr.go") {
|
|
||||||
err := os.RemoveAll(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
348
vendor/github.com/gobuffalo/packr/v2/jam/store/disk.go
generated
vendored
348
vendor/github.com/gobuffalo/packr/v2/jam/store/disk.go
generated
vendored
@ -1,348 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"html/template"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/internal"
|
|
||||||
"github.com/karrick/godirwalk"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/file/resolver/encoding/hex"
|
|
||||||
"github.com/gobuffalo/packr/v2/plog"
|
|
||||||
"github.com/rogpeppe/go-internal/modfile"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Store = &Disk{}
|
|
||||||
|
|
||||||
const DISK_GLOBAL_KEY = "__packr_global__"
|
|
||||||
|
|
||||||
type Disk struct {
|
|
||||||
DBPath string
|
|
||||||
DBPackage string
|
|
||||||
global map[string]string
|
|
||||||
boxes map[string]*parser.Box
|
|
||||||
moot *sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDisk(path string, pkg string) *Disk {
|
|
||||||
if len(path) == 0 {
|
|
||||||
path = "packrd"
|
|
||||||
}
|
|
||||||
if len(pkg) == 0 {
|
|
||||||
pkg = "packrd"
|
|
||||||
}
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
path, _ = filepath.Abs(path)
|
|
||||||
}
|
|
||||||
return &Disk{
|
|
||||||
DBPath: path,
|
|
||||||
DBPackage: pkg,
|
|
||||||
global: map[string]string{},
|
|
||||||
boxes: map[string]*parser.Box{},
|
|
||||||
moot: &sync.RWMutex{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Disk) FileNames(box *parser.Box) ([]string, error) {
|
|
||||||
path := box.AbsPath
|
|
||||||
if len(box.AbsPath) == 0 {
|
|
||||||
path = box.Path
|
|
||||||
}
|
|
||||||
var names []string
|
|
||||||
if _, err := os.Stat(path); err != nil {
|
|
||||||
return names, nil
|
|
||||||
}
|
|
||||||
err := godirwalk.Walk(path, &godirwalk.Options{
|
|
||||||
FollowSymbolicLinks: true,
|
|
||||||
Callback: func(path string, de *godirwalk.Dirent) error {
|
|
||||||
if !de.IsRegular() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
names = append(names, path)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return names, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Disk) Files(box *parser.Box) ([]*parser.File, error) {
|
|
||||||
var files []*parser.File
|
|
||||||
names, err := d.FileNames(box)
|
|
||||||
if err != nil {
|
|
||||||
return files, err
|
|
||||||
}
|
|
||||||
for _, n := range names {
|
|
||||||
b, err := ioutil.ReadFile(n)
|
|
||||||
if err != nil {
|
|
||||||
return files, err
|
|
||||||
}
|
|
||||||
f := parser.NewFile(n, bytes.NewReader(b))
|
|
||||||
files = append(files, f)
|
|
||||||
}
|
|
||||||
return files, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Disk) Pack(box *parser.Box) error {
|
|
||||||
plog.Debug(d, "Pack", "box", box.Name)
|
|
||||||
d.boxes[box.Name] = box
|
|
||||||
names, err := d.FileNames(box)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, n := range names {
|
|
||||||
_, ok := d.global[n]
|
|
||||||
if ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
k := makeKey(box, n)
|
|
||||||
// not in the global, so add it!
|
|
||||||
d.global[n] = k
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Disk) Clean(box *parser.Box) error {
|
|
||||||
root := box.PackageDir
|
|
||||||
if len(root) == 0 {
|
|
||||||
return fmt.Errorf("can't clean an empty box.PackageDir")
|
|
||||||
}
|
|
||||||
plog.Debug(d, "Clean", "box", box.Name, "root", root)
|
|
||||||
return clean(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
Package string
|
|
||||||
GlobalFiles map[string]string
|
|
||||||
Boxes []optsBox
|
|
||||||
GK string
|
|
||||||
}
|
|
||||||
|
|
||||||
type optsBox struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close ...
|
|
||||||
func (d *Disk) Close() error {
|
|
||||||
if len(d.boxes) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
xb := &parser.Box{Name: DISK_GLOBAL_KEY}
|
|
||||||
opts := options{
|
|
||||||
Package: d.DBPackage,
|
|
||||||
GlobalFiles: map[string]string{},
|
|
||||||
GK: makeKey(xb, d.DBPath),
|
|
||||||
}
|
|
||||||
|
|
||||||
wg := errgroup.Group{}
|
|
||||||
for k, v := range d.global {
|
|
||||||
func(k, v string) {
|
|
||||||
wg.Go(func() error {
|
|
||||||
bb := &bytes.Buffer{}
|
|
||||||
enc := hex.NewEncoder(bb)
|
|
||||||
zw := gzip.NewWriter(enc)
|
|
||||||
f, err := os.Open(k)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
io.Copy(zw, f)
|
|
||||||
if err := zw.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.moot.Lock()
|
|
||||||
opts.GlobalFiles[makeKey(xb, k)] = bb.String()
|
|
||||||
d.moot.Unlock()
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := wg.Wait(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range d.boxes {
|
|
||||||
ob := optsBox{
|
|
||||||
Name: b.Name,
|
|
||||||
}
|
|
||||||
opts.Boxes = append(opts.Boxes, ob)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(opts.Boxes, func(a, b int) bool {
|
|
||||||
return opts.Boxes[a].Name < opts.Boxes[b].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
fm := template.FuncMap{
|
|
||||||
"printBox": func(ob optsBox) (template.HTML, error) {
|
|
||||||
box := d.boxes[ob.Name]
|
|
||||||
if box == nil {
|
|
||||||
return "", fmt.Errorf("could not find box %s", ob.Name)
|
|
||||||
}
|
|
||||||
fn, err := d.FileNames(box)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(fn) == 0 {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type file struct {
|
|
||||||
Resolver string
|
|
||||||
ForwardPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, err := template.New("box.go").Parse(diskGlobalBoxTmpl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var files []file
|
|
||||||
for _, s := range fn {
|
|
||||||
p := strings.TrimPrefix(s, box.AbsPath)
|
|
||||||
p = strings.TrimPrefix(p, string(filepath.Separator))
|
|
||||||
files = append(files, file{
|
|
||||||
Resolver: strings.Replace(p, "\\", "/", -1),
|
|
||||||
ForwardPath: makeKey(box, s),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
opts := map[string]interface{}{
|
|
||||||
"Box": box,
|
|
||||||
"Files": files,
|
|
||||||
}
|
|
||||||
|
|
||||||
bb := &bytes.Buffer{}
|
|
||||||
if err := tmpl.Execute(bb, opts); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return template.HTML(bb.String()), nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
os.MkdirAll(d.DBPath, 0755)
|
|
||||||
fp := filepath.Join(d.DBPath, "packed-packr.go")
|
|
||||||
global, err := os.Create(fp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer global.Close()
|
|
||||||
|
|
||||||
tmpl := template.New(fp).Funcs(fm)
|
|
||||||
tmpl, err = tmpl.Parse(diskGlobalTmpl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tmpl.Execute(global, opts); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var ip string
|
|
||||||
if internal.Mods() {
|
|
||||||
// Starting in 1.12, we can rely on Go's method for
|
|
||||||
// resolving where go.mod resides. Prior versions will
|
|
||||||
// simply return an empty string.
|
|
||||||
cmd := exec.Command("go", "env", "GOMOD")
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("go.mod cannot be read or does not exist while go module is enabled")
|
|
||||||
}
|
|
||||||
mp := strings.TrimSpace(string(out))
|
|
||||||
if mp == "" {
|
|
||||||
// We are on a prior version of Go; try and do
|
|
||||||
// the resolution ourselves.
|
|
||||||
mp = filepath.Join(filepath.Dir(d.DBPath), "go.mod")
|
|
||||||
if _, err := os.Stat(mp); err != nil {
|
|
||||||
mp = filepath.Join(d.DBPath, "go.mod")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
moddata, err := ioutil.ReadFile(mp)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("go.mod cannot be read or does not exist while go module is enabled")
|
|
||||||
}
|
|
||||||
ip = modfile.ModulePath(moddata)
|
|
||||||
if ip == "" {
|
|
||||||
return fmt.Errorf("go.mod is malformed")
|
|
||||||
}
|
|
||||||
ip = filepath.Join(ip, strings.TrimPrefix(filepath.Dir(d.DBPath), filepath.Dir(mp)))
|
|
||||||
ip = strings.Replace(ip, "\\", "/", -1)
|
|
||||||
} else {
|
|
||||||
ip = filepath.Dir(d.DBPath)
|
|
||||||
srcs := internal.GoPaths()
|
|
||||||
srcs = append(srcs, build.Default.SrcDirs()...)
|
|
||||||
for _, x := range srcs {
|
|
||||||
ip = strings.TrimPrefix(ip, "/private")
|
|
||||||
ip = strings.TrimPrefix(ip, x)
|
|
||||||
}
|
|
||||||
ip = strings.TrimPrefix(ip, string(filepath.Separator))
|
|
||||||
ip = strings.TrimPrefix(ip, "src")
|
|
||||||
ip = strings.TrimPrefix(ip, string(filepath.Separator))
|
|
||||||
|
|
||||||
ip = strings.Replace(ip, "\\", "/", -1)
|
|
||||||
}
|
|
||||||
ip = path.Join(ip, d.DBPackage)
|
|
||||||
|
|
||||||
for _, n := range opts.Boxes {
|
|
||||||
b := d.boxes[n.Name]
|
|
||||||
if b == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
p := filepath.Join(b.PackageDir, b.Package+"-packr.go")
|
|
||||||
f, err := os.Create(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
o := struct {
|
|
||||||
Package string
|
|
||||||
Import string
|
|
||||||
}{
|
|
||||||
Package: b.Package,
|
|
||||||
Import: ip,
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, err := template.New(p).Parse(diskImportTmpl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := tmpl.Execute(f, o); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolve file paths (only) for the boxes
|
|
||||||
// compile "global" db
|
|
||||||
// resolve files for boxes to point at global db
|
|
||||||
// write global db to disk (default internal/packr)
|
|
||||||
// write boxes db to disk (default internal/packr)
|
|
||||||
// write -packr.go files in each package (1 per package) that init the global db
|
|
||||||
|
|
||||||
func makeKey(box *parser.Box, path string) string {
|
|
||||||
w := md5.New()
|
|
||||||
fmt.Fprint(w, path)
|
|
||||||
h := hex.EncodeToString(w.Sum(nil))
|
|
||||||
return h
|
|
||||||
}
|
|
51
vendor/github.com/gobuffalo/packr/v2/jam/store/disk_tmpl.go
generated
vendored
51
vendor/github.com/gobuffalo/packr/v2/jam/store/disk_tmpl.go
generated
vendored
@ -1,51 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
const diskGlobalTmpl = `// +build !skippackr
|
|
||||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
|
||||||
|
|
||||||
// You can use the "packr2 clean" command to clean up this,
|
|
||||||
// and any other packr generated files.
|
|
||||||
package {{.Package}}
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr/v2"
|
|
||||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = func() error {
|
|
||||||
const gk = "{{.GK}}"
|
|
||||||
g := packr.New(gk, "")
|
|
||||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
|
||||||
{{- range $k, $v := .GlobalFiles }}
|
|
||||||
"{{$k}}": "{{$v}}",
|
|
||||||
{{- end }}
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
g.DefaultResolver = hgr
|
|
||||||
|
|
||||||
{{- range $box := .Boxes}}
|
|
||||||
{{ printBox $box -}}
|
|
||||||
{{ end }}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
`
|
|
||||||
|
|
||||||
const diskImportTmpl = `// +build !skippackr
|
|
||||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
|
||||||
|
|
||||||
// You can use the "packr clean" command to clean up this,
|
|
||||||
// and any other packr generated files.
|
|
||||||
package {{.Package}}
|
|
||||||
|
|
||||||
import _ "{{.Import}}"
|
|
||||||
`
|
|
||||||
|
|
||||||
const diskGlobalBoxTmpl = `
|
|
||||||
func() {
|
|
||||||
b := packr.New("{{.Box.Name}}", "{{.Box.Path}}")
|
|
||||||
{{- range $file := .Files }}
|
|
||||||
b.SetResolver("{{$file.Resolver}}", packr.Pointer{ForwardBox: gk, ForwardPath: "{{$file.ForwardPath}}"})
|
|
||||||
{{- end }}
|
|
||||||
}()`
|
|
39
vendor/github.com/gobuffalo/packr/v2/jam/store/env.go
generated
vendored
39
vendor/github.com/gobuffalo/packr/v2/jam/store/env.go
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var goPath = filepath.Join(os.Getenv("HOME"), "go")
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var once sync.Once
|
|
||||||
once.Do(func() {
|
|
||||||
cmd := exec.Command("go", "env", "GOPATH")
|
|
||||||
b, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
goPath = strings.TrimSpace(string(b))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoPath returns the current GOPATH env var
|
|
||||||
// or if it's missing, the default.
|
|
||||||
func GoPath() string {
|
|
||||||
return goPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoBin returns the current GO_BIN env var
|
|
||||||
// or if it's missing, a default of "go"
|
|
||||||
func GoBin() string {
|
|
||||||
go_bin := os.Getenv("GO_BIN")
|
|
||||||
if go_bin == "" {
|
|
||||||
return "go"
|
|
||||||
}
|
|
||||||
return go_bin
|
|
||||||
}
|
|
44
vendor/github.com/gobuffalo/packr/v2/jam/store/fn.go
generated
vendored
44
vendor/github.com/gobuffalo/packr/v2/jam/store/fn.go
generated
vendored
@ -1,44 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Store = &FnStore{}
|
|
||||||
|
|
||||||
type FnStore struct {
|
|
||||||
FileNamesFn func(*parser.Box) ([]string, error)
|
|
||||||
FilesFn func(*parser.Box) ([]*parser.File, error)
|
|
||||||
PackFn func(*parser.Box) error
|
|
||||||
CleanFn func(*parser.Box) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FnStore) FileNames(box *parser.Box) ([]string, error) {
|
|
||||||
if f.FileNamesFn == nil {
|
|
||||||
return []string{}, fmt.Errorf("FileNames not implemented")
|
|
||||||
}
|
|
||||||
return f.FileNames(box)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FnStore) Files(box *parser.Box) ([]*parser.File, error) {
|
|
||||||
if f.FilesFn == nil {
|
|
||||||
return []*parser.File{}, fmt.Errorf("Files not implemented")
|
|
||||||
}
|
|
||||||
return f.FilesFn(box)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FnStore) Pack(box *parser.Box) error {
|
|
||||||
if f.PackFn == nil {
|
|
||||||
return fmt.Errorf("Pack not implemented")
|
|
||||||
}
|
|
||||||
return f.PackFn(box)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FnStore) Clean(box *parser.Box) error {
|
|
||||||
if f.CleanFn == nil {
|
|
||||||
return fmt.Errorf("Clean not implemented")
|
|
||||||
}
|
|
||||||
return f.Clean(box)
|
|
||||||
}
|
|
129
vendor/github.com/gobuffalo/packr/v2/jam/store/legacy.go
generated
vendored
129
vendor/github.com/gobuffalo/packr/v2/jam/store/legacy.go
generated
vendored
@ -1,129 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"html/template"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Store = &Legacy{}
|
|
||||||
|
|
||||||
type Legacy struct {
|
|
||||||
*Disk
|
|
||||||
boxes map[string][]legacyBox
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLegacy() *Legacy {
|
|
||||||
return &Legacy{
|
|
||||||
Disk: NewDisk("", ""),
|
|
||||||
boxes: map[string][]legacyBox{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Legacy) Pack(box *parser.Box) error {
|
|
||||||
files, err := l.Files(box)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var fcs []legacyFile
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
n := strings.TrimPrefix(f.Name(), box.AbsPath+string(filepath.Separator))
|
|
||||||
c, err := l.prepFile(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fcs = append(fcs, legacyFile{Name: n, Contents: c})
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(fcs, func(a, b int) bool {
|
|
||||||
return fcs[a].Name < fcs[b].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
lbs := l.boxes[box.PackageDir]
|
|
||||||
lbs = append(lbs, legacyBox{
|
|
||||||
Box: box,
|
|
||||||
Files: fcs,
|
|
||||||
})
|
|
||||||
l.boxes[box.PackageDir] = lbs
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Legacy) prepFile(r io.Reader) (string, error) {
|
|
||||||
bb := &bytes.Buffer{}
|
|
||||||
if _, err := io.Copy(bb, r); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(bb.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.Replace(string(b), "\"", "\\\"", -1), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close ...
|
|
||||||
func (l *Legacy) Close() error {
|
|
||||||
for _, b := range l.boxes {
|
|
||||||
if len(b) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bx := b[0].Box
|
|
||||||
pkg := bx.Package
|
|
||||||
opts := map[string]interface{}{
|
|
||||||
"Package": pkg,
|
|
||||||
"Boxes": b,
|
|
||||||
}
|
|
||||||
p := filepath.Join(bx.PackageDir, "a_"+bx.Package+"-packr.go.tmpl")
|
|
||||||
tmpl, err := template.New(p).Parse(legacyTmpl)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tmpl.Execute(f, opts); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type legacyBox struct {
|
|
||||||
Box *parser.Box
|
|
||||||
Files []legacyFile
|
|
||||||
}
|
|
||||||
|
|
||||||
type legacyFile struct {
|
|
||||||
Name string
|
|
||||||
Contents string
|
|
||||||
}
|
|
||||||
|
|
||||||
var legacyTmpl = `// Code generated by github.com/gobuffalo/packr. DO NOT EDIT.
|
|
||||||
|
|
||||||
package {{.Package}}
|
|
||||||
|
|
||||||
import "github.com/gobuffalo/packr"
|
|
||||||
|
|
||||||
// You can use the "packr clean" command to clean up this,
|
|
||||||
// and any other packr generated files.
|
|
||||||
func init() {
|
|
||||||
{{- range $box := .Boxes }}
|
|
||||||
{{- range $box.Files }}
|
|
||||||
_ = packr.PackJSONBytes("{{$box.Box.Name}}", "{{.Name}}", "{{.Contents}}")
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
`
|
|
12
vendor/github.com/gobuffalo/packr/v2/jam/store/store.go
generated
vendored
12
vendor/github.com/gobuffalo/packr/v2/jam/store/store.go
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Store interface {
|
|
||||||
FileNames(*parser.Box) ([]string, error)
|
|
||||||
Files(*parser.Box) ([]*parser.File, error)
|
|
||||||
Pack(*parser.Box) error
|
|
||||||
Clean(*parser.Box) error
|
|
||||||
}
|
|
21
vendor/github.com/gobuffalo/packr/v2/packr2/LICENSE
generated
vendored
21
vendor/github.com/gobuffalo/packr/v2/packr2/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright © 2018 Mark Bates
|
|
||||||
|
|
||||||
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.
|
|
28
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/build.go
generated
vendored
28
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/build.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var buildCmd = &cobra.Command{
|
|
||||||
Use: "build",
|
|
||||||
Short: "Wraps the go build command with packr",
|
|
||||||
DisableFlagParsing: true,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cargs := parseArgs(args)
|
|
||||||
if globalOptions.Verbose {
|
|
||||||
fmt.Println(dont)
|
|
||||||
}
|
|
||||||
if err := jam.Pack(globalOptions.PackOptions); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return goCmd("build", cargs...)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(buildCmd)
|
|
||||||
}
|
|
18
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/clean.go
generated
vendored
18
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/clean.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr/v2/jam"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cleanCmd = &cobra.Command{
|
|
||||||
Use: "clean",
|
|
||||||
Short: "removes any *-packr.go files",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return jam.Clean(args...)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(cleanCmd)
|
|
||||||
}
|
|
23
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix.go
generated
vendored
23
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix.go
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
packr "github.com/gobuffalo/packr/v2"
|
|
||||||
"github.com/gobuffalo/packr/v2/packr2/cmd/fix"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fixCmd represents the info command
|
|
||||||
var fixCmd = &cobra.Command{
|
|
||||||
Use: "fix",
|
|
||||||
Short: fmt.Sprintf("will attempt to fix a application's API to match packr version %s", packr.Version),
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return fix.Run()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
fixCmd.Flags().BoolVarP(&fix.YesToAll, "y", "", false, "update all without asking for confirmation")
|
|
||||||
rootCmd.AddCommand(fixCmd)
|
|
||||||
}
|
|
49
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/fix.go
generated
vendored
49
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/fix.go
generated
vendored
@ -1,49 +0,0 @@
|
|||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam/store"
|
|
||||||
)
|
|
||||||
|
|
||||||
//YesToAll will be used by the command to skip the questions
|
|
||||||
var YesToAll bool
|
|
||||||
|
|
||||||
var replace = map[string]string{
|
|
||||||
"github.com/gobuffalo/packr": "github.com/gobuffalo/packr/v2",
|
|
||||||
}
|
|
||||||
|
|
||||||
var ic = ImportConverter{
|
|
||||||
Data: replace,
|
|
||||||
}
|
|
||||||
|
|
||||||
var checks = []Check{
|
|
||||||
// packrClean,
|
|
||||||
ic.Process,
|
|
||||||
}
|
|
||||||
|
|
||||||
func packrClean(r *Runner) error {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
store.Clean(pwd)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ask(q string) bool {
|
|
||||||
if YesToAll {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("? %s [y/n]\n", q)
|
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
text, _ := reader.ReadString('\n')
|
|
||||||
|
|
||||||
text = strings.ToLower(strings.TrimSpace(text))
|
|
||||||
return text == "y" || text == "yes"
|
|
||||||
}
|
|
251
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/imports.go
generated
vendored
251
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/imports.go
generated
vendored
@ -1,251 +0,0 @@
|
|||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/printer"
|
|
||||||
"go/token"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/ast/astutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImportConverter will changes imports from a -> b
|
|
||||||
type ImportConverter struct {
|
|
||||||
Data map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process will walk all the .go files in an application, excluding ./vendor.
|
|
||||||
// It will then attempt to convert any old import paths to any new import paths
|
|
||||||
// used by this version Buffalo.
|
|
||||||
func (c ImportConverter) Process(r *Runner) error {
|
|
||||||
fmt.Println("~~~ Rewriting Imports ~~~")
|
|
||||||
|
|
||||||
err := filepath.Walk(".", c.processFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat("Gopkg.toml"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := ioutil.ReadFile("Gopkg.toml")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range c.Data {
|
|
||||||
if bytes.Contains(b, []byte(k)) {
|
|
||||||
r.Warnings = append(r.Warnings, fmt.Sprintf("Your Gopkg.toml contains the following import that need to be changed MANUALLY: %s", k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ImportConverter) processFile(p string, info os.FileInfo, err error) error {
|
|
||||||
er := onlyRelevantFiles(p, info, err, func(p string) error {
|
|
||||||
err := c.rewriteFile(p)
|
|
||||||
if err != nil {
|
|
||||||
err = err
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return er
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ImportConverter) rewriteFile(name string) error {
|
|
||||||
// create an empty fileset.
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
|
|
||||||
// parse the .go file.
|
|
||||||
// we are parsing the entire file with comments, so we don't lose anything
|
|
||||||
// if we need to write it back out.
|
|
||||||
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
e := err.Error()
|
|
||||||
msg := "expected 'package', found 'EOF'"
|
|
||||||
if e[len(e)-len(msg):] == msg {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
changed := false
|
|
||||||
funcs := []*ast.FuncDecl{}
|
|
||||||
for _, d := range f.Decls {
|
|
||||||
if fn, isFn := d.(*ast.FuncDecl); isFn {
|
|
||||||
funcs = append(funcs, fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fun := range funcs {
|
|
||||||
ast.Inspect(fun, func(node ast.Node) bool {
|
|
||||||
switch n := node.(type) {
|
|
||||||
case *ast.CallExpr:
|
|
||||||
fn, ok := n.Fun.(*ast.SelectorExpr)
|
|
||||||
if !ok || fn.Sel == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
sel := fn.Sel
|
|
||||||
i, ok := fn.X.(*ast.Ident)
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if i.Name != "packr" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sel.Name == "NewBox" {
|
|
||||||
sel.Name = "New"
|
|
||||||
n.Args = append(n.Args, n.Args[0])
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
if sel.Name == "MustBytes" {
|
|
||||||
sel.Name = "Find"
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
if sel.Name == "MustBytes" {
|
|
||||||
sel.Name = "Find"
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range c.Data {
|
|
||||||
if !astutil.DeleteImport(fset, f, key) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
astutil.AddImport(fset, f, value)
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
commentsChanged, err := c.handleFileComments(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = changed || commentsChanged
|
|
||||||
|
|
||||||
// if no change occurred, then we don't need to write to disk, just return.
|
|
||||||
if !changed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// since the imports changed, resort them.
|
|
||||||
ast.SortImports(fset, f)
|
|
||||||
|
|
||||||
// create a temporary file, this easily avoids conflicts.
|
|
||||||
temp, err := writeTempResult(name, fset, f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// rename the .temp to .go
|
|
||||||
return os.Rename(temp, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ImportConverter) handleFileComments(f *ast.File) (bool, error) {
|
|
||||||
change := false
|
|
||||||
|
|
||||||
for _, cg := range f.Comments {
|
|
||||||
for _, cl := range cg.List {
|
|
||||||
if !strings.HasPrefix(cl.Text, "// import \"") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim off extra comment stuff
|
|
||||||
ctext := cl.Text
|
|
||||||
ctext = strings.TrimPrefix(ctext, "// import")
|
|
||||||
ctext = strings.TrimSpace(ctext)
|
|
||||||
|
|
||||||
// unquote the comment import path value
|
|
||||||
ctext, err := strconv.Unquote(ctext)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// match the comment import path with the given replacement map
|
|
||||||
if ctext, ok := c.match(ctext); ok {
|
|
||||||
cl.Text = "// import " + strconv.Quote(ctext)
|
|
||||||
change = true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return change, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// match takes an import path and replacement map.
|
|
||||||
func (c ImportConverter) match(importpath string) (string, bool) {
|
|
||||||
for key, value := range c.Data {
|
|
||||||
if !strings.HasPrefix(importpath, key) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result := strings.Replace(importpath, key, value, 1)
|
|
||||||
return result, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return importpath, false
|
|
||||||
}
|
|
||||||
|
|
||||||
//onlyRelevantFiles processes only .go files excluding folders like node_modules and vendor.
|
|
||||||
func onlyRelevantFiles(p string, fi os.FileInfo, err error, fn func(p string) error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.IsDir() && p != "." {
|
|
||||||
for _, n := range []string{"_", ".", "vendor", "node_modules", ".git"} {
|
|
||||||
base := filepath.Base(p)
|
|
||||||
if strings.HasPrefix(base, n) {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ext := filepath.Ext(p)
|
|
||||||
if ext != ".go" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return fn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTempResult(name string, fset *token.FileSet, f *ast.File) (string, error) {
|
|
||||||
temp := name + ".temp"
|
|
||||||
w, err := os.Create(temp)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write changes to .temp file, and include proper formatting.
|
|
||||||
err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(w, fset, f)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the writer
|
|
||||||
err = w.Close()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return temp, nil
|
|
||||||
}
|
|
47
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/runner.go
generated
vendored
47
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/fix/runner.go
generated
vendored
@ -1,47 +0,0 @@
|
|||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
packr "github.com/gobuffalo/packr/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check interface for runnable checker functions
|
|
||||||
type Check func(*Runner) error
|
|
||||||
|
|
||||||
// Runner will run all compatible checks
|
|
||||||
type Runner struct {
|
|
||||||
Warnings []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run all compatible checks
|
|
||||||
func Run() error {
|
|
||||||
fmt.Printf("! This updater will attempt to update your application to packr version: %s\n", packr.Version)
|
|
||||||
if !ask("Do you wish to continue?") {
|
|
||||||
fmt.Println("~~~ cancelling update ~~~")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Runner{
|
|
||||||
Warnings: []string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if len(r.Warnings) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("\n\n----------------------------")
|
|
||||||
fmt.Printf("!!! (%d) Warnings Were Found !!!\n\n", len(r.Warnings))
|
|
||||||
for _, w := range r.Warnings {
|
|
||||||
fmt.Printf("[WARNING]: %s\n", w)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for _, c := range checks {
|
|
||||||
if err := c(r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
67
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/gocmd.go
generated
vendored
67
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/gocmd.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/plog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func goCmd(name string, args ...string) error {
|
|
||||||
cargs := []string{name}
|
|
||||||
cargs = append(cargs, args...)
|
|
||||||
if len(args) > 0 {
|
|
||||||
err := func() error {
|
|
||||||
path := "."
|
|
||||||
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi, err := os.Stat(filepath.Join(pwd, args[len(args)-1])); err == nil {
|
|
||||||
if fi.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
path = fi.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
if filepath.Ext(path) != ".go" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
path, err = filepath.Abs(filepath.Dir(path))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
if strings.HasSuffix(f.Name(), "-packr.go") {
|
|
||||||
cargs = append(cargs, f.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goBin := os.Getenv("GO_BIN")
|
|
||||||
if goBin == "" {
|
|
||||||
goBin = "go"
|
|
||||||
}
|
|
||||||
cp := exec.Command(goBin, cargs...)
|
|
||||||
plog.Logger.Debug(strings.Join(cp.Args, " "))
|
|
||||||
cp.Stderr = os.Stderr
|
|
||||||
cp.Stdin = os.Stdin
|
|
||||||
cp.Stdout = os.Stdout
|
|
||||||
return cp.Run()
|
|
||||||
}
|
|
43
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/install.go
generated
vendored
43
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/install.go
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2/jam"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
const dont = `Please don't.
|
|
||||||
The following commands have been deprecated and should not be used:
|
|
||||||
|
|
||||||
* packr2 build
|
|
||||||
* packr2 install
|
|
||||||
|
|
||||||
They are, I'll be kind and say, "problematic" and cause more issues
|
|
||||||
than than the actually solve. Sorry about that. My bad.
|
|
||||||
|
|
||||||
It is recommended you use two commands instead:
|
|
||||||
|
|
||||||
$ packr2
|
|
||||||
$ go build/install
|
|
||||||
`
|
|
||||||
|
|
||||||
var installCmd = &cobra.Command{
|
|
||||||
Use: "install",
|
|
||||||
Short: "Don't. ru",
|
|
||||||
DisableFlagParsing: true,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cargs := parseArgs(args)
|
|
||||||
if globalOptions.Verbose {
|
|
||||||
fmt.Println(dont)
|
|
||||||
}
|
|
||||||
if err := jam.Pack(globalOptions.PackOptions); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return goCmd("install", cargs...)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(installCmd)
|
|
||||||
}
|
|
25
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/pack.go
generated
vendored
25
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/pack.go
generated
vendored
@ -1,25 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
func parseArgs(args []string) []string {
|
|
||||||
var cargs []string
|
|
||||||
for _, a := range args {
|
|
||||||
if a == "--legacy" {
|
|
||||||
globalOptions.Legacy = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if a == "--verbose" {
|
|
||||||
globalOptions.Verbose = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if a == "--silent" {
|
|
||||||
globalOptions.Silent = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if a == "--ignore-imports" {
|
|
||||||
globalOptions.IgnoreImports = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cargs = append(cargs, a)
|
|
||||||
}
|
|
||||||
return cargs
|
|
||||||
}
|
|
82
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/root.go
generated
vendored
82
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/root.go
generated
vendored
@ -1,82 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/gobuffalo/logger"
|
|
||||||
"github.com/gobuffalo/packr/v2/jam"
|
|
||||||
"github.com/gobuffalo/packr/v2/plog"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var globalOptions = struct {
|
|
||||||
jam.PackOptions
|
|
||||||
Verbose bool
|
|
||||||
Silent bool
|
|
||||||
}{
|
|
||||||
PackOptions: jam.PackOptions{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "packr2",
|
|
||||||
Short: "Packr is a simple solution for bundling static assets inside of Go binaries.",
|
|
||||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
for _, a := range args {
|
|
||||||
if a == "--legacy" {
|
|
||||||
globalOptions.Legacy = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if a == "-v" || a == "--verbose" {
|
|
||||||
globalOptions.Verbose = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the last argument is a .go file or directory we should
|
|
||||||
// find boxes from there, not from the current directory.
|
|
||||||
// packr2 build -v cmd/main.go
|
|
||||||
if len(args) > 0 {
|
|
||||||
i := len(args) - 1
|
|
||||||
dir := args[i]
|
|
||||||
if _, err := os.Stat(dir); err == nil {
|
|
||||||
if filepath.Ext(dir) == ".go" {
|
|
||||||
dir = filepath.Dir(dir)
|
|
||||||
}
|
|
||||||
os.Chdir(dir)
|
|
||||||
args[i] = filepath.Base(args[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if globalOptions.Verbose {
|
|
||||||
plog.Logger = logger.New(logger.DebugLevel)
|
|
||||||
}
|
|
||||||
if globalOptions.Silent {
|
|
||||||
plog.Logger = logger.New(logger.FatalLevel)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
opts := globalOptions.PackOptions
|
|
||||||
roots := opts.Roots
|
|
||||||
roots = append(roots, args...)
|
|
||||||
opts.Roots = roots
|
|
||||||
return jam.Pack(opts)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
|
||||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
|
||||||
func Execute() {
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&globalOptions.Verbose, "verbose", "v", false, "enables verbose logging")
|
|
||||||
rootCmd.PersistentFlags().BoolVar(&globalOptions.Legacy, "legacy", false, "uses the legacy resolution and packing system (assumes first arg || pwd for input path)")
|
|
||||||
rootCmd.PersistentFlags().BoolVar(&globalOptions.Silent, "silent", false, "silences all output")
|
|
||||||
rootCmd.PersistentFlags().BoolVar(&globalOptions.IgnoreImports, "ignore-imports", false, "when set to true packr won't resolve imports for boxes")
|
|
||||||
rootCmd.PersistentFlags().StringVar(&globalOptions.StoreCmd, "store-cmd", "", "sub command to use for packing")
|
|
||||||
}
|
|
21
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/version.go
generated
vendored
21
vendor/github.com/gobuffalo/packr/v2/packr2/cmd/version.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
packr "github.com/gobuffalo/packr/v2"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var versionCmd = &cobra.Command{
|
|
||||||
Use: "version",
|
|
||||||
Short: "shows packr version",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
fmt.Println(packr.Version)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(versionCmd)
|
|
||||||
}
|
|
7
vendor/github.com/gobuffalo/packr/v2/packr2/main.go
generated
vendored
7
vendor/github.com/gobuffalo/packr/v2/packr2/main.go
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "github.com/gobuffalo/packr/v2/packr2/cmd"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cmd.Execute()
|
|
||||||
}
|
|
2
vendor/github.com/gobuffalo/packr/v2/version.go
generated
vendored
2
vendor/github.com/gobuffalo/packr/v2/version.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
package packr
|
package packr
|
||||||
|
|
||||||
// Version of Packr
|
// Version of Packr
|
||||||
const Version = "v2.8.0"
|
const Version = "v2.8.1"
|
||||||
|
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
Copyright 2014 Alan Shreve
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
# mousetrap
|
|
||||||
|
|
||||||
mousetrap is a tiny library that answers a single question.
|
|
||||||
|
|
||||||
On a Windows machine, was the process invoked by someone double clicking on
|
|
||||||
the executable file while browsing in explorer?
|
|
||||||
|
|
||||||
### Motivation
|
|
||||||
|
|
||||||
Windows developers unfamiliar with command line tools will often "double-click"
|
|
||||||
the executable for a tool. Because most CLI tools print the help and then exit
|
|
||||||
when invoked without arguments, this is often very frustrating for those users.
|
|
||||||
|
|
||||||
mousetrap provides a way to detect these invocations so that you can provide
|
|
||||||
more helpful behavior and instructions on how to run the CLI tool. To see what
|
|
||||||
this looks like, both from an organizational and a technical perspective, see
|
|
||||||
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
|
|
||||||
|
|
||||||
### The interface
|
|
||||||
|
|
||||||
The library exposes a single interface:
|
|
||||||
|
|
||||||
func StartedByExplorer() (bool)
|
|
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package mousetrap
|
|
||||||
|
|
||||||
// StartedByExplorer returns true if the program was invoked by the user
|
|
||||||
// double-clicking on the executable from explorer.exe
|
|
||||||
//
|
|
||||||
// It is conservative and returns false if any of the internal calls fail.
|
|
||||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
|
||||||
// whether it was launched from explorer.exe
|
|
||||||
//
|
|
||||||
// On non-Windows platforms, it always returns false.
|
|
||||||
func StartedByExplorer() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
@ -1,98 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
// +build !go1.4
|
|
||||||
|
|
||||||
package mousetrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// defined by the Win32 API
|
|
||||||
th32cs_snapprocess uintptr = 0x2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
|
||||||
CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
|
|
||||||
Process32First = kernel.MustFindProc("Process32FirstW")
|
|
||||||
Process32Next = kernel.MustFindProc("Process32NextW")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessEntry32 structure defined by the Win32 API
|
|
||||||
type processEntry32 struct {
|
|
||||||
dwSize uint32
|
|
||||||
cntUsage uint32
|
|
||||||
th32ProcessID uint32
|
|
||||||
th32DefaultHeapID int
|
|
||||||
th32ModuleID uint32
|
|
||||||
cntThreads uint32
|
|
||||||
th32ParentProcessID uint32
|
|
||||||
pcPriClassBase int32
|
|
||||||
dwFlags uint32
|
|
||||||
szExeFile [syscall.MAX_PATH]uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProcessEntry(pid int) (pe *processEntry32, err error) {
|
|
||||||
snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
|
|
||||||
if snapshot == uintptr(syscall.InvalidHandle) {
|
|
||||||
err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(syscall.Handle(snapshot))
|
|
||||||
|
|
||||||
var processEntry processEntry32
|
|
||||||
processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
|
|
||||||
ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
|
||||||
if ok == 0 {
|
|
||||||
err = fmt.Errorf("Process32First: %v", e1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if processEntry.th32ProcessID == uint32(pid) {
|
|
||||||
pe = &processEntry
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
|
||||||
if ok == 0 {
|
|
||||||
err = fmt.Errorf("Process32Next: %v", e1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getppid() (pid int, err error) {
|
|
||||||
pe, err := getProcessEntry(os.Getpid())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = int(pe.th32ParentProcessID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
|
||||||
// on the executable from explorer.exe
|
|
||||||
//
|
|
||||||
// It is conservative and returns false if any of the internal calls fail.
|
|
||||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
|
||||||
// whether it was launched from explorer.exe
|
|
||||||
func StartedByExplorer() bool {
|
|
||||||
ppid, err := getppid()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pe, err := getProcessEntry(ppid)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
name := syscall.UTF16ToString(pe.szExeFile[:])
|
|
||||||
return name == "explorer.exe"
|
|
||||||
}
|
|
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
@ -1,46 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
// +build go1.4
|
|
||||||
|
|
||||||
package mousetrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
|
|
||||||
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(snapshot)
|
|
||||||
var procEntry syscall.ProcessEntry32
|
|
||||||
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
|
||||||
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
if procEntry.ProcessID == uint32(pid) {
|
|
||||||
return &procEntry, nil
|
|
||||||
}
|
|
||||||
err = syscall.Process32Next(snapshot, &procEntry)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
|
||||||
// on the executable from explorer.exe
|
|
||||||
//
|
|
||||||
// It is conservative and returns false if any of the internal calls fail.
|
|
||||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
|
||||||
// whether it was launched from explorer.exe
|
|
||||||
func StartedByExplorer() bool {
|
|
||||||
pe, err := getProcessEntry(os.Getppid())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
|
|
||||||
}
|
|
161
vendor/github.com/karrick/godirwalk/README.md
generated
vendored
161
vendor/github.com/karrick/godirwalk/README.md
generated
vendored
@ -26,6 +26,12 @@ provided callback function.
|
|||||||
dirname := "some/directory/root"
|
dirname := "some/directory/root"
|
||||||
err := godirwalk.Walk(dirname, &godirwalk.Options{
|
err := godirwalk.Walk(dirname, &godirwalk.Options{
|
||||||
Callback: func(osPathname string, de *godirwalk.Dirent) error {
|
Callback: func(osPathname string, de *godirwalk.Dirent) error {
|
||||||
|
// Following string operation is not most performant way
|
||||||
|
// of doing this, but common enough to warrant a simple
|
||||||
|
// example here:
|
||||||
|
if strings.Contains(osPathname, ".git") {
|
||||||
|
return godirwalk.SkipThis
|
||||||
|
}
|
||||||
fmt.Printf("%s %s\n", de.ModeType(), osPathname)
|
fmt.Printf("%s %s\n", de.ModeType(), osPathname)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@ -47,8 +53,8 @@ Here's why I use `godirwalk` in preference to `filepath.Walk`,
|
|||||||
|
|
||||||
When compared against `filepath.Walk` in benchmarks, it has been
|
When compared against `filepath.Walk` in benchmarks, it has been
|
||||||
observed to run between five and ten times the speed on darwin, at
|
observed to run between five and ten times the speed on darwin, at
|
||||||
speeds comparable to the that of the unix `find` utility; about twice
|
speeds comparable to the that of the unix `find` utility; and about
|
||||||
the speed on linux; and about four times the speed on Windows.
|
twice the speed on linux; and about four times the speed on Windows.
|
||||||
|
|
||||||
How does it obtain this performance boost? It does less work to give
|
How does it obtain this performance boost? It does less work to give
|
||||||
you nearly the same output. This library calls the same `syscall`
|
you nearly the same output. This library calls the same `syscall`
|
||||||
@ -60,11 +66,11 @@ file system entry data from the operating system.
|
|||||||
|
|
||||||
While traversing a file system directory tree, `filepath.Walk` obtains
|
While traversing a file system directory tree, `filepath.Walk` obtains
|
||||||
the list of immediate descendants of a directory, and throws away the
|
the list of immediate descendants of a directory, and throws away the
|
||||||
file system node type information provided by the operating system
|
node type information for the file system entry that is provided by
|
||||||
that comes with the node's name. Then, immediately prior to invoking
|
the operating system that comes with the node's name. Then,
|
||||||
the callback function, `filepath.Walk` invokes `os.Stat` for each
|
immediately prior to invoking the callback function, `filepath.Walk`
|
||||||
node, and passes the returned `os.FileInfo` information to the
|
invokes `os.Stat` for each node, and passes the returned `os.FileInfo`
|
||||||
callback.
|
information to the callback.
|
||||||
|
|
||||||
While the `os.FileInfo` information provided by `os.Stat` is extremely
|
While the `os.FileInfo` information provided by `os.Stat` is extremely
|
||||||
helpful--and even includes the `os.FileMode` data--providing it
|
helpful--and even includes the `os.FileMode` data--providing it
|
||||||
@ -141,13 +147,20 @@ The takeaway is that behavior is different based on which platform
|
|||||||
until it is fixed in the standard library, it presents a compatibility
|
until it is fixed in the standard library, it presents a compatibility
|
||||||
problem.
|
problem.
|
||||||
|
|
||||||
This library correctly identifies symbolic links that point to
|
This library fixes the above problem such that it will never follow
|
||||||
directories and will only follow them when `FollowSymbolicLinks` is
|
logical file sytem loops on either unix or Windows. Furthermore, it
|
||||||
set to true. Behavior on Windows and other operating systems is
|
will only follow symbolic links when `FollowSymbolicLinks` is set to
|
||||||
identical.
|
true. Behavior on Windows and other operating systems is identical.
|
||||||
|
|
||||||
### It's more easy to use than `filepath.Walk`
|
### It's more easy to use than `filepath.Walk`
|
||||||
|
|
||||||
|
While this library strives to mimic the behavior of the incredibly
|
||||||
|
well-written `filepath.Walk` standard library, there are places where
|
||||||
|
it deviates a bit in order to provide a more easy or intuitive caller
|
||||||
|
interface.
|
||||||
|
|
||||||
|
#### Callback interface does not send you an error to check
|
||||||
|
|
||||||
Since this library does not invoke `os.Stat` on every file system node
|
Since this library does not invoke `os.Stat` on every file system node
|
||||||
it encounters, there is no possible error event for the callback
|
it encounters, there is no possible error event for the callback
|
||||||
function to filter on. The third argument in the `filepath.WalkFunc`
|
function to filter on. The third argument in the `filepath.WalkFunc`
|
||||||
@ -155,23 +168,105 @@ function signature to pass the error from `os.Stat` to the callback
|
|||||||
function is no longer necessary, and thus eliminated from signature of
|
function is no longer necessary, and thus eliminated from signature of
|
||||||
the callback function from this library.
|
the callback function from this library.
|
||||||
|
|
||||||
Also, `filepath.Walk` invokes the callback function with a solidus
|
Furthermore, this slight interface difference between
|
||||||
delimited pathname regardless of the os-specific path separator. This
|
`filepath.WalkFunc` and this library's `WalkFunc` eliminates the
|
||||||
library invokes the callback function with the os-specific pathname
|
boilerplate code that callback handlers must write when they use
|
||||||
separator, obviating a call to `filepath.Clean` in the callback
|
`filepath.Walk`. Rather than every callback function needing to check
|
||||||
function for each node prior to actually using the provided pathname.
|
the error value passed into it and branch accordingly, users of this
|
||||||
|
library do not even have an error value to check immediately upon
|
||||||
|
entry into the callback function. This is an improvement both in
|
||||||
|
runtime performance and code clarity.
|
||||||
|
|
||||||
|
#### Callback function is invoked with OS specific file system path separator
|
||||||
|
|
||||||
|
On every OS platform `filepath.Walk` invokes the callback function
|
||||||
|
with a solidus (`/`) delimited pathname. By contrast this library
|
||||||
|
invokes the callback with the os-specific pathname separator,
|
||||||
|
obviating a call to `filepath.Clean` in the callback function for each
|
||||||
|
node prior to actually using the provided pathname.
|
||||||
|
|
||||||
In other words, even on Windows, `filepath.Walk` will invoke the
|
In other words, even on Windows, `filepath.Walk` will invoke the
|
||||||
callback with `some/path/to/foo.txt`, requiring well written clients
|
callback with `some/path/to/foo.txt`, requiring well written clients
|
||||||
to perform pathname normalization for every file prior to working with
|
to perform pathname normalization for every file prior to working with
|
||||||
the specified file. In truth, many clients developed on unix and not
|
the specified file. This is a hidden boilerplate requirement to create
|
||||||
tested on Windows neglect this subtlety, and will result in software
|
truly os agnostic callback functions. In truth, many clients developed
|
||||||
bugs when running on Windows. This library would invoke the callback
|
on unix and not tested on Windows neglect this subtlety, and will
|
||||||
function with `some\path\to\foo.txt` for the same file when running on
|
result in software bugs when someone tries to run that software on
|
||||||
Windows, eliminating the need to normalize the pathname by the client,
|
|
||||||
and lessen the likelyhood that a client will work on unix but not on
|
|
||||||
Windows.
|
Windows.
|
||||||
|
|
||||||
|
This library invokes the callback function with `some\path\to\foo.txt`
|
||||||
|
for the same file when running on Windows, eliminating the need to
|
||||||
|
normalize the pathname by the client, and lessen the likelyhood that a
|
||||||
|
client will work on unix but not on Windows.
|
||||||
|
|
||||||
|
This enhancement eliminates necessity for some more boilerplate code
|
||||||
|
in callback functions while improving the runtime performance of this
|
||||||
|
library.
|
||||||
|
|
||||||
|
#### `godirwalk.SkipThis` is more intuitive to use than `filepath.SkipDir`
|
||||||
|
|
||||||
|
One arguably confusing aspect of the `filepath.WalkFunc` interface
|
||||||
|
that this library must emulate is how a caller tells the `Walk`
|
||||||
|
function to skip file system entries. With both `filepath.Walk` and
|
||||||
|
this library's `Walk`, when a callback function wants to skip a
|
||||||
|
directory and not descend into its children, it returns
|
||||||
|
`filepath.SkipDir`. If the callback function returns
|
||||||
|
`filepath.SkipDir` for a non-directory, `filepath.Walk` and this
|
||||||
|
library will stop processing any more entries in the current
|
||||||
|
directory. This is not necessarily what most developers want or
|
||||||
|
expect. If you want to simply skip a particular non-directory entry
|
||||||
|
but continue processing entries in the directory, the callback
|
||||||
|
function must return nil.
|
||||||
|
|
||||||
|
The implications of this interface design is when you want to walk a
|
||||||
|
file system hierarchy and skip an entry, you have to return a
|
||||||
|
different value based on what type of file system entry that node
|
||||||
|
is. To skip an entry, if the entry is a directory, you must return
|
||||||
|
`filepath.SkipDir`, and if entry is not a directory, you must return
|
||||||
|
`nil`. This is an unfortunate hurdle I have observed many developers
|
||||||
|
struggling with, simply because it is not an intuitive interface.
|
||||||
|
|
||||||
|
Here is an example callback function that adheres to
|
||||||
|
`filepath.WalkFunc` interface to have it skip any file system entry
|
||||||
|
whose full pathname includes a particular substring, `optSkip`. Note
|
||||||
|
that this library still supports identical behavior of `filepath.Walk`
|
||||||
|
when the callback function returns `filepath.SkipDir`.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func callback1(osPathname string, de *godirwalk.Dirent) error {
|
||||||
|
if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||||
|
if b, err := de.IsDirOrSymlinkToDir(); b == true && err == nil {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Process file like normal...
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This library attempts to eliminate some of that logic boilerplate
|
||||||
|
required in callback functions by providing a new token error value,
|
||||||
|
`SkipThis`, which a callback function may return to skip the current
|
||||||
|
file system entry regardless of what type of entry it is. If the
|
||||||
|
current entry is a directory, its children will not be enumerated,
|
||||||
|
exactly as if the callback had returned `filepath.SkipDir`. If the
|
||||||
|
current entry is a non-directory, the next file system entry in the
|
||||||
|
current directory will be enumerated, exactly as if the callback
|
||||||
|
returned `nil`. The following example callback function has identical
|
||||||
|
behavior as the previous, but has less boilerplate, and admittedly
|
||||||
|
logic that I find more simple to follow.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func callback2(osPathname string, de *godirwalk.Dirent) error {
|
||||||
|
if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||||
|
return godirwalk.SkipThis
|
||||||
|
}
|
||||||
|
// Process file like normal...
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### It's more flexible than `filepath.Walk`
|
### It's more flexible than `filepath.Walk`
|
||||||
|
|
||||||
#### Configurable Handling of Symbolic Links
|
#### Configurable Handling of Symbolic Links
|
||||||
@ -182,7 +277,7 @@ does. However, it does invoke the callback function with each node it
|
|||||||
finds, including symbolic links. If a particular use case exists to
|
finds, including symbolic links. If a particular use case exists to
|
||||||
follow symbolic links when traversing a directory tree, this library
|
follow symbolic links when traversing a directory tree, this library
|
||||||
can be invoked in manner to do so, by setting the
|
can be invoked in manner to do so, by setting the
|
||||||
`FollowSymbolicLinks` parameter to true.
|
`FollowSymbolicLinks` config parameter to `true`.
|
||||||
|
|
||||||
#### Configurable Sorting of Directory Children
|
#### Configurable Sorting of Directory Children
|
||||||
|
|
||||||
@ -191,11 +286,12 @@ descendants of a directory prior to visiting each node, just like
|
|||||||
`filepath.Walk` does. This is usually the desired behavior. However,
|
`filepath.Walk` does. This is usually the desired behavior. However,
|
||||||
this does come at slight performance and memory penalties required to
|
this does come at slight performance and memory penalties required to
|
||||||
sort the names when a directory node has many entries. Additionally if
|
sort the names when a directory node has many entries. Additionally if
|
||||||
caller specifies `Unsorted` enumeration, reading directories is lazily
|
caller specifies `Unsorted` enumeration in the configuration
|
||||||
performed as the caller consumes entries. If a particular use case
|
parameter, reading directories is lazily performed as the caller
|
||||||
exists that does not require sorting the directory's immediate
|
consumes entries. If a particular use case exists that does not
|
||||||
descendants prior to visiting its nodes, this library will skip the
|
require sorting the directory's immediate descendants prior to
|
||||||
sorting step when the `Unsorted` parameter is set to true.
|
visiting its nodes, this library will skip the sorting step when the
|
||||||
|
`Unsorted` parameter is set to `true`.
|
||||||
|
|
||||||
Here's an interesting read of the potential hazzards of traversing a
|
Here's an interesting read of the potential hazzards of traversing a
|
||||||
file system hierarchy in a non-deterministic order. If you know the
|
file system hierarchy in a non-deterministic order. If you know the
|
||||||
@ -208,10 +304,11 @@ setting this option.
|
|||||||
#### Configurable Post Children Callback
|
#### Configurable Post Children Callback
|
||||||
|
|
||||||
This library provides upstream code with the ability to specify a
|
This library provides upstream code with the ability to specify a
|
||||||
callback to be invoked for each directory after its children are
|
callback function to be invoked for each directory after its children
|
||||||
processed. This has been used to recursively delete empty directories
|
are processed. This has been used to recursively delete empty
|
||||||
after traversing the file system in a more efficient manner. See the
|
directories after traversing the file system in a more efficient
|
||||||
`examples/clean-empties` directory for an example of this usage.
|
manner. See the `examples/clean-empties` directory for an example of
|
||||||
|
this usage.
|
||||||
|
|
||||||
#### Configurable Error Callback
|
#### Configurable Error Callback
|
||||||
|
|
||||||
|
7
vendor/github.com/karrick/godirwalk/bench.sh
generated
vendored
Normal file
7
vendor/github.com/karrick/godirwalk/bench.sh
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# for version in v1.9.1 v1.10.0 v1.10.3 v1.10.12 v1.11.2 v1.11.3 v1.12.0 v1.13.1 v1.14.0 v1.14.1 ; do
|
||||||
|
for version in v1.10.12 v1.14.1 v1.15.2 ; do
|
||||||
|
echo "### $version" > $version.txt
|
||||||
|
git checkout -- go.mod && git checkout $version && go test -run=NONE -bench=Benchmark2 >> $version.txt || exit 1
|
||||||
|
done
|
19
vendor/github.com/karrick/godirwalk/readdir_unix.go
generated
vendored
19
vendor/github.com/karrick/godirwalk/readdir_unix.go
generated
vendored
@ -31,11 +31,15 @@ func readDirents(osDirname string, scratchBuffer []byte) ([]*Dirent, error) {
|
|||||||
scratchBuffer = newScratchBuffer()
|
scratchBuffer = newScratchBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sde syscall.Dirent
|
||||||
for {
|
for {
|
||||||
if len(workBuffer) == 0 {
|
if len(workBuffer) == 0 {
|
||||||
n, err := syscall.ReadDirent(fd, scratchBuffer)
|
n, err := syscall.ReadDirent(fd, scratchBuffer)
|
||||||
// n, err := unix.ReadDirent(fd, scratchBuffer)
|
// n, err := unix.ReadDirent(fd, scratchBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == syscall.EINTR /* || err == unix.EINTR */ {
|
||||||
|
continue
|
||||||
|
}
|
||||||
_ = dh.Close()
|
_ = dh.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -48,14 +52,14 @@ func readDirents(osDirname string, scratchBuffer []byte) ([]*Dirent, error) {
|
|||||||
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
|
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
sde := (*syscall.Dirent)(unsafe.Pointer(&workBuffer[0])) // point entry to first syscall.Dirent in buffer
|
copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(&sde))[:], workBuffer)
|
||||||
workBuffer = workBuffer[reclen(sde):] // advance buffer for next iteration through loop
|
workBuffer = workBuffer[reclen(&sde):] // advance buffer for next iteration through loop
|
||||||
|
|
||||||
if inoFromDirent(sde) == 0 {
|
if inoFromDirent(&sde) == 0 {
|
||||||
continue // inode set to 0 indicates an entry that was marked as deleted
|
continue // inode set to 0 indicates an entry that was marked as deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
nameSlice := nameFromDirent(sde)
|
nameSlice := nameFromDirent(&sde)
|
||||||
nameLength := len(nameSlice)
|
nameLength := len(nameSlice)
|
||||||
|
|
||||||
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
|
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
|
||||||
@ -63,7 +67,7 @@ func readDirents(osDirname string, scratchBuffer []byte) ([]*Dirent, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
childName := string(nameSlice)
|
childName := string(nameSlice)
|
||||||
mt, err := modeTypeFromDirent(sde, osDirname, childName)
|
mt, err := modeTypeFromDirent(&sde, osDirname, childName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = dh.Close()
|
_ = dh.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -92,6 +96,9 @@ func readDirnames(osDirname string, scratchBuffer []byte) ([]string, error) {
|
|||||||
n, err := syscall.ReadDirent(fd, scratchBuffer)
|
n, err := syscall.ReadDirent(fd, scratchBuffer)
|
||||||
// n, err := unix.ReadDirent(fd, scratchBuffer)
|
// n, err := unix.ReadDirent(fd, scratchBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == syscall.EINTR /* || err == unix.EINTR */ {
|
||||||
|
continue
|
||||||
|
}
|
||||||
_ = dh.Close()
|
_ = dh.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -104,8 +111,8 @@ func readDirnames(osDirname string, scratchBuffer []byte) ([]string, error) {
|
|||||||
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
|
workBuffer = scratchBuffer[:n] // trim work buffer to number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle first entry in the work buffer.
|
|
||||||
sde = (*syscall.Dirent)(unsafe.Pointer(&workBuffer[0])) // point entry to first syscall.Dirent in buffer
|
sde = (*syscall.Dirent)(unsafe.Pointer(&workBuffer[0])) // point entry to first syscall.Dirent in buffer
|
||||||
|
// Handle first entry in the work buffer.
|
||||||
workBuffer = workBuffer[reclen(sde):] // advance buffer for next iteration through loop
|
workBuffer = workBuffer[reclen(sde):] // advance buffer for next iteration through loop
|
||||||
|
|
||||||
if inoFromDirent(sde) == 0 {
|
if inoFromDirent(sde) == 0 {
|
||||||
|
19
vendor/github.com/karrick/godirwalk/scandir_unix.go
generated
vendored
19
vendor/github.com/karrick/godirwalk/scandir_unix.go
generated
vendored
@ -18,7 +18,7 @@ type Scanner struct {
|
|||||||
statErr error // statErr is any error return while attempting to stat an entry
|
statErr error // statErr is any error return while attempting to stat an entry
|
||||||
dh *os.File // used to close directory after done reading
|
dh *os.File // used to close directory after done reading
|
||||||
de *Dirent // most recently decoded directory entry
|
de *Dirent // most recently decoded directory entry
|
||||||
sde *syscall.Dirent
|
sde syscall.Dirent
|
||||||
fd int // file descriptor used to read entries from directory
|
fd int // file descriptor used to read entries from directory
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ func NewScannerWithScratchBuffer(osDirname string, scratchBuffer []byte) (*Scann
|
|||||||
func (s *Scanner) Dirent() (*Dirent, error) {
|
func (s *Scanner) Dirent() (*Dirent, error) {
|
||||||
if s.de == nil {
|
if s.de == nil {
|
||||||
s.de = &Dirent{name: s.childName, path: s.osDirname}
|
s.de = &Dirent{name: s.childName, path: s.osDirname}
|
||||||
s.de.modeType, s.statErr = modeTypeFromDirent(s.sde, s.osDirname, s.childName)
|
s.de.modeType, s.statErr = modeTypeFromDirent(&s.sde, s.osDirname, s.childName)
|
||||||
}
|
}
|
||||||
return s.de, s.statErr
|
return s.de, s.statErr
|
||||||
}
|
}
|
||||||
@ -96,7 +96,8 @@ func (s *Scanner) done(err error) {
|
|||||||
|
|
||||||
s.osDirname, s.childName = "", ""
|
s.osDirname, s.childName = "", ""
|
||||||
s.scratchBuffer, s.workBuffer = nil, nil
|
s.scratchBuffer, s.workBuffer = nil, nil
|
||||||
s.dh, s.de, s.sde, s.statErr = nil, nil, nil, nil
|
s.dh, s.de, s.statErr = nil, nil, nil
|
||||||
|
s.sde = syscall.Dirent{}
|
||||||
s.fd = 0
|
s.fd = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +132,9 @@ func (s *Scanner) Scan() bool {
|
|||||||
n, err := syscall.ReadDirent(s.fd, s.scratchBuffer)
|
n, err := syscall.ReadDirent(s.fd, s.scratchBuffer)
|
||||||
// n, err := unix.ReadDirent(s.fd, s.scratchBuffer)
|
// n, err := unix.ReadDirent(s.fd, s.scratchBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == syscall.EINTR /* || err == unix.EINTR */ {
|
||||||
|
continue
|
||||||
|
}
|
||||||
s.done(err)
|
s.done(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -141,14 +145,15 @@ func (s *Scanner) Scan() bool {
|
|||||||
s.workBuffer = s.scratchBuffer[:n] // trim work buffer to number of bytes read
|
s.workBuffer = s.scratchBuffer[:n] // trim work buffer to number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
s.sde = (*syscall.Dirent)(unsafe.Pointer(&s.workBuffer[0])) // point entry to first syscall.Dirent in buffer
|
// point entry to first syscall.Dirent in buffer
|
||||||
s.workBuffer = s.workBuffer[reclen(s.sde):] // advance buffer for next iteration through loop
|
copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(&s.sde))[:], s.workBuffer)
|
||||||
|
s.workBuffer = s.workBuffer[reclen(&s.sde):] // advance buffer for next iteration through loop
|
||||||
|
|
||||||
if inoFromDirent(s.sde) == 0 {
|
if inoFromDirent(&s.sde) == 0 {
|
||||||
continue // inode set to 0 indicates an entry that was marked as deleted
|
continue // inode set to 0 indicates an entry that was marked as deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
nameSlice := nameFromDirent(s.sde)
|
nameSlice := nameFromDirent(&s.sde)
|
||||||
nameLength := len(nameSlice)
|
nameLength := len(nameSlice)
|
||||||
|
|
||||||
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
|
if nameLength == 0 || (nameSlice[0] == '.' && (nameLength == 1 || (nameLength == 2 && nameSlice[1] == '.'))) {
|
||||||
|
67
vendor/github.com/karrick/godirwalk/walk.go
generated
vendored
67
vendor/github.com/karrick/godirwalk/walk.go
generated
vendored
@ -96,6 +96,11 @@ const (
|
|||||||
SkipNode
|
SkipNode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SkipThis is used as a return value from WalkFuncs to indicate that the file
|
||||||
|
// system entry named in the call is to be skipped. It is not returned as an
|
||||||
|
// error by any function.
|
||||||
|
var SkipThis = errors.New("skip this directory entry")
|
||||||
|
|
||||||
// WalkFunc is the type of the function called for each file system node visited
|
// WalkFunc is the type of the function called for each file system node visited
|
||||||
// by Walk. The pathname argument will contain the argument to Walk as a prefix;
|
// by Walk. The pathname argument will contain the argument to Walk as a prefix;
|
||||||
// that is, if Walk is called with "dir", which is a directory containing the
|
// that is, if Walk is called with "dir", which is a directory containing the
|
||||||
@ -119,6 +124,55 @@ const (
|
|||||||
// Walk skips the remaining files in the containing directory. Note that any
|
// Walk skips the remaining files in the containing directory. Note that any
|
||||||
// supplied ErrorCallback function is not invoked with filepath.SkipDir when the
|
// supplied ErrorCallback function is not invoked with filepath.SkipDir when the
|
||||||
// Callback or PostChildrenCallback functions return that special value.
|
// Callback or PostChildrenCallback functions return that special value.
|
||||||
|
//
|
||||||
|
// One arguably confusing aspect of the filepath.WalkFunc API that this library
|
||||||
|
// must emulate is how a caller tells Walk to skip file system entries or
|
||||||
|
// directories. With both filepath.Walk and this Walk, when a callback function
|
||||||
|
// wants to skip a directory and not descend into its children, it returns
|
||||||
|
// filepath.SkipDir. If the callback function returns filepath.SkipDir for a
|
||||||
|
// non-directory, filepath.Walk and this library will stop processing any more
|
||||||
|
// entries in the current directory, which is what many people do not want. If
|
||||||
|
// you want to simply skip a particular non-directory entry but continue
|
||||||
|
// processing entries in the directory, a callback function must return nil. The
|
||||||
|
// implications of this API is when you want to walk a file system hierarchy and
|
||||||
|
// skip an entry, when the entry is a directory, you must return one value,
|
||||||
|
// namely filepath.SkipDir, but when the entry is a non-directory, you must
|
||||||
|
// return a different value, namely nil. In other words, to get identical
|
||||||
|
// behavior for two file system entry types you need to send different token
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// Here is an example callback function that adheres to filepath.Walk API to
|
||||||
|
// have it skip any file system entry whose full pathname includes a particular
|
||||||
|
// substring, optSkip:
|
||||||
|
//
|
||||||
|
// func callback1(osPathname string, de *godirwalk.Dirent) error {
|
||||||
|
// if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||||
|
// if b, err := de.IsDirOrSymlinkToDir(); b == true && err == nil {
|
||||||
|
// return filepath.SkipDir
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// // Process file like normal...
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This library attempts to eliminate some of that logic boilerplate by
|
||||||
|
// providing a new token error value, SkipThis, which a callback function may
|
||||||
|
// return to skip the current file system entry regardless of what type of entry
|
||||||
|
// it is. If the current entry is a directory, its children will not be
|
||||||
|
// enumerated, exactly as if the callback returned filepath.SkipDir. If the
|
||||||
|
// current entry is a non-directory, the next file system entry in the current
|
||||||
|
// directory will be enumerated, exactly as if the callback returned nil. The
|
||||||
|
// following example callback function has identical behavior as the previous,
|
||||||
|
// but has less boilerplate, and admittedly more simple logic.
|
||||||
|
//
|
||||||
|
// func callback2(osPathname string, de *godirwalk.Dirent) error {
|
||||||
|
// if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||||
|
// return godirwalk.SkipThis
|
||||||
|
// }
|
||||||
|
// // Process file like normal...
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
type WalkFunc func(osPathname string, directoryEntry *Dirent) error
|
type WalkFunc func(osPathname string, directoryEntry *Dirent) error
|
||||||
|
|
||||||
// Walk walks the file tree rooted at the specified directory, calling the
|
// Walk walks the file tree rooted at the specified directory, calling the
|
||||||
@ -201,10 +255,15 @@ func Walk(pathname string, options *Options) error {
|
|||||||
options.ErrorCallback = defaultErrorCallback
|
options.ErrorCallback = defaultErrorCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = walk(pathname, dirent, options); err != filepath.SkipDir {
|
err = walk(pathname, dirent, options)
|
||||||
|
switch err {
|
||||||
|
case nil, SkipThis, filepath.SkipDir:
|
||||||
|
// silence SkipThis and filepath.SkipDir for top level
|
||||||
|
debug("no error of significance: %v\n", err)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil // silence SkipDir for top level
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultErrorCallback always returns Halt because if the upstream code did not
|
// defaultErrorCallback always returns Halt because if the upstream code did not
|
||||||
@ -217,7 +276,7 @@ func defaultErrorCallback(_ string, _ error) ErrorAction { return Halt }
|
|||||||
func walk(osPathname string, dirent *Dirent, options *Options) error {
|
func walk(osPathname string, dirent *Dirent, options *Options) error {
|
||||||
err := options.Callback(osPathname, dirent)
|
err := options.Callback(osPathname, dirent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == filepath.SkipDir {
|
if err == SkipThis || err == filepath.SkipDir {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||||
@ -278,7 +337,7 @@ func walk(osPathname string, dirent *Dirent, options *Options) error {
|
|||||||
}
|
}
|
||||||
err = walk(osChildname, deChild, options)
|
err = walk(osChildname, deChild, options)
|
||||||
debug("osChildname: %q; error: %v\n", osChildname, err)
|
debug("osChildname: %q; error: %v\n", osChildname, err)
|
||||||
if err == nil {
|
if err == nil || err == SkipThis {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != filepath.SkipDir {
|
if err != filepath.SkipDir {
|
||||||
|
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
|
|
||||||
|
|
||||||
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.
|
|
42
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
42
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
# Windows Terminal Sequences
|
|
||||||
|
|
||||||
This library allow for enabling Windows terminal color support for Go.
|
|
||||||
|
|
||||||
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
|
|
||||||
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
|
||||||
|
|
||||||
We thank all the authors who provided code to this library:
|
|
||||||
|
|
||||||
* Felix Kollmann
|
|
||||||
* Nicolas Perraut
|
|
||||||
* @dirty49374
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
|
|
||||||
|
|
||||||
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.
|
|
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
generated
vendored
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
generated
vendored
@ -1 +0,0 @@
|
|||||||
module github.com/konsorten/go-windows-terminal-sequences
|
|
35
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
35
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
package sequences
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
|
|
||||||
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
|
||||||
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
|
|
||||||
|
|
||||||
var mode uint32
|
|
||||||
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if enable {
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
} else {
|
|
||||||
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, _, err := setConsoleMode.Call(uintptr(stream), uintptr(mode))
|
|
||||||
if ret == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// +build linux darwin
|
|
||||||
|
|
||||||
package sequences
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
|
|
||||||
return fmt.Errorf("windows only package")
|
|
||||||
}
|
|
27
vendor/github.com/rogpeppe/go-internal/LICENSE
generated
vendored
27
vendor/github.com/rogpeppe/go-internal/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2018 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
47
vendor/github.com/rogpeppe/go-internal/modfile/gopkgin.go
generated
vendored
47
vendor/github.com/rogpeppe/go-internal/modfile/gopkgin.go
generated
vendored
@ -1,47 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// TODO: Figure out what gopkg.in should do.
|
|
||||||
|
|
||||||
package modfile
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// ParseGopkgIn splits gopkg.in import paths into their constituent parts
|
|
||||||
func ParseGopkgIn(path string) (root, repo, major, subdir string, ok bool) {
|
|
||||||
if !strings.HasPrefix(path, "gopkg.in/") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f := strings.Split(path, "/")
|
|
||||||
if len(f) >= 2 {
|
|
||||||
if elem, v, ok := dotV(f[1]); ok {
|
|
||||||
root = strings.Join(f[:2], "/")
|
|
||||||
repo = "github.com/go-" + elem + "/" + elem
|
|
||||||
major = v
|
|
||||||
subdir = strings.Join(f[2:], "/")
|
|
||||||
return root, repo, major, subdir, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(f) >= 3 {
|
|
||||||
if elem, v, ok := dotV(f[2]); ok {
|
|
||||||
root = strings.Join(f[:3], "/")
|
|
||||||
repo = "github.com/" + f[1] + "/" + elem
|
|
||||||
major = v
|
|
||||||
subdir = strings.Join(f[3:], "/")
|
|
||||||
return root, repo, major, subdir, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func dotV(name string) (elem, v string, ok bool) {
|
|
||||||
i := len(name) - 1
|
|
||||||
for i >= 0 && '0' <= name[i] && name[i] <= '9' {
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
if i <= 2 || i+1 >= len(name) || name[i-1] != '.' || name[i] != 'v' || name[i+1] == '0' && len(name) != i+2 {
|
|
||||||
return "", "", false
|
|
||||||
}
|
|
||||||
return name[:i-1], name[i:], true
|
|
||||||
}
|
|
164
vendor/github.com/rogpeppe/go-internal/modfile/print.go
generated
vendored
164
vendor/github.com/rogpeppe/go-internal/modfile/print.go
generated
vendored
@ -1,164 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package modfile implements parsing and formatting for
|
|
||||||
// go.mod files.
|
|
||||||
package modfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Format(f *FileSyntax) []byte {
|
|
||||||
pr := &printer{}
|
|
||||||
pr.file(f)
|
|
||||||
return pr.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// A printer collects the state during printing of a file or expression.
|
|
||||||
type printer struct {
|
|
||||||
bytes.Buffer // output buffer
|
|
||||||
comment []Comment // pending end-of-line comments
|
|
||||||
margin int // left margin (indent), a number of tabs
|
|
||||||
}
|
|
||||||
|
|
||||||
// printf prints to the buffer.
|
|
||||||
func (p *printer) printf(format string, args ...interface{}) {
|
|
||||||
fmt.Fprintf(p, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// indent returns the position on the current line, in bytes, 0-indexed.
|
|
||||||
func (p *printer) indent() int {
|
|
||||||
b := p.Bytes()
|
|
||||||
n := 0
|
|
||||||
for n < len(b) && b[len(b)-1-n] != '\n' {
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// newline ends the current line, flushing end-of-line comments.
|
|
||||||
func (p *printer) newline() {
|
|
||||||
if len(p.comment) > 0 {
|
|
||||||
p.printf(" ")
|
|
||||||
for i, com := range p.comment {
|
|
||||||
if i > 0 {
|
|
||||||
p.trim()
|
|
||||||
p.printf("\n")
|
|
||||||
for i := 0; i < p.margin; i++ {
|
|
||||||
p.printf("\t")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.printf("%s", strings.TrimSpace(com.Token))
|
|
||||||
}
|
|
||||||
p.comment = p.comment[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
p.trim()
|
|
||||||
p.printf("\n")
|
|
||||||
for i := 0; i < p.margin; i++ {
|
|
||||||
p.printf("\t")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim removes trailing spaces and tabs from the current line.
|
|
||||||
func (p *printer) trim() {
|
|
||||||
// Remove trailing spaces and tabs from line we're about to end.
|
|
||||||
b := p.Bytes()
|
|
||||||
n := len(b)
|
|
||||||
for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
|
|
||||||
n--
|
|
||||||
}
|
|
||||||
p.Truncate(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// file formats the given file into the print buffer.
|
|
||||||
func (p *printer) file(f *FileSyntax) {
|
|
||||||
for _, com := range f.Before {
|
|
||||||
p.printf("%s", strings.TrimSpace(com.Token))
|
|
||||||
p.newline()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, stmt := range f.Stmt {
|
|
||||||
switch x := stmt.(type) {
|
|
||||||
case *CommentBlock:
|
|
||||||
// comments already handled
|
|
||||||
p.expr(x)
|
|
||||||
|
|
||||||
default:
|
|
||||||
p.expr(x)
|
|
||||||
p.newline()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, com := range stmt.Comment().After {
|
|
||||||
p.printf("%s", strings.TrimSpace(com.Token))
|
|
||||||
p.newline()
|
|
||||||
}
|
|
||||||
|
|
||||||
if i+1 < len(f.Stmt) {
|
|
||||||
p.newline()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *printer) expr(x Expr) {
|
|
||||||
// Emit line-comments preceding this expression.
|
|
||||||
if before := x.Comment().Before; len(before) > 0 {
|
|
||||||
// Want to print a line comment.
|
|
||||||
// Line comments must be at the current margin.
|
|
||||||
p.trim()
|
|
||||||
if p.indent() > 0 {
|
|
||||||
// There's other text on the line. Start a new line.
|
|
||||||
p.printf("\n")
|
|
||||||
}
|
|
||||||
// Re-indent to margin.
|
|
||||||
for i := 0; i < p.margin; i++ {
|
|
||||||
p.printf("\t")
|
|
||||||
}
|
|
||||||
for _, com := range before {
|
|
||||||
p.printf("%s", strings.TrimSpace(com.Token))
|
|
||||||
p.newline()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch x := x.(type) {
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("printer: unexpected type %T", x))
|
|
||||||
|
|
||||||
case *CommentBlock:
|
|
||||||
// done
|
|
||||||
|
|
||||||
case *LParen:
|
|
||||||
p.printf("(")
|
|
||||||
case *RParen:
|
|
||||||
p.printf(")")
|
|
||||||
|
|
||||||
case *Line:
|
|
||||||
sep := ""
|
|
||||||
for _, tok := range x.Token {
|
|
||||||
p.printf("%s%s", sep, tok)
|
|
||||||
sep = " "
|
|
||||||
}
|
|
||||||
|
|
||||||
case *LineBlock:
|
|
||||||
for _, tok := range x.Token {
|
|
||||||
p.printf("%s ", tok)
|
|
||||||
}
|
|
||||||
p.expr(&x.LParen)
|
|
||||||
p.margin++
|
|
||||||
for _, l := range x.Line {
|
|
||||||
p.newline()
|
|
||||||
p.expr(l)
|
|
||||||
}
|
|
||||||
p.margin--
|
|
||||||
p.newline()
|
|
||||||
p.expr(&x.RParen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Queue end-of-line comments for printing when we
|
|
||||||
// reach the end of the line.
|
|
||||||
p.comment = append(p.comment, x.Comment().Suffix...)
|
|
||||||
}
|
|
869
vendor/github.com/rogpeppe/go-internal/modfile/read.go
generated
vendored
869
vendor/github.com/rogpeppe/go-internal/modfile/read.go
generated
vendored
@ -1,869 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Module file parser.
|
|
||||||
// This is a simplified copy of Google's buildifier parser.
|
|
||||||
|
|
||||||
package modfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Position describes the position between two bytes of input.
|
|
||||||
type Position struct {
|
|
||||||
Line int // line in input (starting at 1)
|
|
||||||
LineRune int // rune in line (starting at 1)
|
|
||||||
Byte int // byte in input (starting at 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add returns the position at the end of s, assuming it starts at p.
|
|
||||||
func (p Position) add(s string) Position {
|
|
||||||
p.Byte += len(s)
|
|
||||||
if n := strings.Count(s, "\n"); n > 0 {
|
|
||||||
p.Line += n
|
|
||||||
s = s[strings.LastIndex(s, "\n")+1:]
|
|
||||||
p.LineRune = 1
|
|
||||||
}
|
|
||||||
p.LineRune += utf8.RuneCountInString(s)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Expr represents an input element.
|
|
||||||
type Expr interface {
|
|
||||||
// Span returns the start and end position of the expression,
|
|
||||||
// excluding leading or trailing comments.
|
|
||||||
Span() (start, end Position)
|
|
||||||
|
|
||||||
// Comment returns the comments attached to the expression.
|
|
||||||
// This method would normally be named 'Comments' but that
|
|
||||||
// would interfere with embedding a type of the same name.
|
|
||||||
Comment() *Comments
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Comment represents a single // comment.
|
|
||||||
type Comment struct {
|
|
||||||
Start Position
|
|
||||||
Token string // without trailing newline
|
|
||||||
Suffix bool // an end of line (not whole line) comment
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comments collects the comments associated with an expression.
|
|
||||||
type Comments struct {
|
|
||||||
Before []Comment // whole-line comments before this expression
|
|
||||||
Suffix []Comment // end-of-line comments after this expression
|
|
||||||
|
|
||||||
// For top-level expressions only, After lists whole-line
|
|
||||||
// comments following the expression.
|
|
||||||
After []Comment
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment returns the receiver. This isn't useful by itself, but
|
|
||||||
// a Comments struct is embedded into all the expression
|
|
||||||
// implementation types, and this gives each of those a Comment
|
|
||||||
// method to satisfy the Expr interface.
|
|
||||||
func (c *Comments) Comment() *Comments {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// A FileSyntax represents an entire go.mod file.
|
|
||||||
type FileSyntax struct {
|
|
||||||
Name string // file path
|
|
||||||
Comments
|
|
||||||
Stmt []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FileSyntax) Span() (start, end Position) {
|
|
||||||
if len(x.Stmt) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
start, _ = x.Stmt[0].Span()
|
|
||||||
_, end = x.Stmt[len(x.Stmt)-1].Span()
|
|
||||||
return start, end
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line {
|
|
||||||
if hint == nil {
|
|
||||||
// If no hint given, add to the last statement of the given type.
|
|
||||||
Loop:
|
|
||||||
for i := len(x.Stmt) - 1; i >= 0; i-- {
|
|
||||||
stmt := x.Stmt[i]
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *Line:
|
|
||||||
if stmt.Token != nil && stmt.Token[0] == tokens[0] {
|
|
||||||
hint = stmt
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
case *LineBlock:
|
|
||||||
if stmt.Token[0] == tokens[0] {
|
|
||||||
hint = stmt
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hint != nil {
|
|
||||||
for i, stmt := range x.Stmt {
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *Line:
|
|
||||||
if stmt == hint {
|
|
||||||
// Convert line to line block.
|
|
||||||
stmt.InBlock = true
|
|
||||||
block := &LineBlock{Token: stmt.Token[:1], Line: []*Line{stmt}}
|
|
||||||
stmt.Token = stmt.Token[1:]
|
|
||||||
x.Stmt[i] = block
|
|
||||||
new := &Line{Token: tokens[1:], InBlock: true}
|
|
||||||
block.Line = append(block.Line, new)
|
|
||||||
return new
|
|
||||||
}
|
|
||||||
case *LineBlock:
|
|
||||||
if stmt == hint {
|
|
||||||
new := &Line{Token: tokens[1:], InBlock: true}
|
|
||||||
stmt.Line = append(stmt.Line, new)
|
|
||||||
return new
|
|
||||||
}
|
|
||||||
for j, line := range stmt.Line {
|
|
||||||
if line == hint {
|
|
||||||
// Add new line after hint.
|
|
||||||
stmt.Line = append(stmt.Line, nil)
|
|
||||||
copy(stmt.Line[j+2:], stmt.Line[j+1:])
|
|
||||||
new := &Line{Token: tokens[1:], InBlock: true}
|
|
||||||
stmt.Line[j+1] = new
|
|
||||||
return new
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new := &Line{Token: tokens}
|
|
||||||
x.Stmt = append(x.Stmt, new)
|
|
||||||
return new
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FileSyntax) updateLine(line *Line, tokens ...string) {
|
|
||||||
if line.InBlock {
|
|
||||||
tokens = tokens[1:]
|
|
||||||
}
|
|
||||||
line.Token = tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *FileSyntax) removeLine(line *Line) {
|
|
||||||
line.Token = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup cleans up the file syntax x after any edit operations.
|
|
||||||
// To avoid quadratic behavior, removeLine marks the line as dead
|
|
||||||
// by setting line.Token = nil but does not remove it from the slice
|
|
||||||
// in which it appears. After edits have all been indicated,
|
|
||||||
// calling Cleanup cleans out the dead lines.
|
|
||||||
func (x *FileSyntax) Cleanup() {
|
|
||||||
w := 0
|
|
||||||
for _, stmt := range x.Stmt {
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *Line:
|
|
||||||
if stmt.Token == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case *LineBlock:
|
|
||||||
ww := 0
|
|
||||||
for _, line := range stmt.Line {
|
|
||||||
if line.Token != nil {
|
|
||||||
stmt.Line[ww] = line
|
|
||||||
ww++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ww == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ww == 1 {
|
|
||||||
// Collapse block into single line.
|
|
||||||
line := &Line{
|
|
||||||
Comments: Comments{
|
|
||||||
Before: commentsAdd(stmt.Before, stmt.Line[0].Before),
|
|
||||||
Suffix: commentsAdd(stmt.Line[0].Suffix, stmt.Suffix),
|
|
||||||
After: commentsAdd(stmt.Line[0].After, stmt.After),
|
|
||||||
},
|
|
||||||
Token: stringsAdd(stmt.Token, stmt.Line[0].Token),
|
|
||||||
}
|
|
||||||
x.Stmt[w] = line
|
|
||||||
w++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
stmt.Line = stmt.Line[:ww]
|
|
||||||
}
|
|
||||||
x.Stmt[w] = stmt
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
x.Stmt = x.Stmt[:w]
|
|
||||||
}
|
|
||||||
|
|
||||||
func commentsAdd(x, y []Comment) []Comment {
|
|
||||||
return append(x[:len(x):len(x)], y...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringsAdd(x, y []string) []string {
|
|
||||||
return append(x[:len(x):len(x)], y...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A CommentBlock represents a top-level block of comments separate
|
|
||||||
// from any rule.
|
|
||||||
type CommentBlock struct {
|
|
||||||
Comments
|
|
||||||
Start Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommentBlock) Span() (start, end Position) {
|
|
||||||
return x.Start, x.Start
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Line is a single line of tokens.
|
|
||||||
type Line struct {
|
|
||||||
Comments
|
|
||||||
Start Position
|
|
||||||
Token []string
|
|
||||||
InBlock bool
|
|
||||||
End Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Line) Span() (start, end Position) {
|
|
||||||
return x.Start, x.End
|
|
||||||
}
|
|
||||||
|
|
||||||
// A LineBlock is a factored block of lines, like
|
|
||||||
//
|
|
||||||
// require (
|
|
||||||
// "x"
|
|
||||||
// "y"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
type LineBlock struct {
|
|
||||||
Comments
|
|
||||||
Start Position
|
|
||||||
LParen LParen
|
|
||||||
Token []string
|
|
||||||
Line []*Line
|
|
||||||
RParen RParen
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LineBlock) Span() (start, end Position) {
|
|
||||||
return x.Start, x.RParen.Pos.add(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
// An LParen represents the beginning of a parenthesized line block.
|
|
||||||
// It is a place to store suffix comments.
|
|
||||||
type LParen struct {
|
|
||||||
Comments
|
|
||||||
Pos Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LParen) Span() (start, end Position) {
|
|
||||||
return x.Pos, x.Pos.add(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
// An RParen represents the end of a parenthesized line block.
|
|
||||||
// It is a place to store whole-line (before) comments.
|
|
||||||
type RParen struct {
|
|
||||||
Comments
|
|
||||||
Pos Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RParen) Span() (start, end Position) {
|
|
||||||
return x.Pos, x.Pos.add(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
// An input represents a single input file being parsed.
|
|
||||||
type input struct {
|
|
||||||
// Lexing state.
|
|
||||||
filename string // name of input file, for errors
|
|
||||||
complete []byte // entire input
|
|
||||||
remaining []byte // remaining input
|
|
||||||
token []byte // token being scanned
|
|
||||||
lastToken string // most recently returned token, for error messages
|
|
||||||
pos Position // current input position
|
|
||||||
comments []Comment // accumulated comments
|
|
||||||
endRule int // position of end of current rule
|
|
||||||
|
|
||||||
// Parser state.
|
|
||||||
file *FileSyntax // returned top-level syntax tree
|
|
||||||
parseError error // error encountered during parsing
|
|
||||||
|
|
||||||
// Comment assignment state.
|
|
||||||
pre []Expr // all expressions, in preorder traversal
|
|
||||||
post []Expr // all expressions, in postorder traversal
|
|
||||||
}
|
|
||||||
|
|
||||||
func newInput(filename string, data []byte) *input {
|
|
||||||
return &input{
|
|
||||||
filename: filename,
|
|
||||||
complete: data,
|
|
||||||
remaining: data,
|
|
||||||
pos: Position{Line: 1, LineRune: 1, Byte: 0},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse parses the input file.
|
|
||||||
func parse(file string, data []byte) (f *FileSyntax, err error) {
|
|
||||||
in := newInput(file, data)
|
|
||||||
// The parser panics for both routine errors like syntax errors
|
|
||||||
// and for programmer bugs like array index errors.
|
|
||||||
// Turn both into error returns. Catching bug panics is
|
|
||||||
// especially important when processing many files.
|
|
||||||
defer func() {
|
|
||||||
if e := recover(); e != nil {
|
|
||||||
if e == in.parseError {
|
|
||||||
err = in.parseError
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("%s:%d:%d: internal error: %v", in.filename, in.pos.Line, in.pos.LineRune, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Invoke the parser.
|
|
||||||
in.parseFile()
|
|
||||||
if in.parseError != nil {
|
|
||||||
return nil, in.parseError
|
|
||||||
}
|
|
||||||
in.file.Name = in.filename
|
|
||||||
|
|
||||||
// Assign comments to nearby syntax.
|
|
||||||
in.assignComments()
|
|
||||||
|
|
||||||
return in.file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error is called to report an error.
|
|
||||||
// The reason s is often "syntax error".
|
|
||||||
// Error does not return: it panics.
|
|
||||||
func (in *input) Error(s string) {
|
|
||||||
if s == "syntax error" && in.lastToken != "" {
|
|
||||||
s += " near " + in.lastToken
|
|
||||||
}
|
|
||||||
in.parseError = fmt.Errorf("%s:%d:%d: %v", in.filename, in.pos.Line, in.pos.LineRune, s)
|
|
||||||
panic(in.parseError)
|
|
||||||
}
|
|
||||||
|
|
||||||
// eof reports whether the input has reached end of file.
|
|
||||||
func (in *input) eof() bool {
|
|
||||||
return len(in.remaining) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// peekRune returns the next rune in the input without consuming it.
|
|
||||||
func (in *input) peekRune() int {
|
|
||||||
if len(in.remaining) == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
r, _ := utf8.DecodeRune(in.remaining)
|
|
||||||
return int(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// peekPrefix reports whether the remaining input begins with the given prefix.
|
|
||||||
func (in *input) peekPrefix(prefix string) bool {
|
|
||||||
// This is like bytes.HasPrefix(in.remaining, []byte(prefix))
|
|
||||||
// but without the allocation of the []byte copy of prefix.
|
|
||||||
for i := 0; i < len(prefix); i++ {
|
|
||||||
if i >= len(in.remaining) || in.remaining[i] != prefix[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// readRune consumes and returns the next rune in the input.
|
|
||||||
func (in *input) readRune() int {
|
|
||||||
if len(in.remaining) == 0 {
|
|
||||||
in.Error("internal lexer error: readRune at EOF")
|
|
||||||
}
|
|
||||||
r, size := utf8.DecodeRune(in.remaining)
|
|
||||||
in.remaining = in.remaining[size:]
|
|
||||||
if r == '\n' {
|
|
||||||
in.pos.Line++
|
|
||||||
in.pos.LineRune = 1
|
|
||||||
} else {
|
|
||||||
in.pos.LineRune++
|
|
||||||
}
|
|
||||||
in.pos.Byte += size
|
|
||||||
return int(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
type symType struct {
|
|
||||||
pos Position
|
|
||||||
endPos Position
|
|
||||||
text string
|
|
||||||
}
|
|
||||||
|
|
||||||
// startToken marks the beginning of the next input token.
|
|
||||||
// It must be followed by a call to endToken, once the token has
|
|
||||||
// been consumed using readRune.
|
|
||||||
func (in *input) startToken(sym *symType) {
|
|
||||||
in.token = in.remaining
|
|
||||||
sym.text = ""
|
|
||||||
sym.pos = in.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// endToken marks the end of an input token.
|
|
||||||
// It records the actual token string in sym.text if the caller
|
|
||||||
// has not done that already.
|
|
||||||
func (in *input) endToken(sym *symType) {
|
|
||||||
if sym.text == "" {
|
|
||||||
tok := string(in.token[:len(in.token)-len(in.remaining)])
|
|
||||||
sym.text = tok
|
|
||||||
in.lastToken = sym.text
|
|
||||||
}
|
|
||||||
sym.endPos = in.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// lex is called from the parser to obtain the next input token.
|
|
||||||
// It returns the token value (either a rune like '+' or a symbolic token _FOR)
|
|
||||||
// and sets val to the data associated with the token.
|
|
||||||
// For all our input tokens, the associated data is
|
|
||||||
// val.Pos (the position where the token begins)
|
|
||||||
// and val.Token (the input string corresponding to the token).
|
|
||||||
func (in *input) lex(sym *symType) int {
|
|
||||||
// Skip past spaces, stopping at non-space or EOF.
|
|
||||||
countNL := 0 // number of newlines we've skipped past
|
|
||||||
for !in.eof() {
|
|
||||||
// Skip over spaces. Count newlines so we can give the parser
|
|
||||||
// information about where top-level blank lines are,
|
|
||||||
// for top-level comment assignment.
|
|
||||||
c := in.peekRune()
|
|
||||||
if c == ' ' || c == '\t' || c == '\r' {
|
|
||||||
in.readRune()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment runs to end of line.
|
|
||||||
if in.peekPrefix("//") {
|
|
||||||
in.startToken(sym)
|
|
||||||
|
|
||||||
// Is this comment the only thing on its line?
|
|
||||||
// Find the last \n before this // and see if it's all
|
|
||||||
// spaces from there to here.
|
|
||||||
i := bytes.LastIndex(in.complete[:in.pos.Byte], []byte("\n"))
|
|
||||||
suffix := len(bytes.TrimSpace(in.complete[i+1:in.pos.Byte])) > 0
|
|
||||||
in.readRune()
|
|
||||||
in.readRune()
|
|
||||||
|
|
||||||
// Consume comment.
|
|
||||||
for len(in.remaining) > 0 && in.readRune() != '\n' {
|
|
||||||
}
|
|
||||||
in.endToken(sym)
|
|
||||||
|
|
||||||
sym.text = strings.TrimRight(sym.text, "\n")
|
|
||||||
in.lastToken = "comment"
|
|
||||||
|
|
||||||
// If we are at top level (not in a statement), hand the comment to
|
|
||||||
// the parser as a _COMMENT token. The grammar is written
|
|
||||||
// to handle top-level comments itself.
|
|
||||||
if !suffix {
|
|
||||||
// Not in a statement. Tell parser about top-level comment.
|
|
||||||
return _COMMENT
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, save comment for later attachment to syntax tree.
|
|
||||||
if countNL > 1 {
|
|
||||||
in.comments = append(in.comments, Comment{sym.pos, "", false})
|
|
||||||
}
|
|
||||||
in.comments = append(in.comments, Comment{sym.pos, sym.text, suffix})
|
|
||||||
countNL = 1
|
|
||||||
return _EOL
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.peekPrefix("/*") {
|
|
||||||
in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found non-space non-comment.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found the beginning of the next token.
|
|
||||||
in.startToken(sym)
|
|
||||||
defer in.endToken(sym)
|
|
||||||
|
|
||||||
// End of file.
|
|
||||||
if in.eof() {
|
|
||||||
in.lastToken = "EOF"
|
|
||||||
return _EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
// Punctuation tokens.
|
|
||||||
switch c := in.peekRune(); c {
|
|
||||||
case '\n':
|
|
||||||
in.readRune()
|
|
||||||
return c
|
|
||||||
|
|
||||||
case '(':
|
|
||||||
in.readRune()
|
|
||||||
return c
|
|
||||||
|
|
||||||
case ')':
|
|
||||||
in.readRune()
|
|
||||||
return c
|
|
||||||
|
|
||||||
case '"', '`': // quoted string
|
|
||||||
quote := c
|
|
||||||
in.readRune()
|
|
||||||
for {
|
|
||||||
if in.eof() {
|
|
||||||
in.pos = sym.pos
|
|
||||||
in.Error("unexpected EOF in string")
|
|
||||||
}
|
|
||||||
if in.peekRune() == '\n' {
|
|
||||||
in.Error("unexpected newline in string")
|
|
||||||
}
|
|
||||||
c := in.readRune()
|
|
||||||
if c == quote {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c == '\\' && quote != '`' {
|
|
||||||
if in.eof() {
|
|
||||||
in.pos = sym.pos
|
|
||||||
in.Error("unexpected EOF in string")
|
|
||||||
}
|
|
||||||
in.readRune()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in.endToken(sym)
|
|
||||||
return _STRING
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checked all punctuation. Must be identifier token.
|
|
||||||
if c := in.peekRune(); !isIdent(c) {
|
|
||||||
in.Error(fmt.Sprintf("unexpected input character %#q", c))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan over identifier.
|
|
||||||
for isIdent(in.peekRune()) {
|
|
||||||
if in.peekPrefix("//") {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if in.peekPrefix("/*") {
|
|
||||||
in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
|
|
||||||
}
|
|
||||||
in.readRune()
|
|
||||||
}
|
|
||||||
return _IDENT
|
|
||||||
}
|
|
||||||
|
|
||||||
// isIdent reports whether c is an identifier rune.
|
|
||||||
// We treat nearly all runes as identifier runes.
|
|
||||||
func isIdent(c int) bool {
|
|
||||||
return c != 0 && !unicode.IsSpace(rune(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment assignment.
|
|
||||||
// We build two lists of all subexpressions, preorder and postorder.
|
|
||||||
// The preorder list is ordered by start location, with outer expressions first.
|
|
||||||
// The postorder list is ordered by end location, with outer expressions last.
|
|
||||||
// We use the preorder list to assign each whole-line comment to the syntax
|
|
||||||
// immediately following it, and we use the postorder list to assign each
|
|
||||||
// end-of-line comment to the syntax immediately preceding it.
|
|
||||||
|
|
||||||
// order walks the expression adding it and its subexpressions to the
|
|
||||||
// preorder and postorder lists.
|
|
||||||
func (in *input) order(x Expr) {
|
|
||||||
if x != nil {
|
|
||||||
in.pre = append(in.pre, x)
|
|
||||||
}
|
|
||||||
switch x := x.(type) {
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("order: unexpected type %T", x))
|
|
||||||
case nil:
|
|
||||||
// nothing
|
|
||||||
case *LParen, *RParen:
|
|
||||||
// nothing
|
|
||||||
case *CommentBlock:
|
|
||||||
// nothing
|
|
||||||
case *Line:
|
|
||||||
// nothing
|
|
||||||
case *FileSyntax:
|
|
||||||
for _, stmt := range x.Stmt {
|
|
||||||
in.order(stmt)
|
|
||||||
}
|
|
||||||
case *LineBlock:
|
|
||||||
in.order(&x.LParen)
|
|
||||||
for _, l := range x.Line {
|
|
||||||
in.order(l)
|
|
||||||
}
|
|
||||||
in.order(&x.RParen)
|
|
||||||
}
|
|
||||||
if x != nil {
|
|
||||||
in.post = append(in.post, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// assignComments attaches comments to nearby syntax.
|
|
||||||
func (in *input) assignComments() {
|
|
||||||
const debug = false
|
|
||||||
|
|
||||||
// Generate preorder and postorder lists.
|
|
||||||
in.order(in.file)
|
|
||||||
|
|
||||||
// Split into whole-line comments and suffix comments.
|
|
||||||
var line, suffix []Comment
|
|
||||||
for _, com := range in.comments {
|
|
||||||
if com.Suffix {
|
|
||||||
suffix = append(suffix, com)
|
|
||||||
} else {
|
|
||||||
line = append(line, com)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if debug {
|
|
||||||
for _, c := range line {
|
|
||||||
fmt.Fprintf(os.Stderr, "LINE %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign line comments to syntax immediately following.
|
|
||||||
for _, x := range in.pre {
|
|
||||||
start, _ := x.Span()
|
|
||||||
if debug {
|
|
||||||
fmt.Printf("pre %T :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte)
|
|
||||||
}
|
|
||||||
xcom := x.Comment()
|
|
||||||
for len(line) > 0 && start.Byte >= line[0].Start.Byte {
|
|
||||||
if debug {
|
|
||||||
fmt.Fprintf(os.Stderr, "ASSIGN LINE %q #%d\n", line[0].Token, line[0].Start.Byte)
|
|
||||||
}
|
|
||||||
xcom.Before = append(xcom.Before, line[0])
|
|
||||||
line = line[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remaining line comments go at end of file.
|
|
||||||
in.file.After = append(in.file.After, line...)
|
|
||||||
|
|
||||||
if debug {
|
|
||||||
for _, c := range suffix {
|
|
||||||
fmt.Fprintf(os.Stderr, "SUFFIX %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign suffix comments to syntax immediately before.
|
|
||||||
for i := len(in.post) - 1; i >= 0; i-- {
|
|
||||||
x := in.post[i]
|
|
||||||
|
|
||||||
start, end := x.Span()
|
|
||||||
if debug {
|
|
||||||
fmt.Printf("post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not assign suffix comments to end of line block or whole file.
|
|
||||||
// Instead assign them to the last element inside.
|
|
||||||
switch x.(type) {
|
|
||||||
case *FileSyntax:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not assign suffix comments to something that starts
|
|
||||||
// on an earlier line, so that in
|
|
||||||
//
|
|
||||||
// x ( y
|
|
||||||
// z ) // comment
|
|
||||||
//
|
|
||||||
// we assign the comment to z and not to x ( ... ).
|
|
||||||
if start.Line != end.Line {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
xcom := x.Comment()
|
|
||||||
for len(suffix) > 0 && end.Byte <= suffix[len(suffix)-1].Start.Byte {
|
|
||||||
if debug {
|
|
||||||
fmt.Fprintf(os.Stderr, "ASSIGN SUFFIX %q #%d\n", suffix[len(suffix)-1].Token, suffix[len(suffix)-1].Start.Byte)
|
|
||||||
}
|
|
||||||
xcom.Suffix = append(xcom.Suffix, suffix[len(suffix)-1])
|
|
||||||
suffix = suffix[:len(suffix)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We assigned suffix comments in reverse.
|
|
||||||
// If multiple suffix comments were appended to the same
|
|
||||||
// expression node, they are now in reverse. Fix that.
|
|
||||||
for _, x := range in.post {
|
|
||||||
reverseComments(x.Comment().Suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remaining suffix comments go at beginning of file.
|
|
||||||
in.file.Before = append(in.file.Before, suffix...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// reverseComments reverses the []Comment list.
|
|
||||||
func reverseComments(list []Comment) {
|
|
||||||
for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
|
|
||||||
list[i], list[j] = list[j], list[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *input) parseFile() {
|
|
||||||
in.file = new(FileSyntax)
|
|
||||||
var sym symType
|
|
||||||
var cb *CommentBlock
|
|
||||||
for {
|
|
||||||
tok := in.lex(&sym)
|
|
||||||
switch tok {
|
|
||||||
case '\n':
|
|
||||||
if cb != nil {
|
|
||||||
in.file.Stmt = append(in.file.Stmt, cb)
|
|
||||||
cb = nil
|
|
||||||
}
|
|
||||||
case _COMMENT:
|
|
||||||
if cb == nil {
|
|
||||||
cb = &CommentBlock{Start: sym.pos}
|
|
||||||
}
|
|
||||||
com := cb.Comment()
|
|
||||||
com.Before = append(com.Before, Comment{Start: sym.pos, Token: sym.text})
|
|
||||||
case _EOF:
|
|
||||||
if cb != nil {
|
|
||||||
in.file.Stmt = append(in.file.Stmt, cb)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
in.parseStmt(&sym)
|
|
||||||
if cb != nil {
|
|
||||||
in.file.Stmt[len(in.file.Stmt)-1].Comment().Before = cb.Before
|
|
||||||
cb = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *input) parseStmt(sym *symType) {
|
|
||||||
start := sym.pos
|
|
||||||
end := sym.endPos
|
|
||||||
token := []string{sym.text}
|
|
||||||
for {
|
|
||||||
tok := in.lex(sym)
|
|
||||||
switch tok {
|
|
||||||
case '\n', _EOF, _EOL:
|
|
||||||
in.file.Stmt = append(in.file.Stmt, &Line{
|
|
||||||
Start: start,
|
|
||||||
Token: token,
|
|
||||||
End: end,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
case '(':
|
|
||||||
in.file.Stmt = append(in.file.Stmt, in.parseLineBlock(start, token, sym))
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
token = append(token, sym.text)
|
|
||||||
end = sym.endPos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *input) parseLineBlock(start Position, token []string, sym *symType) *LineBlock {
|
|
||||||
x := &LineBlock{
|
|
||||||
Start: start,
|
|
||||||
Token: token,
|
|
||||||
LParen: LParen{Pos: sym.pos},
|
|
||||||
}
|
|
||||||
var comments []Comment
|
|
||||||
for {
|
|
||||||
tok := in.lex(sym)
|
|
||||||
switch tok {
|
|
||||||
case _EOL:
|
|
||||||
// ignore
|
|
||||||
case '\n':
|
|
||||||
if len(comments) == 0 && len(x.Line) > 0 || len(comments) > 0 && comments[len(comments)-1].Token != "" {
|
|
||||||
comments = append(comments, Comment{})
|
|
||||||
}
|
|
||||||
case _COMMENT:
|
|
||||||
comments = append(comments, Comment{Start: sym.pos, Token: sym.text})
|
|
||||||
case _EOF:
|
|
||||||
in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune))
|
|
||||||
case ')':
|
|
||||||
x.RParen.Before = comments
|
|
||||||
x.RParen.Pos = sym.pos
|
|
||||||
tok = in.lex(sym)
|
|
||||||
if tok != '\n' && tok != _EOF && tok != _EOL {
|
|
||||||
in.Error("syntax error (expected newline after closing paren)")
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
default:
|
|
||||||
l := in.parseLine(sym)
|
|
||||||
x.Line = append(x.Line, l)
|
|
||||||
l.Comment().Before = comments
|
|
||||||
comments = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *input) parseLine(sym *symType) *Line {
|
|
||||||
start := sym.pos
|
|
||||||
end := sym.endPos
|
|
||||||
token := []string{sym.text}
|
|
||||||
for {
|
|
||||||
tok := in.lex(sym)
|
|
||||||
switch tok {
|
|
||||||
case '\n', _EOF, _EOL:
|
|
||||||
return &Line{
|
|
||||||
Start: start,
|
|
||||||
Token: token,
|
|
||||||
End: end,
|
|
||||||
InBlock: true,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
token = append(token, sym.text)
|
|
||||||
end = sym.endPos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
_EOF = -(1 + iota)
|
|
||||||
_EOL
|
|
||||||
_IDENT
|
|
||||||
_STRING
|
|
||||||
_COMMENT
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
slashSlash = []byte("//")
|
|
||||||
moduleStr = []byte("module")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ModulePath returns the module path from the gomod file text.
|
|
||||||
// If it cannot find a module path, it returns an empty string.
|
|
||||||
// It is tolerant of unrelated problems in the go.mod file.
|
|
||||||
func ModulePath(mod []byte) string {
|
|
||||||
for len(mod) > 0 {
|
|
||||||
line := mod
|
|
||||||
mod = nil
|
|
||||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
|
||||||
line, mod = line[:i], line[i+1:]
|
|
||||||
}
|
|
||||||
if i := bytes.Index(line, slashSlash); i >= 0 {
|
|
||||||
line = line[:i]
|
|
||||||
}
|
|
||||||
line = bytes.TrimSpace(line)
|
|
||||||
if !bytes.HasPrefix(line, moduleStr) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
line = line[len(moduleStr):]
|
|
||||||
n := len(line)
|
|
||||||
line = bytes.TrimSpace(line)
|
|
||||||
if len(line) == n || len(line) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if line[0] == '"' || line[0] == '`' {
|
|
||||||
p, err := strconv.Unquote(string(line))
|
|
||||||
if err != nil {
|
|
||||||
return "" // malformed quoted string or multiline module path
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(line)
|
|
||||||
}
|
|
||||||
return "" // missing module path
|
|
||||||
}
|
|
724
vendor/github.com/rogpeppe/go-internal/modfile/rule.go
generated
vendored
724
vendor/github.com/rogpeppe/go-internal/modfile/rule.go
generated
vendored
@ -1,724 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package modfile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/rogpeppe/go-internal/module"
|
|
||||||
"github.com/rogpeppe/go-internal/semver"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A File is the parsed, interpreted form of a go.mod file.
|
|
||||||
type File struct {
|
|
||||||
Module *Module
|
|
||||||
Go *Go
|
|
||||||
Require []*Require
|
|
||||||
Exclude []*Exclude
|
|
||||||
Replace []*Replace
|
|
||||||
|
|
||||||
Syntax *FileSyntax
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Module is the module statement.
|
|
||||||
type Module struct {
|
|
||||||
Mod module.Version
|
|
||||||
Syntax *Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Go is the go statement.
|
|
||||||
type Go struct {
|
|
||||||
Version string // "1.23"
|
|
||||||
Syntax *Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Require is a single require statement.
|
|
||||||
type Require struct {
|
|
||||||
Mod module.Version
|
|
||||||
Indirect bool // has "// indirect" comment
|
|
||||||
Syntax *Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Exclude is a single exclude statement.
|
|
||||||
type Exclude struct {
|
|
||||||
Mod module.Version
|
|
||||||
Syntax *Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Replace is a single replace statement.
|
|
||||||
type Replace struct {
|
|
||||||
Old module.Version
|
|
||||||
New module.Version
|
|
||||||
Syntax *Line
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddModuleStmt(path string) error {
|
|
||||||
if f.Syntax == nil {
|
|
||||||
f.Syntax = new(FileSyntax)
|
|
||||||
}
|
|
||||||
if f.Module == nil {
|
|
||||||
f.Module = &Module{
|
|
||||||
Mod: module.Version{Path: path},
|
|
||||||
Syntax: f.Syntax.addLine(nil, "module", AutoQuote(path)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f.Module.Mod.Path = path
|
|
||||||
f.Syntax.updateLine(f.Module.Syntax, "module", AutoQuote(path))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddComment(text string) {
|
|
||||||
if f.Syntax == nil {
|
|
||||||
f.Syntax = new(FileSyntax)
|
|
||||||
}
|
|
||||||
f.Syntax.Stmt = append(f.Syntax.Stmt, &CommentBlock{
|
|
||||||
Comments: Comments{
|
|
||||||
Before: []Comment{
|
|
||||||
{
|
|
||||||
Token: text,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersionFixer func(path, version string) (string, error)
|
|
||||||
|
|
||||||
// Parse parses the data, reported in errors as being from file,
|
|
||||||
// into a File struct. It applies fix, if non-nil, to canonicalize all module versions found.
|
|
||||||
func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
|
|
||||||
return parseToFile(file, data, fix, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseLax is like Parse but ignores unknown statements.
|
|
||||||
// It is used when parsing go.mod files other than the main module,
|
|
||||||
// under the theory that most statement types we add in the future will
|
|
||||||
// only apply in the main module, like exclude and replace,
|
|
||||||
// and so we get better gradual deployments if old go commands
|
|
||||||
// simply ignore those statements when found in go.mod files
|
|
||||||
// in dependencies.
|
|
||||||
func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) {
|
|
||||||
return parseToFile(file, data, fix, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) {
|
|
||||||
fs, err := parse(file, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f := &File{
|
|
||||||
Syntax: fs,
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs bytes.Buffer
|
|
||||||
for _, x := range fs.Stmt {
|
|
||||||
switch x := x.(type) {
|
|
||||||
case *Line:
|
|
||||||
f.add(&errs, x, x.Token[0], x.Token[1:], fix, strict)
|
|
||||||
|
|
||||||
case *LineBlock:
|
|
||||||
if len(x.Token) > 1 {
|
|
||||||
if strict {
|
|
||||||
fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch x.Token[0] {
|
|
||||||
default:
|
|
||||||
if strict {
|
|
||||||
fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case "module", "require", "exclude", "replace":
|
|
||||||
for _, l := range x.Line {
|
|
||||||
f.add(&errs, l, x.Token[0], l.Token, fix, strict)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if errs.Len() > 0 {
|
|
||||||
return nil, errors.New(strings.TrimRight(errs.String(), "\n"))
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
|
|
||||||
|
|
||||||
func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
|
|
||||||
// If strict is false, this module is a dependency.
|
|
||||||
// We ignore all unknown directives as well as main-module-only
|
|
||||||
// directives like replace and exclude. It will work better for
|
|
||||||
// forward compatibility if we can depend on modules that have unknown
|
|
||||||
// statements (presumed relevant only when acting as the main module)
|
|
||||||
// and simply ignore those statements.
|
|
||||||
if !strict {
|
|
||||||
switch verb {
|
|
||||||
case "module", "require", "go":
|
|
||||||
// want these even for dependency go.mods
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch verb {
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(errs, "%s:%d: unknown directive: %s\n", f.Syntax.Name, line.Start.Line, verb)
|
|
||||||
|
|
||||||
case "go":
|
|
||||||
if f.Go != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(args) != 1 || !goVersionRE.MatchString(args[0]) {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.Go = &Go{Syntax: line}
|
|
||||||
f.Go.Version = args[0]
|
|
||||||
case "module":
|
|
||||||
if f.Module != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: repeated module statement\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.Module = &Module{Syntax: line}
|
|
||||||
if len(args) != 1 {
|
|
||||||
|
|
||||||
fmt.Fprintf(errs, "%s:%d: usage: module module/path [version]\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s, err := parseString(&args[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.Module.Mod = module.Version{Path: s}
|
|
||||||
case "require", "exclude":
|
|
||||||
if len(args) != 2 {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3\n", f.Syntax.Name, line.Start.Line, verb)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s, err := parseString(&args[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
old := args[1]
|
|
||||||
v, err := parseVersion(s, &args[1], fix)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid module version %q: %v\n", f.Syntax.Name, line.Start.Line, old, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pathMajor, err := modulePathMajor(s)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !module.MatchPathMajor(v, pathMajor) {
|
|
||||||
if pathMajor == "" {
|
|
||||||
pathMajor = "v0 or v1"
|
|
||||||
}
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if verb == "require" {
|
|
||||||
f.Require = append(f.Require, &Require{
|
|
||||||
Mod: module.Version{Path: s, Version: v},
|
|
||||||
Syntax: line,
|
|
||||||
Indirect: isIndirect(line),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
f.Exclude = append(f.Exclude, &Exclude{
|
|
||||||
Mod: module.Version{Path: s, Version: v},
|
|
||||||
Syntax: line,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case "replace":
|
|
||||||
arrow := 2
|
|
||||||
if len(args) >= 2 && args[1] == "=>" {
|
|
||||||
arrow = 1
|
|
||||||
}
|
|
||||||
if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory\n", f.Syntax.Name, line.Start.Line, verb, verb)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s, err := parseString(&args[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pathMajor, err := modulePathMajor(s)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var v string
|
|
||||||
if arrow == 2 {
|
|
||||||
old := args[1]
|
|
||||||
v, err = parseVersion(s, &args[1], fix)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !module.MatchPathMajor(v, pathMajor) {
|
|
||||||
if pathMajor == "" {
|
|
||||||
pathMajor = "v0 or v1"
|
|
||||||
}
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ns, err := parseString(&args[arrow+1])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nv := ""
|
|
||||||
if len(args) == arrow+2 {
|
|
||||||
if !IsDirectoryPath(ns) {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if filepath.Separator == '/' && strings.Contains(ns, `\`) {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)\n", f.Syntax.Name, line.Start.Line)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(args) == arrow+3 {
|
|
||||||
old := args[arrow+1]
|
|
||||||
nv, err = parseVersion(ns, &args[arrow+2], fix)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if IsDirectoryPath(ns) {
|
|
||||||
fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version\n", f.Syntax.Name, line.Start.Line, ns)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Replace = append(f.Replace, &Replace{
|
|
||||||
Old: module.Version{Path: s, Version: v},
|
|
||||||
New: module.Version{Path: ns, Version: nv},
|
|
||||||
Syntax: line,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isIndirect reports whether line has a "// indirect" comment,
|
|
||||||
// meaning it is in go.mod only for its effect on indirect dependencies,
|
|
||||||
// so that it can be dropped entirely once the effective version of the
|
|
||||||
// indirect dependency reaches the given minimum version.
|
|
||||||
func isIndirect(line *Line) bool {
|
|
||||||
if len(line.Suffix) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
f := strings.Fields(line.Suffix[0].Token)
|
|
||||||
return (len(f) == 2 && f[1] == "indirect" || len(f) > 2 && f[1] == "indirect;") && f[0] == "//"
|
|
||||||
}
|
|
||||||
|
|
||||||
// setIndirect sets line to have (or not have) a "// indirect" comment.
|
|
||||||
func setIndirect(line *Line, indirect bool) {
|
|
||||||
if isIndirect(line) == indirect {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if indirect {
|
|
||||||
// Adding comment.
|
|
||||||
if len(line.Suffix) == 0 {
|
|
||||||
// New comment.
|
|
||||||
line.Suffix = []Comment{{Token: "// indirect", Suffix: true}}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Insert at beginning of existing comment.
|
|
||||||
com := &line.Suffix[0]
|
|
||||||
space := " "
|
|
||||||
if len(com.Token) > 2 && com.Token[2] == ' ' || com.Token[2] == '\t' {
|
|
||||||
space = ""
|
|
||||||
}
|
|
||||||
com.Token = "// indirect;" + space + com.Token[2:]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing comment.
|
|
||||||
f := strings.Fields(line.Suffix[0].Token)
|
|
||||||
if len(f) == 2 {
|
|
||||||
// Remove whole comment.
|
|
||||||
line.Suffix = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove comment prefix.
|
|
||||||
com := &line.Suffix[0]
|
|
||||||
i := strings.Index(com.Token, "indirect;")
|
|
||||||
com.Token = "//" + com.Token[i+len("indirect;"):]
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDirectoryPath reports whether the given path should be interpreted
|
|
||||||
// as a directory path. Just like on the go command line, relative paths
|
|
||||||
// and rooted paths are directory paths; the rest are module paths.
|
|
||||||
func IsDirectoryPath(ns string) bool {
|
|
||||||
// Because go.mod files can move from one system to another,
|
|
||||||
// we check all known path syntaxes, both Unix and Windows.
|
|
||||||
return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") ||
|
|
||||||
strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) ||
|
|
||||||
len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':'
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustQuote reports whether s must be quoted in order to appear as
|
|
||||||
// a single token in a go.mod line.
|
|
||||||
func MustQuote(s string) bool {
|
|
||||||
for _, r := range s {
|
|
||||||
if !unicode.IsPrint(r) || r == ' ' || r == '"' || r == '\'' || r == '`' {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s == "" || strings.Contains(s, "//") || strings.Contains(s, "/*")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AutoQuote returns s or, if quoting is required for s to appear in a go.mod,
|
|
||||||
// the quotation of s.
|
|
||||||
func AutoQuote(s string) string {
|
|
||||||
if MustQuote(s) {
|
|
||||||
return strconv.Quote(s)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseString(s *string) (string, error) {
|
|
||||||
t := *s
|
|
||||||
if strings.HasPrefix(t, `"`) {
|
|
||||||
var err error
|
|
||||||
if t, err = strconv.Unquote(t); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
} else if strings.ContainsAny(t, "\"'`") {
|
|
||||||
// Other quotes are reserved both for possible future expansion
|
|
||||||
// and to avoid confusion. For example if someone types 'x'
|
|
||||||
// we want that to be a syntax error and not a literal x in literal quotation marks.
|
|
||||||
return "", fmt.Errorf("unquoted string cannot contain quote")
|
|
||||||
}
|
|
||||||
*s = AutoQuote(t)
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseVersion(path string, s *string, fix VersionFixer) (string, error) {
|
|
||||||
t, err := parseString(s)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if fix != nil {
|
|
||||||
var err error
|
|
||||||
t, err = fix(path, t)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v := module.CanonicalVersion(t); v != "" {
|
|
||||||
*s = v
|
|
||||||
return *s, nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("version must be of the form v1.2.3")
|
|
||||||
}
|
|
||||||
|
|
||||||
func modulePathMajor(path string) (string, error) {
|
|
||||||
_, major, ok := module.SplitPathVersion(path)
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("invalid module path")
|
|
||||||
}
|
|
||||||
return major, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) Format() ([]byte, error) {
|
|
||||||
return Format(f.Syntax), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup cleans up the file f after any edit operations.
|
|
||||||
// To avoid quadratic behavior, modifications like DropRequire
|
|
||||||
// clear the entry but do not remove it from the slice.
|
|
||||||
// Cleanup cleans out all the cleared entries.
|
|
||||||
func (f *File) Cleanup() {
|
|
||||||
w := 0
|
|
||||||
for _, r := range f.Require {
|
|
||||||
if r.Mod.Path != "" {
|
|
||||||
f.Require[w] = r
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Require = f.Require[:w]
|
|
||||||
|
|
||||||
w = 0
|
|
||||||
for _, x := range f.Exclude {
|
|
||||||
if x.Mod.Path != "" {
|
|
||||||
f.Exclude[w] = x
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Exclude = f.Exclude[:w]
|
|
||||||
|
|
||||||
w = 0
|
|
||||||
for _, r := range f.Replace {
|
|
||||||
if r.Old.Path != "" {
|
|
||||||
f.Replace[w] = r
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Replace = f.Replace[:w]
|
|
||||||
|
|
||||||
f.Syntax.Cleanup()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddRequire(path, vers string) error {
|
|
||||||
need := true
|
|
||||||
for _, r := range f.Require {
|
|
||||||
if r.Mod.Path == path {
|
|
||||||
if need {
|
|
||||||
r.Mod.Version = vers
|
|
||||||
f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers)
|
|
||||||
need = false
|
|
||||||
} else {
|
|
||||||
f.Syntax.removeLine(r.Syntax)
|
|
||||||
*r = Require{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if need {
|
|
||||||
f.AddNewRequire(path, vers, false)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddNewRequire(path, vers string, indirect bool) {
|
|
||||||
line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers)
|
|
||||||
setIndirect(line, indirect)
|
|
||||||
f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) SetRequire(req []*Require) {
|
|
||||||
need := make(map[string]string)
|
|
||||||
indirect := make(map[string]bool)
|
|
||||||
for _, r := range req {
|
|
||||||
need[r.Mod.Path] = r.Mod.Version
|
|
||||||
indirect[r.Mod.Path] = r.Indirect
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range f.Require {
|
|
||||||
if v, ok := need[r.Mod.Path]; ok {
|
|
||||||
r.Mod.Version = v
|
|
||||||
r.Indirect = indirect[r.Mod.Path]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var newStmts []Expr
|
|
||||||
for _, stmt := range f.Syntax.Stmt {
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *LineBlock:
|
|
||||||
if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
|
|
||||||
var newLines []*Line
|
|
||||||
for _, line := range stmt.Line {
|
|
||||||
if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" {
|
|
||||||
line.Token[1] = need[p]
|
|
||||||
delete(need, p)
|
|
||||||
setIndirect(line, indirect[p])
|
|
||||||
newLines = append(newLines, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(newLines) == 0 {
|
|
||||||
continue // drop stmt
|
|
||||||
}
|
|
||||||
stmt.Line = newLines
|
|
||||||
}
|
|
||||||
|
|
||||||
case *Line:
|
|
||||||
if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
|
|
||||||
if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" {
|
|
||||||
stmt.Token[2] = need[p]
|
|
||||||
delete(need, p)
|
|
||||||
setIndirect(stmt, indirect[p])
|
|
||||||
} else {
|
|
||||||
continue // drop stmt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newStmts = append(newStmts, stmt)
|
|
||||||
}
|
|
||||||
f.Syntax.Stmt = newStmts
|
|
||||||
|
|
||||||
for path, vers := range need {
|
|
||||||
f.AddNewRequire(path, vers, indirect[path])
|
|
||||||
}
|
|
||||||
f.SortBlocks()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) DropRequire(path string) error {
|
|
||||||
for _, r := range f.Require {
|
|
||||||
if r.Mod.Path == path {
|
|
||||||
f.Syntax.removeLine(r.Syntax)
|
|
||||||
*r = Require{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddExclude(path, vers string) error {
|
|
||||||
var hint *Line
|
|
||||||
for _, x := range f.Exclude {
|
|
||||||
if x.Mod.Path == path && x.Mod.Version == vers {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if x.Mod.Path == path {
|
|
||||||
hint = x.Syntax
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Exclude = append(f.Exclude, &Exclude{Mod: module.Version{Path: path, Version: vers}, Syntax: f.Syntax.addLine(hint, "exclude", AutoQuote(path), vers)})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) DropExclude(path, vers string) error {
|
|
||||||
for _, x := range f.Exclude {
|
|
||||||
if x.Mod.Path == path && x.Mod.Version == vers {
|
|
||||||
f.Syntax.removeLine(x.Syntax)
|
|
||||||
*x = Exclude{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
|
||||||
need := true
|
|
||||||
old := module.Version{Path: oldPath, Version: oldVers}
|
|
||||||
new := module.Version{Path: newPath, Version: newVers}
|
|
||||||
tokens := []string{"replace", AutoQuote(oldPath)}
|
|
||||||
if oldVers != "" {
|
|
||||||
tokens = append(tokens, oldVers)
|
|
||||||
}
|
|
||||||
tokens = append(tokens, "=>", AutoQuote(newPath))
|
|
||||||
if newVers != "" {
|
|
||||||
tokens = append(tokens, newVers)
|
|
||||||
}
|
|
||||||
|
|
||||||
var hint *Line
|
|
||||||
for _, r := range f.Replace {
|
|
||||||
if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
|
|
||||||
if need {
|
|
||||||
// Found replacement for old; update to use new.
|
|
||||||
r.New = new
|
|
||||||
f.Syntax.updateLine(r.Syntax, tokens...)
|
|
||||||
need = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Already added; delete other replacements for same.
|
|
||||||
f.Syntax.removeLine(r.Syntax)
|
|
||||||
*r = Replace{}
|
|
||||||
}
|
|
||||||
if r.Old.Path == oldPath {
|
|
||||||
hint = r.Syntax
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if need {
|
|
||||||
f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) DropReplace(oldPath, oldVers string) error {
|
|
||||||
for _, r := range f.Replace {
|
|
||||||
if r.Old.Path == oldPath && r.Old.Version == oldVers {
|
|
||||||
f.Syntax.removeLine(r.Syntax)
|
|
||||||
*r = Replace{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) SortBlocks() {
|
|
||||||
f.removeDups() // otherwise sorting is unsafe
|
|
||||||
|
|
||||||
for _, stmt := range f.Syntax.Stmt {
|
|
||||||
block, ok := stmt.(*LineBlock)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sort.Slice(block.Line, func(i, j int) bool {
|
|
||||||
li := block.Line[i]
|
|
||||||
lj := block.Line[j]
|
|
||||||
for k := 0; k < len(li.Token) && k < len(lj.Token); k++ {
|
|
||||||
if li.Token[k] != lj.Token[k] {
|
|
||||||
return li.Token[k] < lj.Token[k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(li.Token) < len(lj.Token)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) removeDups() {
|
|
||||||
have := make(map[module.Version]bool)
|
|
||||||
kill := make(map[*Line]bool)
|
|
||||||
for _, x := range f.Exclude {
|
|
||||||
if have[x.Mod] {
|
|
||||||
kill[x.Syntax] = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
have[x.Mod] = true
|
|
||||||
}
|
|
||||||
var excl []*Exclude
|
|
||||||
for _, x := range f.Exclude {
|
|
||||||
if !kill[x.Syntax] {
|
|
||||||
excl = append(excl, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Exclude = excl
|
|
||||||
|
|
||||||
have = make(map[module.Version]bool)
|
|
||||||
// Later replacements take priority over earlier ones.
|
|
||||||
for i := len(f.Replace) - 1; i >= 0; i-- {
|
|
||||||
x := f.Replace[i]
|
|
||||||
if have[x.Old] {
|
|
||||||
kill[x.Syntax] = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
have[x.Old] = true
|
|
||||||
}
|
|
||||||
var repl []*Replace
|
|
||||||
for _, x := range f.Replace {
|
|
||||||
if !kill[x.Syntax] {
|
|
||||||
repl = append(repl, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Replace = repl
|
|
||||||
|
|
||||||
var stmts []Expr
|
|
||||||
for _, stmt := range f.Syntax.Stmt {
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *Line:
|
|
||||||
if kill[stmt] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case *LineBlock:
|
|
||||||
var lines []*Line
|
|
||||||
for _, line := range stmt.Line {
|
|
||||||
if !kill[line] {
|
|
||||||
lines = append(lines, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stmt.Line = lines
|
|
||||||
if len(lines) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stmts = append(stmts, stmt)
|
|
||||||
}
|
|
||||||
f.Syntax.Stmt = stmts
|
|
||||||
}
|
|
540
vendor/github.com/rogpeppe/go-internal/module/module.go
generated
vendored
540
vendor/github.com/rogpeppe/go-internal/module/module.go
generated
vendored
@ -1,540 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package module defines the module.Version type
|
|
||||||
// along with support code.
|
|
||||||
package module
|
|
||||||
|
|
||||||
// IMPORTANT NOTE
|
|
||||||
//
|
|
||||||
// This file essentially defines the set of valid import paths for the go command.
|
|
||||||
// There are many subtle considerations, including Unicode ambiguity,
|
|
||||||
// security, network, and file system representations.
|
|
||||||
//
|
|
||||||
// This file also defines the set of valid module path and version combinations,
|
|
||||||
// another topic with many subtle considerations.
|
|
||||||
//
|
|
||||||
// Changes to the semantics in this file require approval from rsc.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"github.com/rogpeppe/go-internal/semver"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Version is defined by a module path and version pair.
|
|
||||||
type Version struct {
|
|
||||||
Path string
|
|
||||||
|
|
||||||
// Version is usually a semantic version in canonical form.
|
|
||||||
// There are two exceptions to this general rule.
|
|
||||||
// First, the top-level target of a build has no specific version
|
|
||||||
// and uses Version = "".
|
|
||||||
// Second, during MVS calculations the version "none" is used
|
|
||||||
// to represent the decision to take no version of a given module.
|
|
||||||
Version string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check checks that a given module path, version pair is valid.
|
|
||||||
// In addition to the path being a valid module path
|
|
||||||
// and the version being a valid semantic version,
|
|
||||||
// the two must correspond.
|
|
||||||
// For example, the path "yaml/v2" only corresponds to
|
|
||||||
// semantic versions beginning with "v2.".
|
|
||||||
func Check(path, version string) error {
|
|
||||||
if err := CheckPath(path); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !semver.IsValid(version) {
|
|
||||||
return fmt.Errorf("malformed semantic version %v", version)
|
|
||||||
}
|
|
||||||
_, pathMajor, _ := SplitPathVersion(path)
|
|
||||||
if !MatchPathMajor(version, pathMajor) {
|
|
||||||
if pathMajor == "" {
|
|
||||||
pathMajor = "v0 or v1"
|
|
||||||
}
|
|
||||||
if pathMajor[0] == '.' { // .v1
|
|
||||||
pathMajor = pathMajor[1:]
|
|
||||||
}
|
|
||||||
return fmt.Errorf("mismatched module path %v and version %v (want %v)", path, version, pathMajor)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// firstPathOK reports whether r can appear in the first element of a module path.
|
|
||||||
// The first element of the path must be an LDH domain name, at least for now.
|
|
||||||
// To avoid case ambiguity, the domain name must be entirely lower case.
|
|
||||||
func firstPathOK(r rune) bool {
|
|
||||||
return r == '-' || r == '.' ||
|
|
||||||
'0' <= r && r <= '9' ||
|
|
||||||
'a' <= r && r <= 'z'
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathOK reports whether r can appear in an import path element.
|
|
||||||
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~.
|
|
||||||
// This matches what "go get" has historically recognized in import paths.
|
|
||||||
// TODO(rsc): We would like to allow Unicode letters, but that requires additional
|
|
||||||
// care in the safe encoding (see note below).
|
|
||||||
func pathOK(r rune) bool {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
|
|
||||||
'0' <= r && r <= '9' ||
|
|
||||||
'A' <= r && r <= 'Z' ||
|
|
||||||
'a' <= r && r <= 'z'
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// fileNameOK reports whether r can appear in a file name.
|
|
||||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
|
||||||
// If we expand the set of allowed characters here, we have to
|
|
||||||
// work harder at detecting potential case-folding and normalization collisions.
|
|
||||||
// See note about "safe encoding" below.
|
|
||||||
func fileNameOK(r rune) bool {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
// Entire set of ASCII punctuation, from which we remove characters:
|
|
||||||
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
|
||||||
// We disallow some shell special characters: " ' * < > ? ` |
|
|
||||||
// (Note that some of those are disallowed by the Windows file system as well.)
|
|
||||||
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
|
||||||
// We allow spaces (U+0020) in file names.
|
|
||||||
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
|
||||||
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for i := 0; i < len(allowed); i++ {
|
|
||||||
if rune(allowed[i]) == r {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// It may be OK to add more ASCII punctuation here, but only carefully.
|
|
||||||
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
|
||||||
return unicode.IsLetter(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckPath checks that a module path is valid.
|
|
||||||
func CheckPath(path string) error {
|
|
||||||
if err := checkPath(path, false); err != nil {
|
|
||||||
return fmt.Errorf("malformed module path %q: %v", path, err)
|
|
||||||
}
|
|
||||||
i := strings.Index(path, "/")
|
|
||||||
if i < 0 {
|
|
||||||
i = len(path)
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
return fmt.Errorf("malformed module path %q: leading slash", path)
|
|
||||||
}
|
|
||||||
if !strings.Contains(path[:i], ".") {
|
|
||||||
return fmt.Errorf("malformed module path %q: missing dot in first path element", path)
|
|
||||||
}
|
|
||||||
if path[0] == '-' {
|
|
||||||
return fmt.Errorf("malformed module path %q: leading dash in first path element", path)
|
|
||||||
}
|
|
||||||
for _, r := range path[:i] {
|
|
||||||
if !firstPathOK(r) {
|
|
||||||
return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, _, ok := SplitPathVersion(path); !ok {
|
|
||||||
return fmt.Errorf("malformed module path %q: invalid version", path)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckImportPath checks that an import path is valid.
|
|
||||||
func CheckImportPath(path string) error {
|
|
||||||
if err := checkPath(path, false); err != nil {
|
|
||||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkPath checks that a general path is valid.
|
|
||||||
// It returns an error describing why but not mentioning path.
|
|
||||||
// Because these checks apply to both module paths and import paths,
|
|
||||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
|
||||||
// fileName indicates whether the final element of the path is a file name
|
|
||||||
// (as opposed to a directory name).
|
|
||||||
func checkPath(path string, fileName bool) error {
|
|
||||||
if !utf8.ValidString(path) {
|
|
||||||
return fmt.Errorf("invalid UTF-8")
|
|
||||||
}
|
|
||||||
if path == "" {
|
|
||||||
return fmt.Errorf("empty string")
|
|
||||||
}
|
|
||||||
if strings.Contains(path, "..") {
|
|
||||||
return fmt.Errorf("double dot")
|
|
||||||
}
|
|
||||||
if strings.Contains(path, "//") {
|
|
||||||
return fmt.Errorf("double slash")
|
|
||||||
}
|
|
||||||
if path[len(path)-1] == '/' {
|
|
||||||
return fmt.Errorf("trailing slash")
|
|
||||||
}
|
|
||||||
elemStart := 0
|
|
||||||
for i, r := range path {
|
|
||||||
if r == '/' {
|
|
||||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
elemStart = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkElem checks whether an individual path element is valid.
|
|
||||||
// fileName indicates whether the element is a file name (not a directory name).
|
|
||||||
func checkElem(elem string, fileName bool) error {
|
|
||||||
if elem == "" {
|
|
||||||
return fmt.Errorf("empty path element")
|
|
||||||
}
|
|
||||||
if strings.Count(elem, ".") == len(elem) {
|
|
||||||
return fmt.Errorf("invalid path element %q", elem)
|
|
||||||
}
|
|
||||||
if elem[0] == '.' && !fileName {
|
|
||||||
return fmt.Errorf("leading dot in path element")
|
|
||||||
}
|
|
||||||
if elem[len(elem)-1] == '.' {
|
|
||||||
return fmt.Errorf("trailing dot in path element")
|
|
||||||
}
|
|
||||||
charOK := pathOK
|
|
||||||
if fileName {
|
|
||||||
charOK = fileNameOK
|
|
||||||
}
|
|
||||||
for _, r := range elem {
|
|
||||||
if !charOK(r) {
|
|
||||||
return fmt.Errorf("invalid char %q", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Windows disallows a bunch of path elements, sadly.
|
|
||||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
|
||||||
short := elem
|
|
||||||
if i := strings.Index(short, "."); i >= 0 {
|
|
||||||
short = short[:i]
|
|
||||||
}
|
|
||||||
for _, bad := range badWindowsNames {
|
|
||||||
if strings.EqualFold(bad, short) {
|
|
||||||
return fmt.Errorf("disallowed path element %q", elem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckFilePath checks whether a slash-separated file path is valid.
|
|
||||||
func CheckFilePath(path string) error {
|
|
||||||
if err := checkPath(path, true); err != nil {
|
|
||||||
return fmt.Errorf("malformed file path %q: %v", path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// badWindowsNames are the reserved file path elements on Windows.
|
|
||||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
|
||||||
var badWindowsNames = []string{
|
|
||||||
"CON",
|
|
||||||
"PRN",
|
|
||||||
"AUX",
|
|
||||||
"NUL",
|
|
||||||
"COM1",
|
|
||||||
"COM2",
|
|
||||||
"COM3",
|
|
||||||
"COM4",
|
|
||||||
"COM5",
|
|
||||||
"COM6",
|
|
||||||
"COM7",
|
|
||||||
"COM8",
|
|
||||||
"COM9",
|
|
||||||
"LPT1",
|
|
||||||
"LPT2",
|
|
||||||
"LPT3",
|
|
||||||
"LPT4",
|
|
||||||
"LPT5",
|
|
||||||
"LPT6",
|
|
||||||
"LPT7",
|
|
||||||
"LPT8",
|
|
||||||
"LPT9",
|
|
||||||
}
|
|
||||||
|
|
||||||
// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path
|
|
||||||
// and version is either empty or "/vN" for N >= 2.
|
|
||||||
// As a special case, gopkg.in paths are recognized directly;
|
|
||||||
// they require ".vN" instead of "/vN", and for all N, not just N >= 2.
|
|
||||||
func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
|
|
||||||
if strings.HasPrefix(path, "gopkg.in/") {
|
|
||||||
return splitGopkgIn(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
i := len(path)
|
|
||||||
dot := false
|
|
||||||
for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
|
|
||||||
if path[i-1] == '.' {
|
|
||||||
dot = true
|
|
||||||
}
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
if i <= 1 || path[i-1] != 'v' || path[i-2] != '/' {
|
|
||||||
return path, "", true
|
|
||||||
}
|
|
||||||
prefix, pathMajor = path[:i-2], path[i-2:]
|
|
||||||
if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" {
|
|
||||||
return path, "", false
|
|
||||||
}
|
|
||||||
return prefix, pathMajor, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths.
|
|
||||||
func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
|
|
||||||
if !strings.HasPrefix(path, "gopkg.in/") {
|
|
||||||
return path, "", false
|
|
||||||
}
|
|
||||||
i := len(path)
|
|
||||||
if strings.HasSuffix(path, "-unstable") {
|
|
||||||
i -= len("-unstable")
|
|
||||||
}
|
|
||||||
for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') {
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' {
|
|
||||||
// All gopkg.in paths must end in vN for some N.
|
|
||||||
return path, "", false
|
|
||||||
}
|
|
||||||
prefix, pathMajor = path[:i-2], path[i-2:]
|
|
||||||
if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" {
|
|
||||||
return path, "", false
|
|
||||||
}
|
|
||||||
return prefix, pathMajor, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchPathMajor reports whether the semantic version v
|
|
||||||
// matches the path major version pathMajor.
|
|
||||||
func MatchPathMajor(v, pathMajor string) bool {
|
|
||||||
if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") {
|
|
||||||
pathMajor = strings.TrimSuffix(pathMajor, "-unstable")
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" {
|
|
||||||
// Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1.
|
|
||||||
// For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
m := semver.Major(v)
|
|
||||||
if pathMajor == "" {
|
|
||||||
return m == "v0" || m == "v1" || semver.Build(v) == "+incompatible"
|
|
||||||
}
|
|
||||||
return (pathMajor[0] == '/' || pathMajor[0] == '.') && m == pathMajor[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanonicalVersion returns the canonical form of the version string v.
|
|
||||||
// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible".
|
|
||||||
func CanonicalVersion(v string) string {
|
|
||||||
cv := semver.Canonical(v)
|
|
||||||
if semver.Build(v) == "+incompatible" {
|
|
||||||
cv += "+incompatible"
|
|
||||||
}
|
|
||||||
return cv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort sorts the list by Path, breaking ties by comparing Versions.
|
|
||||||
func Sort(list []Version) {
|
|
||||||
sort.Slice(list, func(i, j int) bool {
|
|
||||||
mi := list[i]
|
|
||||||
mj := list[j]
|
|
||||||
if mi.Path != mj.Path {
|
|
||||||
return mi.Path < mj.Path
|
|
||||||
}
|
|
||||||
// To help go.sum formatting, allow version/file.
|
|
||||||
// Compare semver prefix by semver rules,
|
|
||||||
// file by string order.
|
|
||||||
vi := mi.Version
|
|
||||||
vj := mj.Version
|
|
||||||
var fi, fj string
|
|
||||||
if k := strings.Index(vi, "/"); k >= 0 {
|
|
||||||
vi, fi = vi[:k], vi[k:]
|
|
||||||
}
|
|
||||||
if k := strings.Index(vj, "/"); k >= 0 {
|
|
||||||
vj, fj = vj[:k], vj[k:]
|
|
||||||
}
|
|
||||||
if vi != vj {
|
|
||||||
return semver.Compare(vi, vj) < 0
|
|
||||||
}
|
|
||||||
return fi < fj
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safe encodings
|
|
||||||
//
|
|
||||||
// Module paths appear as substrings of file system paths
|
|
||||||
// (in the download cache) and of web server URLs in the proxy protocol.
|
|
||||||
// In general we cannot rely on file systems to be case-sensitive,
|
|
||||||
// nor can we rely on web servers, since they read from file systems.
|
|
||||||
// That is, we cannot rely on the file system to keep rsc.io/QUOTE
|
|
||||||
// and rsc.io/quote separate. Windows and macOS don't.
|
|
||||||
// Instead, we must never require two different casings of a file path.
|
|
||||||
// Because we want the download cache to match the proxy protocol,
|
|
||||||
// and because we want the proxy protocol to be possible to serve
|
|
||||||
// from a tree of static files (which might be stored on a case-insensitive
|
|
||||||
// file system), the proxy protocol must never require two different casings
|
|
||||||
// of a URL path either.
|
|
||||||
//
|
|
||||||
// One possibility would be to make the safe encoding be the lowercase
|
|
||||||
// hexadecimal encoding of the actual path bytes. This would avoid ever
|
|
||||||
// needing different casings of a file path, but it would be fairly illegible
|
|
||||||
// to most programmers when those paths appeared in the file system
|
|
||||||
// (including in file paths in compiler errors and stack traces)
|
|
||||||
// in web server logs, and so on. Instead, we want a safe encoding that
|
|
||||||
// leaves most paths unaltered.
|
|
||||||
//
|
|
||||||
// The safe encoding is this:
|
|
||||||
// replace every uppercase letter with an exclamation mark
|
|
||||||
// followed by the letter's lowercase equivalent.
|
|
||||||
//
|
|
||||||
// For example,
|
|
||||||
// github.com/Azure/azure-sdk-for-go -> github.com/!azure/azure-sdk-for-go.
|
|
||||||
// github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy
|
|
||||||
// github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus.
|
|
||||||
//
|
|
||||||
// Import paths that avoid upper-case letters are left unchanged.
|
|
||||||
// Note that because import paths are ASCII-only and avoid various
|
|
||||||
// problematic punctuation (like : < and >), the safe encoding is also ASCII-only
|
|
||||||
// and avoids the same problematic punctuation.
|
|
||||||
//
|
|
||||||
// Import paths have never allowed exclamation marks, so there is no
|
|
||||||
// need to define how to encode a literal !.
|
|
||||||
//
|
|
||||||
// Although paths are disallowed from using Unicode (see pathOK above),
|
|
||||||
// the eventual plan is to allow Unicode letters as well, to assume that
|
|
||||||
// file systems and URLs are Unicode-safe (storing UTF-8), and apply
|
|
||||||
// the !-for-uppercase convention. Note however that not all runes that
|
|
||||||
// are different but case-fold equivalent are an upper/lower pair.
|
|
||||||
// For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin)
|
|
||||||
// are considered to case-fold to each other. When we do add Unicode
|
|
||||||
// letters, we must not assume that upper/lower are the only case-equivalent pairs.
|
|
||||||
// Perhaps the Kelvin symbol would be disallowed entirely, for example.
|
|
||||||
// Or perhaps it would encode as "!!k", or perhaps as "(212A)".
|
|
||||||
//
|
|
||||||
// Also, it would be nice to allow Unicode marks as well as letters,
|
|
||||||
// but marks include combining marks, and then we must deal not
|
|
||||||
// only with case folding but also normalization: both U+00E9 ('é')
|
|
||||||
// and U+0065 U+0301 ('e' followed by combining acute accent)
|
|
||||||
// look the same on the page and are treated by some file systems
|
|
||||||
// as the same path. If we do allow Unicode marks in paths, there
|
|
||||||
// must be some kind of normalization to allow only one canonical
|
|
||||||
// encoding of any character used in an import path.
|
|
||||||
|
|
||||||
// EncodePath returns the safe encoding of the given module path.
|
|
||||||
// It fails if the module path is invalid.
|
|
||||||
func EncodePath(path string) (encoding string, err error) {
|
|
||||||
if err := CheckPath(path); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return encodeString(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeVersion returns the safe encoding of the given module version.
|
|
||||||
// Versions are allowed to be in non-semver form but must be valid file names
|
|
||||||
// and not contain exclamation marks.
|
|
||||||
func EncodeVersion(v string) (encoding string, err error) {
|
|
||||||
if err := checkElem(v, true); err != nil || strings.Contains(v, "!") {
|
|
||||||
return "", fmt.Errorf("disallowed version string %q", v)
|
|
||||||
}
|
|
||||||
return encodeString(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeString(s string) (encoding string, err error) {
|
|
||||||
haveUpper := false
|
|
||||||
for _, r := range s {
|
|
||||||
if r == '!' || r >= utf8.RuneSelf {
|
|
||||||
// This should be disallowed by CheckPath, but diagnose anyway.
|
|
||||||
// The correctness of the encoding loop below depends on it.
|
|
||||||
return "", fmt.Errorf("internal error: inconsistency in EncodePath")
|
|
||||||
}
|
|
||||||
if 'A' <= r && r <= 'Z' {
|
|
||||||
haveUpper = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !haveUpper {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf []byte
|
|
||||||
for _, r := range s {
|
|
||||||
if 'A' <= r && r <= 'Z' {
|
|
||||||
buf = append(buf, '!', byte(r+'a'-'A'))
|
|
||||||
} else {
|
|
||||||
buf = append(buf, byte(r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(buf), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodePath returns the module path of the given safe encoding.
|
|
||||||
// It fails if the encoding is invalid or encodes an invalid path.
|
|
||||||
func DecodePath(encoding string) (path string, err error) {
|
|
||||||
path, ok := decodeString(encoding)
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("invalid module path encoding %q", encoding)
|
|
||||||
}
|
|
||||||
if err := CheckPath(path); err != nil {
|
|
||||||
return "", fmt.Errorf("invalid module path encoding %q: %v", encoding, err)
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeVersion returns the version string for the given safe encoding.
|
|
||||||
// It fails if the encoding is invalid or encodes an invalid version.
|
|
||||||
// Versions are allowed to be in non-semver form but must be valid file names
|
|
||||||
// and not contain exclamation marks.
|
|
||||||
func DecodeVersion(encoding string) (v string, err error) {
|
|
||||||
v, ok := decodeString(encoding)
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("invalid version encoding %q", encoding)
|
|
||||||
}
|
|
||||||
if err := checkElem(v, true); err != nil {
|
|
||||||
return "", fmt.Errorf("disallowed version string %q", v)
|
|
||||||
}
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeString(encoding string) (string, bool) {
|
|
||||||
var buf []byte
|
|
||||||
|
|
||||||
bang := false
|
|
||||||
for _, r := range encoding {
|
|
||||||
if r >= utf8.RuneSelf {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
if bang {
|
|
||||||
bang = false
|
|
||||||
if r < 'a' || 'z' < r {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
buf = append(buf, byte(r+'A'-'a'))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r == '!' {
|
|
||||||
bang = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if 'A' <= r && r <= 'Z' {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
buf = append(buf, byte(r))
|
|
||||||
}
|
|
||||||
if bang {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return string(buf), true
|
|
||||||
}
|
|
388
vendor/github.com/rogpeppe/go-internal/semver/semver.go
generated
vendored
388
vendor/github.com/rogpeppe/go-internal/semver/semver.go
generated
vendored
@ -1,388 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package semver implements comparison of semantic version strings.
|
|
||||||
// In this package, semantic version strings must begin with a leading "v",
|
|
||||||
// as in "v1.0.0".
|
|
||||||
//
|
|
||||||
// The general form of a semantic version string accepted by this package is
|
|
||||||
//
|
|
||||||
// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
|
|
||||||
//
|
|
||||||
// where square brackets indicate optional parts of the syntax;
|
|
||||||
// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
|
|
||||||
// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
|
|
||||||
// using only alphanumeric characters and hyphens; and
|
|
||||||
// all-numeric PRERELEASE identifiers must not have leading zeros.
|
|
||||||
//
|
|
||||||
// This package follows Semantic Versioning 2.0.0 (see semver.org)
|
|
||||||
// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
|
|
||||||
// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
|
|
||||||
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
|
|
||||||
package semver
|
|
||||||
|
|
||||||
// parsed returns the parsed form of a semantic version string.
|
|
||||||
type parsed struct {
|
|
||||||
major string
|
|
||||||
minor string
|
|
||||||
patch string
|
|
||||||
short string
|
|
||||||
prerelease string
|
|
||||||
build string
|
|
||||||
err string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValid reports whether v is a valid semantic version string.
|
|
||||||
func IsValid(v string) bool {
|
|
||||||
_, ok := parse(v)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical returns the canonical formatting of the semantic version v.
|
|
||||||
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
|
||||||
// Two semantic versions compare equal only if their canonical formattings
|
|
||||||
// are identical strings.
|
|
||||||
// The canonical invalid semantic version is the empty string.
|
|
||||||
func Canonical(v string) string {
|
|
||||||
p, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if p.build != "" {
|
|
||||||
return v[:len(v)-len(p.build)]
|
|
||||||
}
|
|
||||||
if p.short != "" {
|
|
||||||
return v + p.short
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Major returns the major version prefix of the semantic version v.
|
|
||||||
// For example, Major("v2.1.0") == "v2".
|
|
||||||
// If v is an invalid semantic version string, Major returns the empty string.
|
|
||||||
func Major(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return v[:1+len(pv.major)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// MajorMinor returns the major.minor version prefix of the semantic version v.
|
|
||||||
// For example, MajorMinor("v2.1.0") == "v2.1".
|
|
||||||
// If v is an invalid semantic version string, MajorMinor returns the empty string.
|
|
||||||
func MajorMinor(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
i := 1 + len(pv.major)
|
|
||||||
if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
|
|
||||||
return v[:j]
|
|
||||||
}
|
|
||||||
return v[:i] + "." + pv.minor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prerelease returns the prerelease suffix of the semantic version v.
|
|
||||||
// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
|
|
||||||
// If v is an invalid semantic version string, Prerelease returns the empty string.
|
|
||||||
func Prerelease(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return pv.prerelease
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build returns the build suffix of the semantic version v.
|
|
||||||
// For example, Build("v2.1.0+meta") == "+meta".
|
|
||||||
// If v is an invalid semantic version string, Build returns the empty string.
|
|
||||||
func Build(v string) string {
|
|
||||||
pv, ok := parse(v)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return pv.build
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare returns an integer comparing two versions according to
|
|
||||||
// according to semantic version precedence.
|
|
||||||
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
|
||||||
//
|
|
||||||
// An invalid semantic version string is considered less than a valid one.
|
|
||||||
// All invalid semantic version strings compare equal to each other.
|
|
||||||
func Compare(v, w string) int {
|
|
||||||
pv, ok1 := parse(v)
|
|
||||||
pw, ok2 := parse(w)
|
|
||||||
if !ok1 && !ok2 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if !ok1 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if !ok2 {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.major, pw.major); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return comparePrerelease(pv.prerelease, pw.prerelease)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max canonicalizes its arguments and then returns the version string
|
|
||||||
// that compares greater.
|
|
||||||
func Max(v, w string) string {
|
|
||||||
v = Canonical(v)
|
|
||||||
w = Canonical(w)
|
|
||||||
if Compare(v, w) > 0 {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(v string) (p parsed, ok bool) {
|
|
||||||
if v == "" || v[0] != 'v' {
|
|
||||||
p.err = "missing v prefix"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.major, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
p.err = "bad major version"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
p.minor = "0"
|
|
||||||
p.patch = "0"
|
|
||||||
p.short = ".0.0"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
p.err = "bad minor prefix"
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.minor, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
p.err = "bad minor version"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v == "" {
|
|
||||||
p.patch = "0"
|
|
||||||
p.short = ".0"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] != '.' {
|
|
||||||
p.err = "bad patch prefix"
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.patch, v, ok = parseInt(v[1:])
|
|
||||||
if !ok {
|
|
||||||
p.err = "bad patch version"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(v) > 0 && v[0] == '-' {
|
|
||||||
p.prerelease, v, ok = parsePrerelease(v)
|
|
||||||
if !ok {
|
|
||||||
p.err = "bad prerelease"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(v) > 0 && v[0] == '+' {
|
|
||||||
p.build, v, ok = parseBuild(v)
|
|
||||||
if !ok {
|
|
||||||
p.err = "bad build"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v != "" {
|
|
||||||
p.err = "junk on end"
|
|
||||||
ok = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseInt(v string) (t, rest string, ok bool) {
|
|
||||||
if v == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[0] < '0' || '9' < v[0] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if v[0] == '0' && i != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePrerelease(v string) (t, rest string, ok bool) {
|
|
||||||
// "A pre-release version MAY be denoted by appending a hyphen and
|
|
||||||
// a series of dot separated identifiers immediately following the patch version.
|
|
||||||
// Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
|
|
||||||
// Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
|
|
||||||
if v == "" || v[0] != '-' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
start := 1
|
|
||||||
for i < len(v) && v[i] != '+' {
|
|
||||||
if !isIdentChar(v[i]) && v[i] != '.' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[i] == '.' {
|
|
||||||
if start == i || isBadNum(v[start:i]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
start = i + 1
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if start == i || isBadNum(v[start:i]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBuild(v string) (t, rest string, ok bool) {
|
|
||||||
if v == "" || v[0] != '+' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i := 1
|
|
||||||
start := 1
|
|
||||||
for i < len(v) {
|
|
||||||
if !isIdentChar(v[i]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v[i] == '.' {
|
|
||||||
if start == i {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
start = i + 1
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if start == i {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return v[:i], v[i:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIdentChar(c byte) bool {
|
|
||||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isBadNum(v string) bool {
|
|
||||||
i := 0
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i == len(v) && i > 1 && v[0] == '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNum(v string) bool {
|
|
||||||
i := 0
|
|
||||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i == len(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareInt(x, y string) int {
|
|
||||||
if x == y {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if len(x) < len(y) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if len(x) > len(y) {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if x < y {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func comparePrerelease(x, y string) int {
|
|
||||||
// "When major, minor, and patch are equal, a pre-release version has
|
|
||||||
// lower precedence than a normal version.
|
|
||||||
// Example: 1.0.0-alpha < 1.0.0.
|
|
||||||
// Precedence for two pre-release versions with the same major, minor,
|
|
||||||
// and patch version MUST be determined by comparing each dot separated
|
|
||||||
// identifier from left to right until a difference is found as follows:
|
|
||||||
// identifiers consisting of only digits are compared numerically and
|
|
||||||
// identifiers with letters or hyphens are compared lexically in ASCII
|
|
||||||
// sort order. Numeric identifiers always have lower precedence than
|
|
||||||
// non-numeric identifiers. A larger set of pre-release fields has a
|
|
||||||
// higher precedence than a smaller set, if all of the preceding
|
|
||||||
// identifiers are equal.
|
|
||||||
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
|
|
||||||
// 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
|
|
||||||
if x == y {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if x == "" {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
if y == "" {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
for x != "" && y != "" {
|
|
||||||
x = x[1:] // skip - or .
|
|
||||||
y = y[1:] // skip - or .
|
|
||||||
var dx, dy string
|
|
||||||
dx, x = nextIdent(x)
|
|
||||||
dy, y = nextIdent(y)
|
|
||||||
if dx != dy {
|
|
||||||
ix := isNum(dx)
|
|
||||||
iy := isNum(dy)
|
|
||||||
if ix != iy {
|
|
||||||
if ix {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ix {
|
|
||||||
if len(dx) < len(dy) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if len(dx) > len(dy) {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dx < dy {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x == "" {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nextIdent(x string) (dx, rest string) {
|
|
||||||
i := 0
|
|
||||||
for i < len(x) && x[i] != '.' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return x[:i], x[i:]
|
|
||||||
}
|
|
2
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
2
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
@ -1,2 +1,4 @@
|
|||||||
logrus
|
logrus
|
||||||
vendor
|
vendor
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
52
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
Normal file
52
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bufferPool BufferPool
|
||||||
|
)
|
||||||
|
|
||||||
|
type BufferPool interface {
|
||||||
|
Put(*bytes.Buffer)
|
||||||
|
Get() *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultPool struct {
|
||||||
|
pool *sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *defaultPool) Put(buf *bytes.Buffer) {
|
||||||
|
p.pool.Put(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *defaultPool) Get() *bytes.Buffer {
|
||||||
|
return p.pool.Get().(*bytes.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBuffer() *bytes.Buffer {
|
||||||
|
return bufferPool.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
func putBuffer(buf *bytes.Buffer) {
|
||||||
|
buf.Reset()
|
||||||
|
bufferPool.Put(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBufferPool allows to replace the default logrus buffer pool
|
||||||
|
// to better meets the specific needs of an application.
|
||||||
|
func SetBufferPool(bp BufferPool) {
|
||||||
|
bufferPool = bp
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SetBufferPool(&defaultPool{
|
||||||
|
pool: &sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new(bytes.Buffer)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
14
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
14
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
@ -13,7 +13,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bufferPool *sync.Pool
|
|
||||||
|
|
||||||
// qualified package name, cached at first use
|
// qualified package name, cached at first use
|
||||||
logrusPackage string
|
logrusPackage string
|
||||||
@ -31,12 +30,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bufferPool = &sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return new(bytes.Buffer)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// start at the bottom of the stack before the package-name cache is primed
|
// start at the bottom of the stack before the package-name cache is primed
|
||||||
minimumCallerDepth = 1
|
minimumCallerDepth = 1
|
||||||
}
|
}
|
||||||
@ -243,9 +236,12 @@ func (entry Entry) log(level Level, msg string) {
|
|||||||
|
|
||||||
entry.fireHooks()
|
entry.fireHooks()
|
||||||
|
|
||||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
buffer = getBuffer()
|
||||||
|
defer func() {
|
||||||
|
entry.Buffer = nil
|
||||||
|
putBuffer(buffer)
|
||||||
|
}()
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
defer bufferPool.Put(buffer)
|
|
||||||
entry.Buffer = buffer
|
entry.Buffer = buffer
|
||||||
|
|
||||||
entry.write()
|
entry.write()
|
||||||
|
45
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
45
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
@ -134,6 +134,51 @@ func Fatal(args ...interface{}) {
|
|||||||
std.Fatal(args...)
|
std.Fatal(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraceFn logs a message from a func at level Trace on the standard logger.
|
||||||
|
func TraceFn(fn LogFunction) {
|
||||||
|
std.TraceFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugFn logs a message from a func at level Debug on the standard logger.
|
||||||
|
func DebugFn(fn LogFunction) {
|
||||||
|
std.DebugFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintFn logs a message from a func at level Info on the standard logger.
|
||||||
|
func PrintFn(fn LogFunction) {
|
||||||
|
std.PrintFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InfoFn logs a message from a func at level Info on the standard logger.
|
||||||
|
func InfoFn(fn LogFunction) {
|
||||||
|
std.InfoFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WarnFn logs a message from a func at level Warn on the standard logger.
|
||||||
|
func WarnFn(fn LogFunction) {
|
||||||
|
std.WarnFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WarningFn logs a message from a func at level Warn on the standard logger.
|
||||||
|
func WarningFn(fn LogFunction) {
|
||||||
|
std.WarningFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorFn logs a message from a func at level Error on the standard logger.
|
||||||
|
func ErrorFn(fn LogFunction) {
|
||||||
|
std.ErrorFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicFn logs a message from a func at level Panic on the standard logger.
|
||||||
|
func PanicFn(fn LogFunction) {
|
||||||
|
std.PanicFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FatalFn logs a message from a func at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
|
func FatalFn(fn LogFunction) {
|
||||||
|
std.FatalFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
// Tracef logs a message at level Trace on the standard logger.
|
// Tracef logs a message at level Trace on the standard logger.
|
||||||
func Tracef(format string, args ...interface{}) {
|
func Tracef(format string, args ...interface{}) {
|
||||||
std.Tracef(format, args...)
|
std.Tracef(format, args...)
|
||||||
|
3
vendor/github.com/sirupsen/logrus/go.mod
generated
vendored
3
vendor/github.com/sirupsen/logrus/go.mod
generated
vendored
@ -2,10 +2,9 @@ module github.com/sirupsen/logrus
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
6
vendor/github.com/sirupsen/logrus/go.sum
generated
vendored
6
vendor/github.com/sirupsen/logrus/go.sum
generated
vendored
@ -1,12 +1,10 @@
|
|||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
54
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
54
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
@ -9,6 +9,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LogFunction For big messages, it can be more efficient to pass a function
|
||||||
|
// and only call it if the log level is actually enables rather than
|
||||||
|
// generating the log message and then checking if the level is enabled
|
||||||
|
type LogFunction func()[]interface{}
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
@ -70,7 +75,7 @@ func (mw *MutexWrap) Disable() {
|
|||||||
//
|
//
|
||||||
// var log = &logrus.Logger{
|
// var log = &logrus.Logger{
|
||||||
// Out: os.Stderr,
|
// Out: os.Stderr,
|
||||||
// Formatter: new(logrus.JSONFormatter),
|
// Formatter: new(logrus.TextFormatter),
|
||||||
// Hooks: make(logrus.LevelHooks),
|
// Hooks: make(logrus.LevelHooks),
|
||||||
// Level: logrus.DebugLevel,
|
// Level: logrus.DebugLevel,
|
||||||
// }
|
// }
|
||||||
@ -195,6 +200,14 @@ func (logger *Logger) Log(level Level, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) LogFn(level Level, fn LogFunction) {
|
||||||
|
if logger.IsLevelEnabled(level) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Log(level, fn()...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Trace(args ...interface{}) {
|
func (logger *Logger) Trace(args ...interface{}) {
|
||||||
logger.Log(TraceLevel, args...)
|
logger.Log(TraceLevel, args...)
|
||||||
}
|
}
|
||||||
@ -234,6 +247,45 @@ func (logger *Logger) Panic(args ...interface{}) {
|
|||||||
logger.Log(PanicLevel, args...)
|
logger.Log(PanicLevel, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) TraceFn(fn LogFunction) {
|
||||||
|
logger.LogFn(TraceLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) DebugFn(fn LogFunction) {
|
||||||
|
logger.LogFn(DebugLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) InfoFn(fn LogFunction) {
|
||||||
|
logger.LogFn(InfoLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) PrintFn(fn LogFunction) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Print(fn()...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) WarnFn(fn LogFunction) {
|
||||||
|
logger.LogFn(WarnLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) WarningFn(fn LogFunction) {
|
||||||
|
logger.WarnFn(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) ErrorFn(fn LogFunction) {
|
||||||
|
logger.LogFn(ErrorLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) FatalFn(fn LogFunction) {
|
||||||
|
logger.LogFn(FatalLevel, fn)
|
||||||
|
logger.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) PanicFn(fn LogFunction) {
|
||||||
|
logger.LogFn(PanicLevel, fn)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
||||||
if logger.IsLevelEnabled(level) {
|
if logger.IsLevelEnabled(level) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
|
27
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
27
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
@ -5,30 +5,23 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
switch v := w.(type) {
|
|
||||||
case *os.File:
|
|
||||||
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
var ret bool
|
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
|
handle := windows.Handle(v.Fd())
|
||||||
var mode uint32
|
var mode uint32
|
||||||
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
if err := windows.GetConsoleMode(handle, &mode); err != nil {
|
||||||
ret = (err == nil)
|
return false
|
||||||
default:
|
|
||||||
ret = false
|
|
||||||
}
|
}
|
||||||
if ret {
|
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
initTerminal(w)
|
if err := windows.SetConsoleMode(handle, mode); err != nil {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return ret
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
39
vendor/github.com/spf13/cobra/.gitignore
generated
vendored
39
vendor/github.com/spf13/cobra/.gitignore
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Folders
|
|
||||||
_obj
|
|
||||||
_test
|
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
|
||||||
*.[568vq]
|
|
||||||
[568vq].out
|
|
||||||
|
|
||||||
*.cgo1.go
|
|
||||||
*.cgo2.c
|
|
||||||
_cgo_defun.c
|
|
||||||
_cgo_gotypes.go
|
|
||||||
_cgo_export.*
|
|
||||||
|
|
||||||
_testmain.go
|
|
||||||
|
|
||||||
# Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore
|
|
||||||
# swap
|
|
||||||
[._]*.s[a-w][a-z]
|
|
||||||
[._]s[a-w][a-z]
|
|
||||||
# session
|
|
||||||
Session.vim
|
|
||||||
# temporary
|
|
||||||
.netrwhist
|
|
||||||
*~
|
|
||||||
# auto-generated tag files
|
|
||||||
tags
|
|
||||||
|
|
||||||
*.exe
|
|
||||||
cobra.test
|
|
||||||
bin
|
|
||||||
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
3
vendor/github.com/spf13/cobra/.mailmap
generated
vendored
3
vendor/github.com/spf13/cobra/.mailmap
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
Steve Francia <steve.francia@gmail.com>
|
|
||||||
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
|
||||||
Fabiano Franz <ffranz@redhat.com> <contact@fabianofranz.com>
|
|
29
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
29
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- diff
|
|
||||||
- test
|
|
||||||
- build
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.12.x
|
|
||||||
- 1.13.x
|
|
||||||
- tip
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get -u github.com/kyoh86/richgo
|
|
||||||
- go get -u github.com/mitchellh/gox
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- go: tip
|
|
||||||
include:
|
|
||||||
- stage: diff
|
|
||||||
go: 1.13.x
|
|
||||||
script: make fmt
|
|
||||||
- stage: build
|
|
||||||
go: 1.13.x
|
|
||||||
script: make cobra_generator
|
|
||||||
|
|
||||||
script:
|
|
||||||
- make test
|
|
174
vendor/github.com/spf13/cobra/LICENSE.txt
generated
vendored
174
vendor/github.com/spf13/cobra/LICENSE.txt
generated
vendored
@ -1,174 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
36
vendor/github.com/spf13/cobra/Makefile
generated
vendored
36
vendor/github.com/spf13/cobra/Makefile
generated
vendored
@ -1,36 +0,0 @@
|
|||||||
BIN="./bin"
|
|
||||||
SRC=$(shell find . -name "*.go")
|
|
||||||
|
|
||||||
ifeq (, $(shell which richgo))
|
|
||||||
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: fmt vet test cobra_generator install_deps clean
|
|
||||||
|
|
||||||
default: all
|
|
||||||
|
|
||||||
all: fmt vet test cobra_generator
|
|
||||||
|
|
||||||
fmt:
|
|
||||||
$(info ******************** checking formatting ********************)
|
|
||||||
@test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1)
|
|
||||||
|
|
||||||
test: install_deps vet
|
|
||||||
$(info ******************** running tests ********************)
|
|
||||||
richgo test -v ./...
|
|
||||||
|
|
||||||
cobra_generator: install_deps
|
|
||||||
$(info ******************** building generator ********************)
|
|
||||||
mkdir -p $(BIN)
|
|
||||||
make -C cobra all
|
|
||||||
|
|
||||||
install_deps:
|
|
||||||
$(info ******************** downloading dependencies ********************)
|
|
||||||
go get -v ./...
|
|
||||||
|
|
||||||
vet:
|
|
||||||
$(info ******************** vetting ********************)
|
|
||||||
go vet ./...
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BIN)
|
|
770
vendor/github.com/spf13/cobra/README.md
generated
vendored
770
vendor/github.com/spf13/cobra/README.md
generated
vendored
@ -1,770 +0,0 @@
|
|||||||
![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png)
|
|
||||||
|
|
||||||
Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files.
|
|
||||||
|
|
||||||
Many of the most widely used Go projects are built using Cobra, such as:
|
|
||||||
[Kubernetes](http://kubernetes.io/),
|
|
||||||
[Hugo](http://gohugo.io),
|
|
||||||
[rkt](https://github.com/coreos/rkt),
|
|
||||||
[etcd](https://github.com/coreos/etcd),
|
|
||||||
[Moby (former Docker)](https://github.com/moby/moby),
|
|
||||||
[Docker (distribution)](https://github.com/docker/distribution),
|
|
||||||
[OpenShift](https://www.openshift.com/),
|
|
||||||
[Delve](https://github.com/derekparker/delve),
|
|
||||||
[GopherJS](http://www.gopherjs.org/),
|
|
||||||
[CockroachDB](http://www.cockroachlabs.com/),
|
|
||||||
[Bleve](http://www.blevesearch.com/),
|
|
||||||
[ProjectAtomic (enterprise)](http://www.projectatomic.io/),
|
|
||||||
[Giant Swarm's gsctl](https://github.com/giantswarm/gsctl),
|
|
||||||
[Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack),
|
|
||||||
[rclone](http://rclone.org/),
|
|
||||||
[nehm](https://github.com/bogem/nehm),
|
|
||||||
[Pouch](https://github.com/alibaba/pouch),
|
|
||||||
[Istio](https://istio.io),
|
|
||||||
[Prototool](https://github.com/uber/prototool),
|
|
||||||
[mattermost-server](https://github.com/mattermost/mattermost-server),
|
|
||||||
[Gardener](https://github.com/gardener/gardenctl),
|
|
||||||
[Linkerd](https://linkerd.io/),
|
|
||||||
[Github CLI](https://github.com/cli/cli)
|
|
||||||
etc.
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
|
|
||||||
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra)
|
|
||||||
|
|
||||||
# Table of Contents
|
|
||||||
|
|
||||||
- [Overview](#overview)
|
|
||||||
- [Concepts](#concepts)
|
|
||||||
* [Commands](#commands)
|
|
||||||
* [Flags](#flags)
|
|
||||||
- [Installing](#installing)
|
|
||||||
- [Getting Started](#getting-started)
|
|
||||||
* [Using the Cobra Generator](#using-the-cobra-generator)
|
|
||||||
* [Using the Cobra Library](#using-the-cobra-library)
|
|
||||||
* [Working with Flags](#working-with-flags)
|
|
||||||
* [Positional and Custom Arguments](#positional-and-custom-arguments)
|
|
||||||
* [Example](#example)
|
|
||||||
* [Help Command](#help-command)
|
|
||||||
* [Usage Message](#usage-message)
|
|
||||||
* [PreRun and PostRun Hooks](#prerun-and-postrun-hooks)
|
|
||||||
* [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens)
|
|
||||||
* [Generating documentation for your command](#generating-documentation-for-your-command)
|
|
||||||
* [Generating bash completions](#generating-bash-completions)
|
|
||||||
* [Generating zsh completions](#generating-zsh-completions)
|
|
||||||
- [Contributing](#contributing)
|
|
||||||
- [License](#license)
|
|
||||||
|
|
||||||
# Overview
|
|
||||||
|
|
||||||
Cobra is a library providing a simple interface to create powerful modern CLI
|
|
||||||
interfaces similar to git & go tools.
|
|
||||||
|
|
||||||
Cobra is also an application that will generate your application scaffolding to rapidly
|
|
||||||
develop a Cobra-based application.
|
|
||||||
|
|
||||||
Cobra provides:
|
|
||||||
* Easy subcommand-based CLIs: `app server`, `app fetch`, etc.
|
|
||||||
* Fully POSIX-compliant flags (including short & long versions)
|
|
||||||
* Nested subcommands
|
|
||||||
* Global, local and cascading flags
|
|
||||||
* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname`
|
|
||||||
* Intelligent suggestions (`app srver`... did you mean `app server`?)
|
|
||||||
* Automatic help generation for commands and flags
|
|
||||||
* Automatic help flag recognition of `-h`, `--help`, etc.
|
|
||||||
* Automatically generated bash autocomplete for your application
|
|
||||||
* Automatically generated man pages for your application
|
|
||||||
* Command aliases so you can change things without breaking them
|
|
||||||
* The flexibility to define your own help, usage, etc.
|
|
||||||
* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
|
|
||||||
|
|
||||||
# Concepts
|
|
||||||
|
|
||||||
Cobra is built on a structure of commands, arguments & flags.
|
|
||||||
|
|
||||||
**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions.
|
|
||||||
|
|
||||||
The best applications will read like sentences when used. Users will know how
|
|
||||||
to use the application because they will natively understand how to use it.
|
|
||||||
|
|
||||||
The pattern to follow is
|
|
||||||
`APPNAME VERB NOUN --ADJECTIVE.`
|
|
||||||
or
|
|
||||||
`APPNAME COMMAND ARG --FLAG`
|
|
||||||
|
|
||||||
A few good real world examples may better illustrate this point.
|
|
||||||
|
|
||||||
In the following example, 'server' is a command, and 'port' is a flag:
|
|
||||||
|
|
||||||
hugo server --port=1313
|
|
||||||
|
|
||||||
In this command we are telling Git to clone the url bare.
|
|
||||||
|
|
||||||
git clone URL --bare
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
Command is the central point of the application. Each interaction that
|
|
||||||
the application supports will be contained in a Command. A command can
|
|
||||||
have children commands and optionally run an action.
|
|
||||||
|
|
||||||
In the example above, 'server' is the command.
|
|
||||||
|
|
||||||
[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command)
|
|
||||||
|
|
||||||
## Flags
|
|
||||||
|
|
||||||
A flag is a way to modify the behavior of a command. Cobra supports
|
|
||||||
fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/).
|
|
||||||
A Cobra command can define flags that persist through to children commands
|
|
||||||
and flags that are only available to that command.
|
|
||||||
|
|
||||||
In the example above, 'port' is the flag.
|
|
||||||
|
|
||||||
Flag functionality is provided by the [pflag
|
|
||||||
library](https://github.com/spf13/pflag), a fork of the flag standard library
|
|
||||||
which maintains the same interface while adding POSIX compliance.
|
|
||||||
|
|
||||||
# Installing
|
|
||||||
Using Cobra is easy. First, use `go get` to install the latest version
|
|
||||||
of the library. This command will install the `cobra` generator executable
|
|
||||||
along with the library and its dependencies:
|
|
||||||
|
|
||||||
go get -u github.com/spf13/cobra/cobra
|
|
||||||
|
|
||||||
Next, include Cobra in your application:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/spf13/cobra"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
While you are welcome to provide your own organization, typically a Cobra-based
|
|
||||||
application will follow the following organizational structure:
|
|
||||||
|
|
||||||
```
|
|
||||||
▾ appName/
|
|
||||||
▾ cmd/
|
|
||||||
add.go
|
|
||||||
your.go
|
|
||||||
commands.go
|
|
||||||
here.go
|
|
||||||
main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"{pathToYourApp}/cmd"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cmd.Execute()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using the Cobra Generator
|
|
||||||
|
|
||||||
Cobra provides its own program that will create your application and add any
|
|
||||||
commands you want. It's the easiest way to incorporate Cobra into your application.
|
|
||||||
|
|
||||||
[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
|
|
||||||
|
|
||||||
## Using the Cobra Library
|
|
||||||
|
|
||||||
To manually implement Cobra you need to create a bare main.go file and a rootCmd file.
|
|
||||||
You will optionally provide additional commands as you see fit.
|
|
||||||
|
|
||||||
### Create rootCmd
|
|
||||||
|
|
||||||
Cobra doesn't require any special constructors. Simply create your commands.
|
|
||||||
|
|
||||||
Ideally you place this in app/cmd/root.go:
|
|
||||||
|
|
||||||
```go
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "hugo",
|
|
||||||
Short: "Hugo is a very fast static site generator",
|
|
||||||
Long: `A Fast and Flexible Static Site Generator built with
|
|
||||||
love by spf13 and friends in Go.
|
|
||||||
Complete documentation is available at http://hugo.spf13.com`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
// Do Stuff Here
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func Execute() {
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You will additionally define flags and handle configuration in your init() function.
|
|
||||||
|
|
||||||
For example cmd/root.go:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Used for flags.
|
|
||||||
cfgFile string
|
|
||||||
userLicense string
|
|
||||||
|
|
||||||
rootCmd = &cobra.Command{
|
|
||||||
Use: "cobra",
|
|
||||||
Short: "A generator for Cobra based Applications",
|
|
||||||
Long: `Cobra is a CLI library for Go that empowers applications.
|
|
||||||
This application is a tool to generate the needed files
|
|
||||||
to quickly create a Cobra application.`,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Execute executes the root command.
|
|
||||||
func Execute() error {
|
|
||||||
return rootCmd.Execute()
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cobra.OnInitialize(initConfig)
|
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
|
||||||
rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
|
|
||||||
rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
|
|
||||||
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
|
|
||||||
viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
|
|
||||||
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
|
|
||||||
viper.SetDefault("license", "apache")
|
|
||||||
|
|
||||||
rootCmd.AddCommand(addCmd)
|
|
||||||
rootCmd.AddCommand(initCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func er(msg interface{}) {
|
|
||||||
fmt.Println("Error:", msg)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initConfig() {
|
|
||||||
if cfgFile != "" {
|
|
||||||
// Use config file from the flag.
|
|
||||||
viper.SetConfigFile(cfgFile)
|
|
||||||
} else {
|
|
||||||
// Find home directory.
|
|
||||||
home, err := homedir.Dir()
|
|
||||||
if err != nil {
|
|
||||||
er(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search config in home directory with name ".cobra" (without extension).
|
|
||||||
viper.AddConfigPath(home)
|
|
||||||
viper.SetConfigName(".cobra")
|
|
||||||
}
|
|
||||||
|
|
||||||
viper.AutomaticEnv()
|
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err == nil {
|
|
||||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create your main.go
|
|
||||||
|
|
||||||
With the root command you need to have your main function execute it.
|
|
||||||
Execute should be run on the root for clarity, though it can be called on any command.
|
|
||||||
|
|
||||||
In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"{pathToYourApp}/cmd"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cmd.Execute()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create additional commands
|
|
||||||
|
|
||||||
Additional commands can be defined and typically are each given their own file
|
|
||||||
inside of the cmd/ directory.
|
|
||||||
|
|
||||||
If you wanted to create a version command you would create cmd/version.go and
|
|
||||||
populate it with the following:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(versionCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionCmd = &cobra.Command{
|
|
||||||
Use: "version",
|
|
||||||
Short: "Print the version number of Hugo",
|
|
||||||
Long: `All software has versions. This is Hugo's`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Working with Flags
|
|
||||||
|
|
||||||
Flags provide modifiers to control how the action command operates.
|
|
||||||
|
|
||||||
### Assign flags to a command
|
|
||||||
|
|
||||||
Since the flags are defined and used in different locations, we need to
|
|
||||||
define a variable outside with the correct scope to assign the flag to
|
|
||||||
work with.
|
|
||||||
|
|
||||||
```go
|
|
||||||
var Verbose bool
|
|
||||||
var Source string
|
|
||||||
```
|
|
||||||
|
|
||||||
There are two different approaches to assign a flag.
|
|
||||||
|
|
||||||
### Persistent Flags
|
|
||||||
|
|
||||||
A flag can be 'persistent' meaning that this flag will be available to the
|
|
||||||
command it's assigned to as well as every command under that command. For
|
|
||||||
global flags, assign a flag as a persistent flag on the root.
|
|
||||||
|
|
||||||
```go
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Local Flags
|
|
||||||
|
|
||||||
A flag can also be assigned locally which will only apply to that specific command.
|
|
||||||
|
|
||||||
```go
|
|
||||||
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Local Flag on Parent Commands
|
|
||||||
|
|
||||||
By default Cobra only parses local flags on the target command, any local flags on
|
|
||||||
parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
|
|
||||||
parse local flags on each command before executing the target command.
|
|
||||||
|
|
||||||
```go
|
|
||||||
command := cobra.Command{
|
|
||||||
Use: "print [OPTIONS] [COMMANDS]",
|
|
||||||
TraverseChildren: true,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bind Flags with Config
|
|
||||||
|
|
||||||
You can also bind your flags with [viper](https://github.com/spf13/viper):
|
|
||||||
```go
|
|
||||||
var author string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
|
|
||||||
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example the persistent flag `author` is bound with `viper`.
|
|
||||||
**Note**, that the variable `author` will not be set to the value from config,
|
|
||||||
when the `--author` flag is not provided by user.
|
|
||||||
|
|
||||||
More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
|
|
||||||
|
|
||||||
### Required flags
|
|
||||||
|
|
||||||
Flags are optional by default. If instead you wish your command to report an error
|
|
||||||
when a flag has not been set, mark it as required:
|
|
||||||
```go
|
|
||||||
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
|
|
||||||
rootCmd.MarkFlagRequired("region")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Positional and Custom Arguments
|
|
||||||
|
|
||||||
Validation of positional arguments can be specified using the `Args` field
|
|
||||||
of `Command`.
|
|
||||||
|
|
||||||
The following validators are built in:
|
|
||||||
|
|
||||||
- `NoArgs` - the command will report an error if there are any positional args.
|
|
||||||
- `ArbitraryArgs` - the command will accept any args.
|
|
||||||
- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`.
|
|
||||||
- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
|
|
||||||
- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
|
|
||||||
- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
|
|
||||||
- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command`
|
|
||||||
- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
|
|
||||||
|
|
||||||
An example of setting the custom validator:
|
|
||||||
|
|
||||||
```go
|
|
||||||
var cmd = &cobra.Command{
|
|
||||||
Short: "hello",
|
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) < 1 {
|
|
||||||
return errors.New("requires a color argument")
|
|
||||||
}
|
|
||||||
if myapp.IsValidColor(args[0]) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("invalid color specified: %s", args[0])
|
|
||||||
},
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("Hello, World!")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
In the example below, we have defined three commands. Two are at the top level
|
|
||||||
and one (cmdTimes) is a child of one of the top commands. In this case the root
|
|
||||||
is not executable meaning that a subcommand is required. This is accomplished
|
|
||||||
by not providing a 'Run' for the 'rootCmd'.
|
|
||||||
|
|
||||||
We have only defined one flag for a single command.
|
|
||||||
|
|
||||||
More documentation about flags is available at https://github.com/spf13/pflag
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var echoTimes int
|
|
||||||
|
|
||||||
var cmdPrint = &cobra.Command{
|
|
||||||
Use: "print [string to print]",
|
|
||||||
Short: "Print anything to the screen",
|
|
||||||
Long: `print is for printing anything back to the screen.
|
|
||||||
For many years people have printed back to the screen.`,
|
|
||||||
Args: cobra.MinimumNArgs(1),
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("Print: " + strings.Join(args, " "))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmdEcho = &cobra.Command{
|
|
||||||
Use: "echo [string to echo]",
|
|
||||||
Short: "Echo anything to the screen",
|
|
||||||
Long: `echo is for echoing anything back.
|
|
||||||
Echo works a lot like print, except it has a child command.`,
|
|
||||||
Args: cobra.MinimumNArgs(1),
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("Echo: " + strings.Join(args, " "))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmdTimes = &cobra.Command{
|
|
||||||
Use: "times [string to echo]",
|
|
||||||
Short: "Echo anything to the screen more times",
|
|
||||||
Long: `echo things multiple times back to the user by providing
|
|
||||||
a count and a string.`,
|
|
||||||
Args: cobra.MinimumNArgs(1),
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
for i := 0; i < echoTimes; i++ {
|
|
||||||
fmt.Println("Echo: " + strings.Join(args, " "))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{Use: "app"}
|
|
||||||
rootCmd.AddCommand(cmdPrint, cmdEcho)
|
|
||||||
cmdEcho.AddCommand(cmdTimes)
|
|
||||||
rootCmd.Execute()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
|
|
||||||
|
|
||||||
## Help Command
|
|
||||||
|
|
||||||
Cobra automatically adds a help command to your application when you have subcommands.
|
|
||||||
This will be called when a user runs 'app help'. Additionally, help will also
|
|
||||||
support all other commands as input. Say, for instance, you have a command called
|
|
||||||
'create' without any additional configuration; Cobra will work when 'app help
|
|
||||||
create' is called. Every command will automatically have the '--help' flag added.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
The following output is automatically generated by Cobra. Nothing beyond the
|
|
||||||
command and flag definitions are needed.
|
|
||||||
|
|
||||||
$ cobra help
|
|
||||||
|
|
||||||
Cobra is a CLI library for Go that empowers applications.
|
|
||||||
This application is a tool to generate the needed files
|
|
||||||
to quickly create a Cobra application.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
cobra [command]
|
|
||||||
|
|
||||||
Available Commands:
|
|
||||||
add Add a command to a Cobra Application
|
|
||||||
help Help about any command
|
|
||||||
init Initialize a Cobra Application
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
-a, --author string author name for copyright attribution (default "YOUR NAME")
|
|
||||||
--config string config file (default is $HOME/.cobra.yaml)
|
|
||||||
-h, --help help for cobra
|
|
||||||
-l, --license string name of license for the project
|
|
||||||
--viper use Viper for configuration (default true)
|
|
||||||
|
|
||||||
Use "cobra [command] --help" for more information about a command.
|
|
||||||
|
|
||||||
|
|
||||||
Help is just a command like any other. There is no special logic or behavior
|
|
||||||
around it. In fact, you can provide your own if you want.
|
|
||||||
|
|
||||||
### Defining your own help
|
|
||||||
|
|
||||||
You can provide your own Help command or your own template for the default command to use
|
|
||||||
with following functions:
|
|
||||||
|
|
||||||
```go
|
|
||||||
cmd.SetHelpCommand(cmd *Command)
|
|
||||||
cmd.SetHelpFunc(f func(*Command, []string))
|
|
||||||
cmd.SetHelpTemplate(s string)
|
|
||||||
```
|
|
||||||
|
|
||||||
The latter two will also apply to any children commands.
|
|
||||||
|
|
||||||
## Usage Message
|
|
||||||
|
|
||||||
When the user provides an invalid flag or invalid command, Cobra responds by
|
|
||||||
showing the user the 'usage'.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
You may recognize this from the help above. That's because the default help
|
|
||||||
embeds the usage as part of its output.
|
|
||||||
|
|
||||||
$ cobra --invalid
|
|
||||||
Error: unknown flag: --invalid
|
|
||||||
Usage:
|
|
||||||
cobra [command]
|
|
||||||
|
|
||||||
Available Commands:
|
|
||||||
add Add a command to a Cobra Application
|
|
||||||
help Help about any command
|
|
||||||
init Initialize a Cobra Application
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
-a, --author string author name for copyright attribution (default "YOUR NAME")
|
|
||||||
--config string config file (default is $HOME/.cobra.yaml)
|
|
||||||
-h, --help help for cobra
|
|
||||||
-l, --license string name of license for the project
|
|
||||||
--viper use Viper for configuration (default true)
|
|
||||||
|
|
||||||
Use "cobra [command] --help" for more information about a command.
|
|
||||||
|
|
||||||
### Defining your own usage
|
|
||||||
You can provide your own usage function or template for Cobra to use.
|
|
||||||
Like help, the function and template are overridable through public methods:
|
|
||||||
|
|
||||||
```go
|
|
||||||
cmd.SetUsageFunc(f func(*Command) error)
|
|
||||||
cmd.SetUsageTemplate(s string)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version Flag
|
|
||||||
|
|
||||||
Cobra adds a top-level '--version' flag if the Version field is set on the root command.
|
|
||||||
Running an application with the '--version' flag will print the version to stdout using
|
|
||||||
the version template. The template can be customized using the
|
|
||||||
`cmd.SetVersionTemplate(s string)` function.
|
|
||||||
|
|
||||||
## PreRun and PostRun Hooks
|
|
||||||
|
|
||||||
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
|
|
||||||
|
|
||||||
- `PersistentPreRun`
|
|
||||||
- `PreRun`
|
|
||||||
- `Run`
|
|
||||||
- `PostRun`
|
|
||||||
- `PersistentPostRun`
|
|
||||||
|
|
||||||
An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "root [sub]",
|
|
||||||
Short: "My root command",
|
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside rootCmd Run with args: %v\n", args)
|
|
||||||
},
|
|
||||||
PostRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var subCmd = &cobra.Command{
|
|
||||||
Use: "sub [no options!]",
|
|
||||||
Short: "My subcommand",
|
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside subCmd Run with args: %v\n", args)
|
|
||||||
},
|
|
||||||
PostRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCmd.AddCommand(subCmd)
|
|
||||||
|
|
||||||
rootCmd.SetArgs([]string{""})
|
|
||||||
rootCmd.Execute()
|
|
||||||
fmt.Println()
|
|
||||||
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
|
|
||||||
rootCmd.Execute()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Output:
|
|
||||||
```
|
|
||||||
Inside rootCmd PersistentPreRun with args: []
|
|
||||||
Inside rootCmd PreRun with args: []
|
|
||||||
Inside rootCmd Run with args: []
|
|
||||||
Inside rootCmd PostRun with args: []
|
|
||||||
Inside rootCmd PersistentPostRun with args: []
|
|
||||||
|
|
||||||
Inside rootCmd PersistentPreRun with args: [arg1 arg2]
|
|
||||||
Inside subCmd PreRun with args: [arg1 arg2]
|
|
||||||
Inside subCmd Run with args: [arg1 arg2]
|
|
||||||
Inside subCmd PostRun with args: [arg1 arg2]
|
|
||||||
Inside subCmd PersistentPostRun with args: [arg1 arg2]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Suggestions when "unknown command" happens
|
|
||||||
|
|
||||||
Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ hugo srever
|
|
||||||
Error: unknown command "srever" for "hugo"
|
|
||||||
|
|
||||||
Did you mean this?
|
|
||||||
server
|
|
||||||
|
|
||||||
Run 'hugo --help' for usage.
|
|
||||||
```
|
|
||||||
|
|
||||||
Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.
|
|
||||||
|
|
||||||
If you need to disable suggestions or tweak the string distance in your command, use:
|
|
||||||
|
|
||||||
```go
|
|
||||||
command.DisableSuggestions = true
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```go
|
|
||||||
command.SuggestionsMinimumDistance = 1
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl remove
|
|
||||||
Error: unknown command "remove" for "kubectl"
|
|
||||||
|
|
||||||
Did you mean this?
|
|
||||||
delete
|
|
||||||
|
|
||||||
Run 'kubectl help' for usage.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Generating documentation for your command
|
|
||||||
|
|
||||||
Cobra can generate documentation based on subcommands, flags, etc. in the following formats:
|
|
||||||
|
|
||||||
- [Markdown](doc/md_docs.md)
|
|
||||||
- [ReStructured Text](doc/rest_docs.md)
|
|
||||||
- [Man Page](doc/man_docs.md)
|
|
||||||
|
|
||||||
## Generating bash completions
|
|
||||||
|
|
||||||
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
|
|
||||||
|
|
||||||
## Generating zsh completions
|
|
||||||
|
|
||||||
Cobra can generate zsh-completion file. Read more about it in
|
|
||||||
[Zsh Completions](zsh_completions.md).
|
|
||||||
|
|
||||||
# Contributing
|
|
||||||
|
|
||||||
1. Fork it
|
|
||||||
2. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`)
|
|
||||||
3. Create your feature branch (`git checkout -b my-new-feature`)
|
|
||||||
4. Make changes and add them (`git add .`)
|
|
||||||
5. Commit your changes (`git commit -m 'Add some feature'`)
|
|
||||||
6. Push to the branch (`git push origin my-new-feature`)
|
|
||||||
7. Create new pull request
|
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt)
|
|
109
vendor/github.com/spf13/cobra/args.go
generated
vendored
109
vendor/github.com/spf13/cobra/args.go
generated
vendored
@ -1,109 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PositionalArgs func(cmd *Command, args []string) error
|
|
||||||
|
|
||||||
// Legacy arg validation has the following behaviour:
|
|
||||||
// - root commands with no subcommands can take arbitrary arguments
|
|
||||||
// - root commands with subcommands will do subcommand validity checking
|
|
||||||
// - subcommands will always accept arbitrary arguments
|
|
||||||
func legacyArgs(cmd *Command, args []string) error {
|
|
||||||
// no subcommand, always take args
|
|
||||||
if !cmd.HasSubCommands() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// root command with subcommands, do subcommand checking.
|
|
||||||
if !cmd.HasParent() && len(args) > 0 {
|
|
||||||
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoArgs returns an error if any args are included.
|
|
||||||
func NoArgs(cmd *Command, args []string) error {
|
|
||||||
if len(args) > 0 {
|
|
||||||
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
|
|
||||||
func OnlyValidArgs(cmd *Command, args []string) error {
|
|
||||||
if len(cmd.ValidArgs) > 0 {
|
|
||||||
// Remove any description that may be included in ValidArgs.
|
|
||||||
// A description is following a tab character.
|
|
||||||
var validArgs []string
|
|
||||||
for _, v := range cmd.ValidArgs {
|
|
||||||
validArgs = append(validArgs, strings.Split(v, "\t")[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range args {
|
|
||||||
if !stringInSlice(v, validArgs) {
|
|
||||||
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArbitraryArgs never returns an error.
|
|
||||||
func ArbitraryArgs(cmd *Command, args []string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinimumNArgs returns an error if there is not at least N args.
|
|
||||||
func MinimumNArgs(n int) PositionalArgs {
|
|
||||||
return func(cmd *Command, args []string) error {
|
|
||||||
if len(args) < n {
|
|
||||||
return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaximumNArgs returns an error if there are more than N args.
|
|
||||||
func MaximumNArgs(n int) PositionalArgs {
|
|
||||||
return func(cmd *Command, args []string) error {
|
|
||||||
if len(args) > n {
|
|
||||||
return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactArgs returns an error if there are not exactly n args.
|
|
||||||
func ExactArgs(n int) PositionalArgs {
|
|
||||||
return func(cmd *Command, args []string) error {
|
|
||||||
if len(args) != n {
|
|
||||||
return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactValidArgs returns an error if
|
|
||||||
// there are not exactly N positional args OR
|
|
||||||
// there are any positional args that are not in the `ValidArgs` field of `Command`
|
|
||||||
func ExactValidArgs(n int) PositionalArgs {
|
|
||||||
return func(cmd *Command, args []string) error {
|
|
||||||
if err := ExactArgs(n)(cmd, args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return OnlyValidArgs(cmd, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RangeArgs returns an error if the number of args is not within the expected range.
|
|
||||||
func RangeArgs(min int, max int) PositionalArgs {
|
|
||||||
return func(cmd *Command, args []string) error {
|
|
||||||
if len(args) < min || len(args) > max {
|
|
||||||
return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
641
vendor/github.com/spf13/cobra/bash_completions.go
generated
vendored
641
vendor/github.com/spf13/cobra/bash_completions.go
generated
vendored
@ -1,641 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Annotations for Bash completion.
|
|
||||||
const (
|
|
||||||
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions"
|
|
||||||
BashCompCustom = "cobra_annotation_bash_completion_custom"
|
|
||||||
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
|
|
||||||
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
|
|
||||||
)
|
|
||||||
|
|
||||||
func writePreamble(buf *bytes.Buffer, name string) {
|
|
||||||
buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
|
|
||||||
buf.WriteString(fmt.Sprintf(`
|
|
||||||
__%[1]s_debug()
|
|
||||||
{
|
|
||||||
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
|
|
||||||
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Homebrew on Macs have version 1.3 of bash-completion which doesn't include
|
|
||||||
# _init_completion. This is a very minimal version of that function.
|
|
||||||
__%[1]s_init_completion()
|
|
||||||
{
|
|
||||||
COMPREPLY=()
|
|
||||||
_get_comp_words_by_ref "$@" cur prev words cword
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_index_of_word()
|
|
||||||
{
|
|
||||||
local w word=$1
|
|
||||||
shift
|
|
||||||
index=0
|
|
||||||
for w in "$@"; do
|
|
||||||
[[ $w = "$word" ]] && return
|
|
||||||
index=$((index+1))
|
|
||||||
done
|
|
||||||
index=-1
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_contains_word()
|
|
||||||
{
|
|
||||||
local w word=$1; shift
|
|
||||||
for w in "$@"; do
|
|
||||||
[[ $w = "$word" ]] && return
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_go_custom_completion()
|
|
||||||
{
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}"
|
|
||||||
|
|
||||||
local out requestComp lastParam lastChar comp directive args
|
|
||||||
|
|
||||||
# Prepare the command to request completions for the program.
|
|
||||||
# Calling ${words[0]} instead of directly %[1]s allows to handle aliases
|
|
||||||
args=("${words[@]:1}")
|
|
||||||
requestComp="${words[0]} %[2]s ${args[*]}"
|
|
||||||
|
|
||||||
lastParam=${words[$((${#words[@]}-1))]}
|
|
||||||
lastChar=${lastParam:$((${#lastParam}-1)):1}
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}"
|
|
||||||
|
|
||||||
if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then
|
|
||||||
# If the last parameter is complete (there is a space following it)
|
|
||||||
# We add an extra empty parameter so we can indicate this to the go method.
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: Adding extra empty parameter"
|
|
||||||
requestComp="${requestComp} \"\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: calling ${requestComp}"
|
|
||||||
# Use eval to handle any environment variables and such
|
|
||||||
out=$(eval "${requestComp}" 2>/dev/null)
|
|
||||||
|
|
||||||
# Extract the directive integer at the very end of the output following a colon (:)
|
|
||||||
directive=${out##*:}
|
|
||||||
# Remove the directive
|
|
||||||
out=${out%%:*}
|
|
||||||
if [ "${directive}" = "${out}" ]; then
|
|
||||||
# There is not directive specified
|
|
||||||
directive=0
|
|
||||||
fi
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}"
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}"
|
|
||||||
|
|
||||||
if [ $((directive & %[3]d)) -ne 0 ]; then
|
|
||||||
# Error code. No completion.
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: received error from custom completion go code"
|
|
||||||
return
|
|
||||||
else
|
|
||||||
if [ $((directive & %[4]d)) -ne 0 ]; then
|
|
||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: activating no space"
|
|
||||||
compopt -o nospace
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if [ $((directive & %[5]d)) -ne 0 ]; then
|
|
||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: activating no file completion"
|
|
||||||
compopt +o default
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
while IFS='' read -r comp; do
|
|
||||||
COMPREPLY+=("$comp")
|
|
||||||
done < <(compgen -W "${out[*]}" -- "$cur")
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_reply()
|
|
||||||
{
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}"
|
|
||||||
local comp
|
|
||||||
case $cur in
|
|
||||||
-*)
|
|
||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
compopt -o nospace
|
|
||||||
fi
|
|
||||||
local allflags
|
|
||||||
if [ ${#must_have_one_flag[@]} -ne 0 ]; then
|
|
||||||
allflags=("${must_have_one_flag[@]}")
|
|
||||||
else
|
|
||||||
allflags=("${flags[*]} ${two_word_flags[*]}")
|
|
||||||
fi
|
|
||||||
while IFS='' read -r comp; do
|
|
||||||
COMPREPLY+=("$comp")
|
|
||||||
done < <(compgen -W "${allflags[*]}" -- "$cur")
|
|
||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
[[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
|
|
||||||
fi
|
|
||||||
|
|
||||||
# complete after --flag=abc
|
|
||||||
if [[ $cur == *=* ]]; then
|
|
||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
compopt +o nospace
|
|
||||||
fi
|
|
||||||
|
|
||||||
local index flag
|
|
||||||
flag="${cur%%=*}"
|
|
||||||
__%[1]s_index_of_word "${flag}" "${flags_with_completion[@]}"
|
|
||||||
COMPREPLY=()
|
|
||||||
if [[ ${index} -ge 0 ]]; then
|
|
||||||
PREFIX=""
|
|
||||||
cur="${cur#*=}"
|
|
||||||
${flags_completion[${index}]}
|
|
||||||
if [ -n "${ZSH_VERSION}" ]; then
|
|
||||||
# zsh completion needs --flag= prefix
|
|
||||||
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 0;
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# check if we are handling a flag with special work handling
|
|
||||||
local index
|
|
||||||
__%[1]s_index_of_word "${prev}" "${flags_with_completion[@]}"
|
|
||||||
if [[ ${index} -ge 0 ]]; then
|
|
||||||
${flags_completion[${index}]}
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# we are parsing a flag and don't have a special handler, no completion
|
|
||||||
if [[ ${cur} != "${words[cword]}" ]]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local completions
|
|
||||||
completions=("${commands[@]}")
|
|
||||||
if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
|
|
||||||
completions=("${must_have_one_noun[@]}")
|
|
||||||
elif [[ -n "${has_completion_function}" ]]; then
|
|
||||||
# if a go completion function is provided, defer to that function
|
|
||||||
completions=()
|
|
||||||
__%[1]s_handle_go_custom_completion
|
|
||||||
fi
|
|
||||||
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
|
|
||||||
completions+=("${must_have_one_flag[@]}")
|
|
||||||
fi
|
|
||||||
while IFS='' read -r comp; do
|
|
||||||
COMPREPLY+=("$comp")
|
|
||||||
done < <(compgen -W "${completions[*]}" -- "$cur")
|
|
||||||
|
|
||||||
if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
|
|
||||||
while IFS='' read -r comp; do
|
|
||||||
COMPREPLY+=("$comp")
|
|
||||||
done < <(compgen -W "${noun_aliases[*]}" -- "$cur")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
|
|
||||||
if declare -F __%[1]s_custom_func >/dev/null; then
|
|
||||||
# try command name qualified custom func
|
|
||||||
__%[1]s_custom_func
|
|
||||||
else
|
|
||||||
# otherwise fall back to unqualified for compatibility
|
|
||||||
declare -F __custom_func >/dev/null && __custom_func
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# available in bash-completion >= 2, not always present on macOS
|
|
||||||
if declare -F __ltrim_colon_completions >/dev/null; then
|
|
||||||
__ltrim_colon_completions "$cur"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If there is only 1 completion and it is a flag with an = it will be completed
|
|
||||||
# but we don't want a space after the =
|
|
||||||
if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then
|
|
||||||
compopt -o nospace
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# The arguments should be in the form "ext1|ext2|extn"
|
|
||||||
__%[1]s_handle_filename_extension_flag()
|
|
||||||
{
|
|
||||||
local ext="$1"
|
|
||||||
_filedir "@(${ext})"
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_subdirs_in_dir_flag()
|
|
||||||
{
|
|
||||||
local dir="$1"
|
|
||||||
pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_flag()
|
|
||||||
{
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
|
|
||||||
|
|
||||||
# if a command required a flag, and we found it, unset must_have_one_flag()
|
|
||||||
local flagname=${words[c]}
|
|
||||||
local flagvalue
|
|
||||||
# if the word contained an =
|
|
||||||
if [[ ${words[c]} == *"="* ]]; then
|
|
||||||
flagvalue=${flagname#*=} # take in as flagvalue after the =
|
|
||||||
flagname=${flagname%%=*} # strip everything after the =
|
|
||||||
flagname="${flagname}=" # but put the = back
|
|
||||||
fi
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: looking for ${flagname}"
|
|
||||||
if __%[1]s_contains_word "${flagname}" "${must_have_one_flag[@]}"; then
|
|
||||||
must_have_one_flag=()
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if you set a flag which only applies to this command, don't show subcommands
|
|
||||||
if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
|
|
||||||
commands=()
|
|
||||||
fi
|
|
||||||
|
|
||||||
# keep flag value with flagname as flaghash
|
|
||||||
# flaghash variable is an associative array which is only supported in bash > 3.
|
|
||||||
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
|
|
||||||
if [ -n "${flagvalue}" ] ; then
|
|
||||||
flaghash[${flagname}]=${flagvalue}
|
|
||||||
elif [ -n "${words[ $((c+1)) ]}" ] ; then
|
|
||||||
flaghash[${flagname}]=${words[ $((c+1)) ]}
|
|
||||||
else
|
|
||||||
flaghash[${flagname}]="true" # pad "true" for bool flag
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# skip the argument to a two word flag
|
|
||||||
if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
|
|
||||||
c=$((c+1))
|
|
||||||
# if we are looking for a flags value, don't show commands
|
|
||||||
if [[ $c -eq $cword ]]; then
|
|
||||||
commands=()
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
c=$((c+1))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_noun()
|
|
||||||
{
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
|
|
||||||
|
|
||||||
if __%[1]s_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
|
|
||||||
must_have_one_noun=()
|
|
||||||
elif __%[1]s_contains_word "${words[c]}" "${noun_aliases[@]}"; then
|
|
||||||
must_have_one_noun=()
|
|
||||||
fi
|
|
||||||
|
|
||||||
nouns+=("${words[c]}")
|
|
||||||
c=$((c+1))
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_command()
|
|
||||||
{
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
|
|
||||||
|
|
||||||
local next_command
|
|
||||||
if [[ -n ${last_command} ]]; then
|
|
||||||
next_command="_${last_command}_${words[c]//:/__}"
|
|
||||||
else
|
|
||||||
if [[ $c -eq 0 ]]; then
|
|
||||||
next_command="_%[1]s_root_command"
|
|
||||||
else
|
|
||||||
next_command="_${words[c]//:/__}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
c=$((c+1))
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: looking for ${next_command}"
|
|
||||||
declare -F "$next_command" >/dev/null && $next_command
|
|
||||||
}
|
|
||||||
|
|
||||||
__%[1]s_handle_word()
|
|
||||||
{
|
|
||||||
if [[ $c -ge $cword ]]; then
|
|
||||||
__%[1]s_handle_reply
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
__%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
|
|
||||||
if [[ "${words[c]}" == -* ]]; then
|
|
||||||
__%[1]s_handle_flag
|
|
||||||
elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then
|
|
||||||
__%[1]s_handle_command
|
|
||||||
elif [[ $c -eq 0 ]]; then
|
|
||||||
__%[1]s_handle_command
|
|
||||||
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
|
|
||||||
# aliashash variable is an associative array which is only supported in bash > 3.
|
|
||||||
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
|
|
||||||
words[c]=${aliashash[${words[c]}]}
|
|
||||||
__%[1]s_handle_command
|
|
||||||
else
|
|
||||||
__%[1]s_handle_noun
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
__%[1]s_handle_noun
|
|
||||||
fi
|
|
||||||
__%[1]s_handle_word
|
|
||||||
}
|
|
||||||
|
|
||||||
`, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
|
|
||||||
}
|
|
||||||
|
|
||||||
func writePostscript(buf *bytes.Buffer, name string) {
|
|
||||||
name = strings.Replace(name, ":", "__", -1)
|
|
||||||
buf.WriteString(fmt.Sprintf("__start_%s()\n", name))
|
|
||||||
buf.WriteString(fmt.Sprintf(`{
|
|
||||||
local cur prev words cword
|
|
||||||
declare -A flaghash 2>/dev/null || :
|
|
||||||
declare -A aliashash 2>/dev/null || :
|
|
||||||
if declare -F _init_completion >/dev/null 2>&1; then
|
|
||||||
_init_completion -s || return
|
|
||||||
else
|
|
||||||
__%[1]s_init_completion -n "=" || return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local c=0
|
|
||||||
local flags=()
|
|
||||||
local two_word_flags=()
|
|
||||||
local local_nonpersistent_flags=()
|
|
||||||
local flags_with_completion=()
|
|
||||||
local flags_completion=()
|
|
||||||
local commands=("%[1]s")
|
|
||||||
local must_have_one_flag=()
|
|
||||||
local must_have_one_noun=()
|
|
||||||
local has_completion_function
|
|
||||||
local last_command
|
|
||||||
local nouns=()
|
|
||||||
|
|
||||||
__%[1]s_handle_word
|
|
||||||
}
|
|
||||||
|
|
||||||
`, name))
|
|
||||||
buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then
|
|
||||||
complete -o default -F __start_%s %s
|
|
||||||
else
|
|
||||||
complete -o default -o nospace -F __start_%s %s
|
|
||||||
fi
|
|
||||||
|
|
||||||
`, name, name, name, name))
|
|
||||||
buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeCommands(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
buf.WriteString(" commands=()\n")
|
|
||||||
for _, c := range cmd.Commands() {
|
|
||||||
if !c.IsAvailableCommand() || c == cmd.helpCommand {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
|
||||||
writeCmdAliases(buf, c)
|
|
||||||
}
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string, cmd *Command) {
|
|
||||||
for key, value := range annotations {
|
|
||||||
switch key {
|
|
||||||
case BashCompFilenameExt:
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
|
||||||
|
|
||||||
var ext string
|
|
||||||
if len(value) > 0 {
|
|
||||||
ext = fmt.Sprintf("__%s_handle_filename_extension_flag ", cmd.Root().Name()) + strings.Join(value, "|")
|
|
||||||
} else {
|
|
||||||
ext = "_filedir"
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
|
||||||
case BashCompCustom:
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
|
||||||
if len(value) > 0 {
|
|
||||||
handlers := strings.Join(value, "; ")
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
|
|
||||||
} else {
|
|
||||||
buf.WriteString(" flags_completion+=(:)\n")
|
|
||||||
}
|
|
||||||
case BashCompSubdirsInDir:
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
|
||||||
|
|
||||||
var ext string
|
|
||||||
if len(value) == 1 {
|
|
||||||
ext = fmt.Sprintf("__%s_handle_subdirs_in_dir_flag ", cmd.Root().Name()) + value[0]
|
|
||||||
} else {
|
|
||||||
ext = "_filedir -d"
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
|
|
||||||
name := flag.Shorthand
|
|
||||||
format := " "
|
|
||||||
if len(flag.NoOptDefVal) == 0 {
|
|
||||||
format += "two_word_"
|
|
||||||
}
|
|
||||||
format += "flags+=(\"-%s\")\n"
|
|
||||||
buf.WriteString(fmt.Sprintf(format, name))
|
|
||||||
writeFlagHandler(buf, "-"+name, flag.Annotations, cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
|
|
||||||
name := flag.Name
|
|
||||||
format := " flags+=(\"--%s"
|
|
||||||
if len(flag.NoOptDefVal) == 0 {
|
|
||||||
format += "="
|
|
||||||
}
|
|
||||||
format += "\")\n"
|
|
||||||
buf.WriteString(fmt.Sprintf(format, name))
|
|
||||||
if len(flag.NoOptDefVal) == 0 {
|
|
||||||
format = " two_word_flags+=(\"--%s\")\n"
|
|
||||||
buf.WriteString(fmt.Sprintf(format, name))
|
|
||||||
}
|
|
||||||
writeFlagHandler(buf, "--"+name, flag.Annotations, cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
|
|
||||||
name := flag.Name
|
|
||||||
format := " local_nonpersistent_flags+=(\"--%s"
|
|
||||||
if len(flag.NoOptDefVal) == 0 {
|
|
||||||
format += "="
|
|
||||||
}
|
|
||||||
format += "\")\n"
|
|
||||||
buf.WriteString(fmt.Sprintf(format, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup annotations for go completions for registered flags
|
|
||||||
func prepareCustomAnnotationsForFlags(cmd *Command) {
|
|
||||||
for flag := range flagCompletionFunctions {
|
|
||||||
// Make sure the completion script calls the __*_go_custom_completion function for
|
|
||||||
// every registered flag. We need to do this here (and not when the flag was registered
|
|
||||||
// for completion) so that we can know the root command name for the prefix
|
|
||||||
// of __<prefix>_go_custom_completion
|
|
||||||
if flag.Annotations == nil {
|
|
||||||
flag.Annotations = map[string][]string{}
|
|
||||||
}
|
|
||||||
flag.Annotations[BashCompCustom] = []string{fmt.Sprintf("__%[1]s_handle_go_custom_completion", cmd.Root().Name())}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFlags(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
prepareCustomAnnotationsForFlags(cmd)
|
|
||||||
buf.WriteString(` flags=()
|
|
||||||
two_word_flags=()
|
|
||||||
local_nonpersistent_flags=()
|
|
||||||
flags_with_completion=()
|
|
||||||
flags_completion=()
|
|
||||||
|
|
||||||
`)
|
|
||||||
localNonPersistentFlags := cmd.LocalNonPersistentFlags()
|
|
||||||
cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
if nonCompletableFlag(flag) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeFlag(buf, flag, cmd)
|
|
||||||
if len(flag.Shorthand) > 0 {
|
|
||||||
writeShortFlag(buf, flag, cmd)
|
|
||||||
}
|
|
||||||
if localNonPersistentFlags.Lookup(flag.Name) != nil {
|
|
||||||
writeLocalNonPersistentFlag(buf, flag)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
if nonCompletableFlag(flag) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeFlag(buf, flag, cmd)
|
|
||||||
if len(flag.Shorthand) > 0 {
|
|
||||||
writeShortFlag(buf, flag, cmd)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
buf.WriteString(" must_have_one_flag=()\n")
|
|
||||||
flags := cmd.NonInheritedFlags()
|
|
||||||
flags.VisitAll(func(flag *pflag.Flag) {
|
|
||||||
if nonCompletableFlag(flag) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for key := range flag.Annotations {
|
|
||||||
switch key {
|
|
||||||
case BashCompOneRequiredFlag:
|
|
||||||
format := " must_have_one_flag+=(\"--%s"
|
|
||||||
if flag.Value.Type() != "bool" {
|
|
||||||
format += "="
|
|
||||||
}
|
|
||||||
format += "\")\n"
|
|
||||||
buf.WriteString(fmt.Sprintf(format, flag.Name))
|
|
||||||
|
|
||||||
if len(flag.Shorthand) > 0 {
|
|
||||||
buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
buf.WriteString(" must_have_one_noun=()\n")
|
|
||||||
sort.Sort(sort.StringSlice(cmd.ValidArgs))
|
|
||||||
for _, value := range cmd.ValidArgs {
|
|
||||||
// Remove any description that may be included following a tab character.
|
|
||||||
// Descriptions are not supported by bash completion.
|
|
||||||
value = strings.Split(value, "\t")[0]
|
|
||||||
buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
|
|
||||||
}
|
|
||||||
if cmd.ValidArgsFunction != nil {
|
|
||||||
buf.WriteString(" has_completion_function=1\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
if len(cmd.Aliases) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(sort.StringSlice(cmd.Aliases))
|
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
|
|
||||||
for _, value := range cmd.Aliases {
|
|
||||||
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
|
||||||
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
|
||||||
}
|
|
||||||
buf.WriteString(` fi`)
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
buf.WriteString(" noun_aliases=()\n")
|
|
||||||
sort.Sort(sort.StringSlice(cmd.ArgAliases))
|
|
||||||
for _, value := range cmd.ArgAliases {
|
|
||||||
buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func gen(buf *bytes.Buffer, cmd *Command) {
|
|
||||||
for _, c := range cmd.Commands() {
|
|
||||||
if !c.IsAvailableCommand() || c == cmd.helpCommand {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
gen(buf, c)
|
|
||||||
}
|
|
||||||
commandName := cmd.CommandPath()
|
|
||||||
commandName = strings.Replace(commandName, " ", "_", -1)
|
|
||||||
commandName = strings.Replace(commandName, ":", "__", -1)
|
|
||||||
|
|
||||||
if cmd.Root() == cmd {
|
|
||||||
buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName))
|
|
||||||
} else {
|
|
||||||
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
|
|
||||||
buf.WriteString("\n")
|
|
||||||
buf.WriteString(" command_aliases=()\n")
|
|
||||||
buf.WriteString("\n")
|
|
||||||
|
|
||||||
writeCommands(buf, cmd)
|
|
||||||
writeFlags(buf, cmd)
|
|
||||||
writeRequiredFlag(buf, cmd)
|
|
||||||
writeRequiredNouns(buf, cmd)
|
|
||||||
writeArgAliases(buf, cmd)
|
|
||||||
buf.WriteString("}\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenBashCompletion generates bash completion file and writes to the passed writer.
|
|
||||||
func (c *Command) GenBashCompletion(w io.Writer) error {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
writePreamble(buf, c.Name())
|
|
||||||
if len(c.BashCompletionFunction) > 0 {
|
|
||||||
buf.WriteString(c.BashCompletionFunction + "\n")
|
|
||||||
}
|
|
||||||
gen(buf, c)
|
|
||||||
writePostscript(buf, c.Name())
|
|
||||||
|
|
||||||
_, err := buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func nonCompletableFlag(flag *pflag.Flag) bool {
|
|
||||||
return flag.Hidden || len(flag.Deprecated) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenBashCompletionFile generates bash completion file.
|
|
||||||
func (c *Command) GenBashCompletionFile(filename string) error {
|
|
||||||
outFile, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer outFile.Close()
|
|
||||||
|
|
||||||
return c.GenBashCompletion(outFile)
|
|
||||||
}
|
|
383
vendor/github.com/spf13/cobra/bash_completions.md
generated
vendored
383
vendor/github.com/spf13/cobra/bash_completions.md
generated
vendored
@ -1,383 +0,0 @@
|
|||||||
# Generating Bash Completions For Your Own cobra.Command
|
|
||||||
|
|
||||||
If you are using the generator you can create a completion command by running
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cobra add completion
|
|
||||||
```
|
|
||||||
|
|
||||||
Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)
|
|
||||||
|
|
||||||
Writing the shell script to stdout allows the most flexible use.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// completionCmd represents the completion command
|
|
||||||
var completionCmd = &cobra.Command{
|
|
||||||
Use: "completion",
|
|
||||||
Short: "Generates bash completion scripts",
|
|
||||||
Long: `To load completion run
|
|
||||||
|
|
||||||
. <(bitbucket completion)
|
|
||||||
|
|
||||||
To configure your bash shell to load completions for each session add to your bashrc
|
|
||||||
|
|
||||||
# ~/.bashrc or ~/.profile
|
|
||||||
. <(bitbucket completion)
|
|
||||||
`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
rootCmd.GenBashCompletion(os.Stdout);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script
|
|
||||||
|
|
||||||
|
|
||||||
## Example from kubectl
|
|
||||||
|
|
||||||
Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kubectl := cmd.NewKubectlCommand(util.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
|
|
||||||
kubectl.GenBashCompletionFile("out.sh")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior.
|
|
||||||
|
|
||||||
## Have the completions code complete your 'nouns'
|
|
||||||
|
|
||||||
### Static completion of nouns
|
|
||||||
|
|
||||||
This method allows you to provide a pre-defined list of completion choices for your nouns using the `validArgs` field.
|
|
||||||
For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like:
|
|
||||||
|
|
||||||
```go
|
|
||||||
validArgs []string = { "pod", "node", "service", "replicationcontroller" }
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
|
|
||||||
Short: "Display one or many resources",
|
|
||||||
Long: get_long,
|
|
||||||
Example: get_example,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
err := RunGet(f, out, cmd, args)
|
|
||||||
util.CheckErr(err)
|
|
||||||
},
|
|
||||||
ValidArgs: validArgs,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# kubectl get [tab][tab]
|
|
||||||
node pod replicationcontroller service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Plural form and shortcuts for nouns
|
|
||||||
|
|
||||||
If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
...
|
|
||||||
ValidArgs: validArgs,
|
|
||||||
ArgAliases: argAliases
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
|
|
||||||
the completion algorithm if entered manually, e.g. in:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# kubectl get rc [tab][tab]
|
|
||||||
backend frontend database
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
|
|
||||||
in this example again instead of the replication controllers.
|
|
||||||
|
|
||||||
### Dynamic completion of nouns
|
|
||||||
|
|
||||||
In some cases it is not possible to provide a list of possible completions in advance. Instead, the list of completions must be determined at execution-time. Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command.
|
|
||||||
|
|
||||||
**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion. It is therefore recommended to use *Custom Completions written in Go*.
|
|
||||||
|
|
||||||
#### 1. Custom completions of nouns written in Go
|
|
||||||
|
|
||||||
In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command. Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both.
|
|
||||||
Simplified code from `helm status` looks like:
|
|
||||||
|
|
||||||
```go
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "status RELEASE_NAME",
|
|
||||||
Short: "Display the status of the named release",
|
|
||||||
Long: status_long,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) {
|
|
||||||
RunGet(args[0])
|
|
||||||
},
|
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
|
||||||
if len(args) != 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster.
|
|
||||||
Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# helm status [tab][tab]
|
|
||||||
harbor notary rook thanos
|
|
||||||
```
|
|
||||||
You may have noticed the use of `cobra.ShellCompDirective`. These directives are bit fields allowing to control some shell completion behaviors for your particular completion. You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp`
|
|
||||||
```go
|
|
||||||
// Indicates an error occurred and completions should be ignored.
|
|
||||||
ShellCompDirectiveError
|
|
||||||
// Indicates that the shell should not add a space after the completion,
|
|
||||||
// even if there is a single completion provided.
|
|
||||||
ShellCompDirectiveNoSpace
|
|
||||||
// Indicates that the shell should not provide file completion even when
|
|
||||||
// no completion is provided.
|
|
||||||
// This currently does not work for zsh or bash < 4
|
|
||||||
ShellCompDirectiveNoFileComp
|
|
||||||
// Indicates that the shell will perform its default behavior after completions
|
|
||||||
// have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp).
|
|
||||||
ShellCompDirectiveDefault
|
|
||||||
```
|
|
||||||
|
|
||||||
When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function.
|
|
||||||
|
|
||||||
##### Debugging
|
|
||||||
|
|
||||||
Cobra achieves dynamic completions written in Go through the use of a hidden command called by the completion script. To debug your Go completion code, you can call this hidden command directly:
|
|
||||||
```bash
|
|
||||||
# helm __complete status har<ENTER>
|
|
||||||
harbor
|
|
||||||
:4
|
|
||||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
|
|
||||||
```
|
|
||||||
***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command:
|
|
||||||
```bash
|
|
||||||
# helm __complete status ""<ENTER>
|
|
||||||
harbor
|
|
||||||
notary
|
|
||||||
rook
|
|
||||||
thanos
|
|
||||||
:4
|
|
||||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
|
|
||||||
```
|
|
||||||
Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code. You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code:
|
|
||||||
```go
|
|
||||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
|
|
||||||
// is set to a file path) and optionally prints to stderr.
|
|
||||||
cobra.CompDebug(msg string, printToStdErr bool) {
|
|
||||||
cobra.CompDebugln(msg string, printToStdErr bool)
|
|
||||||
|
|
||||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
|
|
||||||
// is set to a file path) and to stderr.
|
|
||||||
cobra.CompError(msg string)
|
|
||||||
cobra.CompErrorln(msg string)
|
|
||||||
```
|
|
||||||
***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned above.
|
|
||||||
|
|
||||||
#### 2. Custom completions of nouns written in Bash
|
|
||||||
|
|
||||||
This method allows you to inject bash functions into the completion script. Those bash functions are responsible for providing the completion choices for your own completions.
|
|
||||||
|
|
||||||
Some more actual code that works in kubernetes:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
const (
|
|
||||||
bash_completion_func = `__kubectl_parse_get()
|
|
||||||
{
|
|
||||||
local kubectl_output out
|
|
||||||
if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
|
|
||||||
out=($(echo "${kubectl_output}" | awk '{print $1}'))
|
|
||||||
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
__kubectl_get_resource()
|
|
||||||
{
|
|
||||||
if [[ ${#nouns[@]} -eq 0 ]]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
__kubectl_parse_get ${nouns[${#nouns[@]} -1]}
|
|
||||||
if [[ $? -eq 0 ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
__kubectl_custom_func() {
|
|
||||||
case ${last_command} in
|
|
||||||
kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
|
|
||||||
__kubectl_get_resource
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
```
|
|
||||||
|
|
||||||
And then I set that in my command definition:
|
|
||||||
|
|
||||||
```go
|
|
||||||
cmds := &cobra.Command{
|
|
||||||
Use: "kubectl",
|
|
||||||
Short: "kubectl controls the Kubernetes cluster manager",
|
|
||||||
Long: `kubectl controls the Kubernetes cluster manager.
|
|
||||||
|
|
||||||
Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
|
|
||||||
Run: runHelp,
|
|
||||||
BashCompletionFunction: bash_completion_func,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`__<command-use>_custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods!
|
|
||||||
|
|
||||||
## Mark flags as required
|
|
||||||
|
|
||||||
Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy.
|
|
||||||
|
|
||||||
```go
|
|
||||||
cmd.MarkFlagRequired("pod")
|
|
||||||
cmd.MarkFlagRequired("container")
|
|
||||||
```
|
|
||||||
|
|
||||||
and you'll get something like
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# kubectl exec [tab][tab][tab]
|
|
||||||
-c --container= -p --pod=
|
|
||||||
```
|
|
||||||
|
|
||||||
# Specify valid filename extensions for flags that take a filename
|
|
||||||
|
|
||||||
In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions.
|
|
||||||
|
|
||||||
```go
|
|
||||||
annotations := []string{"json", "yaml", "yml"}
|
|
||||||
annotation := make(map[string][]string)
|
|
||||||
annotation[cobra.BashCompFilenameExt] = annotations
|
|
||||||
|
|
||||||
flag := &pflag.Flag{
|
|
||||||
Name: "filename",
|
|
||||||
Shorthand: "f",
|
|
||||||
Usage: usage,
|
|
||||||
Value: value,
|
|
||||||
DefValue: value.String(),
|
|
||||||
Annotations: annotation,
|
|
||||||
}
|
|
||||||
cmd.Flags().AddFlag(flag)
|
|
||||||
```
|
|
||||||
|
|
||||||
Now when you run a command with this filename flag you'll get something like
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# kubectl create -f
|
|
||||||
test/ example/ rpmbuild/
|
|
||||||
hello.yml test.json
|
|
||||||
```
|
|
||||||
|
|
||||||
So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
|
|
||||||
|
|
||||||
# Specify custom flag completion
|
|
||||||
|
|
||||||
As for nouns, Cobra provides two ways of defining dynamic completion of flags. Note that both these methods can be used along-side each other as long as they are not both used for the same flag.
|
|
||||||
|
|
||||||
**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion. It is therefore recommended to use *Custom Completions written in Go*.
|
|
||||||
|
|
||||||
## 1. Custom completions of flags written in Go
|
|
||||||
|
|
||||||
To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner:
|
|
||||||
|
|
||||||
```go
|
|
||||||
flagName := "output"
|
|
||||||
cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
|
||||||
return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault
|
|
||||||
})
|
|
||||||
```
|
|
||||||
Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated. In our example this dynamic completion will give results like so:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# helm status --output [tab][tab]
|
|
||||||
json table yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debugging
|
|
||||||
|
|
||||||
You can also easily debug your Go completion code for flags:
|
|
||||||
```bash
|
|
||||||
# helm __complete status --output ""
|
|
||||||
json
|
|
||||||
table
|
|
||||||
yaml
|
|
||||||
:4
|
|
||||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
|
|
||||||
```
|
|
||||||
***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned in the above section.
|
|
||||||
|
|
||||||
## 2. Custom completions of flags written in Bash
|
|
||||||
|
|
||||||
Alternatively, you can use bash code for flag custom completion. Similar to the filename
|
|
||||||
completion and filtering using `cobra.BashCompFilenameExt`, you can specify
|
|
||||||
a custom flag completion bash function with `cobra.BashCompCustom`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
annotation := make(map[string][]string)
|
|
||||||
annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
|
|
||||||
|
|
||||||
flag := &pflag.Flag{
|
|
||||||
Name: "namespace",
|
|
||||||
Usage: usage,
|
|
||||||
Annotations: annotation,
|
|
||||||
}
|
|
||||||
cmd.Flags().AddFlag(flag)
|
|
||||||
```
|
|
||||||
|
|
||||||
In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction`
|
|
||||||
value, e.g.:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
__kubectl_get_namespaces()
|
|
||||||
{
|
|
||||||
local template
|
|
||||||
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
|
|
||||||
local kubectl_out
|
|
||||||
if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
|
|
||||||
COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
```
|
|
||||||
# Using bash aliases for commands
|
|
||||||
|
|
||||||
You can also configure the `bash aliases` for the commands and they will also support completions.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
alias aliasname=origcommand
|
|
||||||
complete -o default -F __start_origcommand aliasname
|
|
||||||
|
|
||||||
# and now when you run `aliasname` completion will make
|
|
||||||
# suggestions as it did for `origcommand`.
|
|
||||||
|
|
||||||
$) aliasname <tab><tab>
|
|
||||||
completion firstcommand secondcommand
|
|
||||||
```
|
|
207
vendor/github.com/spf13/cobra/cobra.go
generated
vendored
207
vendor/github.com/spf13/cobra/cobra.go
generated
vendored
@ -1,207 +0,0 @@
|
|||||||
// Copyright © 2013 Steve Francia <spf@spf13.com>.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Commands similar to git, go tools and other modern CLI tools
|
|
||||||
// inspired by go, go-Commander, gh and subcommand
|
|
||||||
|
|
||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"time"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
var templateFuncs = template.FuncMap{
|
|
||||||
"trim": strings.TrimSpace,
|
|
||||||
"trimRightSpace": trimRightSpace,
|
|
||||||
"trimTrailingWhitespaces": trimRightSpace,
|
|
||||||
"appendIfNotPresent": appendIfNotPresent,
|
|
||||||
"rpad": rpad,
|
|
||||||
"gt": Gt,
|
|
||||||
"eq": Eq,
|
|
||||||
}
|
|
||||||
|
|
||||||
var initializers []func()
|
|
||||||
|
|
||||||
// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing
|
|
||||||
// to automatically enable in CLI tools.
|
|
||||||
// Set this to true to enable it.
|
|
||||||
var EnablePrefixMatching = false
|
|
||||||
|
|
||||||
// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
|
|
||||||
// To disable sorting, set it to false.
|
|
||||||
var EnableCommandSorting = true
|
|
||||||
|
|
||||||
// MousetrapHelpText enables an information splash screen on Windows
|
|
||||||
// if the CLI is started from explorer.exe.
|
|
||||||
// To disable the mousetrap, just set this variable to blank string ("").
|
|
||||||
// Works only on Microsoft Windows.
|
|
||||||
var MousetrapHelpText = `This is a command line tool.
|
|
||||||
|
|
||||||
You need to open cmd.exe and run it from there.
|
|
||||||
`
|
|
||||||
|
|
||||||
// MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows
|
|
||||||
// if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed.
|
|
||||||
// To disable the mousetrap, just set MousetrapHelpText to blank string ("").
|
|
||||||
// Works only on Microsoft Windows.
|
|
||||||
var MousetrapDisplayDuration = 5 * time.Second
|
|
||||||
|
|
||||||
// AddTemplateFunc adds a template function that's available to Usage and Help
|
|
||||||
// template generation.
|
|
||||||
func AddTemplateFunc(name string, tmplFunc interface{}) {
|
|
||||||
templateFuncs[name] = tmplFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddTemplateFuncs adds multiple template functions that are available to Usage and
|
|
||||||
// Help template generation.
|
|
||||||
func AddTemplateFuncs(tmplFuncs template.FuncMap) {
|
|
||||||
for k, v := range tmplFuncs {
|
|
||||||
templateFuncs[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnInitialize sets the passed functions to be run when each command's
|
|
||||||
// Execute method is called.
|
|
||||||
func OnInitialize(y ...func()) {
|
|
||||||
initializers = append(initializers, y...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
||||||
|
|
||||||
// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
|
|
||||||
// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
|
|
||||||
// ints and then compared.
|
|
||||||
func Gt(a interface{}, b interface{}) bool {
|
|
||||||
var left, right int64
|
|
||||||
av := reflect.ValueOf(a)
|
|
||||||
|
|
||||||
switch av.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
||||||
left = int64(av.Len())
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
left = av.Int()
|
|
||||||
case reflect.String:
|
|
||||||
left, _ = strconv.ParseInt(av.String(), 10, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
bv := reflect.ValueOf(b)
|
|
||||||
|
|
||||||
switch bv.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
||||||
right = int64(bv.Len())
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
right = bv.Int()
|
|
||||||
case reflect.String:
|
|
||||||
right, _ = strconv.ParseInt(bv.String(), 10, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
return left > right
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
||||||
|
|
||||||
// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
|
|
||||||
func Eq(a interface{}, b interface{}) bool {
|
|
||||||
av := reflect.ValueOf(a)
|
|
||||||
bv := reflect.ValueOf(b)
|
|
||||||
|
|
||||||
switch av.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
||||||
panic("Eq called on unsupported type")
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return av.Int() == bv.Int()
|
|
||||||
case reflect.String:
|
|
||||||
return av.String() == bv.String()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func trimRightSpace(s string) string {
|
|
||||||
return strings.TrimRightFunc(s, unicode.IsSpace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
||||||
|
|
||||||
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
|
|
||||||
func appendIfNotPresent(s, stringToAppend string) string {
|
|
||||||
if strings.Contains(s, stringToAppend) {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s + " " + stringToAppend
|
|
||||||
}
|
|
||||||
|
|
||||||
// rpad adds padding to the right of a string.
|
|
||||||
func rpad(s string, padding int) string {
|
|
||||||
template := fmt.Sprintf("%%-%ds", padding)
|
|
||||||
return fmt.Sprintf(template, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// tmpl executes the given template text on data, writing the result to w.
|
|
||||||
func tmpl(w io.Writer, text string, data interface{}) error {
|
|
||||||
t := template.New("top")
|
|
||||||
t.Funcs(templateFuncs)
|
|
||||||
template.Must(t.Parse(text))
|
|
||||||
return t.Execute(w, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ld compares two strings and returns the levenshtein distance between them.
|
|
||||||
func ld(s, t string, ignoreCase bool) int {
|
|
||||||
if ignoreCase {
|
|
||||||
s = strings.ToLower(s)
|
|
||||||
t = strings.ToLower(t)
|
|
||||||
}
|
|
||||||
d := make([][]int, len(s)+1)
|
|
||||||
for i := range d {
|
|
||||||
d[i] = make([]int, len(t)+1)
|
|
||||||
}
|
|
||||||
for i := range d {
|
|
||||||
d[i][0] = i
|
|
||||||
}
|
|
||||||
for j := range d[0] {
|
|
||||||
d[0][j] = j
|
|
||||||
}
|
|
||||||
for j := 1; j <= len(t); j++ {
|
|
||||||
for i := 1; i <= len(s); i++ {
|
|
||||||
if s[i-1] == t[j-1] {
|
|
||||||
d[i][j] = d[i-1][j-1]
|
|
||||||
} else {
|
|
||||||
min := d[i-1][j]
|
|
||||||
if d[i][j-1] < min {
|
|
||||||
min = d[i][j-1]
|
|
||||||
}
|
|
||||||
if d[i-1][j-1] < min {
|
|
||||||
min = d[i-1][j-1]
|
|
||||||
}
|
|
||||||
d[i][j] = min + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return d[len(s)][len(t)]
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringInSlice(a string, list []string) bool {
|
|
||||||
for _, b := range list {
|
|
||||||
if b == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
1634
vendor/github.com/spf13/cobra/command.go
generated
vendored
1634
vendor/github.com/spf13/cobra/command.go
generated
vendored
File diff suppressed because it is too large
Load Diff
5
vendor/github.com/spf13/cobra/command_notwin.go
generated
vendored
5
vendor/github.com/spf13/cobra/command_notwin.go
generated
vendored
@ -1,5 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package cobra
|
|
||||||
|
|
||||||
var preExecHookFn func(*Command)
|
|
26
vendor/github.com/spf13/cobra/command_win.go
generated
vendored
26
vendor/github.com/spf13/cobra/command_win.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/inconshreveable/mousetrap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var preExecHookFn = preExecHook
|
|
||||||
|
|
||||||
func preExecHook(c *Command) {
|
|
||||||
if MousetrapHelpText != "" && mousetrap.StartedByExplorer() {
|
|
||||||
c.Print(MousetrapHelpText)
|
|
||||||
if MousetrapDisplayDuration > 0 {
|
|
||||||
time.Sleep(MousetrapDisplayDuration)
|
|
||||||
} else {
|
|
||||||
c.Println("Press return to continue...")
|
|
||||||
fmt.Scanln()
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
384
vendor/github.com/spf13/cobra/custom_completions.go
generated
vendored
384
vendor/github.com/spf13/cobra/custom_completions.go
generated
vendored
@ -1,384 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ShellCompRequestCmd is the name of the hidden command that is used to request
|
|
||||||
// completion results from the program. It is used by the shell completion scripts.
|
|
||||||
ShellCompRequestCmd = "__complete"
|
|
||||||
// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request
|
|
||||||
// completion results without their description. It is used by the shell completion scripts.
|
|
||||||
ShellCompNoDescRequestCmd = "__completeNoDesc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Global map of flag completion functions.
|
|
||||||
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
|
|
||||||
|
|
||||||
// ShellCompDirective is a bit map representing the different behaviors the shell
|
|
||||||
// can be instructed to have once completions have been provided.
|
|
||||||
type ShellCompDirective int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ShellCompDirectiveError indicates an error occurred and completions should be ignored.
|
|
||||||
ShellCompDirectiveError ShellCompDirective = 1 << iota
|
|
||||||
|
|
||||||
// ShellCompDirectiveNoSpace indicates that the shell should not add a space
|
|
||||||
// after the completion even if there is a single completion provided.
|
|
||||||
ShellCompDirectiveNoSpace
|
|
||||||
|
|
||||||
// ShellCompDirectiveNoFileComp indicates that the shell should not provide
|
|
||||||
// file completion even when no completion is provided.
|
|
||||||
// This currently does not work for zsh or bash < 4
|
|
||||||
ShellCompDirectiveNoFileComp
|
|
||||||
|
|
||||||
// ShellCompDirectiveDefault indicates to let the shell perform its default
|
|
||||||
// behavior after completions have been provided.
|
|
||||||
ShellCompDirectiveDefault ShellCompDirective = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
|
|
||||||
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
|
|
||||||
flag := c.Flag(flagName)
|
|
||||||
if flag == nil {
|
|
||||||
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
|
|
||||||
}
|
|
||||||
if _, exists := flagCompletionFunctions[flag]; exists {
|
|
||||||
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName)
|
|
||||||
}
|
|
||||||
flagCompletionFunctions[flag] = f
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a string listing the different directive enabled in the specified parameter
|
|
||||||
func (d ShellCompDirective) string() string {
|
|
||||||
var directives []string
|
|
||||||
if d&ShellCompDirectiveError != 0 {
|
|
||||||
directives = append(directives, "ShellCompDirectiveError")
|
|
||||||
}
|
|
||||||
if d&ShellCompDirectiveNoSpace != 0 {
|
|
||||||
directives = append(directives, "ShellCompDirectiveNoSpace")
|
|
||||||
}
|
|
||||||
if d&ShellCompDirectiveNoFileComp != 0 {
|
|
||||||
directives = append(directives, "ShellCompDirectiveNoFileComp")
|
|
||||||
}
|
|
||||||
if len(directives) == 0 {
|
|
||||||
directives = append(directives, "ShellCompDirectiveDefault")
|
|
||||||
}
|
|
||||||
|
|
||||||
if d > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
|
|
||||||
return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d)
|
|
||||||
}
|
|
||||||
return strings.Join(directives, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a special hidden command that can be used to request custom completions.
|
|
||||||
func (c *Command) initCompleteCmd(args []string) {
|
|
||||||
completeCmd := &Command{
|
|
||||||
Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd),
|
|
||||||
Aliases: []string{ShellCompNoDescRequestCmd},
|
|
||||||
DisableFlagsInUseLine: true,
|
|
||||||
Hidden: true,
|
|
||||||
DisableFlagParsing: true,
|
|
||||||
Args: MinimumNArgs(1),
|
|
||||||
Short: "Request shell completion choices for the specified command-line",
|
|
||||||
Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s",
|
|
||||||
"to request completion choices for the specified command-line.", ShellCompRequestCmd),
|
|
||||||
Run: func(cmd *Command, args []string) {
|
|
||||||
finalCmd, completions, directive, err := cmd.getCompletions(args)
|
|
||||||
if err != nil {
|
|
||||||
CompErrorln(err.Error())
|
|
||||||
// Keep going for multiple reasons:
|
|
||||||
// 1- There could be some valid completions even though there was an error
|
|
||||||
// 2- Even without completions, we need to print the directive
|
|
||||||
}
|
|
||||||
|
|
||||||
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
|
|
||||||
for _, comp := range completions {
|
|
||||||
if noDescriptions {
|
|
||||||
// Remove any description that may be included following a tab character.
|
|
||||||
comp = strings.Split(comp, "\t")[0]
|
|
||||||
}
|
|
||||||
// Print each possible completion to stdout for the completion script to consume.
|
|
||||||
fmt.Fprintln(finalCmd.OutOrStdout(), comp)
|
|
||||||
}
|
|
||||||
|
|
||||||
if directive > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
|
|
||||||
directive = ShellCompDirectiveDefault
|
|
||||||
}
|
|
||||||
|
|
||||||
// As the last printout, print the completion directive for the completion script to parse.
|
|
||||||
// The directive integer must be that last character following a single colon (:).
|
|
||||||
// The completion script expects :<directive>
|
|
||||||
fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive)
|
|
||||||
|
|
||||||
// Print some helpful info to stderr for the user to understand.
|
|
||||||
// Output from stderr must be ignored by the completion script.
|
|
||||||
fmt.Fprintf(finalCmd.ErrOrStderr(), "Completion ended with directive: %s\n", directive.string())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
c.AddCommand(completeCmd)
|
|
||||||
subCmd, _, err := c.Find(args)
|
|
||||||
if err != nil || subCmd.Name() != ShellCompRequestCmd {
|
|
||||||
// Only create this special command if it is actually being called.
|
|
||||||
// This reduces possible side-effects of creating such a command;
|
|
||||||
// for example, having this command would cause problems to a
|
|
||||||
// cobra program that only consists of the root command, since this
|
|
||||||
// command would cause the root command to suddenly have a subcommand.
|
|
||||||
c.RemoveCommand(completeCmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) {
|
|
||||||
var completions []string
|
|
||||||
|
|
||||||
// The last argument, which is not completely typed by the user,
|
|
||||||
// should not be part of the list of arguments
|
|
||||||
toComplete := args[len(args)-1]
|
|
||||||
trimmedArgs := args[:len(args)-1]
|
|
||||||
|
|
||||||
// Find the real command for which completion must be performed
|
|
||||||
finalCmd, finalArgs, err := c.Root().Find(trimmedArgs)
|
|
||||||
if err != nil {
|
|
||||||
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
|
|
||||||
return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// When doing completion of a flag name, as soon as an argument starts with
|
|
||||||
// a '-' we know it is a flag. We cannot use isFlagArg() here as it requires
|
|
||||||
// the flag to be complete
|
|
||||||
if len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") {
|
|
||||||
// We are completing a flag name
|
|
||||||
finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
|
|
||||||
})
|
|
||||||
finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
|
|
||||||
})
|
|
||||||
|
|
||||||
directive := ShellCompDirectiveDefault
|
|
||||||
if len(completions) > 0 {
|
|
||||||
if strings.HasSuffix(completions[0], "=") {
|
|
||||||
directive = ShellCompDirectiveNoSpace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return finalCmd, completions, directive, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var flag *pflag.Flag
|
|
||||||
if !finalCmd.DisableFlagParsing {
|
|
||||||
// We only do flag completion if we are allowed to parse flags
|
|
||||||
// This is important for commands which have requested to do their own flag completion.
|
|
||||||
flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete)
|
|
||||||
if err != nil {
|
|
||||||
// Error while attempting to parse flags
|
|
||||||
return finalCmd, completions, ShellCompDirectiveDefault, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flag == nil {
|
|
||||||
// Complete subcommand names
|
|
||||||
for _, subCmd := range finalCmd.Commands() {
|
|
||||||
if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) {
|
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(finalCmd.ValidArgs) > 0 {
|
|
||||||
// Always complete ValidArgs, even if we are completing a subcommand name.
|
|
||||||
// This is for commands that have both subcommands and ValidArgs.
|
|
||||||
for _, validArg := range finalCmd.ValidArgs {
|
|
||||||
if strings.HasPrefix(validArg, toComplete) {
|
|
||||||
completions = append(completions, validArg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are ValidArgs specified (even if they don't match), we stop completion.
|
|
||||||
// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
|
|
||||||
return finalCmd, completions, ShellCompDirectiveNoFileComp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always let the logic continue so as to add any ValidArgsFunction completions,
|
|
||||||
// even if we already found sub-commands.
|
|
||||||
// This is for commands that have subcommands but also specify a ValidArgsFunction.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the flags and extract the arguments to prepare for calling the completion function
|
|
||||||
if err = finalCmd.ParseFlags(finalArgs); err != nil {
|
|
||||||
return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only remove the flags from the arguments if DisableFlagParsing is not set.
|
|
||||||
// This is important for commands which have requested to do their own flag completion.
|
|
||||||
if !finalCmd.DisableFlagParsing {
|
|
||||||
finalArgs = finalCmd.Flags().Args()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the completion function for the flag or command
|
|
||||||
var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
|
|
||||||
if flag != nil {
|
|
||||||
completionFn = flagCompletionFunctions[flag]
|
|
||||||
} else {
|
|
||||||
completionFn = finalCmd.ValidArgsFunction
|
|
||||||
}
|
|
||||||
if completionFn == nil {
|
|
||||||
// Go custom completion not supported/needed for this flag or command
|
|
||||||
return finalCmd, completions, ShellCompDirectiveDefault, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the registered completion function to get the completions
|
|
||||||
comps, directive := completionFn(finalCmd, finalArgs, toComplete)
|
|
||||||
completions = append(completions, comps...)
|
|
||||||
return finalCmd, completions, directive, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
|
|
||||||
if nonCompletableFlag(flag) {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var completions []string
|
|
||||||
flagName := "--" + flag.Name
|
|
||||||
if strings.HasPrefix(flagName, toComplete) {
|
|
||||||
// Flag without the =
|
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
|
|
||||||
|
|
||||||
if len(flag.NoOptDefVal) == 0 {
|
|
||||||
// Flag requires a value, so it can be suffixed with =
|
|
||||||
flagName += "="
|
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flagName = "-" + flag.Shorthand
|
|
||||||
if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) {
|
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
|
|
||||||
}
|
|
||||||
|
|
||||||
return completions
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) {
|
|
||||||
var flagName string
|
|
||||||
trimmedArgs := args
|
|
||||||
flagWithEqual := false
|
|
||||||
if isFlagArg(lastArg) {
|
|
||||||
if index := strings.Index(lastArg, "="); index >= 0 {
|
|
||||||
flagName = strings.TrimLeft(lastArg[:index], "-")
|
|
||||||
lastArg = lastArg[index+1:]
|
|
||||||
flagWithEqual = true
|
|
||||||
} else {
|
|
||||||
return nil, nil, "", errors.New("Unexpected completion request for flag")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(flagName) == 0 {
|
|
||||||
if len(args) > 0 {
|
|
||||||
prevArg := args[len(args)-1]
|
|
||||||
if isFlagArg(prevArg) {
|
|
||||||
// Only consider the case where the flag does not contain an =.
|
|
||||||
// If the flag contains an = it means it has already been fully processed,
|
|
||||||
// so we don't need to deal with it here.
|
|
||||||
if index := strings.Index(prevArg, "="); index < 0 {
|
|
||||||
flagName = strings.TrimLeft(prevArg, "-")
|
|
||||||
|
|
||||||
// Remove the uncompleted flag or else there could be an error created
|
|
||||||
// for an invalid value for that flag
|
|
||||||
trimmedArgs = args[:len(args)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(flagName) == 0 {
|
|
||||||
// Not doing flag completion
|
|
||||||
return nil, trimmedArgs, lastArg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
flag := findFlag(finalCmd, flagName)
|
|
||||||
if flag == nil {
|
|
||||||
// Flag not supported by this command, nothing to complete
|
|
||||||
err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName)
|
|
||||||
return nil, nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !flagWithEqual {
|
|
||||||
if len(flag.NoOptDefVal) != 0 {
|
|
||||||
// We had assumed dealing with a two-word flag but the flag is a boolean flag.
|
|
||||||
// In that case, there is no value following it, so we are not really doing flag completion.
|
|
||||||
// Reset everything to do noun completion.
|
|
||||||
trimmedArgs = args
|
|
||||||
flag = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return flag, trimmedArgs, lastArg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findFlag(cmd *Command, name string) *pflag.Flag {
|
|
||||||
flagSet := cmd.Flags()
|
|
||||||
if len(name) == 1 {
|
|
||||||
// First convert the short flag into a long flag
|
|
||||||
// as the cmd.Flag() search only accepts long flags
|
|
||||||
if short := flagSet.ShorthandLookup(name); short != nil {
|
|
||||||
name = short.Name
|
|
||||||
} else {
|
|
||||||
set := cmd.InheritedFlags()
|
|
||||||
if short = set.ShorthandLookup(name); short != nil {
|
|
||||||
name = short.Name
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cmd.Flag(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompDebug prints the specified string to the same file as where the
|
|
||||||
// completion script prints its logs.
|
|
||||||
// Note that completion printouts should never be on stdout as they would
|
|
||||||
// be wrongly interpreted as actual completion choices by the completion script.
|
|
||||||
func CompDebug(msg string, printToStdErr bool) {
|
|
||||||
msg = fmt.Sprintf("[Debug] %s", msg)
|
|
||||||
|
|
||||||
// Such logs are only printed when the user has set the environment
|
|
||||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
|
||||||
if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" {
|
|
||||||
f, err := os.OpenFile(path,
|
|
||||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err == nil {
|
|
||||||
defer f.Close()
|
|
||||||
f.WriteString(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if printToStdErr {
|
|
||||||
// Must print to stderr for this not to be read by the completion script.
|
|
||||||
fmt.Fprintf(os.Stderr, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompDebugln prints the specified string with a newline at the end
|
|
||||||
// to the same file as where the completion script prints its logs.
|
|
||||||
// Such logs are only printed when the user has set the environment
|
|
||||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
|
||||||
func CompDebugln(msg string, printToStdErr bool) {
|
|
||||||
CompDebug(fmt.Sprintf("%s\n", msg), printToStdErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompError prints the specified completion message to stderr.
|
|
||||||
func CompError(msg string) {
|
|
||||||
msg = fmt.Sprintf("[Error] %s", msg)
|
|
||||||
CompDebug(msg, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompErrorln prints the specified completion message to stderr with a newline at the end.
|
|
||||||
func CompErrorln(msg string) {
|
|
||||||
CompError(fmt.Sprintf("%s\n", msg))
|
|
||||||
}
|
|
172
vendor/github.com/spf13/cobra/fish_completions.go
generated
vendored
172
vendor/github.com/spf13/cobra/fish_completions.go
generated
vendored
@ -1,172 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
|
||||||
compCmd := ShellCompRequestCmd
|
|
||||||
if !includeDesc {
|
|
||||||
compCmd = ShellCompNoDescRequestCmd
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
|
|
||||||
buf.WriteString(fmt.Sprintf(`
|
|
||||||
function __%[1]s_debug
|
|
||||||
set file "$BASH_COMP_DEBUG_FILE"
|
|
||||||
if test -n "$file"
|
|
||||||
echo "$argv" >> $file
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function __%[1]s_perform_completion
|
|
||||||
__%[1]s_debug "Starting __%[1]s_perform_completion with: $argv"
|
|
||||||
|
|
||||||
set args (string split -- " " "$argv")
|
|
||||||
set lastArg "$args[-1]"
|
|
||||||
|
|
||||||
__%[1]s_debug "args: $args"
|
|
||||||
__%[1]s_debug "last arg: $lastArg"
|
|
||||||
|
|
||||||
set emptyArg ""
|
|
||||||
if test -z "$lastArg"
|
|
||||||
__%[1]s_debug "Setting emptyArg"
|
|
||||||
set emptyArg \"\"
|
|
||||||
end
|
|
||||||
__%[1]s_debug "emptyArg: $emptyArg"
|
|
||||||
|
|
||||||
set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg"
|
|
||||||
__%[1]s_debug "Calling $requestComp"
|
|
||||||
|
|
||||||
set results (eval $requestComp 2> /dev/null)
|
|
||||||
set comps $results[1..-2]
|
|
||||||
set directiveLine $results[-1]
|
|
||||||
|
|
||||||
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
|
|
||||||
# completions must be prefixed with the flag
|
|
||||||
set flagPrefix (string match -r -- '-.*=' "$lastArg")
|
|
||||||
|
|
||||||
__%[1]s_debug "Comps: $comps"
|
|
||||||
__%[1]s_debug "DirectiveLine: $directiveLine"
|
|
||||||
__%[1]s_debug "flagPrefix: $flagPrefix"
|
|
||||||
|
|
||||||
for comp in $comps
|
|
||||||
printf "%%s%%s\n" "$flagPrefix" "$comp"
|
|
||||||
end
|
|
||||||
|
|
||||||
printf "%%s\n" "$directiveLine"
|
|
||||||
end
|
|
||||||
|
|
||||||
# This function does three things:
|
|
||||||
# 1- Obtain the completions and store them in the global __%[1]s_comp_results
|
|
||||||
# 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed
|
|
||||||
# and unset it otherwise
|
|
||||||
# 3- Return true if the completion results are not empty
|
|
||||||
function __%[1]s_prepare_completions
|
|
||||||
# Start fresh
|
|
||||||
set --erase __%[1]s_comp_do_file_comp
|
|
||||||
set --erase __%[1]s_comp_results
|
|
||||||
|
|
||||||
# Check if the command-line is already provided. This is useful for testing.
|
|
||||||
if not set --query __%[1]s_comp_commandLine
|
|
||||||
set __%[1]s_comp_commandLine (commandline)
|
|
||||||
end
|
|
||||||
__%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine"
|
|
||||||
|
|
||||||
set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine")
|
|
||||||
set --erase __%[1]s_comp_commandLine
|
|
||||||
__%[1]s_debug "Completion results: $results"
|
|
||||||
|
|
||||||
if test -z "$results"
|
|
||||||
__%[1]s_debug "No completion, probably due to a failure"
|
|
||||||
# Might as well do file completion, in case it helps
|
|
||||||
set --global __%[1]s_comp_do_file_comp 1
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
set directive (string sub --start 2 $results[-1])
|
|
||||||
set --global __%[1]s_comp_results $results[1..-2]
|
|
||||||
|
|
||||||
__%[1]s_debug "Completions are: $__%[1]s_comp_results"
|
|
||||||
__%[1]s_debug "Directive is: $directive"
|
|
||||||
|
|
||||||
if test -z "$directive"
|
|
||||||
set directive 0
|
|
||||||
end
|
|
||||||
|
|
||||||
set compErr (math (math --scale 0 $directive / %[3]d) %% 2)
|
|
||||||
if test $compErr -eq 1
|
|
||||||
__%[1]s_debug "Received error directive: aborting."
|
|
||||||
# Might as well do file completion, in case it helps
|
|
||||||
set --global __%[1]s_comp_do_file_comp 1
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
set nospace (math (math --scale 0 $directive / %[4]d) %% 2)
|
|
||||||
set nofiles (math (math --scale 0 $directive / %[5]d) %% 2)
|
|
||||||
|
|
||||||
__%[1]s_debug "nospace: $nospace, nofiles: $nofiles"
|
|
||||||
|
|
||||||
# Important not to quote the variable for count to work
|
|
||||||
set numComps (count $__%[1]s_comp_results)
|
|
||||||
__%[1]s_debug "numComps: $numComps"
|
|
||||||
|
|
||||||
if test $numComps -eq 1; and test $nospace -ne 0
|
|
||||||
# To support the "nospace" directive we trick the shell
|
|
||||||
# by outputting an extra, longer completion.
|
|
||||||
__%[1]s_debug "Adding second completion to perform nospace directive"
|
|
||||||
set --append __%[1]s_comp_results $__%[1]s_comp_results[1].
|
|
||||||
end
|
|
||||||
|
|
||||||
if test $numComps -eq 0; and test $nofiles -eq 0
|
|
||||||
__%[1]s_debug "Requesting file completion"
|
|
||||||
set --global __%[1]s_comp_do_file_comp 1
|
|
||||||
end
|
|
||||||
|
|
||||||
# If we don't want file completion, we must return true even if there
|
|
||||||
# are no completions found. This is because fish will perform the last
|
|
||||||
# completion command, even if its condition is false, if no other
|
|
||||||
# completion command was triggered
|
|
||||||
return (not set --query __%[1]s_comp_do_file_comp)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Remove any pre-existing completions for the program since we will be handling all of them
|
|
||||||
# TODO this cleanup is not sufficient. Fish completions are only loaded once the user triggers
|
|
||||||
# them, so the below deletion will not work as it is run too early. What else can we do?
|
|
||||||
complete -c %[1]s -e
|
|
||||||
|
|
||||||
# The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions
|
|
||||||
# is called first. It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable.
|
|
||||||
#
|
|
||||||
# This completion will be run second as complete commands are added FILO.
|
|
||||||
# It triggers file completion choices when __%[1]s_comp_do_file_comp is set.
|
|
||||||
complete -c %[1]s -n 'set --query __%[1]s_comp_do_file_comp'
|
|
||||||
|
|
||||||
# This completion will be run first as complete commands are added FILO.
|
|
||||||
# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results abd __%[1]s_comp_do_file_comp.
|
|
||||||
# It provides the program's completion choices.
|
|
||||||
complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
|
|
||||||
|
|
||||||
`, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenFishCompletion generates fish completion file and writes to the passed writer.
|
|
||||||
func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
genFishComp(buf, c.Name(), includeDesc)
|
|
||||||
_, err := buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenFishCompletionFile generates fish completion file.
|
|
||||||
func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error {
|
|
||||||
outFile, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer outFile.Close()
|
|
||||||
|
|
||||||
return c.GenFishCompletion(outFile, includeDesc)
|
|
||||||
}
|
|
7
vendor/github.com/spf13/cobra/fish_completions.md
generated
vendored
7
vendor/github.com/spf13/cobra/fish_completions.md
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
## Generating Fish Completions for your own cobra.Command
|
|
||||||
|
|
||||||
Cobra supports native Fish completions generated from the root `cobra.Command`. You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users.
|
|
||||||
|
|
||||||
### Limitations
|
|
||||||
|
|
||||||
* Custom completions implemented using the `ValidArgsFunction` and `RegisterFlagCompletionFunc()` are supported automatically but the ones implemented in Bash scripting are not.
|
|
12
vendor/github.com/spf13/cobra/go.mod
generated
vendored
12
vendor/github.com/spf13/cobra/go.mod
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
module github.com/spf13/cobra
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
|
||||||
github.com/spf13/pflag v1.0.3
|
|
||||||
github.com/spf13/viper v1.4.0
|
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
|
||||||
)
|
|
149
vendor/github.com/spf13/cobra/go.sum
generated
vendored
149
vendor/github.com/spf13/cobra/go.sum
generated
vendored
@ -1,149 +0,0 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
100
vendor/github.com/spf13/cobra/powershell_completions.go
generated
vendored
100
vendor/github.com/spf13/cobra/powershell_completions.go
generated
vendored
@ -1,100 +0,0 @@
|
|||||||
// PowerShell completions are based on the amazing work from clap:
|
|
||||||
// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs
|
|
||||||
//
|
|
||||||
// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
|
|
||||||
// can be downloaded separately for windows 7 or 8.1).
|
|
||||||
|
|
||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var powerShellCompletionTemplate = `using namespace System.Management.Automation
|
|
||||||
using namespace System.Management.Automation.Language
|
|
||||||
Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
|
|
||||||
param($wordToComplete, $commandAst, $cursorPosition)
|
|
||||||
$commandElements = $commandAst.CommandElements
|
|
||||||
$command = @(
|
|
||||||
'%s'
|
|
||||||
for ($i = 1; $i -lt $commandElements.Count; $i++) {
|
|
||||||
$element = $commandElements[$i]
|
|
||||||
if ($element -isnot [StringConstantExpressionAst] -or
|
|
||||||
$element.StringConstantType -ne [StringConstantType]::BareWord -or
|
|
||||||
$element.Value.StartsWith('-')) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
$element.Value
|
|
||||||
}
|
|
||||||
) -join ';'
|
|
||||||
$completions = @(switch ($command) {%s
|
|
||||||
})
|
|
||||||
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
|
||||||
Sort-Object -Property ListItemText
|
|
||||||
}`
|
|
||||||
|
|
||||||
func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) {
|
|
||||||
var cmdName string
|
|
||||||
if previousCommandName == "" {
|
|
||||||
cmdName = cmd.Name()
|
|
||||||
} else {
|
|
||||||
cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(out, "\n '%s' {", cmdName)
|
|
||||||
|
|
||||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
if nonCompletableFlag(flag) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
usage := escapeStringForPowerShell(flag.Usage)
|
|
||||||
if len(flag.Shorthand) > 0 {
|
|
||||||
fmt.Fprintf(out, "\n [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(out, "\n [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, subCmd := range cmd.Commands() {
|
|
||||||
usage := escapeStringForPowerShell(subCmd.Short)
|
|
||||||
fmt.Fprintf(out, "\n [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(out, "\n break\n }")
|
|
||||||
|
|
||||||
for _, subCmd := range cmd.Commands() {
|
|
||||||
generatePowerShellSubcommandCases(out, subCmd, cmdName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func escapeStringForPowerShell(s string) string {
|
|
||||||
return strings.Replace(s, "'", "''", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer.
|
|
||||||
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
var subCommandCases bytes.Buffer
|
|
||||||
generatePowerShellSubcommandCases(&subCommandCases, c, "")
|
|
||||||
fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String())
|
|
||||||
|
|
||||||
_, err := buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenPowerShellCompletionFile generates PowerShell completion file.
|
|
||||||
func (c *Command) GenPowerShellCompletionFile(filename string) error {
|
|
||||||
outFile, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer outFile.Close()
|
|
||||||
|
|
||||||
return c.GenPowerShellCompletion(outFile)
|
|
||||||
}
|
|
14
vendor/github.com/spf13/cobra/powershell_completions.md
generated
vendored
14
vendor/github.com/spf13/cobra/powershell_completions.md
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
# Generating PowerShell Completions For Your Own cobra.Command
|
|
||||||
|
|
||||||
Cobra can generate PowerShell completion scripts. Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles.
|
|
||||||
|
|
||||||
# What's supported
|
|
||||||
|
|
||||||
- Completion for subcommands using their `.Short` description
|
|
||||||
- Completion for non-hidden flags using their `.Name` and `.Shorthand`
|
|
||||||
|
|
||||||
# What's not yet supported
|
|
||||||
|
|
||||||
- Command aliases
|
|
||||||
- Required, filename or custom flags (they will work like normal flags)
|
|
||||||
- Custom completion scripts
|
|
85
vendor/github.com/spf13/cobra/shell_completions.go
generated
vendored
85
vendor/github.com/spf13/cobra/shell_completions.go
generated
vendored
@ -1,85 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
|
|
||||||
// and causes your command to report an error if invoked without the flag.
|
|
||||||
func (c *Command) MarkFlagRequired(name string) error {
|
|
||||||
return MarkFlagRequired(c.Flags(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
|
|
||||||
// and causes your command to report an error if invoked without the flag.
|
|
||||||
func (c *Command) MarkPersistentFlagRequired(name string) error {
|
|
||||||
return MarkFlagRequired(c.PersistentFlags(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
|
|
||||||
// and causes your command to report an error if invoked without the flag.
|
|
||||||
func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
|
|
||||||
return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
|
|
||||||
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
|
|
||||||
func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
|
|
||||||
return MarkFlagFilename(c.Flags(), name, extensions...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
|
|
||||||
// Generated bash autocompletion will call the bash function f for the flag.
|
|
||||||
func (c *Command) MarkFlagCustom(name string, f string) error {
|
|
||||||
return MarkFlagCustom(c.Flags(), name, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkPersistentFlagFilename instructs the various shell completion
|
|
||||||
// implementations to limit completions for this persistent flag to the
|
|
||||||
// specified extensions (patterns).
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: bash, zsh
|
|
||||||
func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
|
|
||||||
return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagFilename instructs the various shell completion implementations to
|
|
||||||
// limit completions for this flag to the specified extensions (patterns).
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: bash, zsh
|
|
||||||
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
|
|
||||||
return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagCustom instructs the various shell completion implementations to
|
|
||||||
// limit completions for this flag to the specified extensions (patterns).
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: bash, zsh
|
|
||||||
func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
|
|
||||||
return flags.SetAnnotation(name, BashCompCustom, []string{f})
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagDirname instructs the various shell completion implementations to
|
|
||||||
// complete only directories with this named flag.
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: zsh
|
|
||||||
func (c *Command) MarkFlagDirname(name string) error {
|
|
||||||
return MarkFlagDirname(c.Flags(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkPersistentFlagDirname instructs the various shell completion
|
|
||||||
// implementations to complete only directories with this persistent named flag.
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: zsh
|
|
||||||
func (c *Command) MarkPersistentFlagDirname(name string) error {
|
|
||||||
return MarkFlagDirname(c.PersistentFlags(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkFlagDirname instructs the various shell completion implementations to
|
|
||||||
// complete only directories with this specified flag.
|
|
||||||
//
|
|
||||||
// Shell Completion compatibility matrix: zsh
|
|
||||||
func MarkFlagDirname(flags *pflag.FlagSet, name string) error {
|
|
||||||
zshPattern := "-(/)"
|
|
||||||
return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern})
|
|
||||||
}
|
|
336
vendor/github.com/spf13/cobra/zsh_completions.go
generated
vendored
336
vendor/github.com/spf13/cobra/zsh_completions.go
generated
vendored
@ -1,336 +0,0 @@
|
|||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
zshCompArgumentAnnotation = "cobra_annotations_zsh_completion_argument_annotation"
|
|
||||||
zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion"
|
|
||||||
zshCompArgumentWordComp = "cobra_annotations_zsh_completion_argument_word_completion"
|
|
||||||
zshCompDirname = "cobra_annotations_zsh_dirname"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
zshCompFuncMap = template.FuncMap{
|
|
||||||
"genZshFuncName": zshCompGenFuncName,
|
|
||||||
"extractFlags": zshCompExtractFlag,
|
|
||||||
"genFlagEntryForZshArguments": zshCompGenFlagEntryForArguments,
|
|
||||||
"extractArgsCompletions": zshCompExtractArgumentCompletionHintsForRendering,
|
|
||||||
}
|
|
||||||
zshCompletionText = `
|
|
||||||
{{/* should accept Command (that contains subcommands) as parameter */}}
|
|
||||||
{{define "argumentsC" -}}
|
|
||||||
{{ $cmdPath := genZshFuncName .}}
|
|
||||||
function {{$cmdPath}} {
|
|
||||||
local -a commands
|
|
||||||
|
|
||||||
_arguments -C \{{- range extractFlags .}}
|
|
||||||
{{genFlagEntryForZshArguments .}} \{{- end}}
|
|
||||||
"1: :->cmnds" \
|
|
||||||
"*::arg:->args"
|
|
||||||
|
|
||||||
case $state in
|
|
||||||
cmnds)
|
|
||||||
commands=({{range .Commands}}{{if not .Hidden}}
|
|
||||||
"{{.Name}}:{{.Short}}"{{end}}{{end}}
|
|
||||||
)
|
|
||||||
_describe "command" commands
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$words[1]" in {{- range .Commands}}{{if not .Hidden}}
|
|
||||||
{{.Name}})
|
|
||||||
{{$cmdPath}}_{{.Name}}
|
|
||||||
;;{{end}}{{end}}
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
{{range .Commands}}{{if not .Hidden}}
|
|
||||||
{{template "selectCmdTemplate" .}}
|
|
||||||
{{- end}}{{end}}
|
|
||||||
{{- end}}
|
|
||||||
|
|
||||||
{{/* should accept Command without subcommands as parameter */}}
|
|
||||||
{{define "arguments" -}}
|
|
||||||
function {{genZshFuncName .}} {
|
|
||||||
{{" _arguments"}}{{range extractFlags .}} \
|
|
||||||
{{genFlagEntryForZshArguments . -}}
|
|
||||||
{{end}}{{range extractArgsCompletions .}} \
|
|
||||||
{{.}}{{end}}
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{/* dispatcher for commands with or without subcommands */}}
|
|
||||||
{{define "selectCmdTemplate" -}}
|
|
||||||
{{if .Hidden}}{{/* ignore hidden*/}}{{else -}}
|
|
||||||
{{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}}
|
|
||||||
{{- end}}
|
|
||||||
{{- end}}
|
|
||||||
|
|
||||||
{{/* template entry point */}}
|
|
||||||
{{define "Main" -}}
|
|
||||||
#compdef _{{.Name}} {{.Name}}
|
|
||||||
|
|
||||||
{{template "selectCmdTemplate" .}}
|
|
||||||
{{end}}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
// zshCompArgsAnnotation is used to encode/decode zsh completion for
|
|
||||||
// arguments to/from Command.Annotations.
|
|
||||||
type zshCompArgsAnnotation map[int]zshCompArgHint
|
|
||||||
|
|
||||||
type zshCompArgHint struct {
|
|
||||||
// Indicates the type of the completion to use. One of:
|
|
||||||
// zshCompArgumentFilenameComp or zshCompArgumentWordComp
|
|
||||||
Tipe string `json:"type"`
|
|
||||||
|
|
||||||
// A value for the type above (globs for file completion or words)
|
|
||||||
Options []string `json:"options"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenZshCompletionFile generates zsh completion file.
|
|
||||||
func (c *Command) GenZshCompletionFile(filename string) error {
|
|
||||||
outFile, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer outFile.Close()
|
|
||||||
|
|
||||||
return c.GenZshCompletion(outFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenZshCompletion generates a zsh completion file and writes to the passed
|
|
||||||
// writer. The completion always run on the root command regardless of the
|
|
||||||
// command it was called from.
|
|
||||||
func (c *Command) GenZshCompletion(w io.Writer) error {
|
|
||||||
tmpl, err := template.New("Main").Funcs(zshCompFuncMap).Parse(zshCompletionText)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating zsh completion template: %v", err)
|
|
||||||
}
|
|
||||||
return tmpl.Execute(w, c.Root())
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkZshCompPositionalArgumentFile marks the specified argument (first
|
|
||||||
// argument is 1) as completed by file selection. patterns (e.g. "*.txt") are
|
|
||||||
// optional - if not provided the completion will search for all files.
|
|
||||||
func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error {
|
|
||||||
if argPosition < 1 {
|
|
||||||
return fmt.Errorf("Invalid argument position (%d)", argPosition)
|
|
||||||
}
|
|
||||||
annotation, err := c.zshCompGetArgsAnnotations()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
|
|
||||||
return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
|
|
||||||
}
|
|
||||||
annotation[argPosition] = zshCompArgHint{
|
|
||||||
Tipe: zshCompArgumentFilenameComp,
|
|
||||||
Options: patterns,
|
|
||||||
}
|
|
||||||
return c.zshCompSetArgsAnnotations(annotation)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkZshCompPositionalArgumentWords marks the specified positional argument
|
|
||||||
// (first argument is 1) as completed by the provided words. At east one word
|
|
||||||
// must be provided, spaces within words will be offered completion with
|
|
||||||
// "word\ word".
|
|
||||||
func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error {
|
|
||||||
if argPosition < 1 {
|
|
||||||
return fmt.Errorf("Invalid argument position (%d)", argPosition)
|
|
||||||
}
|
|
||||||
if len(words) == 0 {
|
|
||||||
return fmt.Errorf("Trying to set empty word list for positional argument %d", argPosition)
|
|
||||||
}
|
|
||||||
annotation, err := c.zshCompGetArgsAnnotations()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
|
|
||||||
return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
|
|
||||||
}
|
|
||||||
annotation[argPosition] = zshCompArgHint{
|
|
||||||
Tipe: zshCompArgumentWordComp,
|
|
||||||
Options: words,
|
|
||||||
}
|
|
||||||
return c.zshCompSetArgsAnnotations(annotation)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompExtractArgumentCompletionHintsForRendering(c *Command) ([]string, error) {
|
|
||||||
var result []string
|
|
||||||
annotation, err := c.zshCompGetArgsAnnotations()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for k, v := range annotation {
|
|
||||||
s, err := zshCompRenderZshCompArgHint(k, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, s)
|
|
||||||
}
|
|
||||||
if len(c.ValidArgs) > 0 {
|
|
||||||
if _, positionOneExists := annotation[1]; !positionOneExists {
|
|
||||||
s, err := zshCompRenderZshCompArgHint(1, zshCompArgHint{
|
|
||||||
Tipe: zshCompArgumentWordComp,
|
|
||||||
Options: c.ValidArgs,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(result)
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompRenderZshCompArgHint(i int, z zshCompArgHint) (string, error) {
|
|
||||||
switch t := z.Tipe; t {
|
|
||||||
case zshCompArgumentFilenameComp:
|
|
||||||
var globs []string
|
|
||||||
for _, g := range z.Options {
|
|
||||||
globs = append(globs, fmt.Sprintf(`-g "%s"`, g))
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(`'%d: :_files %s'`, i, strings.Join(globs, " ")), nil
|
|
||||||
case zshCompArgumentWordComp:
|
|
||||||
var words []string
|
|
||||||
for _, w := range z.Options {
|
|
||||||
words = append(words, fmt.Sprintf("%q", w))
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(`'%d: :(%s)'`, i, strings.Join(words, " ")), nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("Invalid zsh argument completion annotation: %s", t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) zshcompArgsAnnotationnIsDuplicatePosition(annotation zshCompArgsAnnotation, position int) bool {
|
|
||||||
_, dup := annotation[position]
|
|
||||||
return dup
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) zshCompGetArgsAnnotations() (zshCompArgsAnnotation, error) {
|
|
||||||
annotation := make(zshCompArgsAnnotation)
|
|
||||||
annotationString, ok := c.Annotations[zshCompArgumentAnnotation]
|
|
||||||
if !ok {
|
|
||||||
return annotation, nil
|
|
||||||
}
|
|
||||||
err := json.Unmarshal([]byte(annotationString), &annotation)
|
|
||||||
if err != nil {
|
|
||||||
return annotation, fmt.Errorf("Error unmarshaling zsh argument annotation: %v", err)
|
|
||||||
}
|
|
||||||
return annotation, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) zshCompSetArgsAnnotations(annotation zshCompArgsAnnotation) error {
|
|
||||||
jsn, err := json.Marshal(annotation)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error marshaling zsh argument annotation: %v", err)
|
|
||||||
}
|
|
||||||
if c.Annotations == nil {
|
|
||||||
c.Annotations = make(map[string]string)
|
|
||||||
}
|
|
||||||
c.Annotations[zshCompArgumentAnnotation] = string(jsn)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompGenFuncName(c *Command) string {
|
|
||||||
if c.HasParent() {
|
|
||||||
return zshCompGenFuncName(c.Parent()) + "_" + c.Name()
|
|
||||||
}
|
|
||||||
return "_" + c.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompExtractFlag(c *Command) []*pflag.Flag {
|
|
||||||
var flags []*pflag.Flag
|
|
||||||
c.LocalFlags().VisitAll(func(f *pflag.Flag) {
|
|
||||||
if !f.Hidden {
|
|
||||||
flags = append(flags, f)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
c.InheritedFlags().VisitAll(func(f *pflag.Flag) {
|
|
||||||
if !f.Hidden {
|
|
||||||
flags = append(flags, f)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return flags
|
|
||||||
}
|
|
||||||
|
|
||||||
// zshCompGenFlagEntryForArguments returns an entry that matches _arguments
|
|
||||||
// zsh-completion parameters. It's too complicated to generate in a template.
|
|
||||||
func zshCompGenFlagEntryForArguments(f *pflag.Flag) string {
|
|
||||||
if f.Name == "" || f.Shorthand == "" {
|
|
||||||
return zshCompGenFlagEntryForSingleOptionFlag(f)
|
|
||||||
}
|
|
||||||
return zshCompGenFlagEntryForMultiOptionFlag(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompGenFlagEntryForSingleOptionFlag(f *pflag.Flag) string {
|
|
||||||
var option, multiMark, extras string
|
|
||||||
|
|
||||||
if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
|
|
||||||
multiMark = "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
option = "--" + f.Name
|
|
||||||
if option == "--" {
|
|
||||||
option = "-" + f.Shorthand
|
|
||||||
}
|
|
||||||
extras = zshCompGenFlagEntryExtras(f)
|
|
||||||
|
|
||||||
return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, zshCompQuoteFlagDescription(f.Usage), extras)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
|
|
||||||
var options, parenMultiMark, curlyMultiMark, extras string
|
|
||||||
|
|
||||||
if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
|
|
||||||
parenMultiMark = "*"
|
|
||||||
curlyMultiMark = "\\*"
|
|
||||||
}
|
|
||||||
|
|
||||||
options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`,
|
|
||||||
parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name)
|
|
||||||
extras = zshCompGenFlagEntryExtras(f)
|
|
||||||
|
|
||||||
return fmt.Sprintf(`%s'[%s]%s'`, options, zshCompQuoteFlagDescription(f.Usage), extras)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompGenFlagEntryExtras(f *pflag.Flag) string {
|
|
||||||
if f.NoOptDefVal != "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
extras := ":" // allow options for flag (even without assistance)
|
|
||||||
for key, values := range f.Annotations {
|
|
||||||
switch key {
|
|
||||||
case zshCompDirname:
|
|
||||||
extras = fmt.Sprintf(":filename:_files -g %q", values[0])
|
|
||||||
case BashCompFilenameExt:
|
|
||||||
extras = ":filename:_files"
|
|
||||||
for _, pattern := range values {
|
|
||||||
extras = extras + fmt.Sprintf(` -g "%s"`, pattern)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return extras
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool {
|
|
||||||
return strings.Contains(f.Value.Type(), "Slice") ||
|
|
||||||
strings.Contains(f.Value.Type(), "Array")
|
|
||||||
}
|
|
||||||
|
|
||||||
func zshCompQuoteFlagDescription(s string) string {
|
|
||||||
return strings.Replace(s, "'", `'\''`, -1)
|
|
||||||
}
|
|
39
vendor/github.com/spf13/cobra/zsh_completions.md
generated
vendored
39
vendor/github.com/spf13/cobra/zsh_completions.md
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
## Generating Zsh Completion for your cobra.Command
|
|
||||||
|
|
||||||
Cobra supports native Zsh completion generated from the root `cobra.Command`.
|
|
||||||
The generated completion script should be put somewhere in your `$fpath` named
|
|
||||||
`_<YOUR COMMAND>`.
|
|
||||||
|
|
||||||
### What's Supported
|
|
||||||
|
|
||||||
* Completion for all non-hidden subcommands using their `.Short` description.
|
|
||||||
* Completion for all non-hidden flags using the following rules:
|
|
||||||
* Filename completion works by marking the flag with `cmd.MarkFlagFilename...`
|
|
||||||
family of commands.
|
|
||||||
* The requirement for argument to the flag is decided by the `.NoOptDefVal`
|
|
||||||
flag value - if it's empty then completion will expect an argument.
|
|
||||||
* Flags of one of the various `*Array` and `*Slice` types supports multiple
|
|
||||||
specifications (with or without argument depending on the specific type).
|
|
||||||
* Completion of positional arguments using the following rules:
|
|
||||||
* Argument position for all options below starts at `1`. If argument position
|
|
||||||
`0` is requested it will raise an error.
|
|
||||||
* Use `command.MarkZshCompPositionalArgumentFile` to complete filenames. Glob
|
|
||||||
patterns (e.g. `"*.log"`) are optional - if not specified it will offer to
|
|
||||||
complete all file types.
|
|
||||||
* Use `command.MarkZshCompPositionalArgumentWords` to offer specific words for
|
|
||||||
completion. At least one word is required.
|
|
||||||
* It's possible to specify completion for some arguments and leave some
|
|
||||||
unspecified (e.g. offer words for second argument but nothing for first
|
|
||||||
argument). This will cause no completion for first argument but words
|
|
||||||
completion for second argument.
|
|
||||||
* If no argument completion was specified for 1st argument (but optionally was
|
|
||||||
specified for 2nd) and the command has `ValidArgs` it will be used as
|
|
||||||
completion options for 1st argument.
|
|
||||||
* Argument completions only offered for commands with no subcommands.
|
|
||||||
|
|
||||||
### What's not yet Supported
|
|
||||||
|
|
||||||
* Custom completion scripts are not supported yet (We should probably create zsh
|
|
||||||
specific one, doesn't make sense to re-use the bash one as the functions will
|
|
||||||
be different).
|
|
||||||
* Whatever other feature you're looking for and doesn't exist :)
|
|
2
vendor/github.com/spf13/pflag/.gitignore
generated
vendored
2
vendor/github.com/spf13/pflag/.gitignore
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
.idea/*
|
|
||||||
|
|
22
vendor/github.com/spf13/pflag/.travis.yml
generated
vendored
22
vendor/github.com/spf13/pflag/.travis.yml
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
|
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.9.x
|
|
||||||
- 1.10.x
|
|
||||||
- 1.11.x
|
|
||||||
- tip
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- go: tip
|
|
||||||
|
|
||||||
install:
|
|
||||||
- go get golang.org/x/lint/golint
|
|
||||||
- export PATH=$GOPATH/bin:$PATH
|
|
||||||
- go install ./...
|
|
||||||
|
|
||||||
script:
|
|
||||||
- verify/all.sh -v
|
|
||||||
- go test ./...
|
|
28
vendor/github.com/spf13/pflag/LICENSE
generated
vendored
28
vendor/github.com/spf13/pflag/LICENSE
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
Copyright (c) 2012 Alex Ogier. All rights reserved.
|
|
||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
296
vendor/github.com/spf13/pflag/README.md
generated
vendored
296
vendor/github.com/spf13/pflag/README.md
generated
vendored
@ -1,296 +0,0 @@
|
|||||||
[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag)
|
|
||||||
[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag)
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
pflag is a drop-in replacement for Go's flag package, implementing
|
|
||||||
POSIX/GNU-style --flags.
|
|
||||||
|
|
||||||
pflag is compatible with the [GNU extensions to the POSIX recommendations
|
|
||||||
for command-line options][1]. For a more precise description, see the
|
|
||||||
"Command-line flag syntax" section below.
|
|
||||||
|
|
||||||
[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
|
||||||
|
|
||||||
pflag is available under the same style of BSD license as the Go language,
|
|
||||||
which can be found in the LICENSE file.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
pflag is available using the standard `go get` command.
|
|
||||||
|
|
||||||
Install by running:
|
|
||||||
|
|
||||||
go get github.com/spf13/pflag
|
|
||||||
|
|
||||||
Run tests by running:
|
|
||||||
|
|
||||||
go test github.com/spf13/pflag
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
pflag is a drop-in replacement of Go's native flag package. If you import
|
|
||||||
pflag under the name "flag" then all code should continue to function
|
|
||||||
with no changes.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
import flag "github.com/spf13/pflag"
|
|
||||||
```
|
|
||||||
|
|
||||||
There is one exception to this: if you directly instantiate the Flag struct
|
|
||||||
there is one more field "Shorthand" that you will need to set.
|
|
||||||
Most code never instantiates this struct directly, and instead uses
|
|
||||||
functions such as String(), BoolVar(), and Var(), and is therefore
|
|
||||||
unaffected.
|
|
||||||
|
|
||||||
Define flags using flag.String(), Bool(), Int(), etc.
|
|
||||||
|
|
||||||
This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
|
|
||||||
```
|
|
||||||
|
|
||||||
If you like, you can bind the flag to a variable using the Var() functions.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
var flagvar int
|
|
||||||
func init() {
|
|
||||||
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you can create custom flags that satisfy the Value interface (with
|
|
||||||
pointer receivers) and couple them to flag parsing by
|
|
||||||
|
|
||||||
``` go
|
|
||||||
flag.Var(&flagVal, "name", "help message for flagname")
|
|
||||||
```
|
|
||||||
|
|
||||||
For such flags, the default value is just the initial value of the variable.
|
|
||||||
|
|
||||||
After all flags are defined, call
|
|
||||||
|
|
||||||
``` go
|
|
||||||
flag.Parse()
|
|
||||||
```
|
|
||||||
|
|
||||||
to parse the command line into the defined flags.
|
|
||||||
|
|
||||||
Flags may then be used directly. If you're using the flags themselves,
|
|
||||||
they are all pointers; if you bind to variables, they're values.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
fmt.Println("ip has value ", *ip)
|
|
||||||
fmt.Println("flagvar has value ", flagvar)
|
|
||||||
```
|
|
||||||
|
|
||||||
There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
|
|
||||||
it difficult to keep up with all of the pointers in your code.
|
|
||||||
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
|
|
||||||
can use GetInt() to get the int value. But notice that 'flagname' must exist
|
|
||||||
and it must be an int. GetString("flagname") will fail.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
i, err := flagset.GetInt("flagname")
|
|
||||||
```
|
|
||||||
|
|
||||||
After parsing, the arguments after the flag are available as the
|
|
||||||
slice flag.Args() or individually as flag.Arg(i).
|
|
||||||
The arguments are indexed from 0 through flag.NArg()-1.
|
|
||||||
|
|
||||||
The pflag package also defines some new functions that are not in flag,
|
|
||||||
that give one-letter shorthands for flags. You can use these by appending
|
|
||||||
'P' to the name of any function that defines a flag.
|
|
||||||
|
|
||||||
``` go
|
|
||||||
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
|
||||||
var flagvar bool
|
|
||||||
func init() {
|
|
||||||
flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
|
|
||||||
}
|
|
||||||
flag.VarP(&flagVal, "varname", "v", "help message")
|
|
||||||
```
|
|
||||||
|
|
||||||
Shorthand letters can be used with single dashes on the command line.
|
|
||||||
Boolean shorthand flags can be combined with other shorthand flags.
|
|
||||||
|
|
||||||
The default set of command-line flags is controlled by
|
|
||||||
top-level functions. The FlagSet type allows one to define
|
|
||||||
independent sets of flags, such as to implement subcommands
|
|
||||||
in a command-line interface. The methods of FlagSet are
|
|
||||||
analogous to the top-level functions for the command-line
|
|
||||||
flag set.
|
|
||||||
|
|
||||||
## Setting no option default values for flags
|
|
||||||
|
|
||||||
After you create a flag it is possible to set the pflag.NoOptDefVal for
|
|
||||||
the given flag. Doing this changes the meaning of the flag slightly. If
|
|
||||||
a flag has a NoOptDefVal and the flag is set on the command line without
|
|
||||||
an option the flag will be set to the NoOptDefVal. For example given:
|
|
||||||
|
|
||||||
``` go
|
|
||||||
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
|
||||||
flag.Lookup("flagname").NoOptDefVal = "4321"
|
|
||||||
```
|
|
||||||
|
|
||||||
Would result in something like
|
|
||||||
|
|
||||||
| Parsed Arguments | Resulting Value |
|
|
||||||
| ------------- | ------------- |
|
|
||||||
| --flagname=1357 | ip=1357 |
|
|
||||||
| --flagname | ip=4321 |
|
|
||||||
| [nothing] | ip=1234 |
|
|
||||||
|
|
||||||
## Command line flag syntax
|
|
||||||
|
|
||||||
```
|
|
||||||
--flag // boolean flags, or flags with no option default values
|
|
||||||
--flag x // only on flags without a default value
|
|
||||||
--flag=x
|
|
||||||
```
|
|
||||||
|
|
||||||
Unlike the flag package, a single dash before an option means something
|
|
||||||
different than a double dash. Single dashes signify a series of shorthand
|
|
||||||
letters for flags. All but the last shorthand letter must be boolean flags
|
|
||||||
or a flag with a default value
|
|
||||||
|
|
||||||
```
|
|
||||||
// boolean or flags where the 'no option default value' is set
|
|
||||||
-f
|
|
||||||
-f=true
|
|
||||||
-abc
|
|
||||||
but
|
|
||||||
-b true is INVALID
|
|
||||||
|
|
||||||
// non-boolean and flags without a 'no option default value'
|
|
||||||
-n 1234
|
|
||||||
-n=1234
|
|
||||||
-n1234
|
|
||||||
|
|
||||||
// mixed
|
|
||||||
-abcs "hello"
|
|
||||||
-absd="hello"
|
|
||||||
-abcs1234
|
|
||||||
```
|
|
||||||
|
|
||||||
Flag parsing stops after the terminator "--". Unlike the flag package,
|
|
||||||
flags can be interspersed with arguments anywhere on the command line
|
|
||||||
before this terminator.
|
|
||||||
|
|
||||||
Integer flags accept 1234, 0664, 0x1234 and may be negative.
|
|
||||||
Boolean flags (in their long form) accept 1, 0, t, f, true, false,
|
|
||||||
TRUE, FALSE, True, False.
|
|
||||||
Duration flags accept any input valid for time.ParseDuration.
|
|
||||||
|
|
||||||
## Mutating or "Normalizing" Flag names
|
|
||||||
|
|
||||||
It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow.
|
|
||||||
|
|
||||||
**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag
|
|
||||||
|
|
||||||
``` go
|
|
||||||
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
|
||||||
from := []string{"-", "_"}
|
|
||||||
to := "."
|
|
||||||
for _, sep := range from {
|
|
||||||
name = strings.Replace(name, sep, to, -1)
|
|
||||||
}
|
|
||||||
return pflag.NormalizedName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name
|
|
||||||
|
|
||||||
``` go
|
|
||||||
func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
|
||||||
switch name {
|
|
||||||
case "old-flag-name":
|
|
||||||
name = "new-flag-name"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return pflag.NormalizedName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
myFlagSet.SetNormalizeFunc(aliasNormalizeFunc)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deprecating a flag or its shorthand
|
|
||||||
It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used.
|
|
||||||
|
|
||||||
**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead.
|
|
||||||
```go
|
|
||||||
// deprecate a flag by specifying its name and a usage message
|
|
||||||
flags.MarkDeprecated("badflag", "please use --good-flag instead")
|
|
||||||
```
|
|
||||||
This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used.
|
|
||||||
|
|
||||||
**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n".
|
|
||||||
```go
|
|
||||||
// deprecate a flag shorthand by specifying its flag name and a usage message
|
|
||||||
flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only")
|
|
||||||
```
|
|
||||||
This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used.
|
|
||||||
|
|
||||||
Note that usage message is essential here, and it should not be empty.
|
|
||||||
|
|
||||||
## Hidden flags
|
|
||||||
It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text.
|
|
||||||
|
|
||||||
**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available.
|
|
||||||
```go
|
|
||||||
// hide a flag by specifying its name
|
|
||||||
flags.MarkHidden("secretFlag")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Disable sorting of flags
|
|
||||||
`pflag` allows you to disable sorting of flags for help and usage message.
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```go
|
|
||||||
flags.BoolP("verbose", "v", false, "verbose output")
|
|
||||||
flags.String("coolflag", "yeaah", "it's really cool flag")
|
|
||||||
flags.Int("usefulflag", 777, "sometimes it's very useful")
|
|
||||||
flags.SortFlags = false
|
|
||||||
flags.PrintDefaults()
|
|
||||||
```
|
|
||||||
**Output**:
|
|
||||||
```
|
|
||||||
-v, --verbose verbose output
|
|
||||||
--coolflag string it's really cool flag (default "yeaah")
|
|
||||||
--usefulflag int sometimes it's very useful (default 777)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Supporting Go flags when using pflag
|
|
||||||
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
|
|
||||||
to support flags defined by third-party dependencies (e.g. `golang/glog`).
|
|
||||||
|
|
||||||
**Example**: You want to add the Go flags to the `CommandLine` flagset
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
goflag "flag"
|
|
||||||
flag "github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
|
||||||
flag.Parse()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## More info
|
|
||||||
|
|
||||||
You can see the full reference documentation of the pflag package
|
|
||||||
[at godoc.org][3], or through go's standard documentation system by
|
|
||||||
running `godoc -http=:6060` and browsing to
|
|
||||||
[http://localhost:6060/pkg/github.com/spf13/pflag][2] after
|
|
||||||
installation.
|
|
||||||
|
|
||||||
[2]: http://localhost:6060/pkg/github.com/spf13/pflag
|
|
||||||
[3]: http://godoc.org/github.com/spf13/pflag
|
|
94
vendor/github.com/spf13/pflag/bool.go
generated
vendored
94
vendor/github.com/spf13/pflag/bool.go
generated
vendored
@ -1,94 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
// optional interface to indicate boolean flags that can be
|
|
||||||
// supplied without "=value" text
|
|
||||||
type boolFlag interface {
|
|
||||||
Value
|
|
||||||
IsBoolFlag() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- bool Value
|
|
||||||
type boolValue bool
|
|
||||||
|
|
||||||
func newBoolValue(val bool, p *bool) *boolValue {
|
|
||||||
*p = val
|
|
||||||
return (*boolValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *boolValue) Set(s string) error {
|
|
||||||
v, err := strconv.ParseBool(s)
|
|
||||||
*b = boolValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *boolValue) Type() string {
|
|
||||||
return "bool"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
|
|
||||||
|
|
||||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
|
||||||
|
|
||||||
func boolConv(sval string) (interface{}, error) {
|
|
||||||
return strconv.ParseBool(sval)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBool return the bool value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetBool(name string) (bool, error) {
|
|
||||||
val, err := f.getFlagType(name, "bool", boolConv)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return val.(bool), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a bool variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
|
||||||
f.BoolVarP(p, name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
|
||||||
flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage)
|
|
||||||
flag.NoOptDefVal = "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a bool variable in which to store the value of the flag.
|
|
||||||
func BoolVar(p *bool, name string, value bool, usage string) {
|
|
||||||
BoolVarP(p, name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
|
||||||
flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage)
|
|
||||||
flag.NoOptDefVal = "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a bool variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
|
|
||||||
return f.BoolP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool {
|
|
||||||
p := new(bool)
|
|
||||||
f.BoolVarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a bool variable that stores the value of the flag.
|
|
||||||
func Bool(name string, value bool, usage string) *bool {
|
|
||||||
return BoolP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BoolP(name, shorthand string, value bool, usage string) *bool {
|
|
||||||
b := CommandLine.BoolP(name, shorthand, value, usage)
|
|
||||||
return b
|
|
||||||
}
|
|
185
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
185
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
@ -1,185 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -- boolSlice Value
|
|
||||||
type boolSliceValue struct {
|
|
||||||
value *[]bool
|
|
||||||
changed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
|
|
||||||
bsv := new(boolSliceValue)
|
|
||||||
bsv.value = p
|
|
||||||
*bsv.value = val
|
|
||||||
return bsv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
|
|
||||||
// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
|
|
||||||
func (s *boolSliceValue) Set(val string) error {
|
|
||||||
|
|
||||||
// remove all quote characters
|
|
||||||
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
|
||||||
|
|
||||||
// read flag arguments with CSV parser
|
|
||||||
boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse boolean values into slice
|
|
||||||
out := make([]bool, 0, len(boolStrSlice))
|
|
||||||
for _, boolStr := range boolStrSlice {
|
|
||||||
b, err := strconv.ParseBool(strings.TrimSpace(boolStr))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
out = append(out, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.changed {
|
|
||||||
*s.value = out
|
|
||||||
} else {
|
|
||||||
*s.value = append(*s.value, out...)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.changed = true
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns a string that uniquely represents this flag's type.
|
|
||||||
func (s *boolSliceValue) Type() string {
|
|
||||||
return "boolSlice"
|
|
||||||
}
|
|
||||||
|
|
||||||
// String defines a "native" format for this boolean slice flag value.
|
|
||||||
func (s *boolSliceValue) String() string {
|
|
||||||
|
|
||||||
boolStrSlice := make([]string, len(*s.value))
|
|
||||||
for i, b := range *s.value {
|
|
||||||
boolStrSlice[i] = strconv.FormatBool(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
out, _ := writeAsCSV(boolStrSlice)
|
|
||||||
|
|
||||||
return "[" + out + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *boolSliceValue) fromString(val string) (bool, error) {
|
|
||||||
return strconv.ParseBool(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *boolSliceValue) toString(val bool) string {
|
|
||||||
return strconv.FormatBool(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *boolSliceValue) Append(val string) error {
|
|
||||||
i, err := s.fromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s.value = append(*s.value, i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *boolSliceValue) Replace(val []string) error {
|
|
||||||
out := make([]bool, len(val))
|
|
||||||
for i, d := range val {
|
|
||||||
var err error
|
|
||||||
out[i], err = s.fromString(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*s.value = out
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *boolSliceValue) GetSlice() []string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = s.toString(d)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func boolSliceConv(val string) (interface{}, error) {
|
|
||||||
val = strings.Trim(val, "[]")
|
|
||||||
// Empty string would cause a slice with one (empty) entry
|
|
||||||
if len(val) == 0 {
|
|
||||||
return []bool{}, nil
|
|
||||||
}
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]bool, len(ss))
|
|
||||||
for i, t := range ss {
|
|
||||||
var err error
|
|
||||||
out[i], err = strconv.ParseBool(t)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBoolSlice returns the []bool value of a flag with the given name.
|
|
||||||
func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) {
|
|
||||||
val, err := f.getFlagType(name, "boolSlice", boolSliceConv)
|
|
||||||
if err != nil {
|
|
||||||
return []bool{}, err
|
|
||||||
}
|
|
||||||
return val.([]bool), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a []bool variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
|
||||||
f.VarP(newBoolSliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
|
||||||
f.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceVar defines a []bool flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a []bool variable in which to store the value of the flag.
|
|
||||||
func BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
|
||||||
CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
|
||||||
CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []bool variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool {
|
|
||||||
p := []bool{}
|
|
||||||
f.BoolSliceVarP(&p, name, "", value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
|
||||||
p := []bool{}
|
|
||||||
f.BoolSliceVarP(&p, name, shorthand, value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []bool variable that stores the value of the flag.
|
|
||||||
func BoolSlice(name string, value []bool, usage string) *[]bool {
|
|
||||||
return CommandLine.BoolSliceP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
|
||||||
return CommandLine.BoolSliceP(name, shorthand, value, usage)
|
|
||||||
}
|
|
209
vendor/github.com/spf13/pflag/bytes.go
generated
vendored
209
vendor/github.com/spf13/pflag/bytes.go
generated
vendored
@ -1,209 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
|
|
||||||
type bytesHexValue []byte
|
|
||||||
|
|
||||||
// String implements pflag.Value.String.
|
|
||||||
func (bytesHex bytesHexValue) String() string {
|
|
||||||
return fmt.Sprintf("%X", []byte(bytesHex))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set implements pflag.Value.Set.
|
|
||||||
func (bytesHex *bytesHexValue) Set(value string) error {
|
|
||||||
bin, err := hex.DecodeString(strings.TrimSpace(value))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*bytesHex = bin
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements pflag.Value.Type.
|
|
||||||
func (*bytesHexValue) Type() string {
|
|
||||||
return "bytesHex"
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
|
|
||||||
*p = val
|
|
||||||
return (*bytesHexValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bytesHexConv(sval string) (interface{}, error) {
|
|
||||||
|
|
||||||
bin, err := hex.DecodeString(sval)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return bin, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBytesHex return the []byte value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
|
|
||||||
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return val.([]byte), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to an []byte variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
|
|
||||||
f.VarP(newBytesHexValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
|
||||||
f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to an []byte variable in which to store the value of the flag.
|
|
||||||
func BytesHexVar(p *[]byte, name string, value []byte, usage string) {
|
|
||||||
CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
|
||||||
CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHex defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an []byte variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte {
|
|
||||||
p := new([]byte)
|
|
||||||
f.BytesHexVarP(p, name, "", value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
|
||||||
p := new([]byte)
|
|
||||||
f.BytesHexVarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHex defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an []byte variable that stores the value of the flag.
|
|
||||||
func BytesHex(name string, value []byte, usage string) *[]byte {
|
|
||||||
return CommandLine.BytesHexP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
|
||||||
return CommandLine.BytesHexP(name, shorthand, value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded
|
|
||||||
type bytesBase64Value []byte
|
|
||||||
|
|
||||||
// String implements pflag.Value.String.
|
|
||||||
func (bytesBase64 bytesBase64Value) String() string {
|
|
||||||
return base64.StdEncoding.EncodeToString([]byte(bytesBase64))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set implements pflag.Value.Set.
|
|
||||||
func (bytesBase64 *bytesBase64Value) Set(value string) error {
|
|
||||||
bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*bytesBase64 = bin
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements pflag.Value.Type.
|
|
||||||
func (*bytesBase64Value) Type() string {
|
|
||||||
return "bytesBase64"
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value {
|
|
||||||
*p = val
|
|
||||||
return (*bytesBase64Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bytesBase64ValueConv(sval string) (interface{}, error) {
|
|
||||||
|
|
||||||
bin, err := base64.StdEncoding.DecodeString(sval)
|
|
||||||
if err == nil {
|
|
||||||
return bin, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBytesBase64 return the []byte value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) {
|
|
||||||
val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return val.([]byte), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to an []byte variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
|
|
||||||
f.VarP(newBytesBase64Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
|
||||||
f.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to an []byte variable in which to store the value of the flag.
|
|
||||||
func BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
|
|
||||||
CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
|
||||||
CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an []byte variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte {
|
|
||||||
p := new([]byte)
|
|
||||||
f.BytesBase64VarP(p, name, "", value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
|
|
||||||
p := new([]byte)
|
|
||||||
f.BytesBase64VarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an []byte variable that stores the value of the flag.
|
|
||||||
func BytesBase64(name string, value []byte, usage string) *[]byte {
|
|
||||||
return CommandLine.BytesBase64P(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
|
|
||||||
return CommandLine.BytesBase64P(name, shorthand, value, usage)
|
|
||||||
}
|
|
96
vendor/github.com/spf13/pflag/count.go
generated
vendored
96
vendor/github.com/spf13/pflag/count.go
generated
vendored
@ -1,96 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
// -- count Value
|
|
||||||
type countValue int
|
|
||||||
|
|
||||||
func newCountValue(val int, p *int) *countValue {
|
|
||||||
*p = val
|
|
||||||
return (*countValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *countValue) Set(s string) error {
|
|
||||||
// "+1" means that no specific value was passed, so increment
|
|
||||||
if s == "+1" {
|
|
||||||
*i = countValue(*i + 1)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
v, err := strconv.ParseInt(s, 0, 0)
|
|
||||||
*i = countValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *countValue) Type() string {
|
|
||||||
return "count"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *countValue) String() string { return strconv.Itoa(int(*i)) }
|
|
||||||
|
|
||||||
func countConv(sval string) (interface{}, error) {
|
|
||||||
i, err := strconv.Atoi(sval)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCount return the int value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetCount(name string) (int, error) {
|
|
||||||
val, err := f.getFlagType(name, "count", countConv)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return val.(int), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountVar defines a count flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to an int variable in which to store the value of the flag.
|
|
||||||
// A count flag will add 1 to its value every time it is found on the command line
|
|
||||||
func (f *FlagSet) CountVar(p *int, name string, usage string) {
|
|
||||||
f.CountVarP(p, name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountVarP is like CountVar only take a shorthand for the flag name.
|
|
||||||
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
|
|
||||||
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
|
|
||||||
flag.NoOptDefVal = "+1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
|
|
||||||
func CountVar(p *int, name string, usage string) {
|
|
||||||
CommandLine.CountVar(p, name, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountVarP is like CountVar only take a shorthand for the flag name.
|
|
||||||
func CountVarP(p *int, name, shorthand string, usage string) {
|
|
||||||
CommandLine.CountVarP(p, name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count defines a count flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an int variable that stores the value of the flag.
|
|
||||||
// A count flag will add 1 to its value every time it is found on the command line
|
|
||||||
func (f *FlagSet) Count(name string, usage string) *int {
|
|
||||||
p := new(int)
|
|
||||||
f.CountVarP(p, name, "", usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountP is like Count only takes a shorthand for the flag name.
|
|
||||||
func (f *FlagSet) CountP(name, shorthand string, usage string) *int {
|
|
||||||
p := new(int)
|
|
||||||
f.CountVarP(p, name, shorthand, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count defines a count flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of an int variable that stores the value of the flag.
|
|
||||||
// A count flag will add 1 to its value evey time it is found on the command line
|
|
||||||
func Count(name string, usage string) *int {
|
|
||||||
return CommandLine.CountP(name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountP is like Count only takes a shorthand for the flag name.
|
|
||||||
func CountP(name, shorthand string, usage string) *int {
|
|
||||||
return CommandLine.CountP(name, shorthand, usage)
|
|
||||||
}
|
|
86
vendor/github.com/spf13/pflag/duration.go
generated
vendored
86
vendor/github.com/spf13/pflag/duration.go
generated
vendored
@ -1,86 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -- time.Duration Value
|
|
||||||
type durationValue time.Duration
|
|
||||||
|
|
||||||
func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
|
|
||||||
*p = val
|
|
||||||
return (*durationValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *durationValue) Set(s string) error {
|
|
||||||
v, err := time.ParseDuration(s)
|
|
||||||
*d = durationValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *durationValue) Type() string {
|
|
||||||
return "duration"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *durationValue) String() string { return (*time.Duration)(d).String() }
|
|
||||||
|
|
||||||
func durationConv(sval string) (interface{}, error) {
|
|
||||||
return time.ParseDuration(sval)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDuration return the duration value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetDuration(name string) (time.Duration, error) {
|
|
||||||
val, err := f.getFlagType(name, "duration", durationConv)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return val.(time.Duration), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
|
||||||
f.VarP(newDurationValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
|
|
||||||
f.VarP(newDurationValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
|
||||||
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
|
||||||
CommandLine.VarP(newDurationValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
|
|
||||||
CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
|
|
||||||
p := new(time.Duration)
|
|
||||||
f.DurationVarP(p, name, "", value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
|
|
||||||
p := new(time.Duration)
|
|
||||||
f.DurationVarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
|
||||||
func Duration(name string, value time.Duration, usage string) *time.Duration {
|
|
||||||
return CommandLine.DurationP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
|
|
||||||
return CommandLine.DurationP(name, shorthand, value, usage)
|
|
||||||
}
|
|
166
vendor/github.com/spf13/pflag/duration_slice.go
generated
vendored
166
vendor/github.com/spf13/pflag/duration_slice.go
generated
vendored
@ -1,166 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -- durationSlice Value
|
|
||||||
type durationSliceValue struct {
|
|
||||||
value *[]time.Duration
|
|
||||||
changed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue {
|
|
||||||
dsv := new(durationSliceValue)
|
|
||||||
dsv.value = p
|
|
||||||
*dsv.value = val
|
|
||||||
return dsv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) Set(val string) error {
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]time.Duration, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
out[i], err = time.ParseDuration(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if !s.changed {
|
|
||||||
*s.value = out
|
|
||||||
} else {
|
|
||||||
*s.value = append(*s.value, out...)
|
|
||||||
}
|
|
||||||
s.changed = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) Type() string {
|
|
||||||
return "durationSlice"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) String() string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = fmt.Sprintf("%s", d)
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(out, ",") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) fromString(val string) (time.Duration, error) {
|
|
||||||
return time.ParseDuration(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) toString(val time.Duration) string {
|
|
||||||
return fmt.Sprintf("%s", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) Append(val string) error {
|
|
||||||
i, err := s.fromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s.value = append(*s.value, i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) Replace(val []string) error {
|
|
||||||
out := make([]time.Duration, len(val))
|
|
||||||
for i, d := range val {
|
|
||||||
var err error
|
|
||||||
out[i], err = s.fromString(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*s.value = out
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *durationSliceValue) GetSlice() []string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = s.toString(d)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func durationSliceConv(val string) (interface{}, error) {
|
|
||||||
val = strings.Trim(val, "[]")
|
|
||||||
// Empty string would cause a slice with one (empty) entry
|
|
||||||
if len(val) == 0 {
|
|
||||||
return []time.Duration{}, nil
|
|
||||||
}
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]time.Duration, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
out[i], err = time.ParseDuration(d)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDurationSlice returns the []time.Duration value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) {
|
|
||||||
val, err := f.getFlagType(name, "durationSlice", durationSliceConv)
|
|
||||||
if err != nil {
|
|
||||||
return []time.Duration{}, err
|
|
||||||
}
|
|
||||||
return val.([]time.Duration), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a []time.Duration variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
|
|
||||||
f.VarP(newDurationSliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
|
|
||||||
f.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a duration[] variable in which to store the value of the flag.
|
|
||||||
func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
|
|
||||||
CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
|
|
||||||
CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []time.Duration variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
|
|
||||||
p := []time.Duration{}
|
|
||||||
f.DurationSliceVarP(&p, name, "", value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
|
|
||||||
p := []time.Duration{}
|
|
||||||
f.DurationSliceVarP(&p, name, shorthand, value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []time.Duration variable that stores the value of the flag.
|
|
||||||
func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
|
|
||||||
return CommandLine.DurationSliceP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
|
|
||||||
return CommandLine.DurationSliceP(name, shorthand, value, usage)
|
|
||||||
}
|
|
1239
vendor/github.com/spf13/pflag/flag.go
generated
vendored
1239
vendor/github.com/spf13/pflag/flag.go
generated
vendored
File diff suppressed because it is too large
Load Diff
88
vendor/github.com/spf13/pflag/float32.go
generated
vendored
88
vendor/github.com/spf13/pflag/float32.go
generated
vendored
@ -1,88 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
// -- float32 Value
|
|
||||||
type float32Value float32
|
|
||||||
|
|
||||||
func newFloat32Value(val float32, p *float32) *float32Value {
|
|
||||||
*p = val
|
|
||||||
return (*float32Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float32Value) Set(s string) error {
|
|
||||||
v, err := strconv.ParseFloat(s, 32)
|
|
||||||
*f = float32Value(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float32Value) Type() string {
|
|
||||||
return "float32"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) }
|
|
||||||
|
|
||||||
func float32Conv(sval string) (interface{}, error) {
|
|
||||||
v, err := strconv.ParseFloat(sval, 32)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return float32(v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloat32 return the float32 value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetFloat32(name string) (float32, error) {
|
|
||||||
val, err := f.getFlagType(name, "float32", float32Conv)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return val.(float32), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32Var defines a float32 flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float32 variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) {
|
|
||||||
f.VarP(newFloat32Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
|
|
||||||
f.VarP(newFloat32Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32Var defines a float32 flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float32 variable in which to store the value of the flag.
|
|
||||||
func Float32Var(p *float32, name string, value float32, usage string) {
|
|
||||||
CommandLine.VarP(newFloat32Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
|
|
||||||
CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32 defines a float32 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a float32 variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Float32(name string, value float32, usage string) *float32 {
|
|
||||||
p := new(float32)
|
|
||||||
f.Float32VarP(p, name, "", value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 {
|
|
||||||
p := new(float32)
|
|
||||||
f.Float32VarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32 defines a float32 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a float32 variable that stores the value of the flag.
|
|
||||||
func Float32(name string, value float32, usage string) *float32 {
|
|
||||||
return CommandLine.Float32P(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float32P(name, shorthand string, value float32, usage string) *float32 {
|
|
||||||
return CommandLine.Float32P(name, shorthand, value, usage)
|
|
||||||
}
|
|
174
vendor/github.com/spf13/pflag/float32_slice.go
generated
vendored
174
vendor/github.com/spf13/pflag/float32_slice.go
generated
vendored
@ -1,174 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -- float32Slice Value
|
|
||||||
type float32SliceValue struct {
|
|
||||||
value *[]float32
|
|
||||||
changed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue {
|
|
||||||
isv := new(float32SliceValue)
|
|
||||||
isv.value = p
|
|
||||||
*isv.value = val
|
|
||||||
return isv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) Set(val string) error {
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]float32, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
var temp64 float64
|
|
||||||
temp64, err = strconv.ParseFloat(d, 32)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
out[i] = float32(temp64)
|
|
||||||
|
|
||||||
}
|
|
||||||
if !s.changed {
|
|
||||||
*s.value = out
|
|
||||||
} else {
|
|
||||||
*s.value = append(*s.value, out...)
|
|
||||||
}
|
|
||||||
s.changed = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) Type() string {
|
|
||||||
return "float32Slice"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) String() string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = fmt.Sprintf("%f", d)
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(out, ",") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) fromString(val string) (float32, error) {
|
|
||||||
t64, err := strconv.ParseFloat(val, 32)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return float32(t64), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) toString(val float32) string {
|
|
||||||
return fmt.Sprintf("%f", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) Append(val string) error {
|
|
||||||
i, err := s.fromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s.value = append(*s.value, i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) Replace(val []string) error {
|
|
||||||
out := make([]float32, len(val))
|
|
||||||
for i, d := range val {
|
|
||||||
var err error
|
|
||||||
out[i], err = s.fromString(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*s.value = out
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float32SliceValue) GetSlice() []string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = s.toString(d)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func float32SliceConv(val string) (interface{}, error) {
|
|
||||||
val = strings.Trim(val, "[]")
|
|
||||||
// Empty string would cause a slice with one (empty) entry
|
|
||||||
if len(val) == 0 {
|
|
||||||
return []float32{}, nil
|
|
||||||
}
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]float32, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
var temp64 float64
|
|
||||||
temp64, err = strconv.ParseFloat(d, 32)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
out[i] = float32(temp64)
|
|
||||||
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloat32Slice return the []float32 value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) {
|
|
||||||
val, err := f.getFlagType(name, "float32Slice", float32SliceConv)
|
|
||||||
if err != nil {
|
|
||||||
return []float32{}, err
|
|
||||||
}
|
|
||||||
return val.([]float32), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a []float32 variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
|
|
||||||
f.VarP(newFloat32SliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
|
|
||||||
f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float32[] variable in which to store the value of the flag.
|
|
||||||
func Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
|
|
||||||
CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
|
|
||||||
CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []float32 variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 {
|
|
||||||
p := []float32{}
|
|
||||||
f.Float32SliceVarP(&p, name, "", value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
|
|
||||||
p := []float32{}
|
|
||||||
f.Float32SliceVarP(&p, name, shorthand, value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []float32 variable that stores the value of the flag.
|
|
||||||
func Float32Slice(name string, value []float32, usage string) *[]float32 {
|
|
||||||
return CommandLine.Float32SliceP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
|
|
||||||
return CommandLine.Float32SliceP(name, shorthand, value, usage)
|
|
||||||
}
|
|
84
vendor/github.com/spf13/pflag/float64.go
generated
vendored
84
vendor/github.com/spf13/pflag/float64.go
generated
vendored
@ -1,84 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
// -- float64 Value
|
|
||||||
type float64Value float64
|
|
||||||
|
|
||||||
func newFloat64Value(val float64, p *float64) *float64Value {
|
|
||||||
*p = val
|
|
||||||
return (*float64Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float64Value) Set(s string) error {
|
|
||||||
v, err := strconv.ParseFloat(s, 64)
|
|
||||||
*f = float64Value(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float64Value) Type() string {
|
|
||||||
return "float64"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
|
|
||||||
|
|
||||||
func float64Conv(sval string) (interface{}, error) {
|
|
||||||
return strconv.ParseFloat(sval, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloat64 return the float64 value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetFloat64(name string) (float64, error) {
|
|
||||||
val, err := f.getFlagType(name, "float64", float64Conv)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return val.(float64), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
|
|
||||||
f.VarP(newFloat64Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
|
|
||||||
f.VarP(newFloat64Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
|
||||||
func Float64Var(p *float64, name string, value float64, usage string) {
|
|
||||||
CommandLine.VarP(newFloat64Value(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
|
|
||||||
CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
|
|
||||||
p := new(float64)
|
|
||||||
f.Float64VarP(p, name, "", value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 {
|
|
||||||
p := new(float64)
|
|
||||||
f.Float64VarP(p, name, shorthand, value, usage)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
|
||||||
func Float64(name string, value float64, usage string) *float64 {
|
|
||||||
return CommandLine.Float64P(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float64P(name, shorthand string, value float64, usage string) *float64 {
|
|
||||||
return CommandLine.Float64P(name, shorthand, value, usage)
|
|
||||||
}
|
|
166
vendor/github.com/spf13/pflag/float64_slice.go
generated
vendored
166
vendor/github.com/spf13/pflag/float64_slice.go
generated
vendored
@ -1,166 +0,0 @@
|
|||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -- float64Slice Value
|
|
||||||
type float64SliceValue struct {
|
|
||||||
value *[]float64
|
|
||||||
changed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue {
|
|
||||||
isv := new(float64SliceValue)
|
|
||||||
isv.value = p
|
|
||||||
*isv.value = val
|
|
||||||
return isv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) Set(val string) error {
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]float64, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
out[i], err = strconv.ParseFloat(d, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if !s.changed {
|
|
||||||
*s.value = out
|
|
||||||
} else {
|
|
||||||
*s.value = append(*s.value, out...)
|
|
||||||
}
|
|
||||||
s.changed = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) Type() string {
|
|
||||||
return "float64Slice"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) String() string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = fmt.Sprintf("%f", d)
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(out, ",") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) fromString(val string) (float64, error) {
|
|
||||||
return strconv.ParseFloat(val, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) toString(val float64) string {
|
|
||||||
return fmt.Sprintf("%f", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) Append(val string) error {
|
|
||||||
i, err := s.fromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s.value = append(*s.value, i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) Replace(val []string) error {
|
|
||||||
out := make([]float64, len(val))
|
|
||||||
for i, d := range val {
|
|
||||||
var err error
|
|
||||||
out[i], err = s.fromString(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*s.value = out
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *float64SliceValue) GetSlice() []string {
|
|
||||||
out := make([]string, len(*s.value))
|
|
||||||
for i, d := range *s.value {
|
|
||||||
out[i] = s.toString(d)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func float64SliceConv(val string) (interface{}, error) {
|
|
||||||
val = strings.Trim(val, "[]")
|
|
||||||
// Empty string would cause a slice with one (empty) entry
|
|
||||||
if len(val) == 0 {
|
|
||||||
return []float64{}, nil
|
|
||||||
}
|
|
||||||
ss := strings.Split(val, ",")
|
|
||||||
out := make([]float64, len(ss))
|
|
||||||
for i, d := range ss {
|
|
||||||
var err error
|
|
||||||
out[i], err = strconv.ParseFloat(d, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloat64Slice return the []float64 value of a flag with the given name
|
|
||||||
func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) {
|
|
||||||
val, err := f.getFlagType(name, "float64Slice", float64SliceConv)
|
|
||||||
if err != nil {
|
|
||||||
return []float64{}, err
|
|
||||||
}
|
|
||||||
return val.([]float64), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a []float64 variable in which to store the value of the flag.
|
|
||||||
func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
|
|
||||||
f.VarP(newFloat64SliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
|
|
||||||
f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string.
|
|
||||||
// The argument p points to a float64[] variable in which to store the value of the flag.
|
|
||||||
func Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
|
|
||||||
CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
|
|
||||||
CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []float64 variable that stores the value of the flag.
|
|
||||||
func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 {
|
|
||||||
p := []float64{}
|
|
||||||
f.Float64SliceVarP(&p, name, "", value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
|
|
||||||
p := []float64{}
|
|
||||||
f.Float64SliceVarP(&p, name, shorthand, value, usage)
|
|
||||||
return &p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
|
|
||||||
// The return value is the address of a []float64 variable that stores the value of the flag.
|
|
||||||
func Float64Slice(name string, value []float64, usage string) *[]float64 {
|
|
||||||
return CommandLine.Float64SliceP(name, "", value, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
|
|
||||||
func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
|
|
||||||
return CommandLine.Float64SliceP(name, shorthand, value, usage)
|
|
||||||
}
|
|
3
vendor/github.com/spf13/pflag/go.mod
generated
vendored
3
vendor/github.com/spf13/pflag/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
module github.com/spf13/pflag
|
|
||||||
|
|
||||||
go 1.12
|
|
0
vendor/github.com/spf13/pflag/go.sum
generated
vendored
0
vendor/github.com/spf13/pflag/go.sum
generated
vendored
105
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
105
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package pflag
|
|
||||||
|
|
||||||
import (
|
|
||||||
goflag "flag"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// flagValueWrapper implements pflag.Value around a flag.Value. The main
|
|
||||||
// difference here is the addition of the Type method that returns a string
|
|
||||||
// name of the type. As this is generally unknown, we approximate that with
|
|
||||||
// reflection.
|
|
||||||
type flagValueWrapper struct {
|
|
||||||
inner goflag.Value
|
|
||||||
flagType string
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are just copying the boolFlag interface out of goflag as that is what
|
|
||||||
// they use to decide if a flag should get "true" when no arg is given.
|
|
||||||
type goBoolFlag interface {
|
|
||||||
goflag.Value
|
|
||||||
IsBoolFlag() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapFlagValue(v goflag.Value) Value {
|
|
||||||
// If the flag.Value happens to also be a pflag.Value, just use it directly.
|
|
||||||
if pv, ok := v.(Value); ok {
|
|
||||||
return pv
|
|
||||||
}
|
|
||||||
|
|
||||||
pv := &flagValueWrapper{
|
|
||||||
inner: v,
|
|
||||||
}
|
|
||||||
|
|
||||||
t := reflect.TypeOf(v)
|
|
||||||
if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
pv.flagType = strings.TrimSuffix(t.Name(), "Value")
|
|
||||||
return pv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *flagValueWrapper) String() string {
|
|
||||||
return v.inner.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *flagValueWrapper) Set(s string) error {
|
|
||||||
return v.inner.Set(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *flagValueWrapper) Type() string {
|
|
||||||
return v.flagType
|
|
||||||
}
|
|
||||||
|
|
||||||
// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag
|
|
||||||
// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei
|
|
||||||
// with both `-v` and `--v` in flags. If the golang flag was more than a single
|
|
||||||
// character (ex: `verbose`) it will only be accessible via `--verbose`
|
|
||||||
func PFlagFromGoFlag(goflag *goflag.Flag) *Flag {
|
|
||||||
// Remember the default value as a string; it won't change.
|
|
||||||
flag := &Flag{
|
|
||||||
Name: goflag.Name,
|
|
||||||
Usage: goflag.Usage,
|
|
||||||
Value: wrapFlagValue(goflag.Value),
|
|
||||||
// Looks like golang flags don't set DefValue correctly :-(
|
|
||||||
//DefValue: goflag.DefValue,
|
|
||||||
DefValue: goflag.Value.String(),
|
|
||||||
}
|
|
||||||
// Ex: if the golang flag was -v, allow both -v and --v to work
|
|
||||||
if len(flag.Name) == 1 {
|
|
||||||
flag.Shorthand = flag.Name
|
|
||||||
}
|
|
||||||
if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() {
|
|
||||||
flag.NoOptDefVal = "true"
|
|
||||||
}
|
|
||||||
return flag
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet
|
|
||||||
func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) {
|
|
||||||
if f.Lookup(goflag.Name) != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newflag := PFlagFromGoFlag(goflag)
|
|
||||||
f.AddFlag(newflag)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet
|
|
||||||
func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
|
|
||||||
if newSet == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newSet.VisitAll(func(goflag *goflag.Flag) {
|
|
||||||
f.AddGoFlag(goflag)
|
|
||||||
})
|
|
||||||
if f.addedGoFlagSets == nil {
|
|
||||||
f.addedGoFlagSets = make([]*goflag.FlagSet, 0)
|
|
||||||
}
|
|
||||||
f.addedGoFlagSets = append(f.addedGoFlagSets, newSet)
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user