diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b2d5e15f0..3b84a6021c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -117,7 +117,7 @@ jobs: type: string default: "" docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18.0 environment: PROVIDER: <> ARGS: <> @@ -136,14 +136,14 @@ jobs: when: always cleanup: docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18.0 steps: - checkout - ci-dependencies - run: scripts/ci-cleanup cleanup_all: docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18.0 steps: - checkout - ci-dependencies @@ -157,15 +157,15 @@ jobs: repo: type: string docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18.0 steps: - checkout - ci-dependencies - run: ci/deploy.sh <> <> <> test: docker: - - image: circleci/golang:1.17 - working_directory: /go/src/github.com/convox/rack + - image: cimg/go:1.18.0 + # working_directory: /go/src/github.com/convox/rack steps: - checkout - ci-dependencies @@ -176,7 +176,7 @@ jobs: - run: curl -s https://codecov.io/bash | bash update: docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18.0 steps: - checkout - ci-dependencies diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c2ba68f8ec..8d0ffd1162 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,10 +15,10 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - - name: golang-1.17 + - name: golang-1.18 uses: actions/setup-go@v3 with: - go-version: '1.17.13' + go-version: '1.18.10' - name: version run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV - name: secrets diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e7541d305..4e05146a5d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,10 +13,10 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - - name: golang-1.17 + - name: golang-1.18 uses: actions/setup-go@v3 with: - go-version: '1.17.13' + go-version: '1.18.10' - name: go path run: | mkdir -p ${HOME}/go @@ -45,8 +45,6 @@ jobs: run: ci/secrets.sh env: SECRETS: ${{ toJson(secrets) }} - - name: install packr - run: go get -u github.com/gobuffalo/packr/packr - name: release run: make release-all - name: create relase version diff --git a/Dockerfile b/Dockerfile index 70c22366f1..d7bcb94093 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ## test ######################################################################## -FROM golang:1.17 AS test +FROM golang:1.18 AS test ARG DOCKER_ARCH=x86_64 ARG KUBECTL_ARCH=amd64 @@ -18,7 +18,7 @@ WORKDIR /go/src/github.com/convox/rack COPY . . -RUN go install --ldflags="-s -w" ./vendor/... +RUN go build -mod=vendor --ldflags="-s -w" $(go list -mod=vendor ./vendor/...) ## development ################################################################# @@ -48,12 +48,10 @@ CMD ["bin/web"] ## package ##################################################################### -FROM golang:1.17 AS package +FROM golang:1.18 AS package RUN apt-get update && apt-get -y install upx-ucl -RUN go get -u github.com/gobuffalo/packr/packr - WORKDIR /go/src/github.com/convox/rack COPY --from=development /go/src/github.com/convox/rack . diff --git a/Dockerfile.arm b/Dockerfile.arm index 3b2d02fe68..f51a69fd88 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -1,11 +1,9 @@ ## package ##################################################################### -FROM golang:1.17 AS package +FROM golang:1.18 AS package RUN apt-get update && apt-get -y install upx-ucl -RUN go get -u github.com/gobuffalo/packr/packr - WORKDIR /go/src/github.com/convox/rack COPY . /go/src/github.com/convox/rack diff --git a/Makefile b/Makefile index 4e3806cd84..eb80b95113 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ mocks: generate-provider mockery -case underscore -dir vendor/github.com/convox/stdcli -outpkg stdcli -output pkg/mock/stdcli -name Executor package: - $(GOPATH)/bin/packr + go run -mod=vendor vendor/github.com/gobuffalo/packr/packr/main.go regions: @aws-vault exec convox-release-standard go run provider/aws/cmd/regions/main.go diff --git a/cmd/build/Dockerfile b/cmd/build/Dockerfile index 43bf10870a..272629e7f5 100644 --- a/cmd/build/Dockerfile +++ b/cmd/build/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17 +FROM golang:1.18 RUN curl -s https://download.docker.com/linux/static/stable/x86_64/docker-18.03.1-ce.tgz | \ tar -C /usr/bin --strip-components 1 -xz diff --git a/cmd/convox/Makefile b/cmd/convox/Makefile index 9f23971e36..dcbd58411f 100644 --- a/cmd/convox/Makefile +++ b/cmd/convox/Makefile @@ -21,7 +21,7 @@ package: go install github.com/crazy-max/xgo@v0.7.5 if [ -f /.dockerenv ]; then tar cz $(GOPATH) | docker run -v $(GOPATH):/gopath -i ubuntu tar xz -C /gopath --strip-components 2; fi - cd ../.. && $(GOPATH)/bin/xgo -branch $(shell git rev-parse HEAD) -pkg cmd/convox -out cmd/convox/pkg/convox -go 1.17.x -targets 'darwin/amd64' -ldflags "-X main.version=$(VERSION)" . + cd ../.. && $(GOPATH)/bin/xgo -branch $(shell git rev-parse HEAD) -pkg cmd/convox -out cmd/convox/pkg/convox -go 1.18.x -targets 'darwin/amd64' -ldflags "-X main.version=$(VERSION)" . if [ -f /.dockerenv ]; then mkdir -p pkg && docker run -v $(GOPATH):/gopath -i ubuntu tar czv /gopath/src/github.com/convox/rack/cmd/convox/pkg | tar xzv -C pkg --strip-components 8; fi release: package diff --git a/go.mod b/go.mod index 29f27041d5..b5039d0e9a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/convox/rack -go 1.17 +go 1.18 require ( github.com/PuerkitoBio/goquery v1.8.0 @@ -48,7 +48,25 @@ require ( ) require ( + github.com/BurntSushi/toml v0.3.1 // indirect github.com/adrg/xdg v0.2.1 // indirect + github.com/gobuffalo/buffalo-plugins v1.11.0 // indirect + github.com/gobuffalo/events v1.1.9 // indirect + github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794 // indirect + github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5 // indirect + github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c // indirect + github.com/gobuffalo/mapi v1.0.1 // indirect + github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d // indirect + github.com/gobuffalo/packr/v2 v2.0.0-rc.15 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/karrick/godirwalk v1.7.8 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect + github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 // indirect + github.com/markbates/safe v1.0.1 // indirect + github.com/sirupsen/logrus v1.6.0 // indirect + github.com/spf13/cobra v1.0.0 // indirect + golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect + golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b30ee2adcd..07254b7f79 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.5 h1:U2XsGR5dBg1yzwSEJoP2dE2/aAXpmad+CNG2hE9Pd5k= @@ -112,6 +113,7 @@ github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGp github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U= github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI= github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI= +github.com/gobuffalo/buffalo-plugins v1.11.0 h1:yZ6USaSdAKpogRS8DZJgeG7/CTPGmyhplwifphmmegw= github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg= github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8= github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= @@ -132,6 +134,7 @@ github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuA github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0= github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY= github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8= +github.com/gobuffalo/events v1.1.9 h1:ukq5ys/h0TuiX7eLJyZBD1dJOy0r19JTEYmgXKG9j+Y= github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM= github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= @@ -144,6 +147,7 @@ github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI= github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= +github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794 h1:HZOs07hF3AmoaUj4HJQHV5RqfOuGnPZI7aFcireIrww= github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k= github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= @@ -167,6 +171,7 @@ github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9 github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8= github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM= github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY= +github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5 h1:boQS3dA9PxhyufJEWIILrG6pJQbDnpwP2rFyvWacdoY= github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo= github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= @@ -184,15 +189,18 @@ github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2du github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew= github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I= +github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c h1:Z/ppYX6EtPEysbW4VEGz2dO+4F4VTthWp2sWRUCANdU= github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.1 h1:JRuTiZzDEZhBHkFiHTxJkYRT6CbYuL0K/rn+1byJoEA= github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM= github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE= github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg= github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE= github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8= +github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d h1:cP3lJDiGboBok8q6axF0rqWjlg/MOCfgjuwuNp5TlhE= github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM= github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0= github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No= @@ -227,6 +235,7 @@ github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8= github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA= github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= +github.com/gobuffalo/packr/v2 v2.0.0-rc.15 h1:vSmYcMO6CtuNQvMSbEJeIJlaeZzz2zoxGLTy8HrDh80= github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= @@ -325,6 +334,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= @@ -342,6 +352,7 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/karrick/godirwalk v1.7.8 h1:VfG72pyIxgtC7+3X9CMHI0AOl4LwyRAg98WAgsvffi8= github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -372,9 +383,11 @@ github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzfe github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 h1:JgVTCPf0uBVcUSWpyXmGpgOc62nK5HWUBKAGc3Qqa5k= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= @@ -476,6 +489,7 @@ github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -493,7 +507,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -556,7 +569,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -595,9 +607,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220913153101-76c7481b5158 h1:XQphkCZeKYaMRSo28HqvvNYuLOoM5CIOOvTZfthvTgI= golang.org/x/sys v0.0.0-20220913153101-76c7481b5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -636,6 +646,7 @@ golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 h1:xFbv3LvlvQAmbNJFCBKRv1Ccvnh9FVsW0FX2kTWWowE= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/provider/aws/formation/rack.json b/provider/aws/formation/rack.json index 72482ff56c..a2c053b91a 100644 --- a/provider/aws/formation/rack.json +++ b/provider/aws/formation/rack.json @@ -70,6 +70,17 @@ "" ] }, + { + "Fn::Equals": [ + { + "Fn::Select": [ + 0, + { "Fn::Split": ["r7g", { "Ref": "InstanceType" }] } + ] + }, + "" + ] + }, { "Fn::Equals": [ { @@ -81,6 +92,17 @@ "" ] }, + { + "Fn::Equals": [ + { + "Fn::Select": [ + 0, + { "Fn::Split": ["m7g", { "Ref": "InstanceType" }] } + ] + }, + "" + ] + }, { "Fn::Equals": [ { diff --git a/tools.go b/tools.go new file mode 100644 index 0000000000..b3db91833d --- /dev/null +++ b/tools.go @@ -0,0 +1,8 @@ +//go:build tools +// +build tools + +package convox + +import ( + _ "github.com/gobuffalo/packr/packr" +) diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore new file mode 100644 index 0000000000..0cd3800377 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/.gitignore @@ -0,0 +1,5 @@ +TAGS +tags +.*.swp +tomlcheck/tomlcheck +toml.test diff --git a/vendor/github.com/BurntSushi/toml/.travis.yml b/vendor/github.com/BurntSushi/toml/.travis.yml new file mode 100644 index 0000000000..8b8afc4f0e --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/.travis.yml @@ -0,0 +1,15 @@ +language: go +go: + - 1.1 + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - tip +install: + - go install ./... + - go get github.com/BurntSushi/toml-test +script: + - export PATH="$PATH:$HOME/gopath/bin" + - make test diff --git a/vendor/github.com/BurntSushi/toml/COMPATIBLE b/vendor/github.com/BurntSushi/toml/COMPATIBLE new file mode 100644 index 0000000000..6efcfd0ce5 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/COMPATIBLE @@ -0,0 +1,3 @@ +Compatible with TOML version +[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md) + diff --git a/vendor/github.com/BurntSushi/toml/COPYING b/vendor/github.com/BurntSushi/toml/COPYING new file mode 100644 index 0000000000..01b5743200 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/COPYING @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 TOML authors + +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. diff --git a/vendor/github.com/BurntSushi/toml/Makefile b/vendor/github.com/BurntSushi/toml/Makefile new file mode 100644 index 0000000000..3600848d33 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/Makefile @@ -0,0 +1,19 @@ +install: + go install ./... + +test: install + go test -v + toml-test toml-test-decoder + toml-test -encoder toml-test-encoder + +fmt: + gofmt -w *.go */*.go + colcheck *.go */*.go + +tags: + find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS + +push: + git push origin master + git push github master + diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md new file mode 100644 index 0000000000..7c1b37ecc7 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/README.md @@ -0,0 +1,218 @@ +## TOML parser and encoder for Go with reflection + +TOML stands for Tom's Obvious, Minimal Language. This Go package provides a +reflection interface similar to Go's standard library `json` and `xml` +packages. This package also supports the `encoding.TextUnmarshaler` and +`encoding.TextMarshaler` interfaces so that you can define custom data +representations. (There is an example of this below.) + +Spec: https://github.com/toml-lang/toml + +Compatible with TOML version +[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) + +Documentation: https://godoc.org/github.com/BurntSushi/toml + +Installation: + +```bash +go get github.com/BurntSushi/toml +``` + +Try the toml validator: + +```bash +go get github.com/BurntSushi/toml/cmd/tomlv +tomlv some-toml-file.toml +``` + +[![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml) + +### Testing + +This package passes all tests in +[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder +and the encoder. + +### Examples + +This package works similarly to how the Go standard library handles `XML` +and `JSON`. Namely, data is loaded into Go values via reflection. + +For the simplest example, consider some TOML file as just a list of keys +and values: + +```toml +Age = 25 +Cats = [ "Cauchy", "Plato" ] +Pi = 3.14 +Perfection = [ 6, 28, 496, 8128 ] +DOB = 1987-07-05T05:45:00Z +``` + +Which could be defined in Go as: + +```go +type Config struct { + Age int + Cats []string + Pi float64 + Perfection []int + DOB time.Time // requires `import time` +} +``` + +And then decoded with: + +```go +var conf Config +if _, err := toml.Decode(tomlData, &conf); err != nil { + // handle error +} +``` + +You can also use struct tags if your struct field name doesn't map to a TOML +key value directly: + +```toml +some_key_NAME = "wat" +``` + +```go +type TOML struct { + ObscureKey string `toml:"some_key_NAME"` +} +``` + +### Using the `encoding.TextUnmarshaler` interface + +Here's an example that automatically parses duration strings into +`time.Duration` values: + +```toml +[[song]] +name = "Thunder Road" +duration = "4m49s" + +[[song]] +name = "Stairway to Heaven" +duration = "8m03s" +``` + +Which can be decoded with: + +```go +type song struct { + Name string + Duration duration +} +type songs struct { + Song []song +} +var favorites songs +if _, err := toml.Decode(blob, &favorites); err != nil { + log.Fatal(err) +} + +for _, s := range favorites.Song { + fmt.Printf("%s (%s)\n", s.Name, s.Duration) +} +``` + +And you'll also need a `duration` type that satisfies the +`encoding.TextUnmarshaler` interface: + +```go +type duration struct { + time.Duration +} + +func (d *duration) UnmarshalText(text []byte) error { + var err error + d.Duration, err = time.ParseDuration(string(text)) + return err +} +``` + +### More complex usage + +Here's an example of how to load the example from the official spec page: + +```toml +# This is a TOML document. Boom. + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +organization = "GitHub" +bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." +dob = 1979-05-27T07:32:00Z # First class dates? Why not? + +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +[clients] +data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it + +# Line breaks are OK when inside arrays +hosts = [ + "alpha", + "omega" +] +``` + +And the corresponding Go types are: + +```go +type tomlConfig struct { + Title string + Owner ownerInfo + DB database `toml:"database"` + Servers map[string]server + Clients clients +} + +type ownerInfo struct { + Name string + Org string `toml:"organization"` + Bio string + DOB time.Time +} + +type database struct { + Server string + Ports []int + ConnMax int `toml:"connection_max"` + Enabled bool +} + +type server struct { + IP string + DC string +} + +type clients struct { + Data [][]interface{} + Hosts []string +} +``` + +Note that a case insensitive match will be tried if an exact match can't be +found. + +A working example of the above can be found in `_examples/example.{go,toml}`. diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go new file mode 100644 index 0000000000..b0fd51d5b6 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/decode.go @@ -0,0 +1,509 @@ +package toml + +import ( + "fmt" + "io" + "io/ioutil" + "math" + "reflect" + "strings" + "time" +) + +func e(format string, args ...interface{}) error { + return fmt.Errorf("toml: "+format, args...) +} + +// Unmarshaler is the interface implemented by objects that can unmarshal a +// TOML description of themselves. +type Unmarshaler interface { + UnmarshalTOML(interface{}) error +} + +// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. +func Unmarshal(p []byte, v interface{}) error { + _, err := Decode(string(p), v) + return err +} + +// Primitive is a TOML value that hasn't been decoded into a Go value. +// When using the various `Decode*` functions, the type `Primitive` may +// be given to any value, and its decoding will be delayed. +// +// A `Primitive` value can be decoded using the `PrimitiveDecode` function. +// +// The underlying representation of a `Primitive` value is subject to change. +// Do not rely on it. +// +// N.B. Primitive values are still parsed, so using them will only avoid +// the overhead of reflection. They can be useful when you don't know the +// exact type of TOML data until run time. +type Primitive struct { + undecoded interface{} + context Key +} + +// DEPRECATED! +// +// Use MetaData.PrimitiveDecode instead. +func PrimitiveDecode(primValue Primitive, v interface{}) error { + md := MetaData{decoded: make(map[string]bool)} + return md.unify(primValue.undecoded, rvalue(v)) +} + +// PrimitiveDecode is just like the other `Decode*` functions, except it +// decodes a TOML value that has already been parsed. Valid primitive values +// can *only* be obtained from values filled by the decoder functions, +// including this method. (i.e., `v` may contain more `Primitive` +// values.) +// +// Meta data for primitive values is included in the meta data returned by +// the `Decode*` functions with one exception: keys returned by the Undecoded +// method will only reflect keys that were decoded. Namely, any keys hidden +// behind a Primitive will be considered undecoded. Executing this method will +// update the undecoded keys in the meta data. (See the example.) +func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { + md.context = primValue.context + defer func() { md.context = nil }() + return md.unify(primValue.undecoded, rvalue(v)) +} + +// Decode will decode the contents of `data` in TOML format into a pointer +// `v`. +// +// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be +// used interchangeably.) +// +// TOML arrays of tables correspond to either a slice of structs or a slice +// of maps. +// +// TOML datetimes correspond to Go `time.Time` values. +// +// All other TOML types (float, string, int, bool and array) correspond +// to the obvious Go types. +// +// An exception to the above rules is if a type implements the +// encoding.TextUnmarshaler interface. In this case, any primitive TOML value +// (floats, strings, integers, booleans and datetimes) will be converted to +// a byte string and given to the value's UnmarshalText method. See the +// Unmarshaler example for a demonstration with time duration strings. +// +// Key mapping +// +// TOML keys can map to either keys in a Go map or field names in a Go +// struct. The special `toml` struct tag may be used to map TOML keys to +// struct fields that don't match the key name exactly. (See the example.) +// A case insensitive match to struct names will be tried if an exact match +// can't be found. +// +// The mapping between TOML values and Go values is loose. That is, there +// may exist TOML values that cannot be placed into your representation, and +// there may be parts of your representation that do not correspond to +// TOML values. This loose mapping can be made stricter by using the IsDefined +// and/or Undecoded methods on the MetaData returned. +// +// This decoder will not handle cyclic types. If a cyclic type is passed, +// `Decode` will not terminate. +func Decode(data string, v interface{}) (MetaData, error) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr { + return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v)) + } + if rv.IsNil() { + return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v)) + } + p, err := parse(data) + if err != nil { + return MetaData{}, err + } + md := MetaData{ + p.mapping, p.types, p.ordered, + make(map[string]bool, len(p.ordered)), nil, + } + return md, md.unify(p.mapping, indirect(rv)) +} + +// DecodeFile is just like Decode, except it will automatically read the +// contents of the file at `fpath` and decode it for you. +func DecodeFile(fpath string, v interface{}) (MetaData, error) { + bs, err := ioutil.ReadFile(fpath) + if err != nil { + return MetaData{}, err + } + return Decode(string(bs), v) +} + +// DecodeReader is just like Decode, except it will consume all bytes +// from the reader and decode it for you. +func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { + bs, err := ioutil.ReadAll(r) + if err != nil { + return MetaData{}, err + } + return Decode(string(bs), v) +} + +// unify performs a sort of type unification based on the structure of `rv`, +// which is the client representation. +// +// Any type mismatch produces an error. Finding a type that we don't know +// how to handle produces an unsupported type error. +func (md *MetaData) unify(data interface{}, rv reflect.Value) error { + + // Special case. Look for a `Primitive` value. + if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() { + // Save the undecoded data and the key context into the primitive + // value. + context := make(Key, len(md.context)) + copy(context, md.context) + rv.Set(reflect.ValueOf(Primitive{ + undecoded: data, + context: context, + })) + return nil + } + + // Special case. Unmarshaler Interface support. + if rv.CanAddr() { + if v, ok := rv.Addr().Interface().(Unmarshaler); ok { + return v.UnmarshalTOML(data) + } + } + + // Special case. Handle time.Time values specifically. + // TODO: Remove this code when we decide to drop support for Go 1.1. + // This isn't necessary in Go 1.2 because time.Time satisfies the encoding + // interfaces. + if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) { + return md.unifyDatetime(data, rv) + } + + // Special case. Look for a value satisfying the TextUnmarshaler interface. + if v, ok := rv.Interface().(TextUnmarshaler); ok { + return md.unifyText(data, v) + } + // BUG(burntsushi) + // The behavior here is incorrect whenever a Go type satisfies the + // encoding.TextUnmarshaler interface but also corresponds to a TOML + // hash or array. In particular, the unmarshaler should only be applied + // to primitive TOML values. But at this point, it will be applied to + // all kinds of values and produce an incorrect error whenever those values + // are hashes or arrays (including arrays of tables). + + k := rv.Kind() + + // laziness + if k >= reflect.Int && k <= reflect.Uint64 { + return md.unifyInt(data, rv) + } + switch k { + case reflect.Ptr: + elem := reflect.New(rv.Type().Elem()) + err := md.unify(data, reflect.Indirect(elem)) + if err != nil { + return err + } + rv.Set(elem) + return nil + case reflect.Struct: + return md.unifyStruct(data, rv) + case reflect.Map: + return md.unifyMap(data, rv) + case reflect.Array: + return md.unifyArray(data, rv) + case reflect.Slice: + return md.unifySlice(data, rv) + case reflect.String: + return md.unifyString(data, rv) + case reflect.Bool: + return md.unifyBool(data, rv) + case reflect.Interface: + // we only support empty interfaces. + if rv.NumMethod() > 0 { + return e("unsupported type %s", rv.Type()) + } + return md.unifyAnything(data, rv) + case reflect.Float32: + fallthrough + case reflect.Float64: + return md.unifyFloat64(data, rv) + } + return e("unsupported type %s", rv.Kind()) +} + +func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { + tmap, ok := mapping.(map[string]interface{}) + if !ok { + if mapping == nil { + return nil + } + return e("type mismatch for %s: expected table but found %T", + rv.Type().String(), mapping) + } + + for key, datum := range tmap { + var f *field + fields := cachedTypeFields(rv.Type()) + for i := range fields { + ff := &fields[i] + if ff.name == key { + f = ff + break + } + if f == nil && strings.EqualFold(ff.name, key) { + f = ff + } + } + if f != nil { + subv := rv + for _, i := range f.index { + subv = indirect(subv.Field(i)) + } + if isUnifiable(subv) { + md.decoded[md.context.add(key).String()] = true + md.context = append(md.context, key) + if err := md.unify(datum, subv); err != nil { + return err + } + md.context = md.context[0 : len(md.context)-1] + } else if f.name != "" { + // Bad user! No soup for you! + return e("cannot write unexported field %s.%s", + rv.Type().String(), f.name) + } + } + } + return nil +} + +func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { + tmap, ok := mapping.(map[string]interface{}) + if !ok { + if tmap == nil { + return nil + } + return badtype("map", mapping) + } + if rv.IsNil() { + rv.Set(reflect.MakeMap(rv.Type())) + } + for k, v := range tmap { + md.decoded[md.context.add(k).String()] = true + md.context = append(md.context, k) + + rvkey := indirect(reflect.New(rv.Type().Key())) + rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) + if err := md.unify(v, rvval); err != nil { + return err + } + md.context = md.context[0 : len(md.context)-1] + + rvkey.SetString(k) + rv.SetMapIndex(rvkey, rvval) + } + return nil +} + +func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { + datav := reflect.ValueOf(data) + if datav.Kind() != reflect.Slice { + if !datav.IsValid() { + return nil + } + return badtype("slice", data) + } + sliceLen := datav.Len() + if sliceLen != rv.Len() { + return e("expected array length %d; got TOML array of length %d", + rv.Len(), sliceLen) + } + return md.unifySliceArray(datav, rv) +} + +func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { + datav := reflect.ValueOf(data) + if datav.Kind() != reflect.Slice { + if !datav.IsValid() { + return nil + } + return badtype("slice", data) + } + n := datav.Len() + if rv.IsNil() || rv.Cap() < n { + rv.Set(reflect.MakeSlice(rv.Type(), n, n)) + } + rv.SetLen(n) + return md.unifySliceArray(datav, rv) +} + +func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { + sliceLen := data.Len() + for i := 0; i < sliceLen; i++ { + v := data.Index(i).Interface() + sliceval := indirect(rv.Index(i)) + if err := md.unify(v, sliceval); err != nil { + return err + } + } + return nil +} + +func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error { + if _, ok := data.(time.Time); ok { + rv.Set(reflect.ValueOf(data)) + return nil + } + return badtype("time.Time", data) +} + +func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { + if s, ok := data.(string); ok { + rv.SetString(s) + return nil + } + return badtype("string", data) +} + +func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { + if num, ok := data.(float64); ok { + switch rv.Kind() { + case reflect.Float32: + fallthrough + case reflect.Float64: + rv.SetFloat(num) + default: + panic("bug") + } + return nil + } + return badtype("float", data) +} + +func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { + if num, ok := data.(int64); ok { + if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 { + switch rv.Kind() { + case reflect.Int, reflect.Int64: + // No bounds checking necessary. + case reflect.Int8: + if num < math.MinInt8 || num > math.MaxInt8 { + return e("value %d is out of range for int8", num) + } + case reflect.Int16: + if num < math.MinInt16 || num > math.MaxInt16 { + return e("value %d is out of range for int16", num) + } + case reflect.Int32: + if num < math.MinInt32 || num > math.MaxInt32 { + return e("value %d is out of range for int32", num) + } + } + rv.SetInt(num) + } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 { + unum := uint64(num) + switch rv.Kind() { + case reflect.Uint, reflect.Uint64: + // No bounds checking necessary. + case reflect.Uint8: + if num < 0 || unum > math.MaxUint8 { + return e("value %d is out of range for uint8", num) + } + case reflect.Uint16: + if num < 0 || unum > math.MaxUint16 { + return e("value %d is out of range for uint16", num) + } + case reflect.Uint32: + if num < 0 || unum > math.MaxUint32 { + return e("value %d is out of range for uint32", num) + } + } + rv.SetUint(unum) + } else { + panic("unreachable") + } + return nil + } + return badtype("integer", data) +} + +func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { + if b, ok := data.(bool); ok { + rv.SetBool(b) + return nil + } + return badtype("boolean", data) +} + +func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { + rv.Set(reflect.ValueOf(data)) + return nil +} + +func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error { + var s string + switch sdata := data.(type) { + case TextMarshaler: + text, err := sdata.MarshalText() + if err != nil { + return err + } + s = string(text) + case fmt.Stringer: + s = sdata.String() + case string: + s = sdata + case bool: + s = fmt.Sprintf("%v", sdata) + case int64: + s = fmt.Sprintf("%d", sdata) + case float64: + s = fmt.Sprintf("%f", sdata) + default: + return badtype("primitive (string-like)", data) + } + if err := v.UnmarshalText([]byte(s)); err != nil { + return err + } + return nil +} + +// rvalue returns a reflect.Value of `v`. All pointers are resolved. +func rvalue(v interface{}) reflect.Value { + return indirect(reflect.ValueOf(v)) +} + +// indirect returns the value pointed to by a pointer. +// Pointers are followed until the value is not a pointer. +// New values are allocated for each nil pointer. +// +// An exception to this rule is if the value satisfies an interface of +// interest to us (like encoding.TextUnmarshaler). +func indirect(v reflect.Value) reflect.Value { + if v.Kind() != reflect.Ptr { + if v.CanSet() { + pv := v.Addr() + if _, ok := pv.Interface().(TextUnmarshaler); ok { + return pv + } + } + return v + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + return indirect(reflect.Indirect(v)) +} + +func isUnifiable(rv reflect.Value) bool { + if rv.CanSet() { + return true + } + if _, ok := rv.Interface().(TextUnmarshaler); ok { + return true + } + return false +} + +func badtype(expected string, data interface{}) error { + return e("cannot load TOML value of type %T into a Go %s", data, expected) +} diff --git a/vendor/github.com/BurntSushi/toml/decode_meta.go b/vendor/github.com/BurntSushi/toml/decode_meta.go new file mode 100644 index 0000000000..b9914a6798 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/decode_meta.go @@ -0,0 +1,121 @@ +package toml + +import "strings" + +// MetaData allows access to meta information about TOML data that may not +// be inferrable via reflection. In particular, whether a key has been defined +// and the TOML type of a key. +type MetaData struct { + mapping map[string]interface{} + types map[string]tomlType + keys []Key + decoded map[string]bool + context Key // Used only during decoding. +} + +// IsDefined returns true if the key given exists in the TOML data. The key +// should be specified hierarchially. e.g., +// +// // access the TOML key 'a.b.c' +// IsDefined("a", "b", "c") +// +// IsDefined will return false if an empty key given. Keys are case sensitive. +func (md *MetaData) IsDefined(key ...string) bool { + if len(key) == 0 { + return false + } + + var hash map[string]interface{} + var ok bool + var hashOrVal interface{} = md.mapping + for _, k := range key { + if hash, ok = hashOrVal.(map[string]interface{}); !ok { + return false + } + if hashOrVal, ok = hash[k]; !ok { + return false + } + } + return true +} + +// Type returns a string representation of the type of the key specified. +// +// Type will return the empty string if given an empty key or a key that +// does not exist. Keys are case sensitive. +func (md *MetaData) Type(key ...string) string { + fullkey := strings.Join(key, ".") + if typ, ok := md.types[fullkey]; ok { + return typ.typeString() + } + return "" +} + +// Key is the type of any TOML key, including key groups. Use (MetaData).Keys +// to get values of this type. +type Key []string + +func (k Key) String() string { + return strings.Join(k, ".") +} + +func (k Key) maybeQuotedAll() string { + var ss []string + for i := range k { + ss = append(ss, k.maybeQuoted(i)) + } + return strings.Join(ss, ".") +} + +func (k Key) maybeQuoted(i int) string { + quote := false + for _, c := range k[i] { + if !isBareKeyChar(c) { + quote = true + break + } + } + if quote { + return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" + } + return k[i] +} + +func (k Key) add(piece string) Key { + newKey := make(Key, len(k)+1) + copy(newKey, k) + newKey[len(k)] = piece + return newKey +} + +// Keys returns a slice of every key in the TOML data, including key groups. +// Each key is itself a slice, where the first element is the top of the +// hierarchy and the last is the most specific. +// +// The list will have the same order as the keys appeared in the TOML data. +// +// All keys returned are non-empty. +func (md *MetaData) Keys() []Key { + return md.keys +} + +// Undecoded returns all keys that have not been decoded in the order in which +// they appear in the original TOML document. +// +// This includes keys that haven't been decoded because of a Primitive value. +// Once the Primitive value is decoded, the keys will be considered decoded. +// +// Also note that decoding into an empty interface will result in no decoding, +// and so no keys will be considered decoded. +// +// In this sense, the Undecoded keys correspond to keys in the TOML document +// that do not have a concrete type in your representation. +func (md *MetaData) Undecoded() []Key { + undecoded := make([]Key, 0, len(md.keys)) + for _, key := range md.keys { + if !md.decoded[key.String()] { + undecoded = append(undecoded, key) + } + } + return undecoded +} diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go new file mode 100644 index 0000000000..b371f396ed --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/doc.go @@ -0,0 +1,27 @@ +/* +Package toml provides facilities for decoding and encoding TOML configuration +files via reflection. There is also support for delaying decoding with +the Primitive type, and querying the set of keys in a TOML document with the +MetaData type. + +The specification implemented: https://github.com/toml-lang/toml + +The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify +whether a file is a valid TOML document. It can also be used to print the +type of each key in a TOML document. + +Testing + +There are two important types of tests used for this package. The first is +contained inside '*_test.go' files and uses the standard Go unit testing +framework. These tests are primarily devoted to holistically testing the +decoder and encoder. + +The second type of testing is used to verify the implementation's adherence +to the TOML specification. These tests have been factored into their own +project: https://github.com/BurntSushi/toml-test + +The reason the tests are in a separate project is so that they can be used by +any implementation of TOML. Namely, it is language agnostic. +*/ +package toml diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go new file mode 100644 index 0000000000..d905c21a24 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -0,0 +1,568 @@ +package toml + +import ( + "bufio" + "errors" + "fmt" + "io" + "reflect" + "sort" + "strconv" + "strings" + "time" +) + +type tomlEncodeError struct{ error } + +var ( + errArrayMixedElementTypes = errors.New( + "toml: cannot encode array with mixed element types") + errArrayNilElement = errors.New( + "toml: cannot encode array with nil element") + errNonString = errors.New( + "toml: cannot encode a map with non-string key type") + errAnonNonStruct = errors.New( + "toml: cannot encode an anonymous field that is not a struct") + errArrayNoTable = errors.New( + "toml: TOML array element cannot contain a table") + errNoKey = errors.New( + "toml: top-level values must be Go maps or structs") + errAnything = errors.New("") // used in testing +) + +var quotedReplacer = strings.NewReplacer( + "\t", "\\t", + "\n", "\\n", + "\r", "\\r", + "\"", "\\\"", + "\\", "\\\\", +) + +// Encoder controls the encoding of Go values to a TOML document to some +// io.Writer. +// +// The indentation level can be controlled with the Indent field. +type Encoder struct { + // A single indentation level. By default it is two spaces. + Indent string + + // hasWritten is whether we have written any output to w yet. + hasWritten bool + w *bufio.Writer +} + +// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer +// given. By default, a single indentation level is 2 spaces. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + w: bufio.NewWriter(w), + Indent: " ", + } +} + +// Encode writes a TOML representation of the Go value to the underlying +// io.Writer. If the value given cannot be encoded to a valid TOML document, +// then an error is returned. +// +// The mapping between Go values and TOML values should be precisely the same +// as for the Decode* functions. Similarly, the TextMarshaler interface is +// supported by encoding the resulting bytes as strings. (If you want to write +// arbitrary binary data then you will need to use something like base64 since +// TOML does not have any binary types.) +// +// When encoding TOML hashes (i.e., Go maps or structs), keys without any +// sub-hashes are encoded first. +// +// If a Go map is encoded, then its keys are sorted alphabetically for +// deterministic output. More control over this behavior may be provided if +// there is demand for it. +// +// Encoding Go values without a corresponding TOML representation---like map +// types with non-string keys---will cause an error to be returned. Similarly +// for mixed arrays/slices, arrays/slices with nil elements, embedded +// non-struct types and nested slices containing maps or structs. +// (e.g., [][]map[string]string is not allowed but []map[string]string is OK +// and so is []map[string][]string.) +func (enc *Encoder) Encode(v interface{}) error { + rv := eindirect(reflect.ValueOf(v)) + if err := enc.safeEncode(Key([]string{}), rv); err != nil { + return err + } + return enc.w.Flush() +} + +func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) { + defer func() { + if r := recover(); r != nil { + if terr, ok := r.(tomlEncodeError); ok { + err = terr.error + return + } + panic(r) + } + }() + enc.encode(key, rv) + return nil +} + +func (enc *Encoder) encode(key Key, rv reflect.Value) { + // Special case. Time needs to be in ISO8601 format. + // Special case. If we can marshal the type to text, then we used that. + // Basically, this prevents the encoder for handling these types as + // generic structs (or whatever the underlying type of a TextMarshaler is). + switch rv.Interface().(type) { + case time.Time, TextMarshaler: + enc.keyEqElement(key, rv) + return + } + + k := rv.Kind() + switch k { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, + reflect.Uint64, + reflect.Float32, reflect.Float64, reflect.String, reflect.Bool: + enc.keyEqElement(key, rv) + case reflect.Array, reflect.Slice: + if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) { + enc.eArrayOfTables(key, rv) + } else { + enc.keyEqElement(key, rv) + } + case reflect.Interface: + if rv.IsNil() { + return + } + enc.encode(key, rv.Elem()) + case reflect.Map: + if rv.IsNil() { + return + } + enc.eTable(key, rv) + case reflect.Ptr: + if rv.IsNil() { + return + } + enc.encode(key, rv.Elem()) + case reflect.Struct: + enc.eTable(key, rv) + default: + panic(e("unsupported type for key '%s': %s", key, k)) + } +} + +// eElement encodes any value that can be an array element (primitives and +// arrays). +func (enc *Encoder) eElement(rv reflect.Value) { + switch v := rv.Interface().(type) { + case time.Time: + // Special case time.Time as a primitive. Has to come before + // TextMarshaler below because time.Time implements + // encoding.TextMarshaler, but we need to always use UTC. + enc.wf(v.UTC().Format("2006-01-02T15:04:05Z")) + return + case TextMarshaler: + // Special case. Use text marshaler if it's available for this value. + if s, err := v.MarshalText(); err != nil { + encPanic(err) + } else { + enc.writeQuoted(string(s)) + } + return + } + switch rv.Kind() { + case reflect.Bool: + enc.wf(strconv.FormatBool(rv.Bool())) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64: + enc.wf(strconv.FormatInt(rv.Int(), 10)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, + reflect.Uint32, reflect.Uint64: + enc.wf(strconv.FormatUint(rv.Uint(), 10)) + case reflect.Float32: + enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32))) + case reflect.Float64: + enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64))) + case reflect.Array, reflect.Slice: + enc.eArrayOrSliceElement(rv) + case reflect.Interface: + enc.eElement(rv.Elem()) + case reflect.String: + enc.writeQuoted(rv.String()) + default: + panic(e("unexpected primitive type: %s", rv.Kind())) + } +} + +// By the TOML spec, all floats must have a decimal with at least one +// number on either side. +func floatAddDecimal(fstr string) string { + if !strings.Contains(fstr, ".") { + return fstr + ".0" + } + return fstr +} + +func (enc *Encoder) writeQuoted(s string) { + enc.wf("\"%s\"", quotedReplacer.Replace(s)) +} + +func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) { + length := rv.Len() + enc.wf("[") + for i := 0; i < length; i++ { + elem := rv.Index(i) + enc.eElement(elem) + if i != length-1 { + enc.wf(", ") + } + } + enc.wf("]") +} + +func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { + if len(key) == 0 { + encPanic(errNoKey) + } + for i := 0; i < rv.Len(); i++ { + trv := rv.Index(i) + if isNil(trv) { + continue + } + panicIfInvalidKey(key) + enc.newline() + enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll()) + enc.newline() + enc.eMapOrStruct(key, trv) + } +} + +func (enc *Encoder) eTable(key Key, rv reflect.Value) { + panicIfInvalidKey(key) + if len(key) == 1 { + // Output an extra newline between top-level tables. + // (The newline isn't written if nothing else has been written though.) + enc.newline() + } + if len(key) > 0 { + enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll()) + enc.newline() + } + enc.eMapOrStruct(key, rv) +} + +func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) { + switch rv := eindirect(rv); rv.Kind() { + case reflect.Map: + enc.eMap(key, rv) + case reflect.Struct: + enc.eStruct(key, rv) + default: + panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String()) + } +} + +func (enc *Encoder) eMap(key Key, rv reflect.Value) { + rt := rv.Type() + if rt.Key().Kind() != reflect.String { + encPanic(errNonString) + } + + // Sort keys so that we have deterministic output. And write keys directly + // underneath this key first, before writing sub-structs or sub-maps. + var mapKeysDirect, mapKeysSub []string + for _, mapKey := range rv.MapKeys() { + k := mapKey.String() + if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) { + mapKeysSub = append(mapKeysSub, k) + } else { + mapKeysDirect = append(mapKeysDirect, k) + } + } + + var writeMapKeys = func(mapKeys []string) { + sort.Strings(mapKeys) + for _, mapKey := range mapKeys { + mrv := rv.MapIndex(reflect.ValueOf(mapKey)) + if isNil(mrv) { + // Don't write anything for nil fields. + continue + } + enc.encode(key.add(mapKey), mrv) + } + } + writeMapKeys(mapKeysDirect) + writeMapKeys(mapKeysSub) +} + +func (enc *Encoder) eStruct(key Key, rv reflect.Value) { + // Write keys for fields directly under this key first, because if we write + // a field that creates a new table, then all keys under it will be in that + // table (not the one we're writing here). + rt := rv.Type() + var fieldsDirect, fieldsSub [][]int + var addFields func(rt reflect.Type, rv reflect.Value, start []int) + addFields = func(rt reflect.Type, rv reflect.Value, start []int) { + for i := 0; i < rt.NumField(); i++ { + f := rt.Field(i) + // skip unexported fields + if f.PkgPath != "" && !f.Anonymous { + continue + } + frv := rv.Field(i) + if f.Anonymous { + t := f.Type + switch t.Kind() { + case reflect.Struct: + // Treat anonymous struct fields with + // tag names as though they are not + // anonymous, like encoding/json does. + if getOptions(f.Tag).name == "" { + addFields(t, frv, f.Index) + continue + } + case reflect.Ptr: + if t.Elem().Kind() == reflect.Struct && + getOptions(f.Tag).name == "" { + if !frv.IsNil() { + addFields(t.Elem(), frv.Elem(), f.Index) + } + continue + } + // Fall through to the normal field encoding logic below + // for non-struct anonymous fields. + } + } + + if typeIsHash(tomlTypeOfGo(frv)) { + fieldsSub = append(fieldsSub, append(start, f.Index...)) + } else { + fieldsDirect = append(fieldsDirect, append(start, f.Index...)) + } + } + } + addFields(rt, rv, nil) + + var writeFields = func(fields [][]int) { + for _, fieldIndex := range fields { + sft := rt.FieldByIndex(fieldIndex) + sf := rv.FieldByIndex(fieldIndex) + if isNil(sf) { + // Don't write anything for nil fields. + continue + } + + opts := getOptions(sft.Tag) + if opts.skip { + continue + } + keyName := sft.Name + if opts.name != "" { + keyName = opts.name + } + if opts.omitempty && isEmpty(sf) { + continue + } + if opts.omitzero && isZero(sf) { + continue + } + + enc.encode(key.add(keyName), sf) + } + } + writeFields(fieldsDirect) + writeFields(fieldsSub) +} + +// tomlTypeName returns the TOML type name of the Go value's type. It is +// used to determine whether the types of array elements are mixed (which is +// forbidden). If the Go value is nil, then it is illegal for it to be an array +// element, and valueIsNil is returned as true. + +// Returns the TOML type of a Go value. The type may be `nil`, which means +// no concrete TOML type could be found. +func tomlTypeOfGo(rv reflect.Value) tomlType { + if isNil(rv) || !rv.IsValid() { + return nil + } + switch rv.Kind() { + case reflect.Bool: + return tomlBool + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, + reflect.Uint64: + return tomlInteger + case reflect.Float32, reflect.Float64: + return tomlFloat + case reflect.Array, reflect.Slice: + if typeEqual(tomlHash, tomlArrayType(rv)) { + return tomlArrayHash + } + return tomlArray + case reflect.Ptr, reflect.Interface: + return tomlTypeOfGo(rv.Elem()) + case reflect.String: + return tomlString + case reflect.Map: + return tomlHash + case reflect.Struct: + switch rv.Interface().(type) { + case time.Time: + return tomlDatetime + case TextMarshaler: + return tomlString + default: + return tomlHash + } + default: + panic("unexpected reflect.Kind: " + rv.Kind().String()) + } +} + +// tomlArrayType returns the element type of a TOML array. The type returned +// may be nil if it cannot be determined (e.g., a nil slice or a zero length +// slize). This function may also panic if it finds a type that cannot be +// expressed in TOML (such as nil elements, heterogeneous arrays or directly +// nested arrays of tables). +func tomlArrayType(rv reflect.Value) tomlType { + if isNil(rv) || !rv.IsValid() || rv.Len() == 0 { + return nil + } + firstType := tomlTypeOfGo(rv.Index(0)) + if firstType == nil { + encPanic(errArrayNilElement) + } + + rvlen := rv.Len() + for i := 1; i < rvlen; i++ { + elem := rv.Index(i) + switch elemType := tomlTypeOfGo(elem); { + case elemType == nil: + encPanic(errArrayNilElement) + case !typeEqual(firstType, elemType): + encPanic(errArrayMixedElementTypes) + } + } + // If we have a nested array, then we must make sure that the nested + // array contains ONLY primitives. + // This checks arbitrarily nested arrays. + if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) { + nest := tomlArrayType(eindirect(rv.Index(0))) + if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) { + encPanic(errArrayNoTable) + } + } + return firstType +} + +type tagOptions struct { + skip bool // "-" + name string + omitempty bool + omitzero bool +} + +func getOptions(tag reflect.StructTag) tagOptions { + t := tag.Get("toml") + if t == "-" { + return tagOptions{skip: true} + } + var opts tagOptions + parts := strings.Split(t, ",") + opts.name = parts[0] + for _, s := range parts[1:] { + switch s { + case "omitempty": + opts.omitempty = true + case "omitzero": + opts.omitzero = true + } + } + return opts +} + +func isZero(rv reflect.Value) bool { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return rv.Uint() == 0 + case reflect.Float32, reflect.Float64: + return rv.Float() == 0.0 + } + return false +} + +func isEmpty(rv reflect.Value) bool { + switch rv.Kind() { + case reflect.Array, reflect.Slice, reflect.Map, reflect.String: + return rv.Len() == 0 + case reflect.Bool: + return !rv.Bool() + } + return false +} + +func (enc *Encoder) newline() { + if enc.hasWritten { + enc.wf("\n") + } +} + +func (enc *Encoder) keyEqElement(key Key, val reflect.Value) { + if len(key) == 0 { + encPanic(errNoKey) + } + panicIfInvalidKey(key) + enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) + enc.eElement(val) + enc.newline() +} + +func (enc *Encoder) wf(format string, v ...interface{}) { + if _, err := fmt.Fprintf(enc.w, format, v...); err != nil { + encPanic(err) + } + enc.hasWritten = true +} + +func (enc *Encoder) indentStr(key Key) string { + return strings.Repeat(enc.Indent, len(key)-1) +} + +func encPanic(err error) { + panic(tomlEncodeError{err}) +} + +func eindirect(v reflect.Value) reflect.Value { + switch v.Kind() { + case reflect.Ptr, reflect.Interface: + return eindirect(v.Elem()) + default: + return v + } +} + +func isNil(rv reflect.Value) bool { + switch rv.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return rv.IsNil() + default: + return false + } +} + +func panicIfInvalidKey(key Key) { + for _, k := range key { + if len(k) == 0 { + encPanic(e("Key '%s' is not a valid table name. Key names "+ + "cannot be empty.", key.maybeQuotedAll())) + } + } +} + +func isValidKeyName(s string) bool { + return len(s) != 0 +} diff --git a/vendor/github.com/BurntSushi/toml/encoding_types.go b/vendor/github.com/BurntSushi/toml/encoding_types.go new file mode 100644 index 0000000000..d36e1dd600 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/encoding_types.go @@ -0,0 +1,19 @@ +// +build go1.2 + +package toml + +// In order to support Go 1.1, we define our own TextMarshaler and +// TextUnmarshaler types. For Go 1.2+, we just alias them with the +// standard library interfaces. + +import ( + "encoding" +) + +// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here +// so that Go 1.1 can be supported. +type TextMarshaler encoding.TextMarshaler + +// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined +// here so that Go 1.1 can be supported. +type TextUnmarshaler encoding.TextUnmarshaler diff --git a/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go b/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go new file mode 100644 index 0000000000..e8d503d046 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go @@ -0,0 +1,18 @@ +// +build !go1.2 + +package toml + +// These interfaces were introduced in Go 1.2, so we add them manually when +// compiling for Go 1.1. + +// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here +// so that Go 1.1 can be supported. +type TextMarshaler interface { + MarshalText() (text []byte, err error) +} + +// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined +// here so that Go 1.1 can be supported. +type TextUnmarshaler interface { + UnmarshalText(text []byte) error +} diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go new file mode 100644 index 0000000000..e0a742a887 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -0,0 +1,953 @@ +package toml + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" +) + +type itemType int + +const ( + itemError itemType = iota + itemNIL // used in the parser to indicate no type + itemEOF + itemText + itemString + itemRawString + itemMultilineString + itemRawMultilineString + itemBool + itemInteger + itemFloat + itemDatetime + itemArray // the start of an array + itemArrayEnd + itemTableStart + itemTableEnd + itemArrayTableStart + itemArrayTableEnd + itemKeyStart + itemCommentStart + itemInlineTableStart + itemInlineTableEnd +) + +const ( + eof = 0 + comma = ',' + tableStart = '[' + tableEnd = ']' + arrayTableStart = '[' + arrayTableEnd = ']' + tableSep = '.' + keySep = '=' + arrayStart = '[' + arrayEnd = ']' + commentStart = '#' + stringStart = '"' + stringEnd = '"' + rawStringStart = '\'' + rawStringEnd = '\'' + inlineTableStart = '{' + inlineTableEnd = '}' +) + +type stateFn func(lx *lexer) stateFn + +type lexer struct { + input string + start int + pos int + line int + state stateFn + items chan item + + // Allow for backing up up to three runes. + // This is necessary because TOML contains 3-rune tokens (""" and '''). + prevWidths [3]int + nprev int // how many of prevWidths are in use + // If we emit an eof, we can still back up, but it is not OK to call + // next again. + atEOF bool + + // A stack of state functions used to maintain context. + // The idea is to reuse parts of the state machine in various places. + // For example, values can appear at the top level or within arbitrarily + // nested arrays. The last state on the stack is used after a value has + // been lexed. Similarly for comments. + stack []stateFn +} + +type item struct { + typ itemType + val string + line int +} + +func (lx *lexer) nextItem() item { + for { + select { + case item := <-lx.items: + return item + default: + lx.state = lx.state(lx) + } + } +} + +func lex(input string) *lexer { + lx := &lexer{ + input: input, + state: lexTop, + line: 1, + items: make(chan item, 10), + stack: make([]stateFn, 0, 10), + } + return lx +} + +func (lx *lexer) push(state stateFn) { + lx.stack = append(lx.stack, state) +} + +func (lx *lexer) pop() stateFn { + if len(lx.stack) == 0 { + return lx.errorf("BUG in lexer: no states to pop") + } + last := lx.stack[len(lx.stack)-1] + lx.stack = lx.stack[0 : len(lx.stack)-1] + return last +} + +func (lx *lexer) current() string { + return lx.input[lx.start:lx.pos] +} + +func (lx *lexer) emit(typ itemType) { + lx.items <- item{typ, lx.current(), lx.line} + lx.start = lx.pos +} + +func (lx *lexer) emitTrim(typ itemType) { + lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line} + lx.start = lx.pos +} + +func (lx *lexer) next() (r rune) { + if lx.atEOF { + panic("next called after EOF") + } + if lx.pos >= len(lx.input) { + lx.atEOF = true + return eof + } + + if lx.input[lx.pos] == '\n' { + lx.line++ + } + lx.prevWidths[2] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[0] + if lx.nprev < 3 { + lx.nprev++ + } + r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) + lx.prevWidths[0] = w + lx.pos += w + return r +} + +// ignore skips over the pending input before this point. +func (lx *lexer) ignore() { + lx.start = lx.pos +} + +// backup steps back one rune. Can be called only twice between calls to next. +func (lx *lexer) backup() { + if lx.atEOF { + lx.atEOF = false + return + } + if lx.nprev < 1 { + panic("backed up too far") + } + w := lx.prevWidths[0] + lx.prevWidths[0] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[2] + lx.nprev-- + lx.pos -= w + if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { + lx.line-- + } +} + +// accept consumes the next rune if it's equal to `valid`. +func (lx *lexer) accept(valid rune) bool { + if lx.next() == valid { + return true + } + lx.backup() + return false +} + +// peek returns but does not consume the next rune in the input. +func (lx *lexer) peek() rune { + r := lx.next() + lx.backup() + return r +} + +// skip ignores all input that matches the given predicate. +func (lx *lexer) skip(pred func(rune) bool) { + for { + r := lx.next() + if pred(r) { + continue + } + lx.backup() + lx.ignore() + return + } +} + +// errorf stops all lexing by emitting an error and returning `nil`. +// Note that any value that is a character is escaped if it's a special +// character (newlines, tabs, etc.). +func (lx *lexer) errorf(format string, values ...interface{}) stateFn { + lx.items <- item{ + itemError, + fmt.Sprintf(format, values...), + lx.line, + } + return nil +} + +// lexTop consumes elements at the top level of TOML data. +func lexTop(lx *lexer) stateFn { + r := lx.next() + if isWhitespace(r) || isNL(r) { + return lexSkip(lx, lexTop) + } + switch r { + case commentStart: + lx.push(lexTop) + return lexCommentStart + case tableStart: + return lexTableStart + case eof: + if lx.pos > lx.start { + return lx.errorf("unexpected EOF") + } + lx.emit(itemEOF) + return nil + } + + // At this point, the only valid item can be a key, so we back up + // and let the key lexer do the rest. + lx.backup() + lx.push(lexTopEnd) + return lexKeyStart +} + +// lexTopEnd is entered whenever a top-level item has been consumed. (A value +// or a table.) It must see only whitespace, and will turn back to lexTop +// upon a newline. If it sees EOF, it will quit the lexer successfully. +func lexTopEnd(lx *lexer) stateFn { + r := lx.next() + switch { + case r == commentStart: + // a comment will read to a newline for us. + lx.push(lexTop) + return lexCommentStart + case isWhitespace(r): + return lexTopEnd + case isNL(r): + lx.ignore() + return lexTop + case r == eof: + lx.emit(itemEOF) + return nil + } + return lx.errorf("expected a top-level item to end with a newline, "+ + "comment, or EOF, but got %q instead", r) +} + +// lexTable lexes the beginning of a table. Namely, it makes sure that +// it starts with a character other than '.' and ']'. +// It assumes that '[' has already been consumed. +// It also handles the case that this is an item in an array of tables. +// e.g., '[[name]]'. +func lexTableStart(lx *lexer) stateFn { + if lx.peek() == arrayTableStart { + lx.next() + lx.emit(itemArrayTableStart) + lx.push(lexArrayTableEnd) + } else { + lx.emit(itemTableStart) + lx.push(lexTableEnd) + } + return lexTableNameStart +} + +func lexTableEnd(lx *lexer) stateFn { + lx.emit(itemTableEnd) + return lexTopEnd +} + +func lexArrayTableEnd(lx *lexer) stateFn { + if r := lx.next(); r != arrayTableEnd { + return lx.errorf("expected end of table array name delimiter %q, "+ + "but got %q instead", arrayTableEnd, r) + } + lx.emit(itemArrayTableEnd) + return lexTopEnd +} + +func lexTableNameStart(lx *lexer) stateFn { + lx.skip(isWhitespace) + switch r := lx.peek(); { + case r == tableEnd || r == eof: + return lx.errorf("unexpected end of table name " + + "(table names cannot be empty)") + case r == tableSep: + return lx.errorf("unexpected table separator " + + "(table names cannot be empty)") + case r == stringStart || r == rawStringStart: + lx.ignore() + lx.push(lexTableNameEnd) + return lexValue // reuse string lexing + default: + return lexBareTableName + } +} + +// lexBareTableName lexes the name of a table. It assumes that at least one +// valid character for the table has already been read. +func lexBareTableName(lx *lexer) stateFn { + r := lx.next() + if isBareKeyChar(r) { + return lexBareTableName + } + lx.backup() + lx.emit(itemText) + return lexTableNameEnd +} + +// lexTableNameEnd reads the end of a piece of a table name, optionally +// consuming whitespace. +func lexTableNameEnd(lx *lexer) stateFn { + lx.skip(isWhitespace) + switch r := lx.next(); { + case isWhitespace(r): + return lexTableNameEnd + case r == tableSep: + lx.ignore() + return lexTableNameStart + case r == tableEnd: + return lx.pop() + default: + return lx.errorf("expected '.' or ']' to end table name, "+ + "but got %q instead", r) + } +} + +// lexKeyStart consumes a key name up until the first non-whitespace character. +// lexKeyStart will ignore whitespace. +func lexKeyStart(lx *lexer) stateFn { + r := lx.peek() + switch { + case r == keySep: + return lx.errorf("unexpected key separator %q", keySep) + case isWhitespace(r) || isNL(r): + lx.next() + return lexSkip(lx, lexKeyStart) + case r == stringStart || r == rawStringStart: + lx.ignore() + lx.emit(itemKeyStart) + lx.push(lexKeyEnd) + return lexValue // reuse string lexing + default: + lx.ignore() + lx.emit(itemKeyStart) + return lexBareKey + } +} + +// lexBareKey consumes the text of a bare key. Assumes that the first character +// (which is not whitespace) has not yet been consumed. +func lexBareKey(lx *lexer) stateFn { + switch r := lx.next(); { + case isBareKeyChar(r): + return lexBareKey + case isWhitespace(r): + lx.backup() + lx.emit(itemText) + return lexKeyEnd + case r == keySep: + lx.backup() + lx.emit(itemText) + return lexKeyEnd + default: + return lx.errorf("bare keys cannot contain %q", r) + } +} + +// lexKeyEnd consumes the end of a key and trims whitespace (up to the key +// separator). +func lexKeyEnd(lx *lexer) stateFn { + switch r := lx.next(); { + case r == keySep: + return lexSkip(lx, lexValue) + case isWhitespace(r): + return lexSkip(lx, lexKeyEnd) + default: + return lx.errorf("expected key separator %q, but got %q instead", + keySep, r) + } +} + +// lexValue starts the consumption of a value anywhere a value is expected. +// lexValue will ignore whitespace. +// After a value is lexed, the last state on the next is popped and returned. +func lexValue(lx *lexer) stateFn { + // We allow whitespace to precede a value, but NOT newlines. + // In array syntax, the array states are responsible for ignoring newlines. + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexValue) + case isDigit(r): + lx.backup() // avoid an extra state and use the same as above + return lexNumberOrDateStart + } + switch r { + case arrayStart: + lx.ignore() + lx.emit(itemArray) + return lexArrayValue + case inlineTableStart: + lx.ignore() + lx.emit(itemInlineTableStart) + return lexInlineTableValue + case stringStart: + if lx.accept(stringStart) { + if lx.accept(stringStart) { + lx.ignore() // Ignore """ + return lexMultilineString + } + lx.backup() + } + lx.ignore() // ignore the '"' + return lexString + case rawStringStart: + if lx.accept(rawStringStart) { + if lx.accept(rawStringStart) { + lx.ignore() // Ignore """ + return lexMultilineRawString + } + lx.backup() + } + lx.ignore() // ignore the "'" + return lexRawString + case '+', '-': + return lexNumberStart + case '.': // special error case, be kind to users + return lx.errorf("floats must start with a digit, not '.'") + } + if unicode.IsLetter(r) { + // Be permissive here; lexBool will give a nice error if the + // user wrote something like + // x = foo + // (i.e. not 'true' or 'false' but is something else word-like.) + lx.backup() + return lexBool + } + return lx.errorf("expected value but found %q instead", r) +} + +// lexArrayValue consumes one value in an array. It assumes that '[' or ',' +// have already been consumed. All whitespace and newlines are ignored. +func lexArrayValue(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r) || isNL(r): + return lexSkip(lx, lexArrayValue) + case r == commentStart: + lx.push(lexArrayValue) + return lexCommentStart + case r == comma: + return lx.errorf("unexpected comma") + case r == arrayEnd: + // NOTE(caleb): The spec isn't clear about whether you can have + // a trailing comma or not, so we'll allow it. + return lexArrayEnd + } + + lx.backup() + lx.push(lexArrayValueEnd) + return lexValue +} + +// lexArrayValueEnd consumes everything between the end of an array value and +// the next value (or the end of the array): it ignores whitespace and newlines +// and expects either a ',' or a ']'. +func lexArrayValueEnd(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r) || isNL(r): + return lexSkip(lx, lexArrayValueEnd) + case r == commentStart: + lx.push(lexArrayValueEnd) + return lexCommentStart + case r == comma: + lx.ignore() + return lexArrayValue // move on to the next value + case r == arrayEnd: + return lexArrayEnd + } + return lx.errorf( + "expected a comma or array terminator %q, but got %q instead", + arrayEnd, r, + ) +} + +// lexArrayEnd finishes the lexing of an array. +// It assumes that a ']' has just been consumed. +func lexArrayEnd(lx *lexer) stateFn { + lx.ignore() + lx.emit(itemArrayEnd) + return lx.pop() +} + +// lexInlineTableValue consumes one key/value pair in an inline table. +// It assumes that '{' or ',' have already been consumed. Whitespace is ignored. +func lexInlineTableValue(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValue) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValue) + return lexCommentStart + case r == comma: + return lx.errorf("unexpected comma") + case r == inlineTableEnd: + return lexInlineTableEnd + } + lx.backup() + lx.push(lexInlineTableValueEnd) + return lexKeyStart +} + +// lexInlineTableValueEnd consumes everything between the end of an inline table +// key/value pair and the next pair (or the end of the table): +// it ignores whitespace and expects either a ',' or a '}'. +func lexInlineTableValueEnd(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValueEnd) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValueEnd) + return lexCommentStart + case r == comma: + lx.ignore() + return lexInlineTableValue + case r == inlineTableEnd: + return lexInlineTableEnd + } + return lx.errorf("expected a comma or an inline table terminator %q, "+ + "but got %q instead", inlineTableEnd, r) +} + +// lexInlineTableEnd finishes the lexing of an inline table. +// It assumes that a '}' has just been consumed. +func lexInlineTableEnd(lx *lexer) stateFn { + lx.ignore() + lx.emit(itemInlineTableEnd) + return lx.pop() +} + +// lexString consumes the inner contents of a string. It assumes that the +// beginning '"' has already been consumed and ignored. +func lexString(lx *lexer) stateFn { + r := lx.next() + switch { + case r == eof: + return lx.errorf("unexpected EOF") + case isNL(r): + return lx.errorf("strings cannot contain newlines") + case r == '\\': + lx.push(lexString) + return lexStringEscape + case r == stringEnd: + lx.backup() + lx.emit(itemString) + lx.next() + lx.ignore() + return lx.pop() + } + return lexString +} + +// lexMultilineString consumes the inner contents of a string. It assumes that +// the beginning '"""' has already been consumed and ignored. +func lexMultilineString(lx *lexer) stateFn { + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case '\\': + return lexMultilineStringEscape + case stringEnd: + if lx.accept(stringEnd) { + if lx.accept(stringEnd) { + lx.backup() + lx.backup() + lx.backup() + lx.emit(itemMultilineString) + lx.next() + lx.next() + lx.next() + lx.ignore() + return lx.pop() + } + lx.backup() + } + } + return lexMultilineString +} + +// lexRawString consumes a raw string. Nothing can be escaped in such a string. +// It assumes that the beginning "'" has already been consumed and ignored. +func lexRawString(lx *lexer) stateFn { + r := lx.next() + switch { + case r == eof: + return lx.errorf("unexpected EOF") + case isNL(r): + return lx.errorf("strings cannot contain newlines") + case r == rawStringEnd: + lx.backup() + lx.emit(itemRawString) + lx.next() + lx.ignore() + return lx.pop() + } + return lexRawString +} + +// lexMultilineRawString consumes a raw string. Nothing can be escaped in such +// a string. It assumes that the beginning "'''" has already been consumed and +// ignored. +func lexMultilineRawString(lx *lexer) stateFn { + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case rawStringEnd: + if lx.accept(rawStringEnd) { + if lx.accept(rawStringEnd) { + lx.backup() + lx.backup() + lx.backup() + lx.emit(itemRawMultilineString) + lx.next() + lx.next() + lx.next() + lx.ignore() + return lx.pop() + } + lx.backup() + } + } + return lexMultilineRawString +} + +// lexMultilineStringEscape consumes an escaped character. It assumes that the +// preceding '\\' has already been consumed. +func lexMultilineStringEscape(lx *lexer) stateFn { + // Handle the special case first: + if isNL(lx.next()) { + return lexMultilineString + } + lx.backup() + lx.push(lexMultilineString) + return lexStringEscape(lx) +} + +func lexStringEscape(lx *lexer) stateFn { + r := lx.next() + switch r { + case 'b': + fallthrough + case 't': + fallthrough + case 'n': + fallthrough + case 'f': + fallthrough + case 'r': + fallthrough + case '"': + fallthrough + case '\\': + return lx.pop() + case 'u': + return lexShortUnicodeEscape + case 'U': + return lexLongUnicodeEscape + } + return lx.errorf("invalid escape character %q; only the following "+ + "escape characters are allowed: "+ + `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r) +} + +func lexShortUnicodeEscape(lx *lexer) stateFn { + var r rune + for i := 0; i < 4; i++ { + r = lx.next() + if !isHexadecimal(r) { + return lx.errorf(`expected four hexadecimal digits after '\u', `+ + "but got %q instead", lx.current()) + } + } + return lx.pop() +} + +func lexLongUnicodeEscape(lx *lexer) stateFn { + var r rune + for i := 0; i < 8; i++ { + r = lx.next() + if !isHexadecimal(r) { + return lx.errorf(`expected eight hexadecimal digits after '\U', `+ + "but got %q instead", lx.current()) + } + } + return lx.pop() +} + +// lexNumberOrDateStart consumes either an integer, a float, or datetime. +func lexNumberOrDateStart(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexNumberOrDate + } + switch r { + case '_': + return lexNumber + case 'e', 'E': + return lexFloat + case '.': + return lx.errorf("floats must start with a digit, not '.'") + } + return lx.errorf("expected a digit but got %q", r) +} + +// lexNumberOrDate consumes either an integer, float or datetime. +func lexNumberOrDate(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexNumberOrDate + } + switch r { + case '-': + return lexDatetime + case '_': + return lexNumber + case '.', 'e', 'E': + return lexFloat + } + + lx.backup() + lx.emit(itemInteger) + return lx.pop() +} + +// lexDatetime consumes a Datetime, to a first approximation. +// The parser validates that it matches one of the accepted formats. +func lexDatetime(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexDatetime + } + switch r { + case '-', 'T', ':', '.', 'Z', '+': + return lexDatetime + } + + lx.backup() + lx.emit(itemDatetime) + return lx.pop() +} + +// lexNumberStart consumes either an integer or a float. It assumes that a sign +// has already been read, but that *no* digits have been consumed. +// lexNumberStart will move to the appropriate integer or float states. +func lexNumberStart(lx *lexer) stateFn { + // We MUST see a digit. Even floats have to start with a digit. + r := lx.next() + if !isDigit(r) { + if r == '.' { + return lx.errorf("floats must start with a digit, not '.'") + } + return lx.errorf("expected a digit but got %q", r) + } + return lexNumber +} + +// lexNumber consumes an integer or a float after seeing the first digit. +func lexNumber(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexNumber + } + switch r { + case '_': + return lexNumber + case '.', 'e', 'E': + return lexFloat + } + + lx.backup() + lx.emit(itemInteger) + return lx.pop() +} + +// lexFloat consumes the elements of a float. It allows any sequence of +// float-like characters, so floats emitted by the lexer are only a first +// approximation and must be validated by the parser. +func lexFloat(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexFloat + } + switch r { + case '_', '.', '-', '+', 'e', 'E': + return lexFloat + } + + lx.backup() + lx.emit(itemFloat) + return lx.pop() +} + +// lexBool consumes a bool string: 'true' or 'false. +func lexBool(lx *lexer) stateFn { + var rs []rune + for { + r := lx.next() + if !unicode.IsLetter(r) { + lx.backup() + break + } + rs = append(rs, r) + } + s := string(rs) + switch s { + case "true", "false": + lx.emit(itemBool) + return lx.pop() + } + return lx.errorf("expected value but found %q instead", s) +} + +// lexCommentStart begins the lexing of a comment. It will emit +// itemCommentStart and consume no characters, passing control to lexComment. +func lexCommentStart(lx *lexer) stateFn { + lx.ignore() + lx.emit(itemCommentStart) + return lexComment +} + +// lexComment lexes an entire comment. It assumes that '#' has been consumed. +// It will consume *up to* the first newline character, and pass control +// back to the last state on the stack. +func lexComment(lx *lexer) stateFn { + r := lx.peek() + if isNL(r) || r == eof { + lx.emit(itemText) + return lx.pop() + } + lx.next() + return lexComment +} + +// lexSkip ignores all slurped input and moves on to the next state. +func lexSkip(lx *lexer, nextState stateFn) stateFn { + return func(lx *lexer) stateFn { + lx.ignore() + return nextState + } +} + +// isWhitespace returns true if `r` is a whitespace character according +// to the spec. +func isWhitespace(r rune) bool { + return r == '\t' || r == ' ' +} + +func isNL(r rune) bool { + return r == '\n' || r == '\r' +} + +func isDigit(r rune) bool { + return r >= '0' && r <= '9' +} + +func isHexadecimal(r rune) bool { + return (r >= '0' && r <= '9') || + (r >= 'a' && r <= 'f') || + (r >= 'A' && r <= 'F') +} + +func isBareKeyChar(r rune) bool { + return (r >= 'A' && r <= 'Z') || + (r >= 'a' && r <= 'z') || + (r >= '0' && r <= '9') || + r == '_' || + r == '-' +} + +func (itype itemType) String() string { + switch itype { + case itemError: + return "Error" + case itemNIL: + return "NIL" + case itemEOF: + return "EOF" + case itemText: + return "Text" + case itemString, itemRawString, itemMultilineString, itemRawMultilineString: + return "String" + case itemBool: + return "Bool" + case itemInteger: + return "Integer" + case itemFloat: + return "Float" + case itemDatetime: + return "DateTime" + case itemTableStart: + return "TableStart" + case itemTableEnd: + return "TableEnd" + case itemKeyStart: + return "KeyStart" + case itemArray: + return "Array" + case itemArrayEnd: + return "ArrayEnd" + case itemCommentStart: + return "CommentStart" + } + panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype))) +} + +func (item item) String() string { + return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val) +} diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go new file mode 100644 index 0000000000..50869ef926 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/parse.go @@ -0,0 +1,592 @@ +package toml + +import ( + "fmt" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" +) + +type parser struct { + mapping map[string]interface{} + types map[string]tomlType + lx *lexer + + // A list of keys in the order that they appear in the TOML data. + ordered []Key + + // the full key for the current hash in scope + context Key + + // the base key name for everything except hashes + currentKey string + + // rough approximation of line number + approxLine int + + // A map of 'key.group.names' to whether they were created implicitly. + implicits map[string]bool +} + +type parseError string + +func (pe parseError) Error() string { + return string(pe) +} + +func parse(data string) (p *parser, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + if err, ok = r.(parseError); ok { + return + } + panic(r) + } + }() + + p = &parser{ + mapping: make(map[string]interface{}), + types: make(map[string]tomlType), + lx: lex(data), + ordered: make([]Key, 0), + implicits: make(map[string]bool), + } + for { + item := p.next() + if item.typ == itemEOF { + break + } + p.topLevel(item) + } + + return p, nil +} + +func (p *parser) panicf(format string, v ...interface{}) { + msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s", + p.approxLine, p.current(), fmt.Sprintf(format, v...)) + panic(parseError(msg)) +} + +func (p *parser) next() item { + it := p.lx.nextItem() + if it.typ == itemError { + p.panicf("%s", it.val) + } + return it +} + +func (p *parser) bug(format string, v ...interface{}) { + panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) +} + +func (p *parser) expect(typ itemType) item { + it := p.next() + p.assertEqual(typ, it.typ) + return it +} + +func (p *parser) assertEqual(expected, got itemType) { + if expected != got { + p.bug("Expected '%s' but got '%s'.", expected, got) + } +} + +func (p *parser) topLevel(item item) { + switch item.typ { + case itemCommentStart: + p.approxLine = item.line + p.expect(itemText) + case itemTableStart: + kg := p.next() + p.approxLine = kg.line + + var key Key + for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() { + key = append(key, p.keyString(kg)) + } + p.assertEqual(itemTableEnd, kg.typ) + + p.establishContext(key, false) + p.setType("", tomlHash) + p.ordered = append(p.ordered, key) + case itemArrayTableStart: + kg := p.next() + p.approxLine = kg.line + + var key Key + for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() { + key = append(key, p.keyString(kg)) + } + p.assertEqual(itemArrayTableEnd, kg.typ) + + p.establishContext(key, true) + p.setType("", tomlArrayHash) + p.ordered = append(p.ordered, key) + case itemKeyStart: + kname := p.next() + p.approxLine = kname.line + p.currentKey = p.keyString(kname) + + val, typ := p.value(p.next()) + p.setValue(p.currentKey, val) + p.setType(p.currentKey, typ) + p.ordered = append(p.ordered, p.context.add(p.currentKey)) + p.currentKey = "" + default: + p.bug("Unexpected type at top level: %s", item.typ) + } +} + +// Gets a string for a key (or part of a key in a table name). +func (p *parser) keyString(it item) string { + switch it.typ { + case itemText: + return it.val + case itemString, itemMultilineString, + itemRawString, itemRawMultilineString: + s, _ := p.value(it) + return s.(string) + default: + p.bug("Unexpected key type: %s", it.typ) + panic("unreachable") + } +} + +// value translates an expected value from the lexer into a Go value wrapped +// as an empty interface. +func (p *parser) value(it item) (interface{}, tomlType) { + switch it.typ { + case itemString: + return p.replaceEscapes(it.val), p.typeOfPrimitive(it) + case itemMultilineString: + trimmed := stripFirstNewline(stripEscapedWhitespace(it.val)) + return p.replaceEscapes(trimmed), p.typeOfPrimitive(it) + case itemRawString: + return it.val, p.typeOfPrimitive(it) + case itemRawMultilineString: + return stripFirstNewline(it.val), p.typeOfPrimitive(it) + case itemBool: + switch it.val { + case "true": + return true, p.typeOfPrimitive(it) + case "false": + return false, p.typeOfPrimitive(it) + } + p.bug("Expected boolean value, but got '%s'.", it.val) + case itemInteger: + if !numUnderscoresOK(it.val) { + p.panicf("Invalid integer %q: underscores must be surrounded by digits", + it.val) + } + val := strings.Replace(it.val, "_", "", -1) + num, err := strconv.ParseInt(val, 10, 64) + if err != nil { + // Distinguish integer values. Normally, it'd be a bug if the lexer + // provides an invalid integer, but it's possible that the number is + // out of range of valid values (which the lexer cannot determine). + // So mark the former as a bug but the latter as a legitimate user + // error. + if e, ok := err.(*strconv.NumError); ok && + e.Err == strconv.ErrRange { + + p.panicf("Integer '%s' is out of the range of 64-bit "+ + "signed integers.", it.val) + } else { + p.bug("Expected integer value, but got '%s'.", it.val) + } + } + return num, p.typeOfPrimitive(it) + case itemFloat: + parts := strings.FieldsFunc(it.val, func(r rune) bool { + switch r { + case '.', 'e', 'E': + return true + } + return false + }) + for _, part := range parts { + if !numUnderscoresOK(part) { + p.panicf("Invalid float %q: underscores must be "+ + "surrounded by digits", it.val) + } + } + if !numPeriodsOK(it.val) { + // As a special case, numbers like '123.' or '1.e2', + // which are valid as far as Go/strconv are concerned, + // must be rejected because TOML says that a fractional + // part consists of '.' followed by 1+ digits. + p.panicf("Invalid float %q: '.' must be followed "+ + "by one or more digits", it.val) + } + val := strings.Replace(it.val, "_", "", -1) + num, err := strconv.ParseFloat(val, 64) + if err != nil { + if e, ok := err.(*strconv.NumError); ok && + e.Err == strconv.ErrRange { + + p.panicf("Float '%s' is out of the range of 64-bit "+ + "IEEE-754 floating-point numbers.", it.val) + } else { + p.panicf("Invalid float value: %q", it.val) + } + } + return num, p.typeOfPrimitive(it) + case itemDatetime: + var t time.Time + var ok bool + var err error + for _, format := range []string{ + "2006-01-02T15:04:05Z07:00", + "2006-01-02T15:04:05", + "2006-01-02", + } { + t, err = time.ParseInLocation(format, it.val, time.Local) + if err == nil { + ok = true + break + } + } + if !ok { + p.panicf("Invalid TOML Datetime: %q.", it.val) + } + return t, p.typeOfPrimitive(it) + case itemArray: + array := make([]interface{}, 0) + types := make([]tomlType, 0) + + for it = p.next(); it.typ != itemArrayEnd; it = p.next() { + if it.typ == itemCommentStart { + p.expect(itemText) + continue + } + + val, typ := p.value(it) + array = append(array, val) + types = append(types, typ) + } + return array, p.typeOfArray(types) + case itemInlineTableStart: + var ( + hash = make(map[string]interface{}) + outerContext = p.context + outerKey = p.currentKey + ) + + p.context = append(p.context, p.currentKey) + p.currentKey = "" + for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() { + if it.typ != itemKeyStart { + p.bug("Expected key start but instead found %q, around line %d", + it.val, p.approxLine) + } + if it.typ == itemCommentStart { + p.expect(itemText) + continue + } + + // retrieve key + k := p.next() + p.approxLine = k.line + kname := p.keyString(k) + + // retrieve value + p.currentKey = kname + val, typ := p.value(p.next()) + // make sure we keep metadata up to date + p.setType(kname, typ) + p.ordered = append(p.ordered, p.context.add(p.currentKey)) + hash[kname] = val + } + p.context = outerContext + p.currentKey = outerKey + return hash, tomlHash + } + p.bug("Unexpected value type: %s", it.typ) + panic("unreachable") +} + +// numUnderscoresOK checks whether each underscore in s is surrounded by +// characters that are not underscores. +func numUnderscoresOK(s string) bool { + accept := false + for _, r := range s { + if r == '_' { + if !accept { + return false + } + accept = false + continue + } + accept = true + } + return accept +} + +// numPeriodsOK checks whether every period in s is followed by a digit. +func numPeriodsOK(s string) bool { + period := false + for _, r := range s { + if period && !isDigit(r) { + return false + } + period = r == '.' + } + return !period +} + +// establishContext sets the current context of the parser, +// where the context is either a hash or an array of hashes. Which one is +// set depends on the value of the `array` parameter. +// +// Establishing the context also makes sure that the key isn't a duplicate, and +// will create implicit hashes automatically. +func (p *parser) establishContext(key Key, array bool) { + var ok bool + + // Always start at the top level and drill down for our context. + hashContext := p.mapping + keyContext := make(Key, 0) + + // We only need implicit hashes for key[0:-1] + for _, k := range key[0 : len(key)-1] { + _, ok = hashContext[k] + keyContext = append(keyContext, k) + + // No key? Make an implicit hash and move on. + if !ok { + p.addImplicit(keyContext) + hashContext[k] = make(map[string]interface{}) + } + + // If the hash context is actually an array of tables, then set + // the hash context to the last element in that array. + // + // Otherwise, it better be a table, since this MUST be a key group (by + // virtue of it not being the last element in a key). + switch t := hashContext[k].(type) { + case []map[string]interface{}: + hashContext = t[len(t)-1] + case map[string]interface{}: + hashContext = t + default: + p.panicf("Key '%s' was already created as a hash.", keyContext) + } + } + + p.context = keyContext + if array { + // If this is the first element for this array, then allocate a new + // list of tables for it. + k := key[len(key)-1] + if _, ok := hashContext[k]; !ok { + hashContext[k] = make([]map[string]interface{}, 0, 5) + } + + // Add a new table. But make sure the key hasn't already been used + // for something else. + if hash, ok := hashContext[k].([]map[string]interface{}); ok { + hashContext[k] = append(hash, make(map[string]interface{})) + } else { + p.panicf("Key '%s' was already created and cannot be used as "+ + "an array.", keyContext) + } + } else { + p.setValue(key[len(key)-1], make(map[string]interface{})) + } + p.context = append(p.context, key[len(key)-1]) +} + +// setValue sets the given key to the given value in the current context. +// It will make sure that the key hasn't already been defined, account for +// implicit key groups. +func (p *parser) setValue(key string, value interface{}) { + var tmpHash interface{} + var ok bool + + hash := p.mapping + keyContext := make(Key, 0) + for _, k := range p.context { + keyContext = append(keyContext, k) + if tmpHash, ok = hash[k]; !ok { + p.bug("Context for key '%s' has not been established.", keyContext) + } + switch t := tmpHash.(type) { + case []map[string]interface{}: + // The context is a table of hashes. Pick the most recent table + // defined as the current hash. + hash = t[len(t)-1] + case map[string]interface{}: + hash = t + default: + p.bug("Expected hash to have type 'map[string]interface{}', but "+ + "it has '%T' instead.", tmpHash) + } + } + keyContext = append(keyContext, key) + + if _, ok := hash[key]; ok { + // Typically, if the given key has already been set, then we have + // to raise an error since duplicate keys are disallowed. However, + // it's possible that a key was previously defined implicitly. In this + // case, it is allowed to be redefined concretely. (See the + // `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.) + // + // But we have to make sure to stop marking it as an implicit. (So that + // another redefinition provokes an error.) + // + // Note that since it has already been defined (as a hash), we don't + // want to overwrite it. So our business is done. + if p.isImplicit(keyContext) { + p.removeImplicit(keyContext) + return + } + + // Otherwise, we have a concrete key trying to override a previous + // key, which is *always* wrong. + p.panicf("Key '%s' has already been defined.", keyContext) + } + hash[key] = value +} + +// setType sets the type of a particular value at a given key. +// It should be called immediately AFTER setValue. +// +// Note that if `key` is empty, then the type given will be applied to the +// current context (which is either a table or an array of tables). +func (p *parser) setType(key string, typ tomlType) { + keyContext := make(Key, 0, len(p.context)+1) + for _, k := range p.context { + keyContext = append(keyContext, k) + } + if len(key) > 0 { // allow type setting for hashes + keyContext = append(keyContext, key) + } + p.types[keyContext.String()] = typ +} + +// addImplicit sets the given Key as having been created implicitly. +func (p *parser) addImplicit(key Key) { + p.implicits[key.String()] = true +} + +// removeImplicit stops tagging the given key as having been implicitly +// created. +func (p *parser) removeImplicit(key Key) { + p.implicits[key.String()] = false +} + +// isImplicit returns true if the key group pointed to by the key was created +// implicitly. +func (p *parser) isImplicit(key Key) bool { + return p.implicits[key.String()] +} + +// current returns the full key name of the current context. +func (p *parser) current() string { + if len(p.currentKey) == 0 { + return p.context.String() + } + if len(p.context) == 0 { + return p.currentKey + } + return fmt.Sprintf("%s.%s", p.context, p.currentKey) +} + +func stripFirstNewline(s string) string { + if len(s) == 0 || s[0] != '\n' { + return s + } + return s[1:] +} + +func stripEscapedWhitespace(s string) string { + esc := strings.Split(s, "\\\n") + if len(esc) > 1 { + for i := 1; i < len(esc); i++ { + esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace) + } + } + return strings.Join(esc, "") +} + +func (p *parser) replaceEscapes(str string) string { + var replaced []rune + s := []byte(str) + r := 0 + for r < len(s) { + if s[r] != '\\' { + c, size := utf8.DecodeRune(s[r:]) + r += size + replaced = append(replaced, c) + continue + } + r += 1 + if r >= len(s) { + p.bug("Escape sequence at end of string.") + return "" + } + switch s[r] { + default: + p.bug("Expected valid escape code after \\, but got %q.", s[r]) + return "" + case 'b': + replaced = append(replaced, rune(0x0008)) + r += 1 + case 't': + replaced = append(replaced, rune(0x0009)) + r += 1 + case 'n': + replaced = append(replaced, rune(0x000A)) + r += 1 + case 'f': + replaced = append(replaced, rune(0x000C)) + r += 1 + case 'r': + replaced = append(replaced, rune(0x000D)) + r += 1 + case '"': + replaced = append(replaced, rune(0x0022)) + r += 1 + case '\\': + replaced = append(replaced, rune(0x005C)) + r += 1 + case 'u': + // At this point, we know we have a Unicode escape of the form + // `uXXXX` at [r, r+5). (Because the lexer guarantees this + // for us.) + escaped := p.asciiEscapeToUnicode(s[r+1 : r+5]) + replaced = append(replaced, escaped) + r += 5 + case 'U': + // At this point, we know we have a Unicode escape of the form + // `uXXXX` at [r, r+9). (Because the lexer guarantees this + // for us.) + escaped := p.asciiEscapeToUnicode(s[r+1 : r+9]) + replaced = append(replaced, escaped) + r += 9 + } + } + return string(replaced) +} + +func (p *parser) asciiEscapeToUnicode(bs []byte) rune { + s := string(bs) + hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32) + if err != nil { + p.bug("Could not parse '%s' as a hexadecimal number, but the "+ + "lexer claims it's OK: %s", s, err) + } + if !utf8.ValidRune(rune(hex)) { + p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s) + } + return rune(hex) +} + +func isStringType(ty itemType) bool { + return ty == itemString || ty == itemMultilineString || + ty == itemRawString || ty == itemRawMultilineString +} diff --git a/vendor/github.com/BurntSushi/toml/session.vim b/vendor/github.com/BurntSushi/toml/session.vim new file mode 100644 index 0000000000..562164be06 --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/session.vim @@ -0,0 +1 @@ +au BufWritePost *.go silent!make tags > /dev/null 2>&1 diff --git a/vendor/github.com/BurntSushi/toml/type_check.go b/vendor/github.com/BurntSushi/toml/type_check.go new file mode 100644 index 0000000000..c73f8afc1a --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/type_check.go @@ -0,0 +1,91 @@ +package toml + +// tomlType represents any Go type that corresponds to a TOML type. +// While the first draft of the TOML spec has a simplistic type system that +// probably doesn't need this level of sophistication, we seem to be militating +// toward adding real composite types. +type tomlType interface { + typeString() string +} + +// typeEqual accepts any two types and returns true if they are equal. +func typeEqual(t1, t2 tomlType) bool { + if t1 == nil || t2 == nil { + return false + } + return t1.typeString() == t2.typeString() +} + +func typeIsHash(t tomlType) bool { + return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) +} + +type tomlBaseType string + +func (btype tomlBaseType) typeString() string { + return string(btype) +} + +func (btype tomlBaseType) String() string { + return btype.typeString() +} + +var ( + tomlInteger tomlBaseType = "Integer" + tomlFloat tomlBaseType = "Float" + tomlDatetime tomlBaseType = "Datetime" + tomlString tomlBaseType = "String" + tomlBool tomlBaseType = "Bool" + tomlArray tomlBaseType = "Array" + tomlHash tomlBaseType = "Hash" + tomlArrayHash tomlBaseType = "ArrayHash" +) + +// typeOfPrimitive returns a tomlType of any primitive value in TOML. +// Primitive values are: Integer, Float, Datetime, String and Bool. +// +// Passing a lexer item other than the following will cause a BUG message +// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. +func (p *parser) typeOfPrimitive(lexItem item) tomlType { + switch lexItem.typ { + case itemInteger: + return tomlInteger + case itemFloat: + return tomlFloat + case itemDatetime: + return tomlDatetime + case itemString: + return tomlString + case itemMultilineString: + return tomlString + case itemRawString: + return tomlString + case itemRawMultilineString: + return tomlString + case itemBool: + return tomlBool + } + p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) + panic("unreachable") +} + +// typeOfArray returns a tomlType for an array given a list of types of its +// values. +// +// In the current spec, if an array is homogeneous, then its type is always +// "Array". If the array is not homogeneous, an error is generated. +func (p *parser) typeOfArray(types []tomlType) tomlType { + // Empty arrays are cool. + if len(types) == 0 { + return tomlArray + } + + theType := types[0] + for _, t := range types[1:] { + if !typeEqual(theType, t) { + p.panicf("Array contains values of type '%s' and '%s', but "+ + "arrays must be homogeneous.", theType, t) + } + } + return tomlArray +} diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go new file mode 100644 index 0000000000..608997c22f --- /dev/null +++ b/vendor/github.com/BurntSushi/toml/type_fields.go @@ -0,0 +1,242 @@ +package toml + +// Struct field handling is adapted from code in encoding/json: +// +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the Go distribution. + +import ( + "reflect" + "sort" + "sync" +) + +// A field represents a single field found in a struct. +type field struct { + name string // the name of the field (`toml` tag included) + tag bool // whether field has a `toml` tag + index []int // represents the depth of an anonymous field + typ reflect.Type // the type of the field +} + +// byName sorts field by name, breaking ties with depth, +// then breaking ties with "name came from toml tag", then +// breaking ties with index sequence. +type byName []field + +func (x byName) Len() int { return len(x) } + +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byName) Less(i, j int) bool { + if x[i].name != x[j].name { + return x[i].name < x[j].name + } + if len(x[i].index) != len(x[j].index) { + return len(x[i].index) < len(x[j].index) + } + if x[i].tag != x[j].tag { + return x[i].tag + } + return byIndex(x).Less(i, j) +} + +// byIndex sorts field by index sequence. +type byIndex []field + +func (x byIndex) Len() int { return len(x) } + +func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byIndex) Less(i, j int) bool { + for k, xik := range x[i].index { + if k >= len(x[j].index) { + return false + } + if xik != x[j].index[k] { + return xik < x[j].index[k] + } + } + return len(x[i].index) < len(x[j].index) +} + +// typeFields returns a list of fields that TOML should recognize for the given +// type. The algorithm is breadth-first search over the set of structs to +// include - the top struct and then any reachable anonymous structs. +func typeFields(t reflect.Type) []field { + // Anonymous fields to explore at the current level and the next. + current := []field{} + next := []field{{typ: t}} + + // Count of queued names for current level and the next. + count := map[reflect.Type]int{} + nextCount := map[reflect.Type]int{} + + // Types already visited at an earlier level. + visited := map[reflect.Type]bool{} + + // Fields found. + var fields []field + + for len(next) > 0 { + current, next = next, current[:0] + count, nextCount = nextCount, map[reflect.Type]int{} + + for _, f := range current { + if visited[f.typ] { + continue + } + visited[f.typ] = true + + // Scan f.typ for fields to include. + for i := 0; i < f.typ.NumField(); i++ { + sf := f.typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { // unexported + continue + } + opts := getOptions(sf.Tag) + if opts.skip { + continue + } + index := make([]int, len(f.index)+1) + copy(index, f.index) + index[len(f.index)] = i + + ft := sf.Type + if ft.Name() == "" && ft.Kind() == reflect.Ptr { + // Follow pointer. + ft = ft.Elem() + } + + // Record found field and index sequence. + if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { + tagged := opts.name != "" + name := opts.name + if name == "" { + name = sf.Name + } + fields = append(fields, field{name, tagged, index, ft}) + if count[f.typ] > 1 { + // If there were multiple instances, add a second, + // so that the annihilation code will see a duplicate. + // It only cares about the distinction between 1 or 2, + // so don't bother generating any more copies. + fields = append(fields, fields[len(fields)-1]) + } + continue + } + + // Record new anonymous struct to explore in next round. + nextCount[ft]++ + if nextCount[ft] == 1 { + f := field{name: ft.Name(), index: index, typ: ft} + next = append(next, f) + } + } + } + } + + sort.Sort(byName(fields)) + + // Delete all fields that are hidden by the Go rules for embedded fields, + // except that fields with TOML tags are promoted. + + // The fields are sorted in primary order of name, secondary order + // of field index length. Loop over names; for each name, delete + // hidden fields by choosing the one dominant field that survives. + out := fields[:0] + for advance, i := 0, 0; i < len(fields); i += advance { + // One iteration per name. + // Find the sequence of fields with the name of this first field. + fi := fields[i] + name := fi.name + for advance = 1; i+advance < len(fields); advance++ { + fj := fields[i+advance] + if fj.name != name { + break + } + } + if advance == 1 { // Only one field with this name + out = append(out, fi) + continue + } + dominant, ok := dominantField(fields[i : i+advance]) + if ok { + out = append(out, dominant) + } + } + + fields = out + sort.Sort(byIndex(fields)) + + return fields +} + +// dominantField looks through the fields, all of which are known to +// have the same name, to find the single field that dominates the +// others using Go's embedding rules, modified by the presence of +// TOML tags. If there are multiple top-level fields, the boolean +// will be false: This condition is an error in Go and we skip all +// the fields. +func dominantField(fields []field) (field, bool) { + // The fields are sorted in increasing index-length order. The winner + // must therefore be one with the shortest index length. Drop all + // longer entries, which is easy: just truncate the slice. + length := len(fields[0].index) + tagged := -1 // Index of first tagged field. + for i, f := range fields { + if len(f.index) > length { + fields = fields[:i] + break + } + if f.tag { + if tagged >= 0 { + // Multiple tagged fields at the same level: conflict. + // Return no field. + return field{}, false + } + tagged = i + } + } + if tagged >= 0 { + return fields[tagged], true + } + // All remaining fields have the same length. If there's more than one, + // we have a conflict (two fields named "X" at the same level) and we + // return no field. + if len(fields) > 1 { + return field{}, false + } + return fields[0], true +} + +var fieldCache struct { + sync.RWMutex + m map[reflect.Type][]field +} + +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. +func cachedTypeFields(t reflect.Type) []field { + fieldCache.RLock() + f := fieldCache.m[t] + fieldCache.RUnlock() + if f != nil { + return f + } + + // Compute fields without lock. + // Might duplicate effort but won't hold other computations back. + f = typeFields(t) + if f == nil { + f = []field{} + } + + fieldCache.Lock() + if fieldCache.m == nil { + fieldCache.m = map[reflect.Type][]field{} + } + fieldCache.m[t] = f + fieldCache.Unlock() + return f +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/LICENSE b/vendor/github.com/gobuffalo/buffalo-plugins/LICENSE new file mode 100644 index 0000000000..aab0dd47a1 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/LICENSE @@ -0,0 +1,21 @@ +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. diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/cache.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/cache.go new file mode 100644 index 0000000000..0210af2eb8 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/cache.go @@ -0,0 +1,96 @@ +package plugins + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "io" + "os" + "os/user" + "path/filepath" + "sync" + + "github.com/gobuffalo/envy" +) + +type cachedPlugin struct { + Commands Commands `json:"commands"` + CheckSum string `json:"check_sum"` +} + +type cachedPlugins map[string]cachedPlugin + +var cachePath = func() string { + home := "." + if usr, err := user.Current(); err == nil { + home = usr.HomeDir + } + return filepath.Join(home, ".buffalo", "plugin.cache") +}() + +var cacheMoot sync.RWMutex + +var cacheOn = envy.Get("BUFFALO_PLUGIN_CACHE", "on") + +var cache = func() cachedPlugins { + m := cachedPlugins{} + if cacheOn != "on" { + return m + } + f, err := os.Open(cachePath) + if err != nil { + return m + } + defer f.Close() + if err := json.NewDecoder(f).Decode(&m); err != nil { + f.Close() + os.Remove(f.Name()) + } + return m +}() + +func findInCache(path string) (cachedPlugin, bool) { + cacheMoot.RLock() + defer cacheMoot.RUnlock() + cp, ok := cache[path] + return cp, ok +} + +func saveCache() error { + if cacheOn != "on" { + return nil + } + cacheMoot.Lock() + defer cacheMoot.Unlock() + os.MkdirAll(filepath.Dir(cachePath), 0744) + f, err := os.Create(cachePath) + if err != nil { + return err + } + return json.NewEncoder(f).Encode(cache) +} + +func sum(path string) string { + f, err := os.Open(path) + if err != nil { + return "" + } + defer f.Close() + hash := sha256.New() + if _, err := io.Copy(hash, f); err != nil { + return "" + } + sum := hash.Sum(nil) + + s := fmt.Sprintf("%x", sum) + return s +} + +func addToCache(path string, cp cachedPlugin) { + if cp.CheckSum == "" { + cp.CheckSum = sum(path) + } + cacheMoot.Lock() + defer cacheMoot.Unlock() + cache[path] = cp +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/command.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/command.go new file mode 100644 index 0000000000..b12f42f61a --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/command.go @@ -0,0 +1,19 @@ +package plugins + +// Command that the plugin supplies +type Command struct { + // Name "foo" + Name string `json:"name"` + // UseCommand "bar" + UseCommand string `json:"use_command"` + // BuffaloCommand "generate" + BuffaloCommand string `json:"buffalo_command"` + // Description "generates a foo" + Description string `json:"description,omitempty"` + Aliases []string `json:"aliases,omitempty"` + Binary string `json:"-"` + Flags []string `json:"flags,omitempty"` +} + +// Commands is a slice of Command +type Commands []Command diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/decorate.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/decorate.go new file mode 100644 index 0000000000..02a00088ae --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/decorate.go @@ -0,0 +1,98 @@ +package plugins + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + + "github.com/gobuffalo/envy" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// ErrPlugMissing ... +var ErrPlugMissing = errors.New("plugin missing") + +func Decorate(c Command) *cobra.Command { + var flags []string + if len(c.Flags) > 0 { + for _, f := range c.Flags { + flags = append(flags, f) + } + } + cc := &cobra.Command{ + Use: c.Name, + Short: fmt.Sprintf("[PLUGIN] %s", c.Description), + Aliases: c.Aliases, + RunE: func(cmd *cobra.Command, args []string) error { + plugCmd := c.Name + if c.UseCommand != "" { + plugCmd = c.UseCommand + } + + ax := []string{plugCmd} + if plugCmd == "-" { + ax = []string{} + } + + ax = append(ax, args...) + ax = append(ax, flags...) + + bin, err := LookPath(c.Binary) + if err != nil { + return errors.WithStack(err) + } + + ex := exec.Command(bin, ax...) + if runtime.GOOS != "windows" { + ex.Env = append(envy.Environ(), "BUFFALO_PLUGIN=1") + } + ex.Stdin = os.Stdin + ex.Stdout = os.Stdout + ex.Stderr = os.Stderr + return log(strings.Join(ex.Args, " "), ex.Run) + }, + } + cc.DisableFlagParsing = true + return cc +} + +// LookPath ... +func LookPath(s string) (string, error) { + if _, err := os.Stat(s); err == nil { + return s, nil + } + + if lp, err := exec.LookPath(s); err == nil { + return lp, err + } + + var bin string + pwd, err := os.Getwd() + if err != nil { + return "", errors.WithStack(err) + } + + var looks []string + if from, err := envy.MustGet("BUFFALO_PLUGIN_PATH"); err == nil { + looks = append(looks, from) + } else { + looks = []string{filepath.Join(pwd, "plugins"), filepath.Join(envy.GoPath(), "bin"), envy.Get("PATH", "")} + } + + for _, p := range looks { + lp := filepath.Join(p, s) + if lp, err = filepath.EvalSymlinks(lp); err == nil { + bin = lp + break + } + } + + if len(bin) == 0 { + return "", errors.Wrapf(ErrPlugMissing, "could not find %s in %q", s, looks) + } + return bin, nil +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/events.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/events.go new file mode 100644 index 0000000000..7368220aaf --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/events.go @@ -0,0 +1,7 @@ +package plugins + +const ( + EvtSetupStarted = "buffalo-plugins:setup:started" + EvtSetupErr = "buffalo-plugins:setup:err" + EvtSetupFinished = "buffalo-plugins:setup:finished" +) diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log.go new file mode 100644 index 0000000000..8a89097632 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log.go @@ -0,0 +1,7 @@ +//+build !debug + +package plugins + +func log(_ string, fn func() error) error { + return fn() +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log_debug.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log_debug.go new file mode 100644 index 0000000000..8c6fcae03a --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/log_debug.go @@ -0,0 +1,14 @@ +//+build debug + +package plugins + +import ( + "fmt" + "time" +) + +func log(name string, fn func() error) error { + start := time.Now() + defer fmt.Println(name, time.Now().Sub(start)) + return fn() +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/command.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/command.go new file mode 100644 index 0000000000..2bf810e77c --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/command.go @@ -0,0 +1,16 @@ +package plugdeps + +import "encoding/json" + +// Command is the plugin command you want to control further +type Command struct { + Name string `toml:"name" json:"name"` + Flags []string `toml:"flags,omitempty" json:"flags,omitempty"` + Commands []Command `toml:"command,omitempty" json:"commands,omitempty"` +} + +// String implementation of fmt.Stringer +func (p Command) String() string { + b, _ := json.Marshal(p) + return string(b) +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugdeps.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugdeps.go new file mode 100644 index 0000000000..bc1cf570cb --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugdeps.go @@ -0,0 +1,88 @@ +package plugdeps + +import ( + "os" + "path/filepath" + "strings" + + "github.com/gobuffalo/meta" + "github.com/karrick/godirwalk" + "github.com/pkg/errors" +) + +// ErrMissingConfig is if config/buffalo-plugins.toml file is not found. Use plugdeps#On(app) to test if plugdeps are being used +var ErrMissingConfig = errors.Errorf("could not find a buffalo-plugins config file at %s", ConfigPath(meta.New("."))) + +// List all of the plugins the application depeneds on. Will return ErrMissingConfig +// if the app is not using config/buffalo-plugins.toml to manage their plugins. +// Use plugdeps#On(app) to test if plugdeps are being used. +func List(app meta.App) (*Plugins, error) { + plugs := New() + if app.WithPop { + plugs.Add(pop) + } + + lp, err := listLocal(app) + if err != nil { + return plugs, errors.WithStack(err) + } + plugs.Add(lp.List()...) + + if !On(app) { + return plugs, ErrMissingConfig + } + + p := ConfigPath(app) + tf, err := os.Open(p) + if err != nil { + return plugs, errors.WithStack(err) + } + if err := plugs.Decode(tf); err != nil { + return plugs, errors.WithStack(err) + } + + return plugs, nil +} + +func listLocal(app meta.App) (*Plugins, error) { + plugs := New() + proot := filepath.Join(app.Root, "plugins") + if _, err := os.Stat(proot); err != nil { + return plugs, nil + } + err := godirwalk.Walk(proot, &godirwalk.Options{ + FollowSymbolicLinks: true, + Callback: func(path string, info *godirwalk.Dirent) error { + if info.IsDir() { + return nil + } + base := filepath.Base(path) + if strings.HasPrefix(base, "buffalo-") { + plugs.Add(Plugin{ + Binary: base, + Local: "." + strings.TrimPrefix(path, app.Root), + }) + } + return nil + }, + }) + if err != nil { + return plugs, errors.WithStack(err) + } + + return plugs, nil +} + +// ConfigPath returns the path to the config/buffalo-plugins.toml file +// relative to the app +func ConfigPath(app meta.App) string { + return filepath.Join(app.Root, "config", "buffalo-plugins.toml") +} + +// On checks for the existence of config/buffalo-plugins.toml if this +// file exists its contents will be used to list plugins. If the file is not +// found, then the BUFFALO_PLUGIN_PATH and ./plugins folders are consulted. +func On(app meta.App) bool { + _, err := os.Stat(ConfigPath(app)) + return err == nil +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugin.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugin.go new file mode 100644 index 0000000000..848345fe37 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugin.go @@ -0,0 +1,26 @@ +package plugdeps + +import ( + "encoding/json" + + "github.com/gobuffalo/meta" +) + +// Plugin represents a Go plugin for Buffalo applications +type Plugin struct { + Binary string `toml:"binary" json:"binary"` + GoGet string `toml:"go_get,omitempty" json:"go_get,omitempty"` + Local string `toml:"local,omitempty" json:"local,omitempty"` + Commands []Command `toml:"command,omitempty" json:"commands,omitempty"` + Tags meta.BuildTags `toml:"tags,omitempty" json:"tags,omitempty"` +} + +// String implementation of fmt.Stringer +func (p Plugin) String() string { + b, _ := json.Marshal(p) + return string(b) +} + +func (p Plugin) key() string { + return p.Binary + p.GoGet + p.Local +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugins.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugins.go new file mode 100644 index 0000000000..5d264534f6 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/plugins.go @@ -0,0 +1,98 @@ +package plugdeps + +import ( + "io" + "sort" + "sync" + + "github.com/BurntSushi/toml" + "github.com/pkg/errors" +) + +// Plugins manages the config/buffalo-plugins.toml file +// as well as the plugins available from the file. +type Plugins struct { + plugins map[string]Plugin + moot *sync.RWMutex +} + +// Encode the list of plugins, in TOML format, to the reader +func (plugs *Plugins) Encode(w io.Writer) error { + tp := tomlPlugins{ + Plugins: plugs.List(), + } + + if err := toml.NewEncoder(w).Encode(tp); err != nil { + return errors.WithStack(err) + } + return nil +} + +// Decode the list of plugins, in TOML format, from the reader +func (plugs *Plugins) Decode(r io.Reader) error { + tp := &tomlPlugins{ + Plugins: []Plugin{}, + } + if _, err := toml.DecodeReader(r, tp); err != nil { + return errors.WithStack(err) + } + for _, p := range tp.Plugins { + plugs.Add(p) + } + return nil +} + +// List of dependent plugins listed in order of Plugin.String() +func (plugs *Plugins) List() []Plugin { + m := map[string]Plugin{} + plugs.moot.RLock() + for _, p := range plugs.plugins { + m[p.key()] = p + } + plugs.moot.RUnlock() + var pp []Plugin + for _, v := range m { + pp = append(pp, v) + } + sort.Slice(pp, func(a, b int) bool { + return pp[a].Binary < pp[b].Binary + }) + return pp +} + +// Add plugin(s) to the list of dependencies +func (plugs *Plugins) Add(pp ...Plugin) { + plugs.moot.Lock() + for _, p := range pp { + plugs.plugins[p.key()] = p + } + plugs.moot.Unlock() +} + +// Remove plugin(s) from the list of dependencies +func (plugs *Plugins) Remove(pp ...Plugin) { + plugs.moot.Lock() + for _, p := range pp { + delete(plugs.plugins, p.key()) + } + plugs.moot.Unlock() +} + +// New returns a configured *Plugins value +func New() *Plugins { + plugs := &Plugins{ + plugins: map[string]Plugin{}, + moot: &sync.RWMutex{}, + } + plugs.Add(self) + return plugs +} + +type tomlPlugins struct { + Plugins []Plugin `toml:"plugin"` +} + +var self = Plugin{ + Binary: "buffalo-plugins", + GoGet: "github.com/gobuffalo/buffalo-plugins", +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/pop.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/pop.go new file mode 100644 index 0000000000..504ac7b857 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps/pop.go @@ -0,0 +1,6 @@ +package plugdeps + +var pop = Plugin{ + Binary: "buffalo-pop", + GoGet: "github.com/gobuffalo/buffalo-pop", +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugins.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugins.go new file mode 100644 index 0000000000..0ea9456864 --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/plugins.go @@ -0,0 +1,232 @@ +package plugins + +import ( + "bytes" + "context" + "encoding/json" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/gobuffalo/buffalo-plugins/plugins/plugdeps" + "github.com/gobuffalo/envy" + "github.com/gobuffalo/meta" + "github.com/karrick/godirwalk" + "github.com/markbates/oncer" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const timeoutEnv = "BUFFALO_PLUGIN_TIMEOUT" + +var t = time.Second * 2 + +func timeout() time.Duration { + oncer.Do("plugins.timeout", func() { + rawTimeout, err := envy.MustGet(timeoutEnv) + if err == nil { + if parsed, err := time.ParseDuration(rawTimeout); err == nil { + t = parsed + } else { + logrus.Errorf("%q value is malformed assuming default %q: %v", timeoutEnv, t, err) + } + } else { + logrus.Debugf("%q not set, assuming default of %v", timeoutEnv, t) + } + }) + return t +} + +// List maps a Buffalo command to a slice of Command +type List map[string]Commands + +var _list List + +// Available plugins for the `buffalo` command. +// It will look in $GOPATH/bin and the `./plugins` directory. +// This can be changed by setting the $BUFFALO_PLUGIN_PATH +// environment variable. +// +// Requirements: +// * file/command must be executable +// * file/command must start with `buffalo-` +// * file/command must respond to `available` and return JSON of +// plugins.Commands{} +// +// Limit full path scan with direct plugin path +// +// If a file/command doesn't respond to being invoked with `available` +// within one second, buffalo will assume that it is unable to load. This +// can be changed by setting the $BUFFALO_PLUGIN_TIMEOUT environment +// variable. It must be set to a duration that `time.ParseDuration` can +// process. +func Available() (List, error) { + var err error + oncer.Do("plugins.Available", func() { + defer func() { + if err := saveCache(); err != nil { + logrus.Error(err) + } + }() + + app := meta.New(".") + + if plugdeps.On(app) { + _list, err = listPlugDeps(app) + return + } + + paths := []string{"plugins"} + + from, err := envy.MustGet("BUFFALO_PLUGIN_PATH") + if err != nil { + from, err = envy.MustGet("GOPATH") + if err != nil { + return + } + from = filepath.Join(from, "bin") + } + + paths = append(paths, strings.Split(from, string(os.PathListSeparator))...) + + list := List{} + for _, p := range paths { + if ignorePath(p) { + continue + } + if _, err := os.Stat(p); err != nil { + continue + } + + err := godirwalk.Walk(p, &godirwalk.Options{ + FollowSymbolicLinks: true, + Callback: func(path string, info *godirwalk.Dirent) error { + if err != nil { + // May indicate a permissions problem with the path, skip it + return nil + } + if info.IsDir() { + return nil + } + base := filepath.Base(path) + if strings.HasPrefix(base, "buffalo-") { + ctx, cancel := context.WithTimeout(context.Background(), timeout()) + commands := askBin(ctx, path) + cancel() + for _, c := range commands { + bc := c.BuffaloCommand + if _, ok := list[bc]; !ok { + list[bc] = Commands{} + } + c.Binary = path + list[bc] = append(list[bc], c) + } + } + return nil + }, + }) + + if err != nil { + return + } + } + _list = list + }) + return _list, err +} + +func askBin(ctx context.Context, path string) Commands { + start := time.Now() + defer func() { + logrus.Debugf("askBin %s=%.4f s", path, time.Since(start).Seconds()) + }() + + commands := Commands{} + defer func() { + addToCache(path, cachedPlugin{ + Commands: commands, + }) + }() + if cp, ok := findInCache(path); ok { + s := sum(path) + if s == cp.CheckSum { + logrus.Debugf("cache hit: %s", path) + commands = cp.Commands + return commands + } + } + logrus.Debugf("cache miss: %s", path) + if strings.HasPrefix(filepath.Base(path), "buffalo-no-sqlite") { + return commands + } + + cmd := exec.CommandContext(ctx, path, "available") + bb := &bytes.Buffer{} + cmd.Stdout = bb + err := cmd.Run() + if err != nil { + return commands + } + msg := bb.String() + for len(msg) > 0 { + err = json.NewDecoder(strings.NewReader(msg)).Decode(&commands) + if err == nil { + return commands + } + msg = msg[1:] + } + logrus.Errorf("[PLUGIN] error decoding plugin %s: %s\n%s\n", path, err, msg) + return commands +} + +func ignorePath(p string) bool { + p = strings.ToLower(p) + for _, x := range []string{`c:\windows`, `c:\program`} { + if strings.HasPrefix(p, x) { + return true + } + } + return false +} + +func listPlugDeps(app meta.App) (List, error) { + list := List{} + plugs, err := plugdeps.List(app) + if err != nil { + return list, err + } + for _, p := range plugs.List() { + ctx, cancel := context.WithTimeout(context.Background(), timeout()) + defer cancel() + bin := p.Binary + if len(p.Local) != 0 { + bin = p.Local + } + bin, err := LookPath(bin) + if err != nil { + if errors.Cause(err) != ErrPlugMissing { + return list, err + } + continue + } + commands := askBin(ctx, bin) + cancel() + for _, c := range commands { + bc := c.BuffaloCommand + if _, ok := list[bc]; !ok { + list[bc] = Commands{} + } + c.Binary = p.Binary + for _, pc := range p.Commands { + if c.Name == pc.Name { + c.Flags = pc.Flags + break + } + } + list[bc] = append(list[bc], c) + } + } + return list, nil +} diff --git a/vendor/github.com/gobuffalo/buffalo-plugins/plugins/version.go b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/version.go new file mode 100644 index 0000000000..a704410c0c --- /dev/null +++ b/vendor/github.com/gobuffalo/buffalo-plugins/plugins/version.go @@ -0,0 +1,3 @@ +package plugins + +const Version = "v1.11.0" diff --git a/vendor/github.com/gobuffalo/events/.gitignore b/vendor/github.com/gobuffalo/events/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/events/.gometalinter.json b/vendor/github.com/gobuffalo/events/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/events/.travis.yml b/vendor/github.com/gobuffalo/events/.travis.yml new file mode 100644 index 0000000000..1fb041a259 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/.travis.yml @@ -0,0 +1,36 @@ +language: go + +sudo: false + +matrix: + include: + - os: linux + go: "1.9.x" + - os: windows + go: "1.9.x" + - os: linux + go: "1.10.x" + - os: windows + go: "1.10.x" + - os: linux + go: "1.11.x" + env: + - GO111MODULE=off + - os: windows + go: "1.11.x" + env: + - GO111MODULE=off + - os: linux + go: "1.11.x" + env: + - GO111MODULE=on + - os: windows + go: "1.11.x" + env: + - GO111MODULE=on + +install: false + +script: + - go get -v -t ./... + - go test -v -timeout=5s -race ./... diff --git a/vendor/github.com/gobuffalo/events/LICENSE b/vendor/github.com/gobuffalo/events/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/events/Makefile b/vendor/github.com/gobuffalo/events/Makefile new file mode 100644 index 0000000000..dd51e08ebb --- /dev/null +++ b/vendor/github.com/gobuffalo/events/Makefile @@ -0,0 +1,55 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -v . + make tidy + +tidy: +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +else + echo skipping go mod tidy +endif + + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... + make tidy + +build: + packr + $(GO_BIN) build -v . + make tidy + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + make tidy + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + make tidy + +update: + $(GO_BIN) get -u -tags ${TAGS} + make tidy + packr + make test + make install + make tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +release: + release -y -f version.go + make tidy diff --git a/vendor/github.com/gobuffalo/events/README.md b/vendor/github.com/gobuffalo/events/README.md new file mode 100644 index 0000000000..38cc50878c --- /dev/null +++ b/vendor/github.com/gobuffalo/events/README.md @@ -0,0 +1,99 @@ +

+ +

+GoDoc +Go Report Card +

+ +# github.com/gobuffalo/events + +**Note:** This package was first introduced to Buffalo in this [PR](https://github.com/gobuffalo/buffalo/pull/1305). Assuming the PR is merged Buffalo will not start emitting events until `v0.13.0-beta.2` or greater. + +A list of known emitted events can be found at [https://godoc.org/github.com/gobuffalo/events#pkg-constants](https://godoc.org/github.com/gobuffalo/events#pkg-constants) + +## Installation + +```bash +$ go get -u -v github.com/gobuffalo/events +``` + +## Listening For Events + +To listen for events you need to register an [`events#Listener`](https://godoc.org/github.com/gobuffalo/events#Listener) function first. + +```go +func init() { + // if you want to give your listener a nice name to identify itself + events.NamedListen("my-listener", func(e events.Event) { + fmt.Println("### e ->", e) + }) + + // if you don't care about identifying your listener + events.Listen(func(e events.Event) { + fmt.Println("### e ->", e) + }) +} +``` + +## Emitting Events + +```go +events.Emit(events.Event{ + Kind: "my-event", + Message: // optional message, + Payload: // optional payload, + Error: // optional error, +}) +``` + +There is only one required field when emitting an event, `Kind`. + +The `Kind` field is key to how people will interpret your messages, and should be constructed as such: `::`. + +In the examples below from [Buffalo](https://gobuffalo.io) you can see it is using the `buffalo:` name space for its events. + +```go +// EvtAppStart is emitted when buffalo.App#Serve is called +EvtAppStart = "buffalo:app:start" +// EvtAppStartErr is emitted when an error occurs calling buffalo.App#Serve +EvtAppStartErr = "buffalo:app:start:err" +// EvtAppStop is emitted when buffalo.App#Stop is called +EvtAppStop = "buffalo:app:stop" +// EvtAppStopErr is emitted when an error occurs calling buffalo.App#Stop +EvtAppStopErr = "buffalo:app:stop:err" +``` + +## Implementing a Manager + +By default `events` implements a basic manager for you. Should you want to replace that with your own implementation, perhaps that's backed by a proper message queue, you can implement the [`events#Manager`](https://godoc.org/github.com/gobuffalo/events#Manager) interface. + +```go +var _ events.Manager = MyManager{} +events.SetManager(MyManager{}) +``` + +## Listening via Buffalo Plugins + +Once Buffalo is actively emitting events, plugins, will be able to listen those events via their CLIs. + +To do so you can set the `BuffaloCommand` to `events` when telling Buffalo which plugin in commands are available. Buffalo will create a new listener that says the JSON version of the event to that command in question. + +```go +var availableCmd = &cobra.Command{ + Use: "available", + Short: "a list of available buffalo plugins", + RunE: func(cmd *cobra.Command, args []string) error { + plugs := plugins.Commands{ + {Name: "echo", UseCommand: "echo", BuffaloCommand: "events", Description: echoCmd.Short, Aliases: echoCmd.Aliases}, + } + return json.NewEncoder(os.Stdout).Encode(plugs) + }, +} + + +events.Emit(events.Event{ + Kind: "my-event", +}) + +// buffalo-foo echo "{\"kind\": \"my-event\"}" +``` diff --git a/vendor/github.com/gobuffalo/events/event.go b/vendor/github.com/gobuffalo/events/event.go new file mode 100644 index 0000000000..3f7b89d811 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/event.go @@ -0,0 +1,56 @@ +package events + +import ( + "encoding/json" + "errors" + "strings" +) + +// Event represents different events +// in the lifecycle of a Buffalo app +type Event struct { + // Kind is the "type" of event "app:start" + Kind string `json:"kind"` + // Message is optional + Message string `json:"message"` + // Payload is optional + Payload Payload `json:"payload"` + // Error is optional + Error error `json:"-"` +} + +func (e Event) String() string { + b, _ := e.MarshalJSON() + + return string(b) +} + +// MarshalJSON implements the json marshaler for an event +func (e Event) MarshalJSON() ([]byte, error) { + m := map[string]interface{}{ + "kind": e.Kind, + } + if len(e.Message) != 0 { + m["message"] = e.Message + } + if e.Error != nil { + m["error"] = e.Error.Error() + } + if len(e.Payload) != 0 { + m["payload"] = e.Payload + } + + return json.Marshal(m) +} + +// Validate that an event is ready to be emitted +func (e Event) Validate() error { + if len(e.Kind) == 0 { + return errors.New("kind can not be blank") + } + return nil +} + +func (e Event) IsError() bool { + return strings.HasSuffix(e.Kind, ":err") +} diff --git a/vendor/github.com/gobuffalo/events/events.go b/vendor/github.com/gobuffalo/events/events.go new file mode 100644 index 0000000000..40d86cc0b2 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/events.go @@ -0,0 +1,44 @@ +package events + +import ( + "strings" + + "github.com/gobuffalo/mapi" +) + +type Payload = mapi.Mapi + +const ( + // ErrGeneral is emitted for general errors + ErrGeneral = "general:err" + // ErrPanic is emitted when a panic is recovered + ErrPanic = "panic:err" +) + +// Emit an event to all listeners +func Emit(e Event) error { + return boss.Emit(e) +} + +func EmitPayload(kind string, payload interface{}) error { + return EmitError(kind, nil, payload) +} + +func EmitError(kind string, err error, payload interface{}) error { + if err != nil && !strings.HasSuffix(kind, ":err") { + kind += ":err" + } + var pl Payload + pl, ok := payload.(Payload) + if !ok { + pl = Payload{ + "data": payload, + } + } + e := Event{ + Kind: kind, + Payload: pl, + Error: err, + } + return Emit(e) +} diff --git a/vendor/github.com/gobuffalo/events/filter.go b/vendor/github.com/gobuffalo/events/filter.go new file mode 100644 index 0000000000..5c9bc28ed5 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/filter.go @@ -0,0 +1,21 @@ +package events + +import ( + "regexp" + + "github.com/markbates/safe" +) + +// Filter compiles the string as a regex and returns +// the original listener wrapped in a new listener +// that filters incoming events by the Kind +func Filter(s string, fn Listener) Listener { + rx := regexp.MustCompile(s) + return func(e Event) { + if rx.MatchString(e.Kind) { + safe.Run(func() { + fn(e) + }) + } + } +} diff --git a/vendor/github.com/gobuffalo/events/listener.go b/vendor/github.com/gobuffalo/events/listener.go new file mode 100644 index 0000000000..1f293e2282 --- /dev/null +++ b/vendor/github.com/gobuffalo/events/listener.go @@ -0,0 +1,36 @@ +package events + +import ( + "fmt" + "runtime" + + "github.com/pkg/errors" +) + +// Listener is a function capable of handling events +type Listener func(e Event) + +// NamedListen for events. Name is the name of the +// listener NOT the events you want to listen for, +// so something like "my-listener", "kafka-listener", etc... +func NamedListen(name string, l Listener) (DeleteFn, error) { + return boss.Listen(name, l) +} + +// Listen for events. +func Listen(l Listener) (DeleteFn, error) { + _, file, line, _ := runtime.Caller(1) + return NamedListen(fmt.Sprintf("%s:%d", file, line), l) +} + +type listable interface { + List() ([]string, error) +} + +// List all listeners +func List() ([]string, error) { + if l, ok := boss.(listable); ok { + return l.List() + } + return []string{}, errors.Errorf("manager %T does not implemented listable", boss) +} diff --git a/vendor/github.com/gobuffalo/events/listener_map.go b/vendor/github.com/gobuffalo/events/listener_map.go new file mode 100644 index 0000000000..a6e727646f --- /dev/null +++ b/vendor/github.com/gobuffalo/events/listener_map.go @@ -0,0 +1,73 @@ +//go:generate mapgen -name "listener" -zero "nil" -go-type "Listener" -pkg "" -a "func(e) {}" -b "nil" -c "nil" -bb "nil" -destination "events" +// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT. + +package events + +import ( + "sort" + "sync" +) + +// listenerMap wraps sync.Map and uses the following types: +// key: string +// value: Listener +type listenerMap struct { + data sync.Map +} + +// Delete the key from the map +func (m *listenerMap) Delete(key string) { + m.data.Delete(key) +} + +// Load the key from the map. +// Returns Listener or bool. +// A false return indicates either the key was not found +// or the value is not of type Listener +func (m *listenerMap) Load(key string) (Listener, bool) { + i, ok := m.data.Load(key) + if !ok { + return nil, false + } + s, ok := i.(Listener) + return s, ok +} + +// LoadOrStore will return an existing key or +// store the value if not already in the map +func (m *listenerMap) LoadOrStore(key string, value Listener) (Listener, bool) { + i, _ := m.data.LoadOrStore(key, value) + s, ok := i.(Listener) + return s, ok +} + +// Range over the Listener values in the map +func (m *listenerMap) Range(f func(key string, value Listener) bool) { + m.data.Range(func(k, v interface{}) bool { + key, ok := k.(string) + if !ok { + return false + } + value, ok := v.(Listener) + if !ok { + return false + } + return f(key, value) + }) +} + +// Store a Listener in the map +func (m *listenerMap) Store(key string, value Listener) { + m.data.Store(key, value) +} + +// Keys returns a list of keys in the map +func (m *listenerMap) Keys() []string { + var keys []string + m.Range(func(key string, value Listener) bool { + keys = append(keys, key) + return true + }) + sort.Strings(keys) + return keys +} diff --git a/vendor/github.com/gobuffalo/events/manager.go b/vendor/github.com/gobuffalo/events/manager.go new file mode 100644 index 0000000000..5dd879cfdb --- /dev/null +++ b/vendor/github.com/gobuffalo/events/manager.go @@ -0,0 +1,86 @@ +package events + +import ( + "strings" + + "github.com/markbates/safe" + "github.com/pkg/errors" +) + +type DeleteFn func() + +// Manager can be implemented to replace the default +// events manager +type Manager interface { + Listen(string, Listener) (DeleteFn, error) + Emit(Event) error +} + +// DefaultManager implements a map backed Manager +func DefaultManager() Manager { + return &manager{ + listeners: listenerMap{}, + } +} + +// SetManager allows you to replace the default +// event manager with a custom one +func SetManager(m Manager) { + boss = m +} + +var boss Manager = DefaultManager() +var _ listable = &manager{} + +type manager struct { + listeners listenerMap +} + +func (m *manager) Listen(name string, l Listener) (DeleteFn, error) { + _, ok := m.listeners.Load(name) + if ok { + return nil, errors.Errorf("listener named %s is already listening", name) + } + + m.listeners.Store(name, l) + + df := func() { + m.listeners.Delete(name) + } + + return df, nil +} + +func (m *manager) Emit(e Event) error { + if err := e.Validate(); err != nil { + return errors.WithStack(err) + } + e.Kind = strings.ToLower(e.Kind) + if e.IsError() && e.Error == nil { + e.Error = errors.New(e.Kind) + } + go func(e Event) { + m.listeners.Range(func(key string, l Listener) bool { + ex := Event{ + Kind: e.Kind, + Error: e.Error, + Message: e.Message, + Payload: Payload{}, + } + for k, v := range e.Payload { + ex.Payload[k] = v + } + go func(e Event, l Listener) { + safe.Run(func() { + l(e) + }) + }(ex, l) + return true + }) + }(e) + return nil +} + +func (m *manager) List() ([]string, error) { + return m.listeners.Keys(), nil +} diff --git a/vendor/github.com/gobuffalo/events/plugins.go b/vendor/github.com/gobuffalo/events/plugins.go new file mode 100644 index 0000000000..f13d28721d --- /dev/null +++ b/vendor/github.com/gobuffalo/events/plugins.go @@ -0,0 +1,67 @@ +package events + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "strings" + + "github.com/gobuffalo/buffalo-plugins/plugins" + "github.com/gobuffalo/envy" + "github.com/markbates/oncer" + "github.com/markbates/safe" + "github.com/pkg/errors" +) + +// LoadPlugins will add listeners for any plugins that support "events" +func LoadPlugins() error { + var err error + oncer.Do("events.LoadPlugins", func() { + // don't send plugins events during testing + if envy.Get("GO_ENV", "development") == "test" { + return + } + plugs, err := plugins.Available() + if err != nil { + err = errors.WithStack(err) + return + } + for _, cmds := range plugs { + for _, c := range cmds { + if c.BuffaloCommand != "events" { + continue + } + err := func(c plugins.Command) error { + return safe.RunE(func() error { + n := fmt.Sprintf("[PLUGIN] %s %s", c.Binary, c.Name) + _, err := NamedListen(n, func(e Event) { + b, err := json.Marshal(e) + if err != nil { + fmt.Println("error trying to marshal event", e, err) + return + } + cmd := exec.Command(c.Binary, c.UseCommand, string(b)) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + if err := cmd.Run(); err != nil { + fmt.Println("error trying to send event", strings.Join(cmd.Args, " "), err) + } + }) + if err != nil { + return errors.WithStack(err) + } + return nil + }) + }(c) + if err != nil { + err = errors.WithStack(err) + return + } + } + + } + }) + return err +} diff --git a/vendor/github.com/gobuffalo/events/shoulders.md b/vendor/github.com/gobuffalo/events/shoulders.md new file mode 100644 index 0000000000..fe2aefb41f --- /dev/null +++ b/vendor/github.com/gobuffalo/events/shoulders.md @@ -0,0 +1,50 @@ +# github.com/gobuffalo/events Stands on the Shoulders of Giants + +github.com/gobuffalo/events 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**: + + +* [github.com/BurntSushi/toml](https://godoc.org/github.com/BurntSushi/toml) + +* [github.com/gobuffalo/buffalo-plugins/plugins](https://godoc.org/github.com/gobuffalo/buffalo-plugins/plugins) + +* [github.com/gobuffalo/buffalo-plugins/plugins/plugdeps](https://godoc.org/github.com/gobuffalo/buffalo-plugins/plugins/plugdeps) + +* [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy) + +* [github.com/gobuffalo/events](https://godoc.org/github.com/gobuffalo/events) + +* [github.com/gobuffalo/flect](https://godoc.org/github.com/gobuffalo/flect) + +* [github.com/gobuffalo/flect/name](https://godoc.org/github.com/gobuffalo/flect/name) + +* [github.com/gobuffalo/mapi](https://godoc.org/github.com/gobuffalo/mapi) + +* [github.com/gobuffalo/meta](https://godoc.org/github.com/gobuffalo/meta) + +* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv) + +* [github.com/karrick/godirwalk](https://godoc.org/github.com/karrick/godirwalk) + +* [github.com/markbates/oncer](https://godoc.org/github.com/markbates/oncer) + +* [github.com/markbates/safe](https://godoc.org/github.com/markbates/safe) + +* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors) + +* [github.com/rogpeppe/go-internal/modfile](https://godoc.org/github.com/rogpeppe/go-internal/modfile) + +* [github.com/rogpeppe/go-internal/module](https://godoc.org/github.com/rogpeppe/go-internal/module) + +* [github.com/rogpeppe/go-internal/semver](https://godoc.org/github.com/rogpeppe/go-internal/semver) + +* [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus) + +* [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra) + +* [github.com/spf13/pflag](https://godoc.org/github.com/spf13/pflag) + +* [golang.org/x/crypto/ssh/terminal](https://godoc.org/golang.org/x/crypto/ssh/terminal) + +* [golang.org/x/sys/unix](https://godoc.org/golang.org/x/sys/unix) diff --git a/vendor/github.com/gobuffalo/events/version.go b/vendor/github.com/gobuffalo/events/version.go new file mode 100644 index 0000000000..4d85ea9ddf --- /dev/null +++ b/vendor/github.com/gobuffalo/events/version.go @@ -0,0 +1,3 @@ +package events + +const Version = "v1.1.9" diff --git a/vendor/github.com/gobuffalo/flect/.gitignore b/vendor/github.com/gobuffalo/flect/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/flect/.gometalinter.json b/vendor/github.com/gobuffalo/flect/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/flect/.travis.yml b/vendor/github.com/gobuffalo/flect/.travis.yml new file mode 100644 index 0000000000..1fb041a259 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/.travis.yml @@ -0,0 +1,36 @@ +language: go + +sudo: false + +matrix: + include: + - os: linux + go: "1.9.x" + - os: windows + go: "1.9.x" + - os: linux + go: "1.10.x" + - os: windows + go: "1.10.x" + - os: linux + go: "1.11.x" + env: + - GO111MODULE=off + - os: windows + go: "1.11.x" + env: + - GO111MODULE=off + - os: linux + go: "1.11.x" + env: + - GO111MODULE=on + - os: windows + go: "1.11.x" + env: + - GO111MODULE=on + +install: false + +script: + - go get -v -t ./... + - go test -v -timeout=5s -race ./... diff --git a/vendor/github.com/gobuffalo/flect/LICENSE.txt b/vendor/github.com/gobuffalo/flect/LICENSE.txt new file mode 100644 index 0000000000..123ddc0d80 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/LICENSE.txt @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/flect/Makefile b/vendor/github.com/gobuffalo/flect/Makefile new file mode 100644 index 0000000000..b0db1c4f88 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/Makefile @@ -0,0 +1,46 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -v . + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + +build: + packr + $(GO_BIN) build -v . + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + +update: + $(GO_BIN) get -u -tags ${TAGS} +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + packr + make test + make install +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +release: + release -y -f version.go diff --git a/vendor/github.com/gobuffalo/flect/README.md b/vendor/github.com/gobuffalo/flect/README.md new file mode 100644 index 0000000000..af0afbda98 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/README.md @@ -0,0 +1,36 @@ +# Flect + +

+GoDoc +Build Status +Go Report Card +

+ +This is a new inflection engine to replace [https://github.com/markbates/inflect](https://github.com/markbates/inflect) designed to be more modular, more readable, and easier to fix issues on than the original. + +## Installation + +```bash +$ go get -u -v github.com/gobuffalo/flect +``` + +## `github.com/gobuffalo/flect` +GoDoc + +The `github.com/gobuffalo/flect` package contains "basic" inflection tools, like pluralization, singularization, etc... + +### The `Ident` Type + +In addition to helpful methods that take in a `string` and return a `string`, there is an `Ident` type that can be used to create new, custom, inflection rules. + +The `Ident` type contains two fields. + +* `Original` - This is the original `string` that was used to create the `Ident` +* `Parts` - This is a `[]string` that represents all of the "parts" of the string, that have been split apart, making the segments easier to work with + +Examples of creating new inflection rules using `Ident` can be found in the `github.com/gobuffalo/flect/name` package. + +## `github.com/gobuffalo/flect/name` +GoDoc + +The `github.com/gobuffalo/flect/name` package contains more "business" inflection rules like creating proper names, table names, etc... diff --git a/vendor/github.com/gobuffalo/flect/acronyms.go b/vendor/github.com/gobuffalo/flect/acronyms.go new file mode 100644 index 0000000000..b169724a4c --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/acronyms.go @@ -0,0 +1,152 @@ +package flect + +import "sync" + +var acronymsMoot = &sync.RWMutex{} + +var baseAcronyms = map[string]bool{ + "OK": true, + "UTF8": true, + "HTML": true, + "JSON": true, + "JWT": true, + "ID": true, + "UUID": true, + "SQL": true, + "ACK": true, + "ACL": true, + "ADSL": true, + "AES": true, + "ANSI": true, + "API": true, + "ARP": true, + "ATM": true, + "BGP": true, + "BSS": true, + "CCITT": true, + "CHAP": true, + "CIDR": true, + "CIR": true, + "CLI": true, + "CPE": true, + "CPU": true, + "CRC": true, + "CRT": true, + "CSMA": true, + "CMOS": true, + "DCE": true, + "DEC": true, + "DES": true, + "DHCP": true, + "DNS": true, + "DRAM": true, + "DSL": true, + "DSLAM": true, + "DTE": true, + "DMI": true, + "EHA": true, + "EIA": true, + "EIGRP": true, + "EOF": true, + "ESS": true, + "FCC": true, + "FCS": true, + "FDDI": true, + "FTP": true, + "GBIC": true, + "gbps": true, + "GEPOF": true, + "HDLC": true, + "HTTP": true, + "HTTPS": true, + "IANA": true, + "ICMP": true, + "IDF": true, + "IDS": true, + "IEEE": true, + "IETF": true, + "IMAP": true, + "IP": true, + "IPS": true, + "ISDN": true, + "ISP": true, + "kbps": true, + "LACP": true, + "LAN": true, + "LAPB": true, + "LAPF": true, + "LLC": true, + "MAC": true, + "Mbps": true, + "MC": true, + "MDF": true, + "MIB": true, + "MoCA": true, + "MPLS": true, + "MTU": true, + "NAC": true, + "NAT": true, + "NBMA": true, + "NIC": true, + "NRZ": true, + "NRZI": true, + "NVRAM": true, + "OSI": true, + "OSPF": true, + "OUI": true, + "PAP": true, + "PAT": true, + "PC": true, + "PIM": true, + "PCM": true, + "PDU": true, + "POP3": true, + "POTS": true, + "PPP": true, + "PPTP": true, + "PTT": true, + "PVST": true, + "RAM": true, + "RARP": true, + "RFC": true, + "RIP": true, + "RLL": true, + "ROM": true, + "RSTP": true, + "RTP": true, + "RCP": true, + "SDLC": true, + "SFD": true, + "SFP": true, + "SLARP": true, + "SLIP": true, + "SMTP": true, + "SNA": true, + "SNAP": true, + "SNMP": true, + "SOF": true, + "SRAM": true, + "SSH": true, + "SSID": true, + "STP": true, + "SYN": true, + "TDM": true, + "TFTP": true, + "TIA": true, + "TOFU": true, + "UDP": true, + "URL": true, + "URI": true, + "USB": true, + "UTP": true, + "VC": true, + "VLAN": true, + "VLSM": true, + "VPN": true, + "W3C": true, + "WAN": true, + "WEP": true, + "WiFi": true, + "WPA": true, + "WWW": true, +} diff --git a/vendor/github.com/gobuffalo/flect/camelize.go b/vendor/github.com/gobuffalo/flect/camelize.go new file mode 100644 index 0000000000..8a9928e8be --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/camelize.go @@ -0,0 +1,48 @@ +package flect + +import ( + "strings" + "unicode" +) + +// Camelize returns a camelize version of a string +// bob dylan = bobDylan +// widget_id = widgetID +// WidgetID = widgetID +func Camelize(s string) string { + return New(s).Camelize().String() +} + +// Camelize returns a camelize version of a string +// bob dylan = bobDylan +// widget_id = widgetID +// WidgetID = widgetID +func (i Ident) Camelize() Ident { + var out []string + for i, part := range i.Parts { + var x string + var capped bool + if strings.ToLower(part) == "id" { + out = append(out, "ID") + continue + } + for _, c := range part { + if unicode.IsLetter(c) || unicode.IsDigit(c) { + if i == 0 { + x += string(unicode.ToLower(c)) + continue + } + if !capped { + capped = true + x += string(unicode.ToUpper(c)) + continue + } + x += string(c) + } + } + if x != "" { + out = append(out, x) + } + } + return New(strings.Join(out, "")) +} diff --git a/vendor/github.com/gobuffalo/flect/capitalize.go b/vendor/github.com/gobuffalo/flect/capitalize.go new file mode 100644 index 0000000000..42ecc166cb --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/capitalize.go @@ -0,0 +1,27 @@ +package flect + +import "unicode" + +// Capitalize will cap the first letter of string +// user = User +// bob dylan = Bob dylan +// widget_id = Widget_id +func Capitalize(s string) string { + return New(s).Capitalize().String() +} + +// Capitalize will cap the first letter of string +// user = User +// bob dylan = Bob dylan +// widget_id = Widget_id +func (i Ident) Capitalize() Ident { + var x string + if len(i.Parts) == 0 { + return New("") + } + x = string(unicode.ToTitle(rune(i.Original[0]))) + if len(i.Original) > 1 { + x += i.Original[1:] + } + return New(x) +} diff --git a/vendor/github.com/gobuffalo/flect/custom_data.go b/vendor/github.com/gobuffalo/flect/custom_data.go new file mode 100644 index 0000000000..12d3f9b470 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/custom_data.go @@ -0,0 +1,82 @@ +package flect + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + + "github.com/gobuffalo/envy" +) + +func init() { + loadCustomData("inflections.json", "INFLECT_PATH", "could not read inflection file", LoadInflections) + loadCustomData("acronyms.json", "ACRONYMS_PATH", "could not read acronyms file", LoadAcronyms) +} + +//CustomDataParser are functions that parse data like acronyms or +//plurals in the shape of a io.Reader it receives. +type CustomDataParser func(io.Reader) error + +func loadCustomData(defaultFile, env, readErrorMessage string, parser CustomDataParser) { + pwd, _ := os.Getwd() + path := envy.Get(env, filepath.Join(pwd, defaultFile)) + + if _, err := os.Stat(path); err != nil { + return + } + + b, err := ioutil.ReadFile(path) + if err != nil { + fmt.Printf("%s %s (%s)\n", readErrorMessage, path, err) + return + } + + if err = parser(bytes.NewReader(b)); err != nil { + fmt.Println(err) + } +} + +//LoadAcronyms loads rules from io.Reader param +func LoadAcronyms(r io.Reader) error { + m := []string{} + err := json.NewDecoder(r).Decode(&m) + + if err != nil { + return fmt.Errorf("could not decode acronyms JSON from reader: %s", err) + } + + acronymsMoot.Lock() + defer acronymsMoot.Unlock() + + for _, acronym := range m { + baseAcronyms[acronym] = true + } + + return nil +} + +//LoadInflections loads rules from io.Reader param +func LoadInflections(r io.Reader) error { + m := map[string]string{} + + err := json.NewDecoder(r).Decode(&m) + if err != nil { + return fmt.Errorf("could not decode inflection JSON from reader: %s", err) + } + + pluralMoot.Lock() + defer pluralMoot.Unlock() + singularMoot.Lock() + defer singularMoot.Unlock() + + for s, p := range m { + singleToPlural[s] = p + pluralToSingle[p] = s + } + + return nil +} diff --git a/vendor/github.com/gobuffalo/flect/dasherize.go b/vendor/github.com/gobuffalo/flect/dasherize.go new file mode 100644 index 0000000000..c7a8a33e36 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/dasherize.go @@ -0,0 +1,34 @@ +package flect + +import ( + "strings" + "unicode" +) + +// Dasherize returns an alphanumeric, lowercased, dashed string +// Donald E. Knuth = donald-e-knuth +// Test with + sign = test-with-sign +// admin/WidgetID = admin-widget-id +func Dasherize(s string) string { + return New(s).Dasherize().String() +} + +// Dasherize returns an alphanumeric, lowercased, dashed string +// Donald E. Knuth = donald-e-knuth +// Test with + sign = test-with-sign +// admin/WidgetID = admin-widget-id +func (i Ident) Dasherize() Ident { + var parts []string + + for _, part := range i.Parts { + var x string + for _, c := range part { + if unicode.IsLetter(c) || unicode.IsDigit(c) { + x += string(c) + } + } + parts = xappend(parts, x) + } + + return New(strings.ToLower(strings.Join(parts, "-"))) +} diff --git a/vendor/github.com/gobuffalo/flect/flect.go b/vendor/github.com/gobuffalo/flect/flect.go new file mode 100644 index 0000000000..ee81b6f2bc --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/flect.go @@ -0,0 +1,43 @@ +/* +Package flect is a new inflection engine to replace [https://github.com/markbates/inflect](https://github.com/markbates/inflect) designed to be more modular, more readable, and easier to fix issues on than the original. +*/ +package flect + +import ( + "strings" + "unicode" +) + +var spaces = []rune{'_', ' ', ':', '-', '/'} + +func isSpace(c rune) bool { + for _, r := range spaces { + if r == c { + return true + } + } + return unicode.IsSpace(c) +} + +func xappend(a []string, ss ...string) []string { + for _, s := range ss { + s = strings.TrimSpace(s) + for _, x := range spaces { + s = strings.Trim(s, string(x)) + } + if _, ok := baseAcronyms[strings.ToUpper(s)]; ok { + s = strings.ToUpper(s) + } + if s != "" { + a = append(a, s) + } + } + return a +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} diff --git a/vendor/github.com/gobuffalo/flect/ident.go b/vendor/github.com/gobuffalo/flect/ident.go new file mode 100644 index 0000000000..8c58455739 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/ident.go @@ -0,0 +1,109 @@ +package flect + +import ( + "encoding" + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +// Ident represents the string and it's parts +type Ident struct { + Original string + Parts []string +} + +// String implements fmt.Stringer and returns the original string +func (i Ident) String() string { + return i.Original +} + +// New creates a new Ident from the string +func New(s string) Ident { + i := Ident{ + Original: s, + Parts: toParts(s), + } + + return i +} + +var splitRx = regexp.MustCompile("[^\\p{L}]") + +func toParts(s string) []string { + parts := []string{} + s = strings.TrimSpace(s) + if len(s) == 0 { + return parts + } + if _, ok := baseAcronyms[strings.ToUpper(s)]; ok { + return []string{strings.ToUpper(s)} + } + var prev rune + var x string + for _, c := range s { + cs := string(c) + // fmt.Println("### cs ->", cs) + // fmt.Println("### unicode.IsControl(c) ->", unicode.IsControl(c)) + // fmt.Println("### unicode.IsDigit(c) ->", unicode.IsDigit(c)) + // fmt.Println("### unicode.IsGraphic(c) ->", unicode.IsGraphic(c)) + // fmt.Println("### unicode.IsLetter(c) ->", unicode.IsLetter(c)) + // fmt.Println("### unicode.IsLower(c) ->", unicode.IsLower(c)) + // fmt.Println("### unicode.IsMark(c) ->", unicode.IsMark(c)) + // fmt.Println("### unicode.IsPrint(c) ->", unicode.IsPrint(c)) + // fmt.Println("### unicode.IsPunct(c) ->", unicode.IsPunct(c)) + // fmt.Println("### unicode.IsSpace(c) ->", unicode.IsSpace(c)) + // fmt.Println("### unicode.IsTitle(c) ->", unicode.IsTitle(c)) + // fmt.Println("### unicode.IsUpper(c) ->", unicode.IsUpper(c)) + if !utf8.ValidRune(c) { + continue + } + + if isSpace(c) { + parts = xappend(parts, x) + x = cs + prev = c + continue + } + + if unicode.IsUpper(c) && !unicode.IsUpper(prev) { + parts = xappend(parts, x) + x = cs + prev = c + continue + } + if unicode.IsUpper(c) && baseAcronyms[strings.ToUpper(x)] { + parts = xappend(parts, x) + x = cs + prev = c + continue + } + if unicode.IsLetter(c) || unicode.IsDigit(c) || unicode.IsPunct(c) || c == '`' { + prev = c + x += cs + continue + } + + parts = xappend(parts, x) + x = "" + prev = c + } + parts = xappend(parts, x) + + return parts +} + +var _ encoding.TextUnmarshaler = &Ident{} +var _ encoding.TextMarshaler = &Ident{} + +//UnmarshalText unmarshalls byte array into the Ident +func (i *Ident) UnmarshalText(data []byte) error { + (*i) = New(string(data)) + return nil +} + +//MarshalText marshals Ident into byte array +func (i Ident) MarshalText() ([]byte, error) { + return []byte(i.Original), nil +} diff --git a/vendor/github.com/gobuffalo/flect/lower_upper.go b/vendor/github.com/gobuffalo/flect/lower_upper.go new file mode 100644 index 0000000000..930da58d8c --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/lower_upper.go @@ -0,0 +1,13 @@ +package flect + +import "strings" + +// ToUpper is a convience wrapper for strings.ToUpper +func (i Ident) ToUpper() Ident { + return New(strings.ToUpper(i.Original)) +} + +// ToLower is a convience wrapper for strings.ToLower +func (i Ident) ToLower() Ident { + return New(strings.ToLower(i.Original)) +} diff --git a/vendor/github.com/gobuffalo/flect/name/char.go b/vendor/github.com/gobuffalo/flect/name/char.go new file mode 100644 index 0000000000..64b2cb8d05 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/char.go @@ -0,0 +1,24 @@ +package name + +import "unicode" + +// Char returns the first letter, lowered +// "" = "x" +// "foo" = "f" +// "123d456" = "d" +func Char(s string) string { + return New(s).Char().String() +} + +// Char returns the first letter, lowered +// "" = "x" +// "foo" = "f" +// "123d456" = "d" +func (i Ident) Char() Ident { + for _, c := range i.Original { + if unicode.IsLetter(c) { + return New(string(unicode.ToLower(c))) + } + } + return New("x") +} diff --git a/vendor/github.com/gobuffalo/flect/name/file.go b/vendor/github.com/gobuffalo/flect/name/file.go new file mode 100644 index 0000000000..ec5cdae795 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/file.go @@ -0,0 +1,28 @@ +package name + +import ( + "strings" + + "github.com/gobuffalo/flect" +) + +// File creates a suitable file name +// admin/widget = admin/widget +// foo_bar = foo_bar +// U$ser = u_ser +func File(s string, exts ...string) string { + return New(s).File(exts...).String() +} + +// File creates a suitable file name +// admin/widget = admin/widget +// foo_bar = foo_bar +// U$ser = u_ser +func (i Ident) File(exts ...string) Ident { + var parts []string + + for _, part := range strings.Split(i.Original, "/") { + parts = append(parts, flect.Underscore(part)) + } + return New(strings.Join(parts, "/") + strings.Join(exts, "")) +} diff --git a/vendor/github.com/gobuffalo/flect/name/folder.go b/vendor/github.com/gobuffalo/flect/name/folder.go new file mode 100644 index 0000000000..16b1839d47 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/folder.go @@ -0,0 +1,36 @@ +package name + +import ( + "regexp" + "strings" +) + +var alphanum = regexp.MustCompile("[^a-zA-Z0-9_\\-\\/]+") + +// Folder creates a suitable folder name +// admin/widget = admin/widget +// foo_bar = foo_bar +// U$ser = u_ser +func Folder(s string, exts ...string) string { + return New(s).Folder(exts...).String() +} + +// Folder creates a suitable folder name +// admin/widget = admin/widget +// foo_bar = foo/bar +// U$ser = u/ser +func (i Ident) Folder(exts ...string) Ident { + var parts []string + + s := i.Original + if i.Pascalize().String() == s { + s = i.Underscore().String() + s = strings.Replace(s, "_", "/", -1) + } + for _, part := range strings.Split(s, "/") { + part = strings.ToLower(part) + part = alphanum.ReplaceAllString(part, "") + parts = append(parts, part) + } + return New(strings.Join(parts, "/") + strings.Join(exts, "")) +} diff --git a/vendor/github.com/gobuffalo/flect/name/ident.go b/vendor/github.com/gobuffalo/flect/name/ident.go new file mode 100644 index 0000000000..91f5d8bf8e --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/ident.go @@ -0,0 +1,13 @@ +package name + +import "github.com/gobuffalo/flect" + +// Ident represents the string and it's parts +type Ident struct { + flect.Ident +} + +// New creates a new Ident from the string +func New(s string) Ident { + return Ident{flect.New(s)} +} diff --git a/vendor/github.com/gobuffalo/flect/name/join.go b/vendor/github.com/gobuffalo/flect/name/join.go new file mode 100644 index 0000000000..de84883184 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/join.go @@ -0,0 +1,20 @@ +package name + +import "path/filepath" + +func FilePathJoin(names ...string) string { + var ni = make([]Ident, len(names)) + for i, n := range names { + ni[i] = New(n) + } + base := New("") + return base.FilePathJoin(ni...).String() +} + +func (i Ident) FilePathJoin(ni ...Ident) Ident { + var s = make([]string, len(ni)) + for i, n := range ni { + s[i] = n.OsPath().String() + } + return New(filepath.Join(s...)) +} diff --git a/vendor/github.com/gobuffalo/flect/name/key.go b/vendor/github.com/gobuffalo/flect/name/key.go new file mode 100644 index 0000000000..5fbf9ada2d --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/key.go @@ -0,0 +1,14 @@ +package name + +import ( + "strings" +) + +func Key(s string) string { + return New(s).Key().String() +} + +func (i Ident) Key() Ident { + s := strings.Replace(i.String(), "\\", "/", -1) + return New(strings.ToLower(s)) +} diff --git a/vendor/github.com/gobuffalo/flect/name/name.go b/vendor/github.com/gobuffalo/flect/name/name.go new file mode 100644 index 0000000000..c90cfb2715 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/name.go @@ -0,0 +1,62 @@ +package name + +import ( + "encoding" + "strings" + + "github.com/gobuffalo/flect" +) + +// Proper pascalizes and singularizes the string +// person = Person +// foo_bar = FooBar +// admin/widgets = AdminWidget +func Proper(s string) string { + return New(s).Proper().String() +} + +// Proper pascalizes and singularizes the string +// person = Person +// foo_bar = FooBar +// admin/widgets = AdminWidget +func (i Ident) Proper() Ident { + return Ident{i.Singularize().Pascalize()} +} + +// Group pascalizes and pluralizes the string +// person = People +// foo_bar = FooBars +// admin/widget = AdminWidgets +func Group(s string) string { + return New(s).Group().String() +} + +// Group pascalizes and pluralizes the string +// person = People +// foo_bar = FooBars +// admin/widget = AdminWidgets +func (i Ident) Group() Ident { + var parts []string + if len(i.Original) == 0 { + return i + } + last := i.Parts[len(i.Parts)-1] + for _, part := range i.Parts[:len(i.Parts)-1] { + parts = append(parts, flect.Pascalize(part)) + } + last = New(last).Pluralize().Pascalize().String() + parts = append(parts, last) + return New(strings.Join(parts, "")) +} + +var _ encoding.TextUnmarshaler = &Ident{} +var _ encoding.TextMarshaler = &Ident{} + +func (i *Ident) UnmarshalText(data []byte) error { + (*i) = New(string(data)) + return nil +} + +func (i Ident) MarshalText() ([]byte, error) { + return []byte(i.Original), nil +} diff --git a/vendor/github.com/gobuffalo/flect/name/os_path.go b/vendor/github.com/gobuffalo/flect/name/os_path.go new file mode 100644 index 0000000000..2a85723b44 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/os_path.go @@ -0,0 +1,21 @@ +package name + +import ( + "path/filepath" + "runtime" + "strings" +) + +func OsPath(s string) string { + return New(s).OsPath().String() +} + +func (i Ident) OsPath() Ident { + s := i.String() + if runtime.GOOS == "windows" { + s = strings.Replace(s, "/", string(filepath.Separator), -1) + } else { + s = strings.Replace(s, "\\", string(filepath.Separator), -1) + } + return New(s) +} diff --git a/vendor/github.com/gobuffalo/flect/name/package.go b/vendor/github.com/gobuffalo/flect/name/package.go new file mode 100644 index 0000000000..28f3d18c84 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/package.go @@ -0,0 +1,35 @@ +package name + +import ( + "go/build" + "path/filepath" + "strings" +) + +// Package will attempt to return a package version of the name +// $GOPATH/src/foo/bar = foo/bar +// $GOPATH\src\foo\bar = foo/bar +// foo/bar = foo/bar +func Package(s string) string { + return New(s).Package().String() +} + +// Package will attempt to return a package version of the name +// $GOPATH/src/foo/bar = foo/bar +// $GOPATH\src\foo\bar = foo/bar +// foo/bar = foo/bar +func (i Ident) Package() Ident { + c := build.Default + + s := i.Original + + for _, src := range c.SrcDirs() { + s = strings.TrimPrefix(s, src) + s = strings.TrimPrefix(s, filepath.Dir(src)) // encase there's no /src prefix + } + + s = strings.TrimPrefix(s, string(filepath.Separator)) + s = strings.Replace(s, "\\", "/", -1) + s = strings.Replace(s, "_", "", -1) + return Ident{New(s).ToLower()} +} diff --git a/vendor/github.com/gobuffalo/flect/name/param_id.go b/vendor/github.com/gobuffalo/flect/name/param_id.go new file mode 100644 index 0000000000..926e42265c --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/param_id.go @@ -0,0 +1,24 @@ +package name + +import "strings" + +// ParamID returns the string as parameter with _id added +// user = user_id +// UserID = user_id +// admin/widgets = admin_widgets_id +func ParamID(s string) string { + return New(s).ParamID().String() +} + +// ParamID returns the string as parameter with _id added +// user = user_id +// UserID = user_id +// admin/widgets = admin_widget_id +func (i Ident) ParamID() Ident { + s := i.Singularize().Underscore().String() + s = strings.ToLower(s) + if strings.HasSuffix(s, "_id") { + return New(s) + } + return New(s + "_id") +} diff --git a/vendor/github.com/gobuffalo/flect/name/resource.go b/vendor/github.com/gobuffalo/flect/name/resource.go new file mode 100644 index 0000000000..c79480953e --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/resource.go @@ -0,0 +1,24 @@ +package name + +import ( + "strings" +) + +// Resource version of a name +func (n Ident) Resource() Ident { + name := n.Underscore().String() + x := strings.FieldsFunc(name, func(r rune) bool { + return r == '_' || r == '/' + }) + + for i, w := range x { + if i == len(x)-1 { + x[i] = New(w).Pluralize().Pascalize().String() + continue + } + + x[i] = New(w).Pascalize().String() + } + + return New(strings.Join(x, "")) +} diff --git a/vendor/github.com/gobuffalo/flect/name/tablize.go b/vendor/github.com/gobuffalo/flect/name/tablize.go new file mode 100644 index 0000000000..e03fe2109e --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/tablize.go @@ -0,0 +1,17 @@ +package name + +// Tableize returns an underscore, pluralized string +// User = users +// Person = persons +// Admin/Widget = admin_widgets +func Tableize(s string) string { + return New(s).Tableize().String() +} + +// Tableize returns an underscore, pluralized string +// User = users +// Person = persons +// Admin/Widget = admin_widgets +func (i Ident) Tableize() Ident { + return Ident{i.Pluralize().Underscore()} +} diff --git a/vendor/github.com/gobuffalo/flect/name/url.go b/vendor/github.com/gobuffalo/flect/name/url.go new file mode 100644 index 0000000000..1acfcf7c23 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/url.go @@ -0,0 +1,5 @@ +package name + +func (n Ident) URL() Ident { + return Ident{n.File().Pluralize()} +} diff --git a/vendor/github.com/gobuffalo/flect/name/var_case.go b/vendor/github.com/gobuffalo/flect/name/var_case.go new file mode 100644 index 0000000000..804ce103aa --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/name/var_case.go @@ -0,0 +1,33 @@ +package name + +// VarCaseSingle version of a name. +// foo_bar = fooBar +// admin/widget = adminWidget +// User = users +func VarCaseSingle(s string) string { + return New(s).VarCaseSingle().String() +} + +// VarCaseSingle version of a name. +// foo_bar = fooBar +// admin/widget = adminWidget +// User = users +func (i Ident) VarCaseSingle() Ident { + return Ident{i.Group().Singularize().Camelize()} +} + +// VarCasePlural version of a name. +// foo_bar = fooBars +// admin/widget = adminWidgets +// User = users +func VarCasePlural(s string) string { + return New(s).VarCasePlural().String() +} + +// VarCasePlural version of a name. +// foo_bar = fooBars +// admin/widget = adminWidgets +// User = users +func (i Ident) VarCasePlural() Ident { + return Ident{i.Group().Pluralize().Camelize()} +} diff --git a/vendor/github.com/gobuffalo/flect/ordinalize.go b/vendor/github.com/gobuffalo/flect/ordinalize.go new file mode 100644 index 0000000000..1ce27b3a0d --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/ordinalize.go @@ -0,0 +1,43 @@ +package flect + +import ( + "fmt" + "strconv" +) + +// Ordinalize converts a number to an ordinal version +// 42 = 42nd +// 45 = 45th +// 1 = 1st +func Ordinalize(s string) string { + return New(s).Ordinalize().String() +} + +// Ordinalize converts a number to an ordinal version +// 42 = 42nd +// 45 = 45th +// 1 = 1st +func (i Ident) Ordinalize() Ident { + number, err := strconv.Atoi(i.Original) + if err != nil { + return i + } + var s string + switch abs(number) % 100 { + case 11, 12, 13: + s = fmt.Sprintf("%dth", number) + default: + switch abs(number) % 10 { + case 1: + s = fmt.Sprintf("%dst", number) + case 2: + s = fmt.Sprintf("%dnd", number) + case 3: + s = fmt.Sprintf("%drd", number) + } + } + if s != "" { + return New(s) + } + return New(fmt.Sprintf("%dth", number)) +} diff --git a/vendor/github.com/gobuffalo/flect/pascalize.go b/vendor/github.com/gobuffalo/flect/pascalize.go new file mode 100644 index 0000000000..76f0c6a706 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/pascalize.go @@ -0,0 +1,25 @@ +package flect + +import ( + "unicode" +) + +// Pascalize returns a string with each segment capitalized +// user = User +// bob dylan = BobDylan +// widget_id = WidgetID +func Pascalize(s string) string { + return New(s).Pascalize().String() +} + +// Pascalize returns a string with each segment capitalized +// user = User +// bob dylan = BobDylan +// widget_id = WidgetID +func (i Ident) Pascalize() Ident { + c := i.Camelize() + if len(c.String()) == 0 { + return c + } + return New(string(unicode.ToUpper(rune(c.Original[0]))) + c.Original[1:]) +} diff --git a/vendor/github.com/gobuffalo/flect/plural_rules.go b/vendor/github.com/gobuffalo/flect/plural_rules.go new file mode 100644 index 0000000000..1ebee22ab6 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/plural_rules.go @@ -0,0 +1,240 @@ +package flect + +var pluralRules = []rule{} + +// AddPlural adds a rule that will replace the given suffix with the replacement suffix. +func AddPlural(suffix string, repl string) { + pluralMoot.Lock() + defer pluralMoot.Unlock() + pluralRules = append(pluralRules, rule{ + suffix: suffix, + fn: func(s string) string { + s = s[:len(s)-len(suffix)] + return s + repl + }, + }) + + pluralRules = append(pluralRules, rule{ + suffix: repl, + fn: noop, + }) +} + +var singleToPlural = map[string]string{ + "human": "humans", + "matrix": "matrices", + "vertix": "vertices", + "index": "indices", + "mouse": "mice", + "louse": "lice", + "ress": "resses", + "ox": "oxen", + "quiz": "quizzes", + "series": "series", + "octopus": "octopi", + "equipment": "equipment", + "information": "information", + "rice": "rice", + "money": "money", + "species": "species", + "fish": "fish", + "sheep": "sheep", + "jeans": "jeans", + "police": "police", + "dear": "dear", + "goose": "geese", + "tooth": "teeth", + "foot": "feet", + "bus": "buses", + "fez": "fezzes", + "piano": "pianos", + "halo": "halos", + "photo": "photos", + "aircraft": "aircraft", + "alumna": "alumnae", + "alumnus": "alumni", + "analysis": "analyses", + "antenna": "antennas", + "antithesis": "antitheses", + "apex": "apexes", + "appendix": "appendices", + "axis": "axes", + "bacillus": "bacilli", + "bacterium": "bacteria", + "basis": "bases", + "beau": "beaus", + "bison": "bison", + "bureau": "bureaus", + "campus": "campuses", + "château": "châteaux", + "codex": "codices", + "concerto": "concertos", + "corpus": "corpora", + "crisis": "crises", + "curriculum": "curriculums", + "deer": "deer", + "diagnosis": "diagnoses", + "die": "dice", + "dwarf": "dwarves", + "ellipsis": "ellipses", + "erratum": "errata", + "faux pas": "faux pas", + "focus": "foci", + "formula": "formulas", + "fungus": "fungi", + "genus": "genera", + "graffito": "graffiti", + "grouse": "grouse", + "half": "halves", + "hoof": "hooves", + "hypothesis": "hypotheses", + "larva": "larvae", + "libretto": "librettos", + "loaf": "loaves", + "locus": "loci", + "minutia": "minutiae", + "moose": "moose", + "nebula": "nebulae", + "nucleus": "nuclei", + "oasis": "oases", + "offspring": "offspring", + "opus": "opera", + "parenthesis": "parentheses", + "phenomenon": "phenomena", + "phylum": "phyla", + "prognosis": "prognoses", + "radius": "radiuses", + "referendum": "referendums", + "salmon": "salmon", + "shrimp": "shrimp", + "stimulus": "stimuli", + "stratum": "strata", + "swine": "swine", + "syllabus": "syllabi", + "symposium": "symposiums", + "synopsis": "synopses", + "tableau": "tableaus", + "thesis": "theses", + "thief": "thieves", + "trout": "trout", + "tuna": "tuna", + "vertebra": "vertebrae", + "vita": "vitae", + "vortex": "vortices", + "wharf": "wharves", + "wife": "wives", + "wolf": "wolves", + "datum": "data", + "testis": "testes", + "alias": "aliases", + "house": "houses", + "shoe": "shoes", + "news": "news", + "ovum": "ova", + "foo": "foos", +} + +var pluralToSingle = map[string]string{} + +func init() { + for k, v := range singleToPlural { + pluralToSingle[v] = k + } +} +func init() { + AddPlural("campus", "campuses") + AddPlural("man", "men") + AddPlural("tz", "tzes") + AddPlural("alias", "aliases") + AddPlural("oasis", "oasis") + AddPlural("wife", "wives") + AddPlural("basis", "basis") + AddPlural("atum", "ata") + AddPlural("adium", "adia") + AddPlural("actus", "acti") + AddPlural("irus", "iri") + AddPlural("iterion", "iteria") + AddPlural("dium", "diums") + AddPlural("ovum", "ova") + AddPlural("ize", "izes") + AddPlural("dge", "dges") + AddPlural("focus", "foci") + AddPlural("child", "children") + AddPlural("oaf", "oaves") + AddPlural("randum", "randa") + AddPlural("base", "bases") + AddPlural("atus", "atuses") + AddPlural("ode", "odes") + AddPlural("person", "people") + AddPlural("va", "vae") + AddPlural("leus", "li") + AddPlural("oot", "eet") + AddPlural("oose", "eese") + AddPlural("box", "boxes") + AddPlural("ium", "ia") + AddPlural("sis", "ses") + AddPlural("nna", "nnas") + AddPlural("eses", "esis") + AddPlural("stis", "stes") + AddPlural("ex", "ices") + AddPlural("ula", "ulae") + AddPlural("isis", "ises") + AddPlural("ouses", "ouse") + AddPlural("olves", "olf") + AddPlural("lf", "lves") + AddPlural("rf", "rves") + AddPlural("afe", "aves") + AddPlural("bfe", "bves") + AddPlural("cfe", "cves") + AddPlural("dfe", "dves") + AddPlural("efe", "eves") + AddPlural("gfe", "gves") + AddPlural("hfe", "hves") + AddPlural("ife", "ives") + AddPlural("jfe", "jves") + AddPlural("kfe", "kves") + AddPlural("lfe", "lves") + AddPlural("mfe", "mves") + AddPlural("nfe", "nves") + AddPlural("ofe", "oves") + AddPlural("pfe", "pves") + AddPlural("qfe", "qves") + AddPlural("rfe", "rves") + AddPlural("sfe", "sves") + AddPlural("tfe", "tves") + AddPlural("ufe", "uves") + AddPlural("vfe", "vves") + AddPlural("wfe", "wves") + AddPlural("xfe", "xves") + AddPlural("yfe", "yves") + AddPlural("zfe", "zves") + AddPlural("hive", "hives") + AddPlural("quy", "quies") + AddPlural("by", "bies") + AddPlural("cy", "cies") + AddPlural("dy", "dies") + AddPlural("fy", "fies") + AddPlural("gy", "gies") + AddPlural("hy", "hies") + AddPlural("jy", "jies") + AddPlural("ky", "kies") + AddPlural("ly", "lies") + AddPlural("my", "mies") + AddPlural("ny", "nies") + AddPlural("py", "pies") + AddPlural("qy", "qies") + AddPlural("ry", "ries") + AddPlural("sy", "sies") + AddPlural("ty", "ties") + AddPlural("vy", "vies") + AddPlural("wy", "wies") + AddPlural("xy", "xies") + AddPlural("zy", "zies") + AddPlural("x", "xes") + AddPlural("ch", "ches") + AddPlural("ss", "sses") + AddPlural("sh", "shes") + AddPlural("oe", "oes") + AddPlural("io", "ios") + AddPlural("o", "oes") +} diff --git a/vendor/github.com/gobuffalo/flect/pluralize.go b/vendor/github.com/gobuffalo/flect/pluralize.go new file mode 100644 index 0000000000..1b9d43e462 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/pluralize.go @@ -0,0 +1,49 @@ +package flect + +import ( + "strings" + "sync" +) + +var pluralMoot = &sync.RWMutex{} + +// Pluralize returns a plural version of the string +// user = users +// person = people +// datum = data +func Pluralize(s string) string { + return New(s).Pluralize().String() +} + +// Pluralize returns a plural version of the string +// user = users +// person = people +// datum = data +func (i Ident) Pluralize() Ident { + s := i.Original + if len(s) == 0 { + return New("") + } + + pluralMoot.RLock() + defer pluralMoot.RUnlock() + + ls := strings.ToLower(s) + if _, ok := pluralToSingle[ls]; ok { + return i + } + if p, ok := singleToPlural[ls]; ok { + return New(p) + } + for _, r := range pluralRules { + if strings.HasSuffix(ls, r.suffix) { + return New(r.fn(s)) + } + } + + if strings.HasSuffix(ls, "s") { + return i + } + + return New(i.String() + "s") +} diff --git a/vendor/github.com/gobuffalo/flect/rule.go b/vendor/github.com/gobuffalo/flect/rule.go new file mode 100644 index 0000000000..dc616b337d --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/rule.go @@ -0,0 +1,10 @@ +package flect + +type ruleFn func(string) string + +type rule struct { + suffix string + fn ruleFn +} + +func noop(s string) string { return s } diff --git a/vendor/github.com/gobuffalo/flect/singular_rules.go b/vendor/github.com/gobuffalo/flect/singular_rules.go new file mode 100644 index 0000000000..14b471cd00 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/singular_rules.go @@ -0,0 +1,122 @@ +package flect + +var singularRules = []rule{} + +// AddSingular adds a rule that will replace the given suffix with the replacement suffix. +func AddSingular(ext string, repl string) { + singularMoot.Lock() + defer singularMoot.Unlock() + singularRules = append(singularRules, rule{ + suffix: ext, + fn: func(s string) string { + s = s[:len(s)-len(ext)] + return s + repl + }, + }) + + singularRules = append(singularRules, rule{ + suffix: repl, + fn: func(s string) string { + return s + }, + }) +} + +func init() { + AddSingular("ria", "rion") + AddSingular("news", "news") + AddSingular("halves", "half") + AddSingular("appendix", "appendix") + AddSingular("zzes", "zz") + AddSingular("ulas", "ula") + AddSingular("psis", "pse") + AddSingular("genus", "genera") + AddSingular("phyla", "phylum") + AddSingular("odice", "odex") + AddSingular("oxen", "ox") + AddSingular("ianos", "iano") + AddSingular("ulus", "uli") + AddSingular("mice", "mouse") + AddSingular("ouses", "ouse") + AddSingular("mni", "mnus") + AddSingular("ocus", "oci") + AddSingular("shoes", "shoe") + AddSingular("oasis", "oasis") + AddSingular("lice", "louse") + AddSingular("men", "man") + AddSingular("ta", "tum") + AddSingular("ia", "ium") + AddSingular("tives", "tive") + AddSingular("ldren", "ld") + AddSingular("people", "person") + AddSingular("aves", "afe") + AddSingular("uses", "us") + AddSingular("bves", "bfe") + AddSingular("cves", "cfe") + AddSingular("dves", "dfe") + AddSingular("eves", "efe") + AddSingular("gves", "gfe") + AddSingular("hves", "hfe") + AddSingular("chives", "chive") + AddSingular("ives", "ife") + AddSingular("movies", "movie") + AddSingular("jeans", "jeans") + AddSingular("cesses", "cess") + AddSingular("cess", "cess") + AddSingular("acti", "actus") + AddSingular("itzes", "itz") + AddSingular("usses", "uss") + AddSingular("uss", "uss") + AddSingular("jves", "jfe") + AddSingular("kves", "kfe") + AddSingular("mves", "mfe") + AddSingular("nves", "nfe") + AddSingular("moves", "move") + AddSingular("oves", "ofe") + AddSingular("pves", "pfe") + AddSingular("qves", "qfe") + AddSingular("sves", "sfe") + AddSingular("tves", "tfe") + AddSingular("uves", "ufe") + AddSingular("vves", "vfe") + AddSingular("wves", "wfe") + AddSingular("xves", "xfe") + AddSingular("yves", "yfe") + AddSingular("zves", "zfe") + AddSingular("hives", "hive") + AddSingular("lves", "lf") + AddSingular("rves", "rf") + AddSingular("quies", "quy") + AddSingular("bies", "by") + AddSingular("cies", "cy") + AddSingular("dies", "dy") + AddSingular("fies", "fy") + AddSingular("gies", "gy") + AddSingular("hies", "hy") + AddSingular("jies", "jy") + AddSingular("kies", "ky") + AddSingular("lies", "ly") + AddSingular("mies", "my") + AddSingular("nies", "ny") + AddSingular("pies", "py") + AddSingular("qies", "qy") + AddSingular("ries", "ry") + AddSingular("sies", "sy") + AddSingular("ties", "ty") + AddSingular("vies", "vy") + AddSingular("wies", "wy") + AddSingular("xies", "xy") + AddSingular("zies", "zy") + AddSingular("xes", "x") + AddSingular("ches", "ch") + AddSingular("sses", "ss") + AddSingular("shes", "sh") + AddSingular("oes", "o") + AddSingular("ress", "ress") + AddSingular("iri", "irus") + AddSingular("irus", "irus") + AddSingular("tuses", "tus") + AddSingular("tus", "tus") + AddSingular("s", "") + AddSingular("ss", "ss") +} diff --git a/vendor/github.com/gobuffalo/flect/singularize.go b/vendor/github.com/gobuffalo/flect/singularize.go new file mode 100644 index 0000000000..a08cbd5862 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/singularize.go @@ -0,0 +1,44 @@ +package flect + +import ( + "strings" + "sync" +) + +var singularMoot = &sync.RWMutex{} + +// Singularize returns a singular version of the string +// users = user +// data = datum +// people = person +func Singularize(s string) string { + return New(s).Singularize().String() +} + +// Singularize returns a singular version of the string +// users = user +// data = datum +// people = person +func (i Ident) Singularize() Ident { + s := i.Original + if len(s) == 0 { + return i + } + + singularMoot.RLock() + defer singularMoot.RUnlock() + ls := strings.ToLower(s) + if p, ok := pluralToSingle[ls]; ok { + return New(p) + } + if _, ok := singleToPlural[ls]; ok { + return i + } + for _, r := range singularRules { + if strings.HasSuffix(ls, r.suffix) { + return New(r.fn(s)) + } + } + + return i +} diff --git a/vendor/github.com/gobuffalo/flect/titleize.go b/vendor/github.com/gobuffalo/flect/titleize.go new file mode 100644 index 0000000000..e7a20d37f2 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/titleize.go @@ -0,0 +1,31 @@ +package flect + +import ( + "strings" + "unicode" +) + +// Titleize will capitalize the start of each part +// "Nice to see you!" = "Nice To See You!" +// "i've read a book! have you?" = "I've Read A Book! Have You?" +// "This is `code` ok" = "This Is `code` OK" +func Titleize(s string) string { + return New(s).Titleize().String() +} + +// Titleize will capitalize the start of each part +// "Nice to see you!" = "Nice To See You!" +// "i've read a book! have you?" = "I've Read A Book! Have You?" +// "This is `code` ok" = "This Is `code` OK" +func (i Ident) Titleize() Ident { + var parts []string + for _, part := range i.Parts { + var x string + x = string(unicode.ToTitle(rune(part[0]))) + if len(part) > 1 { + x += part[1:] + } + parts = append(parts, x) + } + return New(strings.Join(parts, " ")) +} diff --git a/vendor/github.com/gobuffalo/flect/underscore.go b/vendor/github.com/gobuffalo/flect/underscore.go new file mode 100644 index 0000000000..b92488aa00 --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/underscore.go @@ -0,0 +1,34 @@ +package flect + +import ( + "strings" + "unicode" +) + +// Underscore a string +// bob dylan = bob_dylan +// Nice to see you! = nice_to_see_you +// widgetID = widget_id +func Underscore(s string) string { + return New(s).Underscore().String() +} + +// Underscore a string +// bob dylan = bob_dylan +// Nice to see you! = nice_to_see_you +// widgetID = widget_id +func (i Ident) Underscore() Ident { + var out []string + for _, part := range i.Parts { + var x string + for _, c := range part { + if unicode.IsLetter(c) || unicode.IsDigit(c) { + x += string(c) + } + } + if x != "" { + out = append(out, x) + } + } + return New(strings.ToLower(strings.Join(out, "_"))) +} diff --git a/vendor/github.com/gobuffalo/flect/version.go b/vendor/github.com/gobuffalo/flect/version.go new file mode 100644 index 0000000000..b5f62170dc --- /dev/null +++ b/vendor/github.com/gobuffalo/flect/version.go @@ -0,0 +1,4 @@ +package flect + +//Version holds Flect version number +const Version = "v0.0.1" diff --git a/vendor/github.com/gobuffalo/genny/.codeclimate.yml b/vendor/github.com/gobuffalo/genny/.codeclimate.yml new file mode 100644 index 0000000000..3d77930c2f --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/.codeclimate.yml @@ -0,0 +1,14 @@ +--- +version: "2" +plugins: + golint: + enabled: true + checks: + GoLint/Naming/MixedCaps: + enabled: false + govet: + enabled: true + gofmt: + enabled: true + fixme: + enabled: true diff --git a/vendor/github.com/gobuffalo/genny/.gitignore b/vendor/github.com/gobuffalo/genny/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/genny/.gometalinter.json b/vendor/github.com/gobuffalo/genny/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/genny/.goreleaser.yml b/vendor/github.com/gobuffalo/genny/.goreleaser.yml new file mode 100644 index 0000000000..ba2dc82cea --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/.goreleaser.yml @@ -0,0 +1,28 @@ +builds: +- + goos: + - darwin + - linux + - windows + env: + - CGO_ENABLED=0 + # main: ./genny/main.go + # binary: {{.Binary}} + # hooks: + # pre: packr + # post: packr clean + +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' +brew: + github: + owner: markbates + name: homebrew-tap diff --git a/vendor/github.com/gobuffalo/genny/.travis.yml b/vendor/github.com/gobuffalo/genny/.travis.yml new file mode 100644 index 0000000000..1fb041a259 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/.travis.yml @@ -0,0 +1,36 @@ +language: go + +sudo: false + +matrix: + include: + - os: linux + go: "1.9.x" + - os: windows + go: "1.9.x" + - os: linux + go: "1.10.x" + - os: windows + go: "1.10.x" + - os: linux + go: "1.11.x" + env: + - GO111MODULE=off + - os: windows + go: "1.11.x" + env: + - GO111MODULE=off + - os: linux + go: "1.11.x" + env: + - GO111MODULE=on + - os: windows + go: "1.11.x" + env: + - GO111MODULE=on + +install: false + +script: + - go get -v -t ./... + - go test -v -timeout=5s -race ./... diff --git a/vendor/github.com/gobuffalo/genny/LICENSE.txt b/vendor/github.com/gobuffalo/genny/LICENSE.txt new file mode 100644 index 0000000000..123ddc0d80 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/LICENSE.txt @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/genny/Makefile b/vendor/github.com/gobuffalo/genny/Makefile new file mode 100644 index 0000000000..2eb0cd95c6 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/Makefile @@ -0,0 +1,53 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr2 + $(GO_BIN) install -v ./genny + +tidy: +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +else + echo skipping go mod tidy +endif + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/v2/packr2 + $(GO_BIN) get -tags ${TAGS} -t ./... + make tidy + +build: + packr2 + $(GO_BIN) build -v . + make tidy + +test: + packr2 + $(GO_BIN) test -tags ${TAGS} ./... + make tidy + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + +update: + packr2 clean + $(GO_BIN) get -u -tags ${TAGS} + make tidy + packr2 + make test + make install + make tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +release: + make tidy + release -y -f version.go + make tidy diff --git a/vendor/github.com/gobuffalo/genny/README.md b/vendor/github.com/gobuffalo/genny/README.md new file mode 100644 index 0000000000..e4ec55b8b3 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/README.md @@ -0,0 +1,495 @@ +

+ +

+GoDoc +Build Status +Go Report Card +

+ +# Genny + +## What Is Genny? + +Genny is a _framework_ for writing modular generators, it however, doesn't actually generate anything. It just makes it easier for you to. :) + +## Core Concepts + +### Generators + +A [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) is used to build a blue print of what you want to generate. + +A few of things that can be added to a `Generator` are: + +* [`github.com/gobuffalo/genny#File`](https://godoc.org/github.com/gobuffalo/genny#File) +* [`os/exec#Cmd`](https://godoc.org/os/exec#Cmd) +* [`github.com/gobuffalo/packd#Box`](https://godoc.org/github.com/gobuffalo/packd#Box) +* [`net/http#Request`](https://godoc.org/net/http#Request) +* and more + +A [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) does *not* actually generate anything; a [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner) is needed to run the generator. + +```go +g := genny.New() + +// add a file +g.File(genny.NewFileS("index.html", "Hello\n")) + +// execute a command +g.Command(exec.Command("go", "env")) + +// run a function at run time +g.RunFn(func(r *genny.Runner) error { + // look for the `genny` executable + if _, err := r.LookPath("genny"); err != nil { + // it wasn't found, so install it + if err := gotools.Get("github.com/gobuffalo/genny/genny")(r); err != nil { + return err + } + } + // call the `genny` executable with the `-h` flag. + return r.Exec(exec.Command("genny", "-h")) +}) +``` + +When a [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) is run each item that was added to it will be run in FIFO order. In the above example this means the following will happen: + +1. Create a new file `r.Root/index.html` +1. Run the command `go env` +1. Run a function that installs `genny` + +#### Runtime Checks + +Genny has two different components; the "generator" (or blueprint) and the "runner" which executes the generator. Often it is necessary to only run certain code when the generator is run, not built. For example, checking the existing of an executable and installing it if missing. + +In these situations you will want to use a [`github.com/gobuffalo/genny#RunFn`](https://godoc.org/github.com/gobuffalo/genny#RunFn) function. + +In this example at runtime the `RunFn` will be called given the `*Runner` that is calling it. When called the function will ask the [`github.com/gobuffalo/genny#Runner.LookPath`](https://godoc.org/github.com/gobuffalo/genny#Runner.LookPath) function to ask the location of the `genny` executable. + +In [`github.com/gobuffalo/genny#DryRunner`](https://godoc.org/github.com/gobuffalo/genny#DryRunner) this will simply echo back the name of the executable that has been asked for, in this case `return "genny", nil`. + +In [`github.com/gobuffalo/genny#WetRunner`](https://godoc.org/github.com/gobuffalo/genny#WetRunner) this will call the [`os/exec#LookPath`](https://godoc.org/os/exec#LookPath) and return its results. + +If the `genny` binary is not found, it will attempt to install it. Should that succeed the method returns the execution of a call to `genny -h`. + +```go +g.RunFn(func(r *genny.Runner) error { + // look for the `genny` executable + if _, err := r.LookPath("genny"); err != nil { + // it wasn't found, so install it + if err := gotools.Get("github.com/gobuffalo/genny/genny")(r); err != nil { + return err + } + } + // call the `genny` executable with the `-h` flag. + return r.Exec(exec.Command("genny", "-h")) +}) +``` + +The flexibility of the `*Fn` functions, combined with [`github.com/gobuffalo/genny#RunFn`](https://godoc.org/github.com/gobuffalo/genny#RunFn) make for a powerful testing combination. + +### Runners + +A [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner) is used to run generators and control the environment in which those generators are run. + +Genny ships with three implementations of `Runner` that cover _most_ situations. They can also provide good starting points for customized implementations of `Runner`. + +* [`github.com/gobuffalo/genny#DryRunner`](https://godoc.org/github.com/gobuffalo/genny#DryRunner) +* [`github.com/gobuffalo/genny#WetRunner`](https://godoc.org/github.com/gobuffalo/genny#WetRunner) +* [`github.com/gobuffalo/genny/gentest#NewRunner`](https://godoc.org/github.com/gobuffalo/genny/gentest#NewRunner) + +#### Adding Generators + +To add a [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) to a [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner) the [`github.com/gobuffalo/genny#Runner.With`](https://godoc.org/github.com/gobuffalo/genny#Runner.With) function can be used. + +```go +run := genny.DryRunner(context.Background()) + +// add a generator from the `simple` package +g := simple.New() +run.With(g) + +// add a generator from the `notsimple` package +g := notsimple.New() +run.With(g) +``` + +Each [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) is run in FIFO order in which it was added to the [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner). + +It is common to have a function that builds a new [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) or returns an `error` if there was a problem. + +```go +func New() (*genny.Generator, error) { + g := simple.New() + // do work which might error + return g, nil +} +``` + +The [`github.com/gobuffalo/genny#Runner.WithNew`](https://godoc.org/github.com/gobuffalo/genny#Runner.WithNew) function was designed to make adding a [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator) with this return argument signature easier. + +```go +if err := run.WithNew(New()); err != nil { + log.Fatal(err) +} +``` + +#### Dry Running (**NON-DESTRUCTIVE**) + +The idea of "dry" running means that no commands are executed, no files are written to disk, no HTTP requests are made, etc... Instead these steps are run "dry", which in the case of [`github.com/gobuffalo/genny#DryRunner`](https://godoc.org/github.com/gobuffalo/genny#DryRunner) is the case. + +```go +func main() { + run := genny.DryRunner(context.Background()) + + g := simple.New() + run.With(g) + + if err := run.Run(); err != nil { + log.Fatal(err) + } +} +``` + +```plain +// output +DEBU[2018-12-06T15:13:47-05:00] Step: 4eac628c +DEBU[2018-12-06T15:13:47-05:00] Chdir: /go/src/github.com/gobuffalo/genny/internal/_examples/dry +DEBU[2018-12-06T15:13:47-05:00] File: /go/src/github.com/gobuffalo/genny/internal/_examples/dry/index.html +DEBU[2018-12-06T15:13:47-05:00] Exec: go env +DEBU[2018-12-06T15:13:47-05:00] LookPath: genny +DEBU[2018-12-06T15:13:47-05:00] Exec: genny -h +``` + +```bash +// file list +. +└── main.go + +0 directories, 1 file +``` + +Using a "dry" runner can make testing easier when you don't have to worry about commands running, files being written, etc... It can also make it easy to provide a "dry-run" flag to your generators to let people see what will be generated when the generator is run for real. + +#### Wet Running (**DESTRUCTIVE**) + +While "dry" means to not execute commands or write files, "wet" running means the exact opposite; it will write files and execute commands. + +Use the [`github.com/gobuffalo/genny#WetRunner`](https://godoc.org/github.com/gobuffalo/genny#WetRunner) when "wet" running is the desired outcome. + +```go +func main() { + run := genny.WetRunner(context.Background()) + + g := simple.New() + run.With(g) + + if err := run.Run(); err != nil { + log.Fatal(err) + } +} +``` + +```plain +GOARCH="amd64" +GOBIN="" +// ... +A brief description of your application + +Usage: + genny [command] + +Available Commands: + help Help about any command + new generates a new genny stub + +Flags: + -h, --help help for genny + +Use "genny [command] --help" for more information about a command. +``` + +```bash +// file list +. +├── index.html +└── main.go + +0 directories, 2 files +``` + +```bash +$ cat index.html + +Hello +``` + +#### Changing Runner Behavior + +The change the way [`github.com/gobuffalo/genny#DryRunner`](https://godoc.org/github.com/gobuffalo/genny#DryRunner) or [`github.com/gobuffalo/genny#WetRunner`](https://godoc.org/github.com/gobuffalo/genny#WetRunner) work, or to build your own [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner) you need to implement the `*Fn` attributes on the [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner). + +```go +type Runner struct { + // ... + ExecFn func(*exec.Cmd) error // function to use when executing files + FileFn func(File) (File, error) // function to use when writing files + ChdirFn func(string, func() error) error // function to use when changing directories + DeleteFn func(string) error // function used to delete files/folders + RequestFn func(*http.Request, *http.Client) (*http.Response, error) // function used to make http requests + LookPathFn func(string) (string, error) // function used to make exec.LookPath lookups + // ... +} +``` + +These `*Fn` functions represent the **FINAL** end-point for the that is trying to be run. + +Here are two implementations of the [`github.com/gobuffalo/genny#Runner.FileFn`](https://godoc.org/github.com/gobuffalo/genny#Runner.FileFn) function. + +The first will result in the file being printed to the screen. The second implementation writes the file to disk. + +```go +run.FileFn = func(f packd.SimpleFile) (packd.SimpleFile, error) { + io.Copy(os.Stdout, f) + return f, nil +} + +run.FileFn = func(f genny.File) (genny.File, error) { + if d, ok := f.(genny.Dir); ok { + if err := os.MkdirAll(d.Name(), d.Perm); err != nil { + return f, err + } + return d, nil + } + + name := f.Name() + if !filepath.IsAbs(name) { + name = filepath.Join(run.Root, name) + } + dir := filepath.Dir(name) + if err := os.MkdirAll(dir, 0755); err != nil { + return f, err + } + ff, err := os.Create(name) + if err != nil { + return f, err + } + defer ff.Close() + if _, err := io.Copy(ff, f); err != nil { + return f, err + } + return f, nil +} +``` + +### Files + +Working with files, both creating new ones as well as, existing ones, is a core component of writing a generator. Genny understands this and offers several ways of working with files that is flexible and helps to make writing and testing your generators easier. + +The [`github.com/gobuffalo/genny#File`](https://godoc.org/github.com/gobuffalo/genny#File) interface is the heart of working with files in Genny. + +Genny ships with several convenience method for creating a [`github.com/gobuffalo/genny#File`](https://godoc.org/github.com/gobuffalo/genny#File). + +* [`github.com/gobuffalo/genny#NewFile`](https://godoc.org/github.com/gobuffalo/genny#NewFile) +* [`github.com/gobuffalo/genny#NewFileS`](https://godoc.org/github.com/gobuffalo/genny#NewFileS) +* [`github.com/gobuffalo/genny#NewFileB`](https://godoc.org/github.com/gobuffalo/genny#NewFileB) +* [`github.com/gobuffalo/genny#NewDir`](https://godoc.org/github.com/gobuffalo/genny#NewDir) + +#### Writing Files + +To write a file you can add a [`github.com/gobuffalo/genny#File`](https://godoc.org/github.com/gobuffalo/genny#File) to your [`github.com/gobuffalo/genny#Generator.File`](https://godoc.org/github.com/gobuffalo/genny#Generator.File) and your file will then be handled by your `*Runner` when your generator is run. + +```go +g.File(genny.NewFile("index.html", strings.NewReader("Hello\n"))) +g.File(genny.NewFileS("strings/string.html", "Hello\n")) +g.File(genny.NewFileB("bytes/byte.html", []byte("Hello\n"))) +``` + +In the case of [`github.com/gobuffalo/genny#WetRunner`](https://godoc.org/github.com/gobuffalo/genny#WetRunner) will attemp to create any directories your files require. + +#### Reading Files + +When writing generators you may need to read an existing file, perhaps to modify it, or perhaps read it's contents. This presents a problem in generators. + +The first problem is that anytime we have to read files from disk, we make testing more difficult. + +The bigger problems, however, present themselves more with "dry" runners (for example testing), than they do with "wet" runners. + +If generator `A` creates a new file and generator `B` wants to modify that file in testing and "dry" runners this is a problem as the file may not present on disk for generator `B` to access. + +To work around this issue Genny has the concept of a [`github.com/gobuffalo/genny#Disk`](https://godoc.org/github.com/gobuffalo/genny#Disk). + +Now, instead of asking for the file directly from the file system, we can ask for it from the [`github.com/gobuffalo/genny#Runner.Disk`](https://godoc.org/github.com/gobuffalo/genny#Runner.Disk) instead. + +```go +g.RunFn(func(r *genny.Runner) error { + // try to find main.go either in the virtual "disk" + // or the physical one + f, err := r.Disk.Find("main.go") + if err != nil { + return err + } + // print the contents of the file + fmt.Println(f.String()) + return nil +}) +``` + +When asking for files from [`github.com/gobuffalo/genny#Runner.Disk`](https://godoc.org/github.com/gobuffalo/genny#Runner.Disk) it will first check its internal cache for the file, returning it if found. If the file is not in the cache, then it try to read it from disk at `filepath.Join(r.Root, name)`. + +#### Transforming Files + +There are times that you may need to transform either certain files, or all files. This could be as simple as replacing a variable in a template's name to match some user input, or something more complex, such as running any templates with a given extension through a certain template engine. + +The [`github.com/gobuffalo/genny#Transformer`](https://godoc.org/github.com/gobuffalo/genny#Transformer) type can be used to implement these types of file transformations. + +To create a new [`github.com/gobuffalo/genny#Transformer`](https://godoc.org/github.com/gobuffalo/genny#Transformer) you can use the [`github.com/gobuffalo/genny#NewTransformer`](https://godoc.org/github.com/gobuffalo/genny#NewTransformer) function. + +The example below is taken from the [`github.com/gobuffalo/plushgen`](https://godoc.org/github.com/gobuffalo/plushgen) package. + +```go +// Transformer will plushify any file that has a ".plush" extension +func Transformer(ctx *plush.Context) genny.Transformer { + t := genny.NewTransformer(".plush", func(f genny.File) (genny.File, error) { + s, err := plush.RenderR(f, ctx) + if err != nil { + return f, errors.Wrap(err, f.Name()) + } + return genny.NewFileS(f.Name(), s), nil + }) + t.StripExt = true + return t +} +``` + +The [`github.com/gobuffalo/genny#Transformer`](https://godoc.org/github.com/gobuffalo/genny#Transformer) that is returned in the example will only be run on files that have a `.plush` extension in their name. + +Should a file have a `.plush` extension, it will be sent to [`github.com/gobuffalo/plush`](https://godoc.org/github.com/gobuffalo/plush) to be rendered. The result of that rendering is returned as a new [`github.com/gobuffalo/genny#File`](https://godoc.org/github.com/gobuffalo/genny#File). Finally, the extension `.plush` will be stripped from the file name. + +```go +g := genny.New() + +// add a file +g.File(genny.NewFileS("index.html.plush", "Hello <%= name %>\n")) + +// add the plush transformer +ctx := plush.NewContext() +ctx.Set("name", "World") +g.Transformer(plushgen.Transformer(ctx)) +``` + +```plain +// output +DEBU[2018-12-07T10:35:56-05:00] Step: 09c9663e +DEBU[2018-12-07T10:35:56-05:00] Chdir: /go/src/github.com/gobuffalo/genny/internal/_examples/dry +DEBU[2018-12-07T10:35:56-05:00] File: /go/src/github.com/gobuffalo/genny/internal/_examples/dry/index.html +Hello World +``` + +### Testing + +Testing a generator can be difficult because creating, deleting, and modifying files can be painful to handle during testing. The same can be said of running functions and HTTP requests. + +The `*Fn` attributes on [`github.com/gobuffalo/genny#Runner`](https://godoc.org/github.com/gobuffalo/genny#Runner) make it simplier to mock out different test cases. + +Most of the time the out of the box defaults are "good enough" for testing. The [`github.com/gobuffalo/genny/gentest`](https://godoc.org/github.com/gobuffalo/genny/gentest) package offers several helpers to simplify testing further. + +In this example we test the "happy" path of a [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator). + +```go +func Test_Happy(t *testing.T) { + r := require.New(t) + + run := gentest.NewRunner() + run.Disk.Add(genny.NewFileS("main.go", "my main.go file")) + + g := New() + run.With(g) + + r.NoError(run.Run()) + res := run.Results() + + cmds := []string{"go env", "genny -h"} + r.NoError(gentest.CompareCommands(cmds, res.Commands)) + + files := []string{"index.html", "main.go"} + r.NoError(gentest.CompareFiles(files, res.Files)) +} +``` + +Notice how in the above example we had to add `main.go` to the [`github.com/gobuffalo/genny#Runner.Disk`](https://godoc.org/github.com/gobuffalo/genny#Runner.Disk). That is because the file doesn't exist in our testing directory. + +In the following example we test what happens when the `genny` executable can not be found when running the [`github.com/gobuffalo/genny#Generator`](https://godoc.org/github.com/gobuffalo/genny#Generator). + +We can simulate this experience by using the [`github.com/gobuffalo/genny#Runner.LookPathFn`](https://godoc.org/github.com/gobuffalo/genny#Runner.LookPathFn) to return an error if it is asked about that particular executable. + +```go +func Test_Missing_Genny(t *testing.T) { + r := require.New(t) + + run := gentest.NewRunner() + run.Disk.Add(genny.NewFileS("main.go", "my main.go file")) + + g := New() + run.With(g) + + // pretend we can't find genny + run.LookPathFn = func(s string) (string, error) { + if s == "genny" { + return "", errors.New("can't find genny") + } + return s, nil + } + + r.NoError(run.Run()) + res := run.Results() + + cmds := []string{"go env", "go get github.com/gobuffalo/genny/genny", "genny -h"} + r.NoError(gentest.CompareCommands(cmds, res.Commands)) + + files := []string{"index.html", "main.go"} + r.NoError(gentest.CompareFiles(files, res.Files)) +} +``` + +## The `genny` Executable + +Genny ships with an executable that helps to generate new generators. + +### Installation + +```bash +$ go get -u github.com/gobuffalo/genny/genny +``` + +### Usage + +```bash +$ genny -h + +tools for working with genny + +Usage: + genny [command] + +Available Commands: + help Help about any command + new generates a new genny stub + +Flags: + -h, --help help for genny + +Use "genny [command] --help" for more information about a command. +``` + +### Generating a New Generator + +```bash +$ genny new coke -h + +DEBU[2018-12-07T11:07:01-05:00] Step: a1d8eb2f +DEBU[2018-12-07T11:07:01-05:00] Chdir: /go/src/github.com/gobuffalo +DEBU[2018-12-07T11:07:01-05:00] File: /go/src/github.com/gobuffalo/coke/coke.go +DEBU[2018-12-07T11:07:01-05:00] File: /go/src/github.com/gobuffalo/coke/coke_test.go +DEBU[2018-12-07T11:07:01-05:00] File: /go/src/github.com/gobuffalo/coke/options.go +DEBU[2018-12-07T11:07:01-05:00] File: /go/src/github.com/gobuffalo/coke/options_test.go +DEBU[2018-12-07T11:07:01-05:00] File: /go/src/github.com/gobuffalo/coke/templates/example.txt +``` diff --git a/vendor/github.com/gobuffalo/genny/SHOULDERS.md b/vendor/github.com/gobuffalo/genny/SHOULDERS.md new file mode 100644 index 0000000000..42b36ba913 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/SHOULDERS.md @@ -0,0 +1,108 @@ +# `github.com/gobuffalo/genny` Stands on the Shoulders of Giants + +`github.com/gobuffalo/genny` does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them altogether 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**: + + +* [github.com/fatih/structs](https://godoc.org/github.com/fatih/structs) + +* [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy) + +* [github.com/gobuffalo/flect](https://godoc.org/github.com/gobuffalo/flect) + +* [github.com/gobuffalo/flect/name](https://godoc.org/github.com/gobuffalo/flect/name) + +* [github.com/gobuffalo/github_flavored_markdown](https://godoc.org/github.com/gobuffalo/github_flavored_markdown) + +* [github.com/gobuffalo/packr](https://godoc.org/github.com/gobuffalo/packr) + +* [github.com/gobuffalo/plush](https://godoc.org/github.com/gobuffalo/plush) + +* [github.com/gobuffalo/plush/ast](https://godoc.org/github.com/gobuffalo/plush/ast) + +* [github.com/gobuffalo/plush/lexer](https://godoc.org/github.com/gobuffalo/plush/lexer) + +* [github.com/gobuffalo/plush/parser](https://godoc.org/github.com/gobuffalo/plush/parser) + +* [github.com/gobuffalo/plush/token](https://godoc.org/github.com/gobuffalo/plush/token) + +* [github.com/gobuffalo/tags](https://godoc.org/github.com/gobuffalo/tags) + +* [github.com/gobuffalo/tags/form](https://godoc.org/github.com/gobuffalo/tags/form) + +* [github.com/gobuffalo/tags/form/bootstrap](https://godoc.org/github.com/gobuffalo/tags/form/bootstrap) + +* [github.com/gobuffalo/uuid](https://godoc.org/github.com/gobuffalo/uuid) + +* [github.com/gobuffalo/validate](https://godoc.org/github.com/gobuffalo/validate) + +* [github.com/gobuffalo/validate/validators](https://godoc.org/github.com/gobuffalo/validate/validators) + +* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv) + +* [github.com/kr/pretty](https://godoc.org/github.com/kr/pretty) + +* [github.com/markbates/going/defaults](https://godoc.org/github.com/markbates/going/defaults) + +* [github.com/markbates/going/randx](https://godoc.org/github.com/markbates/going/randx) + +* [github.com/markbates/going/wait](https://godoc.org/github.com/markbates/going/wait) + +* [github.com/markbates/inflect](https://godoc.org/github.com/markbates/inflect) + +* [github.com/microcosm-cc/bluemonday](https://godoc.org/github.com/microcosm-cc/bluemonday) + +* [github.com/onsi/ginkgo](https://godoc.org/github.com/onsi/ginkgo) + +* [github.com/onsi/gomega](https://godoc.org/github.com/onsi/gomega) + +* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors) + +* [github.com/serenize/snaker](https://godoc.org/github.com/serenize/snaker) + +* [github.com/sergi/go-diff/diffmatchpatch](https://godoc.org/github.com/sergi/go-diff/diffmatchpatch) + +* [github.com/shurcooL/highlight_diff](https://godoc.org/github.com/shurcooL/highlight_diff) + +* [github.com/shurcooL/highlight_go](https://godoc.org/github.com/shurcooL/highlight_go) + +* [github.com/shurcooL/octicon](https://godoc.org/github.com/shurcooL/octicon) + +* [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/sourcegraph/annotate](https://godoc.org/github.com/sourcegraph/annotate) + +* [github.com/sourcegraph/syntaxhighlight](https://godoc.org/github.com/sourcegraph/syntaxhighlight) + +* [github.com/stretchr/testify/assert](https://godoc.org/github.com/stretchr/testify/assert) + +* [github.com/stretchr/testify/require](https://godoc.org/github.com/stretchr/testify/require) + +* [github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew](https://godoc.org/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew) + +* [github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib](https://godoc.org/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib) + +* [golang.org/x/crypto/ssh/terminal](https://godoc.org/golang.org/x/crypto/ssh/terminal) + +* [golang.org/x/net/context](https://godoc.org/golang.org/x/net/context) + +* [golang.org/x/net/html](https://godoc.org/golang.org/x/net/html) + +* [golang.org/x/net/html/atom](https://godoc.org/golang.org/x/net/html/atom) + +* [golang.org/x/sync/errgroup](https://godoc.org/golang.org/x/sync/errgroup) + +* [golang.org/x/sys/unix](https://godoc.org/golang.org/x/sys/unix) + +* [golang.org/x/tools/go/ast/astutil](https://godoc.org/golang.org/x/tools/go/ast/astutil) + +* [golang.org/x/tools/imports](https://godoc.org/golang.org/x/tools/imports) + +* [golang.org/x/tools/internal/fastwalk](https://godoc.org/golang.org/x/tools/internal/fastwalk) + +* [gopkg.in/check.v1](https://godoc.org/gopkg.in/check.v1) + +* [gopkg.in/russross/blackfriday.v1](https://godoc.org/gopkg.in/russross/blackfriday.v1) diff --git a/vendor/github.com/gobuffalo/genny/confirm.go b/vendor/github.com/gobuffalo/genny/confirm.go new file mode 100644 index 0000000000..1316cccdaf --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/confirm.go @@ -0,0 +1,15 @@ +package genny + +import ( + "bufio" + "fmt" + "os" +) + +func Confirm(msg string) bool { + reader := bufio.NewReader(os.Stdin) + fmt.Print(msg) + text, _ := reader.ReadString('\n') + + return (text == "y\n" || text == "Y\n") +} diff --git a/vendor/github.com/gobuffalo/genny/dir.go b/vendor/github.com/gobuffalo/genny/dir.go new file mode 100644 index 0000000000..4f5ea5838a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/dir.go @@ -0,0 +1,18 @@ +package genny + +import "os" + +var _ File = Dir{} + +type Dir struct { + File + Perm os.FileMode +} + +func NewDir(path string, perm os.FileMode) File { + f := NewFileS(path, path) + return Dir{ + File: f, + Perm: perm, + } +} diff --git a/vendor/github.com/gobuffalo/genny/disk.go b/vendor/github.com/gobuffalo/genny/disk.go new file mode 100644 index 0000000000..d9fa04d89a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/disk.go @@ -0,0 +1,112 @@ +package genny + +import ( + "bytes" + "io" + "os" + "runtime" + "sort" + "strings" + "sync" + + "github.com/gobuffalo/packd" + "github.com/pkg/errors" +) + +// Disk is a virtual file system that works +// with both dry and wet runners. Perfect for seeding +// Files or non-destructively deleting files +type Disk struct { + Runner *Runner + files map[string]File + moot *sync.RWMutex +} + +func (d *Disk) AddBox(box packd.Walker) error { + return box.Walk(func(path string, file packd.File) error { + d.Add(NewFile(path, file)) + return nil + }) +} + +// Files returns a sorted list of all the files in the disk +func (d *Disk) Files() []File { + var files []File + for _, f := range d.files { + if s, ok := f.(io.Seeker); ok { + s.Seek(0, 0) + } + files = append(files, f) + } + sort.Slice(files, func(i, j int) bool { + return files[i].Name() < files[j].Name() + }) + return files +} + +func newDisk(r *Runner) *Disk { + return &Disk{ + Runner: r, + files: map[string]File{}, + moot: &sync.RWMutex{}, + } +} + +// Remove a file(s) from the virtual disk. +func (d *Disk) Remove(name string) { + d.moot.Lock() + defer d.moot.Unlock() + for f, _ := range d.files { + if strings.HasPrefix(f, name) { + delete(d.files, f) + } + } +} + +// Delete calls the Runner#Delete function +func (d *Disk) Delete(name string) error { + return d.Runner.Delete(name) +} + +// Add file to the virtual disk +func (d *Disk) Add(f File) { + d.moot.Lock() + defer d.moot.Unlock() + d.files[f.Name()] = f +} + +// Find a file from the virtual disk. If the file doesn't +// exist it will try to read the file from the physical disk. +func (d *Disk) Find(name string) (File, error) { + + d.moot.RLock() + if f, ok := d.files[name]; ok { + if seek, ok := f.(io.Seeker); ok { + seek.Seek(0, 0) + } + d.moot.RUnlock() + return f, nil + } + d.moot.RUnlock() + + gf := NewFile(name, bytes.NewReader([]byte(""))) + + osname := name + if runtime.GOOS == "windows" { + osname = strings.Replace(osname, "/", "\\", -1) + } + f, err := os.Open(osname) + if err != nil { + return gf, errors.WithStack(err) + } + defer f.Close() + + bb := &bytes.Buffer{} + + if _, err := io.Copy(bb, f); err != nil { + return gf, errors.WithStack(err) + } + gf = NewFile(name, bb) + d.Add(gf) + return gf, nil +} diff --git a/vendor/github.com/gobuffalo/genny/dry_runner.go b/vendor/github.com/gobuffalo/genny/dry_runner.go new file mode 100644 index 0000000000..4f4eee768d --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/dry_runner.go @@ -0,0 +1,15 @@ +package genny + +import ( + "context" + + "github.com/gobuffalo/logger" +) + +// DryRunner will NOT execute commands and write files +// it is NOT destructive +func DryRunner(ctx context.Context) *Runner { + r := NewRunner(ctx) + r.Logger = logger.New(logger.DebugLevel) + return r +} diff --git a/vendor/github.com/gobuffalo/genny/events.go b/vendor/github.com/gobuffalo/genny/events.go new file mode 100644 index 0000000000..3bc313eb6f --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/events.go @@ -0,0 +1,8 @@ +package genny + +const ( + EvtStarted = "genny:runner:started" + EvtFinished = "genny:runner:finished" + EvtFinishedErr = "genny:runner:finished:err" + EvtStepPrefix = "genny:step" +) diff --git a/vendor/github.com/gobuffalo/genny/file.go b/vendor/github.com/gobuffalo/genny/file.go new file mode 100644 index 0000000000..30c33d717b --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/file.go @@ -0,0 +1,32 @@ +package genny + +import ( + "bytes" + "io" + "runtime" + "strings" + + "github.com/gobuffalo/packd" +) + +// File interface for working with files +type File = packd.SimpleFile + +// NewFile takes the name of the file you want to +// write to and a reader to reader from +func NewFile(name string, r io.Reader) File { + osname := name + if runtime.GOOS == "windows" { + osname = strings.Replace(osname, "\\", "/", -1) + } + f, _ := packd.NewFile(osname, r) + return f +} + +func NewFileS(name string, s string) File { + return NewFile(name, strings.NewReader(s)) +} + +func NewFileB(name string, s []byte) File { + return NewFile(name, bytes.NewReader(s)) +} diff --git a/vendor/github.com/gobuffalo/genny/force.go b/vendor/github.com/gobuffalo/genny/force.go new file mode 100644 index 0000000000..4078c8418a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/force.go @@ -0,0 +1,84 @@ +package genny + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/gobuffalo/packd" + "github.com/pkg/errors" +) + +// ForceBox will mount each file in the box and wrap it with ForceFile +func ForceBox(g *Generator, box packd.Walker, force bool) error { + return box.Walk(func(path string, bf packd.File) error { + f := NewFile(path, bf) + ff := ForceFile(f, force) + f, err := ff(f) + if err != nil { + return errors.WithStack(err) + } + g.File(f) + return nil + }) +} + +// ForceFile is a TransformerFn that will return an error if the path exists if `force` is false. If `force` is true it will delete the path. +func ForceFile(f File, force bool) TransformerFn { + return func(f File) (File, error) { + path := f.Name() + path, err := filepath.Abs(path) + if err != nil { + return f, errors.WithStack(err) + } + _, err = os.Stat(path) + if err != nil { + // path doesn't exist. move on. + return f, nil + } + if !force { + return f, errors.Errorf("path %s already exists", path) + } + if err := os.RemoveAll(path); err != nil { + return f, errors.WithStack(err) + } + return f, nil + } +} + +// Force is a RunFn that will return an error if the path exists if `force` is false. If `force` is true it will delete the path. +// Is is recommended to use ForceFile when you can. +func Force(path string, force bool) RunFn { + if path == "." || path == "" { + pwd, _ := os.Getwd() + path = pwd + } + return func(r *Runner) error { + path, err := filepath.Abs(path) + if err != nil { + return errors.WithStack(err) + } + fi, err := os.Stat(path) + if err != nil { + // path doesn't exist. move on. + return nil + } + if !force { + if !fi.IsDir() { + return errors.Errorf("path %s already exists", path) + } + files, err := ioutil.ReadDir(path) + if err != nil { + return errors.WithStack(err) + } + if len(files) > 0 { + return errors.Errorf("path %s already exists", path) + } + return nil + } + if err := os.RemoveAll(path); err != nil { + return errors.WithStack(err) + } + return nil + } +} diff --git a/vendor/github.com/gobuffalo/genny/generator.go b/vendor/github.com/gobuffalo/genny/generator.go new file mode 100644 index 0000000000..8baf530494 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/generator.go @@ -0,0 +1,104 @@ +package genny + +import ( + "math/rand" + "os/exec" + "sync" + "time" + + "github.com/gobuffalo/events" + "github.com/gobuffalo/packd" + "github.com/pkg/errors" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// Generator is the basic type for generators to use +type Generator struct { + StepName string + Should func(*Runner) bool + Root string + ErrorFn func(error) + runners []RunFn + transformers []Transformer + moot *sync.RWMutex +} + +// New, well-formed, generator +func New() *Generator { + g := &Generator{ + StepName: stepName(), + runners: []RunFn{}, + moot: &sync.RWMutex{}, + transformers: []Transformer{}, + } + return g +} + +func (g *Generator) Event(kind string, payload events.Payload) { + g.RunFn(func(r *Runner) error { + return events.EmitPayload(kind, payload) + }) +} + +// File adds a file to be run when the generator is run +func (g *Generator) File(f File) { + g.RunFn(func(r *Runner) error { + return r.File(f) + }) +} + +func (g *Generator) Transform(f File) (File, error) { + g.moot.RLock() + defer g.moot.RUnlock() + var err error + for _, t := range g.transformers { + f, err = t.Transform(f) + if err != nil { + return f, errors.WithStack(err) + } + } + + return f, nil +} + +// Transformer adds a file transform to the generator +func (g *Generator) Transformer(t Transformer) { + g.moot.Lock() + defer g.moot.Unlock() + g.transformers = append(g.transformers, t) +} + +// Command adds a command to be run when the generator is run +func (g *Generator) Command(cmd *exec.Cmd) { + g.RunFn(func(r *Runner) error { + return r.Exec(cmd) + }) +} + +// Box walks through a packr.Box and adds Files for each entry +// in the box. +func (g *Generator) Box(box packd.Walker) error { + return box.Walk(func(path string, f packd.File) error { + g.File(NewFile(path, f)) + return nil + }) +} + +// RunFn adds a generic "runner" function to the generator. +func (g *Generator) RunFn(fn RunFn) { + g.moot.Lock() + defer g.moot.Unlock() + g.runners = append(g.runners, fn) +} + +func (g1 *Generator) Merge(g2 *Generator) { + g2.moot.Lock() + g1.moot.Lock() + g1.runners = append(g1.runners, g2.runners...) + g1.transformers = append(g1.transformers, g2.transformers...) + g1.moot.Unlock() + g2.moot.Unlock() +} diff --git a/vendor/github.com/gobuffalo/genny/genny.go b/vendor/github.com/gobuffalo/genny/genny.go new file mode 100644 index 0000000000..85962ca977 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/genny.go @@ -0,0 +1,4 @@ +/* +Package genny is a _framework_ for writing modular generators, it however, doesn't actually generate anything. It just makes it easier for you to. :) +*/ +package genny diff --git a/vendor/github.com/gobuffalo/genny/group.go b/vendor/github.com/gobuffalo/genny/group.go new file mode 100644 index 0000000000..e1be356e4a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/group.go @@ -0,0 +1,30 @@ +package genny + +import "sync" + +type Group struct { + Generators []*Generator + moot sync.RWMutex +} + +func (gg *Group) Add(g *Generator) { + m := &gg.moot + m.Lock() + defer m.Unlock() + gg.Generators = append(gg.Generators, g) +} + +func (gg *Group) Merge(g2 *Group) { + for _, g := range g2.Generators { + gg.Add(g) + } +} + +func (gg *Group) With(r *Runner) { + m := &gg.moot + m.RLock() + defer m.RUnlock() + for _, g := range gg.Generators { + r.With(g) + } +} diff --git a/vendor/github.com/gobuffalo/genny/helpers.go b/vendor/github.com/gobuffalo/genny/helpers.go new file mode 100644 index 0000000000..67d0c59b18 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/helpers.go @@ -0,0 +1,54 @@ +package genny + +import ( + "path/filepath" + "strings" + + "github.com/gobuffalo/envy" +) + +func exts(f File) []string { + var exts []string + + name := f.Name() + ext := filepath.Ext(name) + + for ext != "" { + exts = append([]string{ext}, exts...) + name = strings.TrimSuffix(name, ext) + ext = filepath.Ext(name) + } + return exts +} + +// HasExt checks if a file has ANY of the +// extensions passed in. If no extensions +// are given then `true` is returned +func HasExt(f File, ext ...string) bool { + if len(ext) == 0 || ext == nil { + return true + } + for _, xt := range ext { + xt = strings.TrimSpace(xt) + if xt == "*" || xt == "*.*" { + return true + } + for _, x := range exts(f) { + if x == xt { + return true + } + } + } + return false +} + +// StripExt from a File and return a new one +func StripExt(f File, ext string) File { + name := f.Name() + name = strings.Replace(name, ext, "", -1) + return NewFile(name, f) +} + +func GoBin() string { + return envy.Get("GO_BIN", "go") +} diff --git a/vendor/github.com/gobuffalo/genny/logger.go b/vendor/github.com/gobuffalo/genny/logger.go new file mode 100644 index 0000000000..a262a23f4d --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/logger.go @@ -0,0 +1,8 @@ +package genny + +import "github.com/gobuffalo/logger" + +// Logger interface for a logger to be used with genny. Logrus is 100% compatible. +type Logger = logger.Logger + +var DefaultLogLvl = logger.InfoLevel diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_import.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_import.go new file mode 100644 index 0000000000..8714c626ec --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_import.go @@ -0,0 +1,52 @@ +package gotools + +import ( + "fmt" + "go/ast" + "go/token" + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +// AddImport adds n number of import statements into the path provided +func AddImport(gf genny.File, imports ...string) (genny.File, error) { + pf, err := ParseFile(gf) + if err != nil { + return gf, errors.WithStack(err) + } + gf = pf.File + + end := findLastImport(pf.Ast, pf.FileSet, pf.Lines) + + x := make([]string, len(imports), len(imports)+2) + for _, i := range imports { + x = append(x, fmt.Sprintf("\t\"%s\"", i)) + + } + if end < 0 { + x = append([]string{"import ("}, x...) + x = append(x, ")") + } + + pf.Lines = append(pf.Lines[:end], append(x, pf.Lines[end:]...)...) + + fileContent := strings.Join(pf.Lines, "\n") + return genny.NewFile(gf.Name(), strings.NewReader(fileContent)), nil +} + +func findLastImport(f *ast.File, fset *token.FileSet, fileLines []string) int { + var end = -1 + + ast.Inspect(f, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.ImportSpec: + end = fset.Position(x.End()).Line + return true + } + return true + }) + + return end +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_inside_block.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_inside_block.go new file mode 100644 index 0000000000..9c72b611dc --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/add_inside_block.go @@ -0,0 +1,81 @@ +package gotools + +import ( + "fmt" + "go/ast" + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +// AddInsideBlock will add anything inside of the app declaration block inside of file +func AddInsideBlock(gf genny.File, search string, expressions ...string) (genny.File, error) { + pf, err := ParseFile(gf) + if err != nil { + return gf, errors.WithStack(err) + } + gf = pf.File + + _, end := findBlockCoordinates(search, pf) + if end < 0 { + return gf, errors.Errorf("could not find desired block in %s", gf.Name()) + } + + if len(pf.Lines) == end { + end = end - 1 + } + + el := pf.Lines[end:] + sl := []string{} + sf := []string{} + for _, l := range pf.Lines[:end] { + // if there's a app.ServeFiles("/", foo) line it needs to be the last added to the router + if strings.Contains(l, "ServeFiles(\"/\"") { + sf = append(sf, l) + continue + } + sl = append(sl, l) + } + + for i := 0; i < len(expressions); i++ { + expressions[i] = fmt.Sprintf("\t\t%s", expressions[i]) + } + + el = append(sf, el...) + pf.Lines = append(sl, append(expressions, el...)...) + + fileContent := strings.Join(pf.Lines, "\n") + return genny.NewFile(gf.Name(), strings.NewReader(fileContent)), nil +} + +func findBlockCoordinates(search string, pf ParsedFile) (int, int) { + var end = -1 + var start = -1 + + ast.Inspect(pf.Ast, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.StructType: + line := pf.FileSet.Position(x.Pos()).Line + structDeclaration := fmt.Sprintf("%s\n", pf.Lines[line-1]) + + if strings.Contains(structDeclaration, search) { + start = line + end = pf.FileSet.Position(x.End()).Line + return false + } + + case *ast.BlockStmt: + start = pf.FileSet.Position(x.Lbrace).Line + blockDeclaration := fmt.Sprintf("%s\n", pf.Lines[start-1]) + + if strings.Contains(blockDeclaration, search) { + end = pf.FileSet.Position(x.Rbrace).Line - 1 + } + + } + return true + }) + + return start, end +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/append.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/append.go new file mode 100644 index 0000000000..438f32459d --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/append.go @@ -0,0 +1,22 @@ +package gotools + +import ( + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +//Append allows to append source into a go file +func Append(gf genny.File, expressions ...string) (genny.File, error) { + pf, err := ParseFile(gf) + if err != nil { + return gf, errors.WithStack(err) + } + + gf = pf.File + pf.Lines = append(pf.Lines, expressions...) + + fileContent := strings.Join(pf.Lines, "\n") + return genny.NewFile(gf.Name(), strings.NewReader(fileContent)), nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/change_import.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/change_import.go new file mode 100644 index 0000000000..1927a9b913 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/change_import.go @@ -0,0 +1,34 @@ +package gotools + +import ( + "bytes" + "go/ast" + "go/parser" + "go/printer" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" + "golang.org/x/tools/go/ast/astutil" +) + +func RewriteImports(gf genny.File, swaps map[string]string) (genny.File, error) { + pf, err := ParseFileMode(gf, parser.ParseComments) + if err != nil { + return gf, errors.WithStack(err) + } + for key, value := range swaps { + if !astutil.DeleteImport(pf.FileSet, pf.Ast, key) { + continue + } + + astutil.AddImport(pf.FileSet, pf.Ast, value) + } + ast.SortImports(pf.FileSet, pf.Ast) + + w := &bytes.Buffer{} + if err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(w, pf.FileSet, pf.Ast); err != nil { + return gf, errors.WithStack(err) + } + + return genny.NewFile(gf.Name(), w), nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/files.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/files.go new file mode 100644 index 0000000000..466cda7d73 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/files.go @@ -0,0 +1,36 @@ +package gotools + +import ( + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +func GoFiles(dir string) ([]string, error) { + var files []string + + pwd, err := os.Getwd() + if err != nil { + return files, errors.WithStack(err) + } + if dir == "" { + dir = pwd + } + + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + path = strings.TrimPrefix(path, pwd+"/") + if strings.Contains(path, ".git") || strings.Contains(path, "node_modules") || strings.Contains(path, "vendor"+string(os.PathSeparator)) { + if info.IsDir() { + return filepath.SkipDir + } + return nil + } + if filepath.Ext(path) == ".go" { + files = append(files, path) + } + return nil + }) + return files, nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/fmt.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/fmt.go new file mode 100644 index 0000000000..f2669884b7 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/fmt.go @@ -0,0 +1,40 @@ +package gotools + +import ( + "bytes" + + "github.com/gobuffalo/genny" + "github.com/gobuffalo/genny/movinglater/gotools/goimports" + "github.com/pkg/errors" +) + +func GoFmt(root string) (*genny.Generator, error) { + g := genny.New() + g.RunFn(func(r *genny.Runner) error { + i, err := goimports.New(root) + if err != nil { + return errors.WithStack(err) + } + return i.Run() + }) + + return g, nil +} + +func FmtTransformer() genny.Transformer { + t := genny.NewTransformer(".go", func(f genny.File) (genny.File, error) { + bb := &bytes.Buffer{} + gi := goimports.NewFromFiles(goimports.File{ + Name: f.Name(), + In: f, + Out: bb, + }) + if err := gi.Run(); err != nil { + return f, errors.WithStack(err) + } + f = genny.NewFile(f.Name(), bb) + return f, nil + }) + t.StripExt = false + return t +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/get.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/get.go new file mode 100644 index 0000000000..a497df621d --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/get.go @@ -0,0 +1,25 @@ +package gotools + +import ( + "os/exec" + + "github.com/gobuffalo/genny" + "github.com/gobuffalo/genny/movinglater/gotools/gomods" +) + +func Get(pkg string, args ...string) genny.RunFn { + return func(r *genny.Runner) error { + args = append([]string{"get"}, args...) + args = append(args, pkg) + cmd := exec.Command(genny.GoBin(), args...) + return r.Exec(cmd) + } +} + +func Install(pkg string, args ...string) genny.RunFn { + return func(r *genny.Runner) error { + return gomods.Disable(func() error { + return Get(pkg, args...)(r) + }) + } +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/LICENSE b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 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. diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/README.md b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/README.md new file mode 100644 index 0000000000..2fc7513757 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/README.md @@ -0,0 +1,5 @@ +# goimports + +This package is a modified version of [https://github.com/golang/tools/tree/master/cmd/goimports](https://github.com/golang/tools/tree/master/cmd/goimports) to be called programmatically, instead of via the binary. + +Please see the `LICENSE` file details on the original license. diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/goimports.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/goimports.go new file mode 100644 index 0000000000..1c68a124e9 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/goimports/goimports.go @@ -0,0 +1,122 @@ +// Copyright 2013 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 goimports + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "golang.org/x/tools/imports" +) + +type File struct { + Name string + In io.Reader + Out io.Writer +} + +type Runner struct { + files []File +} + +func New(path ...string) (Runner, error) { + r := Runner{} + files, err := buildFiles(path...) + if err != nil { + return r, errors.WithStack(err) + } + r.files = files + return r, nil +} + +func NewFromFiles(files ...File) Runner { + return Runner{ + files: files, + } +} + +func (r Runner) Run() error { + for _, file := range r.files { + if err := r.processFile(file); err != nil { + return errors.WithStack(err) + } + } + return nil +} + +func (r Runner) processFile(file File) error { + var src []byte + var err error + if file.In == nil { + src, err = ioutil.ReadFile(file.Name) + } else { + src, err = ioutil.ReadAll(file.In) + } + if err != nil { + return errors.WithStack(err) + } + res, err := imports.Process(file.Name, src, nil) + if err != nil && err != io.EOF { + return errors.WithStack(err) + } + if bytes.Equal(src, res) { + if s, ok := file.In.(io.Seeker); ok { + s.Seek(0, 0) + } + return nil + } + if file.Out == nil { + if err = ioutil.WriteFile(file.Name, res, 0); err != nil { + return errors.WithStack(err) + } + return nil + } + _, err = file.Out.Write(res) + if c, ok := file.Out.(io.Closer); ok { + c.Close() + } + return err +} + +func isGoFile(f os.FileInfo) bool { + // ignore non-Go files + name := f.Name() + return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") +} + +func buildFiles(paths ...string) ([]File, error) { + var files []File + for _, root := range paths { + err := filepath.Walk(root, func(path string, info os.FileInfo, _ error) error { + if info == nil { + return nil + } + if info.IsDir() { + return nil + } + if !isGoFile(info) { + return nil + } + b, err := ioutil.ReadFile(path) + if err != nil { + return errors.WithStack(err) + } + files = append(files, File{ + Name: path, + In: bytes.NewReader(b), + }) + return nil + }) + if err != nil { + return files, errors.WithStack(err) + } + } + return files, nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/gomods.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/gomods.go new file mode 100644 index 0000000000..906fefea82 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/gomods.go @@ -0,0 +1,32 @@ +package gomods + +import ( + "github.com/gobuffalo/envy" + "github.com/markbates/safe" + "github.com/pkg/errors" +) + +const ENV = "GO111MODULE" + +var ErrModsOff = errors.New("go mods are turned off") + +func Force(b bool) { + if b { + envy.MustSet(ENV, "on") + return + } + envy.MustSet(ENV, "off") +} + +func On() bool { + return envy.Mods() +} + +func Disable(fn func() error) error { + oe := envy.Get(ENV, "off") + envy.MustSet(ENV, "off") + + err := safe.RunE(fn) + envy.MustSet(ENV, oe) + return err +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/init.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/init.go new file mode 100644 index 0000000000..70b7a41113 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/init.go @@ -0,0 +1,65 @@ +package gomods + +import ( + "go/build" + "os" + "os/exec" + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +func New(name string, path string) (*genny.Group, error) { + g := &genny.Group{} + + init, err := Init(name, path) + if err != nil { + return g, errors.WithStack(err) + } + g.Add(init) + + tidy, err := Tidy(path, false) + if err != nil { + return g, errors.WithStack(err) + } + g.Add(tidy) + return g, nil +} + +func Init(name string, path string) (*genny.Generator, error) { + if len(name) == 0 && len(path) == 0 { + pwd, err := os.Getwd() + if err != nil { + return nil, errors.WithStack(err) + } + path = pwd + } + + if len(name) == 0 && path != "." { + name = path + c := build.Default + for _, s := range c.SrcDirs() { + name = strings.TrimPrefix(name, s) + } + } + + name = strings.Replace(name, "\\", "/", -1) + name = strings.TrimPrefix(name, "/") + + g := genny.New() + g.RunFn(func(r *genny.Runner) error { + if !On() { + return nil + } + return r.Chdir(path, func() error { + args := []string{"mod", "init"} + if len(name) > 0 { + args = append(args, name) + } + cmd := exec.Command(genny.GoBin(), args...) + return r.Exec(cmd) + }) + }) + return g, nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/tidy.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/tidy.go new file mode 100644 index 0000000000..3c6b240fe5 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gomods/tidy.go @@ -0,0 +1,24 @@ +package gomods + +import ( + "os/exec" + + "github.com/gobuffalo/genny" +) + +func Tidy(path string, verbose bool) (*genny.Generator, error) { + g := genny.New() + g.RunFn(func(r *genny.Runner) error { + if !On() { + return nil + } + return r.Chdir(path, func() error { + cmd := exec.Command(genny.GoBin(), "mod", "tidy") + if verbose { + cmd.Args = append(cmd.Args, "-v") + } + return r.Exec(cmd) + }) + }) + return g, nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/gotools.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gotools.go new file mode 100644 index 0000000000..7174107ec9 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/gotools.go @@ -0,0 +1 @@ +package gotools diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/package.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/package.go new file mode 100644 index 0000000000..26dd7e0a50 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/package.go @@ -0,0 +1,20 @@ +package gotools + +import ( + "path/filepath" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +func PackageName(f genny.File) (string, error) { + pkg := filepath.Base(filepath.Dir(f.Name())) + pf, err := ParseFile(f) + if err == nil { + pkg = pf.Ast.Name.String() + } + if len(pkg) == 0 || pkg == "." { + return "", errors.New("could not determine package") + } + return pkg, nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/parsed_file.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/parsed_file.go new file mode 100644 index 0000000000..773237f17e --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/parsed_file.go @@ -0,0 +1,40 @@ +package gotools + +import ( + "go/ast" + "go/parser" + "go/token" + "io" + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +type ParsedFile struct { + File genny.File + FileSet *token.FileSet + Ast *ast.File + Lines []string +} + +func ParseFileMode(gf genny.File, mode parser.Mode) (ParsedFile, error) { + pf := ParsedFile{ + FileSet: token.NewFileSet(), + File: gf, + } + + src := gf.String() + f, err := parser.ParseFile(pf.FileSet, gf.Name(), src, mode) + if err != nil && errors.Cause(err) != io.EOF { + return pf, errors.WithStack(err) + } + pf.Ast = f + + pf.Lines = strings.Split(src, "\n") + return pf, nil +} + +func ParseFile(gf genny.File) (ParsedFile, error) { + return ParseFileMode(gf, 0) +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/replace_block_body.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/replace_block_body.go new file mode 100644 index 0000000000..22c21f648b --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/replace_block_body.go @@ -0,0 +1,27 @@ +package gotools + +import ( + "strings" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +// ReplaceBlockBody will replace found block with expressions passed +func ReplaceBlockBody(gf genny.File, search string, expressions ...string) (genny.File, error) { + pf, err := ParseFile(gf) + if err != nil { + return gf, errors.WithStack(err) + } + gf = pf.File + + start, end := findBlockCoordinates(search, pf) + if end < 0 { + return gf, errors.Errorf("could not find desired block in %s", gf.Name()) + } + + pf.Lines = append(pf.Lines[:start], append(expressions, pf.Lines[end:]...)...) + + fileContent := strings.Join(pf.Lines, "\n") + return genny.NewFile(gf.Name(), strings.NewReader(fileContent)), nil +} diff --git a/vendor/github.com/gobuffalo/genny/movinglater/gotools/templates.go b/vendor/github.com/gobuffalo/genny/movinglater/gotools/templates.go new file mode 100644 index 0000000000..017f283bdb --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/movinglater/gotools/templates.go @@ -0,0 +1,52 @@ +package gotools + +import ( + "bytes" + "io/ioutil" + + "text/template" + + "github.com/gobuffalo/genny" + "github.com/pkg/errors" +) + +var TemplateHelpers = map[string]interface{}{} + +// TemplateTransformer will run any file that has a ".tmpl" extension through text/template +func TemplateTransformer(data interface{}, helpers map[string]interface{}) genny.Transformer { + if helpers == nil { + helpers = TemplateHelpers + } + t := genny.NewTransformer(".tmpl", func(f genny.File) (genny.File, error) { + return renderWithTemplate(f, data, helpers) + }) + t.StripExt = true + return t +} + +func renderWithTemplate(f genny.File, data interface{}, helpers template.FuncMap) (genny.File, error) { + if f == nil { + return f, errors.New("file was nil") + } + path := f.Name() + t := template.New(path) + if helpers != nil { + t = t.Funcs(helpers) + } + + b, err := ioutil.ReadAll(f) + if err != nil { + return f, errors.WithStack(err) + } + t, err = t.Parse(string(b)) + if err != nil { + return f, errors.WithStack(err) + } + + var bb bytes.Buffer + if err = t.Execute(&bb, data); err != nil { + err = errors.WithStack(err) + return f, errors.WithStack(err) + } + return genny.StripExt(genny.NewFile(path, &bb), ".tmpl"), nil +} diff --git a/vendor/github.com/gobuffalo/genny/replacer.go b/vendor/github.com/gobuffalo/genny/replacer.go new file mode 100644 index 0000000000..3866071893 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/replacer.go @@ -0,0 +1,20 @@ +package genny + +import ( + "strings" +) + +// Replace search/replace in a file name +func Replace(search string, replace string) Transformer { + return NewTransformer("*", func(f File) (File, error) { + name := f.Name() + name = strings.Replace(name, search, replace, -1) + return NewFile(name, f), nil + }) +} + +// Dot will convert -dot- in a file name to just a . +// example -dot-travis.yml becomes .travis.yml +func Dot() Transformer { + return Replace("-dot-", ".") +} diff --git a/vendor/github.com/gobuffalo/genny/results.go b/vendor/github.com/gobuffalo/genny/results.go new file mode 100644 index 0000000000..a1a3df3e97 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/results.go @@ -0,0 +1,30 @@ +package genny + +import ( + "net/http" + "os/exec" + + "github.com/pkg/errors" +) + +type Results struct { + Files []File + Commands []*exec.Cmd + Requests []RequestResult +} + +func (r Results) Find(s string) (File, error) { + for _, f := range r.Files { + if s == f.Name() { + return f, nil + } + } + return nil, errors.Errorf("%s not found", s) +} + +type RequestResult struct { + Request *http.Request + Response *http.Response + Client *http.Client + Error error +} diff --git a/vendor/github.com/gobuffalo/genny/runner.go b/vendor/github.com/gobuffalo/genny/runner.go new file mode 100644 index 0000000000..8da9a46905 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/runner.go @@ -0,0 +1,326 @@ +package genny + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + "sync" + + "github.com/gobuffalo/events" + "github.com/markbates/oncer" + "github.com/markbates/safe" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +type RunFn func(r *Runner) error + +// Runner will run the generators +type Runner struct { + Logger Logger // Logger to use for the run + Context context.Context // context to use for the run + ExecFn func(*exec.Cmd) error // function to use when executing files + FileFn func(File) (File, error) // function to use when writing files + ChdirFn func(string, func() error) error // function to use when changing directories + DeleteFn func(string) error // function used to delete files/folders + RequestFn func(*http.Request, *http.Client) (*http.Response, error) // function used to make http requests + LookPathFn func(string) (string, error) // function used to make exec.LookPath lookups + Root string // the root of the write path + Disk *Disk + steps map[string]*Step + generators []*Generator + moot *sync.RWMutex + results Results + curGen *Generator +} + +func (r *Runner) Results() Results { + r.moot.Lock() + defer r.moot.Unlock() + r.results.Files = r.Disk.Files() + return r.results +} + +func (r *Runner) WithRun(fn RunFn) { + g := New() + g.RunFn(fn) + r.With(g) +} + +// With adds a Generator to the Runner +func (r *Runner) With(g *Generator) error { + r.moot.Lock() + step, ok := r.steps[g.StepName] + if !ok { + var err error + step, err = NewStep(g, len(r.steps)) + if err != nil { + return errors.WithStack(err) + } + } + r.moot.Unlock() + return r.WithStep(g.StepName, step) +} + +func (r *Runner) WithGroup(gg *Group) { + for _, g := range gg.Generators { + r.With(g) + } +} + +// WithNew takes a Generator and an error. +// Perfect for new-ing up generators +/* + // foo.New(Options) (*genny.Generator, error) + if err := run.WithNew(foo.New(opts)); err != nil { + return err + } +*/ +func (r *Runner) WithNew(g *Generator, err error) error { + if err != nil { + return errors.WithStack(err) + } + r.With(g) + return nil +} + +// WithFn will evaluate the function and if successful it will add +// the Generator to the Runner, otherwise it will return the error +// Deprecated +func (r *Runner) WithFn(fn func() (*Generator, error)) error { + oncer.Deprecate(5, "genny.Runner#WithFn", "") + return safe.RunE(func() error { + g, err := fn() + if err != nil { + return errors.WithStack(err) + } + r.With(g) + return nil + }) +} + +func (r *Runner) WithStep(name string, step *Step) error { + r.moot.Lock() + defer r.moot.Unlock() + if len(name) == 0 { + name = stepName() + } + r.steps[name] = step + return nil +} + +func (r *Runner) Steps() []*Step { + r.moot.RLock() + + var steps []*Step + + for _, step := range r.steps { + steps = append(steps, step) + } + + sort.Slice(steps, func(a, b int) bool { + return steps[a].index < steps[b].index + }) + + r.moot.RUnlock() + return steps +} + +func (r *Runner) FindStep(name string) (*Step, error) { + r.moot.RLock() + s, ok := r.steps[name] + r.moot.RUnlock() + if !ok { + return nil, errors.Errorf("could not find step %s", name) + } + return s, nil +} + +func (r *Runner) Run() error { + if f, ok := r.Logger.(io.Closer); ok { + defer f.Close() + } + steps := r.Steps() + + payload := events.Payload{ + "runner": r, + "steps": steps, + } + + events.EmitPayload(EvtStarted, payload) + + for _, step := range steps { + if err := step.Run(r); err != nil { + payload = events.Payload{ + "runner": r, + "step": step, + } + events.EmitError(EvtFinishedErr, err, payload) + return errors.WithStack(err) + } + } + events.EmitPayload(EvtFinished, payload) + + return nil +} + +// Exec can be used inside of Generators to run commands +func (r *Runner) Exec(cmd *exec.Cmd) error { + r.results.Commands = append(r.results.Commands, cmd) + r.Logger.Debug("Exec: ", strings.Join(cmd.Args, " ")) + if r.ExecFn == nil { + return nil + } + return safe.RunE(func() error { + return r.ExecFn(cmd) + }) +} + +func (r *Runner) LookPath(s string) (string, error) { + r.Logger.Debug("LookPath: ", s) + if r.LookPathFn != nil { + return r.LookPathFn(s) + } + return s, nil +} + +// File can be used inside of Generators to write files +func (r *Runner) File(f File) error { + if r.curGen != nil { + var err error + f, err = r.curGen.Transform(f) + if err != nil { + return errors.WithStack(err) + } + } + name := f.Name() + if !filepath.IsAbs(name) { + name = filepath.Join(r.Root, name) + } + + _, isDir := f.(Dir) + if isDir { + r.Logger.Debug("Dir: ", name) + } else { + r.Logger.Debug("File: ", name) + } + + if r.FileFn != nil { + err := safe.RunE(func() error { + var e error + if f, e = r.FileFn(f); e != nil { + return errors.WithStack(e) + } + if s, ok := f.(io.Seeker); ok { + s.Seek(0, 0) + } + return nil + }) + if err != nil { + return errors.WithStack(err) + } + } + f = NewFile(f.Name(), f) + if s, ok := f.(io.Seeker); ok { + s.Seek(0, 0) + } + r.Disk.Add(f) + return nil +} + +func (r *Runner) FindFile(name string) (File, error) { + return r.Disk.Find(name) +} + +// Chdir will change to the specified directory +// and revert back to the current directory when +// the runner function has returned. +// If the directory does not exist, it will be +// created for you. +func (r *Runner) Chdir(path string, fn func() error) error { + if len(path) == 0 { + return fn() + } + r.Logger.Debug("Chdir: ", path) + + if r.ChdirFn != nil { + return safe.RunE(func() error { + return r.ChdirFn(path, fn) + }) + } + + if err := safe.RunE(fn); err != nil { + return errors.WithStack(err) + } + return nil +} + +func (r *Runner) Delete(path string) error { + r.Logger.Debug("Delete: ", path) + + defer r.Disk.Remove(path) + if r.DeleteFn != nil { + return safe.RunE(func() error { + return r.DeleteFn(path) + }) + } + return nil +} + +func (r *Runner) Request(req *http.Request) (*http.Response, error) { + return r.RequestWithClient(req, http.DefaultClient) +} + +func (r *Runner) RequestWithClient(req *http.Request, c *http.Client) (*http.Response, error) { + key := fmt.Sprintf("[%s] %s\n", strings.ToUpper(req.Method), req.URL) + r.Logger.Debug("Request: ", key) + store := func(res *http.Response, err error) (*http.Response, error) { + r.moot.Lock() + r.results.Requests = append(r.results.Requests, RequestResult{ + Request: req, + Response: res, + Client: c, + Error: err, + }) + r.moot.Unlock() + return res, err + } + if r.RequestFn == nil { + return store(nil, nil) + } + var res *http.Response + err := safe.RunE(func() error { + var e error + res, e = r.RequestFn(req, c) + if e != nil { + return errors.WithStack(e) + } + return nil + }) + return store(res, err) +} + +// NewRunner will NOT execute commands and write files +// it is NOT destructive it is just the most basic Runner +// you can have. +func NewRunner(ctx context.Context) *Runner { + pwd, _ := os.Getwd() + l := logrus.New() + l.Out = os.Stdout + l.SetLevel(logrus.DebugLevel) + r := &Runner{ + Logger: l, + Context: ctx, + Root: pwd, + moot: &sync.RWMutex{}, + steps: map[string]*Step{}, + } + r.Disk = newDisk(r) + return r +} diff --git a/vendor/github.com/gobuffalo/genny/step.go b/vendor/github.com/gobuffalo/genny/step.go new file mode 100644 index 0000000000..49f56b280a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/step.go @@ -0,0 +1,146 @@ +package genny + +import ( + "bytes" + "crypto/sha1" + "fmt" + "io" + "math/rand" + "strconv" + "sync" + "time" + + "github.com/gobuffalo/events" + "github.com/markbates/safe" + "github.com/pkg/errors" +) + +type DeleteFn func() + +type Step struct { + as *Generator + before []*Generator + after []*Generator + index int + moot *sync.RWMutex +} + +func (s *Step) Before(g *Generator) DeleteFn { + df := func() { + var a []*Generator + s.moot.Lock() + for _, b := range s.before { + if g.StepName == b.StepName { + continue + } + a = append(a, b) + } + s.before = a + s.moot.Unlock() + } + s.moot.Lock() + s.before = append(s.before, g) + s.moot.Unlock() + return df +} + +func (s *Step) After(g *Generator) DeleteFn { + df := func() { + var a []*Generator + s.moot.Lock() + for _, b := range s.after { + if g.StepName == b.StepName { + continue + } + a = append(a, b) + } + s.after = a + s.moot.Unlock() + } + s.moot.Lock() + s.after = append(s.after, g) + s.moot.Unlock() + return df +} + +func (s *Step) Run(r *Runner) error { + for _, b := range s.before { + if err := s.runGenerator(r, b); err != nil { + return errors.WithStack(err) + } + } + + if err := s.runGenerator(r, s.as); err != nil { + return errors.WithStack(err) + } + + for _, b := range s.after { + if err := s.runGenerator(r, b); err != nil { + return errors.WithStack(err) + } + } + + return nil +} + +func (s *Step) runGenerator(r *Runner, g *Generator) error { + r.curGen = g + + payload := events.Payload{ + "runner": r, + "step": s, + "generator": g, + } + if g.Should != nil { + err := safe.RunE(func() error { + if !g.Should(r) { + return io.EOF + } + return nil + }) + if err != nil { + r.Logger.Debugf("Step: %s [skipped]", g.StepName) + events.EmitPayload(EvtStepPrefix+":skipping:"+g.StepName, payload) + return nil + } + } + r.Logger.Debugf("Step: %s", g.StepName) + events.EmitPayload(EvtStepPrefix+":running:"+g.StepName, payload) + return r.Chdir(r.Root, func() error { + for _, fn := range g.runners { + err := safe.RunE(func() error { + return fn(r) + }) + if err != nil { + events.EmitError(EvtStepPrefix+":running:"+g.StepName+":err", err, payload) + return errors.WithStack(err) + } + } + return nil + }) +} + +func NewStep(g *Generator, index int) (*Step, error) { + if g == nil { + return nil, errors.New("generator can not be nil") + } + return &Step{ + as: g, + index: index, + moot: &sync.RWMutex{}, + }, nil +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func stepName() string { + bb := &bytes.Buffer{} + bb.WriteString(fmt.Sprint(time.Now().UnixNano())) + bb.WriteString(strconv.Itoa(rand.Int())) + bb.WriteString(strconv.Itoa(rand.Int())) + h := sha1.New() + h.Write(bb.Bytes()) + return fmt.Sprintf("%x", h.Sum(nil))[:8] +} diff --git a/vendor/github.com/gobuffalo/genny/transformer.go b/vendor/github.com/gobuffalo/genny/transformer.go new file mode 100644 index 0000000000..29c7fe1814 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/transformer.go @@ -0,0 +1,45 @@ +package genny + +import ( + "github.com/markbates/safe" + "github.com/pkg/errors" +) + +type TransformerFn func(File) (File, error) + +type Transformer struct { + Ext string + StripExt bool + fn TransformerFn +} + +func (t Transformer) Transform(f File) (File, error) { + if !HasExt(f, t.Ext) { + return f, nil + } + if t.fn == nil { + return f, nil + } + err := safe.RunE(func() error { + var e error + f, e = t.fn(f) + if e != nil { + return errors.WithStack(e) + } + return nil + }) + if err != nil { + return f, errors.WithStack(err) + } + if t.StripExt { + return StripExt(f, t.Ext), nil + } + return f, nil +} + +func NewTransformer(ext string, fn TransformerFn) Transformer { + return Transformer{ + Ext: ext, + fn: fn, + } +} diff --git a/vendor/github.com/gobuffalo/genny/version.go b/vendor/github.com/gobuffalo/genny/version.go new file mode 100644 index 0000000000..103c8c9f7a --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/version.go @@ -0,0 +1,3 @@ +package genny + +const Version = "v0.0.1" diff --git a/vendor/github.com/gobuffalo/genny/wet_runner.go b/vendor/github.com/gobuffalo/genny/wet_runner.go new file mode 100644 index 0000000000..6b4a87d227 --- /dev/null +++ b/vendor/github.com/gobuffalo/genny/wet_runner.go @@ -0,0 +1,99 @@ +package genny + +import ( + "context" + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + "time" + + "github.com/gobuffalo/logger" + "github.com/pkg/errors" +) + +// WetRunner will execute commands and write files +// it is DESTRUCTIVE +func WetRunner(ctx context.Context) *Runner { + r := DryRunner(ctx) + l := logger.New(DefaultLogLvl) + r.Logger = l + + r.ExecFn = wetExecFn + r.FileFn = func(f File) (File, error) { + return wetFileFn(r, f) + } + r.DeleteFn = os.RemoveAll + r.RequestFn = wetRequestFn + r.ChdirFn = func(path string, fn func() error) error { + pwd, _ := os.Getwd() + defer os.Chdir(pwd) + os.MkdirAll(path, 0755) + if err := os.Chdir(path); err != nil { + return errors.WithStack(err) + } + return fn() + } + r.LookPathFn = exec.LookPath + return r +} + +func wetRequestFn(req *http.Request, c *http.Client) (*http.Response, error) { + if c == nil { + c = &http.Client{} + } + ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) + defer cancel() + req = req.WithContext(ctx) + + res, err := c.Do(req) + if err != nil { + return res, errors.WithStack(err) + } + + if res.StatusCode >= 400 { + return res, errors.WithStack(errors.Errorf("response returned non-success code: %d", res.StatusCode)) + } + return res, nil +} + +func wetExecFn(cmd *exec.Cmd) error { + if cmd.Stdin == nil { + cmd.Stdin = os.Stdin + } + if cmd.Stdout == nil { + cmd.Stdout = os.Stdout + } + if cmd.Stderr == nil { + cmd.Stderr = os.Stderr + } + return cmd.Run() +} + +func wetFileFn(r *Runner, f File) (File, error) { + if d, ok := f.(Dir); ok { + if err := os.MkdirAll(d.Name(), d.Perm); err != nil { + return f, errors.WithStack(err) + } + return d, nil + } + + name := f.Name() + if !filepath.IsAbs(name) { + name = filepath.Join(r.Root, name) + } + dir := filepath.Dir(name) + if err := os.MkdirAll(dir, 0755); err != nil { + return f, errors.WithStack(err) + } + ff, err := os.Create(name) + if err != nil { + return f, errors.WithStack(err) + } + defer ff.Close() + if _, err := io.Copy(ff, f); err != nil { + return f, errors.WithStack(err) + } + return f, nil +} diff --git a/vendor/github.com/gobuffalo/logger/.gitignore b/vendor/github.com/gobuffalo/logger/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/logger/.gometalinter.json b/vendor/github.com/gobuffalo/logger/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/logger/.travis.yml b/vendor/github.com/gobuffalo/logger/.travis.yml new file mode 100644 index 0000000000..1fb041a259 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/.travis.yml @@ -0,0 +1,36 @@ +language: go + +sudo: false + +matrix: + include: + - os: linux + go: "1.9.x" + - os: windows + go: "1.9.x" + - os: linux + go: "1.10.x" + - os: windows + go: "1.10.x" + - os: linux + go: "1.11.x" + env: + - GO111MODULE=off + - os: windows + go: "1.11.x" + env: + - GO111MODULE=off + - os: linux + go: "1.11.x" + env: + - GO111MODULE=on + - os: windows + go: "1.11.x" + env: + - GO111MODULE=on + +install: false + +script: + - go get -v -t ./... + - go test -v -timeout=5s -race ./... diff --git a/vendor/github.com/gobuffalo/logger/LICENSE b/vendor/github.com/gobuffalo/logger/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/logger/Makefile b/vendor/github.com/gobuffalo/logger/Makefile new file mode 100644 index 0000000000..e0e2f3baa4 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/Makefile @@ -0,0 +1,55 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -tags ${TAGS} -v . + make tidy + +tidy: +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +else + echo skipping go mod tidy +endif + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... + make tidy + +build: + packr + $(GO_BIN) build -v . + make tidy + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + make tidy + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + make tidy + +update: + $(GO_BIN) get -u -tags ${TAGS} + make tidy + packr + make test + make install + make tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +release: + make tidy + release -y -f version.go + make tidy diff --git a/vendor/github.com/gobuffalo/logger/README.md b/vendor/github.com/gobuffalo/logger/README.md new file mode 100644 index 0000000000..15aefce982 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/README.md @@ -0,0 +1,22 @@ +

+ +

+GoDoc +Build Status +Go Report Card +

+ +# Logger + +The [`logger.Logger`](https://godoc.org/github.com/gobuffalo/logger#Logger) interface is used throughout Buffalo apps, and other systems, to log a whole manner of things. + +## Installation + +```bash +$ go get -u github.com/gobuffalo/logger +``` + +## Documentation + +* [GoDoc](https://godoc.org/github.com/gobuffalo/logger) +* [General Buffalo Documentation](https://gobuffalo.io) diff --git a/vendor/github.com/gobuffalo/logger/formatter.go b/vendor/github.com/gobuffalo/logger/formatter.go new file mode 100644 index 0000000000..cb173d77ec --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/formatter.go @@ -0,0 +1,153 @@ +package logger + +// I really don't want to have this, but until (if) https://github.com/sirupsen/logrus/pull/606 is merged we're stuck with all this code. And yes, this is ALL needed just to remove some blank space in the logs + +import ( + "bytes" + "fmt" + "sort" + "strings" + "sync" + "time" + + "github.com/sirupsen/logrus" +) + +const ( + red = 31 + yellow = 33 + blue = 36 + gray = 37 +) + +// textFormatter formats logs into text +type textFormatter struct { + ForceColors bool + isTerminal bool + sync.Once +} + +func (f *textFormatter) init(entry *logrus.Entry) { + if entry.Logger != nil { + f.isTerminal = checkIfTerminal(entry.Logger.Out) + } +} + +const defaultTimestampFormat = time.RFC3339 + +// Format renders a single log entry +func (f *textFormatter) Format(entry *logrus.Entry) ([]byte, error) { + prefixFieldClashes(entry.Data) + + keys := make([]string, 0, len(entry.Data)) + for k := range entry.Data { + keys = append(keys, k) + } + + sort.Strings(keys) + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + f.Do(func() { f.init(entry) }) + + isColored := (f.ForceColors || f.isTerminal) + + if isColored { + f.printColored(b, entry, keys) + } else { + f.appendKeyValue(b, "level", entry.Level.String()) + if entry.Message != "" { + f.appendKeyValue(b, "msg", entry.Message) + } + for _, key := range keys { + f.appendKeyValue(b, key, entry.Data[key]) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *textFormatter) printColored(b *bytes.Buffer, entry *logrus.Entry, keys []string) { + var levelColor int + switch entry.Level { + case logrus.DebugLevel: + levelColor = gray + case logrus.WarnLevel: + levelColor = yellow + case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String())[0:4] + + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]", levelColor, levelText, entry.Time.Format(defaultTimestampFormat)) + + if entry.Message != "" { + fmt.Fprintf(b, " %s", entry.Message) + } + + for _, k := range keys { + v := entry.Data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *textFormatter) needsQuoting(text string) bool { + if len(text) == 0 { + return true + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { + return true + } + } + return false +} + +func (f *textFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) +} + +func (f *textFormatter) appendValue(b *bytes.Buffer, value interface{}) { + stringVal, ok := value.(string) + if !ok { + stringVal = fmt.Sprint(value) + } + + if !f.needsQuoting(stringVal) { + b.WriteString(stringVal) + } else { + b.WriteString(fmt.Sprintf("%q", stringVal)) + } +} + +func prefixFieldClashes(data logrus.Fields) { + if t, ok := data["time"]; ok { + data["fields.time"] = t + } + + if m, ok := data["msg"]; ok { + data["fields.msg"] = m + } + + if l, ok := data["level"]; ok { + data["fields.level"] = l + } +} diff --git a/vendor/github.com/gobuffalo/logger/level.go b/vendor/github.com/gobuffalo/logger/level.go new file mode 100644 index 0000000000..0c9199a7a9 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/level.go @@ -0,0 +1,25 @@ +package logger + +import "github.com/sirupsen/logrus" + +// Level of the logger +type Level = logrus.Level + +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel = logrus.PanicLevel + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel = logrus.FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel = logrus.ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel = logrus.WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel = logrus.InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel = logrus.DebugLevel +) diff --git a/vendor/github.com/gobuffalo/logger/logger.go b/vendor/github.com/gobuffalo/logger/logger.go new file mode 100644 index 0000000000..ad7d1f8e80 --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/logger.go @@ -0,0 +1,64 @@ +package logger + +import ( + "os" + + "github.com/gobuffalo/envy" + "github.com/sirupsen/logrus" +) + +// FieldLogger interface +type FieldLogger interface { + Logger + WithField(string, interface{}) FieldLogger + WithFields(map[string]interface{}) FieldLogger +} + +// Logger interface is used throughout Buffalo +// apps to log a whole manner of things. +type Logger interface { + Debugf(string, ...interface{}) + Infof(string, ...interface{}) + Printf(string, ...interface{}) + Warnf(string, ...interface{}) + Errorf(string, ...interface{}) + Fatalf(string, ...interface{}) + Debug(...interface{}) + Info(...interface{}) + Warn(...interface{}) + Error(...interface{}) + Fatal(...interface{}) + Panic(...interface{}) +} + +func ParseLevel(level string) (Level, error) { + l, err := logrus.ParseLevel(level) + return Level(l), err +} + +// NewLogger based on the specified log level, defaults to "debug". +// See `New` for more details. +func NewLogger(level string) FieldLogger { + lvl, err := logrus.ParseLevel(level) + if err != nil { + lvl = logrus.DebugLevel + } + return New(lvl) +} + +// New based on the specified log level, defaults to "debug". +// This logger will log to the STDOUT in a human readable, +// but parseable form. +/* + Example: time="2016-12-01T21:02:07-05:00" level=info duration=225.283µs human_size="106 B" method=GET path="/" render=199.79µs request_id=2265736089 size=106 status=200 +*/ +func New(lvl Level) FieldLogger { + dev := envy.Get("GO_ENV", "development") == "development" + l := logrus.New() + l.SetOutput(os.Stdout) + l.Level = lvl + l.Formatter = &textFormatter{ + ForceColors: dev, + } + return Logrus{l} +} diff --git a/vendor/github.com/gobuffalo/logger/logrus.go b/vendor/github.com/gobuffalo/logger/logrus.go new file mode 100644 index 0000000000..bf13148edb --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/logrus.go @@ -0,0 +1,34 @@ +package logger + +import ( + "io" + + "github.com/sirupsen/logrus" +) + +var _ Logger = Logrus{} +var _ FieldLogger = Logrus{} +var _ Outable = Logrus{} + +// Logrus is a Logger implementation backed by sirupsen/logrus +type Logrus struct { + logrus.FieldLogger +} + +// SetOutput will try and set the output of the underlying +// logrus.FieldLogger if it can +func (l Logrus) SetOutput(w io.Writer) { + if lg, ok := l.FieldLogger.(Outable); ok { + lg.SetOutput(w) + } +} + +// WithField returns a new Logger with the field added +func (l Logrus) WithField(s string, i interface{}) FieldLogger { + return Logrus{l.FieldLogger.WithField(s, i)} +} + +// WithFields returns a new Logger with the fields added +func (l Logrus) WithFields(m map[string]interface{}) FieldLogger { + return Logrus{l.FieldLogger.WithFields(m)} +} diff --git a/vendor/github.com/gobuffalo/logger/outable.go b/vendor/github.com/gobuffalo/logger/outable.go new file mode 100644 index 0000000000..459fe1972b --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/outable.go @@ -0,0 +1,8 @@ +package logger + +import "io" + +// Outable interface for loggers that allow setting the output writer +type Outable interface { + SetOutput(out io.Writer) +} diff --git a/vendor/github.com/gobuffalo/logger/terminal_check.go b/vendor/github.com/gobuffalo/logger/terminal_check.go new file mode 100644 index 0000000000..f7ec282c8c --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/terminal_check.go @@ -0,0 +1,19 @@ +// +build !appengine + +package logger + +import ( + "io" + "os" + + "golang.org/x/crypto/ssh/terminal" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return terminal.IsTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/vendor/github.com/gobuffalo/logger/terminal_check_appengine.go b/vendor/github.com/gobuffalo/logger/terminal_check_appengine.go new file mode 100644 index 0000000000..fe84f0b89b --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/terminal_check_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package logger + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/vendor/github.com/gobuffalo/logger/version.go b/vendor/github.com/gobuffalo/logger/version.go new file mode 100644 index 0000000000..40b8bf87ac --- /dev/null +++ b/vendor/github.com/gobuffalo/logger/version.go @@ -0,0 +1,4 @@ +package logger + +// Version of the logger +const Version = "v0.0.1" diff --git a/vendor/github.com/gobuffalo/mapi/.gitignore b/vendor/github.com/gobuffalo/mapi/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/mapi/.gometalinter.json b/vendor/github.com/gobuffalo/mapi/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/mapi/LICENSE b/vendor/github.com/gobuffalo/mapi/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/mapi/Makefile b/vendor/github.com/gobuffalo/mapi/Makefile new file mode 100644 index 0000000000..187cb8a3f3 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/Makefile @@ -0,0 +1,40 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -v . + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... + $(GO_BIN) mod tidy + +build: + packr + $(GO_BIN) build -v . + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + +ci-test: deps + $(GO_BIN) test -tags ${TAGS} -race ./... + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + +update: + $(GO_BIN) get -u -tags ${TAGS} + $(GO_BIN) mod tidy + packr + make test + make install + $(GO_BIN) mod tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +release: + release -y -f version.go diff --git a/vendor/github.com/gobuffalo/mapi/mapi.go b/vendor/github.com/gobuffalo/mapi/mapi.go new file mode 100644 index 0000000000..21de16a3ab --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/mapi.go @@ -0,0 +1,109 @@ +package mapi + +import ( + "encoding/json" + "reflect" + "strings" + + "github.com/pkg/errors" +) + +var ErrNotFound = errors.New("not found") + +type Mapi map[string]interface{} + +func (mi Mapi) String() string { + b, _ := mi.MarshalJSON() + return string(b) +} + +func (mi Mapi) Interface() interface{} { + return mi +} + +func (mi Mapi) Pluck(s string) (interface{}, error) { + keys := strings.Split(s, ":") + return reduce(keys, mi) +} + +func (mi *Mapi) UnmarshalJSON(b []byte) error { + mm := map[string]interface{}{} + if err := json.Unmarshal(b, &mm); err != nil { + return errors.WithStack(err) + } + unmarshal(mm) + (*mi) = Mapi(mm) + return nil +} + +func unmarshal(m map[string]interface{}) { + for k, v := range m { + if mv, ok := v.(map[string]interface{}); ok { + unmarshal(mv) + m[k] = Mapi(mv) + } + } +} + +func (mi Mapi) MarshalJSON() ([]byte, error) { + m := map[string]interface{}{} + + for k, v := range mi { + rv := reflect.Indirect(reflect.ValueOf(v)) + switch rv.Kind() { + case reflect.Map: + mm := Mapi{} + for _, xk := range rv.MapKeys() { + mm[xk.String()] = rv.MapIndex(xk).Interface() + } + m[k] = mm + default: + if _, ok := v.(Mapi); ok { + continue + } + if _, err := json.Marshal(v); err == nil { + // if it can be marshaled, add it to the map + m[k] = v + } + } + } + return json.Marshal(m) +} + +func reduce(keys []string, in interface{}) (interface{}, error) { + if len(keys) == 0 { + return nil, ErrNotFound + } + + rv := reflect.Indirect(reflect.ValueOf(in)) + if !rv.IsValid() { + return nil, ErrNotFound + } + if rv.Kind() != reflect.Map { + return nil, ErrNotFound + } + + var key reflect.Value + for _, k := range rv.MapKeys() { + if k.String() == keys[0] { + key = k + break + } + } + if !key.IsValid() { + return nil, ErrNotFound + } + + keys = keys[1:] + iv := rv.MapIndex(key) + + if !iv.IsValid() { + return nil, ErrNotFound + } + + if len(keys) == 0 { + return iv.Interface(), nil + } + + return reduce(keys, iv.Interface()) +} diff --git a/vendor/github.com/gobuffalo/mapi/shoulders.md b/vendor/github.com/gobuffalo/mapi/shoulders.md new file mode 100644 index 0000000000..47f65e8e03 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/shoulders.md @@ -0,0 +1,10 @@ +# github.com/gobuffalo/mapi Stands on the Shoulders of Giants + +github.com/gobuffalo/mapi 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**: + + +* [github.com/gobuffalo/mapi](https://godoc.org/github.com/gobuffalo/mapi) + +* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors) diff --git a/vendor/github.com/gobuffalo/mapi/version.go b/vendor/github.com/gobuffalo/mapi/version.go new file mode 100644 index 0000000000..5af0dd14a3 --- /dev/null +++ b/vendor/github.com/gobuffalo/mapi/version.go @@ -0,0 +1,3 @@ +package mapi + +const Version = "v1.0.1" diff --git a/vendor/github.com/gobuffalo/meta/.gitignore b/vendor/github.com/gobuffalo/meta/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/gobuffalo/meta/.gometalinter.json b/vendor/github.com/gobuffalo/meta/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/gobuffalo/meta/.travis.yml b/vendor/github.com/gobuffalo/meta/.travis.yml new file mode 100644 index 0000000000..1fb041a259 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/.travis.yml @@ -0,0 +1,36 @@ +language: go + +sudo: false + +matrix: + include: + - os: linux + go: "1.9.x" + - os: windows + go: "1.9.x" + - os: linux + go: "1.10.x" + - os: windows + go: "1.10.x" + - os: linux + go: "1.11.x" + env: + - GO111MODULE=off + - os: windows + go: "1.11.x" + env: + - GO111MODULE=off + - os: linux + go: "1.11.x" + env: + - GO111MODULE=on + - os: windows + go: "1.11.x" + env: + - GO111MODULE=on + +install: false + +script: + - go get -v -t ./... + - go test -v -timeout=5s -race ./... diff --git a/vendor/github.com/gobuffalo/meta/LICENSE b/vendor/github.com/gobuffalo/meta/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/gobuffalo/meta/Makefile b/vendor/github.com/gobuffalo/meta/Makefile new file mode 100644 index 0000000000..fee1bee001 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/Makefile @@ -0,0 +1,46 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: deps + packr + $(GO_BIN) install -tags ${TAGS} -v . + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + +build: + packr + $(GO_BIN) build -v . + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + +update: + $(GO_BIN) get -u -tags ${TAGS} +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + packr + make test + make install +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +endif + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +release: + release -y -f version.go diff --git a/vendor/github.com/gobuffalo/meta/SHOULDERS.md b/vendor/github.com/gobuffalo/meta/SHOULDERS.md new file mode 100644 index 0000000000..97639fee99 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/SHOULDERS.md @@ -0,0 +1,20 @@ +# `github.com/gobuffalo/meta` Stands on the Shoulders of Giants + +`github.com/gobuffalo/meta` 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**: + + +* [github.com/BurntSushi/toml](https://godoc.org/github.com/BurntSushi/toml) + +* [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy) + +* [github.com/gobuffalo/flect](https://godoc.org/github.com/gobuffalo/flect) + +* [github.com/gobuffalo/flect/name](https://godoc.org/github.com/gobuffalo/flect/name) + +* [github.com/gobuffalo/meta](https://godoc.org/github.com/gobuffalo/meta) + +* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv) + +* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors) diff --git a/vendor/github.com/gobuffalo/meta/app.go b/vendor/github.com/gobuffalo/meta/app.go new file mode 100644 index 0000000000..718e0d0a40 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/app.go @@ -0,0 +1,160 @@ +package meta + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + + "github.com/BurntSushi/toml" + "github.com/gobuffalo/envy" + "github.com/gobuffalo/flect/name" + "github.com/markbates/oncer" + "github.com/pkg/errors" +) + +// App represents meta data for a Buffalo application on disk +type App struct { + Pwd string `json:"pwd" toml:"-"` + Root string `json:"root" toml:"-"` + GoPath string `json:"go_path" toml:"-"` + PackagePkg string `json:"package_path" toml:"-"` + ActionsPkg string `json:"actions_path" toml:"-"` + ModelsPkg string `json:"models_path" toml:"-"` + GriftsPkg string `json:"grifts_path" toml:"-"` + WithModules bool `json:"with_modules" toml:"-"` + Name name.Ident `json:"name" toml:"name"` + Bin string `json:"bin" toml:"bin"` + VCS string `json:"vcs" toml:"vcs"` + WithPop bool `json:"with_pop" toml:"with_pop"` + WithSQLite bool `json:"with_sqlite" toml:"with_sqlite"` + WithDep bool `json:"with_dep" toml:"with_dep"` + WithWebpack bool `json:"with_webpack" toml:"with_webpack"` + WithNodeJs bool `json:"with_nodejs" toml:"with_nodejs"` + WithYarn bool `json:"with_yarn" toml:"with_yarn"` + WithDocker bool `json:"with_docker" toml:"with_docker"` + WithGrifts bool `json:"with_grifts" toml:"with_grifts"` + AsWeb bool `json:"as_web" toml:"as_web"` + AsAPI bool `json:"as_api" toml:"as_api"` + packageJSON packageJSON +} + +func (a App) IsZero() bool { + return a.String() == App{}.String() +} + +func resolvePackageName(name string, pwd string) string { + result := envy.CurrentPackage() + + if filepath.Base(result) != name { + result = path.Join(result, name) + } + if envy.Mods() { + //Extract package from go.mod + p := filepath.Join(pwd, "go.mod") + if f, err := os.Open(p); err == nil { + if s, err := ioutil.ReadAll(f); err == nil { + re := regexp.MustCompile("module (.*)") + res := re.FindAllStringSubmatch(string(s), 1) + + if len(res) == 1 && len(res[0]) == 2 { + return res[0][1] + } + result = filepath.Base(pwd) + } + } + } + + return result +} + +// ResolveSymlinks takes a path and gets the pointed path +// if the original one is a symlink. +func ResolveSymlinks(p string) string { + cd, err := os.Lstat(p) + if err != nil { + return p + } + if cd.Mode()&os.ModeSymlink != 0 { + // This is a symlink + r, err := filepath.EvalSymlinks(p) + if err != nil { + return p + } + return r + } + return p +} + +func (a App) String() string { + b, _ := json.Marshal(a) + return string(b) +} + +// Encode the list of plugins, in TOML format, to the reader +func (a App) Encode(w io.Writer) error { + if err := toml.NewEncoder(w).Encode(a); err != nil { + return errors.WithStack(err) + } + return nil +} + +// Decode the list of plugins, in TOML format, from the reader +func (a *App) Decode(r io.Reader) error { + xa := New(".") + if _, err := toml.DecodeReader(r, &xa); err != nil { + return errors.WithStack(err) + } + (*a) = xa + return nil +} + +// PackageRoot sets the root package of the application and +// recalculates package related values +func (a *App) PackageRoot(pp string) { + a.PackagePkg = pp + a.ActionsPkg = pp + "/actions" + a.ModelsPkg = pp + "/models" + a.GriftsPkg = pp + "/grifts" +} + +type packageJSON struct { + Scripts map[string]string `json:"scripts"` +} + +// NodeScript gets the "scripts" section from package.json and +// returns the matching script if it exists. +func (a App) NodeScript(name string) (string, error) { + if !a.WithNodeJs { + return "", errors.New("package.json not found") + } + var err error + oncer.Do("meta.NodeScript", func() { + var b []byte + b, err = ioutil.ReadFile(filepath.Join(a.Root, "package.json")) + if err != nil { + err = errors.WithMessage(err, "could not read package.json") + return + } + p := packageJSON{} + if err = json.Unmarshal(b, &p); err != nil { + err = errors.WithMessage(err, "could not parse package.json") + return + } + a.packageJSON = p + }) + + if err != nil { + return "", err + } + + s, ok := a.packageJSON.Scripts[name] + if ok { + return s, nil + } + return "", fmt.Errorf("node script %s not found", name) +} diff --git a/vendor/github.com/gobuffalo/meta/meta.go b/vendor/github.com/gobuffalo/meta/meta.go new file mode 100644 index 0000000000..7705f13342 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/meta.go @@ -0,0 +1,115 @@ +package meta + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/BurntSushi/toml" + "github.com/gobuffalo/envy" + fname "github.com/gobuffalo/flect/name" +) + +func Named(name string, root string) App { + pwd, _ := os.Getwd() + pwd = strings.TrimPrefix(root, "/private") + if root == "." { + root = pwd + } + + // Handle symlinks + var oldPwd = pwd + pwd = ResolveSymlinks(pwd) + os.Chdir(pwd) + if runtime.GOOS != "windows" { + // On Non-Windows OS, os.Getwd() uses PWD env var as a preferred + // way to get the working dir. + os.Setenv("PWD", pwd) + } + defer func() { + // Restore PWD + os.Chdir(oldPwd) + if runtime.GOOS != "windows" { + os.Setenv("PWD", oldPwd) + } + }() + + // Gather meta data + if len(name) == 0 { + name = filepath.Base(root) + } + pp := resolvePackageName(name, pwd) + + app := App{ + Pwd: pwd, + Root: root, + GoPath: envy.GoPath(), + Name: fname.New(name), + WithModules: envy.Mods(), + AsAPI: false, + AsWeb: true, + } + app.PackageRoot(pp) + + app.Bin = filepath.Join("bin", app.Name.String()) + + if runtime.GOOS == "windows" { + app.Bin += ".exe" + } + + cf, err := os.Open(filepath.Join(app.Root, "config", "buffalo-app.toml")) + if err != nil { + return oldSchool(app) + } + defer cf.Close() + + if _, err := toml.DecodeReader(cf, &app); err != nil { + fmt.Println(err) + } + + return app +} + +// New App based on the details found at the provided root path +func New(root string) App { + return Named("", root) +} + +func oldSchool(app App) App { + root := app.Root + db := filepath.Join(root, "database.yml") + if _, err := os.Stat(db); err == nil { + app.WithPop = true + if b, err := ioutil.ReadFile(db); err == nil { + app.WithSQLite = bytes.Contains(bytes.ToLower(b), []byte("sqlite")) + } + } + if _, err := os.Stat(filepath.Join(root, "Gopkg.toml")); err == nil { + app.WithDep = true + } + if _, err := os.Stat(filepath.Join(root, "package.json")); err == nil { + app.WithNodeJs = true + } + if _, err := os.Stat(filepath.Join(root, "webpack.config.js")); err == nil { + app.WithWebpack = true + } + if _, err := os.Stat(filepath.Join(root, "yarn.lock")); err == nil { + app.WithYarn = true + } + if _, err := os.Stat(filepath.Join(root, "Dockerfile")); err == nil { + app.WithDocker = true + } + if _, err := os.Stat(filepath.Join(root, "grifts")); err == nil { + app.WithGrifts = true + } + if _, err := os.Stat(filepath.Join(root, ".git")); err == nil { + app.VCS = "git" + } else if _, err := os.Stat(filepath.Join(root, ".bzr")); err == nil { + app.VCS = "bzr" + } + return app +} diff --git a/vendor/github.com/gobuffalo/meta/tags.go b/vendor/github.com/gobuffalo/meta/tags.go new file mode 100644 index 0000000000..82e89e4136 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/tags.go @@ -0,0 +1,39 @@ +package meta + +import ( + "sort" + "strings" +) + +// BuildTags are tags used for building apps +type BuildTags []string + +// String returns the tags in the form of: +// "foo bar baz" (with the quotes!) +func (t BuildTags) String() string { + return strings.Join(t, " ") +} + +// BuildTags combines the passed in env, and any additional tags, +// with tags that Buffalo decides the build process requires. +// An example would be adding the "sqlite" build tag if using +// SQLite3. +func (a App) BuildTags(env string, tags ...string) BuildTags { + m := map[string]string{} + m[env] = env + for _, t := range tags { + m[t] = t + } + if a.WithSQLite { + m["sqlite"] = "sqlite" + } + var tt []string + for k := range m { + k = strings.TrimSpace(k) + if len(k) != 0 { + tt = append(tt, k) + } + } + sort.Strings(tt) + return BuildTags(tt) +} diff --git a/vendor/github.com/gobuffalo/meta/version.go b/vendor/github.com/gobuffalo/meta/version.go new file mode 100644 index 0000000000..b6a333a350 --- /dev/null +++ b/vendor/github.com/gobuffalo/meta/version.go @@ -0,0 +1,3 @@ +package meta + +const Version = "v0.0.1" diff --git a/vendor/github.com/gobuffalo/packr/builder/box.go b/vendor/github.com/gobuffalo/packr/builder/box.go new file mode 100644 index 0000000000..8490455dcb --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/box.go @@ -0,0 +1,76 @@ +package builder + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +type box struct { + Name string + Files []file + compress bool +} + +func (b *box) Walk(root string) error { + root, err := filepath.EvalSymlinks(root) + if err != nil { + return errors.WithStack(err) + } + if _, err := os.Stat(root); err != nil { + // return nil + return errors.Errorf("could not find folder for box: %s", root) + } + return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if info == nil || info.IsDir() || strings.HasSuffix(info.Name(), "-packr.go") { + return nil + } + name := strings.Replace(path, root+string(os.PathSeparator), "", 1) + name = strings.Replace(name, "\\", "/", -1) + f := file{ + Name: name, + } + + DebugLog("packing file %s\n", f.Name) + + bb, err := ioutil.ReadFile(path) + if err != nil { + return errors.WithStack(err) + } + if b.compress { + bb, err = compressFile(bb) + if err != nil { + return errors.WithStack(err) + } + } + bb, err = json.Marshal(bb) + if err != nil { + return errors.WithStack(err) + } + f.Contents = strings.Replace(string(bb), "\"", "\\\"", -1) + + DebugLog("packed file %s\n", f.Name) + b.Files = append(b.Files, f) + return nil + }) +} + +func compressFile(bb []byte) ([]byte, error) { + var buf bytes.Buffer + writer := gzip.NewWriter(&buf) + _, err := writer.Write(bb) + if err != nil { + return bb, errors.WithStack(err) + } + err = writer.Close() + if err != nil { + return bb, errors.WithStack(err) + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/gobuffalo/packr/builder/builder.go b/vendor/github.com/gobuffalo/packr/builder/builder.go new file mode 100644 index 0000000000..1e00239081 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/builder.go @@ -0,0 +1,172 @@ +package builder + +import ( + "context" + "os" + "path/filepath" + "regexp" + "strings" + "sync" + "text/template" + + "github.com/pkg/errors" + "golang.org/x/sync/errgroup" +) + +var DebugLog func(string, ...interface{}) + +func init() { + DebugLog = func(string, ...interface{}) {} +} + +var invalidFilePattern = regexp.MustCompile(`(_test|-packr).go$`) + +// Builder scans folders/files looking for `packr.NewBox` and then compiling +// the required static files into `-packr.go` files so they can +// be built into Go binaries. +type Builder struct { + context.Context + RootPath string + IgnoredBoxes []string + IgnoredFolders []string + pkgs map[string]pkg + moot *sync.Mutex + Compress bool +} + +// Run the builder. +func (b *Builder) Run() error { + wg := &errgroup.Group{} + root, err := filepath.EvalSymlinks(b.RootPath) + if err != nil { + return errors.WithStack(err) + } + err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if info == nil { + return filepath.SkipDir + } + + base := strings.ToLower(filepath.Base(path)) + if strings.HasPrefix(base, "_") { + return filepath.SkipDir + } + for _, f := range b.IgnoredFolders { + if strings.ToLower(f) == base { + if info.IsDir() { + return filepath.SkipDir + } else { + return nil + } + } + } + if !info.IsDir() { + wg.Go(func() error { + return b.process(path) + }) + } + return nil + }) + if err != nil { + return errors.WithStack(err) + } + if err := wg.Wait(); err != nil { + return errors.WithStack(err) + } + return b.dump() +} + +func (b *Builder) dump() error { + for _, p := range b.pkgs { + name := filepath.Join(p.Dir, "a_"+p.Name+"-packr.go") + f, err := os.Create(name) + defer f.Close() + if err != nil { + return errors.WithStack(err) + } + t, err := template.New("").Parse(tmpl) + + if err != nil { + return errors.WithStack(err) + } + err = t.Execute(f, p) + if err != nil { + return errors.WithStack(err) + } + } + return nil +} + +func (b *Builder) process(path string) error { + ext := filepath.Ext(path) + if ext != ".go" || invalidFilePattern.MatchString(path) { + return nil + } + + v := newVisitor(path) + if err := v.Run(); err != nil { + return errors.WithStack(err) + } + + pk := pkg{ + Dir: filepath.Dir(path), + Boxes: []box{}, + Name: v.Package, + } + + for _, n := range v.Boxes { + var ignored bool + for _, i := range b.IgnoredBoxes { + if n == i { + // this is an ignored box + ignored = true + break + } + } + if ignored { + continue + } + bx := &box{ + Name: n, + Files: []file{}, + compress: b.Compress, + } + DebugLog("building box %s\n", bx.Name) + p := filepath.Join(pk.Dir, bx.Name) + if err := bx.Walk(p); err != nil { + return errors.WithStack(err) + } + if len(bx.Files) > 0 { + pk.Boxes = append(pk.Boxes, *bx) + } + DebugLog("built box %s with %q\n", bx.Name, bx.Files) + } + + if len(pk.Boxes) > 0 { + b.addPkg(pk) + } + return nil +} + +func (b *Builder) addPkg(p pkg) { + b.moot.Lock() + defer b.moot.Unlock() + if _, ok := b.pkgs[p.Name]; !ok { + b.pkgs[p.Name] = p + return + } + pp := b.pkgs[p.Name] + pp.Boxes = append(pp.Boxes, p.Boxes...) + b.pkgs[p.Name] = pp +} + +// New Builder with a given context and path +func New(ctx context.Context, path string) *Builder { + return &Builder{ + Context: ctx, + RootPath: path, + IgnoredBoxes: []string{}, + IgnoredFolders: []string{"vendor", ".git", "node_modules", ".idea"}, + pkgs: map[string]pkg{}, + moot: &sync.Mutex{}, + } +} diff --git a/vendor/github.com/gobuffalo/packr/builder/clean.go b/vendor/github.com/gobuffalo/packr/builder/clean.go new file mode 100644 index 0000000000..e68b398109 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/clean.go @@ -0,0 +1,38 @@ +package builder + +import ( + "os" + "path/filepath" + + "github.com/gobuffalo/packr/v2/jam/parser" + "github.com/gobuffalo/packr/v2/jam/store" + "github.com/pkg/errors" +) + +// Clean up an *-packr.go files +func Clean(root string) error { + defer func() { + packd := filepath.Join(root, "packrd") + os.RemoveAll(packd) + }() + + p, err := parser.NewFromRoots([]string{root}, &parser.RootsOptions{ + IgnoreImports: true, + }) + if err != nil { + return errors.WithStack(err) + } + + boxes, err := p.Run() + if err != nil { + return errors.WithStack(err) + } + + d := store.NewDisk("", "") + for _, box := range boxes { + if err := d.Clean(box); err != nil { + return errors.WithStack(err) + } + } + return nil +} diff --git a/vendor/github.com/gobuffalo/packr/builder/file.go b/vendor/github.com/gobuffalo/packr/builder/file.go new file mode 100644 index 0000000000..d439d49b6e --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/file.go @@ -0,0 +1,10 @@ +package builder + +type file struct { + Name string + Contents string +} + +func (f file) String() string { + return f.Name +} diff --git a/vendor/github.com/gobuffalo/packr/builder/pkg.go b/vendor/github.com/gobuffalo/packr/builder/pkg.go new file mode 100644 index 0000000000..fbad2acfca --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/pkg.go @@ -0,0 +1,7 @@ +package builder + +type pkg struct { + Name string + Dir string + Boxes []box +} diff --git a/vendor/github.com/gobuffalo/packr/builder/tmpl.go b/vendor/github.com/gobuffalo/packr/builder/tmpl.go new file mode 100644 index 0000000000..2b335adc32 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/tmpl.go @@ -0,0 +1,18 @@ +package builder + +var tmpl = `// Code generated by github.com/gobuffalo/packr. DO NOT EDIT. + +package {{.Name}} + +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 .Files }} + packr.PackJSONBytes("{{$box.Name}}", "{{.Name}}", "{{.Contents}}") + {{- end }} + {{- end }} +} +` diff --git a/vendor/github.com/gobuffalo/packr/builder/visitor.go b/vendor/github.com/gobuffalo/packr/builder/visitor.go new file mode 100644 index 0000000000..ea24bde244 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/builder/visitor.go @@ -0,0 +1,248 @@ +package builder + +import ( + "go/ast" + "go/parser" + "go/token" + "io/ioutil" + "sort" + "strings" + + "github.com/pkg/errors" +) + +type visitor struct { + Path string + Package string + Boxes []string + Errors []error +} + +func newVisitor(path string) *visitor { + return &visitor{ + Path: path, + Boxes: []string{}, + Errors: []error{}, + } +} + +func (v *visitor) Run() error { + b, err := ioutil.ReadFile(v.Path) + if err != nil { + return errors.WithStack(err) + } + + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, v.Path, string(b), parser.ParseComments) + if err != nil { + return errors.WithStack(err) + } + + v.Package = file.Name.Name + ast.Walk(v, file) + + m := map[string]string{} + for _, s := range v.Boxes { + m[s] = s + } + v.Boxes = []string{} + for k := range m { + v.Boxes = append(v.Boxes, k) + } + + sort.Strings(v.Boxes) + + if len(v.Errors) > 0 { + s := make([]string, len(v.Errors)) + for i, e := range v.Errors { + s[i] = e.Error() + } + return errors.New(strings.Join(s, "\n")) + } + return nil +} + +func (v *visitor) Visit(node ast.Node) ast.Visitor { + if node == nil { + return v + } + if err := v.eval(node); err != nil { + v.Errors = append(v.Errors, err) + } + return v +} + +func (v *visitor) eval(node ast.Node) error { + switch t := node.(type) { + case *ast.CallExpr: + return v.evalExpr(t) + case *ast.Ident: + return v.evalIdent(t) + case *ast.GenDecl: + for _, n := range t.Specs { + if err := v.eval(n); err != nil { + return errors.WithStack(err) + } + } + case *ast.FuncDecl: + if t.Body == nil { + return nil + } + for _, b := range t.Body.List { + if err := v.evalStmt(b); err != nil { + return errors.WithStack(err) + } + } + return nil + case *ast.ValueSpec: + for _, e := range t.Values { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *visitor) evalStmt(stmt ast.Stmt) error { + switch t := stmt.(type) { + case *ast.ExprStmt: + return v.evalExpr(t.X) + case *ast.AssignStmt: + for _, e := range t.Rhs { + if err := v.evalArgs(e); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *visitor) evalExpr(expr ast.Expr) error { + switch t := expr.(type) { + case *ast.CallExpr: + if t.Fun == nil { + return nil + } + for _, a := range t.Args { + switch at := a.(type) { + case *ast.CallExpr: + if sel, ok := t.Fun.(*ast.SelectorExpr); ok { + return v.evalSelector(at, sel) + } + + if err := v.evalArgs(at); err != nil { + return errors.WithStack(err) + } + case *ast.CompositeLit: + for _, e := range at.Elts { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + } + } + if ft, ok := t.Fun.(*ast.SelectorExpr); ok { + return v.evalSelector(t, ft) + } + case *ast.KeyValueExpr: + return v.evalExpr(t.Value) + } + return nil +} + +func (v *visitor) evalArgs(expr ast.Expr) error { + switch at := expr.(type) { + case *ast.CompositeLit: + for _, e := range at.Elts { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + // case *ast.BasicLit: + // fmt.Println("evalArgs", at.Value) + // v.addBox(at.Value) + case *ast.CallExpr: + if at.Fun == nil { + return nil + } + switch st := at.Fun.(type) { + case *ast.SelectorExpr: + if err := v.evalSelector(at, st); err != nil { + return errors.WithStack(err) + } + case *ast.Ident: + return v.evalIdent(st) + } + for _, a := range at.Args { + if err := v.evalArgs(a); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *visitor) evalSelector(expr *ast.CallExpr, sel *ast.SelectorExpr) error { + x, ok := sel.X.(*ast.Ident) + if !ok { + return nil + } + if x.Name == "packr" && sel.Sel.Name == "NewBox" { + for _, e := range expr.Args { + switch at := e.(type) { + case *ast.Ident: + switch at.Obj.Kind { + case ast.Var: + if as, ok := at.Obj.Decl.(*ast.AssignStmt); ok { + v.addVariable(as) + } + case ast.Con: + if vs, ok := at.Obj.Decl.(*ast.ValueSpec); ok { + v.addConstant(vs) + } + } + return v.evalIdent(at) + case *ast.BasicLit: + v.addBox(at.Value) + case *ast.CallExpr: + return v.evalExpr(at) + } + } + } + + return nil +} + +func (v *visitor) evalIdent(i *ast.Ident) error { + if i.Obj == nil { + return nil + } + if s, ok := i.Obj.Decl.(*ast.AssignStmt); ok { + return v.evalStmt(s) + } + return nil +} + +func (v *visitor) addBox(b string) { + b = strings.Replace(b, "\"", "", -1) + v.Boxes = append(v.Boxes, b) +} + +func (v *visitor) addVariable(as *ast.AssignStmt) error { + if len(as.Rhs) == 1 { + if bs, ok := as.Rhs[0].(*ast.BasicLit); ok { + v.addBox(bs.Value) + } + } + return nil +} + +func (v *visitor) addConstant(vs *ast.ValueSpec) error { + if len(vs.Values) == 1 { + if bs, ok := vs.Values[0].(*ast.BasicLit); ok { + v.addBox(bs.Value) + } + } + return nil +} diff --git a/vendor/github.com/gobuffalo/packr/packr/cmd/build.go b/vendor/github.com/gobuffalo/packr/packr/cmd/build.go new file mode 100644 index 0000000000..aaa640d1b5 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/cmd/build.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "context" + "os" + "os/exec" + + "github.com/gobuffalo/packr" + "github.com/gobuffalo/packr/builder" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// buildCmd represents the build command +var buildCmd = &cobra.Command{ + Use: "build", + Short: "Wraps the go build command with packr", + DisableFlagParsing: true, + RunE: func(cmd *cobra.Command, args []string) error { + defer builder.Clean(input) + b := builder.New(context.Background(), input) + err := b.Run() + if err != nil { + return errors.WithStack(err) + } + + cargs := []string{"build"} + cargs = append(cargs, args...) + cp := exec.Command(packr.GoBin(), cargs...) + cp.Stderr = os.Stderr + cp.Stdin = os.Stdin + cp.Stdout = os.Stdout + + return cp.Run() + }, +} + +func init() { + rootCmd.AddCommand(buildCmd) +} diff --git a/vendor/github.com/gobuffalo/packr/packr/cmd/clean.go b/vendor/github.com/gobuffalo/packr/packr/cmd/clean.go new file mode 100644 index 0000000000..3be7992e0a --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/cmd/clean.go @@ -0,0 +1,18 @@ +package cmd + +import ( + "github.com/gobuffalo/packr/builder" + "github.com/spf13/cobra" +) + +var cleanCmd = &cobra.Command{ + Use: "clean", + Short: "removes any *-packr.go files", + Run: func(cmd *cobra.Command, args []string) { + builder.Clean(input) + }, +} + +func init() { + rootCmd.AddCommand(cleanCmd) +} diff --git a/vendor/github.com/gobuffalo/packr/packr/cmd/install.go b/vendor/github.com/gobuffalo/packr/packr/cmd/install.go new file mode 100644 index 0000000000..1c8b16600c --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/cmd/install.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/gobuffalo/packr" + "github.com/gobuffalo/packr/builder" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// installCmd represents the install command +var installCmd = &cobra.Command{ + Use: "install", + Short: "Wraps the go install command with packr", + DisableFlagParsing: true, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) > 0 { + input = args[len(args)-1] + if !strings.HasPrefix(input, ".") { + input = filepath.Join(packr.GoPath(), "src", input) + if _, err := os.Stat(input); err != nil { + return errors.WithStack(err) + } + } + } + defer builder.Clean(input) + b := builder.New(context.Background(), input) + err := b.Run() + if err != nil { + return errors.WithStack(err) + } + + cargs := []string{"install"} + cargs = append(cargs, args...) + cp := exec.Command(packr.GoBin(), cargs...) + cp.Stderr = os.Stderr + cp.Stdin = os.Stdin + cp.Stdout = os.Stdout + + return cp.Run() + }, +} + +func init() { + rootCmd.AddCommand(installCmd) +} diff --git a/vendor/github.com/gobuffalo/packr/packr/cmd/root.go b/vendor/github.com/gobuffalo/packr/packr/cmd/root.go new file mode 100644 index 0000000000..94f1c5563c --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/cmd/root.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/gobuffalo/packr/builder" + "github.com/spf13/cobra" +) + +var input string +var compress bool +var verbose bool + +var rootCmd = &cobra.Command{ + Use: "packr", + Short: "compiles static files into Go files", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !verbose { + for _, a := range args { + if a == "-v" { + verbose = true + break + } + } + } + + if verbose { + builder.DebugLog = func(s string, a ...interface{}) { + os.Stdout.WriteString(fmt.Sprintf(s, a...)) + } + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.New(context.Background(), input) + b.Compress = compress + return b.Run() + }, +} + +func init() { + pwd, _ := os.Getwd() + rootCmd.Flags().StringVarP(&input, "input", "i", pwd, "path to scan for packr Boxes") + rootCmd.Flags().BoolVarP(&compress, "compress", "z", false, "compress box contents") + rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "print verbose logging information") +} + +// Execute the commands +func Execute() { + if err := rootCmd.Execute(); err != nil { + os.Exit(-1) + } +} diff --git a/vendor/github.com/gobuffalo/packr/packr/cmd/version.go b/vendor/github.com/gobuffalo/packr/packr/cmd/version.go new file mode 100644 index 0000000000..df43919840 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/cmd/version.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "fmt" + + "github.com/gobuffalo/packr" + "github.com/spf13/cobra" +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "prints packr version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Print(packr.Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/vendor/github.com/gobuffalo/packr/packr/main.go b/vendor/github.com/gobuffalo/packr/packr/main.go new file mode 100644 index 0000000000..c59a00bd4d --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/packr/main.go @@ -0,0 +1,21 @@ +// Copyright © 2017 NAME HERE +// +// 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. + +package main + +import "github.com/gobuffalo/packr/packr/cmd" + +func main() { + cmd.Execute() +} diff --git a/vendor/github.com/gobuffalo/packr/v2/LICENSE.txt b/vendor/github.com/gobuffalo/packr/v2/LICENSE.txt new file mode 100644 index 0000000000..3ccb336a08 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/LICENSE.txt @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2016 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. diff --git a/vendor/github.com/gobuffalo/packr/v2/file/file.go b/vendor/github.com/gobuffalo/packr/v2/file/file.go new file mode 100644 index 0000000000..bef50c8dd1 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/file.go @@ -0,0 +1,32 @@ +package file + +import ( + "bytes" + "io" + + "github.com/gobuffalo/packd" +) + +// File represents a virtual, or physical, backing of +// a file object in a Box +type File = packd.File + +// FileMappable types are capable of returning a map of +// path => File +type FileMappable interface { + FileMap() map[string]File +} + +// NewFile returns a virtual File implementation +func NewFile(name string, b []byte) (File, error) { + return packd.NewFile(name, bytes.NewReader(b)) +} + +// NewDir returns a virtual dir implementation +func NewDir(name string) (File, error) { + return packd.NewDir(name) +} + +func NewFileR(name string, r io.Reader) (File, error) { + return packd.NewFile(name, r) +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/info.go b/vendor/github.com/gobuffalo/packr/v2/file/info.go new file mode 100644 index 0000000000..90acb8c215 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/info.go @@ -0,0 +1,38 @@ +package file + +import ( + "os" + "time" +) + +type info struct { + Path string + Contents []byte + size int64 + modTime time.Time + isDir bool +} + +func (f info) Name() string { + return f.Path +} + +func (f info) Size() int64 { + return f.size +} + +func (f info) Mode() os.FileMode { + return 0444 +} + +func (f info) ModTime() time.Time { + return f.modTime +} + +func (f info) IsDir() bool { + return f.isDir +} + +func (f info) Sys() interface{} { + return nil +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/disk.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/disk.go new file mode 100644 index 0000000000..2a431179a3 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/disk.go @@ -0,0 +1,81 @@ +package resolver + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/gobuffalo/packr/v2/file" + "github.com/gobuffalo/packr/v2/plog" + "github.com/karrick/godirwalk" + "github.com/pkg/errors" +) + +var _ Resolver = &Disk{} + +type Disk struct { + Root string +} + +func (d Disk) String() string { + return String(&d) +} + +func (d *Disk) Resolve(box string, name string) (file.File, error) { + path := OsPath(name) + if !filepath.IsAbs(path) { + path = filepath.Join(OsPath(d.Root), path) + } + fi, err := os.Stat(path) + if err != nil { + return nil, err + } + if fi.IsDir() { + return file.NewDir(OsPath(name)) + } + if bb, err := ioutil.ReadFile(path); err == nil { + return file.NewFile(OsPath(name), bb) + } + return nil, os.ErrNotExist +} + +var _ file.FileMappable = &Disk{} + +func (d *Disk) FileMap() map[string]file.File { + moot := &sync.Mutex{} + m := map[string]file.File{} + root := OsPath(d.Root) + if _, err := os.Stat(root); err != nil { + return m + } + callback := func(path string, de *godirwalk.Dirent) error { + if _, err := os.Stat(root); err != nil { + return nil + } + if !de.IsRegular() { + return nil + } + moot.Lock() + name := strings.TrimPrefix(path, root+string(filepath.Separator)) + b, err := ioutil.ReadFile(path) + if err != nil { + return errors.WithStack(err) + } + m[name], err = file.NewFile(name, b) + if err != nil { + return errors.WithStack(err) + } + moot.Unlock() + return nil + } + err := godirwalk.Walk(root, &godirwalk.Options{ + FollowSymbolicLinks: true, + Callback: callback, + }) + if err != nil { + plog.Logger.Errorf("[%s] error walking %v", root, err) + } + return m +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/encoding/hex/hex.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/encoding/hex/hex.go new file mode 100644 index 0000000000..aee5aecb1a --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/encoding/hex/hex.go @@ -0,0 +1,315 @@ +// 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 hex implements hexadecimal encoding and decoding. +package hex + +import ( + "bytes" + "errors" + "fmt" + "io" +) + +const hextable = "0123456789abcdef" + +// EncodedLen returns the length of an encoding of n source bytes. +// Specifically, it returns n * 2. +func EncodedLen(n int) int { return n * 2 } + +// Encode encodes src into EncodedLen(len(src)) +// bytes of dst. As a convenience, it returns the number +// of bytes written to dst, but this value is always EncodedLen(len(src)). +// Encode implements hexadecimal encoding. +func Encode(dst, src []byte) int { + for i, v := range src { + dst[i*2] = hextable[v>>4] + dst[i*2+1] = hextable[v&0x0f] + } + + return len(src) * 2 +} + +// ErrLength reports an attempt to decode an odd-length input +// using Decode or DecodeString. +// The stream-based Decoder returns io.ErrUnexpectedEOF instead of ErrLength. +var ErrLength = errors.New("encoding/hex: odd length hex string") + +// InvalidByteError values describe errors resulting from an invalid byte in a hex string. +type InvalidByteError byte + +func (e InvalidByteError) Error() string { + return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e)) +} + +// DecodedLen returns the length of a decoding of x source bytes. +// Specifically, it returns x / 2. +func DecodedLen(x int) int { return x / 2 } + +// Decode decodes src into DecodedLen(len(src)) bytes, +// returning the actual number of bytes written to dst. +// +// Decode expects that src contains only hexadecimal +// characters and that src has even length. +// If the input is malformed, Decode returns the number +// of bytes decoded before the error. +func Decode(dst, src []byte) (int, error) { + var i int + for i = 0; i < len(src)/2; i++ { + a, ok := fromHexChar(src[i*2]) + if !ok { + return i, InvalidByteError(src[i*2]) + } + b, ok := fromHexChar(src[i*2+1]) + if !ok { + return i, InvalidByteError(src[i*2+1]) + } + dst[i] = (a << 4) | b + } + if len(src)%2 == 1 { + // Check for invalid char before reporting bad length, + // since the invalid char (if present) is an earlier problem. + if _, ok := fromHexChar(src[i*2]); !ok { + return i, InvalidByteError(src[i*2]) + } + return i, ErrLength + } + return i, nil +} + +// fromHexChar converts a hex character into its value and a success flag. +func fromHexChar(c byte) (byte, bool) { + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + + return 0, false +} + +// EncodeToString returns the hexadecimal encoding of src. +func EncodeToString(src []byte) string { + dst := make([]byte, EncodedLen(len(src))) + Encode(dst, src) + return string(dst) +} + +// DecodeString returns the bytes represented by the hexadecimal string s. +// +// DecodeString expects that src contains only hexadecimal +// characters and that src has even length. +// If the input is malformed, DecodeString returns +// the bytes decoded before the error. +func DecodeString(s string) ([]byte, error) { + src := []byte(s) + // We can use the source slice itself as the destination + // because the decode loop increments by one and then the 'seen' byte is not used anymore. + n, err := Decode(src, src) + return src[:n], err +} + +// Dump returns a string that contains a hex dump of the given data. The format +// of the hex dump matches the output of `hexdump -C` on the command line. +func Dump(data []byte) string { + var buf bytes.Buffer + dumper := Dumper(&buf) + dumper.Write(data) + dumper.Close() + return buf.String() +} + +// bufferSize is the number of hexadecimal characters to buffer in encoder and decoder. +const bufferSize = 1024 + +type encoder struct { + w io.Writer + err error + out [bufferSize]byte // output buffer +} + +// NewEncoder returns an io.Writer that writes lowercase hexadecimal characters to w. +func NewEncoder(w io.Writer) io.Writer { + return &encoder{w: w} +} + +func (e *encoder) Write(p []byte) (n int, err error) { + for len(p) > 0 && e.err == nil { + chunkSize := bufferSize / 2 + if len(p) < chunkSize { + chunkSize = len(p) + } + + var written int + encoded := Encode(e.out[:], p[:chunkSize]) + written, e.err = e.w.Write(e.out[:encoded]) + n += written / 2 + p = p[chunkSize:] + } + return n, e.err +} + +type decoder struct { + r io.Reader + err error + in []byte // input buffer (encoded form) + arr [bufferSize]byte // backing array for in +} + +// NewDecoder returns an io.Reader that decodes hexadecimal characters from r. +// NewDecoder expects that r contain only an even number of hexadecimal characters. +func NewDecoder(r io.Reader) io.Reader { + return &decoder{r: r} +} + +func (d *decoder) Read(p []byte) (n int, err error) { + // Fill internal buffer with sufficient bytes to decode + if len(d.in) < 2 && d.err == nil { + var numCopy, numRead int + numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes + numRead, d.err = d.r.Read(d.arr[numCopy:]) + d.in = d.arr[:numCopy+numRead] + if d.err == io.EOF && len(d.in)%2 != 0 { + if _, ok := fromHexChar(d.in[len(d.in)-1]); !ok { + d.err = InvalidByteError(d.in[len(d.in)-1]) + } else { + d.err = io.ErrUnexpectedEOF + } + } + } + + // Decode internal buffer into output buffer + if numAvail := len(d.in) / 2; len(p) > numAvail { + p = p[:numAvail] + } + numDec, err := Decode(p, d.in[:len(p)*2]) + d.in = d.in[2*numDec:] + if err != nil { + d.in, d.err = nil, err // Decode error; discard input remainder + } + + if len(d.in) < 2 { + return numDec, d.err // Only expose errors when buffer fully consumed + } + return numDec, nil +} + +// Dumper returns a WriteCloser that writes a hex dump of all written data to +// w. The format of the dump matches the output of `hexdump -C` on the command +// line. +func Dumper(w io.Writer) io.WriteCloser { + return &dumper{w: w} +} + +type dumper struct { + w io.Writer + rightChars [18]byte + buf [14]byte + used int // number of bytes in the current line + n uint // number of bytes, total + closed bool +} + +func toChar(b byte) byte { + if b < 32 || b > 126 { + return '.' + } + return b +} + +func (h *dumper) Write(data []byte) (n int, err error) { + if h.closed { + return 0, errors.New("encoding/hex: dumper closed") + } + + // Output lines look like: + // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| + // ^ offset ^ extra space ^ ASCII of line. + for i := range data { + if h.used == 0 { + // At the beginning of a line we print the current + // offset in hex. + h.buf[0] = byte(h.n >> 24) + h.buf[1] = byte(h.n >> 16) + h.buf[2] = byte(h.n >> 8) + h.buf[3] = byte(h.n) + Encode(h.buf[4:], h.buf[:4]) + h.buf[12] = ' ' + h.buf[13] = ' ' + _, err = h.w.Write(h.buf[4:]) + if err != nil { + return + } + } + Encode(h.buf[:], data[i:i+1]) + h.buf[2] = ' ' + l := 3 + if h.used == 7 { + // There's an additional space after the 8th byte. + h.buf[3] = ' ' + l = 4 + } else if h.used == 15 { + // At the end of the line there's an extra space and + // the bar for the right column. + h.buf[3] = ' ' + h.buf[4] = '|' + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + n++ + h.rightChars[h.used] = toChar(data[i]) + h.used++ + h.n++ + if h.used == 16 { + h.rightChars[16] = '|' + h.rightChars[17] = '\n' + _, err = h.w.Write(h.rightChars[:]) + if err != nil { + return + } + h.used = 0 + } + } + return +} + +func (h *dumper) Close() (err error) { + // See the comments in Write() for the details of this format. + if h.closed { + return + } + h.closed = true + if h.used == 0 { + return + } + h.buf[0] = ' ' + h.buf[1] = ' ' + h.buf[2] = ' ' + h.buf[3] = ' ' + h.buf[4] = '|' + nBytes := h.used + for h.used < 16 { + l := 3 + if h.used == 7 { + l = 4 + } else if h.used == 15 { + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + h.used++ + } + h.rightChars[nBytes] = '|' + h.rightChars[nBytes+1] = '\n' + _, err = h.w.Write(h.rightChars[:nBytes+2]) + return +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/hex_gzip.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/hex_gzip.go new file mode 100644 index 0000000000..0fc5b7d6e0 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/hex_gzip.go @@ -0,0 +1,113 @@ +package resolver + +import ( + "bytes" + "compress/gzip" + "io" + "io/ioutil" + "os" + "strings" + "sync" + + "github.com/gobuffalo/packr/v2/file/resolver/encoding/hex" + "github.com/gobuffalo/packr/v2/plog" + + "github.com/gobuffalo/packr/v2/file" + "github.com/pkg/errors" +) + +var _ Resolver = &HexGzip{} + +type HexGzip struct { + packed map[string]string + unpacked map[string]string + moot *sync.RWMutex +} + +func (hg HexGzip) String() string { + return String(&hg) +} + +var _ file.FileMappable = &HexGzip{} + +func (hg *HexGzip) FileMap() map[string]file.File { + hg.moot.RLock() + var names []string + for k := range hg.packed { + names = append(names, k) + } + hg.moot.RUnlock() + m := map[string]file.File{} + for _, n := range names { + if f, err := hg.Resolve("", n); err == nil { + m[n] = f + } + } + return m +} + +func (hg *HexGzip) Resolve(box string, name string) (file.File, error) { + plog.Debug(hg, "Resolve", "box", box, "name", name) + hg.moot.Lock() + defer hg.moot.Unlock() + + if s, ok := hg.unpacked[name]; ok { + return file.NewFile(name, []byte(s)) + } + packed, ok := hg.packed[name] + if !ok { + return nil, os.ErrNotExist + } + + unpacked, err := UnHexGzipString(packed) + if err != nil { + return nil, errors.WithStack(err) + } + + f, err := file.NewFile(OsPath(name), []byte(unpacked)) + if err != nil { + return nil, errors.WithStack(err) + } + hg.unpacked[name] = f.String() + return f, nil +} + +func NewHexGzip(files map[string]string) (*HexGzip, error) { + if files == nil { + files = map[string]string{} + } + + hg := &HexGzip{ + packed: files, + unpacked: map[string]string{}, + moot: &sync.RWMutex{}, + } + + return hg, nil +} + +func HexGzipString(s string) (string, error) { + bb := &bytes.Buffer{} + enc := hex.NewEncoder(bb) + zw := gzip.NewWriter(enc) + io.Copy(zw, strings.NewReader(s)) + zw.Close() + + return bb.String(), nil +} + +func UnHexGzipString(packed string) (string, error) { + br := bytes.NewBufferString(packed) + dec := hex.NewDecoder(br) + zr, err := gzip.NewReader(dec) + if err != nil { + return "", errors.WithStack(err) + } + defer zr.Close() + + b, err := ioutil.ReadAll(zr) + if err != nil { + return "", errors.WithStack(err) + } + return string(b), nil +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/ident.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/ident.go new file mode 100644 index 0000000000..0b90d1f4d3 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/ident.go @@ -0,0 +1,21 @@ +package resolver + +import ( + "path/filepath" + "runtime" + "strings" +) + +func Key(s string) string { + s = strings.Replace(s, "\\", "/", -1) + return s +} + +func OsPath(s string) string { + if runtime.GOOS == "windows" { + s = strings.Replace(s, "/", string(filepath.Separator), -1) + } else { + s = strings.Replace(s, "\\", string(filepath.Separator), -1) + } + return s +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/in_memory.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/in_memory.go new file mode 100644 index 0000000000..aa37297e6d --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/in_memory.go @@ -0,0 +1,64 @@ +package resolver + +import ( + "io/ioutil" + + "github.com/gobuffalo/packd" + "github.com/gobuffalo/packr/v2/file" + "github.com/gobuffalo/packr/v2/plog" + "github.com/pkg/errors" +) + +var _ Resolver = &InMemory{} + +type InMemory struct { + *packd.MemoryBox +} + +func (d InMemory) String() string { + return String(&d) +} + +func (d *InMemory) Resolve(box string, name string) (file.File, error) { + b, err := d.MemoryBox.Find(name) + if err != nil { + return nil, err + } + return file.NewFile(name, b) +} + +func (d *InMemory) Pack(name string, f file.File) error { + plog.Debug(d, "Pack", "name", name) + b, err := ioutil.ReadAll(f) + if err != nil { + return errors.WithStack(err) + } + d.AddBytes(name, b) + return nil +} + +func (d *InMemory) FileMap() map[string]file.File { + m := map[string]file.File{} + d.Walk(func(path string, file file.File) error { + m[path] = file + return nil + }) + return m +} + +func NewInMemory(files map[string]file.File) *InMemory { + if files == nil { + files = map[string]file.File{} + } + box := packd.NewMemoryBox() + + for p, f := range files { + if b, err := ioutil.ReadAll(f); err == nil { + box.AddBytes(p, b) + } + } + + return &InMemory{ + MemoryBox: box, + } +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/packable.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/packable.go new file mode 100644 index 0000000000..ee551fcc0c --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/packable.go @@ -0,0 +1,7 @@ +package resolver + +import "github.com/gobuffalo/packr/v2/file" + +type Packable interface { + Pack(name string, f file.File) error +} diff --git a/vendor/github.com/gobuffalo/packr/v2/file/resolver/resolver.go b/vendor/github.com/gobuffalo/packr/v2/file/resolver/resolver.go new file mode 100644 index 0000000000..8b00397ab1 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/file/resolver/resolver.go @@ -0,0 +1,33 @@ +package resolver + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/gobuffalo/packr/v2/file" +) + +type Resolver interface { + Resolve(string, string) (file.File, error) +} + +func defaultResolver() Resolver { + pwd, _ := os.Getwd() + return &Disk{ + Root: pwd, + } +} + +var DefaultResolver = defaultResolver() + +func String(r Resolver) string { + m := map[string]interface{}{ + "name": fmt.Sprintf("%T", r), + } + if fm, ok := r.(file.FileMappable); ok { + m["files"] = fm + } + b, _ := json.Marshal(m) + return string(b) +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/args.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/args.go new file mode 100644 index 0000000000..5f042d15e3 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/args.go @@ -0,0 +1,53 @@ +package parser + +import ( + "encoding/json" + + "github.com/pkg/errors" +) + +// FromArgs is useful when writing packr store-cmd binaries. +/* + package main + + import ( + "log" + "os" + + "github.com/gobuffalo/packr/v2/jam/parser" + "github.com/markbates/s3packr/s3packr" + ) + + func main() { + err := parser.FromArgs(os.Args[1:], func(boxes parser.Boxes) error { + for _, box := range boxes { + s3 := s3packr.New(box) + if err := s3.Pack(box); err != nil { + return err + } + } + return nil + }) + + if err != nil { + log.Fatal(err) + } + } +*/ +func FromArgs(args []string, fn func(Boxes) error) error { + if len(args) == 0 { + return errors.New("you must supply a payload") + } + payload := args[0] + if len(payload) == 0 { + return errors.New("you must supply a payload") + } + + var boxes Boxes + err := json.Unmarshal([]byte(payload), &boxes) + if err != nil { + return err + } + + return fn(boxes) +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/box.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/box.go new file mode 100644 index 0000000000..b294191273 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/box.go @@ -0,0 +1,40 @@ +package parser + +import ( + "encoding/json" + "os" + "strings" +) + +// Box found while parsing a file +type Box struct { + Name string // name of the box + Path string // relative path of folder NewBox("./templates") + AbsPath string // absolute path of Path + Package string // the package name the box was found in + PWD string // the PWD when the parser was run + PackageDir string // the absolute path of the package where the box was found +} + +type Boxes []*Box + +// String - json returned +func (b Box) String() string { + x, _ := json.Marshal(b) + return string(x) +} + +// NewBox stub from the name and the path provided +func NewBox(name string, path string) *Box { + if len(name) == 0 { + name = path + } + name = strings.Replace(name, "\"", "", -1) + pwd, _ := os.Getwd() + box := &Box{ + Name: name, + Path: path, + PWD: pwd, + } + return box +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/file.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/file.go new file mode 100644 index 0000000000..3bf49cd0a4 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/file.go @@ -0,0 +1,54 @@ +package parser + +import ( + "bytes" + "io" + "io/ioutil" + "path/filepath" +) + +// File that is to be parsed +type File struct { + io.Reader + Path string + AbsPath string +} + +// Name of the file "app.go" +func (f File) Name() string { + return f.Path +} + +// String returns the contents of the reader +func (f *File) String() string { + src, _ := ioutil.ReadAll(f) + f.Reader = bytes.NewReader(src) + return string(src) +} + +func (s *File) Write(p []byte) (int, error) { + bb := &bytes.Buffer{} + i, err := bb.Write(p) + s.Reader = bb + return i, err +} + +// NewFile takes the name of the file you want to +// write to and a reader to reader from +func NewFile(path string, r io.Reader) *File { + if r == nil { + r = &bytes.Buffer{} + } + if seek, ok := r.(io.Seeker); ok { + seek.Seek(0, 0) + } + abs := path + if !filepath.IsAbs(path) { + abs, _ = filepath.Abs(path) + } + return &File{ + Reader: r, + Path: path, + AbsPath: abs, + } +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/finder.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/finder.go new file mode 100644 index 0000000000..164638829b --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/finder.go @@ -0,0 +1,101 @@ +package parser + +import ( + "fmt" + "go/build" + "path/filepath" + "strings" + "time" + + "github.com/gobuffalo/packr/v2/plog" + "github.com/karrick/godirwalk" + "github.com/markbates/oncer" + "github.com/pkg/errors" +) + +type finder struct { + id time.Time +} + +func (fd *finder) key(m, dir string) string { + return fmt.Sprintf("%s-*parser.finder#%s-%s", fd.id, m, dir) +} + +// findAllGoFiles *.go files for a given diretory +func (fd *finder) findAllGoFiles(dir string) ([]string, error) { + var err error + var names []string + oncer.Do(fd.key("findAllGoFiles", dir), func() { + plog.Debug(fd, "findAllGoFiles", "dir", dir) + + callback := func(path string, do *godirwalk.Dirent) error { + ext := filepath.Ext(path) + if ext != ".go" { + return nil + } + names = append(names, path) + return nil + } + err = godirwalk.Walk(dir, &godirwalk.Options{ + FollowSymbolicLinks: true, + Callback: callback, + }) + }) + + return names, err +} + +func (fd *finder) findAllGoFilesImports(dir string) ([]string, error) { + var err error + var names []string + oncer.Do(fd.key("findAllGoFilesImports", dir), func() { + ctx := build.Default + + if len(ctx.SrcDirs()) == 0 { + err = errors.New("no src directories found") + return + } + + pkg, err := ctx.ImportDir(dir, 0) + if strings.HasPrefix(pkg.ImportPath, "github.com/gobuffalo/packr") { + return + } + + if err != nil { + if !strings.Contains(err.Error(), "cannot find package") { + if _, ok := errors.Cause(err).(*build.NoGoError); !ok { + err = errors.WithStack(err) + return + } + } + } + + if pkg.Goroot { + return + } + if len(pkg.GoFiles) <= 0 { + return + } + + plog.Debug(fd, "findAllGoFilesImports", "dir", dir) + + names, _ = fd.findAllGoFiles(dir) + for _, n := range pkg.GoFiles { + names = append(names, filepath.Join(pkg.Dir, n)) + } + for _, imp := range pkg.Imports { + if len(ctx.SrcDirs()) == 0 { + continue + } + d := ctx.SrcDirs()[len(ctx.SrcDirs())-1] + ip := filepath.Join(d, imp) + n, err := fd.findAllGoFilesImports(ip) + if err != nil && len(n) != 0 { + names = n + return + } + names = append(names, n...) + } + }) + return names, err +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/parser.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/parser.go new file mode 100644 index 0000000000..17c1516d85 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/parser.go @@ -0,0 +1,47 @@ +package parser + +import ( + "os" + "sort" + "strings" + + "github.com/gobuffalo/packr/v2/plog" + "github.com/pkg/errors" +) + +// Parser to find boxes +type Parser struct { + Prospects []*File // a list of files to check for boxes + IgnoreImports bool +} + +// Run the parser and run any boxes found +func (p *Parser) Run() (Boxes, error) { + var boxes Boxes + for _, pros := range p.Prospects { + plog.Debug(p, "Run", "parsing", pros.Name()) + v := NewVisitor(pros) + pbr, err := v.Run() + if err != nil { + return boxes, errors.WithStack(err) + } + for _, b := range pbr { + plog.Debug(p, "Run", "file", pros.Name(), "box", b.Name) + boxes = append(boxes, b) + } + } + + pwd, _ := os.Getwd() + sort.Slice(boxes, func(a, b int) bool { + b1 := boxes[a] + return !strings.HasPrefix(b1.AbsPath, pwd) + }) + return boxes, nil +} + +// New Parser from a list of File +func New(prospects ...*File) *Parser { + return &Parser{ + Prospects: prospects, + } +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/prospect.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/prospect.go new file mode 100644 index 0000000000..d5421cc1d4 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/prospect.go @@ -0,0 +1,77 @@ +package parser + +import ( + "os" + "path/filepath" + "strings" + + "github.com/gobuffalo/packr/v2/file/resolver" + "github.com/gobuffalo/packr/v2/plog" +) + +var DefaultIgnoredFolders = []string{".", "_", "vendor", "node_modules", "_fixtures"} + +func IsProspect(path string, ignore ...string) (status bool) { + // plog.Debug("parser", "IsProspect", "path", path, "ignore", ignore) + defer func() { + if status { + plog.Debug("parser", "IsProspect (TRUE)", "path", path, "status", status) + } + }() + if path == "." { + return true + } + + ext := filepath.Ext(path) + dir := filepath.Dir(path) + + fi, _ := os.Stat(path) + if fi != nil { + if fi.IsDir() { + dir = filepath.Base(path) + } else { + if len(ext) > 0 { + dir = filepath.Base(filepath.Dir(path)) + } + } + } + + path = strings.ToLower(path) + dir = strings.ToLower(dir) + + if strings.HasSuffix(path, "-packr.go") { + return false + } + + if strings.HasSuffix(path, "_test.go") { + return false + } + + ignore = append(ignore, DefaultIgnoredFolders...) + for i, x := range ignore { + ignore[i] = strings.TrimSpace(strings.ToLower(x)) + } + + parts := strings.Split(resolver.OsPath(path), string(filepath.Separator)) + if len(parts) == 0 { + return false + } + + for _, i := range ignore { + for _, p := range parts { + if strings.HasPrefix(p, i) { + return false + } + } + } + + un := filepath.Base(path) + if len(ext) != 0 { + un = filepath.Base(filepath.Dir(path)) + } + if strings.HasPrefix(un, "_") { + return false + } + + return ext == ".go" +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/roots.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/roots.go new file mode 100644 index 0000000000..777f535dec --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/roots.go @@ -0,0 +1,90 @@ +package parser + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/gobuffalo/packr/v2/plog" + "github.com/karrick/godirwalk" + "github.com/pkg/errors" +) + +type RootsOptions struct { + IgnoreImports bool + Ignores []string +} + +func (r RootsOptions) String() string { + x, _ := json.Marshal(r) + return string(x) +} + +// NewFromRoots scans the file roots provided and returns a +// new Parser containing the prospects +func NewFromRoots(roots []string, opts *RootsOptions) (*Parser, error) { + if opts == nil { + opts = &RootsOptions{} + } + + if len(roots) == 0 { + pwd, _ := os.Getwd() + roots = append(roots, pwd) + } + p := New() + plog.Debug(p, "NewFromRoots", "roots", roots, "options", opts) + callback := func(path string, de *godirwalk.Dirent) error { + if IsProspect(path, opts.Ignores...) { + if de.IsDir() { + return nil + } + roots = append(roots, path) + return nil + } + if de.IsDir() { + return filepath.SkipDir + } + return nil + } + wopts := &godirwalk.Options{ + FollowSymbolicLinks: true, + Callback: callback, + } + for _, root := range roots { + plog.Debug(p, "NewFromRoots", "walking", root) + err := godirwalk.Walk(root, wopts) + if err != nil { + return p, errors.WithStack(err) + } + } + + dd := map[string]string{} + fd := &finder{id: time.Now()} + for _, r := range roots { + var names []string + if opts.IgnoreImports { + names, _ = fd.findAllGoFiles(r) + } else { + names, _ = fd.findAllGoFilesImports(r) + } + for _, n := range names { + if IsProspect(n) { + plog.Debug(p, "NewFromRoots", "mapping", n) + dd[n] = n + } + } + } + for path := range dd { + plog.Debug(p, "NewFromRoots", "reading file", path) + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, errors.WithStack(err) + } + p.Prospects = append(p.Prospects, NewFile(path, bytes.NewReader(b))) + } + plog.Debug(p, "NewFromRoots", "found prospects", len(p.Prospects)) + return p, nil +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/parser/visitor.go b/vendor/github.com/gobuffalo/packr/v2/jam/parser/visitor.go new file mode 100644 index 0000000000..8c6ce6d2c8 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/parser/visitor.go @@ -0,0 +1,326 @@ +package parser + +import ( + "fmt" + "go/ast" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/gobuffalo/genny" + "github.com/gobuffalo/genny/movinglater/gotools" + "github.com/pkg/errors" +) + +type Visitor struct { + File genny.File + Package string + boxes map[string]*Box + errors []error +} + +func NewVisitor(f *File) *Visitor { + return &Visitor{ + File: f, + boxes: map[string]*Box{}, + errors: []error{}, + } +} + +func (v *Visitor) Run() (Boxes, error) { + var boxes Boxes + pf, err := gotools.ParseFile(v.File) + if err != nil { + return boxes, errors.Wrap(err, v.File.Name()) + } + + v.Package = pf.Ast.Name.Name + ast.Walk(v, pf.Ast) + + for _, vb := range v.boxes { + boxes = append(boxes, vb) + } + + sort.Slice(boxes, func(i, j int) bool { + return boxes[i].Name < boxes[j].Name + }) + + if len(v.errors) > 0 { + s := make([]string, len(v.errors)) + for i, e := range v.errors { + s[i] = e.Error() + } + return boxes, errors.Wrap(errors.New(strings.Join(s, "\n")), v.File.Name()) + } + return boxes, nil +} + +func (v *Visitor) Visit(node ast.Node) ast.Visitor { + if node == nil { + return v + } + if err := v.eval(node); err != nil { + v.errors = append(v.errors, err) + } + + return v +} + +func (v *Visitor) eval(node ast.Node) error { + switch t := node.(type) { + case *ast.CallExpr: + return v.evalExpr(t) + case *ast.Ident: + return v.evalIdent(t) + case *ast.GenDecl: + for _, n := range t.Specs { + if err := v.eval(n); err != nil { + return errors.WithStack(err) + } + } + case *ast.FuncDecl: + if t.Body == nil { + return nil + } + for _, b := range t.Body.List { + if err := v.evalStmt(b); err != nil { + return errors.WithStack(err) + } + } + return nil + case *ast.ValueSpec: + for _, e := range t.Values { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *Visitor) evalStmt(stmt ast.Stmt) error { + switch t := stmt.(type) { + case *ast.ExprStmt: + return v.evalExpr(t.X) + case *ast.AssignStmt: + for _, e := range t.Rhs { + if err := v.evalArgs(e); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *Visitor) evalExpr(expr ast.Expr) error { + switch t := expr.(type) { + case *ast.CallExpr: + if t.Fun == nil { + return nil + } + for _, a := range t.Args { + switch at := a.(type) { + case *ast.CallExpr: + if sel, ok := t.Fun.(*ast.SelectorExpr); ok { + return v.evalSelector(at, sel) + } + + if err := v.evalArgs(at); err != nil { + return errors.WithStack(err) + } + case *ast.CompositeLit: + for _, e := range at.Elts { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + } + } + if ft, ok := t.Fun.(*ast.SelectorExpr); ok { + return v.evalSelector(t, ft) + } + case *ast.KeyValueExpr: + return v.evalExpr(t.Value) + } + return nil +} + +func (v *Visitor) evalArgs(expr ast.Expr) error { + switch at := expr.(type) { + case *ast.CompositeLit: + for _, e := range at.Elts { + if err := v.evalExpr(e); err != nil { + return errors.WithStack(err) + } + } + case *ast.CallExpr: + if at.Fun == nil { + return nil + } + switch st := at.Fun.(type) { + case *ast.SelectorExpr: + if err := v.evalSelector(at, st); err != nil { + return errors.WithStack(err) + } + case *ast.Ident: + return v.evalIdent(st) + } + for _, a := range at.Args { + if err := v.evalArgs(a); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +func (v *Visitor) evalSelector(expr *ast.CallExpr, sel *ast.SelectorExpr) error { + x, ok := sel.X.(*ast.Ident) + if !ok { + return nil + } + if x.Name == "packr" { + switch sel.Sel.Name { + case "New": + if len(expr.Args) != 2 { + return errors.New("`New` requires two arguments") + } + + zz := func(e ast.Expr) (string, error) { + switch at := e.(type) { + case *ast.Ident: + switch at.Obj.Kind { + case ast.Var: + if as, ok := at.Obj.Decl.(*ast.AssignStmt); ok { + return v.fromVariable(as) + } + case ast.Con: + if vs, ok := at.Obj.Decl.(*ast.ValueSpec); ok { + return v.fromConstant(vs) + } + } + return "", v.evalIdent(at) + case *ast.BasicLit: + return at.Value, nil + case *ast.CallExpr: + return "", v.evalExpr(at) + } + return "", errors.Errorf("can't handle %T", e) + } + + k1, err := zz(expr.Args[0]) + if err != nil { + return errors.WithStack(err) + } + k2, err := zz(expr.Args[1]) + if err != nil { + return errors.WithStack(err) + } + v.addBox(k1, k2) + + return nil + case "NewBox": + for _, e := range expr.Args { + switch at := e.(type) { + case *ast.Ident: + switch at.Obj.Kind { + case ast.Var: + if as, ok := at.Obj.Decl.(*ast.AssignStmt); ok { + v.addVariable("", as) + } + case ast.Con: + if vs, ok := at.Obj.Decl.(*ast.ValueSpec); ok { + v.addConstant("", vs) + } + } + return v.evalIdent(at) + case *ast.BasicLit: + v.addBox("", at.Value) + case *ast.CallExpr: + return v.evalExpr(at) + } + } + } + } + + return nil +} + +func (v *Visitor) evalIdent(i *ast.Ident) error { + if i.Obj == nil { + return nil + } + if s, ok := i.Obj.Decl.(*ast.AssignStmt); ok { + return v.evalStmt(s) + } + return nil +} + +func (v *Visitor) addBox(name string, path string) { + if len(name) == 0 { + name = path + } + name = strings.Replace(name, "\"", "", -1) + path = strings.Replace(path, "\"", "", -1) + abs := path + if _, ok := v.boxes[name]; !ok { + box := NewBox(name, path) + box.Package = v.Package + + pd := filepath.Dir(v.File.Name()) + pwd, _ := os.Getwd() + if !filepath.IsAbs(pd) { + pd = filepath.Join(pwd, pd) + } + box.PackageDir = pd + + if !filepath.IsAbs(abs) { + abs = filepath.Join(pd, abs) + } + box.AbsPath = abs + v.boxes[name] = box + } +} +func (v *Visitor) fromVariable(as *ast.AssignStmt) (string, error) { + if len(as.Rhs) == 1 { + if bs, ok := as.Rhs[0].(*ast.BasicLit); ok { + return bs.Value, nil + } + } + return "", errors.Wrap(errors.New("unable to find value from variable"), fmt.Sprint(as)) +} + +func (v *Visitor) addVariable(bn string, as *ast.AssignStmt) error { + bv, err := v.fromVariable(as) + if err != nil { + return nil + } + if len(bn) == 0 { + bn = bv + } + v.addBox(bn, bv) + return nil +} + +func (v *Visitor) fromConstant(vs *ast.ValueSpec) (string, error) { + if len(vs.Values) == 1 { + if bs, ok := vs.Values[0].(*ast.BasicLit); ok { + return bs.Value, nil + } + } + return "", errors.Wrap(errors.New("unable to find value from constant"), fmt.Sprint(vs)) +} + +func (v *Visitor) addConstant(bn string, vs *ast.ValueSpec) error { + if len(vs.Values) == 1 { + if bs, ok := vs.Values[0].(*ast.BasicLit); ok { + bv := bs.Value + if len(bn) == 0 { + bn = bv + } + v.addBox(bn, bv) + } + } + return nil +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/clean.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/clean.go new file mode 100644 index 0000000000..cfdca4b98b --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/clean.go @@ -0,0 +1,76 @@ +package store + +import ( + "os" + "path/filepath" + "strings" + + "github.com/gobuffalo/packr/v2/jam/parser" + "github.com/pkg/errors" +) + +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 errors.WithStack(err) + } + + boxes, err := p.Run() + if err != nil { + return errors.WithStack(err) + } + + d := NewDisk("", "") + for _, box := range boxes { + if err := d.Clean(box); err != nil { + return errors.WithStack(err) + } + } + return nil +} + +func clean(root string) error { + if len(root) == 0 { + pwd, err := os.Getwd() + if err != nil { + return errors.WithStack(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 errors.WithStack(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 errors.WithStack(err) + } + } + return nil + }) + if err != nil { + return errors.WithStack(err) + } + + return nil +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/disk.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/disk.go new file mode 100644 index 0000000000..0bd4fe7a98 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/disk.go @@ -0,0 +1,328 @@ +package store + +import ( + "bytes" + "compress/gzip" + "context" + "crypto/md5" + "fmt" + "go/build" + "html/template" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "strings" + "sync" + + "github.com/gobuffalo/envy" + "github.com/gobuffalo/genny" + "github.com/gobuffalo/genny/movinglater/gotools" + "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" + "github.com/karrick/godirwalk" + "github.com/pkg/errors" + "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, errors.WithStack(err) + } + for _, n := range names { + b, err := ioutil.ReadFile(n) + if err != nil { + return files, errors.WithStack(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 errors.WithStack(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 errors.New("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 +} + +func (d *Disk) Generator() (*genny.Generator, error) { + g := genny.New() + + 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 errors.WithStack(err) + } + defer f.Close() + io.Copy(zw, f) + if err := zw.Close(); err != nil { + return errors.WithStack(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 g, errors.WithStack(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 + }) + + t := gotools.TemplateTransformer(opts, template.FuncMap{ + "printBox": func(ob optsBox) (template.HTML, error) { + box := d.boxes[ob.Name] + if box == nil { + return "", errors.Errorf("could not find box %s", ob.Name) + } + fn, err := d.FileNames(box) + if err != nil { + return "", errors.WithStack(err) + } + if len(fn) == 0 { + return "", nil + } + + type file struct { + Resolver string + ForwardPath string + } + + gf := genny.NewFile("box.go.tmpl", strings.NewReader(diskGlobalBoxTmpl)) + 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, + } + t := gotools.TemplateTransformer(opts, nil) + gf, err = t.Transform(gf) + if err != nil { + return "", errors.WithStack(err) + } + return template.HTML(gf.String()), nil + }, + }) + g.Transformer(t) + + fp := filepath.Join(d.DBPath, "packed-packr.go.tmpl") + global := genny.NewFile(fp, strings.NewReader(diskGlobalTmpl)) + global, err := t.Transform(global) + if err != nil { + return g, errors.WithStack(err) + } + + ft := gotools.FmtTransformer() + global, err = ft.Transform(global) + if err != nil { + return g, errors.WithStack(err) + } + g.File(global) + + var ip string + if envy.Mods() { + 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 g, errors.New("go.mod cannot be read or does not exist while go module is enabled.") + } + ip = modfile.ModulePath(moddata) + if ip == "" { + return g, errors.New("go.mod is malformed.") + } + } else { + ip = filepath.Dir(d.DBPath) + srcs := build.Default.SrcDirs() + srcs = append(srcs, envy.GoPaths()...) + 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.tmpl") + f := genny.NewFile(p, strings.NewReader(diskImportTmpl)) + + o := struct { + Package string + Import string + }{ + Package: b.Package, + Import: ip, + } + + t := gotools.TemplateTransformer(o, template.FuncMap{}) + f, err := t.Transform(f) + if err != nil { + return g, nil + } + g.File(f) + } + + return g, nil +} + +func (d *Disk) Close() error { + plog.Debug(d, "Close") + run := genny.WetRunner(context.Background()) + run.Logger = plog.Logger + if err := run.WithNew(d.Generator()); err != nil { + return errors.WithStack(err) + } + return run.Run() +} + +// 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 +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/disk_tmpl.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/disk_tmpl.go new file mode 100644 index 0000000000..bc29d48653 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/disk_tmpl.go @@ -0,0 +1,50 @@ +package store + +const diskGlobalTmpl = `// 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 = `// 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 -}} + }() +` diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/env.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/env.go new file mode 100644 index 0000000000..9a65e6dfa2 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/env.go @@ -0,0 +1,39 @@ +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 +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/fn.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/fn.go new file mode 100644 index 0000000000..e71aaac824 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/fn.go @@ -0,0 +1,44 @@ +package store + +import ( + "errors" + + "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{}, errors.New("FileNames not implemented") + } + return f.FileNames(box) +} + +func (f *FnStore) Files(box *parser.Box) ([]*parser.File, error) { + if f.FilesFn == nil { + return []*parser.File{}, errors.New("Files not implemented") + } + return f.FilesFn(box) +} + +func (f *FnStore) Pack(box *parser.Box) error { + if f.PackFn == nil { + return errors.New("Pack not implemented") + } + return f.PackFn(box) +} + +func (f *FnStore) Clean(box *parser.Box) error { + if f.CleanFn == nil { + return errors.New("Clean not implemented") + } + return f.Clean(box) +} diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/legacy.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/legacy.go new file mode 100644 index 0000000000..c1ee411a1c --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/legacy.go @@ -0,0 +1,140 @@ +package store + +import ( + "bytes" + "context" + "encoding/json" + "io" + "path/filepath" + "sort" + "strings" + + "github.com/pkg/errors" + + "github.com/gobuffalo/genny" + "github.com/gobuffalo/genny/movinglater/gotools" + "github.com/gobuffalo/packr/v2/jam/parser" + "github.com/gobuffalo/packr/v2/plog" +) + +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 errors.WithStack(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 errors.WithStack(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 + + // run := genny.WetRunner(context.Background()) + // if err := run.WithNew(l.Generator(box)); err != nil { + // return errors.WithStack(err) + // } + // run.Logger = plog.Logger + // return run.Run() +} + +func (l *Legacy) prepFile(r io.Reader) (string, error) { + bb := &bytes.Buffer{} + if _, err := io.Copy(bb, r); err != nil { + return "", errors.WithStack(err) + } + b, err := json.Marshal(bb.Bytes()) + if err != nil { + return "", errors.WithStack(err) + } + return strings.Replace(string(b), "\"", "\\\"", -1), nil +} + +func (l *Legacy) Generator() (*genny.Generator, error) { + g := genny.New() + 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, + } + f := genny.NewFile(filepath.Join(bx.PackageDir, "a_"+bx.Package+"-packr.go.tmpl"), strings.NewReader(legacyTmpl)) + t := gotools.TemplateTransformer(opts, nil) + f, err := t.Transform(f) + if err != nil { + return g, errors.WithStack(err) + } + g.File(f) + } + return g, nil +} + +func (l *Legacy) Close() error { + run := genny.WetRunner(context.Background()) + if err := run.WithNew(l.Generator()); err != nil { + return errors.WithStack(err) + } + run.Logger = plog.Logger + return run.Run() +} + +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 }} +} +` diff --git a/vendor/github.com/gobuffalo/packr/v2/jam/store/store.go b/vendor/github.com/gobuffalo/packr/v2/jam/store/store.go new file mode 100644 index 0000000000..35c0781fce --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/jam/store/store.go @@ -0,0 +1,12 @@ +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 +} diff --git a/vendor/github.com/gobuffalo/packr/v2/plog/plog.go b/vendor/github.com/gobuffalo/packr/v2/plog/plog.go new file mode 100644 index 0000000000..8b1eec1090 --- /dev/null +++ b/vendor/github.com/gobuffalo/packr/v2/plog/plog.go @@ -0,0 +1,41 @@ +package plog + +import ( + "encoding/json" + "fmt" + + "github.com/gobuffalo/logger" + "github.com/sirupsen/logrus" +) + +var Logger = logger.New(logger.ErrorLevel) + +func Debug(t interface{}, m string, args ...interface{}) { + if len(args)%2 == 1 { + args = append(args, "") + } + f := logrus.Fields{} + for i := 0; i < len(args); i += 2 { + k := fmt.Sprint(args[i]) + v := args[i+1] + if s, ok := v.(fmt.Stringer); ok { + f[k] = s.String() + continue + } + if s, ok := v.(string); ok { + f[k] = s + continue + } + if b, err := json.Marshal(v); err == nil { + f[k] = string(b) + continue + } + f[k] = v + } + e := Logger.WithFields(f) + if s, ok := t.(string); ok { + e.Debugf("%s#%s", s, m) + return + } + e.Debugf("%T#%s", t, m) +} diff --git a/vendor/github.com/inconshreveable/mousetrap/LICENSE b/vendor/github.com/inconshreveable/mousetrap/LICENSE new file mode 100644 index 0000000000..5f0d1fb6a7 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/LICENSE @@ -0,0 +1,13 @@ +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. diff --git a/vendor/github.com/inconshreveable/mousetrap/README.md b/vendor/github.com/inconshreveable/mousetrap/README.md new file mode 100644 index 0000000000..7a950d1774 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/README.md @@ -0,0 +1,23 @@ +# 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) diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go new file mode 100644 index 0000000000..9d2d8a4bab --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -0,0 +1,15 @@ +// +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 +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go new file mode 100644 index 0000000000..336142a5e3 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -0,0 +1,98 @@ +// +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" +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go new file mode 100644 index 0000000000..9a28e57c3c --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go @@ -0,0 +1,46 @@ +// +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[:]) +} diff --git a/vendor/github.com/karrick/godirwalk/.gitignore b/vendor/github.com/karrick/godirwalk/.gitignore new file mode 100644 index 0000000000..a1338d6851 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/.gitignore @@ -0,0 +1,14 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ diff --git a/vendor/github.com/karrick/godirwalk/LICENSE b/vendor/github.com/karrick/godirwalk/LICENSE new file mode 100644 index 0000000000..01ce194c80 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2017, Karrick McDermott +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. + +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 HOLDER 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. diff --git a/vendor/github.com/karrick/godirwalk/README.md b/vendor/github.com/karrick/godirwalk/README.md new file mode 100644 index 0000000000..4f9922fefb --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/README.md @@ -0,0 +1,208 @@ +# godirwalk + +`godirwalk` is a library for traversing a directory tree on a file +system. + +In short, why do I use this library? + +1. It's faster than `filepath.Walk`. +1. It's more correct on Windows than `filepath.Walk`. +1. It's more easy to use than `filepath.Walk`. +1. It's more flexible than `filepath.Walk`. + +## Usage Example + +Additional examples are provided in the `examples/` subdirectory. + +This library will normalize the provided top level directory name +based on the os-specific path separator by calling `filepath.Clean` on +its first argument. However it always provides the pathname created by +using the correct os-specific path separator when invoking the +provided callback function. + +```Go + dirname := "some/directory/root" + err := godirwalk.Walk(dirname, &godirwalk.Options{ + Callback: func(osPathname string, de *godirwalk.Dirent) error { + fmt.Printf("%s %s\n", de.ModeType(), osPathname) + return nil + }, + Unsorted: true, // (optional) set true for faster yet non-deterministic enumeration (see godoc) + }) +``` + +This library not only provides functions for traversing a file system +directory tree, but also for obtaining a list of immediate descendants +of a particular directory, typically much more quickly than using +`os.ReadDir` or `os.ReadDirnames`. + +Documentation is available via +[![GoDoc](https://godoc.org/github.com/karrick/godirwalk?status.svg)](https://godoc.org/github.com/karrick/godirwalk). + +## Description + +Here's why I use `godirwalk` in preference to `filepath.Walk`, +`os.ReadDir`, and `os.ReadDirnames`. + +### It's faster than `filepath.Walk` + +When compared against `filepath.Walk` in benchmarks, it has been +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 +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 +you nearly the same output. This library calls the same `syscall` +functions to do the work, but it makes fewer calls, does not throw +away information that it might need, and creates less memory churn +along the way by reusing the same scratch buffer rather than +reallocating a new buffer every time it reads data from the operating +system. + +While traversing a file system directory tree, `filepath.Walk` obtains +the list of immediate descendants of a directory, and throws away the +file system node type information provided by the operating system +that comes with the node's name. Then, immediately prior to invoking +the callback function, `filepath.Walk` invokes `os.Stat` for each +node, and passes the returned `os.FileInfo` information to the +callback. + +While the `os.FileInfo` information provided by `os.Stat` is extremely +helpful--and even includes the `os.FileMode` data--providing it +requires an additional system call for each node. + +Because most callbacks only care about what the node type is, this +library does not throw the type information away, but rather provides +that information to the callback function in the form of a +`os.FileMode` value. Note that the provided `os.FileMode` value that +this library provides only has the node type information, and does not +have the permission bits, sticky bits, or other information from the +file's mode. If the callback does care about a particular node's +entire `os.FileInfo` data structure, the callback can easiy invoke +`os.Stat` when needed, and only when needed. + +#### Benchmarks + +##### macOS + +```Bash +go test -bench=. +goos: darwin +goarch: amd64 +pkg: github.com/karrick/godirwalk +BenchmarkFilepathWalk-8 1 3001274570 ns/op +BenchmarkGoDirWalk-8 3 465573172 ns/op +BenchmarkFlameGraphFilepathWalk-8 1 6957916936 ns/op +BenchmarkFlameGraphGoDirWalk-8 1 4210582571 ns/op +PASS +ok github.com/karrick/godirwalk 16.822s +``` + +##### Linux + +```Bash +go test -bench=. +goos: linux +goarch: amd64 +pkg: github.com/karrick/godirwalk +BenchmarkFilepathWalk-12 1 1609189170 ns/op +BenchmarkGoDirWalk-12 5 211336628 ns/op +BenchmarkFlameGraphFilepathWalk-12 1 3968119932 ns/op +BenchmarkFlameGraphGoDirWalk-12 1 2139598998 ns/op +PASS +ok github.com/karrick/godirwalk 9.007s +``` + +### It's more correct on Windows than `filepath.Walk` + +I did not previously care about this either, but humor me. We all love +how we can write once and run everywhere. It is essential for the +language's adoption, growth, and success, that the software we create +can run unmodified on all architectures and operating systems +supported by Go. + +When the traversed file system has a logical loop caused by symbolic +links to directories, on unix `filepath.Walk` ignores symbolic links +and traverses the entire directory tree without error. On Windows +however, `filepath.Walk` will continue following directory symbolic +links, even though it is not supposed to, eventually causing +`filepath.Walk` to terminate early and return an error when the +pathname gets too long from concatenating endless loops of symbolic +links onto the pathname. This error comes from Windows, passes through +`filepath.Walk`, and to the upstream client running `filepath.Walk`. + +The takeaway is that behavior is different based on which platform +`filepath.Walk` is running. While this is clearly not intentional, +until it is fixed in the standard library, it presents a compatibility +problem. + +This library correctly identifies symbolic links that point to +directories and will only follow them when `FollowSymbolicLinks` is +set to true. Behavior on Windows and other operating systems is +identical. + +### It's more easy to use than `filepath.Walk` + +Since this library does not invoke `os.Stat` on every file system node +it encounters, there is no possible error event for the callback +function to filter on. The third argument in the `filepath.WalkFunc` +function signature to pass the error from `os.Stat` to the callback +function is no longer necessary, and thus eliminated from signature of +the callback function from this library. + +Also, `filepath.Walk` invokes the callback function with a solidus +delimited pathname regardless of the os-specific path separator. This +library invokes the callback function 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 +callback with `some/path/to/foo.txt`, requiring well written clients +to perform pathname normalization for every file prior to working with +the specified file. In truth, many clients developed on unix and not +tested on Windows neglect this subtlety, and will result in software +bugs when running on Windows. This library would invoke 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. + +### It's more flexible than `filepath.Walk` + +#### Configurable Handling of Symbolic Links + +The default behavior of this library is to ignore symbolic links to +directories when walking a directory tree, just like `filepath.Walk` +does. However, it does invoke the callback function with each node it +finds, including symbolic links. If a particular use case exists to +follow symbolic links when traversing a directory tree, this library +can be invoked in manner to do so, by setting the +`FollowSymbolicLinks` parameter to true. + +#### Configurable Sorting of Directory Children + +The default behavior of this library is to always sort the immediate +descendants of a directory prior to visiting each node, just like +`filepath.Walk` does. This is usually the desired behavior. However, +this does come at a performance penalty to sort the names when a +directory node has many entries. If a particular use case exists that +does not require sorting the directory's immediate descendants prior +to visiting its nodes, this library will skip the sorting step when +the `Unsorted` parameter is set to true. + +#### Configurable Post Children Callback + +This library provides upstream code with the ability to specify a +callback to be invoked for each directory after its children are +processed. This has been used to recursively delete empty directories +after traversing the file system in a more efficient manner. See the +`examples/clean-empties` directory for an example of this usage. + +#### Configurable Error Callback + +This library provides upstream code with the ability to specify a +callback to be invoked for errors that the operating system returns, +allowing the upstream code to determine the next course of action to +take, whether to halt walking the hierarchy, as it would do were no +error callback provided, or skip the node that caused the error. See +the `examples/walk-fast` directory for an example of this usage. diff --git a/vendor/github.com/karrick/godirwalk/dirent.go b/vendor/github.com/karrick/godirwalk/dirent.go new file mode 100644 index 0000000000..5a27722480 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/dirent.go @@ -0,0 +1,74 @@ +package godirwalk + +import ( + "os" + "path/filepath" + + "github.com/pkg/errors" +) + +// Dirent stores the name and file system mode type of discovered file system +// entries. +type Dirent struct { + name string + modeType os.FileMode +} + +// NewDirent returns a newly initialized Dirent structure, or an error. This +// function does not follow symbolic links. +// +// This function is rarely used, as Dirent structures are provided by other +// functions in this library that read and walk directories. +func NewDirent(osPathname string) (*Dirent, error) { + fi, err := os.Lstat(osPathname) + if err != nil { + return nil, errors.Wrap(err, "cannot lstat") + } + return &Dirent{ + name: filepath.Base(osPathname), + modeType: fi.Mode() & os.ModeType, + }, nil +} + +// Name returns the basename of the file system entry. +func (de Dirent) Name() string { return de.name } + +// ModeType returns the mode bits that specify the file system node type. We +// could make our own enum-like data type for encoding the file type, but Go's +// runtime already gives us architecture independent file modes, as discussed in +// `os/types.go`: +// +// Go's runtime FileMode type has same definition on all systems, so that +// information about files can be moved from one system to another portably. +func (de Dirent) ModeType() os.FileMode { return de.modeType } + +// IsDir returns true if and only if the Dirent represents a file system +// directory. Note that on some operating systems, more than one file mode bit +// may be set for a node. For instance, on Windows, a symbolic link that points +// to a directory will have both the directory and the symbolic link bits set. +func (de Dirent) IsDir() bool { return de.modeType&os.ModeDir != 0 } + +// IsRegular returns true if and only if the Dirent represents a regular +// file. That is, it ensures that no mode type bits are set. +func (de Dirent) IsRegular() bool { return de.modeType&os.ModeType == 0 } + +// IsSymlink returns true if and only if the Dirent represents a file system +// symbolic link. Note that on some operating systems, more than one file mode +// bit may be set for a node. For instance, on Windows, a symbolic link that +// points to a directory will have both the directory and the symbolic link bits +// set. +func (de Dirent) IsSymlink() bool { return de.modeType&os.ModeSymlink != 0 } + +// Dirents represents a slice of Dirent pointers, which are sortable by +// name. This type satisfies the `sort.Interface` interface. +type Dirents []*Dirent + +// Len returns the count of Dirent structures in the slice. +func (l Dirents) Len() int { return len(l) } + +// Less returns true if and only if the Name of the element specified by the +// first index is lexicographically less than that of the second index. +func (l Dirents) Less(i, j int) bool { return l[i].name < l[j].name } + +// Swap exchanges the two Dirent entries specified by the two provided indexes. +func (l Dirents) Swap(i, j int) { l[i], l[j] = l[j], l[i] } diff --git a/vendor/github.com/karrick/godirwalk/doc.go b/vendor/github.com/karrick/godirwalk/doc.go new file mode 100644 index 0000000000..0dfdabd488 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/doc.go @@ -0,0 +1,34 @@ +/* +Package godirwalk provides functions to read and traverse directory trees. + +In short, why do I use this library? + +* It's faster than `filepath.Walk`. + +* It's more correct on Windows than `filepath.Walk`. + +* It's more easy to use than `filepath.Walk`. + +* It's more flexible than `filepath.Walk`. + +USAGE + +This library will normalize the provided top level directory name based on the +os-specific path separator by calling `filepath.Clean` on its first +argument. However it always provides the pathname created by using the correct +os-specific path separator when invoking the provided callback function. + + dirname := "some/directory/root" + err := godirwalk.Walk(dirname, &godirwalk.Options{ + Callback: func(osPathname string, de *godirwalk.Dirent) error { + fmt.Printf("%s %s\n", de.ModeType(), osPathname) + return nil + }, + }) + +This library not only provides functions for traversing a file system directory +tree, but also for obtaining a list of immediate descendants of a particular +directory, typically much more quickly than using `os.ReadDir` or +`os.ReadDirnames`. +*/ +package godirwalk diff --git a/vendor/github.com/karrick/godirwalk/readdir.go b/vendor/github.com/karrick/godirwalk/readdir.go new file mode 100644 index 0000000000..2bba689751 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/readdir.go @@ -0,0 +1,47 @@ +package godirwalk + +// ReadDirents returns a sortable slice of pointers to Dirent structures, each +// representing the file system name and mode type for one of the immediate +// descendant of the specified directory. If the specified directory is a +// symbolic link, it will be resolved. +// +// If an optional scratch buffer is provided that is at least one page of +// memory, it will be used when reading directory entries from the file system. +// +// children, err := godirwalk.ReadDirents(osDirname, nil) +// if err != nil { +// return nil, errors.Wrap(err, "cannot get list of directory children") +// } +// sort.Sort(children) +// for _, child := range children { +// fmt.Printf("%s %s\n", child.ModeType, child.Name) +// } +func ReadDirents(osDirname string, scratchBuffer []byte) (Dirents, error) { + return readdirents(osDirname, scratchBuffer) +} + +// ReadDirnames returns a slice of strings, representing the immediate +// descendants of the specified directory. If the specified directory is a +// symbolic link, it will be resolved. +// +// If an optional scratch buffer is provided that is at least one page of +// memory, it will be used when reading directory entries from the file system. +// +// Note that this function, depending on operating system, may or may not invoke +// the ReadDirents function, in order to prepare the list of immediate +// descendants. Therefore, if your program needs both the names and the file +// system mode types of descendants, it will always be faster to invoke +// ReadDirents directly, rather than calling this function, then looping over +// the results and calling os.Stat for each child. +// +// children, err := godirwalk.ReadDirnames(osDirname, nil) +// if err != nil { +// return nil, errors.Wrap(err, "cannot get list of directory children") +// } +// sort.Strings(children) +// for _, child := range children { +// fmt.Printf("%s\n", child) +// } +func ReadDirnames(osDirname string, scratchBuffer []byte) ([]string, error) { + return readdirnames(osDirname, scratchBuffer) +} diff --git a/vendor/github.com/karrick/godirwalk/readdir_unix.go b/vendor/github.com/karrick/godirwalk/readdir_unix.go new file mode 100644 index 0000000000..04a628f7fc --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/readdir_unix.go @@ -0,0 +1,109 @@ +// +build darwin freebsd linux netbsd openbsd + +package godirwalk + +import ( + "os" + "path/filepath" + "syscall" + "unsafe" + + "github.com/pkg/errors" +) + +func readdirents(osDirname string, scratchBuffer []byte) (Dirents, error) { + dh, err := os.Open(osDirname) + if err != nil { + return nil, errors.Wrap(err, "cannot Open") + } + + var entries Dirents + + fd := int(dh.Fd()) + + if len(scratchBuffer) < MinimumScratchBufferSize { + scratchBuffer = make([]byte, DefaultScratchBufferSize) + } + + var de *syscall.Dirent + + for { + n, err := syscall.ReadDirent(fd, scratchBuffer) + if err != nil { + _ = dh.Close() // ignore potential error returned by Close + return nil, errors.Wrap(err, "cannot ReadDirent") + } + if n <= 0 { + break // end of directory reached + } + // Loop over the bytes returned by reading the directory entries. + buf := scratchBuffer[:n] + for len(buf) > 0 { + de = (*syscall.Dirent)(unsafe.Pointer(&buf[0])) // point entry to first syscall.Dirent in buffer + buf = buf[de.Reclen:] // advance buffer + + if inoFromDirent(de) == 0 { + continue // this item has been deleted, but not yet removed from directory + } + + nameSlice := nameFromDirent(de) + namlen := len(nameSlice) + if (namlen == 0) || (namlen == 1 && nameSlice[0] == '.') || (namlen == 2 && nameSlice[0] == '.' && nameSlice[1] == '.') { + continue // skip unimportant entries + } + osChildname := string(nameSlice) + + // Convert syscall constant, which is in purview of OS, to a + // constant defined by Go, assumed by this project to be stable. + var mode os.FileMode + switch de.Type { + case syscall.DT_REG: + // regular file + case syscall.DT_DIR: + mode = os.ModeDir + case syscall.DT_LNK: + mode = os.ModeSymlink + case syscall.DT_CHR: + mode = os.ModeDevice | os.ModeCharDevice + case syscall.DT_BLK: + mode = os.ModeDevice + case syscall.DT_FIFO: + mode = os.ModeNamedPipe + case syscall.DT_SOCK: + mode = os.ModeSocket + default: + // If syscall returned unknown type (e.g., DT_UNKNOWN, DT_WHT), + // then resolve actual mode by getting stat. + fi, err := os.Lstat(filepath.Join(osDirname, osChildname)) + if err != nil { + _ = dh.Close() // ignore potential error returned by Close + return nil, errors.Wrap(err, "cannot Stat") + } + // We only care about the bits that identify the type of a file + // system node, and can ignore append, exclusive, temporary, + // setuid, setgid, permission bits, and sticky bits, which are + // coincident to the bits that declare type of the file system + // node. + mode = fi.Mode() & os.ModeType + } + + entries = append(entries, &Dirent{name: osChildname, modeType: mode}) + } + } + if err = dh.Close(); err != nil { + return nil, err + } + return entries, nil +} + +func readdirnames(osDirname string, scratchBuffer []byte) ([]string, error) { + des, err := readdirents(osDirname, scratchBuffer) + if err != nil { + return nil, err + } + names := make([]string, len(des)) + for i, v := range des { + names[i] = v.name + } + return names, nil +} diff --git a/vendor/github.com/karrick/godirwalk/readdir_windows.go b/vendor/github.com/karrick/godirwalk/readdir_windows.go new file mode 100644 index 0000000000..885a067a4b --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/readdir_windows.go @@ -0,0 +1,54 @@ +package godirwalk + +import ( + "os" + + "github.com/pkg/errors" +) + +// The functions in this file are mere wrappers of what is already provided by +// standard library, in order to provide the same API as this library provides. +// +// The scratch buffer argument is ignored by this architecture. +// +// Please send PR or link to article if you know of a more performant way of +// enumerating directory contents and mode types on Windows. + +func readdirents(osDirname string, _ []byte) (Dirents, error) { + dh, err := os.Open(osDirname) + if err != nil { + return nil, errors.Wrap(err, "cannot Open") + } + + fileinfos, err := dh.Readdir(0) + if er := dh.Close(); err == nil { + err = er + } + if err != nil { + return nil, errors.Wrap(err, "cannot Readdir") + } + + entries := make(Dirents, len(fileinfos)) + for i, info := range fileinfos { + entries[i] = &Dirent{name: info.Name(), modeType: info.Mode() & os.ModeType} + } + + return entries, nil +} + +func readdirnames(osDirname string, _ []byte) ([]string, error) { + dh, err := os.Open(osDirname) + if err != nil { + return nil, errors.Wrap(err, "cannot Open") + } + + entries, err := dh.Readdirnames(0) + if er := dh.Close(); err == nil { + err = er + } + if err != nil { + return nil, errors.Wrap(err, "cannot Readdirnames") + } + + return entries, nil +} diff --git a/vendor/github.com/karrick/godirwalk/walk.go b/vendor/github.com/karrick/godirwalk/walk.go new file mode 100644 index 0000000000..4c184ab87e --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/walk.go @@ -0,0 +1,367 @@ +package godirwalk + +import ( + "os" + "path/filepath" + "sort" + + "github.com/pkg/errors" +) + +// DefaultScratchBufferSize specifies the size of the scratch buffer that will +// be allocated by Walk, ReadDirents, or ReadDirnames when a scratch buffer is +// not provided or the scratch buffer that is provided is smaller than +// MinimumScratchBufferSize bytes. This may seem like a large value; however, +// when a program intends to enumerate large directories, having a larger +// scratch buffer results in fewer operating system calls. +const DefaultScratchBufferSize = 64 * 1024 + +// MinimumScratchBufferSize specifies the minimum size of the scratch buffer +// that Walk, ReadDirents, and ReadDirnames will use when reading file entries +// from the operating system. It is initialized to the result from calling +// `os.Getpagesize()` during program startup. +var MinimumScratchBufferSize int + +func init() { + MinimumScratchBufferSize = os.Getpagesize() +} + +// Options provide parameters for how the Walk function operates. +type Options struct { + // ErrorCallback specifies a function to be invoked in the case of an error + // that could potentially be ignored while walking a file system + // hierarchy. When set to nil or left as its zero-value, any error condition + // causes Walk to immediately return the error describing what took + // place. When non-nil, this user supplied function is invoked with the OS + // pathname of the file system object that caused the error along with the + // error that took place. The return value of the supplied ErrorCallback + // function determines whether the error will cause Walk to halt immediately + // as it would were no ErrorCallback value provided, or skip this file + // system node yet continue on with the remaining nodes in the file system + // hierarchy. + // + // ErrorCallback is invoked both for errors that are returned by the + // runtime, and for errors returned by other user supplied callback + // functions. + ErrorCallback func(string, error) ErrorAction + + // FollowSymbolicLinks specifies whether Walk will follow symbolic links + // that refer to directories. When set to false or left as its zero-value, + // Walk will still invoke the callback function with symbolic link nodes, + // but if the symbolic link refers to a directory, it will not recurse on + // that directory. When set to true, Walk will recurse on symbolic links + // that refer to a directory. + FollowSymbolicLinks bool + + // Unsorted controls whether or not Walk will sort the immediate descendants + // of a directory by their relative names prior to visiting each of those + // entries. + // + // When set to false or left at its zero-value, Walk will get the list of + // immediate descendants of a particular directory, sort that list by + // lexical order of their names, and then visit each node in the list in + // sorted order. This will cause Walk to always traverse the same directory + // tree in the same order, however may be inefficient for directories with + // many immediate descendants. + // + // When set to true, Walk skips sorting the list of immediate descendants + // for a directory, and simply visits each node in the order the operating + // system enumerated them. This will be more fast, but with the side effect + // that the traversal order may be different from one invocation to the + // next. + Unsorted bool + + // Callback is a required function that Walk will invoke for every file + // system node it encounters. + Callback WalkFunc + + // PostChildrenCallback is an option function that Walk will invoke for + // every file system directory it encounters after its children have been + // processed. + PostChildrenCallback WalkFunc + + // ScratchBuffer is an optional byte slice to use as a scratch buffer for + // Walk to use when reading directory entries, to reduce amount of garbage + // generation. Not all architectures take advantage of the scratch + // buffer. If omitted or the provided buffer has fewer bytes than + // MinimumScratchBufferSize, then a buffer with DefaultScratchBufferSize + // bytes will be created and used once per Walk invocation. + ScratchBuffer []byte +} + +// ErrorAction defines a set of actions the Walk function could take based on +// the occurrence of an error while walking the file system. See the +// documentation for the ErrorCallback field of the Options structure for more +// information. +type ErrorAction int + +const ( + // Halt is the ErrorAction return value when the upstream code wants to halt + // the walk process when a runtime error takes place. It matches the default + // action the Walk function would take were no ErrorCallback provided. + Halt ErrorAction = iota + + // SkipNode is the ErrorAction return value when the upstream code wants to + // ignore the runtime error for the current file system node, skip + // processing of the node that caused the error, and continue walking the + // file system hierarchy with the remaining nodes. + SkipNode +) + +// 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; +// that is, if Walk is called with "dir", which is a directory containing the +// file "a", the provided WalkFunc will be invoked with the argument "dir/a", +// using the correct os.PathSeparator for the Go Operating System architecture, +// GOOS. The directory entry argument is a pointer to a Dirent for the node, +// providing access to both the basename and the mode type of the file system +// node. +// +// If an error is returned by the Callback or PostChildrenCallback functions, +// and no ErrorCallback function is provided, processing stops. If an +// ErrorCallback function is provided, then it is invoked with the OS pathname +// of the node that caused the error along along with the error. The return +// value of the ErrorCallback function determines whether to halt processing, or +// skip this node and continue processing remaining file system nodes. +// +// The exception is when the function returns the special value +// filepath.SkipDir. If the function returns filepath.SkipDir when invoked on a +// directory, Walk skips the directory's contents entirely. If the function +// returns filepath.SkipDir when invoked on a non-directory file system node, +// Walk skips the remaining files in the containing directory. Note that any +// supplied ErrorCallback function is not invoked with filepath.SkipDir when the +// Callback or PostChildrenCallback functions return that special value. +type WalkFunc func(osPathname string, directoryEntry *Dirent) error + +// Walk walks the file tree rooted at the specified directory, calling the +// specified callback function for each file system node in the tree, including +// root, symbolic links, and other node types. The nodes are walked in lexical +// order, which makes the output deterministic but means that for very large +// directories this function can be inefficient. +// +// This function is often much faster than filepath.Walk because it does not +// invoke os.Stat for every node it encounters, but rather obtains the file +// system node type when it reads the parent directory. +// +// If a runtime error occurs, either from the operating system or from the +// upstream Callback or PostChildrenCallback functions, processing typically +// halts. However, when an ErrorCallback function is provided in the provided +// Options structure, that function is invoked with the error along with the OS +// pathname of the file system node that caused the error. The ErrorCallback +// function's return value determines the action that Walk will then take. +// +// func main() { +// dirname := "." +// if len(os.Args) > 1 { +// dirname = os.Args[1] +// } +// err := godirwalk.Walk(dirname, &godirwalk.Options{ +// Callback: func(osPathname string, de *godirwalk.Dirent) error { +// fmt.Printf("%s %s\n", de.ModeType(), osPathname) +// return nil +// }, +// ErrorCallback: func(osPathname string, err error) godirwalk.ErrorAction { +// // Your program may want to log the error somehow. +// fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) +// +// // For the purposes of this example, a simple SkipNode will suffice, +// // although in reality perhaps additional logic might be called for. +// return godirwalk.SkipNode +// }, +// }) +// if err != nil { +// fmt.Fprintf(os.Stderr, "%s\n", err) +// os.Exit(1) +// } +// } +func Walk(pathname string, options *Options) error { + pathname = filepath.Clean(pathname) + + var fi os.FileInfo + var err error + + if options.FollowSymbolicLinks { + fi, err = os.Stat(pathname) + if err != nil { + return errors.Wrap(err, "cannot Stat") + } + } else { + fi, err = os.Lstat(pathname) + if err != nil { + return errors.Wrap(err, "cannot Lstat") + } + } + + mode := fi.Mode() + if mode&os.ModeDir == 0 { + return errors.Errorf("cannot Walk non-directory: %s", pathname) + } + + dirent := &Dirent{ + name: filepath.Base(pathname), + modeType: mode & os.ModeType, + } + + // If ErrorCallback is nil, set to a default value that halts the walk + // process on all operating system errors. This is done to allow error + // handling to be more succinct in the walk code. + if options.ErrorCallback == nil { + options.ErrorCallback = defaultErrorCallback + } + + if len(options.ScratchBuffer) < MinimumScratchBufferSize { + options.ScratchBuffer = make([]byte, DefaultScratchBufferSize) + } + + err = walk(pathname, dirent, options) + if err == filepath.SkipDir { + return nil // silence SkipDir for top level + } + return err +} + +// defaultErrorCallback always returns Halt because if the upstream code did not +// provide an ErrorCallback function, walking the file system hierarchy ought to +// halt upon any operating system error. +func defaultErrorCallback(_ string, _ error) ErrorAction { return Halt } + +// walk recursively traverses the file system node specified by pathname and the +// Dirent. +func walk(osPathname string, dirent *Dirent, options *Options) error { + err := options.Callback(osPathname, dirent) + if err != nil { + if err == filepath.SkipDir { + return err + } + err = errors.Wrap(err, "Callback") // wrap potential errors returned by callback + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + + // On some platforms, an entry can have more than one mode type bit set. + // For instance, it could have both the symlink bit and the directory bit + // set indicating it's a symlink to a directory. + if dirent.IsSymlink() { + if !options.FollowSymbolicLinks { + return nil + } + // Only need to Stat entry if platform did not already have os.ModeDir + // set, such as would be the case for unix like operating systems. (This + // guard eliminates extra os.Stat check on Windows.) + if !dirent.IsDir() { + referent, err := os.Readlink(osPathname) + if err != nil { + err = errors.Wrap(err, "cannot Readlink") + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + + var osp string + if filepath.IsAbs(referent) { + osp = referent + } else { + osp = filepath.Join(filepath.Dir(osPathname), referent) + } + + fi, err := os.Stat(osp) + if err != nil { + err = errors.Wrap(err, "cannot Stat") + if action := options.ErrorCallback(osp, err); action == SkipNode { + return nil + } + return err + } + dirent.modeType = fi.Mode() & os.ModeType + } + } + + if !dirent.IsDir() { + return nil + } + + // If get here, then specified pathname refers to a directory. + deChildren, err := ReadDirents(osPathname, options.ScratchBuffer) + if err != nil { + err = errors.Wrap(err, "cannot ReadDirents") + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + + if !options.Unsorted { + sort.Sort(deChildren) // sort children entries unless upstream says to leave unsorted + } + + for _, deChild := range deChildren { + osChildname := filepath.Join(osPathname, deChild.name) + err = walk(osChildname, deChild, options) + if err != nil { + if err != filepath.SkipDir { + return err + } + // If received skipdir on a directory, stop processing that + // directory, but continue to its siblings. If received skipdir on a + // non-directory, stop processing remaining siblings. + if deChild.IsSymlink() { + // Only need to Stat entry if platform did not already have + // os.ModeDir set, such as would be the case for unix like + // operating systems. (This guard eliminates extra os.Stat check + // on Windows.) + if !deChild.IsDir() { + // Resolve symbolic link referent to determine whether node + // is directory or not. + referent, err := os.Readlink(osChildname) + if err != nil { + err = errors.Wrap(err, "cannot Readlink") + if action := options.ErrorCallback(osChildname, err); action == SkipNode { + continue // with next child + } + return err + } + + var osp string + if filepath.IsAbs(referent) { + osp = referent + } else { + osp = filepath.Join(osPathname, referent) + } + + fi, err := os.Stat(osp) + if err != nil { + err = errors.Wrap(err, "cannot Stat") + if action := options.ErrorCallback(osp, err); action == SkipNode { + continue // with next child + } + return err + } + deChild.modeType = fi.Mode() & os.ModeType + } + } + if !deChild.IsDir() { + // If not directory, return immediately, thus skipping remainder + // of siblings. + return nil + } + } + } + + if options.PostChildrenCallback == nil { + return nil + } + + err = options.PostChildrenCallback(osPathname, dirent) + if err == nil || err == filepath.SkipDir { + return err + } + + err = errors.Wrap(err, "PostChildrenCallback") // wrap potential errors returned by callback + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err +} diff --git a/vendor/github.com/karrick/godirwalk/withFileno.go b/vendor/github.com/karrick/godirwalk/withFileno.go new file mode 100644 index 0000000000..1dc04a717a --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/withFileno.go @@ -0,0 +1,9 @@ +// +build dragonfly freebsd openbsd netbsd + +package godirwalk + +import "syscall" + +func inoFromDirent(de *syscall.Dirent) uint64 { + return uint64(de.Fileno) +} diff --git a/vendor/github.com/karrick/godirwalk/withIno.go b/vendor/github.com/karrick/godirwalk/withIno.go new file mode 100644 index 0000000000..47fc12540f --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/withIno.go @@ -0,0 +1,9 @@ +// +build darwin linux + +package godirwalk + +import "syscall" + +func inoFromDirent(de *syscall.Dirent) uint64 { + return de.Ino +} diff --git a/vendor/github.com/karrick/godirwalk/withNamlen.go b/vendor/github.com/karrick/godirwalk/withNamlen.go new file mode 100644 index 0000000000..46a4af5004 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/withNamlen.go @@ -0,0 +1,29 @@ +// +build darwin dragonfly freebsd netbsd openbsd + +package godirwalk + +import ( + "reflect" + "syscall" + "unsafe" +) + +func nameFromDirent(de *syscall.Dirent) []byte { + // Because this GOOS' syscall.Dirent provides a Namlen field that says how + // long the name is, this function does not need to search for the NULL + // byte. + ml := int(de.Namlen) + + // Convert syscall.Dirent.Name, which is array of int8, to []byte, by + // overwriting Cap, Len, and Data slice header fields to values from + // syscall.Dirent fields. Setting the Cap, Len, and Data field values for + // the slice header modifies what the slice header points to, and in this + // case, the name buffer. + var name []byte + sh := (*reflect.SliceHeader)(unsafe.Pointer(&name)) + sh.Cap = ml + sh.Len = ml + sh.Data = uintptr(unsafe.Pointer(&de.Name[0])) + + return name +} diff --git a/vendor/github.com/karrick/godirwalk/withoutNamlen.go b/vendor/github.com/karrick/godirwalk/withoutNamlen.go new file mode 100644 index 0000000000..dcf9f3a972 --- /dev/null +++ b/vendor/github.com/karrick/godirwalk/withoutNamlen.go @@ -0,0 +1,36 @@ +// +build nacl linux solaris + +package godirwalk + +import ( + "bytes" + "reflect" + "syscall" + "unsafe" +) + +func nameFromDirent(de *syscall.Dirent) []byte { + // Because this GOOS' syscall.Dirent does not provide a field that specifies + // the name length, this function must first calculate the max possible name + // length, and then search for the NULL byte. + ml := int(uint64(de.Reclen) - uint64(unsafe.Offsetof(syscall.Dirent{}.Name))) + + // Convert syscall.Dirent.Name, which is array of int8, to []byte, by + // overwriting Cap, Len, and Data slice header fields to values from + // syscall.Dirent fields. Setting the Cap, Len, and Data field values for + // the slice header modifies what the slice header points to, and in this + // case, the name buffer. + var name []byte + sh := (*reflect.SliceHeader)(unsafe.Pointer(&name)) + sh.Cap = ml + sh.Len = ml + sh.Data = uintptr(unsafe.Pointer(&de.Name[0])) + + if index := bytes.IndexByte(name, 0); index >= 0 { + // Found NULL byte; set slice's cap and len accordingly. + sh.Cap = index + sh.Len = index + } + + return name +} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE new file mode 100644 index 0000000000..14127cd831 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE @@ -0,0 +1,9 @@ +(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. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md new file mode 100644 index 0000000000..09a4a35c9b --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md @@ -0,0 +1,42 @@ +# 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. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go new file mode 100644 index 0000000000..57f530ae83 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go @@ -0,0 +1,35 @@ +// +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 +} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go new file mode 100644 index 0000000000..df61a6f2f6 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go @@ -0,0 +1,11 @@ +// +build linux darwin + +package sequences + +import ( + "fmt" +) + +func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error { + return fmt.Errorf("windows only package") +} diff --git a/vendor/github.com/markbates/oncer/.gitignore b/vendor/github.com/markbates/oncer/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/markbates/oncer/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/markbates/oncer/LICENSE b/vendor/github.com/markbates/oncer/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/markbates/oncer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/markbates/oncer/Makefile b/vendor/github.com/markbates/oncer/Makefile new file mode 100644 index 0000000000..187cb8a3f3 --- /dev/null +++ b/vendor/github.com/markbates/oncer/Makefile @@ -0,0 +1,40 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -v . + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... + $(GO_BIN) mod tidy + +build: + packr + $(GO_BIN) build -v . + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + +ci-test: deps + $(GO_BIN) test -tags ${TAGS} -race ./... + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + +update: + $(GO_BIN) get -u -tags ${TAGS} + $(GO_BIN) mod tidy + packr + make test + make install + $(GO_BIN) mod tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + +release: + release -y -f version.go diff --git a/vendor/github.com/markbates/oncer/deprecate.go b/vendor/github.com/markbates/oncer/deprecate.go new file mode 100644 index 0000000000..4eb3a443e2 --- /dev/null +++ b/vendor/github.com/markbates/oncer/deprecate.go @@ -0,0 +1,20 @@ +package oncer + +import ( + "fmt" + "io" + "os" +) + +const deprecated = "DEPRECATED" + +var deprecationWriter io.Writer = os.Stdout + +func Deprecate(depth int, name string, msg string) { + Do(deprecated+name, func() { + fmt.Fprintf(deprecationWriter, "[%s] %s has been deprecated.\n", deprecated, name) + if len(msg) > 0 { + fmt.Fprintf(deprecationWriter, "\t%s\n", msg) + } + }) +} diff --git a/vendor/github.com/markbates/oncer/log.go b/vendor/github.com/markbates/oncer/log.go new file mode 100644 index 0000000000..ed43463962 --- /dev/null +++ b/vendor/github.com/markbates/oncer/log.go @@ -0,0 +1,7 @@ +//+build !debug + +package oncer + +func log(name string, fn func()) func() { + return fn +} diff --git a/vendor/github.com/markbates/oncer/log_debug.go b/vendor/github.com/markbates/oncer/log_debug.go new file mode 100644 index 0000000000..76d0e11490 --- /dev/null +++ b/vendor/github.com/markbates/oncer/log_debug.go @@ -0,0 +1,19 @@ +//+build debug + +package oncer + +import ( + "fmt" + "time" +) + +func log(name string, fn func()) func() { + return func() { + start := time.Now() + if len(name) > 80 { + name = name[(len(name) - 80):] + } + defer fmt.Println(name, time.Now().Sub(start)) + fn() + } +} diff --git a/vendor/github.com/markbates/oncer/oncer.go b/vendor/github.com/markbates/oncer/oncer.go new file mode 100644 index 0000000000..5b3ab8df0e --- /dev/null +++ b/vendor/github.com/markbates/oncer/oncer.go @@ -0,0 +1,26 @@ +package oncer + +import ( + "sync" +) + +var onces = &sync.Map{} + +func Do(name string, fn func()) { + o, _ := onces.LoadOrStore(name, &sync.Once{}) + if once, ok := o.(*sync.Once); ok { + once.Do(log(name, fn)) + } +} + +func Reset(names ...string) { + if len(names) == 0 { + onces = &sync.Map{} + return + } + + for _, n := range names { + onces.Delete(n) + onces.Delete(deprecated + n) + } +} diff --git a/vendor/github.com/markbates/safe/.gitignore b/vendor/github.com/markbates/safe/.gitignore new file mode 100644 index 0000000000..3689718594 --- /dev/null +++ b/vendor/github.com/markbates/safe/.gitignore @@ -0,0 +1,29 @@ +*.log +.DS_Store +doc +tmp +pkg +*.gem +*.pid +coverage +coverage.data +build/* +*.pbxuser +*.mode1v3 +.svn +profile +.console_history +.sass-cache/* +.rake_tasks~ +*.log.lck +solr/ +.jhw-cache/ +jhw.* +*.sublime* +node_modules/ +dist/ +generated/ +.vendor/ +bin/* +gin-bin +.idea/ diff --git a/vendor/github.com/markbates/safe/.gometalinter.json b/vendor/github.com/markbates/safe/.gometalinter.json new file mode 100644 index 0000000000..e4f65a36e8 --- /dev/null +++ b/vendor/github.com/markbates/safe/.gometalinter.json @@ -0,0 +1,3 @@ +{ + "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"] +} diff --git a/vendor/github.com/markbates/safe/.travis.yml b/vendor/github.com/markbates/safe/.travis.yml new file mode 100644 index 0000000000..cf1d2c7d42 --- /dev/null +++ b/vendor/github.com/markbates/safe/.travis.yml @@ -0,0 +1,26 @@ +language: go + +sudo: false + +matrix: + include: + - go: "1.9.x" + - go: "1.10.x" + - go: "1.11.x" + env: + - GO111MODULE=off + - go: "1.11.x" + env: + - GO111MODULE=on + - go: "tip" + env: + - GO111MODULE=off + - go: "tip" + env: + - GO111MODULE=on + allow_failures: + - go: "tip" + +install: make deps + +script: make ci-test diff --git a/vendor/github.com/markbates/safe/LICENSE b/vendor/github.com/markbates/safe/LICENSE new file mode 100644 index 0000000000..a538bcbf28 --- /dev/null +++ b/vendor/github.com/markbates/safe/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/vendor/github.com/markbates/safe/Makefile b/vendor/github.com/markbates/safe/Makefile new file mode 100644 index 0000000000..e0e2f3baa4 --- /dev/null +++ b/vendor/github.com/markbates/safe/Makefile @@ -0,0 +1,55 @@ +TAGS ?= "sqlite" +GO_BIN ?= go + +install: + packr + $(GO_BIN) install -tags ${TAGS} -v . + make tidy + +tidy: +ifeq ($(GO111MODULE),on) + $(GO_BIN) mod tidy +else + echo skipping go mod tidy +endif + +deps: + $(GO_BIN) get github.com/gobuffalo/release + $(GO_BIN) get github.com/gobuffalo/packr/packr + $(GO_BIN) get -tags ${TAGS} -t ./... + make tidy + +build: + packr + $(GO_BIN) build -v . + make tidy + +test: + packr + $(GO_BIN) test -tags ${TAGS} ./... + make tidy + +ci-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +lint: + gometalinter --vendor ./... --deadline=1m --skip=internal + make tidy + +update: + $(GO_BIN) get -u -tags ${TAGS} + make tidy + packr + make test + make install + make tidy + +release-test: + $(GO_BIN) test -tags ${TAGS} -race ./... + make tidy + +release: + make tidy + release -y -f version.go + make tidy diff --git a/vendor/github.com/markbates/safe/safe.go b/vendor/github.com/markbates/safe/safe.go new file mode 100644 index 0000000000..a40d2083e5 --- /dev/null +++ b/vendor/github.com/markbates/safe/safe.go @@ -0,0 +1,33 @@ +package safe + +import ( + "errors" + "fmt" +) + +// Run the function safely knowing that if it panics +// the panic will be caught and returned as an error +func Run(fn func()) (err error) { + return RunE(func() error { + fn() + return nil + }) +} + +// Run the function safely knowing that if it panics +// the panic will be caught and returned as an error +func RunE(fn func() error) (err error) { + defer func() { + if err != nil { + return + } + if ex := recover(); ex != nil { + if e, ok := ex.(error); ok { + err = e + return + } + err = errors.New(fmt.Sprint(ex)) + } + }() + return fn() +} diff --git a/vendor/github.com/markbates/safe/shoulders.md b/vendor/github.com/markbates/safe/shoulders.md new file mode 100644 index 0000000000..a3821f2ad1 --- /dev/null +++ b/vendor/github.com/markbates/safe/shoulders.md @@ -0,0 +1,8 @@ +# github.com/markbates/safe Stands on the Shoulders of Giants + +github.com/markbates/safe 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**: + + +* [github.com/markbates/safe](https://godoc.org/github.com/markbates/safe) diff --git a/vendor/github.com/markbates/safe/version.go b/vendor/github.com/markbates/safe/version.go new file mode 100644 index 0000000000..e655dc5e3c --- /dev/null +++ b/vendor/github.com/markbates/safe/version.go @@ -0,0 +1,3 @@ +package safe + +const Version = "v1.0.1" diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore new file mode 100644 index 0000000000..6b7d7d1e8b --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.gitignore @@ -0,0 +1,2 @@ +logrus +vendor diff --git a/vendor/github.com/sirupsen/logrus/.golangci.yml b/vendor/github.com/sirupsen/logrus/.golangci.yml new file mode 100644 index 0000000000..65dc285037 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.golangci.yml @@ -0,0 +1,40 @@ +run: + # do not run on test files yet + tests: false + +# all available settings of specific linters +linters-settings: + errcheck: + # report about not checking of errors in type assetions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + + lll: + line-length: 100 + tab-width: 4 + + prealloc: + simple: false + range-loops: false + for-loops: false + + whitespace: + multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-func: false # Enforces newlines (or comments) after every multi-line function signature + +linters: + enable: + - megacheck + - govet + disable: + - maligned + - prealloc + disable-all: false + presets: + - bugs + - unused + fast: false diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml new file mode 100644 index 0000000000..5e20aa4140 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.travis.yml @@ -0,0 +1,17 @@ +language: go +go_import_path: github.com/sirupsen/logrus +git: + depth: 1 +env: + - GO111MODULE=on +go: [1.13.x, 1.14.x] +os: [linux, osx] +install: + - ./travis/install.sh +script: + - ./travis/cross_build.sh + - ./travis/lint.sh + - export GOMAXPROCS=4 + - export GORACE=halt_on_error=1 + - go test -race -v ./... + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md new file mode 100644 index 0000000000..584026d67c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -0,0 +1,223 @@ +# 1.6.0 +Fixes: + * end of line cleanup + * revert the entry concurrency bug fix whic leads to deadlock under some circumstances + * update dependency on go-windows-terminal-sequences to fix a crash with go 1.14 + +Features: + * add an option to the `TextFormatter` to completely disable fields quoting + +# 1.5.0 +Code quality: + * add golangci linter run on travis + +Fixes: + * add mutex for hooks concurrent access on `Entry` data + * caller function field for go1.14 + * fix build issue for gopherjs target + +Feature: + * add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level + * add a `DisableHTMLEscape` option in the `JSONFormatter` + * add `ForceQuote` and `PadLevelText` options in the `TextFormatter` + +# 1.4.2 + * Fixes build break for plan9, nacl, solaris +# 1.4.1 +This new release introduces: + * Enhance TextFormatter to not print caller information when they are empty (#944) + * Remove dependency on golang.org/x/crypto (#932, #943) + +Fixes: + * Fix Entry.WithContext method to return a copy of the initial entry (#941) + +# 1.4.0 +This new release introduces: + * Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848). + * Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911) + * Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919). + +Fixes: + * Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893). + * Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903) + * Fix infinite recursion on unknown `Level.String()` (#907) + * Fix race condition in `getCaller` (#916). + + +# 1.3.0 +This new release introduces: + * Log, Logf, Logln functions for Logger and Entry that take a Level + +Fixes: + * Building prometheus node_exporter on AIX (#840) + * Race condition in TextFormatter (#468) + * Travis CI import path (#868) + * Remove coloured output on Windows (#862) + * Pointer to func as field in JSONFormatter (#870) + * Properly marshal Levels (#873) + +# 1.2.0 +This new release introduces: + * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued + * A new trace level named `Trace` whose level is below `Debug` + * A configurable exit function to be called upon a Fatal trace + * The `Level` object now implements `encoding.TextUnmarshaler` interface + +# 1.1.1 +This is a bug fix release. + * fix the build break on Solaris + * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized + +# 1.1.0 +This new release introduces: + * several fixes: + * a fix for a race condition on entry formatting + * proper cleanup of previously used entries before putting them back in the pool + * the extra new line at the end of message in text formatter has been removed + * a new global public API to check if a level is activated: IsLevelEnabled + * the following methods have been added to the Logger object + * IsLevelEnabled + * SetFormatter + * SetOutput + * ReplaceHooks + * introduction of go module + * an indent configuration for the json formatter + * output colour support for windows + * the field sort function is now configurable for text formatter + * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater + +# 1.0.6 + +This new release introduces: + * a new api WithTime which allows to easily force the time of the log entry + which is mostly useful for logger wrapper + * a fix reverting the immutability of the entry given as parameter to the hooks + a new configuration field of the json formatter in order to put all the fields + in a nested dictionnary + * a new SetOutput method in the Logger + * a new configuration of the textformatter to configure the name of the default keys + * a new configuration of the text formatter to disable the level truncation + +# 1.0.5 + +* Fix hooks race (#707) +* Fix panic deadlock (#695) + +# 1.0.4 + +* Fix race when adding hooks (#612) +* Fix terminal check in AppEngine (#635) + +# 1.0.3 + +* Replace example files with testable examples + +# 1.0.2 + +* bug: quote non-string values in text formatter (#583) +* Make (*Logger) SetLevel a public method + +# 1.0.1 + +* bug: fix escaping in text formatter (#575) + +# 1.0.0 + +* Officially changed name to lower-case +* bug: colors on Windows 10 (#541) +* bug: fix race in accessing level (#512) + +# 0.11.5 + +* feature: add writer and writerlevel to entry (#372) + +# 0.11.4 + +* bug: fix undefined variable on solaris (#493) + +# 0.11.3 + +* formatter: configure quoting of empty values (#484) +* formatter: configure quoting character (default is `"`) (#484) +* bug: fix not importing io correctly in non-linux environments (#481) + +# 0.11.2 + +* bug: fix windows terminal detection (#476) + +# 0.11.1 + +* bug: fix tty detection with custom out (#471) + +# 0.11.0 + +* performance: Use bufferpool to allocate (#370) +* terminal: terminal detection for app-engine (#343) +* feature: exit handler (#375) + +# 0.10.0 + +* feature: Add a test hook (#180) +* feature: `ParseLevel` is now case-insensitive (#326) +* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) +* performance: avoid re-allocations on `WithFields` (#335) + +# 0.9.0 + +* logrus/text_formatter: don't emit empty msg +* logrus/hooks/airbrake: move out of main repository +* logrus/hooks/sentry: move out of main repository +* logrus/hooks/papertrail: move out of main repository +* logrus/hooks/bugsnag: move out of main repository +* logrus/core: run tests with `-race` +* logrus/core: detect TTY based on `stderr` +* logrus/core: support `WithError` on logger +* logrus/core: Solaris support + +# 0.8.7 + +* logrus/core: fix possible race (#216) +* logrus/doc: small typo fixes and doc improvements + + +# 0.8.6 + +* hooks/raven: allow passing an initialized client + +# 0.8.5 + +* logrus/core: revert #208 + +# 0.8.4 + +* formatter/text: fix data race (#218) + +# 0.8.3 + +* logrus/core: fix entry log level (#208) +* logrus/core: improve performance of text formatter by 40% +* logrus/core: expose `LevelHooks` type +* logrus/core: add support for DragonflyBSD and NetBSD +* formatter/text: print structs more verbosely + +# 0.8.2 + +* logrus: fix more Fatal family functions + +# 0.8.1 + +* logrus: fix not exiting on `Fatalf` and `Fatalln` + +# 0.8.0 + +* logrus: defaults to stderr instead of stdout +* hooks/sentry: add special field for `*http.Request` +* formatter/text: ignore Windows for colors + +# 0.7.3 + +* formatter/\*: allow configuration of timestamp layout + +# 0.7.2 + +* formatter/text: Add configuration option for time format (#158) diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE new file mode 100644 index 0000000000..f090cb42f3 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +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. diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md new file mode 100644 index 0000000000..5796706dbf --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -0,0 +1,513 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. + +**Logrus is in maintenance-mode.** We will not be introducing new features. It's +simply too hard to do in a way that won't break many people's projects, which is +the last thing you want from your Logging library (again...). + +This does not mean Logrus is dead. Logrus will continue to be maintained for +security, (backwards compatible) bug fixes, and performance (where we are +limited by the interface). + +I believe Logrus' biggest contribution is to have played a part in today's +widespread use of structured logging in Golang. There doesn't seem to be a +reason to do a major, breaking iteration into Logrus V2, since the fantastic Go +community has built those independently. Many fantastic alternatives have sprung +up. Logrus would look like those, had it been re-designed with what we know +about structured logging in Go today. Check out, for example, +[Zerolog][zerolog], [Zap][zap], and [Apex][apex]. + +[zerolog]: https://github.com/rs/zerolog +[zap]: https://github.com/uber-go/zap +[apex]: https://github.com/apex/log + +**Seeing weird case-sensitive problems?** It's in the past been possible to +import Logrus as both upper- and lower-case. Due to the Go package environment, +this caused issues in the community and we needed a standard. Some environments +experienced problems with the upper-case variant, so the lower-case was decided. +Everything using `logrus` will need to use the lower-case: +`github.com/sirupsen/logrus`. Any package that isn't, should be changed. + +To fix Glide, see [these +comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). +For an in-depth explanation of the casing issue, see [this +comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +``` +To ensure this behaviour even if a TTY is attached, set your formatter as follows: + +```go + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) +``` + +#### Logging Method Name + +If you wish to add the calling method as a field, instruct the logger via: +```go +log.SetReportCaller(true) +``` +This adds the caller as 'method' like so: + +```json +{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", +"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} +``` + +```text +time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin +``` +Note that this does add measurable overhead - the cost will depend on the version of Go, but is +between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your +environment via benchmarks: +``` +go test -bench=.*CallerTracing +``` + + +#### Case-sensitivity + +The organization's name was changed to lower-case--and this will not be changed +back. If you are getting import conflicts due to case sensitivity, please use +the lower-case import: `github.com/sirupsen/logrus`. + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging through logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + + +#### Level logging + +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Trace("Something very low level.") +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. + * When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. +* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html). +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo. +* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure. +* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files. +* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") + + assert.Equal(t, 1, len(hook.Entries)) + assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal(t, "Helloerror", hook.LastEntry().Message) + + hook.Reset() + assert.Nil(t, hook.LastEntry()) +} +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go new file mode 100644 index 0000000000..8fd189e1cc --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/alt_exit.go @@ -0,0 +1,76 @@ +package logrus + +// The following code was sourced and modified from the +// https://github.com/tebeka/atexit package governed by the following license: +// +// Copyright (c) 2012 Miki Tebeka . +// +// 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. + +import ( + "fmt" + "os" +) + +var handlers = []func(){} + +func runHandler(handler func()) { + defer func() { + if err := recover(); err != nil { + fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) + } + }() + + handler() +} + +func runHandlers() { + for _, handler := range handlers { + runHandler(handler) + } +} + +// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) +func Exit(code int) { + runHandlers() + os.Exit(code) +} + +// RegisterExitHandler appends a Logrus Exit handler to the list of handlers, +// call logrus.Exit to invoke all handlers. The handlers will also be invoked when +// any Fatal log entry is made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func RegisterExitHandler(handler func()) { + handlers = append(handlers, handler) +} + +// DeferExitHandler prepends a Logrus Exit handler to the list of handlers, +// call logrus.Exit to invoke all handlers. The handlers will also be invoked when +// any Fatal log entry is made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func DeferExitHandler(handler func()) { + handlers = append([]func(){handler}, handlers...) +} diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml new file mode 100644 index 0000000000..df9d65c3a5 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/appveyor.yml @@ -0,0 +1,14 @@ +version: "{build}" +platform: x64 +clone_folder: c:\gopath\src\github.com\sirupsen\logrus +environment: + GOPATH: c:\gopath +branches: + only: + - master +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version +build_script: + - go get -t + - go test diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go new file mode 100644 index 0000000000..da67aba06d --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/doc.go @@ -0,0 +1,26 @@ +/* +Package logrus is a structured logger for Go, completely API compatible with the standard library logger. + + +The simplest way to use Logrus is simply the package-level exported logger: + + package main + + import ( + log "github.com/sirupsen/logrus" + ) + + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } + +Output: + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + +For a full guide visit https://github.com/sirupsen/logrus +*/ +package logrus diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go new file mode 100644 index 0000000000..f6e062a346 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -0,0 +1,426 @@ +package logrus + +import ( + "bytes" + "context" + "fmt" + "os" + "reflect" + "runtime" + "strings" + "sync" + "time" +) + +var ( + bufferPool *sync.Pool + + // qualified package name, cached at first use + logrusPackage string + + // Positions in the call stack when tracing to report the calling method + minimumCallerDepth int + + // Used for caller information initialisation + callerInitOnce sync.Once +) + +const ( + maximumCallerDepth int = 25 + knownLogrusFrames int = 4 +) + +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 + minimumCallerDepth = 1 +} + +// Defines the key when adding errors using WithError. +var ErrorKey = "error" + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, +// Info, Warn, Error, Fatal or Panic is called on it. These objects can be +// reused and passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic + // This field will be set on entry firing and the value will be equal to the one in Logger struct field. + Level Level + + // Calling method, with package name + Caller *runtime.Frame + + // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic + Message string + + // When formatter is called in entry.log(), a Buffer may be set to entry + Buffer *bytes.Buffer + + // Contains the context set by the user. Useful for hook processing etc. + Context context.Context + + // err may contain a field formatting error + err string +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, plus one optional. Give a little extra room. + Data: make(Fields, 6), + } +} + +// Returns the bytes representation of this entry from the formatter. +func (entry *Entry) Bytes() ([]byte, error) { + return entry.Logger.Formatter.Format(entry) +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + serialized, err := entry.Bytes() + if err != nil { + return "", err + } + str := string(serialized) + return str, nil +} + +// Add an error as single field (using the key defined in ErrorKey) to the Entry. +func (entry *Entry) WithError(err error) *Entry { + return entry.WithField(ErrorKey, err) +} + +// Add a context to the Entry. +func (entry *Entry) WithContext(ctx context.Context) *Entry { + dataCopy := make(Fields, len(entry.Data)) + for k, v := range entry.Data { + dataCopy[k] = v + } + return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx} +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := make(Fields, len(entry.Data)+len(fields)) + for k, v := range entry.Data { + data[k] = v + } + fieldErr := entry.err + for k, v := range fields { + isErrField := false + if t := reflect.TypeOf(v); t != nil { + switch t.Kind() { + case reflect.Func: + isErrField = true + case reflect.Ptr: + isErrField = t.Elem().Kind() == reflect.Func + } + } + if isErrField { + tmp := fmt.Sprintf("can not add field %q", k) + if fieldErr != "" { + fieldErr = entry.err + ", " + tmp + } else { + fieldErr = tmp + } + } else { + data[k] = v + } + } + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + dataCopy := make(Fields, len(entry.Data)) + for k, v := range entry.Data { + dataCopy[k] = v + } + return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context} +} + +// getPackageName reduces a fully qualified function name to the package name +// There really ought to be to be a better way... +func getPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + + return f +} + +// getCaller retrieves the name of the first non-logrus calling function +func getCaller() *runtime.Frame { + // cache this package's fully-qualified name + callerInitOnce.Do(func() { + pcs := make([]uintptr, maximumCallerDepth) + _ = runtime.Callers(0, pcs) + + // dynamic get the package name and the minimum caller depth + for i := 0; i < maximumCallerDepth; i++ { + funcName := runtime.FuncForPC(pcs[i]).Name() + if strings.Contains(funcName, "getCaller") { + logrusPackage = getPackageName(funcName) + break + } + } + + minimumCallerDepth = knownLogrusFrames + }) + + // Restrict the lookback frames to avoid runaway lookups + pcs := make([]uintptr, maximumCallerDepth) + depth := runtime.Callers(minimumCallerDepth, pcs) + frames := runtime.CallersFrames(pcs[:depth]) + + for f, again := frames.Next(); again; f, again = frames.Next() { + pkg := getPackageName(f.Function) + + // If the caller isn't part of this package, we're done + if pkg != logrusPackage { + return &f //nolint:scopelint + } + } + + // if we got here, we failed to find the caller's context + return nil +} + +func (entry Entry) HasCaller() (has bool) { + return entry.Logger != nil && + entry.Logger.ReportCaller && + entry.Caller != nil +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + + entry.Level = level + entry.Message = msg + entry.Logger.mu.Lock() + if entry.Logger.ReportCaller { + entry.Caller = getCaller() + } + entry.Logger.mu.Unlock() + + entry.fireHooks() + + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + + entry.write() + + entry.Buffer = nil + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) fireHooks() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + err := entry.Logger.Hooks.Fire(entry.Level, entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + } +} + +func (entry *Entry) write() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + return + } + if _, err = entry.Logger.Out.Write(serialized); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } +} + +func (entry *Entry) Log(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.log(level, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Trace(args ...interface{}) { + entry.Log(TraceLevel, args...) +} + +func (entry *Entry) Debug(args ...interface{}) { + entry.Log(DebugLevel, args...) +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + entry.Log(InfoLevel, args...) +} + +func (entry *Entry) Warn(args ...interface{}) { + entry.Log(WarnLevel, args...) +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + entry.Log(ErrorLevel, args...) +} + +func (entry *Entry) Fatal(args ...interface{}) { + entry.Log(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + entry.Log(PanicLevel, args...) + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Logf(level Level, format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.Log(level, fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Tracef(format string, args ...interface{}) { + entry.Logf(TraceLevel, format, args...) +} + +func (entry *Entry) Debugf(format string, args ...interface{}) { + entry.Logf(DebugLevel, format, args...) +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + entry.Logf(InfoLevel, format, args...) +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + entry.Logf(WarnLevel, format, args...) +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + entry.Logf(ErrorLevel, format, args...) +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + entry.Logf(FatalLevel, format, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + entry.Logf(PanicLevel, format, args...) +} + +// Entry Println family functions + +func (entry *Entry) Logln(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.Log(level, entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Traceln(args ...interface{}) { + entry.Logln(TraceLevel, args...) +} + +func (entry *Entry) Debugln(args ...interface{}) { + entry.Logln(DebugLevel, args...) +} + +func (entry *Entry) Infoln(args ...interface{}) { + entry.Logln(InfoLevel, args...) +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + entry.Logln(WarnLevel, args...) +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + entry.Logln(ErrorLevel, args...) +} + +func (entry *Entry) Fatalln(args ...interface{}) { + entry.Logln(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + entry.Logln(PanicLevel, args...) +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go new file mode 100644 index 0000000000..42b04f6c80 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -0,0 +1,225 @@ +package logrus + +import ( + "context" + "io" + "time" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.SetOutput(out) +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.SetFormatter(formatter) +} + +// SetReportCaller sets whether the standard logger will include the calling +// method as a field. +func SetReportCaller(include bool) { + std.SetReportCaller(include) +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.SetLevel(level) +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + return std.GetLevel() +} + +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.AddHook(hook) +} + +// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. +func WithError(err error) *Entry { + return std.WithField(ErrorKey, err) +} + +// WithContext creates an entry from the standard logger and adds a context to it. +func WithContext(ctx context.Context) *Entry { + return std.WithContext(ctx) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// WithTime creates an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + +// Trace logs a message at level Trace on the standard logger. +func Trace(args ...interface{}) { + std.Trace(args...) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Tracef logs a message at level Trace on the standard logger. +func Tracef(format string, args ...interface{}) { + std.Tracef(format, args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Traceln logs a message at level Trace on the standard logger. +func Traceln(args ...interface{}) { + std.Traceln(args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go new file mode 100644 index 0000000000..408883773e --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -0,0 +1,78 @@ +package logrus + +import "time" + +// Default key names for the default fields +const ( + defaultTimestampFormat = time.RFC3339 + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" + FieldKeyLogrusError = "logrus_error" + FieldKeyFunc = "func" + FieldKeyFile = "file" +) + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t + delete(data, timeKey) + } + + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m + delete(data, msgKey) + } + + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l + delete(data, levelKey) + } + + logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) + if l, ok := data[logrusErrKey]; ok { + data["fields."+logrusErrKey] = l + delete(data, logrusErrKey) + } + + // If reportCaller is not set, 'func' will not conflict. + if reportCaller { + funcKey := fieldMap.resolve(FieldKeyFunc) + if l, ok := data[funcKey]; ok { + data["fields."+funcKey] = l + } + fileKey := fieldMap.resolve(FieldKeyFile) + if l, ok := data[fileKey]; ok { + data["fields."+fileKey] = l + } + } +} diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go new file mode 100644 index 0000000000..3f151cdc39 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go new file mode 100644 index 0000000000..ba7f237112 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -0,0 +1,125 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" + "runtime" +) + +type fieldKey string + +// FieldMap allows customization of the key names for default fields. +type FieldMap map[fieldKey]string + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + +// JSONFormatter formats logs into parsable json +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // DisableHTMLEscape allows disabling html escaping in output + DisableHTMLEscape bool + + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message", + // FieldKeyFunc: "@caller", + // }, + // } + FieldMap FieldMap + + // CallerPrettyfier can be set by the user to modify the content + // of the function and file keys in the json data when ReportCaller is + // activated. If any of the returned value is the empty string the + // corresponding key will be removed from json fields. + CallerPrettyfier func(*runtime.Frame) (function string, file string) + + // PrettyPrint will indent all json logs + PrettyPrint bool +} + +// Format renders a single log entry +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+4) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + + if entry.err != "" { + data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err + } + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() + if entry.HasCaller() { + funcVal := entry.Caller.Function + fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } + if funcVal != "" { + data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal + } + if fileVal != "" { + data[f.FieldMap.resolve(FieldKeyFile)] = fileVal + } + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + encoder := json.NewEncoder(b) + encoder.SetEscapeHTML(!f.DisableHTMLEscape) + if f.PrettyPrint { + encoder.SetIndent("", " ") + } + if err := encoder.Encode(data); err != nil { + return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err) + } + + return b.Bytes(), nil +} diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go new file mode 100644 index 0000000000..6fdda748e4 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -0,0 +1,352 @@ +package logrus + +import ( + "context" + "io" + "os" + "sync" + "sync/atomic" + "time" +) + +type Logger struct { + // 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 + // something more adventurous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + + // Flag for whether to log caller info (off by default) + ReportCaller bool + + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. + Level Level + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool + // Function to exit the application, defaults to `os.Exit()` + ExitFunc exitFunc +} + +type exitFunc func(int) + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &logrus.Logger{ +// Out: os.Stderr, +// Formatter: new(logrus.JSONFormatter), +// Hooks: make(logrus.LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + ExitFunc: os.Exit, + ReportCaller: false, + } +} + +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} + logger.entryPool.Put(entry) +} + +// WithField allocates a new entry and adds a field to it. +// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to +// this new returned entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) +} + +// Add an error as single field to the log entry. All it does is call +// `WithError` for the given `error`. +func (logger *Logger) WithError(err error) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) +} + +// Add a context to the log entry. +func (logger *Logger) WithContext(ctx context.Context) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithContext(ctx) +} + +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + +func (logger *Logger) Logf(level Level, format string, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logf(level, format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Tracef(format string, args ...interface{}) { + logger.Logf(TraceLevel, format, args...) +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + logger.Logf(DebugLevel, format, args...) +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + logger.Logf(InfoLevel, format, args...) +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + logger.Logf(WarnLevel, format, args...) +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + logger.Warnf(format, args...) +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + logger.Logf(ErrorLevel, format, args...) +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + logger.Logf(FatalLevel, format, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + logger.Logf(PanicLevel, format, args...) +} + +func (logger *Logger) Log(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Log(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Trace(args ...interface{}) { + logger.Log(TraceLevel, args...) +} + +func (logger *Logger) Debug(args ...interface{}) { + logger.Log(DebugLevel, args...) +} + +func (logger *Logger) Info(args ...interface{}) { + logger.Log(InfoLevel, args...) +} + +func (logger *Logger) Print(args ...interface{}) { + entry := logger.newEntry() + entry.Print(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warn(args ...interface{}) { + logger.Log(WarnLevel, args...) +} + +func (logger *Logger) Warning(args ...interface{}) { + logger.Warn(args...) +} + +func (logger *Logger) Error(args ...interface{}) { + logger.Log(ErrorLevel, args...) +} + +func (logger *Logger) Fatal(args ...interface{}) { + logger.Log(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + logger.Log(PanicLevel, args...) +} + +func (logger *Logger) Logln(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logln(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Traceln(args ...interface{}) { + logger.Logln(TraceLevel, args...) +} + +func (logger *Logger) Debugln(args ...interface{}) { + logger.Logln(DebugLevel, args...) +} + +func (logger *Logger) Infoln(args ...interface{}) { + logger.Logln(InfoLevel, args...) +} + +func (logger *Logger) Println(args ...interface{}) { + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnln(args ...interface{}) { + logger.Logln(WarnLevel, args...) +} + +func (logger *Logger) Warningln(args ...interface{}) { + logger.Warnln(args...) +} + +func (logger *Logger) Errorln(args ...interface{}) { + logger.Logln(ErrorLevel, args...) +} + +func (logger *Logger) Fatalln(args ...interface{}) { + logger.Logln(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + logger.Logln(PanicLevel, args...) +} + +func (logger *Logger) Exit(code int) { + runHandlers() + if logger.ExitFunc == nil { + logger.ExitFunc = os.Exit + } + logger.ExitFunc(code) +} + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} + +func (logger *Logger) level() Level { + return Level(atomic.LoadUint32((*uint32)(&logger.Level))) +} + +// SetLevel sets the logger level. +func (logger *Logger) SetLevel(level Level) { + atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) +} + +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. +func (logger *Logger) AddHook(hook Hook) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Hooks.Add(hook) +} + +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level +} + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} + +func (logger *Logger) SetReportCaller(reportCaller bool) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.ReportCaller = reportCaller +} + +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { + logger.mu.Lock() + oldHooks := logger.Hooks + logger.Hooks = hooks + logger.mu.Unlock() + return oldHooks +} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go new file mode 100644 index 0000000000..2f16224cb9 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -0,0 +1,186 @@ +package logrus + +import ( + "fmt" + "log" + "strings" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint32 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + if b, err := level.MarshalText(); err == nil { + return string(b) + } else { + return "unknown" + } +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch strings.ToLower(lvl) { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + case "trace": + return TraceLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (level *Level) UnmarshalText(text []byte) error { + l, err := ParseLevel(string(text)) + if err != nil { + return err + } + + *level = l + + return nil +} + +func (level Level) MarshalText() ([]byte, error) { + switch level { + case TraceLevel: + return []byte("trace"), nil + case DebugLevel: + return []byte("debug"), nil + case InfoLevel: + return []byte("info"), nil + case WarnLevel: + return []byte("warning"), nil + case ErrorLevel: + return []byte("error"), nil + case FatalLevel: + return []byte("fatal"), nil + case PanicLevel: + return []byte("panic"), nil + } + + return nil, fmt.Errorf("not a valid logrus level %d", level) +} + +// A constant exposing all logging levels +var AllLevels = []Level{ + PanicLevel, + FatalLevel, + ErrorLevel, + WarnLevel, + InfoLevel, + DebugLevel, + TraceLevel, +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel + // TraceLevel level. Designates finer-grained informational events than the Debug. + TraceLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var ( + _ StdLogger = &log.Logger{} + _ StdLogger = &Entry{} + _ StdLogger = &Logger{} +) + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} + +// The FieldLogger interface generalizes the Entry and Logger types +type FieldLogger interface { + WithField(key string, value interface{}) *Entry + WithFields(fields Fields) *Entry + WithError(err error) *Entry + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Printf(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Warningf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) + Panicf(format string, args ...interface{}) + + Debug(args ...interface{}) + Info(args ...interface{}) + Print(args ...interface{}) + Warn(args ...interface{}) + Warning(args ...interface{}) + Error(args ...interface{}) + Fatal(args ...interface{}) + Panic(args ...interface{}) + + Debugln(args ...interface{}) + Infoln(args ...interface{}) + Println(args ...interface{}) + Warnln(args ...interface{}) + Warningln(args ...interface{}) + Errorln(args ...interface{}) + Fatalln(args ...interface{}) + Panicln(args ...interface{}) + + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool +} + +// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is +// here for consistancy. Do not use. Use Logger or Entry instead. +type Ext1FieldLogger interface { + FieldLogger + Tracef(format string, args ...interface{}) + Trace(args ...interface{}) + Traceln(args ...interface{}) +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go new file mode 100644 index 0000000000..2403de9819 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go new file mode 100644 index 0000000000..499789984d --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go @@ -0,0 +1,13 @@ +// +build darwin dragonfly freebsd netbsd openbsd +// +build !js + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TIOCGETA + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go new file mode 100644 index 0000000000..ebdae3ec62 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_js.go @@ -0,0 +1,7 @@ +// +build js + +package logrus + +func isTerminal(fd int) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go new file mode 100644 index 0000000000..97af92c68e --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go @@ -0,0 +1,11 @@ +// +build js nacl plan9 + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go new file mode 100644 index 0000000000..3293fb3caa --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -0,0 +1,17 @@ +// +build !appengine,!js,!windows,!nacl,!plan9 + +package logrus + +import ( + "io" + "os" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return isTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go new file mode 100644 index 0000000000..f6710b3bd0 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go @@ -0,0 +1,11 @@ +package logrus + +import ( + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermio(fd, unix.TCGETA) + return err == nil +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go new file mode 100644 index 0000000000..cc4fe6e317 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go @@ -0,0 +1,13 @@ +// +build linux aix +// +build !js + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go new file mode 100644 index 0000000000..572889db21 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -0,0 +1,34 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +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 { + var ret bool + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + ret = (err == nil) + default: + ret = false + } + if ret { + initTerminal(w) + } + return ret +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go new file mode 100644 index 0000000000..3c28b54cab --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -0,0 +1,334 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "time" + "unicode/utf8" +) + +const ( + red = 31 + yellow = 33 + blue = 36 + gray = 37 +) + +var baseTimestamp time.Time + +func init() { + baseTimestamp = time.Now() +} + +// TextFormatter formats logs into text +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Force quoting of all values + ForceQuote bool + + // DisableQuote disables quoting for all values. + // DisableQuote will have a lower priority than ForceQuote. + // If both of them are set to true, quote will be forced on all values. + DisableQuote bool + + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + EnvironmentOverrideColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool + + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool + + // PadLevelText Adds padding the level text so that all the levels output at the same length + // PadLevelText is a superset of the DisableLevelTruncation option + PadLevelText bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // Whether the logger's out is to a terminal + isTerminal bool + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &TextFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + + // CallerPrettyfier can be set by the user to modify the content + // of the function and file keys in the data when ReportCaller is + // activated. If any of the returned value is the empty string the + // corresponding key will be removed from fields. + CallerPrettyfier func(*runtime.Frame) (function string, file string) + + terminalInitOnce sync.Once + + // The max length of the level text, generated dynamically on init + levelTextMaxLength int +} + +func (f *TextFormatter) init(entry *Entry) { + if entry.Logger != nil { + f.isTerminal = checkIfTerminal(entry.Logger.Out) + } + // Get the max length of the level text + for _, level := range AllLevels { + levelTextLength := utf8.RuneCount([]byte(level.String())) + if levelTextLength > f.levelTextMaxLength { + f.levelTextMaxLength = levelTextLength + } + } +} + +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows")) + + if f.EnvironmentOverrideColors { + switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); { + case ok && force != "0": + isColored = true + case ok && force == "0", os.Getenv("CLICOLOR") == "0": + isColored = false + } + } + + return isColored && !f.DisableColors +} + +// Format renders a single log entry +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields) + for k, v := range entry.Data { + data[k] = v + } + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + keys := make([]string, 0, len(data)) + for k := range data { + keys = append(keys, k) + } + + var funcVal, fileVal string + + fixedKeys := make([]string, 0, 4+len(data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) + } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + if entry.err != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) + } + if entry.HasCaller() { + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } else { + funcVal = entry.Caller.Function + fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + } + + if funcVal != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc)) + } + if fileVal != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile)) + } + } + + if !f.DisableSorting { + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + f.terminalInitOnce.Do(func() { f.init(entry) }) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + if f.isColored() { + f.printColored(b, entry, keys, data, timestampFormat) + } else { + + for _, key := range fixedKeys { + var value interface{} + switch { + case key == f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case key == f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case key == f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + case key == f.FieldMap.resolve(FieldKeyLogrusError): + value = entry.err + case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): + value = funcVal + case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): + value = fileVal + default: + value = data[key] + } + f.appendKeyValue(b, key, value) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel, TraceLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation && !f.PadLevelText { + levelText = levelText[0:4] + } + if f.PadLevelText { + // Generates the format string used in the next line, for example "%-6s" or "%-7s". + // Based on the max level text length. + formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s" + // Formats the level text by appending spaces up to the max length, for example: + // - "INFO " + // - "WARNING" + levelText = fmt.Sprintf(formatString, levelText) + } + + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") + + caller := "" + if entry.HasCaller() { + funcVal := fmt.Sprintf("%s()", entry.Caller.Function) + fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } + + if fileVal == "" { + caller = funcVal + } else if funcVal == "" { + caller = fileVal + } else { + caller = fileVal + " " + funcVal + } + } + + switch { + case f.DisableTimestamp: + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) + case !f.FullTimestamp: + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) + default: + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) + } + for _, k := range keys { + v := data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *TextFormatter) needsQuoting(text string) bool { + if f.ForceQuote { + return true + } + if f.QuoteEmptyFields && len(text) == 0 { + return true + } + if f.DisableQuote { + return false + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { + return true + } + } + return false +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) +} + +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { + stringVal, ok := value.(string) + if !ok { + stringVal = fmt.Sprint(value) + } + + if !f.needsQuoting(stringVal) { + b.WriteString(stringVal) + } else { + b.WriteString(fmt.Sprintf("%q", stringVal)) + } +} diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go new file mode 100644 index 0000000000..72e8e3a1b6 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/writer.go @@ -0,0 +1,70 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +// Writer at INFO level. See WriterLevel for details. +func (logger *Logger) Writer() *io.PipeWriter { + return logger.WriterLevel(InfoLevel) +} + +// WriterLevel returns an io.Writer that can be used to write arbitrary text to +// the logger at the given log level. Each line written to the writer will be +// printed in the usual way using formatters and hooks. The writer is part of an +// io.Pipe and it is the callers responsibility to close the writer when done. +// This can be used to override the standard library logger easily. +func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { + reader, writer := io.Pipe() + + var printFunc func(args ...interface{}) + + switch level { + case TraceLevel: + printFunc = entry.Trace + case DebugLevel: + printFunc = entry.Debug + case InfoLevel: + printFunc = entry.Info + case WarnLevel: + printFunc = entry.Warn + case ErrorLevel: + printFunc = entry.Error + case FatalLevel: + printFunc = entry.Fatal + case PanicLevel: + printFunc = entry.Panic + default: + printFunc = entry.Print + } + + go entry.writerScanner(reader, printFunc) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + printFunc(scanner.Text()) + } + if err := scanner.Err(); err != nil { + entry.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/vendor/github.com/spf13/cobra/.gitignore b/vendor/github.com/spf13/cobra/.gitignore new file mode 100644 index 0000000000..c7b459e4dd --- /dev/null +++ b/vendor/github.com/spf13/cobra/.gitignore @@ -0,0 +1,39 @@ +# 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 diff --git a/vendor/github.com/spf13/cobra/.mailmap b/vendor/github.com/spf13/cobra/.mailmap new file mode 100644 index 0000000000..94ec53068a --- /dev/null +++ b/vendor/github.com/spf13/cobra/.mailmap @@ -0,0 +1,3 @@ +Steve Francia +Bjørn Erik Pedersen +Fabiano Franz diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml new file mode 100644 index 0000000000..a9bd4e5478 --- /dev/null +++ b/vendor/github.com/spf13/cobra/.travis.yml @@ -0,0 +1,29 @@ +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 diff --git a/vendor/github.com/spf13/cobra/LICENSE.txt b/vendor/github.com/spf13/cobra/LICENSE.txt new file mode 100644 index 0000000000..298f0e2665 --- /dev/null +++ b/vendor/github.com/spf13/cobra/LICENSE.txt @@ -0,0 +1,174 @@ + 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. diff --git a/vendor/github.com/spf13/cobra/Makefile b/vendor/github.com/spf13/cobra/Makefile new file mode 100644 index 0000000000..e9740d1e17 --- /dev/null +++ b/vendor/github.com/spf13/cobra/Makefile @@ -0,0 +1,36 @@ +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) diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md new file mode 100644 index 0000000000..9d79934260 --- /dev/null +++ b/vendor/github.com/spf13/cobra/README.md @@ -0,0 +1,770 @@ +![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 ") + 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) diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go new file mode 100644 index 0000000000..70e9b26291 --- /dev/null +++ b/vendor/github.com/spf13/cobra/args.go @@ -0,0 +1,109 @@ +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 + } +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go new file mode 100644 index 0000000000..1e27188c3d --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -0,0 +1,641 @@ +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 ___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) +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md new file mode 100644 index 0000000000..e61a3a6546 --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -0,0 +1,383 @@ +# 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 +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 "" +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()` (`___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 +completion firstcommand secondcommand +``` diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go new file mode 100644 index 0000000000..d01becc8fa --- /dev/null +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -0,0 +1,207 @@ +// Copyright © 2013 Steve Francia . +// +// 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 +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go new file mode 100644 index 0000000000..88e6ed77d0 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command.go @@ -0,0 +1,1634 @@ +// Copyright © 2013 Steve Francia . +// +// 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. + +// Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. +// In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. +package cobra + +import ( + "bytes" + "context" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + flag "github.com/spf13/pflag" +) + +// FParseErrWhitelist configures Flag parse errors to be ignored +type FParseErrWhitelist flag.ParseErrorsWhitelist + +// Command is just that, a command for your application. +// E.g. 'go run ...' - 'run' is the command. Cobra requires +// you to define the usage and description as part of your command +// definition to ensure usability. +type Command struct { + // Use is the one-line usage message. + Use string + + // Aliases is an array of aliases that can be used instead of the first word in Use. + Aliases []string + + // SuggestFor is an array of command names for which this command will be suggested - + // similar to aliases but only suggests. + SuggestFor []string + + // Short is the short description shown in the 'help' output. + Short string + + // Long is the long message shown in the 'help ' output. + Long string + + // Example is examples of how to use the command. + Example string + + // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions + ValidArgs []string + // ValidArgsFunction is an optional function that provides valid non-flag arguments for bash completion. + // It is a dynamic version of using ValidArgs. + // Only one of ValidArgs and ValidArgsFunction can be used for a command. + ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) + + // Expected arguments + Args PositionalArgs + + // ArgAliases is List of aliases for ValidArgs. + // These are not suggested to the user in the bash completion, + // but accepted if entered manually. + ArgAliases []string + + // BashCompletionFunction is custom functions used by the bash autocompletion generator. + BashCompletionFunction string + + // Deprecated defines, if this command is deprecated and should print this string when used. + Deprecated string + + // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. + Hidden bool + + // Annotations are key/value pairs that can be used by applications to identify or + // group commands. + Annotations map[string]string + + // Version defines the version for this command. If this value is non-empty and the command does not + // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, + // will print content of the "Version" variable. A shorthand "v" flag will also be added if the + // command does not define one. + Version string + + // The *Run functions are executed in the following order: + // * PersistentPreRun() + // * PreRun() + // * Run() + // * PostRun() + // * PersistentPostRun() + // All functions get the same args, the arguments after the command name. + // + // PersistentPreRun: children of this command will inherit and execute. + PersistentPreRun func(cmd *Command, args []string) + // PersistentPreRunE: PersistentPreRun but returns an error. + PersistentPreRunE func(cmd *Command, args []string) error + // PreRun: children of this command will not inherit. + PreRun func(cmd *Command, args []string) + // PreRunE: PreRun but returns an error. + PreRunE func(cmd *Command, args []string) error + // Run: Typically the actual work function. Most commands will only implement this. + Run func(cmd *Command, args []string) + // RunE: Run but returns an error. + RunE func(cmd *Command, args []string) error + // PostRun: run after the Run command. + PostRun func(cmd *Command, args []string) + // PostRunE: PostRun but returns an error. + PostRunE func(cmd *Command, args []string) error + // PersistentPostRun: children of this command will inherit and execute after PostRun. + PersistentPostRun func(cmd *Command, args []string) + // PersistentPostRunE: PersistentPostRun but returns an error. + PersistentPostRunE func(cmd *Command, args []string) error + + // SilenceErrors is an option to quiet errors down stream. + SilenceErrors bool + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage bool + + // DisableFlagParsing disables the flag parsing. + // If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool + + // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") + // will be printed by generating docs for this command. + DisableAutoGenTag bool + + // DisableFlagsInUseLine will disable the addition of [flags] to the usage + // line of a command when printing help or generating docs + DisableFlagsInUseLine bool + + // DisableSuggestions disables the suggestions based on Levenshtein distance + // that go along with 'unknown command' messages. + DisableSuggestions bool + // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. + // Must be > 0. + SuggestionsMinimumDistance int + + // TraverseChildren parses flags on all parents before executing child command. + TraverseChildren bool + + // FParseErrWhitelist flag parse errors to be ignored + FParseErrWhitelist FParseErrWhitelist + + ctx context.Context + + // commands is the list of commands supported by this program. + commands []*Command + // parent is a parent command for this command. + parent *Command + // Max lengths of commands' string lengths for use in padding. + commandsMaxUseLen int + commandsMaxCommandPathLen int + commandsMaxNameLen int + // commandsAreSorted defines, if command slice are sorted or not. + commandsAreSorted bool + // commandCalledAs is the name or alias value used to call this command. + commandCalledAs struct { + name string + called bool + } + + // args is actual args parsed from flags. + args []string + // flagErrorBuf contains all error messages from pflag. + flagErrorBuf *bytes.Buffer + // flags is full set of flags. + flags *flag.FlagSet + // pflags contains persistent flags. + pflags *flag.FlagSet + // lflags contains local flags. + lflags *flag.FlagSet + // iflags contains inherited flags. + iflags *flag.FlagSet + // parentsPflags is all persistent flags of cmd's parents. + parentsPflags *flag.FlagSet + // globNormFunc is the global normalization function + // that we can use on every pflag set and children commands + globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName + + // usageFunc is usage func defined by user. + usageFunc func(*Command) error + // usageTemplate is usage template defined by user. + usageTemplate string + // flagErrorFunc is func defined by user and it's called when the parsing of + // flags returns an error. + flagErrorFunc func(*Command, error) error + // helpTemplate is help template defined by user. + helpTemplate string + // helpFunc is help func defined by user. + helpFunc func(*Command, []string) + // helpCommand is command with usage 'help'. If it's not defined by user, + // cobra uses default help command. + helpCommand *Command + // versionTemplate is the version template defined by user. + versionTemplate string + + // inReader is a reader defined by the user that replaces stdin + inReader io.Reader + // outWriter is a writer defined by the user that replaces stdout + outWriter io.Writer + // errWriter is a writer defined by the user that replaces stderr + errWriter io.Writer +} + +// Context returns underlying command context. If command wasn't +// executed with ExecuteContext Context returns Background context. +func (c *Command) Context() context.Context { + return c.ctx +} + +// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden +// particularly useful when testing. +func (c *Command) SetArgs(a []string) { + c.args = a +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +// Deprecated: Use SetOut and/or SetErr instead +func (c *Command) SetOutput(output io.Writer) { + c.outWriter = output + c.errWriter = output +} + +// SetOut sets the destination for usage messages. +// If newOut is nil, os.Stdout is used. +func (c *Command) SetOut(newOut io.Writer) { + c.outWriter = newOut +} + +// SetErr sets the destination for error messages. +// If newErr is nil, os.Stderr is used. +func (c *Command) SetErr(newErr io.Writer) { + c.errWriter = newErr +} + +// SetIn sets the source for input data +// If newIn is nil, os.Stdin is used. +func (c *Command) SetIn(newIn io.Reader) { + c.inReader = newIn +} + +// SetUsageFunc sets usage function. Usage can be defined by application. +func (c *Command) SetUsageFunc(f func(*Command) error) { + c.usageFunc = f +} + +// SetUsageTemplate sets usage template. Can be defined by Application. +func (c *Command) SetUsageTemplate(s string) { + c.usageTemplate = s +} + +// SetFlagErrorFunc sets a function to generate an error when flag parsing +// fails. +func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { + c.flagErrorFunc = f +} + +// SetHelpFunc sets help function. Can be defined by Application. +func (c *Command) SetHelpFunc(f func(*Command, []string)) { + c.helpFunc = f +} + +// SetHelpCommand sets help command. +func (c *Command) SetHelpCommand(cmd *Command) { + c.helpCommand = cmd +} + +// SetHelpTemplate sets help template to be used. Application can use it to set custom template. +func (c *Command) SetHelpTemplate(s string) { + c.helpTemplate = s +} + +// SetVersionTemplate sets version template to be used. Application can use it to set custom template. +func (c *Command) SetVersionTemplate(s string) { + c.versionTemplate = s +} + +// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. +// The user should not have a cyclic dependency on commands. +func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { + c.Flags().SetNormalizeFunc(n) + c.PersistentFlags().SetNormalizeFunc(n) + c.globNormFunc = n + + for _, command := range c.commands { + command.SetGlobalNormalizationFunc(n) + } +} + +// OutOrStdout returns output to stdout. +func (c *Command) OutOrStdout() io.Writer { + return c.getOut(os.Stdout) +} + +// OutOrStderr returns output to stderr +func (c *Command) OutOrStderr() io.Writer { + return c.getOut(os.Stderr) +} + +// ErrOrStderr returns output to stderr +func (c *Command) ErrOrStderr() io.Writer { + return c.getErr(os.Stderr) +} + +// InOrStdin returns input to stdin +func (c *Command) InOrStdin() io.Reader { + return c.getIn(os.Stdin) +} + +func (c *Command) getOut(def io.Writer) io.Writer { + if c.outWriter != nil { + return c.outWriter + } + if c.HasParent() { + return c.parent.getOut(def) + } + return def +} + +func (c *Command) getErr(def io.Writer) io.Writer { + if c.errWriter != nil { + return c.errWriter + } + if c.HasParent() { + return c.parent.getErr(def) + } + return def +} + +func (c *Command) getIn(def io.Reader) io.Reader { + if c.inReader != nil { + return c.inReader + } + if c.HasParent() { + return c.parent.getIn(def) + } + return def +} + +// UsageFunc returns either the function set by SetUsageFunc for this command +// or a parent, or it returns a default usage function. +func (c *Command) UsageFunc() (f func(*Command) error) { + if c.usageFunc != nil { + return c.usageFunc + } + if c.HasParent() { + return c.Parent().UsageFunc() + } + return func(c *Command) error { + c.mergePersistentFlags() + err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + if err != nil { + c.Println(err) + } + return err + } +} + +// Usage puts out the usage for the command. +// Used when a user provides invalid input. +// Can be defined by user by overriding UsageFunc. +func (c *Command) Usage() error { + return c.UsageFunc()(c) +} + +// HelpFunc returns either the function set by SetHelpFunc for this command +// or a parent, or it returns a function with default help behavior. +func (c *Command) HelpFunc() func(*Command, []string) { + if c.helpFunc != nil { + return c.helpFunc + } + if c.HasParent() { + return c.Parent().HelpFunc() + } + return func(c *Command, a []string) { + c.mergePersistentFlags() + // The help should be sent to stdout + // See https://github.com/spf13/cobra/issues/1002 + err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + if err != nil { + c.Println(err) + } + } +} + +// Help puts out the help for the command. +// Used when a user calls help [command]. +// Can be defined by user by overriding HelpFunc. +func (c *Command) Help() error { + c.HelpFunc()(c, []string{}) + return nil +} + +// UsageString returns usage string. +func (c *Command) UsageString() string { + // Storing normal writers + tmpOutput := c.outWriter + tmpErr := c.errWriter + + bb := new(bytes.Buffer) + c.outWriter = bb + c.errWriter = bb + + c.Usage() + + // Setting things back to normal + c.outWriter = tmpOutput + c.errWriter = tmpErr + + return bb.String() +} + +// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this +// command or a parent, or it returns a function which returns the original +// error. +func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { + if c.flagErrorFunc != nil { + return c.flagErrorFunc + } + + if c.HasParent() { + return c.parent.FlagErrorFunc() + } + return func(c *Command, err error) error { + return err + } +} + +var minUsagePadding = 25 + +// UsagePadding return padding for the usage. +func (c *Command) UsagePadding() int { + if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { + return minUsagePadding + } + return c.parent.commandsMaxUseLen +} + +var minCommandPathPadding = 11 + +// CommandPathPadding return padding for the command path. +func (c *Command) CommandPathPadding() int { + if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { + return minCommandPathPadding + } + return c.parent.commandsMaxCommandPathLen +} + +var minNamePadding = 11 + +// NamePadding returns padding for the name. +func (c *Command) NamePadding() int { + if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { + return minNamePadding + } + return c.parent.commandsMaxNameLen +} + +// UsageTemplate returns usage template for the command. +func (c *Command) UsageTemplate() string { + if c.usageTemplate != "" { + return c.usageTemplate + } + + if c.HasParent() { + return c.parent.UsageTemplate() + } + return `Usage:{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} + +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}} + +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` +} + +// HelpTemplate return help template for the command. +func (c *Command) HelpTemplate() string { + if c.helpTemplate != "" { + return c.helpTemplate + } + + if c.HasParent() { + return c.parent.HelpTemplate() + } + return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` +} + +// VersionTemplate return version template for the command. +func (c *Command) VersionTemplate() string { + if c.versionTemplate != "" { + return c.versionTemplate + } + + if c.HasParent() { + return c.parent.VersionTemplate() + } + return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} +` +} + +func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { + flag := fs.Lookup(name) + if flag == nil { + return false + } + return flag.NoOptDefVal != "" +} + +func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { + if len(name) == 0 { + return false + } + + flag := fs.ShorthandLookup(name[:1]) + if flag == nil { + return false + } + return flag.NoOptDefVal != "" +} + +func stripFlags(args []string, c *Command) []string { + if len(args) == 0 { + return args + } + c.mergePersistentFlags() + + commands := []string{} + flags := c.Flags() + +Loop: + for len(args) > 0 { + s := args[0] + args = args[1:] + switch { + case s == "--": + // "--" terminates the flags + break Loop + case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): + // If '--flag arg' then + // delete arg from args. + fallthrough // (do the same as below) + case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): + // If '-f arg' then + // delete 'arg' from args or break the loop if len(args) <= 1. + if len(args) <= 1 { + break Loop + } else { + args = args[1:] + continue + } + case s != "" && !strings.HasPrefix(s, "-"): + commands = append(commands, s) + } + } + + return commands +} + +// argsMinusFirstX removes only the first x from args. Otherwise, commands that look like +// openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). +func argsMinusFirstX(args []string, x string) []string { + for i, y := range args { + if x == y { + ret := []string{} + ret = append(ret, args[:i]...) + ret = append(ret, args[i+1:]...) + return ret + } + } + return args +} + +func isFlagArg(arg string) bool { + return ((len(arg) >= 3 && arg[1] == '-') || + (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) +} + +// Find the target command given the args and command tree +// Meant to be run on the highest node. Only searches down. +func (c *Command) Find(args []string) (*Command, []string, error) { + var innerfind func(*Command, []string) (*Command, []string) + + innerfind = func(c *Command, innerArgs []string) (*Command, []string) { + argsWOflags := stripFlags(innerArgs, c) + if len(argsWOflags) == 0 { + return c, innerArgs + } + nextSubCmd := argsWOflags[0] + + cmd := c.findNext(nextSubCmd) + if cmd != nil { + return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) + } + return c, innerArgs + } + + commandFound, a := innerfind(c, args) + if commandFound.Args == nil { + return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) + } + return commandFound, a, nil +} + +func (c *Command) findSuggestions(arg string) string { + if c.DisableSuggestions { + return "" + } + if c.SuggestionsMinimumDistance <= 0 { + c.SuggestionsMinimumDistance = 2 + } + suggestionsString := "" + if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) + } + } + return suggestionsString +} + +func (c *Command) findNext(next string) *Command { + matches := make([]*Command, 0) + for _, cmd := range c.commands { + if cmd.Name() == next || cmd.HasAlias(next) { + cmd.commandCalledAs.name = next + return cmd + } + if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { + matches = append(matches, cmd) + } + } + + if len(matches) == 1 { + return matches[0] + } + + return nil +} + +// Traverse the command tree to find the command, and parse args for +// each parent. +func (c *Command) Traverse(args []string) (*Command, []string, error) { + flags := []string{} + inFlag := false + + for i, arg := range args { + switch { + // A long flag with a space separated value + case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="): + // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' + inFlag = !hasNoOptDefVal(arg[2:], c.Flags()) + flags = append(flags, arg) + continue + // A short flag with a space separated value + case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()): + inFlag = true + flags = append(flags, arg) + continue + // The value for a flag + case inFlag: + inFlag = false + flags = append(flags, arg) + continue + // A flag without a value, or with an `=` separated value + case isFlagArg(arg): + flags = append(flags, arg) + continue + } + + cmd := c.findNext(arg) + if cmd == nil { + return c, args, nil + } + + if err := c.ParseFlags(flags); err != nil { + return nil, args, err + } + return cmd.Traverse(args[i+1:]) + } + return c, args, nil +} + +// SuggestionsFor provides suggestions for the typedName. +func (c *Command) SuggestionsFor(typedName string) []string { + suggestions := []string{} + for _, cmd := range c.commands { + if cmd.IsAvailableCommand() { + levenshteinDistance := ld(typedName, cmd.Name(), true) + suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance + suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) + if suggestByLevenshtein || suggestByPrefix { + suggestions = append(suggestions, cmd.Name()) + } + for _, explicitSuggestion := range cmd.SuggestFor { + if strings.EqualFold(typedName, explicitSuggestion) { + suggestions = append(suggestions, cmd.Name()) + } + } + } + } + return suggestions +} + +// VisitParents visits all parents of the command and invokes fn on each parent. +func (c *Command) VisitParents(fn func(*Command)) { + if c.HasParent() { + fn(c.Parent()) + c.Parent().VisitParents(fn) + } +} + +// Root finds root command. +func (c *Command) Root() *Command { + if c.HasParent() { + return c.Parent().Root() + } + return c +} + +// ArgsLenAtDash will return the length of c.Flags().Args at the moment +// when a -- was found during args parsing. +func (c *Command) ArgsLenAtDash() int { + return c.Flags().ArgsLenAtDash() +} + +func (c *Command) execute(a []string) (err error) { + if c == nil { + return fmt.Errorf("Called Execute() on a nil Command") + } + + if len(c.Deprecated) > 0 { + c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) + } + + // initialize help and version flag at the last point possible to allow for user + // overriding + c.InitDefaultHelpFlag() + c.InitDefaultVersionFlag() + + err = c.ParseFlags(a) + if err != nil { + return c.FlagErrorFunc()(c, err) + } + + // If help is called, regardless of other flags, return we want help. + // Also say we need help if the command isn't runnable. + helpVal, err := c.Flags().GetBool("help") + if err != nil { + // should be impossible to get here as we always declare a help + // flag in InitDefaultHelpFlag() + c.Println("\"help\" flag declared as non-bool. Please correct your code") + return err + } + + if helpVal { + return flag.ErrHelp + } + + // for back-compat, only add version flag behavior if version is defined + if c.Version != "" { + versionVal, err := c.Flags().GetBool("version") + if err != nil { + c.Println("\"version\" flag declared as non-bool. Please correct your code") + return err + } + if versionVal { + err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) + if err != nil { + c.Println(err) + } + return err + } + } + + if !c.Runnable() { + return flag.ErrHelp + } + + c.preRun() + + argWoFlags := c.Flags().Args() + if c.DisableFlagParsing { + argWoFlags = a + } + + if err := c.ValidateArgs(argWoFlags); err != nil { + return err + } + + for p := c; p != nil; p = p.Parent() { + if p.PersistentPreRunE != nil { + if err := p.PersistentPreRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPreRun != nil { + p.PersistentPreRun(c, argWoFlags) + break + } + } + if c.PreRunE != nil { + if err := c.PreRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PreRun != nil { + c.PreRun(c, argWoFlags) + } + + if err := c.validateRequiredFlags(); err != nil { + return err + } + if c.RunE != nil { + if err := c.RunE(c, argWoFlags); err != nil { + return err + } + } else { + c.Run(c, argWoFlags) + } + if c.PostRunE != nil { + if err := c.PostRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PostRun != nil { + c.PostRun(c, argWoFlags) + } + for p := c; p != nil; p = p.Parent() { + if p.PersistentPostRunE != nil { + if err := p.PersistentPostRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPostRun != nil { + p.PersistentPostRun(c, argWoFlags) + break + } + } + + return nil +} + +func (c *Command) preRun() { + for _, x := range initializers { + x() + } +} + +// ExecuteContext is the same as Execute(), but sets the ctx on the command. +// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle functions. +func (c *Command) ExecuteContext(ctx context.Context) error { + c.ctx = ctx + return c.Execute() +} + +// Execute uses the args (os.Args[1:] by default) +// and run through the command tree finding appropriate matches +// for commands and then corresponding flags. +func (c *Command) Execute() error { + _, err := c.ExecuteC() + return err +} + +// ExecuteC executes the command. +func (c *Command) ExecuteC() (cmd *Command, err error) { + if c.ctx == nil { + c.ctx = context.Background() + } + + // Regardless of what command execute is called on, run on Root only + if c.HasParent() { + return c.Root().ExecuteC() + } + + // windows hook + if preExecHookFn != nil { + preExecHookFn(c) + } + + // initialize help as the last point possible to allow for user + // overriding + c.InitDefaultHelpCmd() + + args := c.args + + // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 + if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { + args = os.Args[1:] + } + + // initialize the hidden command to be used for bash completion + c.initCompleteCmd(args) + + var flags []string + if c.TraverseChildren { + cmd, flags, err = c.Traverse(args) + } else { + cmd, flags, err = c.Find(args) + } + if err != nil { + // If found parse to a subcommand and then failed, talk about the subcommand + if cmd != nil { + c = cmd + } + if !c.SilenceErrors { + c.Println("Error:", err.Error()) + c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) + } + return c, err + } + + cmd.commandCalledAs.called = true + if cmd.commandCalledAs.name == "" { + cmd.commandCalledAs.name = cmd.Name() + } + + // We have to pass global context to children command + // if context is present on the parent command. + if cmd.ctx == nil { + cmd.ctx = c.ctx + } + + err = cmd.execute(flags) + if err != nil { + // Always show help if requested, even if SilenceErrors is in + // effect + if err == flag.ErrHelp { + cmd.HelpFunc()(cmd, args) + return cmd, nil + } + + // If root command has SilentErrors flagged, + // all subcommands should respect it + if !cmd.SilenceErrors && !c.SilenceErrors { + c.Println("Error:", err.Error()) + } + + // If root command has SilentUsage flagged, + // all subcommands should respect it + if !cmd.SilenceUsage && !c.SilenceUsage { + c.Println(cmd.UsageString()) + } + } + return cmd, err +} + +func (c *Command) ValidateArgs(args []string) error { + if c.Args == nil { + return nil + } + return c.Args(c, args) +} + +func (c *Command) validateRequiredFlags() error { + flags := c.Flags() + missingFlagNames := []string{} + flags.VisitAll(func(pflag *flag.Flag) { + requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag] + if !found { + return + } + if (requiredAnnotation[0] == "true") && !pflag.Changed { + missingFlagNames = append(missingFlagNames, pflag.Name) + } + }) + + if len(missingFlagNames) > 0 { + return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) + } + return nil +} + +// InitDefaultHelpFlag adds default help flag to c. +// It is called automatically by executing the c or by calling help and usage. +// If c already has help flag, it will do nothing. +func (c *Command) InitDefaultHelpFlag() { + c.mergePersistentFlags() + if c.Flags().Lookup("help") == nil { + usage := "help for " + if c.Name() == "" { + usage += "this command" + } else { + usage += c.Name() + } + c.Flags().BoolP("help", "h", false, usage) + } +} + +// InitDefaultVersionFlag adds default version flag to c. +// It is called automatically by executing the c. +// If c already has a version flag, it will do nothing. +// If c.Version is empty, it will do nothing. +func (c *Command) InitDefaultVersionFlag() { + if c.Version == "" { + return + } + + c.mergePersistentFlags() + if c.Flags().Lookup("version") == nil { + usage := "version for " + if c.Name() == "" { + usage += "this command" + } else { + usage += c.Name() + } + if c.Flags().ShorthandLookup("v") == nil { + c.Flags().BoolP("version", "v", false, usage) + } else { + c.Flags().Bool("version", false, usage) + } + } +} + +// InitDefaultHelpCmd adds default help command to c. +// It is called automatically by executing the c or by calling help and usage. +// If c already has help command or c has no subcommands, it will do nothing. +func (c *Command) InitDefaultHelpCmd() { + if !c.HasSubCommands() { + return + } + + if c.helpCommand == nil { + c.helpCommand = &Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. +Simply type ` + c.Name() + ` help [path to command] for full details.`, + + Run: func(c *Command, args []string) { + cmd, _, e := c.Root().Find(args) + if cmd == nil || e != nil { + c.Printf("Unknown help topic %#q\n", args) + c.Root().Usage() + } else { + cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown + cmd.Help() + } + }, + } + } + c.RemoveCommand(c.helpCommand) + c.AddCommand(c.helpCommand) +} + +// ResetCommands delete parent, subcommand and help command from c. +func (c *Command) ResetCommands() { + c.parent = nil + c.commands = nil + c.helpCommand = nil + c.parentsPflags = nil +} + +// Sorts commands by their names. +type commandSorterByName []*Command + +func (c commandSorterByName) Len() int { return len(c) } +func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } + +// Commands returns a sorted slice of child commands. +func (c *Command) Commands() []*Command { + // do not sort commands if it already sorted or sorting was disabled + if EnableCommandSorting && !c.commandsAreSorted { + sort.Sort(commandSorterByName(c.commands)) + c.commandsAreSorted = true + } + return c.commands +} + +// AddCommand adds one or more commands to this parent command. +func (c *Command) AddCommand(cmds ...*Command) { + for i, x := range cmds { + if cmds[i] == c { + panic("Command can't be a child of itself") + } + cmds[i].parent = c + // update max lengths + usageLen := len(x.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(x.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(x.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + // If global normalization function exists, update all children + if c.globNormFunc != nil { + x.SetGlobalNormalizationFunc(c.globNormFunc) + } + c.commands = append(c.commands, x) + c.commandsAreSorted = false + } +} + +// RemoveCommand removes one or more commands from a parent command. +func (c *Command) RemoveCommand(cmds ...*Command) { + commands := []*Command{} +main: + for _, command := range c.commands { + for _, cmd := range cmds { + if command == cmd { + command.parent = nil + continue main + } + } + commands = append(commands, command) + } + c.commands = commands + // recompute all lengths + c.commandsMaxUseLen = 0 + c.commandsMaxCommandPathLen = 0 + c.commandsMaxNameLen = 0 + for _, command := range c.commands { + usageLen := len(command.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(command.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(command.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + } +} + +// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. +func (c *Command) Print(i ...interface{}) { + fmt.Fprint(c.OutOrStderr(), i...) +} + +// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. +func (c *Command) Println(i ...interface{}) { + c.Print(fmt.Sprintln(i...)) +} + +// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. +func (c *Command) Printf(format string, i ...interface{}) { + c.Print(fmt.Sprintf(format, i...)) +} + +// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErr(i ...interface{}) { + fmt.Fprint(c.ErrOrStderr(), i...) +} + +// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErrln(i ...interface{}) { + c.Print(fmt.Sprintln(i...)) +} + +// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErrf(format string, i ...interface{}) { + c.Print(fmt.Sprintf(format, i...)) +} + +// CommandPath returns the full path to this command. +func (c *Command) CommandPath() string { + if c.HasParent() { + return c.Parent().CommandPath() + " " + c.Name() + } + return c.Name() +} + +// UseLine puts out the full usage for a given command (including parents). +func (c *Command) UseLine() string { + var useline string + if c.HasParent() { + useline = c.parent.CommandPath() + " " + c.Use + } else { + useline = c.Use + } + if c.DisableFlagsInUseLine { + return useline + } + if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { + useline += " [flags]" + } + return useline +} + +// DebugFlags used to determine which flags have been assigned to which commands +// and which persist. +func (c *Command) DebugFlags() { + c.Println("DebugFlags called on", c.Name()) + var debugflags func(*Command) + + debugflags = func(x *Command) { + if x.HasFlags() || x.HasPersistentFlags() { + c.Println(x.Name()) + } + if x.HasFlags() { + x.flags.VisitAll(func(f *flag.Flag) { + if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") + } + }) + } + if x.HasPersistentFlags() { + x.pflags.VisitAll(func(f *flag.Flag) { + if x.HasFlags() { + if x.flags.Lookup(f.Name) == nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + }) + } + c.Println(x.flagErrorBuf) + if x.HasSubCommands() { + for _, y := range x.commands { + debugflags(y) + } + } + } + + debugflags(c) +} + +// Name returns the command's name: the first word in the use line. +func (c *Command) Name() string { + name := c.Use + i := strings.Index(name, " ") + if i >= 0 { + name = name[:i] + } + return name +} + +// HasAlias determines if a given string is an alias of the command. +func (c *Command) HasAlias(s string) bool { + for _, a := range c.Aliases { + if a == s { + return true + } + } + return false +} + +// CalledAs returns the command name or alias that was used to invoke +// this command or an empty string if the command has not been called. +func (c *Command) CalledAs() string { + if c.commandCalledAs.called { + return c.commandCalledAs.name + } + return "" +} + +// hasNameOrAliasPrefix returns true if the Name or any of aliases start +// with prefix +func (c *Command) hasNameOrAliasPrefix(prefix string) bool { + if strings.HasPrefix(c.Name(), prefix) { + c.commandCalledAs.name = c.Name() + return true + } + for _, alias := range c.Aliases { + if strings.HasPrefix(alias, prefix) { + c.commandCalledAs.name = alias + return true + } + } + return false +} + +// NameAndAliases returns a list of the command name and all aliases +func (c *Command) NameAndAliases() string { + return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") +} + +// HasExample determines if the command has example. +func (c *Command) HasExample() bool { + return len(c.Example) > 0 +} + +// Runnable determines if the command is itself runnable. +func (c *Command) Runnable() bool { + return c.Run != nil || c.RunE != nil +} + +// HasSubCommands determines if the command has children commands. +func (c *Command) HasSubCommands() bool { + return len(c.commands) > 0 +} + +// IsAvailableCommand determines if a command is available as a non-help command +// (this includes all non deprecated/hidden commands). +func (c *Command) IsAvailableCommand() bool { + if len(c.Deprecated) != 0 || c.Hidden { + return false + } + + if c.HasParent() && c.Parent().helpCommand == c { + return false + } + + if c.Runnable() || c.HasAvailableSubCommands() { + return true + } + + return false +} + +// IsAdditionalHelpTopicCommand determines if a command is an additional +// help topic command; additional help topic command is determined by the +// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that +// are runnable/hidden/deprecated. +// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. +func (c *Command) IsAdditionalHelpTopicCommand() bool { + // if a command is runnable, deprecated, or hidden it is not a 'help' command + if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { + return false + } + + // if any non-help sub commands are found, the command is not a 'help' command + for _, sub := range c.commands { + if !sub.IsAdditionalHelpTopicCommand() { + return false + } + } + + // the command either has no sub commands, or no non-help sub commands + return true +} + +// HasHelpSubCommands determines if a command has any available 'help' sub commands +// that need to be shown in the usage/help default template under 'additional help +// topics'. +func (c *Command) HasHelpSubCommands() bool { + // return true on the first found available 'help' sub command + for _, sub := range c.commands { + if sub.IsAdditionalHelpTopicCommand() { + return true + } + } + + // the command either has no sub commands, or no available 'help' sub commands + return false +} + +// HasAvailableSubCommands determines if a command has available sub commands that +// need to be shown in the usage/help default template under 'available commands'. +func (c *Command) HasAvailableSubCommands() bool { + // return true on the first found available (non deprecated/help/hidden) + // sub command + for _, sub := range c.commands { + if sub.IsAvailableCommand() { + return true + } + } + + // the command either has no sub commands, or no available (non deprecated/help/hidden) + // sub commands + return false +} + +// HasParent determines if the command is a child command. +func (c *Command) HasParent() bool { + return c.parent != nil +} + +// GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. +func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { + return c.globNormFunc +} + +// Flags returns the complete FlagSet that applies +// to this command (local and persistent declared here and by all parents). +func (c *Command) Flags() *flag.FlagSet { + if c.flags == nil { + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.flags.SetOutput(c.flagErrorBuf) + } + + return c.flags +} + +// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. +func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { + persistentFlags := c.PersistentFlags() + + out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.LocalFlags().VisitAll(func(f *flag.Flag) { + if persistentFlags.Lookup(f.Name) == nil { + out.AddFlag(f) + } + }) + return out +} + +// LocalFlags returns the local FlagSet specifically set in the current command. +func (c *Command) LocalFlags() *flag.FlagSet { + c.mergePersistentFlags() + + if c.lflags == nil { + c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.lflags.SetOutput(c.flagErrorBuf) + } + c.lflags.SortFlags = c.Flags().SortFlags + if c.globNormFunc != nil { + c.lflags.SetNormalizeFunc(c.globNormFunc) + } + + addToLocal := func(f *flag.Flag) { + if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { + c.lflags.AddFlag(f) + } + } + c.Flags().VisitAll(addToLocal) + c.PersistentFlags().VisitAll(addToLocal) + return c.lflags +} + +// InheritedFlags returns all flags which were inherited from parent commands. +func (c *Command) InheritedFlags() *flag.FlagSet { + c.mergePersistentFlags() + + if c.iflags == nil { + c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.iflags.SetOutput(c.flagErrorBuf) + } + + local := c.LocalFlags() + if c.globNormFunc != nil { + c.iflags.SetNormalizeFunc(c.globNormFunc) + } + + c.parentsPflags.VisitAll(func(f *flag.Flag) { + if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { + c.iflags.AddFlag(f) + } + }) + return c.iflags +} + +// NonInheritedFlags returns all flags which were not inherited from parent commands. +func (c *Command) NonInheritedFlags() *flag.FlagSet { + return c.LocalFlags() +} + +// PersistentFlags returns the persistent FlagSet specifically set in the current command. +func (c *Command) PersistentFlags() *flag.FlagSet { + if c.pflags == nil { + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.pflags.SetOutput(c.flagErrorBuf) + } + return c.pflags +} + +// ResetFlags deletes all flags from command. +func (c *Command) ResetFlags() { + c.flagErrorBuf = new(bytes.Buffer) + c.flagErrorBuf.Reset() + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.flags.SetOutput(c.flagErrorBuf) + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.pflags.SetOutput(c.flagErrorBuf) + + c.lflags = nil + c.iflags = nil + c.parentsPflags = nil +} + +// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). +func (c *Command) HasFlags() bool { + return c.Flags().HasFlags() +} + +// HasPersistentFlags checks if the command contains persistent flags. +func (c *Command) HasPersistentFlags() bool { + return c.PersistentFlags().HasFlags() +} + +// HasLocalFlags checks if the command has flags specifically declared locally. +func (c *Command) HasLocalFlags() bool { + return c.LocalFlags().HasFlags() +} + +// HasInheritedFlags checks if the command has flags inherited from its parent command. +func (c *Command) HasInheritedFlags() bool { + return c.InheritedFlags().HasFlags() +} + +// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire +// structure) which are not hidden or deprecated. +func (c *Command) HasAvailableFlags() bool { + return c.Flags().HasAvailableFlags() +} + +// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. +func (c *Command) HasAvailablePersistentFlags() bool { + return c.PersistentFlags().HasAvailableFlags() +} + +// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden +// or deprecated. +func (c *Command) HasAvailableLocalFlags() bool { + return c.LocalFlags().HasAvailableFlags() +} + +// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are +// not hidden or deprecated. +func (c *Command) HasAvailableInheritedFlags() bool { + return c.InheritedFlags().HasAvailableFlags() +} + +// Flag climbs up the command tree looking for matching flag. +func (c *Command) Flag(name string) (flag *flag.Flag) { + flag = c.Flags().Lookup(name) + + if flag == nil { + flag = c.persistentFlag(name) + } + + return +} + +// Recursively find matching persistent flag. +func (c *Command) persistentFlag(name string) (flag *flag.Flag) { + if c.HasPersistentFlags() { + flag = c.PersistentFlags().Lookup(name) + } + + if flag == nil { + c.updateParentsPflags() + flag = c.parentsPflags.Lookup(name) + } + return +} + +// ParseFlags parses persistent flag tree and local flags. +func (c *Command) ParseFlags(args []string) error { + if c.DisableFlagParsing { + return nil + } + + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + beforeErrorBufLen := c.flagErrorBuf.Len() + c.mergePersistentFlags() + + // do it here after merging all flags and just before parse + c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) + + err := c.Flags().Parse(args) + // Print warnings if they occurred (e.g. deprecated flag messages). + if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { + c.Print(c.flagErrorBuf.String()) + } + + return err +} + +// Parent returns a commands parent command. +func (c *Command) Parent() *Command { + return c.parent +} + +// mergePersistentFlags merges c.PersistentFlags() to c.Flags() +// and adds missing persistent flags of all parents. +func (c *Command) mergePersistentFlags() { + c.updateParentsPflags() + c.Flags().AddFlagSet(c.PersistentFlags()) + c.Flags().AddFlagSet(c.parentsPflags) +} + +// updateParentsPflags updates c.parentsPflags by adding +// new persistent flags of all parents. +// If c.parentsPflags == nil, it makes new. +func (c *Command) updateParentsPflags() { + if c.parentsPflags == nil { + c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.parentsPflags.SetOutput(c.flagErrorBuf) + c.parentsPflags.SortFlags = false + } + + if c.globNormFunc != nil { + c.parentsPflags.SetNormalizeFunc(c.globNormFunc) + } + + c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) + + c.VisitParents(func(parent *Command) { + c.parentsPflags.AddFlagSet(parent.PersistentFlags()) + }) +} diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go new file mode 100644 index 0000000000..6159c1cc19 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -0,0 +1,5 @@ +// +build !windows + +package cobra + +var preExecHookFn func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go new file mode 100644 index 0000000000..8768b1736d --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -0,0 +1,26 @@ +// +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) + } +} diff --git a/vendor/github.com/spf13/cobra/custom_completions.go b/vendor/github.com/spf13/cobra/custom_completions.go new file mode 100644 index 0000000000..ba57327c15 --- /dev/null +++ b/vendor/github.com/spf13/cobra/custom_completions.go @@ -0,0 +1,384 @@ +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 : + 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., someInvalidCmd + 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)) +} diff --git a/vendor/github.com/spf13/cobra/fish_completions.go b/vendor/github.com/spf13/cobra/fish_completions.go new file mode 100644 index 0000000000..c83609c83b --- /dev/null +++ b/vendor/github.com/spf13/cobra/fish_completions.go @@ -0,0 +1,172 @@ +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., -n=) + # 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) +} diff --git a/vendor/github.com/spf13/cobra/fish_completions.md b/vendor/github.com/spf13/cobra/fish_completions.md new file mode 100644 index 0000000000..6bfe5f88ef --- /dev/null +++ b/vendor/github.com/spf13/cobra/fish_completions.md @@ -0,0 +1,7 @@ +## 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. diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go new file mode 100644 index 0000000000..756c61b9dc --- /dev/null +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -0,0 +1,100 @@ +// 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) +} diff --git a/vendor/github.com/spf13/cobra/powershell_completions.md b/vendor/github.com/spf13/cobra/powershell_completions.md new file mode 100644 index 0000000000..afed802408 --- /dev/null +++ b/vendor/github.com/spf13/cobra/powershell_completions.md @@ -0,0 +1,14 @@ +# 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 diff --git a/vendor/github.com/spf13/cobra/shell_completions.go b/vendor/github.com/spf13/cobra/shell_completions.go new file mode 100644 index 0000000000..ba0af9cb55 --- /dev/null +++ b/vendor/github.com/spf13/cobra/shell_completions.go @@ -0,0 +1,85 @@ +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}) +} diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go new file mode 100644 index 0000000000..12755482f0 --- /dev/null +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -0,0 +1,336 @@ +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) +} diff --git a/vendor/github.com/spf13/cobra/zsh_completions.md b/vendor/github.com/spf13/cobra/zsh_completions.md new file mode 100644 index 0000000000..df9c2eac93 --- /dev/null +++ b/vendor/github.com/spf13/cobra/zsh_completions.md @@ -0,0 +1,39 @@ +## 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 +`_`. + +### 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 :) diff --git a/vendor/golang.org/x/sync/AUTHORS b/vendor/golang.org/x/sync/AUTHORS new file mode 100644 index 0000000000..15167cd746 --- /dev/null +++ b/vendor/golang.org/x/sync/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/sync/CONTRIBUTORS b/vendor/golang.org/x/sync/CONTRIBUTORS new file mode 100644 index 0000000000..1c4577e968 --- /dev/null +++ b/vendor/golang.org/x/sync/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/sync/LICENSE b/vendor/golang.org/x/sync/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/golang.org/x/sync/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 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. diff --git a/vendor/golang.org/x/sync/PATENTS b/vendor/golang.org/x/sync/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/golang.org/x/sync/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go new file mode 100644 index 0000000000..9857fe53d3 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -0,0 +1,66 @@ +// Copyright 2016 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 errgroup provides synchronization, error propagation, and Context +// cancelation for groups of goroutines working on subtasks of a common task. +package errgroup + +import ( + "context" + "sync" +) + +// A Group is a collection of goroutines working on subtasks that are part of +// the same overall task. +// +// A zero Group is valid and does not cancel on error. +type Group struct { + cancel func() + + wg sync.WaitGroup + + errOnce sync.Once + err error +} + +// WithContext returns a new Group and an associated Context derived from ctx. +// +// The derived Context is canceled the first time a function passed to Go +// returns a non-nil error or the first time Wait returns, whichever occurs +// first. +func WithContext(ctx context.Context) (*Group, context.Context) { + ctx, cancel := context.WithCancel(ctx) + return &Group{cancel: cancel}, ctx +} + +// Wait blocks until all function calls from the Go method have returned, then +// returns the first non-nil error (if any) from them. +func (g *Group) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel() + } + return g.err +} + +// Go calls the given function in a new goroutine. +// +// The first call to return a non-nil error cancels the group; its error will be +// returned by Wait. +func (g *Group) Go(f func() error) { + g.wg.Add(1) + + go func() { + defer g.wg.Done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel() + } + }) + } + }() +} diff --git a/vendor/golang.org/x/tools/AUTHORS b/vendor/golang.org/x/tools/AUTHORS new file mode 100644 index 0000000000..15167cd746 --- /dev/null +++ b/vendor/golang.org/x/tools/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/tools/CONTRIBUTORS b/vendor/golang.org/x/tools/CONTRIBUTORS new file mode 100644 index 0000000000..1c4577e968 --- /dev/null +++ b/vendor/golang.org/x/tools/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/tools/LICENSE b/vendor/golang.org/x/tools/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/golang.org/x/tools/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 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. diff --git a/vendor/golang.org/x/tools/PATENTS b/vendor/golang.org/x/tools/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/golang.org/x/tools/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go new file mode 100644 index 0000000000..6b7052b892 --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go @@ -0,0 +1,627 @@ +// Copyright 2013 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 astutil + +// This file defines utilities for working with source positions. + +import ( + "fmt" + "go/ast" + "go/token" + "sort" +) + +// PathEnclosingInterval returns the node that encloses the source +// interval [start, end), and all its ancestors up to the AST root. +// +// The definition of "enclosing" used by this function considers +// additional whitespace abutting a node to be enclosed by it. +// In this example: +// +// z := x + y // add them +// <-A-> +// <----B-----> +// +// the ast.BinaryExpr(+) node is considered to enclose interval B +// even though its [Pos()..End()) is actually only interval A. +// This behaviour makes user interfaces more tolerant of imperfect +// input. +// +// This function treats tokens as nodes, though they are not included +// in the result. e.g. PathEnclosingInterval("+") returns the +// enclosing ast.BinaryExpr("x + y"). +// +// If start==end, the 1-char interval following start is used instead. +// +// The 'exact' result is true if the interval contains only path[0] +// and perhaps some adjacent whitespace. It is false if the interval +// overlaps multiple children of path[0], or if it contains only +// interior whitespace of path[0]. +// In this example: +// +// z := x + y // add them +// <--C--> <---E--> +// ^ +// D +// +// intervals C, D and E are inexact. C is contained by the +// z-assignment statement, because it spans three of its children (:=, +// x, +). So too is the 1-char interval D, because it contains only +// interior whitespace of the assignment. E is considered interior +// whitespace of the BlockStmt containing the assignment. +// +// Precondition: [start, end) both lie within the same file as root. +// TODO(adonovan): return (nil, false) in this case and remove precond. +// Requires FileSet; see loader.tokenFileContainsPos. +// +// Postcondition: path is never nil; it always contains at least 'root'. +// +func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) { + // fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging + + // Precondition: node.[Pos..End) and adjoining whitespace contain [start, end). + var visit func(node ast.Node) bool + visit = func(node ast.Node) bool { + path = append(path, node) + + nodePos := node.Pos() + nodeEnd := node.End() + + // fmt.Printf("visit(%T, %d, %d)\n", node, nodePos, nodeEnd) // debugging + + // Intersect [start, end) with interval of node. + if start < nodePos { + start = nodePos + } + if end > nodeEnd { + end = nodeEnd + } + + // Find sole child that contains [start, end). + children := childrenOf(node) + l := len(children) + for i, child := range children { + // [childPos, childEnd) is unaugmented interval of child. + childPos := child.Pos() + childEnd := child.End() + + // [augPos, augEnd) is whitespace-augmented interval of child. + augPos := childPos + augEnd := childEnd + if i > 0 { + augPos = children[i-1].End() // start of preceding whitespace + } + if i < l-1 { + nextChildPos := children[i+1].Pos() + // Does [start, end) lie between child and next child? + if start >= augEnd && end <= nextChildPos { + return false // inexact match + } + augEnd = nextChildPos // end of following whitespace + } + + // fmt.Printf("\tchild %d: [%d..%d)\tcontains interval [%d..%d)?\n", + // i, augPos, augEnd, start, end) // debugging + + // Does augmented child strictly contain [start, end)? + if augPos <= start && end <= augEnd { + _, isToken := child.(tokenNode) + return isToken || visit(child) + } + + // Does [start, end) overlap multiple children? + // i.e. left-augmented child contains start + // but LR-augmented child does not contain end. + if start < childEnd && end > augEnd { + break + } + } + + // No single child contained [start, end), + // so node is the result. Is it exact? + + // (It's tempting to put this condition before the + // child loop, but it gives the wrong result in the + // case where a node (e.g. ExprStmt) and its sole + // child have equal intervals.) + if start == nodePos && end == nodeEnd { + return true // exact match + } + + return false // inexact: overlaps multiple children + } + + if start > end { + start, end = end, start + } + + if start < root.End() && end > root.Pos() { + if start == end { + end = start + 1 // empty interval => interval of size 1 + } + exact = visit(root) + + // Reverse the path: + for i, l := 0, len(path); i < l/2; i++ { + path[i], path[l-1-i] = path[l-1-i], path[i] + } + } else { + // Selection lies within whitespace preceding the + // first (or following the last) declaration in the file. + // The result nonetheless always includes the ast.File. + path = append(path, root) + } + + return +} + +// tokenNode is a dummy implementation of ast.Node for a single token. +// They are used transiently by PathEnclosingInterval but never escape +// this package. +// +type tokenNode struct { + pos token.Pos + end token.Pos +} + +func (n tokenNode) Pos() token.Pos { + return n.pos +} + +func (n tokenNode) End() token.Pos { + return n.end +} + +func tok(pos token.Pos, len int) ast.Node { + return tokenNode{pos, pos + token.Pos(len)} +} + +// childrenOf returns the direct non-nil children of ast.Node n. +// It may include fake ast.Node implementations for bare tokens. +// it is not safe to call (e.g.) ast.Walk on such nodes. +// +func childrenOf(n ast.Node) []ast.Node { + var children []ast.Node + + // First add nodes for all true subtrees. + ast.Inspect(n, func(node ast.Node) bool { + if node == n { // push n + return true // recur + } + if node != nil { // push child + children = append(children, node) + } + return false // no recursion + }) + + // Then add fake Nodes for bare tokens. + switch n := n.(type) { + case *ast.ArrayType: + children = append(children, + tok(n.Lbrack, len("[")), + tok(n.Elt.End(), len("]"))) + + case *ast.AssignStmt: + children = append(children, + tok(n.TokPos, len(n.Tok.String()))) + + case *ast.BasicLit: + children = append(children, + tok(n.ValuePos, len(n.Value))) + + case *ast.BinaryExpr: + children = append(children, tok(n.OpPos, len(n.Op.String()))) + + case *ast.BlockStmt: + children = append(children, + tok(n.Lbrace, len("{")), + tok(n.Rbrace, len("}"))) + + case *ast.BranchStmt: + children = append(children, + tok(n.TokPos, len(n.Tok.String()))) + + case *ast.CallExpr: + children = append(children, + tok(n.Lparen, len("(")), + tok(n.Rparen, len(")"))) + if n.Ellipsis != 0 { + children = append(children, tok(n.Ellipsis, len("..."))) + } + + case *ast.CaseClause: + if n.List == nil { + children = append(children, + tok(n.Case, len("default"))) + } else { + children = append(children, + tok(n.Case, len("case"))) + } + children = append(children, tok(n.Colon, len(":"))) + + case *ast.ChanType: + switch n.Dir { + case ast.RECV: + children = append(children, tok(n.Begin, len("<-chan"))) + case ast.SEND: + children = append(children, tok(n.Begin, len("chan<-"))) + case ast.RECV | ast.SEND: + children = append(children, tok(n.Begin, len("chan"))) + } + + case *ast.CommClause: + if n.Comm == nil { + children = append(children, + tok(n.Case, len("default"))) + } else { + children = append(children, + tok(n.Case, len("case"))) + } + children = append(children, tok(n.Colon, len(":"))) + + case *ast.Comment: + // nop + + case *ast.CommentGroup: + // nop + + case *ast.CompositeLit: + children = append(children, + tok(n.Lbrace, len("{")), + tok(n.Rbrace, len("{"))) + + case *ast.DeclStmt: + // nop + + case *ast.DeferStmt: + children = append(children, + tok(n.Defer, len("defer"))) + + case *ast.Ellipsis: + children = append(children, + tok(n.Ellipsis, len("..."))) + + case *ast.EmptyStmt: + // nop + + case *ast.ExprStmt: + // nop + + case *ast.Field: + // TODO(adonovan): Field.{Doc,Comment,Tag}? + + case *ast.FieldList: + children = append(children, + tok(n.Opening, len("(")), + tok(n.Closing, len(")"))) + + case *ast.File: + // TODO test: Doc + children = append(children, + tok(n.Package, len("package"))) + + case *ast.ForStmt: + children = append(children, + tok(n.For, len("for"))) + + case *ast.FuncDecl: + // TODO(adonovan): FuncDecl.Comment? + + // Uniquely, FuncDecl breaks the invariant that + // preorder traversal yields tokens in lexical order: + // in fact, FuncDecl.Recv precedes FuncDecl.Type.Func. + // + // As a workaround, we inline the case for FuncType + // here and order things correctly. + // + children = nil // discard ast.Walk(FuncDecl) info subtrees + children = append(children, tok(n.Type.Func, len("func"))) + if n.Recv != nil { + children = append(children, n.Recv) + } + children = append(children, n.Name) + if n.Type.Params != nil { + children = append(children, n.Type.Params) + } + if n.Type.Results != nil { + children = append(children, n.Type.Results) + } + if n.Body != nil { + children = append(children, n.Body) + } + + case *ast.FuncLit: + // nop + + case *ast.FuncType: + if n.Func != 0 { + children = append(children, + tok(n.Func, len("func"))) + } + + case *ast.GenDecl: + children = append(children, + tok(n.TokPos, len(n.Tok.String()))) + if n.Lparen != 0 { + children = append(children, + tok(n.Lparen, len("(")), + tok(n.Rparen, len(")"))) + } + + case *ast.GoStmt: + children = append(children, + tok(n.Go, len("go"))) + + case *ast.Ident: + children = append(children, + tok(n.NamePos, len(n.Name))) + + case *ast.IfStmt: + children = append(children, + tok(n.If, len("if"))) + + case *ast.ImportSpec: + // TODO(adonovan): ImportSpec.{Doc,EndPos}? + + case *ast.IncDecStmt: + children = append(children, + tok(n.TokPos, len(n.Tok.String()))) + + case *ast.IndexExpr: + children = append(children, + tok(n.Lbrack, len("{")), + tok(n.Rbrack, len("}"))) + + case *ast.InterfaceType: + children = append(children, + tok(n.Interface, len("interface"))) + + case *ast.KeyValueExpr: + children = append(children, + tok(n.Colon, len(":"))) + + case *ast.LabeledStmt: + children = append(children, + tok(n.Colon, len(":"))) + + case *ast.MapType: + children = append(children, + tok(n.Map, len("map"))) + + case *ast.ParenExpr: + children = append(children, + tok(n.Lparen, len("(")), + tok(n.Rparen, len(")"))) + + case *ast.RangeStmt: + children = append(children, + tok(n.For, len("for")), + tok(n.TokPos, len(n.Tok.String()))) + + case *ast.ReturnStmt: + children = append(children, + tok(n.Return, len("return"))) + + case *ast.SelectStmt: + children = append(children, + tok(n.Select, len("select"))) + + case *ast.SelectorExpr: + // nop + + case *ast.SendStmt: + children = append(children, + tok(n.Arrow, len("<-"))) + + case *ast.SliceExpr: + children = append(children, + tok(n.Lbrack, len("[")), + tok(n.Rbrack, len("]"))) + + case *ast.StarExpr: + children = append(children, tok(n.Star, len("*"))) + + case *ast.StructType: + children = append(children, tok(n.Struct, len("struct"))) + + case *ast.SwitchStmt: + children = append(children, tok(n.Switch, len("switch"))) + + case *ast.TypeAssertExpr: + children = append(children, + tok(n.Lparen-1, len(".")), + tok(n.Lparen, len("(")), + tok(n.Rparen, len(")"))) + + case *ast.TypeSpec: + // TODO(adonovan): TypeSpec.{Doc,Comment}? + + case *ast.TypeSwitchStmt: + children = append(children, tok(n.Switch, len("switch"))) + + case *ast.UnaryExpr: + children = append(children, tok(n.OpPos, len(n.Op.String()))) + + case *ast.ValueSpec: + // TODO(adonovan): ValueSpec.{Doc,Comment}? + + case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt: + // nop + } + + // TODO(adonovan): opt: merge the logic of ast.Inspect() into + // the switch above so we can make interleaved callbacks for + // both Nodes and Tokens in the right order and avoid the need + // to sort. + sort.Sort(byPos(children)) + + return children +} + +type byPos []ast.Node + +func (sl byPos) Len() int { + return len(sl) +} +func (sl byPos) Less(i, j int) bool { + return sl[i].Pos() < sl[j].Pos() +} +func (sl byPos) Swap(i, j int) { + sl[i], sl[j] = sl[j], sl[i] +} + +// NodeDescription returns a description of the concrete type of n suitable +// for a user interface. +// +// TODO(adonovan): in some cases (e.g. Field, FieldList, Ident, +// StarExpr) we could be much more specific given the path to the AST +// root. Perhaps we should do that. +// +func NodeDescription(n ast.Node) string { + switch n := n.(type) { + case *ast.ArrayType: + return "array type" + case *ast.AssignStmt: + return "assignment" + case *ast.BadDecl: + return "bad declaration" + case *ast.BadExpr: + return "bad expression" + case *ast.BadStmt: + return "bad statement" + case *ast.BasicLit: + return "basic literal" + case *ast.BinaryExpr: + return fmt.Sprintf("binary %s operation", n.Op) + case *ast.BlockStmt: + return "block" + case *ast.BranchStmt: + switch n.Tok { + case token.BREAK: + return "break statement" + case token.CONTINUE: + return "continue statement" + case token.GOTO: + return "goto statement" + case token.FALLTHROUGH: + return "fall-through statement" + } + case *ast.CallExpr: + if len(n.Args) == 1 && !n.Ellipsis.IsValid() { + return "function call (or conversion)" + } + return "function call" + case *ast.CaseClause: + return "case clause" + case *ast.ChanType: + return "channel type" + case *ast.CommClause: + return "communication clause" + case *ast.Comment: + return "comment" + case *ast.CommentGroup: + return "comment group" + case *ast.CompositeLit: + return "composite literal" + case *ast.DeclStmt: + return NodeDescription(n.Decl) + " statement" + case *ast.DeferStmt: + return "defer statement" + case *ast.Ellipsis: + return "ellipsis" + case *ast.EmptyStmt: + return "empty statement" + case *ast.ExprStmt: + return "expression statement" + case *ast.Field: + // Can be any of these: + // struct {x, y int} -- struct field(s) + // struct {T} -- anon struct field + // interface {I} -- interface embedding + // interface {f()} -- interface method + // func (A) func(B) C -- receiver, param(s), result(s) + return "field/method/parameter" + case *ast.FieldList: + return "field/method/parameter list" + case *ast.File: + return "source file" + case *ast.ForStmt: + return "for loop" + case *ast.FuncDecl: + return "function declaration" + case *ast.FuncLit: + return "function literal" + case *ast.FuncType: + return "function type" + case *ast.GenDecl: + switch n.Tok { + case token.IMPORT: + return "import declaration" + case token.CONST: + return "constant declaration" + case token.TYPE: + return "type declaration" + case token.VAR: + return "variable declaration" + } + case *ast.GoStmt: + return "go statement" + case *ast.Ident: + return "identifier" + case *ast.IfStmt: + return "if statement" + case *ast.ImportSpec: + return "import specification" + case *ast.IncDecStmt: + if n.Tok == token.INC { + return "increment statement" + } + return "decrement statement" + case *ast.IndexExpr: + return "index expression" + case *ast.InterfaceType: + return "interface type" + case *ast.KeyValueExpr: + return "key/value association" + case *ast.LabeledStmt: + return "statement label" + case *ast.MapType: + return "map type" + case *ast.Package: + return "package" + case *ast.ParenExpr: + return "parenthesized " + NodeDescription(n.X) + case *ast.RangeStmt: + return "range loop" + case *ast.ReturnStmt: + return "return statement" + case *ast.SelectStmt: + return "select statement" + case *ast.SelectorExpr: + return "selector" + case *ast.SendStmt: + return "channel send" + case *ast.SliceExpr: + return "slice expression" + case *ast.StarExpr: + return "*-operation" // load/store expr or pointer type + case *ast.StructType: + return "struct type" + case *ast.SwitchStmt: + return "switch statement" + case *ast.TypeAssertExpr: + return "type assertion" + case *ast.TypeSpec: + return "type specification" + case *ast.TypeSwitchStmt: + return "type switch" + case *ast.UnaryExpr: + return fmt.Sprintf("unary %s operation", n.Op) + case *ast.ValueSpec: + return "value specification" + + } + panic(fmt.Sprintf("unexpected node type: %T", n)) +} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/vendor/golang.org/x/tools/go/ast/astutil/imports.go new file mode 100644 index 0000000000..3e4b195368 --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/imports.go @@ -0,0 +1,481 @@ +// Copyright 2013 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 astutil contains common utilities for working with the Go AST. +package astutil // import "golang.org/x/tools/go/ast/astutil" + +import ( + "fmt" + "go/ast" + "go/token" + "strconv" + "strings" +) + +// AddImport adds the import path to the file f, if absent. +func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { + return AddNamedImport(fset, f, "", path) +} + +// AddNamedImport adds the import with the given name and path to the file f, if absent. +// If name is not empty, it is used to rename the import. +// +// For example, calling +// AddNamedImport(fset, f, "pathpkg", "path") +// adds +// import pathpkg "path" +func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) (added bool) { + if imports(f, name, path) { + return false + } + + newImport := &ast.ImportSpec{ + Path: &ast.BasicLit{ + Kind: token.STRING, + Value: strconv.Quote(path), + }, + } + if name != "" { + newImport.Name = &ast.Ident{Name: name} + } + + // Find an import decl to add to. + // The goal is to find an existing import + // whose import path has the longest shared + // prefix with path. + var ( + bestMatch = -1 // length of longest shared prefix + lastImport = -1 // index in f.Decls of the file's final import decl + impDecl *ast.GenDecl // import decl containing the best match + impIndex = -1 // spec index in impDecl containing the best match + + isThirdPartyPath = isThirdParty(path) + ) + for i, decl := range f.Decls { + gen, ok := decl.(*ast.GenDecl) + if ok && gen.Tok == token.IMPORT { + lastImport = i + // Do not add to import "C", to avoid disrupting the + // association with its doc comment, breaking cgo. + if declImports(gen, "C") { + continue + } + + // Match an empty import decl if that's all that is available. + if len(gen.Specs) == 0 && bestMatch == -1 { + impDecl = gen + } + + // Compute longest shared prefix with imports in this group and find best + // matched import spec. + // 1. Always prefer import spec with longest shared prefix. + // 2. While match length is 0, + // - for stdlib package: prefer first import spec. + // - for third party package: prefer first third party import spec. + // We cannot use last import spec as best match for third party package + // because grouped imports are usually placed last by goimports -local + // flag. + // See issue #19190. + seenAnyThirdParty := false + for j, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + p := importPath(impspec) + n := matchLen(p, path) + if n > bestMatch || (bestMatch == 0 && !seenAnyThirdParty && isThirdPartyPath) { + bestMatch = n + impDecl = gen + impIndex = j + } + seenAnyThirdParty = seenAnyThirdParty || isThirdParty(p) + } + } + } + + // If no import decl found, add one after the last import. + if impDecl == nil { + impDecl = &ast.GenDecl{ + Tok: token.IMPORT, + } + if lastImport >= 0 { + impDecl.TokPos = f.Decls[lastImport].End() + } else { + // There are no existing imports. + // Our new import, preceded by a blank line, goes after the package declaration + // and after the comment, if any, that starts on the same line as the + // package declaration. + impDecl.TokPos = f.Package + + file := fset.File(f.Package) + pkgLine := file.Line(f.Package) + for _, c := range f.Comments { + if file.Line(c.Pos()) > pkgLine { + break + } + // +2 for a blank line + impDecl.TokPos = c.End() + 2 + } + } + f.Decls = append(f.Decls, nil) + copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:]) + f.Decls[lastImport+1] = impDecl + } + + // Insert new import at insertAt. + insertAt := 0 + if impIndex >= 0 { + // insert after the found import + insertAt = impIndex + 1 + } + impDecl.Specs = append(impDecl.Specs, nil) + copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:]) + impDecl.Specs[insertAt] = newImport + pos := impDecl.Pos() + if insertAt > 0 { + // If there is a comment after an existing import, preserve the comment + // position by adding the new import after the comment. + if spec, ok := impDecl.Specs[insertAt-1].(*ast.ImportSpec); ok && spec.Comment != nil { + pos = spec.Comment.End() + } else { + // Assign same position as the previous import, + // so that the sorter sees it as being in the same block. + pos = impDecl.Specs[insertAt-1].Pos() + } + } + if newImport.Name != nil { + newImport.Name.NamePos = pos + } + newImport.Path.ValuePos = pos + newImport.EndPos = pos + + // Clean up parens. impDecl contains at least one spec. + if len(impDecl.Specs) == 1 { + // Remove unneeded parens. + impDecl.Lparen = token.NoPos + } else if !impDecl.Lparen.IsValid() { + // impDecl needs parens added. + impDecl.Lparen = impDecl.Specs[0].Pos() + } + + f.Imports = append(f.Imports, newImport) + + if len(f.Decls) <= 1 { + return true + } + + // Merge all the import declarations into the first one. + var first *ast.GenDecl + for i := 0; i < len(f.Decls); i++ { + decl := f.Decls[i] + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { + continue + } + if first == nil { + first = gen + continue // Don't touch the first one. + } + // We now know there is more than one package in this import + // declaration. Ensure that it ends up parenthesized. + first.Lparen = first.Pos() + // Move the imports of the other import declaration to the first one. + for _, spec := range gen.Specs { + spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() + first.Specs = append(first.Specs, spec) + } + f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) + i-- + } + + return true +} + +func isThirdParty(importPath string) bool { + // Third party package import path usually contains "." (".com", ".org", ...) + // This logic is taken from golang.org/x/tools/imports package. + return strings.Contains(importPath, ".") +} + +// DeleteImport deletes the import path from the file f, if present. +// If there are duplicate import declarations, all matching ones are deleted. +func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool) { + return DeleteNamedImport(fset, f, "", path) +} + +// DeleteNamedImport deletes the import with the given name and path from the file f, if present. +// If there are duplicate import declarations, all matching ones are deleted. +func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (deleted bool) { + var delspecs []*ast.ImportSpec + var delcomments []*ast.CommentGroup + + // Find the import nodes that import path, if any. + for i := 0; i < len(f.Decls); i++ { + decl := f.Decls[i] + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT { + continue + } + for j := 0; j < len(gen.Specs); j++ { + spec := gen.Specs[j] + impspec := spec.(*ast.ImportSpec) + if importName(impspec) != name || importPath(impspec) != path { + continue + } + + // We found an import spec that imports path. + // Delete it. + delspecs = append(delspecs, impspec) + deleted = true + copy(gen.Specs[j:], gen.Specs[j+1:]) + gen.Specs = gen.Specs[:len(gen.Specs)-1] + + // If this was the last import spec in this decl, + // delete the decl, too. + if len(gen.Specs) == 0 { + copy(f.Decls[i:], f.Decls[i+1:]) + f.Decls = f.Decls[:len(f.Decls)-1] + i-- + break + } else if len(gen.Specs) == 1 { + if impspec.Doc != nil { + delcomments = append(delcomments, impspec.Doc) + } + if impspec.Comment != nil { + delcomments = append(delcomments, impspec.Comment) + } + for _, cg := range f.Comments { + // Found comment on the same line as the import spec. + if cg.End() < impspec.Pos() && fset.Position(cg.End()).Line == fset.Position(impspec.Pos()).Line { + delcomments = append(delcomments, cg) + break + } + } + + spec := gen.Specs[0].(*ast.ImportSpec) + + // Move the documentation right after the import decl. + if spec.Doc != nil { + for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Doc.Pos()).Line { + fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) + } + } + for _, cg := range f.Comments { + if cg.End() < spec.Pos() && fset.Position(cg.End()).Line == fset.Position(spec.Pos()).Line { + for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Pos()).Line { + fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) + } + break + } + } + } + if j > 0 { + lastImpspec := gen.Specs[j-1].(*ast.ImportSpec) + lastLine := fset.Position(lastImpspec.Path.ValuePos).Line + line := fset.Position(impspec.Path.ValuePos).Line + + // We deleted an entry but now there may be + // a blank line-sized hole where the import was. + if line-lastLine > 1 { + // There was a blank line immediately preceding the deleted import, + // so there's no need to close the hole. + // Do nothing. + } else if line != fset.File(gen.Rparen).LineCount() { + // There was no blank line. Close the hole. + fset.File(gen.Rparen).MergeLine(line) + } + } + j-- + } + } + + // Delete imports from f.Imports. + for i := 0; i < len(f.Imports); i++ { + imp := f.Imports[i] + for j, del := range delspecs { + if imp == del { + copy(f.Imports[i:], f.Imports[i+1:]) + f.Imports = f.Imports[:len(f.Imports)-1] + copy(delspecs[j:], delspecs[j+1:]) + delspecs = delspecs[:len(delspecs)-1] + i-- + break + } + } + } + + // Delete comments from f.Comments. + for i := 0; i < len(f.Comments); i++ { + cg := f.Comments[i] + for j, del := range delcomments { + if cg == del { + copy(f.Comments[i:], f.Comments[i+1:]) + f.Comments = f.Comments[:len(f.Comments)-1] + copy(delcomments[j:], delcomments[j+1:]) + delcomments = delcomments[:len(delcomments)-1] + i-- + break + } + } + } + + if len(delspecs) > 0 { + panic(fmt.Sprintf("deleted specs from Decls but not Imports: %v", delspecs)) + } + + return +} + +// RewriteImport rewrites any import of path oldPath to path newPath. +func RewriteImport(fset *token.FileSet, f *ast.File, oldPath, newPath string) (rewrote bool) { + for _, imp := range f.Imports { + if importPath(imp) == oldPath { + rewrote = true + // record old End, because the default is to compute + // it using the length of imp.Path.Value. + imp.EndPos = imp.End() + imp.Path.Value = strconv.Quote(newPath) + } + } + return +} + +// UsesImport reports whether a given import is used. +func UsesImport(f *ast.File, path string) (used bool) { + spec := importSpec(f, path) + if spec == nil { + return + } + + name := spec.Name.String() + switch name { + case "": + // If the package name is not explicitly specified, + // make an educated guess. This is not guaranteed to be correct. + lastSlash := strings.LastIndex(path, "/") + if lastSlash == -1 { + name = path + } else { + name = path[lastSlash+1:] + } + case "_", ".": + // Not sure if this import is used - err on the side of caution. + return true + } + + ast.Walk(visitFn(func(n ast.Node) { + sel, ok := n.(*ast.SelectorExpr) + if ok && isTopName(sel.X, name) { + used = true + } + }), f) + + return +} + +type visitFn func(node ast.Node) + +func (fn visitFn) Visit(node ast.Node) ast.Visitor { + fn(node) + return fn +} + +// imports reports whether f has an import with the specified name and path. +func imports(f *ast.File, name, path string) bool { + for _, s := range f.Imports { + if importName(s) == name && importPath(s) == path { + return true + } + } + return false +} + +// importSpec returns the import spec if f imports path, +// or nil otherwise. +func importSpec(f *ast.File, path string) *ast.ImportSpec { + for _, s := range f.Imports { + if importPath(s) == path { + return s + } + } + return nil +} + +// importName returns the name of s, +// or "" if the import is not named. +func importName(s *ast.ImportSpec) string { + if s.Name == nil { + return "" + } + return s.Name.Name +} + +// importPath returns the unquoted import path of s, +// or "" if the path is not properly quoted. +func importPath(s *ast.ImportSpec) string { + t, err := strconv.Unquote(s.Path.Value) + if err != nil { + return "" + } + return t +} + +// declImports reports whether gen contains an import of path. +func declImports(gen *ast.GenDecl, path string) bool { + if gen.Tok != token.IMPORT { + return false + } + for _, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + if importPath(impspec) == path { + return true + } + } + return false +} + +// matchLen returns the length of the longest path segment prefix shared by x and y. +func matchLen(x, y string) int { + n := 0 + for i := 0; i < len(x) && i < len(y) && x[i] == y[i]; i++ { + if x[i] == '/' { + n++ + } + } + return n +} + +// isTopName returns true if n is a top-level unresolved identifier with the given name. +func isTopName(n ast.Expr, name string) bool { + id, ok := n.(*ast.Ident) + return ok && id.Name == name && id.Obj == nil +} + +// Imports returns the file imports grouped by paragraph. +func Imports(fset *token.FileSet, f *ast.File) [][]*ast.ImportSpec { + var groups [][]*ast.ImportSpec + + for _, decl := range f.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok || genDecl.Tok != token.IMPORT { + break + } + + group := []*ast.ImportSpec{} + + var lastLine int + for _, spec := range genDecl.Specs { + importSpec := spec.(*ast.ImportSpec) + pos := importSpec.Path.ValuePos + line := fset.Position(pos).Line + if lastLine > 0 && pos > 0 && line-lastLine > 1 { + groups = append(groups, group) + group = []*ast.ImportSpec{} + } + group = append(group, importSpec) + lastLine = line + } + groups = append(groups, group) + } + + return groups +} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go new file mode 100644 index 0000000000..cf72ea990b --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go @@ -0,0 +1,477 @@ +// Copyright 2017 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 astutil + +import ( + "fmt" + "go/ast" + "reflect" + "sort" +) + +// An ApplyFunc is invoked by Apply for each node n, even if n is nil, +// before and/or after the node's children, using a Cursor describing +// the current node and providing operations on it. +// +// The return value of ApplyFunc controls the syntax tree traversal. +// See Apply for details. +type ApplyFunc func(*Cursor) bool + +// Apply traverses a syntax tree recursively, starting with root, +// and calling pre and post for each node as described below. +// Apply returns the syntax tree, possibly modified. +// +// If pre is not nil, it is called for each node before the node's +// children are traversed (pre-order). If pre returns false, no +// children are traversed, and post is not called for that node. +// +// If post is not nil, and a prior call of pre didn't return false, +// post is called for each node after its children are traversed +// (post-order). If post returns false, traversal is terminated and +// Apply returns immediately. +// +// Only fields that refer to AST nodes are considered children; +// i.e., token.Pos, Scopes, Objects, and fields of basic types +// (strings, etc.) are ignored. +// +// Children are traversed in the order in which they appear in the +// respective node's struct definition. A package's files are +// traversed in the filenames' alphabetical order. +// +func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { + parent := &struct{ ast.Node }{root} + defer func() { + if r := recover(); r != nil && r != abort { + panic(r) + } + result = parent.Node + }() + a := &application{pre: pre, post: post} + a.apply(parent, "Node", nil, root) + return +} + +var abort = new(int) // singleton, to signal termination of Apply + +// A Cursor describes a node encountered during Apply. +// Information about the node and its parent is available +// from the Node, Parent, Name, and Index methods. +// +// If p is a variable of type and value of the current parent node +// c.Parent(), and f is the field identifier with name c.Name(), +// the following invariants hold: +// +// p.f == c.Node() if c.Index() < 0 +// p.f[c.Index()] == c.Node() if c.Index() >= 0 +// +// The methods Replace, Delete, InsertBefore, and InsertAfter +// can be used to change the AST without disrupting Apply. +type Cursor struct { + parent ast.Node + name string + iter *iterator // valid if non-nil + node ast.Node +} + +// Node returns the current Node. +func (c *Cursor) Node() ast.Node { return c.node } + +// Parent returns the parent of the current Node. +func (c *Cursor) Parent() ast.Node { return c.parent } + +// Name returns the name of the parent Node field that contains the current Node. +// If the parent is a *ast.Package and the current Node is a *ast.File, Name returns +// the filename for the current Node. +func (c *Cursor) Name() string { return c.name } + +// Index reports the index >= 0 of the current Node in the slice of Nodes that +// contains it, or a value < 0 if the current Node is not part of a slice. +// The index of the current node changes if InsertBefore is called while +// processing the current node. +func (c *Cursor) Index() int { + if c.iter != nil { + return c.iter.index + } + return -1 +} + +// field returns the current node's parent field value. +func (c *Cursor) field() reflect.Value { + return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) +} + +// Replace replaces the current Node with n. +// The replacement node is not walked by Apply. +func (c *Cursor) Replace(n ast.Node) { + if _, ok := c.node.(*ast.File); ok { + file, ok := n.(*ast.File) + if !ok { + panic("attempt to replace *ast.File with non-*ast.File") + } + c.parent.(*ast.Package).Files[c.name] = file + return + } + + v := c.field() + if i := c.Index(); i >= 0 { + v = v.Index(i) + } + v.Set(reflect.ValueOf(n)) +} + +// Delete deletes the current Node from its containing slice. +// If the current Node is not part of a slice, Delete panics. +// As a special case, if the current node is a package file, +// Delete removes it from the package's Files map. +func (c *Cursor) Delete() { + if _, ok := c.node.(*ast.File); ok { + delete(c.parent.(*ast.Package).Files, c.name) + return + } + + i := c.Index() + if i < 0 { + panic("Delete node not contained in slice") + } + v := c.field() + l := v.Len() + reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) + v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) + v.SetLen(l - 1) + c.iter.step-- +} + +// InsertAfter inserts n after the current Node in its containing slice. +// If the current Node is not part of a slice, InsertAfter panics. +// Apply does not walk n. +func (c *Cursor) InsertAfter(n ast.Node) { + i := c.Index() + if i < 0 { + panic("InsertAfter node not contained in slice") + } + v := c.field() + v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) + l := v.Len() + reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) + v.Index(i + 1).Set(reflect.ValueOf(n)) + c.iter.step++ +} + +// InsertBefore inserts n before the current Node in its containing slice. +// If the current Node is not part of a slice, InsertBefore panics. +// Apply will not walk n. +func (c *Cursor) InsertBefore(n ast.Node) { + i := c.Index() + if i < 0 { + panic("InsertBefore node not contained in slice") + } + v := c.field() + v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) + l := v.Len() + reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) + v.Index(i).Set(reflect.ValueOf(n)) + c.iter.index++ +} + +// application carries all the shared data so we can pass it around cheaply. +type application struct { + pre, post ApplyFunc + cursor Cursor + iter iterator +} + +func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { + // convert typed nil into untyped nil + if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { + n = nil + } + + // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead + saved := a.cursor + a.cursor.parent = parent + a.cursor.name = name + a.cursor.iter = iter + a.cursor.node = n + + if a.pre != nil && !a.pre(&a.cursor) { + a.cursor = saved + return + } + + // walk children + // (the order of the cases matches the order of the corresponding node types in go/ast) + switch n := n.(type) { + case nil: + // nothing to do + + // Comments and fields + case *ast.Comment: + // nothing to do + + case *ast.CommentGroup: + if n != nil { + a.applyList(n, "List") + } + + case *ast.Field: + a.apply(n, "Doc", nil, n.Doc) + a.applyList(n, "Names") + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Tag", nil, n.Tag) + a.apply(n, "Comment", nil, n.Comment) + + case *ast.FieldList: + a.applyList(n, "List") + + // Expressions + case *ast.BadExpr, *ast.Ident, *ast.BasicLit: + // nothing to do + + case *ast.Ellipsis: + a.apply(n, "Elt", nil, n.Elt) + + case *ast.FuncLit: + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Body", nil, n.Body) + + case *ast.CompositeLit: + a.apply(n, "Type", nil, n.Type) + a.applyList(n, "Elts") + + case *ast.ParenExpr: + a.apply(n, "X", nil, n.X) + + case *ast.SelectorExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Sel", nil, n.Sel) + + case *ast.IndexExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Index", nil, n.Index) + + case *ast.SliceExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Low", nil, n.Low) + a.apply(n, "High", nil, n.High) + a.apply(n, "Max", nil, n.Max) + + case *ast.TypeAssertExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Type", nil, n.Type) + + case *ast.CallExpr: + a.apply(n, "Fun", nil, n.Fun) + a.applyList(n, "Args") + + case *ast.StarExpr: + a.apply(n, "X", nil, n.X) + + case *ast.UnaryExpr: + a.apply(n, "X", nil, n.X) + + case *ast.BinaryExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Y", nil, n.Y) + + case *ast.KeyValueExpr: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + + // Types + case *ast.ArrayType: + a.apply(n, "Len", nil, n.Len) + a.apply(n, "Elt", nil, n.Elt) + + case *ast.StructType: + a.apply(n, "Fields", nil, n.Fields) + + case *ast.FuncType: + a.apply(n, "Params", nil, n.Params) + a.apply(n, "Results", nil, n.Results) + + case *ast.InterfaceType: + a.apply(n, "Methods", nil, n.Methods) + + case *ast.MapType: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + + case *ast.ChanType: + a.apply(n, "Value", nil, n.Value) + + // Statements + case *ast.BadStmt: + // nothing to do + + case *ast.DeclStmt: + a.apply(n, "Decl", nil, n.Decl) + + case *ast.EmptyStmt: + // nothing to do + + case *ast.LabeledStmt: + a.apply(n, "Label", nil, n.Label) + a.apply(n, "Stmt", nil, n.Stmt) + + case *ast.ExprStmt: + a.apply(n, "X", nil, n.X) + + case *ast.SendStmt: + a.apply(n, "Chan", nil, n.Chan) + a.apply(n, "Value", nil, n.Value) + + case *ast.IncDecStmt: + a.apply(n, "X", nil, n.X) + + case *ast.AssignStmt: + a.applyList(n, "Lhs") + a.applyList(n, "Rhs") + + case *ast.GoStmt: + a.apply(n, "Call", nil, n.Call) + + case *ast.DeferStmt: + a.apply(n, "Call", nil, n.Call) + + case *ast.ReturnStmt: + a.applyList(n, "Results") + + case *ast.BranchStmt: + a.apply(n, "Label", nil, n.Label) + + case *ast.BlockStmt: + a.applyList(n, "List") + + case *ast.IfStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Cond", nil, n.Cond) + a.apply(n, "Body", nil, n.Body) + a.apply(n, "Else", nil, n.Else) + + case *ast.CaseClause: + a.applyList(n, "List") + a.applyList(n, "Body") + + case *ast.SwitchStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Tag", nil, n.Tag) + a.apply(n, "Body", nil, n.Body) + + case *ast.TypeSwitchStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Assign", nil, n.Assign) + a.apply(n, "Body", nil, n.Body) + + case *ast.CommClause: + a.apply(n, "Comm", nil, n.Comm) + a.applyList(n, "Body") + + case *ast.SelectStmt: + a.apply(n, "Body", nil, n.Body) + + case *ast.ForStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Cond", nil, n.Cond) + a.apply(n, "Post", nil, n.Post) + a.apply(n, "Body", nil, n.Body) + + case *ast.RangeStmt: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + a.apply(n, "X", nil, n.X) + a.apply(n, "Body", nil, n.Body) + + // Declarations + case *ast.ImportSpec: + a.apply(n, "Doc", nil, n.Doc) + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Path", nil, n.Path) + a.apply(n, "Comment", nil, n.Comment) + + case *ast.ValueSpec: + a.apply(n, "Doc", nil, n.Doc) + a.applyList(n, "Names") + a.apply(n, "Type", nil, n.Type) + a.applyList(n, "Values") + a.apply(n, "Comment", nil, n.Comment) + + case *ast.TypeSpec: + a.apply(n, "Doc", nil, n.Doc) + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Comment", nil, n.Comment) + + case *ast.BadDecl: + // nothing to do + + case *ast.GenDecl: + a.apply(n, "Doc", nil, n.Doc) + a.applyList(n, "Specs") + + case *ast.FuncDecl: + a.apply(n, "Doc", nil, n.Doc) + a.apply(n, "Recv", nil, n.Recv) + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Body", nil, n.Body) + + // Files and packages + case *ast.File: + a.apply(n, "Doc", nil, n.Doc) + a.apply(n, "Name", nil, n.Name) + a.applyList(n, "Decls") + // Don't walk n.Comments; they have either been walked already if + // they are Doc comments, or they can be easily walked explicitly. + + case *ast.Package: + // collect and sort names for reproducible behavior + var names []string + for name := range n.Files { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + a.apply(n, name, nil, n.Files[name]) + } + + default: + panic(fmt.Sprintf("Apply: unexpected node type %T", n)) + } + + if a.post != nil && !a.post(&a.cursor) { + panic(abort) + } + + a.cursor = saved +} + +// An iterator controls iteration over a slice of nodes. +type iterator struct { + index, step int +} + +func (a *application) applyList(parent ast.Node, name string) { + // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead + saved := a.iter + a.iter.index = 0 + for { + // must reload parent.name each time, since cursor modifications might change it + v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) + if a.iter.index >= v.Len() { + break + } + + // element x may be nil in a bad AST - be cautious + var x ast.Node + if e := v.Index(a.iter.index); e.IsValid() { + x = e.Interface().(ast.Node) + } + + a.iter.step = 1 + a.apply(parent, name, &a.iter, x) + a.iter.index += a.iter.step + } + a.iter = saved +} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/util.go b/vendor/golang.org/x/tools/go/ast/astutil/util.go new file mode 100644 index 0000000000..7630629824 --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/util.go @@ -0,0 +1,14 @@ +package astutil + +import "go/ast" + +// Unparen returns e with any enclosing parentheses stripped. +func Unparen(e ast.Expr) ast.Expr { + for { + p, ok := e.(*ast.ParenExpr) + if !ok { + return e + } + e = p.X + } +} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go new file mode 100644 index 0000000000..98b3987b97 --- /dev/null +++ b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -0,0 +1,109 @@ +// Copyright 2016 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 gcexportdata provides functions for locating, reading, and +// writing export data files containing type information produced by the +// gc compiler. This package supports go1.7 export data format and all +// later versions. +// +// Although it might seem convenient for this package to live alongside +// go/types in the standard library, this would cause version skew +// problems for developer tools that use it, since they must be able to +// consume the outputs of the gc compiler both before and after a Go +// update such as from Go 1.7 to Go 1.8. Because this package lives in +// golang.org/x/tools, sites can update their version of this repo some +// time before the Go 1.8 release and rebuild and redeploy their +// developer tools, which will then be able to consume both Go 1.7 and +// Go 1.8 export data files, so they will work before and after the +// Go update. (See discussion at https://golang.org/issue/15651.) +// +package gcexportdata // import "golang.org/x/tools/go/gcexportdata" + +import ( + "bufio" + "bytes" + "fmt" + "go/token" + "go/types" + "io" + "io/ioutil" + + "golang.org/x/tools/go/internal/gcimporter" +) + +// Find returns the name of an object (.o) or archive (.a) file +// containing type information for the specified import path, +// using the workspace layout conventions of go/build. +// If no file was found, an empty filename is returned. +// +// A relative srcDir is interpreted relative to the current working directory. +// +// Find also returns the package's resolved (canonical) import path, +// reflecting the effects of srcDir and vendoring on importPath. +func Find(importPath, srcDir string) (filename, path string) { + return gcimporter.FindPkg(importPath, srcDir) +} + +// NewReader returns a reader for the export data section of an object +// (.o) or archive (.a) file read from r. The new reader may provide +// additional trailing data beyond the end of the export data. +func NewReader(r io.Reader) (io.Reader, error) { + buf := bufio.NewReader(r) + _, err := gcimporter.FindExportData(buf) + // If we ever switch to a zip-like archive format with the ToC + // at the end, we can return the correct portion of export data, + // but for now we must return the entire rest of the file. + return buf, err +} + +// Read reads export data from in, decodes it, and returns type +// information for the package. +// The package name is specified by path. +// File position information is added to fset. +// +// Read may inspect and add to the imports map to ensure that references +// within the export data to other packages are consistent. The caller +// must ensure that imports[path] does not exist, or exists but is +// incomplete (see types.Package.Complete), and Read inserts the +// resulting package into this map entry. +// +// On return, the state of the reader is undefined. +func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { + data, err := ioutil.ReadAll(in) + if err != nil { + return nil, fmt.Errorf("reading export data for %q: %v", path, err) + } + + if bytes.HasPrefix(data, []byte("!")) { + return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path) + } + + // The App Engine Go runtime v1.6 uses the old export data format. + // TODO(adonovan): delete once v1.7 has been around for a while. + if bytes.HasPrefix(data, []byte("package ")) { + return gcimporter.ImportData(imports, path, path, bytes.NewReader(data)) + } + + // The indexed export format starts with an 'i'; the older + // binary export format starts with a 'c', 'd', or 'v' + // (from "version"). Select appropriate importer. + if len(data) > 0 && data[0] == 'i' { + _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) + return pkg, err + } + + _, pkg, err := gcimporter.BImportData(fset, imports, data, path) + return pkg, err +} + +// Write writes encoded type information for the specified package to out. +// The FileSet provides file position information for named objects. +func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error { + b, err := gcimporter.BExportData(fset, pkg) + if err != nil { + return err + } + _, err = out.Write(b) + return err +} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/importer.go b/vendor/golang.org/x/tools/go/gcexportdata/importer.go new file mode 100644 index 0000000000..efe221e7e1 --- /dev/null +++ b/vendor/golang.org/x/tools/go/gcexportdata/importer.go @@ -0,0 +1,73 @@ +// Copyright 2016 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 gcexportdata + +import ( + "fmt" + "go/token" + "go/types" + "os" +) + +// NewImporter returns a new instance of the types.Importer interface +// that reads type information from export data files written by gc. +// The Importer also satisfies types.ImporterFrom. +// +// Export data files are located using "go build" workspace conventions +// and the build.Default context. +// +// Use this importer instead of go/importer.For("gc", ...) to avoid the +// version-skew problems described in the documentation of this package, +// or to control the FileSet or access the imports map populated during +// package loading. +// +func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom { + return importer{fset, imports} +} + +type importer struct { + fset *token.FileSet + imports map[string]*types.Package +} + +func (imp importer) Import(importPath string) (*types.Package, error) { + return imp.ImportFrom(importPath, "", 0) +} + +func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) { + filename, path := Find(importPath, srcDir) + if filename == "" { + if importPath == "unsafe" { + // Even for unsafe, call Find first in case + // the package was vendored. + return types.Unsafe, nil + } + return nil, fmt.Errorf("can't find import: %s", importPath) + } + + if pkg, ok := imp.imports[path]; ok && pkg.Complete() { + return pkg, nil // cache hit + } + + // open file + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer func() { + f.Close() + if err != nil { + // add file name to error + err = fmt.Errorf("reading export data: %s: %v", filename, err) + } + }() + + r, err := NewReader(f) + if err != nil { + return nil, err + } + + return Read(r, imp.fset, imp.imports, path) +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go new file mode 100644 index 0000000000..a807d0aaa2 --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go @@ -0,0 +1,852 @@ +// Copyright 2016 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. + +// Binary package export. +// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; +// see that file for specification of the format. + +package gcimporter + +import ( + "bytes" + "encoding/binary" + "fmt" + "go/ast" + "go/constant" + "go/token" + "go/types" + "math" + "math/big" + "sort" + "strings" +) + +// If debugFormat is set, each integer and string value is preceded by a marker +// and position information in the encoding. This mechanism permits an importer +// to recognize immediately when it is out of sync. The importer recognizes this +// mode automatically (i.e., it can import export data produced with debugging +// support even if debugFormat is not set at the time of import). This mode will +// lead to massively larger export data (by a factor of 2 to 3) and should only +// be enabled during development and debugging. +// +// NOTE: This flag is the first flag to enable if importing dies because of +// (suspected) format errors, and whenever a change is made to the format. +const debugFormat = false // default: false + +// If trace is set, debugging output is printed to std out. +const trace = false // default: false + +// Current export format version. Increase with each format change. +// Note: The latest binary (non-indexed) export format is at version 6. +// This exporter is still at level 4, but it doesn't matter since +// the binary importer can handle older versions just fine. +// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE +// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMEMTED HERE +// 4: type name objects support type aliases, uses aliasTag +// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) +// 2: removed unused bool in ODCL export (compiler only) +// 1: header format change (more regular), export package for _ struct fields +// 0: Go1.7 encoding +const exportVersion = 4 + +// trackAllTypes enables cycle tracking for all types, not just named +// types. The existing compiler invariants assume that unnamed types +// that are not completely set up are not used, or else there are spurious +// errors. +// If disabled, only named types are tracked, possibly leading to slightly +// less efficient encoding in rare cases. It also prevents the export of +// some corner-case type declarations (but those are not handled correctly +// with with the textual export format either). +// TODO(gri) enable and remove once issues caused by it are fixed +const trackAllTypes = false + +type exporter struct { + fset *token.FileSet + out bytes.Buffer + + // object -> index maps, indexed in order of serialization + strIndex map[string]int + pkgIndex map[*types.Package]int + typIndex map[types.Type]int + + // position encoding + posInfoFormat bool + prevFile string + prevLine int + + // debugging support + written int // bytes written + indent int // for trace +} + +// internalError represents an error generated inside this package. +type internalError string + +func (e internalError) Error() string { return "gcimporter: " + string(e) } + +func internalErrorf(format string, args ...interface{}) error { + return internalError(fmt.Sprintf(format, args...)) +} + +// BExportData returns binary export data for pkg. +// If no file set is provided, position info will be missing. +func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { + defer func() { + if e := recover(); e != nil { + if ierr, ok := e.(internalError); ok { + err = ierr + return + } + // Not an internal error; panic again. + panic(e) + } + }() + + p := exporter{ + fset: fset, + strIndex: map[string]int{"": 0}, // empty string is mapped to 0 + pkgIndex: make(map[*types.Package]int), + typIndex: make(map[types.Type]int), + posInfoFormat: true, // TODO(gri) might become a flag, eventually + } + + // write version info + // The version string must start with "version %d" where %d is the version + // number. Additional debugging information may follow after a blank; that + // text is ignored by the importer. + p.rawStringln(fmt.Sprintf("version %d", exportVersion)) + var debug string + if debugFormat { + debug = "debug" + } + p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly + p.bool(trackAllTypes) + p.bool(p.posInfoFormat) + + // --- generic export data --- + + // populate type map with predeclared "known" types + for index, typ := range predeclared() { + p.typIndex[typ] = index + } + if len(p.typIndex) != len(predeclared()) { + return nil, internalError("duplicate entries in type map?") + } + + // write package data + p.pkg(pkg, true) + if trace { + p.tracef("\n") + } + + // write objects + objcount := 0 + scope := pkg.Scope() + for _, name := range scope.Names() { + if !ast.IsExported(name) { + continue + } + if trace { + p.tracef("\n") + } + p.obj(scope.Lookup(name)) + objcount++ + } + + // indicate end of list + if trace { + p.tracef("\n") + } + p.tag(endTag) + + // for self-verification only (redundant) + p.int(objcount) + + if trace { + p.tracef("\n") + } + + // --- end of export data --- + + return p.out.Bytes(), nil +} + +func (p *exporter) pkg(pkg *types.Package, emptypath bool) { + if pkg == nil { + panic(internalError("unexpected nil pkg")) + } + + // if we saw the package before, write its index (>= 0) + if i, ok := p.pkgIndex[pkg]; ok { + p.index('P', i) + return + } + + // otherwise, remember the package, write the package tag (< 0) and package data + if trace { + p.tracef("P%d = { ", len(p.pkgIndex)) + defer p.tracef("} ") + } + p.pkgIndex[pkg] = len(p.pkgIndex) + + p.tag(packageTag) + p.string(pkg.Name()) + if emptypath { + p.string("") + } else { + p.string(pkg.Path()) + } +} + +func (p *exporter) obj(obj types.Object) { + switch obj := obj.(type) { + case *types.Const: + p.tag(constTag) + p.pos(obj) + p.qualifiedName(obj) + p.typ(obj.Type()) + p.value(obj.Val()) + + case *types.TypeName: + if obj.IsAlias() { + p.tag(aliasTag) + p.pos(obj) + p.qualifiedName(obj) + } else { + p.tag(typeTag) + } + p.typ(obj.Type()) + + case *types.Var: + p.tag(varTag) + p.pos(obj) + p.qualifiedName(obj) + p.typ(obj.Type()) + + case *types.Func: + p.tag(funcTag) + p.pos(obj) + p.qualifiedName(obj) + sig := obj.Type().(*types.Signature) + p.paramList(sig.Params(), sig.Variadic()) + p.paramList(sig.Results(), false) + + default: + panic(internalErrorf("unexpected object %v (%T)", obj, obj)) + } +} + +func (p *exporter) pos(obj types.Object) { + if !p.posInfoFormat { + return + } + + file, line := p.fileLine(obj) + if file == p.prevFile { + // common case: write line delta + // delta == 0 means different file or no line change + delta := line - p.prevLine + p.int(delta) + if delta == 0 { + p.int(-1) // -1 means no file change + } + } else { + // different file + p.int(0) + // Encode filename as length of common prefix with previous + // filename, followed by (possibly empty) suffix. Filenames + // frequently share path prefixes, so this can save a lot + // of space and make export data size less dependent on file + // path length. The suffix is unlikely to be empty because + // file names tend to end in ".go". + n := commonPrefixLen(p.prevFile, file) + p.int(n) // n >= 0 + p.string(file[n:]) // write suffix only + p.prevFile = file + p.int(line) + } + p.prevLine = line +} + +func (p *exporter) fileLine(obj types.Object) (file string, line int) { + if p.fset != nil { + pos := p.fset.Position(obj.Pos()) + file = pos.Filename + line = pos.Line + } + return +} + +func commonPrefixLen(a, b string) int { + if len(a) > len(b) { + a, b = b, a + } + // len(a) <= len(b) + i := 0 + for i < len(a) && a[i] == b[i] { + i++ + } + return i +} + +func (p *exporter) qualifiedName(obj types.Object) { + p.string(obj.Name()) + p.pkg(obj.Pkg(), false) +} + +func (p *exporter) typ(t types.Type) { + if t == nil { + panic(internalError("nil type")) + } + + // Possible optimization: Anonymous pointer types *T where + // T is a named type are common. We could canonicalize all + // such types *T to a single type PT = *T. This would lead + // to at most one *T entry in typIndex, and all future *T's + // would be encoded as the respective index directly. Would + // save 1 byte (pointerTag) per *T and reduce the typIndex + // size (at the cost of a canonicalization map). We can do + // this later, without encoding format change. + + // if we saw the type before, write its index (>= 0) + if i, ok := p.typIndex[t]; ok { + p.index('T', i) + return + } + + // otherwise, remember the type, write the type tag (< 0) and type data + if trackAllTypes { + if trace { + p.tracef("T%d = {>\n", len(p.typIndex)) + defer p.tracef("<\n} ") + } + p.typIndex[t] = len(p.typIndex) + } + + switch t := t.(type) { + case *types.Named: + if !trackAllTypes { + // if we don't track all types, track named types now + p.typIndex[t] = len(p.typIndex) + } + + p.tag(namedTag) + p.pos(t.Obj()) + p.qualifiedName(t.Obj()) + p.typ(t.Underlying()) + if !types.IsInterface(t) { + p.assocMethods(t) + } + + case *types.Array: + p.tag(arrayTag) + p.int64(t.Len()) + p.typ(t.Elem()) + + case *types.Slice: + p.tag(sliceTag) + p.typ(t.Elem()) + + case *dddSlice: + p.tag(dddTag) + p.typ(t.elem) + + case *types.Struct: + p.tag(structTag) + p.fieldList(t) + + case *types.Pointer: + p.tag(pointerTag) + p.typ(t.Elem()) + + case *types.Signature: + p.tag(signatureTag) + p.paramList(t.Params(), t.Variadic()) + p.paramList(t.Results(), false) + + case *types.Interface: + p.tag(interfaceTag) + p.iface(t) + + case *types.Map: + p.tag(mapTag) + p.typ(t.Key()) + p.typ(t.Elem()) + + case *types.Chan: + p.tag(chanTag) + p.int(int(3 - t.Dir())) // hack + p.typ(t.Elem()) + + default: + panic(internalErrorf("unexpected type %T: %s", t, t)) + } +} + +func (p *exporter) assocMethods(named *types.Named) { + // Sort methods (for determinism). + var methods []*types.Func + for i := 0; i < named.NumMethods(); i++ { + methods = append(methods, named.Method(i)) + } + sort.Sort(methodsByName(methods)) + + p.int(len(methods)) + + if trace && methods != nil { + p.tracef("associated methods {>\n") + } + + for i, m := range methods { + if trace && i > 0 { + p.tracef("\n") + } + + p.pos(m) + name := m.Name() + p.string(name) + if !exported(name) { + p.pkg(m.Pkg(), false) + } + + sig := m.Type().(*types.Signature) + p.paramList(types.NewTuple(sig.Recv()), false) + p.paramList(sig.Params(), sig.Variadic()) + p.paramList(sig.Results(), false) + p.int(0) // dummy value for go:nointerface pragma - ignored by importer + } + + if trace && methods != nil { + p.tracef("<\n} ") + } +} + +type methodsByName []*types.Func + +func (x methodsByName) Len() int { return len(x) } +func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } + +func (p *exporter) fieldList(t *types.Struct) { + if trace && t.NumFields() > 0 { + p.tracef("fields {>\n") + defer p.tracef("<\n} ") + } + + p.int(t.NumFields()) + for i := 0; i < t.NumFields(); i++ { + if trace && i > 0 { + p.tracef("\n") + } + p.field(t.Field(i)) + p.string(t.Tag(i)) + } +} + +func (p *exporter) field(f *types.Var) { + if !f.IsField() { + panic(internalError("field expected")) + } + + p.pos(f) + p.fieldName(f) + p.typ(f.Type()) +} + +func (p *exporter) iface(t *types.Interface) { + // TODO(gri): enable importer to load embedded interfaces, + // then emit Embeddeds and ExplicitMethods separately here. + p.int(0) + + n := t.NumMethods() + if trace && n > 0 { + p.tracef("methods {>\n") + defer p.tracef("<\n} ") + } + p.int(n) + for i := 0; i < n; i++ { + if trace && i > 0 { + p.tracef("\n") + } + p.method(t.Method(i)) + } +} + +func (p *exporter) method(m *types.Func) { + sig := m.Type().(*types.Signature) + if sig.Recv() == nil { + panic(internalError("method expected")) + } + + p.pos(m) + p.string(m.Name()) + if m.Name() != "_" && !ast.IsExported(m.Name()) { + p.pkg(m.Pkg(), false) + } + + // interface method; no need to encode receiver. + p.paramList(sig.Params(), sig.Variadic()) + p.paramList(sig.Results(), false) +} + +func (p *exporter) fieldName(f *types.Var) { + name := f.Name() + + if f.Anonymous() { + // anonymous field - we distinguish between 3 cases: + // 1) field name matches base type name and is exported + // 2) field name matches base type name and is not exported + // 3) field name doesn't match base type name (alias name) + bname := basetypeName(f.Type()) + if name == bname { + if ast.IsExported(name) { + name = "" // 1) we don't need to know the field name or package + } else { + name = "?" // 2) use unexported name "?" to force package export + } + } else { + // 3) indicate alias and export name as is + // (this requires an extra "@" but this is a rare case) + p.string("@") + } + } + + p.string(name) + if name != "" && !ast.IsExported(name) { + p.pkg(f.Pkg(), false) + } +} + +func basetypeName(typ types.Type) string { + switch typ := deref(typ).(type) { + case *types.Basic: + return typ.Name() + case *types.Named: + return typ.Obj().Name() + default: + return "" // unnamed type + } +} + +func (p *exporter) paramList(params *types.Tuple, variadic bool) { + // use negative length to indicate unnamed parameters + // (look at the first parameter only since either all + // names are present or all are absent) + n := params.Len() + if n > 0 && params.At(0).Name() == "" { + n = -n + } + p.int(n) + for i := 0; i < params.Len(); i++ { + q := params.At(i) + t := q.Type() + if variadic && i == params.Len()-1 { + t = &dddSlice{t.(*types.Slice).Elem()} + } + p.typ(t) + if n > 0 { + name := q.Name() + p.string(name) + if name != "_" { + p.pkg(q.Pkg(), false) + } + } + p.string("") // no compiler-specific info + } +} + +func (p *exporter) value(x constant.Value) { + if trace { + p.tracef("= ") + } + + switch x.Kind() { + case constant.Bool: + tag := falseTag + if constant.BoolVal(x) { + tag = trueTag + } + p.tag(tag) + + case constant.Int: + if v, exact := constant.Int64Val(x); exact { + // common case: x fits into an int64 - use compact encoding + p.tag(int64Tag) + p.int64(v) + return + } + // uncommon case: large x - use float encoding + // (powers of 2 will be encoded efficiently with exponent) + p.tag(floatTag) + p.float(constant.ToFloat(x)) + + case constant.Float: + p.tag(floatTag) + p.float(x) + + case constant.Complex: + p.tag(complexTag) + p.float(constant.Real(x)) + p.float(constant.Imag(x)) + + case constant.String: + p.tag(stringTag) + p.string(constant.StringVal(x)) + + case constant.Unknown: + // package contains type errors + p.tag(unknownTag) + + default: + panic(internalErrorf("unexpected value %v (%T)", x, x)) + } +} + +func (p *exporter) float(x constant.Value) { + if x.Kind() != constant.Float { + panic(internalErrorf("unexpected constant %v, want float", x)) + } + // extract sign (there is no -0) + sign := constant.Sign(x) + if sign == 0 { + // x == 0 + p.int(0) + return + } + // x != 0 + + var f big.Float + if v, exact := constant.Float64Val(x); exact { + // float64 + f.SetFloat64(v) + } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { + // TODO(gri): add big.Rat accessor to constant.Value. + r := valueToRat(num) + f.SetRat(r.Quo(r, valueToRat(denom))) + } else { + // Value too large to represent as a fraction => inaccessible. + // TODO(gri): add big.Float accessor to constant.Value. + f.SetFloat64(math.MaxFloat64) // FIXME + } + + // extract exponent such that 0.5 <= m < 1.0 + var m big.Float + exp := f.MantExp(&m) + + // extract mantissa as *big.Int + // - set exponent large enough so mant satisfies mant.IsInt() + // - get *big.Int from mant + m.SetMantExp(&m, int(m.MinPrec())) + mant, acc := m.Int(nil) + if acc != big.Exact { + panic(internalError("internal error")) + } + + p.int(sign) + p.int(exp) + p.string(string(mant.Bytes())) +} + +func valueToRat(x constant.Value) *big.Rat { + // Convert little-endian to big-endian. + // I can't believe this is necessary. + bytes := constant.Bytes(x) + for i := 0; i < len(bytes)/2; i++ { + bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] + } + return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) +} + +func (p *exporter) bool(b bool) bool { + if trace { + p.tracef("[") + defer p.tracef("= %v] ", b) + } + + x := 0 + if b { + x = 1 + } + p.int(x) + return b +} + +// ---------------------------------------------------------------------------- +// Low-level encoders + +func (p *exporter) index(marker byte, index int) { + if index < 0 { + panic(internalError("invalid index < 0")) + } + if debugFormat { + p.marker('t') + } + if trace { + p.tracef("%c%d ", marker, index) + } + p.rawInt64(int64(index)) +} + +func (p *exporter) tag(tag int) { + if tag >= 0 { + panic(internalError("invalid tag >= 0")) + } + if debugFormat { + p.marker('t') + } + if trace { + p.tracef("%s ", tagString[-tag]) + } + p.rawInt64(int64(tag)) +} + +func (p *exporter) int(x int) { + p.int64(int64(x)) +} + +func (p *exporter) int64(x int64) { + if debugFormat { + p.marker('i') + } + if trace { + p.tracef("%d ", x) + } + p.rawInt64(x) +} + +func (p *exporter) string(s string) { + if debugFormat { + p.marker('s') + } + if trace { + p.tracef("%q ", s) + } + // if we saw the string before, write its index (>= 0) + // (the empty string is mapped to 0) + if i, ok := p.strIndex[s]; ok { + p.rawInt64(int64(i)) + return + } + // otherwise, remember string and write its negative length and bytes + p.strIndex[s] = len(p.strIndex) + p.rawInt64(-int64(len(s))) + for i := 0; i < len(s); i++ { + p.rawByte(s[i]) + } +} + +// marker emits a marker byte and position information which makes +// it easy for a reader to detect if it is "out of sync". Used for +// debugFormat format only. +func (p *exporter) marker(m byte) { + p.rawByte(m) + // Enable this for help tracking down the location + // of an incorrect marker when running in debugFormat. + if false && trace { + p.tracef("#%d ", p.written) + } + p.rawInt64(int64(p.written)) +} + +// rawInt64 should only be used by low-level encoders. +func (p *exporter) rawInt64(x int64) { + var tmp [binary.MaxVarintLen64]byte + n := binary.PutVarint(tmp[:], x) + for i := 0; i < n; i++ { + p.rawByte(tmp[i]) + } +} + +// rawStringln should only be used to emit the initial version string. +func (p *exporter) rawStringln(s string) { + for i := 0; i < len(s); i++ { + p.rawByte(s[i]) + } + p.rawByte('\n') +} + +// rawByte is the bottleneck interface to write to p.out. +// rawByte escapes b as follows (any encoding does that +// hides '$'): +// +// '$' => '|' 'S' +// '|' => '|' '|' +// +// Necessary so other tools can find the end of the +// export data by searching for "$$". +// rawByte should only be used by low-level encoders. +func (p *exporter) rawByte(b byte) { + switch b { + case '$': + // write '$' as '|' 'S' + b = 'S' + fallthrough + case '|': + // write '|' as '|' '|' + p.out.WriteByte('|') + p.written++ + } + p.out.WriteByte(b) + p.written++ +} + +// tracef is like fmt.Printf but it rewrites the format string +// to take care of indentation. +func (p *exporter) tracef(format string, args ...interface{}) { + if strings.ContainsAny(format, "<>\n") { + var buf bytes.Buffer + for i := 0; i < len(format); i++ { + // no need to deal with runes + ch := format[i] + switch ch { + case '>': + p.indent++ + continue + case '<': + p.indent-- + continue + } + buf.WriteByte(ch) + if ch == '\n' { + for j := p.indent; j > 0; j-- { + buf.WriteString(". ") + } + } + } + format = buf.String() + } + fmt.Printf(format, args...) +} + +// Debugging support. +// (tagString is only used when tracing is enabled) +var tagString = [...]string{ + // Packages + -packageTag: "package", + + // Types + -namedTag: "named type", + -arrayTag: "array", + -sliceTag: "slice", + -dddTag: "ddd", + -structTag: "struct", + -pointerTag: "pointer", + -signatureTag: "signature", + -interfaceTag: "interface", + -mapTag: "map", + -chanTag: "chan", + + // Values + -falseTag: "false", + -trueTag: "true", + -int64Tag: "int64", + -floatTag: "float", + -fractionTag: "fraction", + -complexTag: "complex", + -stringTag: "string", + -unknownTag: "unknown", + + // Type aliases + -aliasTag: "alias", +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go new file mode 100644 index 0000000000..3288a0bfc7 --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go @@ -0,0 +1,1037 @@ +// Copyright 2015 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. + +// This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go. + +package gcimporter + +import ( + "encoding/binary" + "fmt" + "go/constant" + "go/token" + "go/types" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +type importer struct { + imports map[string]*types.Package + data []byte + importpath string + buf []byte // for reading strings + version int // export format version + + // object lists + strList []string // in order of appearance + pathList []string // in order of appearance + pkgList []*types.Package // in order of appearance + typList []types.Type // in order of appearance + interfaceList []*types.Interface // for delayed completion only + trackAllTypes bool + + // position encoding + posInfoFormat bool + prevFile string + prevLine int + fake fakeFileSet + + // debugging support + debugFormat bool + read int // bytes read +} + +// BImportData imports a package from the serialized package data +// and returns the number of bytes consumed and a reference to the package. +// If the export data version is not recognized or the format is otherwise +// compromised, an error is returned. +func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { + // catch panics and return them as errors + const currentVersion = 6 + version := -1 // unknown version + defer func() { + if e := recover(); e != nil { + // Return a (possibly nil or incomplete) package unchanged (see #16088). + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } + } + }() + + p := importer{ + imports: imports, + data: data, + importpath: path, + version: version, + strList: []string{""}, // empty string is mapped to 0 + pathList: []string{""}, // empty string is mapped to 0 + fake: fakeFileSet{ + fset: fset, + files: make(map[string]*token.File), + }, + } + + // read version info + var versionstr string + if b := p.rawByte(); b == 'c' || b == 'd' { + // Go1.7 encoding; first byte encodes low-level + // encoding format (compact vs debug). + // For backward-compatibility only (avoid problems with + // old installed packages). Newly compiled packages use + // the extensible format string. + // TODO(gri) Remove this support eventually; after Go1.8. + if b == 'd' { + p.debugFormat = true + } + p.trackAllTypes = p.rawByte() == 'a' + p.posInfoFormat = p.int() != 0 + versionstr = p.string() + if versionstr == "v1" { + version = 0 + } + } else { + // Go1.8 extensible encoding + // read version string and extract version number (ignore anything after the version number) + versionstr = p.rawStringln(b) + if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { + if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { + version = v + } + } + } + p.version = version + + // read version specific flags - extend as necessary + switch p.version { + // case currentVersion: + // ... + // fallthrough + case currentVersion, 5, 4, 3, 2, 1: + p.debugFormat = p.rawStringln(p.rawByte()) == "debug" + p.trackAllTypes = p.int() != 0 + p.posInfoFormat = p.int() != 0 + case 0: + // Go1.7 encoding format - nothing to do here + default: + errorf("unknown bexport format version %d (%q)", p.version, versionstr) + } + + // --- generic export data --- + + // populate typList with predeclared "known" types + p.typList = append(p.typList, predeclared()...) + + // read package data + pkg = p.pkg() + + // read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go) + objcount := 0 + for { + tag := p.tagOrIndex() + if tag == endTag { + break + } + p.obj(tag) + objcount++ + } + + // self-verification + if count := p.int(); count != objcount { + errorf("got %d objects; want %d", objcount, count) + } + + // ignore compiler-specific import data + + // complete interfaces + // TODO(gri) re-investigate if we still need to do this in a delayed fashion + for _, typ := range p.interfaceList { + typ.Complete() + } + + // record all referenced packages as imports + list := append(([]*types.Package)(nil), p.pkgList[1:]...) + sort.Sort(byPath(list)) + pkg.SetImports(list) + + // package was imported completely and without errors + pkg.MarkComplete() + + return p.read, pkg, nil +} + +func errorf(format string, args ...interface{}) { + panic(fmt.Sprintf(format, args...)) +} + +func (p *importer) pkg() *types.Package { + // if the package was seen before, i is its index (>= 0) + i := p.tagOrIndex() + if i >= 0 { + return p.pkgList[i] + } + + // otherwise, i is the package tag (< 0) + if i != packageTag { + errorf("unexpected package tag %d version %d", i, p.version) + } + + // read package data + name := p.string() + var path string + if p.version >= 5 { + path = p.path() + } else { + path = p.string() + } + if p.version >= 6 { + p.int() // package height; unused by go/types + } + + // we should never see an empty package name + if name == "" { + errorf("empty package name in import") + } + + // an empty path denotes the package we are currently importing; + // it must be the first package we see + if (path == "") != (len(p.pkgList) == 0) { + errorf("package path %q for pkg index %d", path, len(p.pkgList)) + } + + // if the package was imported before, use that one; otherwise create a new one + if path == "" { + path = p.importpath + } + pkg := p.imports[path] + if pkg == nil { + pkg = types.NewPackage(path, name) + p.imports[path] = pkg + } else if pkg.Name() != name { + errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path) + } + p.pkgList = append(p.pkgList, pkg) + + return pkg +} + +// objTag returns the tag value for each object kind. +func objTag(obj types.Object) int { + switch obj.(type) { + case *types.Const: + return constTag + case *types.TypeName: + return typeTag + case *types.Var: + return varTag + case *types.Func: + return funcTag + default: + errorf("unexpected object: %v (%T)", obj, obj) // panics + panic("unreachable") + } +} + +func sameObj(a, b types.Object) bool { + // Because unnamed types are not canonicalized, we cannot simply compare types for + // (pointer) identity. + // Ideally we'd check equality of constant values as well, but this is good enough. + return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type()) +} + +func (p *importer) declare(obj types.Object) { + pkg := obj.Pkg() + if alt := pkg.Scope().Insert(obj); alt != nil { + // This can only trigger if we import a (non-type) object a second time. + // Excluding type aliases, this cannot happen because 1) we only import a package + // once; and b) we ignore compiler-specific export data which may contain + // functions whose inlined function bodies refer to other functions that + // were already imported. + // However, type aliases require reexporting the original type, so we need + // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go, + // method importer.obj, switch case importing functions). + // TODO(gri) review/update this comment once the gc compiler handles type aliases. + if !sameObj(obj, alt) { + errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt) + } + } +} + +func (p *importer) obj(tag int) { + switch tag { + case constTag: + pos := p.pos() + pkg, name := p.qualifiedName() + typ := p.typ(nil, nil) + val := p.value() + p.declare(types.NewConst(pos, pkg, name, typ, val)) + + case aliasTag: + // TODO(gri) verify type alias hookup is correct + pos := p.pos() + pkg, name := p.qualifiedName() + typ := p.typ(nil, nil) + p.declare(types.NewTypeName(pos, pkg, name, typ)) + + case typeTag: + p.typ(nil, nil) + + case varTag: + pos := p.pos() + pkg, name := p.qualifiedName() + typ := p.typ(nil, nil) + p.declare(types.NewVar(pos, pkg, name, typ)) + + case funcTag: + pos := p.pos() + pkg, name := p.qualifiedName() + params, isddd := p.paramList() + result, _ := p.paramList() + sig := types.NewSignature(nil, params, result, isddd) + p.declare(types.NewFunc(pos, pkg, name, sig)) + + default: + errorf("unexpected object tag %d", tag) + } +} + +const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go + +func (p *importer) pos() token.Pos { + if !p.posInfoFormat { + return token.NoPos + } + + file := p.prevFile + line := p.prevLine + delta := p.int() + line += delta + if p.version >= 5 { + if delta == deltaNewFile { + if n := p.int(); n >= 0 { + // file changed + file = p.path() + line = n + } + } + } else { + if delta == 0 { + if n := p.int(); n >= 0 { + // file changed + file = p.prevFile[:n] + p.string() + line = p.int() + } + } + } + p.prevFile = file + p.prevLine = line + + return p.fake.pos(file, line) +} + +// Synthesize a token.Pos +type fakeFileSet struct { + fset *token.FileSet + files map[string]*token.File +} + +func (s *fakeFileSet) pos(file string, line int) token.Pos { + // Since we don't know the set of needed file positions, we + // reserve maxlines positions per file. + const maxlines = 64 * 1024 + f := s.files[file] + if f == nil { + f = s.fset.AddFile(file, -1, maxlines) + s.files[file] = f + // Allocate the fake linebreak indices on first use. + // TODO(adonovan): opt: save ~512KB using a more complex scheme? + fakeLinesOnce.Do(func() { + fakeLines = make([]int, maxlines) + for i := range fakeLines { + fakeLines[i] = i + } + }) + f.SetLines(fakeLines) + } + + if line > maxlines { + line = 1 + } + + // Treat the file as if it contained only newlines + // and column=1: use the line number as the offset. + return f.Pos(line - 1) +} + +var ( + fakeLines []int + fakeLinesOnce sync.Once +) + +func (p *importer) qualifiedName() (pkg *types.Package, name string) { + name = p.string() + pkg = p.pkg() + return +} + +func (p *importer) record(t types.Type) { + p.typList = append(p.typList, t) +} + +// A dddSlice is a types.Type representing ...T parameters. +// It only appears for parameter types and does not escape +// the importer. +type dddSlice struct { + elem types.Type +} + +func (t *dddSlice) Underlying() types.Type { return t } +func (t *dddSlice) String() string { return "..." + t.elem.String() } + +// parent is the package which declared the type; parent == nil means +// the package currently imported. The parent package is needed for +// exported struct fields and interface methods which don't contain +// explicit package information in the export data. +// +// A non-nil tname is used as the "owner" of the result type; i.e., +// the result type is the underlying type of tname. tname is used +// to give interface methods a named receiver type where possible. +func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type { + // if the type was seen before, i is its index (>= 0) + i := p.tagOrIndex() + if i >= 0 { + return p.typList[i] + } + + // otherwise, i is the type tag (< 0) + switch i { + case namedTag: + // read type object + pos := p.pos() + parent, name := p.qualifiedName() + scope := parent.Scope() + obj := scope.Lookup(name) + + // if the object doesn't exist yet, create and insert it + if obj == nil { + obj = types.NewTypeName(pos, parent, name, nil) + scope.Insert(obj) + } + + if _, ok := obj.(*types.TypeName); !ok { + errorf("pkg = %s, name = %s => %s", parent, name, obj) + } + + // associate new named type with obj if it doesn't exist yet + t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) + + // but record the existing type, if any + tname := obj.Type().(*types.Named) // tname is either t0 or the existing type + p.record(tname) + + // read underlying type + t0.SetUnderlying(p.typ(parent, t0)) + + // interfaces don't have associated methods + if types.IsInterface(t0) { + return tname + } + + // read associated methods + for i := p.int(); i > 0; i-- { + // TODO(gri) replace this with something closer to fieldName + pos := p.pos() + name := p.string() + if !exported(name) { + p.pkg() + } + + recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? + params, isddd := p.paramList() + result, _ := p.paramList() + p.int() // go:nointerface pragma - discarded + + sig := types.NewSignature(recv.At(0), params, result, isddd) + t0.AddMethod(types.NewFunc(pos, parent, name, sig)) + } + + return tname + + case arrayTag: + t := new(types.Array) + if p.trackAllTypes { + p.record(t) + } + + n := p.int64() + *t = *types.NewArray(p.typ(parent, nil), n) + return t + + case sliceTag: + t := new(types.Slice) + if p.trackAllTypes { + p.record(t) + } + + *t = *types.NewSlice(p.typ(parent, nil)) + return t + + case dddTag: + t := new(dddSlice) + if p.trackAllTypes { + p.record(t) + } + + t.elem = p.typ(parent, nil) + return t + + case structTag: + t := new(types.Struct) + if p.trackAllTypes { + p.record(t) + } + + *t = *types.NewStruct(p.fieldList(parent)) + return t + + case pointerTag: + t := new(types.Pointer) + if p.trackAllTypes { + p.record(t) + } + + *t = *types.NewPointer(p.typ(parent, nil)) + return t + + case signatureTag: + t := new(types.Signature) + if p.trackAllTypes { + p.record(t) + } + + params, isddd := p.paramList() + result, _ := p.paramList() + *t = *types.NewSignature(nil, params, result, isddd) + return t + + case interfaceTag: + // Create a dummy entry in the type list. This is safe because we + // cannot expect the interface type to appear in a cycle, as any + // such cycle must contain a named type which would have been + // first defined earlier. + // TODO(gri) Is this still true now that we have type aliases? + // See issue #23225. + n := len(p.typList) + if p.trackAllTypes { + p.record(nil) + } + + var embeddeds []types.Type + for n := p.int(); n > 0; n-- { + p.pos() + embeddeds = append(embeddeds, p.typ(parent, nil)) + } + + t := newInterface(p.methodList(parent, tname), embeddeds) + p.interfaceList = append(p.interfaceList, t) + if p.trackAllTypes { + p.typList[n] = t + } + return t + + case mapTag: + t := new(types.Map) + if p.trackAllTypes { + p.record(t) + } + + key := p.typ(parent, nil) + val := p.typ(parent, nil) + *t = *types.NewMap(key, val) + return t + + case chanTag: + t := new(types.Chan) + if p.trackAllTypes { + p.record(t) + } + + dir := chanDir(p.int()) + val := p.typ(parent, nil) + *t = *types.NewChan(dir, val) + return t + + default: + errorf("unexpected type tag %d", i) // panics + panic("unreachable") + } +} + +func chanDir(d int) types.ChanDir { + // tag values must match the constants in cmd/compile/internal/gc/go.go + switch d { + case 1 /* Crecv */ : + return types.RecvOnly + case 2 /* Csend */ : + return types.SendOnly + case 3 /* Cboth */ : + return types.SendRecv + default: + errorf("unexpected channel dir %d", d) + return 0 + } +} + +func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) { + if n := p.int(); n > 0 { + fields = make([]*types.Var, n) + tags = make([]string, n) + for i := range fields { + fields[i], tags[i] = p.field(parent) + } + } + return +} + +func (p *importer) field(parent *types.Package) (*types.Var, string) { + pos := p.pos() + pkg, name, alias := p.fieldName(parent) + typ := p.typ(parent, nil) + tag := p.string() + + anonymous := false + if name == "" { + // anonymous field - typ must be T or *T and T must be a type name + switch typ := deref(typ).(type) { + case *types.Basic: // basic types are named types + pkg = nil // // objects defined in Universe scope have no package + name = typ.Name() + case *types.Named: + name = typ.Obj().Name() + default: + errorf("named base type expected") + } + anonymous = true + } else if alias { + // anonymous field: we have an explicit name because it's an alias + anonymous = true + } + + return types.NewField(pos, pkg, name, typ, anonymous), tag +} + +func (p *importer) methodList(parent *types.Package, baseType *types.Named) (methods []*types.Func) { + if n := p.int(); n > 0 { + methods = make([]*types.Func, n) + for i := range methods { + methods[i] = p.method(parent, baseType) + } + } + return +} + +func (p *importer) method(parent *types.Package, baseType *types.Named) *types.Func { + pos := p.pos() + pkg, name, _ := p.fieldName(parent) + // If we don't have a baseType, use a nil receiver. + // A receiver using the actual interface type (which + // we don't know yet) will be filled in when we call + // types.Interface.Complete. + var recv *types.Var + if baseType != nil { + recv = types.NewVar(token.NoPos, parent, "", baseType) + } + params, isddd := p.paramList() + result, _ := p.paramList() + sig := types.NewSignature(recv, params, result, isddd) + return types.NewFunc(pos, pkg, name, sig) +} + +func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) { + name = p.string() + pkg = parent + if pkg == nil { + // use the imported package instead + pkg = p.pkgList[0] + } + if p.version == 0 && name == "_" { + // version 0 didn't export a package for _ fields + return + } + switch name { + case "": + // 1) field name matches base type name and is exported: nothing to do + case "?": + // 2) field name matches base type name and is not exported: need package + name = "" + pkg = p.pkg() + case "@": + // 3) field name doesn't match type name (alias) + name = p.string() + alias = true + fallthrough + default: + if !exported(name) { + pkg = p.pkg() + } + } + return +} + +func (p *importer) paramList() (*types.Tuple, bool) { + n := p.int() + if n == 0 { + return nil, false + } + // negative length indicates unnamed parameters + named := true + if n < 0 { + n = -n + named = false + } + // n > 0 + params := make([]*types.Var, n) + isddd := false + for i := range params { + params[i], isddd = p.param(named) + } + return types.NewTuple(params...), isddd +} + +func (p *importer) param(named bool) (*types.Var, bool) { + t := p.typ(nil, nil) + td, isddd := t.(*dddSlice) + if isddd { + t = types.NewSlice(td.elem) + } + + var pkg *types.Package + var name string + if named { + name = p.string() + if name == "" { + errorf("expected named parameter") + } + if name != "_" { + pkg = p.pkg() + } + if i := strings.Index(name, "·"); i > 0 { + name = name[:i] // cut off gc-specific parameter numbering + } + } + + // read and discard compiler-specific info + p.string() + + return types.NewVar(token.NoPos, pkg, name, t), isddd +} + +func exported(name string) bool { + ch, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(ch) +} + +func (p *importer) value() constant.Value { + switch tag := p.tagOrIndex(); tag { + case falseTag: + return constant.MakeBool(false) + case trueTag: + return constant.MakeBool(true) + case int64Tag: + return constant.MakeInt64(p.int64()) + case floatTag: + return p.float() + case complexTag: + re := p.float() + im := p.float() + return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) + case stringTag: + return constant.MakeString(p.string()) + case unknownTag: + return constant.MakeUnknown() + default: + errorf("unexpected value tag %d", tag) // panics + panic("unreachable") + } +} + +func (p *importer) float() constant.Value { + sign := p.int() + if sign == 0 { + return constant.MakeInt64(0) + } + + exp := p.int() + mant := []byte(p.string()) // big endian + + // remove leading 0's if any + for len(mant) > 0 && mant[0] == 0 { + mant = mant[1:] + } + + // convert to little endian + // TODO(gri) go/constant should have a more direct conversion function + // (e.g., once it supports a big.Float based implementation) + for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { + mant[i], mant[j] = mant[j], mant[i] + } + + // adjust exponent (constant.MakeFromBytes creates an integer value, + // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) + exp -= len(mant) << 3 + if len(mant) > 0 { + for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { + exp++ + } + } + + x := constant.MakeFromBytes(mant) + switch { + case exp < 0: + d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) + x = constant.BinaryOp(x, token.QUO, d) + case exp > 0: + x = constant.Shift(x, token.SHL, uint(exp)) + } + + if sign < 0 { + x = constant.UnaryOp(token.SUB, x, 0) + } + return x +} + +// ---------------------------------------------------------------------------- +// Low-level decoders + +func (p *importer) tagOrIndex() int { + if p.debugFormat { + p.marker('t') + } + + return int(p.rawInt64()) +} + +func (p *importer) int() int { + x := p.int64() + if int64(int(x)) != x { + errorf("exported integer too large") + } + return int(x) +} + +func (p *importer) int64() int64 { + if p.debugFormat { + p.marker('i') + } + + return p.rawInt64() +} + +func (p *importer) path() string { + if p.debugFormat { + p.marker('p') + } + // if the path was seen before, i is its index (>= 0) + // (the empty string is at index 0) + i := p.rawInt64() + if i >= 0 { + return p.pathList[i] + } + // otherwise, i is the negative path length (< 0) + a := make([]string, -i) + for n := range a { + a[n] = p.string() + } + s := strings.Join(a, "/") + p.pathList = append(p.pathList, s) + return s +} + +func (p *importer) string() string { + if p.debugFormat { + p.marker('s') + } + // if the string was seen before, i is its index (>= 0) + // (the empty string is at index 0) + i := p.rawInt64() + if i >= 0 { + return p.strList[i] + } + // otherwise, i is the negative string length (< 0) + if n := int(-i); n <= cap(p.buf) { + p.buf = p.buf[:n] + } else { + p.buf = make([]byte, n) + } + for i := range p.buf { + p.buf[i] = p.rawByte() + } + s := string(p.buf) + p.strList = append(p.strList, s) + return s +} + +func (p *importer) marker(want byte) { + if got := p.rawByte(); got != want { + errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) + } + + pos := p.read + if n := int(p.rawInt64()); n != pos { + errorf("incorrect position: got %d; want %d", n, pos) + } +} + +// rawInt64 should only be used by low-level decoders. +func (p *importer) rawInt64() int64 { + i, err := binary.ReadVarint(p) + if err != nil { + errorf("read error: %v", err) + } + return i +} + +// rawStringln should only be used to read the initial version string. +func (p *importer) rawStringln(b byte) string { + p.buf = p.buf[:0] + for b != '\n' { + p.buf = append(p.buf, b) + b = p.rawByte() + } + return string(p.buf) +} + +// needed for binary.ReadVarint in rawInt64 +func (p *importer) ReadByte() (byte, error) { + return p.rawByte(), nil +} + +// byte is the bottleneck interface for reading p.data. +// It unescapes '|' 'S' to '$' and '|' '|' to '|'. +// rawByte should only be used by low-level decoders. +func (p *importer) rawByte() byte { + b := p.data[0] + r := 1 + if b == '|' { + b = p.data[1] + r = 2 + switch b { + case 'S': + b = '$' + case '|': + // nothing to do + default: + errorf("unexpected escape sequence in export data") + } + } + p.data = p.data[r:] + p.read += r + return b + +} + +// ---------------------------------------------------------------------------- +// Export format + +// Tags. Must be < 0. +const ( + // Objects + packageTag = -(iota + 1) + constTag + typeTag + varTag + funcTag + endTag + + // Types + namedTag + arrayTag + sliceTag + dddTag + structTag + pointerTag + signatureTag + interfaceTag + mapTag + chanTag + + // Values + falseTag + trueTag + int64Tag + floatTag + fractionTag // not used by gc + complexTag + stringTag + nilTag // only used by gc (appears in exported inlined function bodies) + unknownTag // not used by gc (only appears in packages with errors) + + // Type aliases + aliasTag +) + +var predeclOnce sync.Once +var predecl []types.Type // initialized lazily + +func predeclared() []types.Type { + predeclOnce.Do(func() { + // initialize lazily to be sure that all + // elements have been initialized before + predecl = []types.Type{ // basic types + types.Typ[types.Bool], + types.Typ[types.Int], + types.Typ[types.Int8], + types.Typ[types.Int16], + types.Typ[types.Int32], + types.Typ[types.Int64], + types.Typ[types.Uint], + types.Typ[types.Uint8], + types.Typ[types.Uint16], + types.Typ[types.Uint32], + types.Typ[types.Uint64], + types.Typ[types.Uintptr], + types.Typ[types.Float32], + types.Typ[types.Float64], + types.Typ[types.Complex64], + types.Typ[types.Complex128], + types.Typ[types.String], + + // basic type aliases + types.Universe.Lookup("byte").Type(), + types.Universe.Lookup("rune").Type(), + + // error + types.Universe.Lookup("error").Type(), + + // untyped types + types.Typ[types.UntypedBool], + types.Typ[types.UntypedInt], + types.Typ[types.UntypedRune], + types.Typ[types.UntypedFloat], + types.Typ[types.UntypedComplex], + types.Typ[types.UntypedString], + types.Typ[types.UntypedNil], + + // package unsafe + types.Typ[types.UnsafePointer], + + // invalid type + types.Typ[types.Invalid], // only appears in packages with errors + + // used internally by gc; never used by this package or in .a files + anyType{}, + } + }) + return predecl +} + +type anyType struct{} + +func (t anyType) Underlying() types.Type { return t } +func (t anyType) String() string { return "any" } diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go b/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go new file mode 100644 index 0000000000..f33dc5613e --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go @@ -0,0 +1,93 @@ +// Copyright 2011 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. + +// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go. + +// This file implements FindExportData. + +package gcimporter + +import ( + "bufio" + "fmt" + "io" + "strconv" + "strings" +) + +func readGopackHeader(r *bufio.Reader) (name string, size int, err error) { + // See $GOROOT/include/ar.h. + hdr := make([]byte, 16+12+6+6+8+10+2) + _, err = io.ReadFull(r, hdr) + if err != nil { + return + } + // leave for debugging + if false { + fmt.Printf("header: %s", hdr) + } + s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) + size, err = strconv.Atoi(s) + if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { + err = fmt.Errorf("invalid archive header") + return + } + name = strings.TrimSpace(string(hdr[:16])) + return +} + +// FindExportData positions the reader r at the beginning of the +// export data section of an underlying GC-created object/archive +// file by reading from it. The reader must be positioned at the +// start of the file before calling this function. The hdr result +// is the string before the export data, either "$$" or "$$B". +// +func FindExportData(r *bufio.Reader) (hdr string, err error) { + // Read first line to make sure this is an object file. + line, err := r.ReadSlice('\n') + if err != nil { + err = fmt.Errorf("can't find export data (%v)", err) + return + } + + if string(line) == "!\n" { + // Archive file. Scan to __.PKGDEF. + var name string + if name, _, err = readGopackHeader(r); err != nil { + return + } + + // First entry should be __.PKGDEF. + if name != "__.PKGDEF" { + err = fmt.Errorf("go archive is missing __.PKGDEF") + return + } + + // Read first line of __.PKGDEF data, so that line + // is once again the first line of the input. + if line, err = r.ReadSlice('\n'); err != nil { + err = fmt.Errorf("can't find export data (%v)", err) + return + } + } + + // Now at __.PKGDEF in archive or still at beginning of file. + // Either way, line should begin with "go object ". + if !strings.HasPrefix(string(line), "go object ") { + err = fmt.Errorf("not a Go object file") + return + } + + // Skip over object header to export data. + // Begins after first line starting with $$. + for line[0] != '$' { + if line, err = r.ReadSlice('\n'); err != nil { + err = fmt.Errorf("can't find export data (%v)", err) + return + } + } + hdr = string(line) + + return +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go new file mode 100644 index 0000000000..9cf186605f --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go @@ -0,0 +1,1078 @@ +// Copyright 2011 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. + +// This file is a modified copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go, +// but it also contains the original source-based importer code for Go1.6. +// Once we stop supporting 1.6, we can remove that code. + +// Package gcimporter provides various functions for reading +// gc-generated object files that can be used to implement the +// Importer interface defined by the Go 1.5 standard library package. +package gcimporter // import "golang.org/x/tools/go/internal/gcimporter" + +import ( + "bufio" + "errors" + "fmt" + "go/build" + "go/constant" + "go/token" + "go/types" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "text/scanner" +) + +// debugging/development support +const debug = false + +var pkgExts = [...]string{".a", ".o"} + +// FindPkg returns the filename and unique package id for an import +// path based on package information provided by build.Import (using +// the build.Default build.Context). A relative srcDir is interpreted +// relative to the current working directory. +// If no file was found, an empty filename is returned. +// +func FindPkg(path, srcDir string) (filename, id string) { + if path == "" { + return + } + + var noext string + switch { + default: + // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" + // Don't require the source files to be present. + if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 + srcDir = abs + } + bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) + if bp.PkgObj == "" { + id = path // make sure we have an id to print in error message + return + } + noext = strings.TrimSuffix(bp.PkgObj, ".a") + id = bp.ImportPath + + case build.IsLocalImport(path): + // "./x" -> "/this/directory/x.ext", "/this/directory/x" + noext = filepath.Join(srcDir, path) + id = noext + + case filepath.IsAbs(path): + // for completeness only - go/build.Import + // does not support absolute imports + // "/x" -> "/x.ext", "/x" + noext = path + id = path + } + + if false { // for debugging + if path != id { + fmt.Printf("%s -> %s\n", path, id) + } + } + + // try extensions + for _, ext := range pkgExts { + filename = noext + ext + if f, err := os.Stat(filename); err == nil && !f.IsDir() { + return + } + } + + filename = "" // not found + return +} + +// ImportData imports a package by reading the gc-generated export data, +// adds the corresponding package object to the packages map indexed by id, +// and returns the object. +// +// The packages map must contains all packages already imported. The data +// reader position must be the beginning of the export data section. The +// filename is only used in error messages. +// +// If packages[id] contains the completely imported package, that package +// can be used directly, and there is no need to call this function (but +// there is also no harm but for extra time used). +// +func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) { + // support for parser error handling + defer func() { + switch r := recover().(type) { + case nil: + // nothing to do + case importError: + err = r + default: + panic(r) // internal error + } + }() + + var p parser + p.init(filename, id, data, packages) + pkg = p.parseExport() + + return +} + +// Import imports a gc-generated package given its import path and srcDir, adds +// the corresponding package object to the packages map, and returns the object. +// The packages map must contain all packages already imported. +// +func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { + var rc io.ReadCloser + var filename, id string + if lookup != nil { + // With custom lookup specified, assume that caller has + // converted path to a canonical import path for use in the map. + if path == "unsafe" { + return types.Unsafe, nil + } + id = path + + // No need to re-import if the package was imported completely before. + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + f, err := lookup(path) + if err != nil { + return nil, err + } + rc = f + } else { + filename, id = FindPkg(path, srcDir) + if filename == "" { + if path == "unsafe" { + return types.Unsafe, nil + } + return nil, fmt.Errorf("can't find import: %q", id) + } + + // no need to re-import if the package was imported completely before + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + + // open file + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + // add file name to error + err = fmt.Errorf("%s: %v", filename, err) + } + }() + rc = f + } + defer rc.Close() + + var hdr string + buf := bufio.NewReader(rc) + if hdr, err = FindExportData(buf); err != nil { + return + } + + switch hdr { + case "$$\n": + // Work-around if we don't have a filename; happens only if lookup != nil. + // Either way, the filename is only needed for importer error messages, so + // this is fine. + if filename == "" { + filename = path + } + return ImportData(packages, filename, id, buf) + + case "$$B\n": + var data []byte + data, err = ioutil.ReadAll(buf) + if err != nil { + break + } + + // TODO(gri): allow clients of go/importer to provide a FileSet. + // Or, define a new standard go/types/gcexportdata package. + fset := token.NewFileSet() + + // The indexed export format starts with an 'i'; the older + // binary export format starts with a 'c', 'd', or 'v' + // (from "version"). Select appropriate importer. + if len(data) > 0 && data[0] == 'i' { + _, pkg, err = IImportData(fset, packages, data[1:], id) + } else { + _, pkg, err = BImportData(fset, packages, data, id) + } + + default: + err = fmt.Errorf("unknown export data header: %q", hdr) + } + + return +} + +// ---------------------------------------------------------------------------- +// Parser + +// TODO(gri) Imported objects don't have position information. +// Ideally use the debug table line info; alternatively +// create some fake position (or the position of the +// import). That way error messages referring to imported +// objects can print meaningful information. + +// parser parses the exports inside a gc compiler-produced +// object/archive file and populates its scope with the results. +type parser struct { + scanner scanner.Scanner + tok rune // current token + lit string // literal string; only valid for Ident, Int, String tokens + id string // package id of imported package + sharedPkgs map[string]*types.Package // package id -> package object (across importer) + localPkgs map[string]*types.Package // package id -> package object (just this package) +} + +func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) { + p.scanner.Init(src) + p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } + p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments + p.scanner.Whitespace = 1<<'\t' | 1<<' ' + p.scanner.Filename = filename // for good error messages + p.next() + p.id = id + p.sharedPkgs = packages + if debug { + // check consistency of packages map + for _, pkg := range packages { + if pkg.Name() == "" { + fmt.Printf("no package name for %s\n", pkg.Path()) + } + } + } +} + +func (p *parser) next() { + p.tok = p.scanner.Scan() + switch p.tok { + case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·': + p.lit = p.scanner.TokenText() + default: + p.lit = "" + } + if debug { + fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit) + } +} + +func declTypeName(pkg *types.Package, name string) *types.TypeName { + scope := pkg.Scope() + if obj := scope.Lookup(name); obj != nil { + return obj.(*types.TypeName) + } + obj := types.NewTypeName(token.NoPos, pkg, name, nil) + // a named type may be referred to before the underlying type + // is known - set it up + types.NewNamed(obj, nil, nil) + scope.Insert(obj) + return obj +} + +// ---------------------------------------------------------------------------- +// Error handling + +// Internal errors are boxed as importErrors. +type importError struct { + pos scanner.Position + err error +} + +func (e importError) Error() string { + return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err) +} + +func (p *parser) error(err interface{}) { + if s, ok := err.(string); ok { + err = errors.New(s) + } + // panic with a runtime.Error if err is not an error + panic(importError{p.scanner.Pos(), err.(error)}) +} + +func (p *parser) errorf(format string, args ...interface{}) { + p.error(fmt.Sprintf(format, args...)) +} + +func (p *parser) expect(tok rune) string { + lit := p.lit + if p.tok != tok { + p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit) + } + p.next() + return lit +} + +func (p *parser) expectSpecial(tok string) { + sep := 'x' // not white space + i := 0 + for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' { + sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token + p.next() + i++ + } + if i < len(tok) { + p.errorf("expected %q, got %q", tok, tok[0:i]) + } +} + +func (p *parser) expectKeyword(keyword string) { + lit := p.expect(scanner.Ident) + if lit != keyword { + p.errorf("expected keyword %s, got %q", keyword, lit) + } +} + +// ---------------------------------------------------------------------------- +// Qualified and unqualified names + +// PackageId = string_lit . +// +func (p *parser) parsePackageId() string { + id, err := strconv.Unquote(p.expect(scanner.String)) + if err != nil { + p.error(err) + } + // id == "" stands for the imported package id + // (only known at time of package installation) + if id == "" { + id = p.id + } + return id +} + +// PackageName = ident . +// +func (p *parser) parsePackageName() string { + return p.expect(scanner.Ident) +} + +// dotIdentifier = ( ident | '·' ) { ident | int | '·' } . +func (p *parser) parseDotIdent() string { + ident := "" + if p.tok != scanner.Int { + sep := 'x' // not white space + for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' { + ident += p.lit + sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token + p.next() + } + } + if ident == "" { + p.expect(scanner.Ident) // use expect() for error handling + } + return ident +} + +// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) . +// +func (p *parser) parseQualifiedName() (id, name string) { + p.expect('@') + id = p.parsePackageId() + p.expect('.') + // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields. + if p.tok == '?' { + p.next() + } else { + name = p.parseDotIdent() + } + return +} + +// getPkg returns the package for a given id. If the package is +// not found, create the package and add it to the p.localPkgs +// and p.sharedPkgs maps. name is the (expected) name of the +// package. If name == "", the package name is expected to be +// set later via an import clause in the export data. +// +// id identifies a package, usually by a canonical package path like +// "encoding/json" but possibly by a non-canonical import path like +// "./json". +// +func (p *parser) getPkg(id, name string) *types.Package { + // package unsafe is not in the packages maps - handle explicitly + if id == "unsafe" { + return types.Unsafe + } + + pkg := p.localPkgs[id] + if pkg == nil { + // first import of id from this package + pkg = p.sharedPkgs[id] + if pkg == nil { + // first import of id by this importer; + // add (possibly unnamed) pkg to shared packages + pkg = types.NewPackage(id, name) + p.sharedPkgs[id] = pkg + } + // add (possibly unnamed) pkg to local packages + if p.localPkgs == nil { + p.localPkgs = make(map[string]*types.Package) + } + p.localPkgs[id] = pkg + } else if name != "" { + // package exists already and we have an expected package name; + // make sure names match or set package name if necessary + if pname := pkg.Name(); pname == "" { + pkg.SetName(name) + } else if pname != name { + p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name) + } + } + return pkg +} + +// parseExportedName is like parseQualifiedName, but +// the package id is resolved to an imported *types.Package. +// +func (p *parser) parseExportedName() (pkg *types.Package, name string) { + id, name := p.parseQualifiedName() + pkg = p.getPkg(id, "") + return +} + +// ---------------------------------------------------------------------------- +// Types + +// BasicType = identifier . +// +func (p *parser) parseBasicType() types.Type { + id := p.expect(scanner.Ident) + obj := types.Universe.Lookup(id) + if obj, ok := obj.(*types.TypeName); ok { + return obj.Type() + } + p.errorf("not a basic type: %s", id) + return nil +} + +// ArrayType = "[" int_lit "]" Type . +// +func (p *parser) parseArrayType(parent *types.Package) types.Type { + // "[" already consumed and lookahead known not to be "]" + lit := p.expect(scanner.Int) + p.expect(']') + elem := p.parseType(parent) + n, err := strconv.ParseInt(lit, 10, 64) + if err != nil { + p.error(err) + } + return types.NewArray(elem, n) +} + +// MapType = "map" "[" Type "]" Type . +// +func (p *parser) parseMapType(parent *types.Package) types.Type { + p.expectKeyword("map") + p.expect('[') + key := p.parseType(parent) + p.expect(']') + elem := p.parseType(parent) + return types.NewMap(key, elem) +} + +// Name = identifier | "?" | QualifiedName . +// +// For unqualified and anonymous names, the returned package is the parent +// package unless parent == nil, in which case the returned package is the +// package being imported. (The parent package is not nil if the the name +// is an unqualified struct field or interface method name belonging to a +// type declared in another package.) +// +// For qualified names, the returned package is nil (and not created if +// it doesn't exist yet) unless materializePkg is set (which creates an +// unnamed package with valid package path). In the latter case, a +// subsequent import clause is expected to provide a name for the package. +// +func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) { + pkg = parent + if pkg == nil { + pkg = p.sharedPkgs[p.id] + } + switch p.tok { + case scanner.Ident: + name = p.lit + p.next() + case '?': + // anonymous + p.next() + case '@': + // exported name prefixed with package path + pkg = nil + var id string + id, name = p.parseQualifiedName() + if materializePkg { + pkg = p.getPkg(id, "") + } + default: + p.error("name expected") + } + return +} + +func deref(typ types.Type) types.Type { + if p, _ := typ.(*types.Pointer); p != nil { + return p.Elem() + } + return typ +} + +// Field = Name Type [ string_lit ] . +// +func (p *parser) parseField(parent *types.Package) (*types.Var, string) { + pkg, name := p.parseName(parent, true) + + if name == "_" { + // Blank fields should be package-qualified because they + // are unexported identifiers, but gc does not qualify them. + // Assuming that the ident belongs to the current package + // causes types to change during re-exporting, leading + // to spurious "can't assign A to B" errors from go/types. + // As a workaround, pretend all blank fields belong + // to the same unique dummy package. + const blankpkg = "<_>" + pkg = p.getPkg(blankpkg, blankpkg) + } + + typ := p.parseType(parent) + anonymous := false + if name == "" { + // anonymous field - typ must be T or *T and T must be a type name + switch typ := deref(typ).(type) { + case *types.Basic: // basic types are named types + pkg = nil // objects defined in Universe scope have no package + name = typ.Name() + case *types.Named: + name = typ.Obj().Name() + default: + p.errorf("anonymous field expected") + } + anonymous = true + } + tag := "" + if p.tok == scanner.String { + s := p.expect(scanner.String) + var err error + tag, err = strconv.Unquote(s) + if err != nil { + p.errorf("invalid struct tag %s: %s", s, err) + } + } + return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag +} + +// StructType = "struct" "{" [ FieldList ] "}" . +// FieldList = Field { ";" Field } . +// +func (p *parser) parseStructType(parent *types.Package) types.Type { + var fields []*types.Var + var tags []string + + p.expectKeyword("struct") + p.expect('{') + for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { + if i > 0 { + p.expect(';') + } + fld, tag := p.parseField(parent) + if tag != "" && tags == nil { + tags = make([]string, i) + } + if tags != nil { + tags = append(tags, tag) + } + fields = append(fields, fld) + } + p.expect('}') + + return types.NewStruct(fields, tags) +} + +// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] . +// +func (p *parser) parseParameter() (par *types.Var, isVariadic bool) { + _, name := p.parseName(nil, false) + // remove gc-specific parameter numbering + if i := strings.Index(name, "·"); i >= 0 { + name = name[:i] + } + if p.tok == '.' { + p.expectSpecial("...") + isVariadic = true + } + typ := p.parseType(nil) + if isVariadic { + typ = types.NewSlice(typ) + } + // ignore argument tag (e.g. "noescape") + if p.tok == scanner.String { + p.next() + } + // TODO(gri) should we provide a package? + par = types.NewVar(token.NoPos, nil, name, typ) + return +} + +// Parameters = "(" [ ParameterList ] ")" . +// ParameterList = { Parameter "," } Parameter . +// +func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) { + p.expect('(') + for p.tok != ')' && p.tok != scanner.EOF { + if len(list) > 0 { + p.expect(',') + } + par, variadic := p.parseParameter() + list = append(list, par) + if variadic { + if isVariadic { + p.error("... not on final argument") + } + isVariadic = true + } + } + p.expect(')') + + return +} + +// Signature = Parameters [ Result ] . +// Result = Type | Parameters . +// +func (p *parser) parseSignature(recv *types.Var) *types.Signature { + params, isVariadic := p.parseParameters() + + // optional result type + var results []*types.Var + if p.tok == '(' { + var variadic bool + results, variadic = p.parseParameters() + if variadic { + p.error("... not permitted on result type") + } + } + + return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic) +} + +// InterfaceType = "interface" "{" [ MethodList ] "}" . +// MethodList = Method { ";" Method } . +// Method = Name Signature . +// +// The methods of embedded interfaces are always "inlined" +// by the compiler and thus embedded interfaces are never +// visible in the export data. +// +func (p *parser) parseInterfaceType(parent *types.Package) types.Type { + var methods []*types.Func + + p.expectKeyword("interface") + p.expect('{') + for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { + if i > 0 { + p.expect(';') + } + pkg, name := p.parseName(parent, true) + sig := p.parseSignature(nil) + methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) + } + p.expect('}') + + // Complete requires the type's embedded interfaces to be fully defined, + // but we do not define any + return types.NewInterface(methods, nil).Complete() +} + +// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type . +// +func (p *parser) parseChanType(parent *types.Package) types.Type { + dir := types.SendRecv + if p.tok == scanner.Ident { + p.expectKeyword("chan") + if p.tok == '<' { + p.expectSpecial("<-") + dir = types.SendOnly + } + } else { + p.expectSpecial("<-") + p.expectKeyword("chan") + dir = types.RecvOnly + } + elem := p.parseType(parent) + return types.NewChan(dir, elem) +} + +// Type = +// BasicType | TypeName | ArrayType | SliceType | StructType | +// PointerType | FuncType | InterfaceType | MapType | ChanType | +// "(" Type ")" . +// +// BasicType = ident . +// TypeName = ExportedName . +// SliceType = "[" "]" Type . +// PointerType = "*" Type . +// FuncType = "func" Signature . +// +func (p *parser) parseType(parent *types.Package) types.Type { + switch p.tok { + case scanner.Ident: + switch p.lit { + default: + return p.parseBasicType() + case "struct": + return p.parseStructType(parent) + case "func": + // FuncType + p.next() + return p.parseSignature(nil) + case "interface": + return p.parseInterfaceType(parent) + case "map": + return p.parseMapType(parent) + case "chan": + return p.parseChanType(parent) + } + case '@': + // TypeName + pkg, name := p.parseExportedName() + return declTypeName(pkg, name).Type() + case '[': + p.next() // look ahead + if p.tok == ']' { + // SliceType + p.next() + return types.NewSlice(p.parseType(parent)) + } + return p.parseArrayType(parent) + case '*': + // PointerType + p.next() + return types.NewPointer(p.parseType(parent)) + case '<': + return p.parseChanType(parent) + case '(': + // "(" Type ")" + p.next() + typ := p.parseType(parent) + p.expect(')') + return typ + } + p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) + return nil +} + +// ---------------------------------------------------------------------------- +// Declarations + +// ImportDecl = "import" PackageName PackageId . +// +func (p *parser) parseImportDecl() { + p.expectKeyword("import") + name := p.parsePackageName() + p.getPkg(p.parsePackageId(), name) +} + +// int_lit = [ "+" | "-" ] { "0" ... "9" } . +// +func (p *parser) parseInt() string { + s := "" + switch p.tok { + case '-': + s = "-" + p.next() + case '+': + p.next() + } + return s + p.expect(scanner.Int) +} + +// number = int_lit [ "p" int_lit ] . +// +func (p *parser) parseNumber() (typ *types.Basic, val constant.Value) { + // mantissa + mant := constant.MakeFromLiteral(p.parseInt(), token.INT, 0) + if mant == nil { + panic("invalid mantissa") + } + + if p.lit == "p" { + // exponent (base 2) + p.next() + exp, err := strconv.ParseInt(p.parseInt(), 10, 0) + if err != nil { + p.error(err) + } + if exp < 0 { + denom := constant.MakeInt64(1) + denom = constant.Shift(denom, token.SHL, uint(-exp)) + typ = types.Typ[types.UntypedFloat] + val = constant.BinaryOp(mant, token.QUO, denom) + return + } + if exp > 0 { + mant = constant.Shift(mant, token.SHL, uint(exp)) + } + typ = types.Typ[types.UntypedFloat] + val = mant + return + } + + typ = types.Typ[types.UntypedInt] + val = mant + return +} + +// ConstDecl = "const" ExportedName [ Type ] "=" Literal . +// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit . +// bool_lit = "true" | "false" . +// complex_lit = "(" float_lit "+" float_lit "i" ")" . +// rune_lit = "(" int_lit "+" int_lit ")" . +// string_lit = `"` { unicode_char } `"` . +// +func (p *parser) parseConstDecl() { + p.expectKeyword("const") + pkg, name := p.parseExportedName() + + var typ0 types.Type + if p.tok != '=' { + // constant types are never structured - no need for parent type + typ0 = p.parseType(nil) + } + + p.expect('=') + var typ types.Type + var val constant.Value + switch p.tok { + case scanner.Ident: + // bool_lit + if p.lit != "true" && p.lit != "false" { + p.error("expected true or false") + } + typ = types.Typ[types.UntypedBool] + val = constant.MakeBool(p.lit == "true") + p.next() + + case '-', scanner.Int: + // int_lit + typ, val = p.parseNumber() + + case '(': + // complex_lit or rune_lit + p.next() + if p.tok == scanner.Char { + p.next() + p.expect('+') + typ = types.Typ[types.UntypedRune] + _, val = p.parseNumber() + p.expect(')') + break + } + _, re := p.parseNumber() + p.expect('+') + _, im := p.parseNumber() + p.expectKeyword("i") + p.expect(')') + typ = types.Typ[types.UntypedComplex] + val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) + + case scanner.Char: + // rune_lit + typ = types.Typ[types.UntypedRune] + val = constant.MakeFromLiteral(p.lit, token.CHAR, 0) + p.next() + + case scanner.String: + // string_lit + typ = types.Typ[types.UntypedString] + val = constant.MakeFromLiteral(p.lit, token.STRING, 0) + p.next() + + default: + p.errorf("expected literal got %s", scanner.TokenString(p.tok)) + } + + if typ0 == nil { + typ0 = typ + } + + pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val)) +} + +// TypeDecl = "type" ExportedName Type . +// +func (p *parser) parseTypeDecl() { + p.expectKeyword("type") + pkg, name := p.parseExportedName() + obj := declTypeName(pkg, name) + + // The type object may have been imported before and thus already + // have a type associated with it. We still need to parse the type + // structure, but throw it away if the object already has a type. + // This ensures that all imports refer to the same type object for + // a given type declaration. + typ := p.parseType(pkg) + + if name := obj.Type().(*types.Named); name.Underlying() == nil { + name.SetUnderlying(typ) + } +} + +// VarDecl = "var" ExportedName Type . +// +func (p *parser) parseVarDecl() { + p.expectKeyword("var") + pkg, name := p.parseExportedName() + typ := p.parseType(pkg) + pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ)) +} + +// Func = Signature [ Body ] . +// Body = "{" ... "}" . +// +func (p *parser) parseFunc(recv *types.Var) *types.Signature { + sig := p.parseSignature(recv) + if p.tok == '{' { + p.next() + for i := 1; i > 0; p.next() { + switch p.tok { + case '{': + i++ + case '}': + i-- + } + } + } + return sig +} + +// MethodDecl = "func" Receiver Name Func . +// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . +// +func (p *parser) parseMethodDecl() { + // "func" already consumed + p.expect('(') + recv, _ := p.parseParameter() // receiver + p.expect(')') + + // determine receiver base type object + base := deref(recv.Type()).(*types.Named) + + // parse method name, signature, and possibly inlined body + _, name := p.parseName(nil, false) + sig := p.parseFunc(recv) + + // methods always belong to the same package as the base type object + pkg := base.Obj().Pkg() + + // add method to type unless type was imported before + // and method exists already + // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small. + base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) +} + +// FuncDecl = "func" ExportedName Func . +// +func (p *parser) parseFuncDecl() { + // "func" already consumed + pkg, name := p.parseExportedName() + typ := p.parseFunc(nil) + pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ)) +} + +// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" . +// +func (p *parser) parseDecl() { + if p.tok == scanner.Ident { + switch p.lit { + case "import": + p.parseImportDecl() + case "const": + p.parseConstDecl() + case "type": + p.parseTypeDecl() + case "var": + p.parseVarDecl() + case "func": + p.next() // look ahead + if p.tok == '(' { + p.parseMethodDecl() + } else { + p.parseFuncDecl() + } + } + } + p.expect('\n') +} + +// ---------------------------------------------------------------------------- +// Export + +// Export = "PackageClause { Decl } "$$" . +// PackageClause = "package" PackageName [ "safe" ] "\n" . +// +func (p *parser) parseExport() *types.Package { + p.expectKeyword("package") + name := p.parsePackageName() + if p.tok == scanner.Ident && p.lit == "safe" { + // package was compiled with -u option - ignore + p.next() + } + p.expect('\n') + + pkg := p.getPkg(p.id, name) + + for p.tok != '$' && p.tok != scanner.EOF { + p.parseDecl() + } + + if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' { + // don't call next()/expect() since reading past the + // export data may cause scanner errors (e.g. NUL chars) + p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch) + } + + if n := p.scanner.ErrorCount; n != 0 { + p.errorf("expected no scanner errors, got %d", n) + } + + // Record all locally referenced packages as imports. + var imports []*types.Package + for id, pkg2 := range p.localPkgs { + if pkg2.Name() == "" { + p.errorf("%s package has no name", id) + } + if id == p.id { + continue // avoid self-edge + } + imports = append(imports, pkg2) + } + sort.Sort(byPath(imports)) + pkg.SetImports(imports) + + // package was imported completely and without errors + pkg.MarkComplete() + + return pkg +} + +type byPath []*types.Package + +func (a byPath) Len() int { return len(a) } +func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go new file mode 100644 index 0000000000..be671c79b7 --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go @@ -0,0 +1,723 @@ +// Copyright 2019 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. + +// Indexed binary package export. +// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go; +// see that file for specification of the format. + +// +build go1.11 + +package gcimporter + +import ( + "bytes" + "encoding/binary" + "go/ast" + "go/constant" + "go/token" + "go/types" + "io" + "math/big" + "reflect" + "sort" +) + +// Current indexed export format version. Increase with each format change. +// 0: Go1.11 encoding +const iexportVersion = 0 + +// IExportData returns the binary export data for pkg. +// If no file set is provided, position info will be missing. +func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { + defer func() { + if e := recover(); e != nil { + if ierr, ok := e.(internalError); ok { + err = ierr + return + } + // Not an internal error; panic again. + panic(e) + } + }() + + p := iexporter{ + out: bytes.NewBuffer(nil), + fset: fset, + allPkgs: map[*types.Package]bool{}, + stringIndex: map[string]uint64{}, + declIndex: map[types.Object]uint64{}, + typIndex: map[types.Type]uint64{}, + } + + for i, pt := range predeclared() { + p.typIndex[pt] = uint64(i) + } + if len(p.typIndex) > predeclReserved { + panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)) + } + + // Initialize work queue with exported declarations. + scope := pkg.Scope() + for _, name := range scope.Names() { + if ast.IsExported(name) { + p.pushDecl(scope.Lookup(name)) + } + } + + // Loop until no more work. + for !p.declTodo.empty() { + p.doDecl(p.declTodo.popHead()) + } + + // Append indices to data0 section. + dataLen := uint64(p.data0.Len()) + w := p.newWriter() + w.writeIndex(p.declIndex, pkg) + w.flush() + + // Assemble header. + var hdr intWriter + hdr.WriteByte('i') + hdr.uint64(iexportVersion) + hdr.uint64(uint64(p.strings.Len())) + hdr.uint64(dataLen) + + // Flush output. + io.Copy(p.out, &hdr) + io.Copy(p.out, &p.strings) + io.Copy(p.out, &p.data0) + + return p.out.Bytes(), nil +} + +// writeIndex writes out an object index. mainIndex indicates whether +// we're writing out the main index, which is also read by +// non-compiler tools and includes a complete package description +// (i.e., name and height). +func (w *exportWriter) writeIndex(index map[types.Object]uint64, localpkg *types.Package) { + // Build a map from packages to objects from that package. + pkgObjs := map[*types.Package][]types.Object{} + + // For the main index, make sure to include every package that + // we reference, even if we're not exporting (or reexporting) + // any symbols from it. + pkgObjs[localpkg] = nil + for pkg := range w.p.allPkgs { + pkgObjs[pkg] = nil + } + + for obj := range index { + pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], obj) + } + + var pkgs []*types.Package + for pkg, objs := range pkgObjs { + pkgs = append(pkgs, pkg) + + sort.Slice(objs, func(i, j int) bool { + return objs[i].Name() < objs[j].Name() + }) + } + + sort.Slice(pkgs, func(i, j int) bool { + return pkgs[i].Path() < pkgs[j].Path() + }) + + w.uint64(uint64(len(pkgs))) + for _, pkg := range pkgs { + w.string(pkg.Path()) + w.string(pkg.Name()) + w.uint64(uint64(0)) // package height is not needed for go/types + + objs := pkgObjs[pkg] + w.uint64(uint64(len(objs))) + for _, obj := range objs { + w.string(obj.Name()) + w.uint64(index[obj]) + } + } +} + +type iexporter struct { + fset *token.FileSet + out *bytes.Buffer + + // allPkgs tracks all packages that have been referenced by + // the export data, so we can ensure to include them in the + // main index. + allPkgs map[*types.Package]bool + + declTodo objQueue + + strings intWriter + stringIndex map[string]uint64 + + data0 intWriter + declIndex map[types.Object]uint64 + typIndex map[types.Type]uint64 +} + +// stringOff returns the offset of s within the string section. +// If not already present, it's added to the end. +func (p *iexporter) stringOff(s string) uint64 { + off, ok := p.stringIndex[s] + if !ok { + off = uint64(p.strings.Len()) + p.stringIndex[s] = off + + p.strings.uint64(uint64(len(s))) + p.strings.WriteString(s) + } + return off +} + +// pushDecl adds n to the declaration work queue, if not already present. +func (p *iexporter) pushDecl(obj types.Object) { + // Package unsafe is known to the compiler and predeclared. + assert(obj.Pkg() != types.Unsafe) + + if _, ok := p.declIndex[obj]; ok { + return + } + + p.declIndex[obj] = ^uint64(0) // mark n present in work queue + p.declTodo.pushTail(obj) +} + +// exportWriter handles writing out individual data section chunks. +type exportWriter struct { + p *iexporter + + data intWriter + currPkg *types.Package + prevFile string + prevLine int64 +} + +func (p *iexporter) doDecl(obj types.Object) { + w := p.newWriter() + w.setPkg(obj.Pkg(), false) + + switch obj := obj.(type) { + case *types.Var: + w.tag('V') + w.pos(obj.Pos()) + w.typ(obj.Type(), obj.Pkg()) + + case *types.Func: + sig, _ := obj.Type().(*types.Signature) + if sig.Recv() != nil { + panic(internalErrorf("unexpected method: %v", sig)) + } + w.tag('F') + w.pos(obj.Pos()) + w.signature(sig) + + case *types.Const: + w.tag('C') + w.pos(obj.Pos()) + w.value(obj.Type(), obj.Val()) + + case *types.TypeName: + if obj.IsAlias() { + w.tag('A') + w.pos(obj.Pos()) + w.typ(obj.Type(), obj.Pkg()) + break + } + + // Defined type. + w.tag('T') + w.pos(obj.Pos()) + + underlying := obj.Type().Underlying() + w.typ(underlying, obj.Pkg()) + + t := obj.Type() + if types.IsInterface(t) { + break + } + + named, ok := t.(*types.Named) + if !ok { + panic(internalErrorf("%s is not a defined type", t)) + } + + n := named.NumMethods() + w.uint64(uint64(n)) + for i := 0; i < n; i++ { + m := named.Method(i) + w.pos(m.Pos()) + w.string(m.Name()) + sig, _ := m.Type().(*types.Signature) + w.param(sig.Recv()) + w.signature(sig) + } + + default: + panic(internalErrorf("unexpected object: %v", obj)) + } + + p.declIndex[obj] = w.flush() +} + +func (w *exportWriter) tag(tag byte) { + w.data.WriteByte(tag) +} + +func (w *exportWriter) pos(pos token.Pos) { + p := w.p.fset.Position(pos) + file := p.Filename + line := int64(p.Line) + + // When file is the same as the last position (common case), + // we can save a few bytes by delta encoding just the line + // number. + // + // Note: Because data objects may be read out of order (or not + // at all), we can only apply delta encoding within a single + // object. This is handled implicitly by tracking prevFile and + // prevLine as fields of exportWriter. + + if file == w.prevFile { + delta := line - w.prevLine + w.int64(delta) + if delta == deltaNewFile { + w.int64(-1) + } + } else { + w.int64(deltaNewFile) + w.int64(line) // line >= 0 + w.string(file) + w.prevFile = file + } + w.prevLine = line +} + +func (w *exportWriter) pkg(pkg *types.Package) { + // Ensure any referenced packages are declared in the main index. + w.p.allPkgs[pkg] = true + + w.string(pkg.Path()) +} + +func (w *exportWriter) qualifiedIdent(obj types.Object) { + // Ensure any referenced declarations are written out too. + w.p.pushDecl(obj) + + w.string(obj.Name()) + w.pkg(obj.Pkg()) +} + +func (w *exportWriter) typ(t types.Type, pkg *types.Package) { + w.data.uint64(w.p.typOff(t, pkg)) +} + +func (p *iexporter) newWriter() *exportWriter { + return &exportWriter{p: p} +} + +func (w *exportWriter) flush() uint64 { + off := uint64(w.p.data0.Len()) + io.Copy(&w.p.data0, &w.data) + return off +} + +func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { + off, ok := p.typIndex[t] + if !ok { + w := p.newWriter() + w.doTyp(t, pkg) + off = predeclReserved + w.flush() + p.typIndex[t] = off + } + return off +} + +func (w *exportWriter) startType(k itag) { + w.data.uint64(uint64(k)) +} + +func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { + switch t := t.(type) { + case *types.Named: + w.startType(definedType) + w.qualifiedIdent(t.Obj()) + + case *types.Pointer: + w.startType(pointerType) + w.typ(t.Elem(), pkg) + + case *types.Slice: + w.startType(sliceType) + w.typ(t.Elem(), pkg) + + case *types.Array: + w.startType(arrayType) + w.uint64(uint64(t.Len())) + w.typ(t.Elem(), pkg) + + case *types.Chan: + w.startType(chanType) + // 1 RecvOnly; 2 SendOnly; 3 SendRecv + var dir uint64 + switch t.Dir() { + case types.RecvOnly: + dir = 1 + case types.SendOnly: + dir = 2 + case types.SendRecv: + dir = 3 + } + w.uint64(dir) + w.typ(t.Elem(), pkg) + + case *types.Map: + w.startType(mapType) + w.typ(t.Key(), pkg) + w.typ(t.Elem(), pkg) + + case *types.Signature: + w.startType(signatureType) + w.setPkg(pkg, true) + w.signature(t) + + case *types.Struct: + w.startType(structType) + w.setPkg(pkg, true) + + n := t.NumFields() + w.uint64(uint64(n)) + for i := 0; i < n; i++ { + f := t.Field(i) + w.pos(f.Pos()) + w.string(f.Name()) + w.typ(f.Type(), pkg) + w.bool(f.Embedded()) + w.string(t.Tag(i)) // note (or tag) + } + + case *types.Interface: + w.startType(interfaceType) + w.setPkg(pkg, true) + + n := t.NumEmbeddeds() + w.uint64(uint64(n)) + for i := 0; i < n; i++ { + f := t.Embedded(i) + w.pos(f.Obj().Pos()) + w.typ(f.Obj().Type(), f.Obj().Pkg()) + } + + n = t.NumExplicitMethods() + w.uint64(uint64(n)) + for i := 0; i < n; i++ { + m := t.ExplicitMethod(i) + w.pos(m.Pos()) + w.string(m.Name()) + sig, _ := m.Type().(*types.Signature) + w.signature(sig) + } + + default: + panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) + } +} + +func (w *exportWriter) setPkg(pkg *types.Package, write bool) { + if write { + w.pkg(pkg) + } + + w.currPkg = pkg +} + +func (w *exportWriter) signature(sig *types.Signature) { + w.paramList(sig.Params()) + w.paramList(sig.Results()) + if sig.Params().Len() > 0 { + w.bool(sig.Variadic()) + } +} + +func (w *exportWriter) paramList(tup *types.Tuple) { + n := tup.Len() + w.uint64(uint64(n)) + for i := 0; i < n; i++ { + w.param(tup.At(i)) + } +} + +func (w *exportWriter) param(obj types.Object) { + w.pos(obj.Pos()) + w.localIdent(obj) + w.typ(obj.Type(), obj.Pkg()) +} + +func (w *exportWriter) value(typ types.Type, v constant.Value) { + w.typ(typ, nil) + + switch v.Kind() { + case constant.Bool: + w.bool(constant.BoolVal(v)) + case constant.Int: + var i big.Int + if i64, exact := constant.Int64Val(v); exact { + i.SetInt64(i64) + } else if ui64, exact := constant.Uint64Val(v); exact { + i.SetUint64(ui64) + } else { + i.SetString(v.ExactString(), 10) + } + w.mpint(&i, typ) + case constant.Float: + f := constantToFloat(v) + w.mpfloat(f, typ) + case constant.Complex: + w.mpfloat(constantToFloat(constant.Real(v)), typ) + w.mpfloat(constantToFloat(constant.Imag(v)), typ) + case constant.String: + w.string(constant.StringVal(v)) + case constant.Unknown: + // package contains type errors + default: + panic(internalErrorf("unexpected value %v (%T)", v, v)) + } +} + +// constantToFloat converts a constant.Value with kind constant.Float to a +// big.Float. +func constantToFloat(x constant.Value) *big.Float { + assert(x.Kind() == constant.Float) + // Use the same floating-point precision (512) as cmd/compile + // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). + const mpprec = 512 + var f big.Float + f.SetPrec(mpprec) + if v, exact := constant.Float64Val(x); exact { + // float64 + f.SetFloat64(v) + } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { + // TODO(gri): add big.Rat accessor to constant.Value. + n := valueToRat(num) + d := valueToRat(denom) + f.SetRat(n.Quo(n, d)) + } else { + // Value too large to represent as a fraction => inaccessible. + // TODO(gri): add big.Float accessor to constant.Value. + _, ok := f.SetString(x.ExactString()) + assert(ok) + } + return &f +} + +// mpint exports a multi-precision integer. +// +// For unsigned types, small values are written out as a single +// byte. Larger values are written out as a length-prefixed big-endian +// byte string, where the length prefix is encoded as its complement. +// For example, bytes 0, 1, and 2 directly represent the integer +// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, +// 2-, and 3-byte big-endian string follow. +// +// Encoding for signed types use the same general approach as for +// unsigned types, except small values use zig-zag encoding and the +// bottom bit of length prefix byte for large values is reserved as a +// sign bit. +// +// The exact boundary between small and large encodings varies +// according to the maximum number of bytes needed to encode a value +// of type typ. As a special case, 8-bit types are always encoded as a +// single byte. +// +// TODO(mdempsky): Is this level of complexity really worthwhile? +func (w *exportWriter) mpint(x *big.Int, typ types.Type) { + basic, ok := typ.Underlying().(*types.Basic) + if !ok { + panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) + } + + signed, maxBytes := intSize(basic) + + negative := x.Sign() < 0 + if !signed && negative { + panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) + } + + b := x.Bytes() + if len(b) > 0 && b[0] == 0 { + panic(internalErrorf("leading zeros")) + } + if uint(len(b)) > maxBytes { + panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) + } + + maxSmall := 256 - maxBytes + if signed { + maxSmall = 256 - 2*maxBytes + } + if maxBytes == 1 { + maxSmall = 256 + } + + // Check if x can use small value encoding. + if len(b) <= 1 { + var ux uint + if len(b) == 1 { + ux = uint(b[0]) + } + if signed { + ux <<= 1 + if negative { + ux-- + } + } + if ux < maxSmall { + w.data.WriteByte(byte(ux)) + return + } + } + + n := 256 - uint(len(b)) + if signed { + n = 256 - 2*uint(len(b)) + if negative { + n |= 1 + } + } + if n < maxSmall || n >= 256 { + panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) + } + + w.data.WriteByte(byte(n)) + w.data.Write(b) +} + +// mpfloat exports a multi-precision floating point number. +// +// The number's value is decomposed into mantissa × 2**exponent, where +// mantissa is an integer. The value is written out as mantissa (as a +// multi-precision integer) and then the exponent, except exponent is +// omitted if mantissa is zero. +func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { + if f.IsInf() { + panic("infinite constant") + } + + // Break into f = mant × 2**exp, with 0.5 <= mant < 1. + var mant big.Float + exp := int64(f.MantExp(&mant)) + + // Scale so that mant is an integer. + prec := mant.MinPrec() + mant.SetMantExp(&mant, int(prec)) + exp -= int64(prec) + + manti, acc := mant.Int(nil) + if acc != big.Exact { + panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) + } + w.mpint(manti, typ) + if manti.Sign() != 0 { + w.int64(exp) + } +} + +func (w *exportWriter) bool(b bool) bool { + var x uint64 + if b { + x = 1 + } + w.uint64(x) + return b +} + +func (w *exportWriter) int64(x int64) { w.data.int64(x) } +func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } +func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } + +func (w *exportWriter) localIdent(obj types.Object) { + // Anonymous parameters. + if obj == nil { + w.string("") + return + } + + name := obj.Name() + if name == "_" { + w.string("_") + return + } + + w.string(name) +} + +type intWriter struct { + bytes.Buffer +} + +func (w *intWriter) int64(x int64) { + var buf [binary.MaxVarintLen64]byte + n := binary.PutVarint(buf[:], x) + w.Write(buf[:n]) +} + +func (w *intWriter) uint64(x uint64) { + var buf [binary.MaxVarintLen64]byte + n := binary.PutUvarint(buf[:], x) + w.Write(buf[:n]) +} + +func assert(cond bool) { + if !cond { + panic("internal error: assertion failed") + } +} + +// The below is copied from go/src/cmd/compile/internal/gc/syntax.go. + +// objQueue is a FIFO queue of types.Object. The zero value of objQueue is +// a ready-to-use empty queue. +type objQueue struct { + ring []types.Object + head, tail int +} + +// empty returns true if q contains no Nodes. +func (q *objQueue) empty() bool { + return q.head == q.tail +} + +// pushTail appends n to the tail of the queue. +func (q *objQueue) pushTail(obj types.Object) { + if len(q.ring) == 0 { + q.ring = make([]types.Object, 16) + } else if q.head+len(q.ring) == q.tail { + // Grow the ring. + nring := make([]types.Object, len(q.ring)*2) + // Copy the old elements. + part := q.ring[q.head%len(q.ring):] + if q.tail-q.head <= len(part) { + part = part[:q.tail-q.head] + copy(nring, part) + } else { + pos := copy(nring, part) + copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) + } + q.ring, q.head, q.tail = nring, 0, q.tail-q.head + } + + q.ring[q.tail%len(q.ring)] = obj + q.tail++ +} + +// popHead pops a node from the head of the queue. It panics if q is empty. +func (q *objQueue) popHead() types.Object { + if q.empty() { + panic("dequeue empty") + } + obj := q.ring[q.head%len(q.ring)] + q.head++ + return obj +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go new file mode 100644 index 0000000000..3cb7ae5b9e --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go @@ -0,0 +1,606 @@ +// 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. + +// Indexed package import. +// See cmd/compile/internal/gc/iexport.go for the export data format. + +// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go. + +package gcimporter + +import ( + "bytes" + "encoding/binary" + "fmt" + "go/constant" + "go/token" + "go/types" + "io" + "sort" +) + +type intReader struct { + *bytes.Reader + path string +} + +func (r *intReader) int64() int64 { + i, err := binary.ReadVarint(r.Reader) + if err != nil { + errorf("import %q: read varint error: %v", r.path, err) + } + return i +} + +func (r *intReader) uint64() uint64 { + i, err := binary.ReadUvarint(r.Reader) + if err != nil { + errorf("import %q: read varint error: %v", r.path, err) + } + return i +} + +const predeclReserved = 32 + +type itag uint64 + +const ( + // Types + definedType itag = iota + pointerType + sliceType + arrayType + chanType + mapType + signatureType + structType + interfaceType +) + +// IImportData imports a package from the serialized package data +// and returns the number of bytes consumed and a reference to the package. +// If the export data version is not recognized or the format is otherwise +// compromised, an error is returned. +func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { + const currentVersion = 0 + version := -1 + defer func() { + if e := recover(); e != nil { + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } + } + }() + + r := &intReader{bytes.NewReader(data), path} + + version = int(r.uint64()) + switch version { + case currentVersion: + default: + errorf("unknown iexport format version %d", version) + } + + sLen := int64(r.uint64()) + dLen := int64(r.uint64()) + + whence, _ := r.Seek(0, io.SeekCurrent) + stringData := data[whence : whence+sLen] + declData := data[whence+sLen : whence+sLen+dLen] + r.Seek(sLen+dLen, io.SeekCurrent) + + p := iimporter{ + ipath: path, + + stringData: stringData, + stringCache: make(map[uint64]string), + pkgCache: make(map[uint64]*types.Package), + + declData: declData, + pkgIndex: make(map[*types.Package]map[string]uint64), + typCache: make(map[uint64]types.Type), + + fake: fakeFileSet{ + fset: fset, + files: make(map[string]*token.File), + }, + } + + for i, pt := range predeclared() { + p.typCache[uint64(i)] = pt + } + + pkgList := make([]*types.Package, r.uint64()) + for i := range pkgList { + pkgPathOff := r.uint64() + pkgPath := p.stringAt(pkgPathOff) + pkgName := p.stringAt(r.uint64()) + _ = r.uint64() // package height; unused by go/types + + if pkgPath == "" { + pkgPath = path + } + pkg := imports[pkgPath] + if pkg == nil { + pkg = types.NewPackage(pkgPath, pkgName) + imports[pkgPath] = pkg + } else if pkg.Name() != pkgName { + errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) + } + + p.pkgCache[pkgPathOff] = pkg + + nameIndex := make(map[string]uint64) + for nSyms := r.uint64(); nSyms > 0; nSyms-- { + name := p.stringAt(r.uint64()) + nameIndex[name] = r.uint64() + } + + p.pkgIndex[pkg] = nameIndex + pkgList[i] = pkg + } + var localpkg *types.Package + for _, pkg := range pkgList { + if pkg.Path() == path { + localpkg = pkg + } + } + + names := make([]string, 0, len(p.pkgIndex[localpkg])) + for name := range p.pkgIndex[localpkg] { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + p.doDecl(localpkg, name) + } + + for _, typ := range p.interfaceList { + typ.Complete() + } + + // record all referenced packages as imports + list := append(([]*types.Package)(nil), pkgList[1:]...) + sort.Sort(byPath(list)) + localpkg.SetImports(list) + + // package was imported completely and without errors + localpkg.MarkComplete() + + consumed, _ := r.Seek(0, io.SeekCurrent) + return int(consumed), localpkg, nil +} + +type iimporter struct { + ipath string + + stringData []byte + stringCache map[uint64]string + pkgCache map[uint64]*types.Package + + declData []byte + pkgIndex map[*types.Package]map[string]uint64 + typCache map[uint64]types.Type + + fake fakeFileSet + interfaceList []*types.Interface +} + +func (p *iimporter) doDecl(pkg *types.Package, name string) { + // See if we've already imported this declaration. + if obj := pkg.Scope().Lookup(name); obj != nil { + return + } + + off, ok := p.pkgIndex[pkg][name] + if !ok { + errorf("%v.%v not in index", pkg, name) + } + + r := &importReader{p: p, currPkg: pkg} + r.declReader.Reset(p.declData[off:]) + + r.obj(name) +} + +func (p *iimporter) stringAt(off uint64) string { + if s, ok := p.stringCache[off]; ok { + return s + } + + slen, n := binary.Uvarint(p.stringData[off:]) + if n <= 0 { + errorf("varint failed") + } + spos := off + uint64(n) + s := string(p.stringData[spos : spos+slen]) + p.stringCache[off] = s + return s +} + +func (p *iimporter) pkgAt(off uint64) *types.Package { + if pkg, ok := p.pkgCache[off]; ok { + return pkg + } + path := p.stringAt(off) + errorf("missing package %q in %q", path, p.ipath) + return nil +} + +func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { + if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) { + return t + } + + if off < predeclReserved { + errorf("predeclared type missing from cache: %v", off) + } + + r := &importReader{p: p} + r.declReader.Reset(p.declData[off-predeclReserved:]) + t := r.doType(base) + + if base == nil || !isInterface(t) { + p.typCache[off] = t + } + return t +} + +type importReader struct { + p *iimporter + declReader bytes.Reader + currPkg *types.Package + prevFile string + prevLine int64 +} + +func (r *importReader) obj(name string) { + tag := r.byte() + pos := r.pos() + + switch tag { + case 'A': + typ := r.typ() + + r.declare(types.NewTypeName(pos, r.currPkg, name, typ)) + + case 'C': + typ, val := r.value() + + r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) + + case 'F': + sig := r.signature(nil) + + r.declare(types.NewFunc(pos, r.currPkg, name, sig)) + + case 'T': + // Types can be recursive. We need to setup a stub + // declaration before recursing. + obj := types.NewTypeName(pos, r.currPkg, name, nil) + named := types.NewNamed(obj, nil, nil) + r.declare(obj) + + underlying := r.p.typAt(r.uint64(), named).Underlying() + named.SetUnderlying(underlying) + + if !isInterface(underlying) { + for n := r.uint64(); n > 0; n-- { + mpos := r.pos() + mname := r.ident() + recv := r.param() + msig := r.signature(recv) + + named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig)) + } + } + + case 'V': + typ := r.typ() + + r.declare(types.NewVar(pos, r.currPkg, name, typ)) + + default: + errorf("unexpected tag: %v", tag) + } +} + +func (r *importReader) declare(obj types.Object) { + obj.Pkg().Scope().Insert(obj) +} + +func (r *importReader) value() (typ types.Type, val constant.Value) { + typ = r.typ() + + switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { + case types.IsBoolean: + val = constant.MakeBool(r.bool()) + + case types.IsString: + val = constant.MakeString(r.string()) + + case types.IsInteger: + val = r.mpint(b) + + case types.IsFloat: + val = r.mpfloat(b) + + case types.IsComplex: + re := r.mpfloat(b) + im := r.mpfloat(b) + val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) + + default: + if b.Kind() == types.Invalid { + val = constant.MakeUnknown() + return + } + errorf("unexpected type %v", typ) // panics + panic("unreachable") + } + + return +} + +func intSize(b *types.Basic) (signed bool, maxBytes uint) { + if (b.Info() & types.IsUntyped) != 0 { + return true, 64 + } + + switch b.Kind() { + case types.Float32, types.Complex64: + return true, 3 + case types.Float64, types.Complex128: + return true, 7 + } + + signed = (b.Info() & types.IsUnsigned) == 0 + switch b.Kind() { + case types.Int8, types.Uint8: + maxBytes = 1 + case types.Int16, types.Uint16: + maxBytes = 2 + case types.Int32, types.Uint32: + maxBytes = 4 + default: + maxBytes = 8 + } + + return +} + +func (r *importReader) mpint(b *types.Basic) constant.Value { + signed, maxBytes := intSize(b) + + maxSmall := 256 - maxBytes + if signed { + maxSmall = 256 - 2*maxBytes + } + if maxBytes == 1 { + maxSmall = 256 + } + + n, _ := r.declReader.ReadByte() + if uint(n) < maxSmall { + v := int64(n) + if signed { + v >>= 1 + if n&1 != 0 { + v = ^v + } + } + return constant.MakeInt64(v) + } + + v := -n + if signed { + v = -(n &^ 1) >> 1 + } + if v < 1 || uint(v) > maxBytes { + errorf("weird decoding: %v, %v => %v", n, signed, v) + } + + buf := make([]byte, v) + io.ReadFull(&r.declReader, buf) + + // convert to little endian + // TODO(gri) go/constant should have a more direct conversion function + // (e.g., once it supports a big.Float based implementation) + for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { + buf[i], buf[j] = buf[j], buf[i] + } + + x := constant.MakeFromBytes(buf) + if signed && n&1 != 0 { + x = constant.UnaryOp(token.SUB, x, 0) + } + return x +} + +func (r *importReader) mpfloat(b *types.Basic) constant.Value { + x := r.mpint(b) + if constant.Sign(x) == 0 { + return x + } + + exp := r.int64() + switch { + case exp > 0: + x = constant.Shift(x, token.SHL, uint(exp)) + case exp < 0: + d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) + x = constant.BinaryOp(x, token.QUO, d) + } + return x +} + +func (r *importReader) ident() string { + return r.string() +} + +func (r *importReader) qualifiedIdent() (*types.Package, string) { + name := r.string() + pkg := r.pkg() + return pkg, name +} + +func (r *importReader) pos() token.Pos { + delta := r.int64() + if delta != deltaNewFile { + r.prevLine += delta + } else if l := r.int64(); l == -1 { + r.prevLine += deltaNewFile + } else { + r.prevFile = r.string() + r.prevLine = l + } + + if r.prevFile == "" && r.prevLine == 0 { + return token.NoPos + } + + return r.p.fake.pos(r.prevFile, int(r.prevLine)) +} + +func (r *importReader) typ() types.Type { + return r.p.typAt(r.uint64(), nil) +} + +func isInterface(t types.Type) bool { + _, ok := t.(*types.Interface) + return ok +} + +func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) } +func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } + +func (r *importReader) doType(base *types.Named) types.Type { + switch k := r.kind(); k { + default: + errorf("unexpected kind tag in %q: %v", r.p.ipath, k) + return nil + + case definedType: + pkg, name := r.qualifiedIdent() + r.p.doDecl(pkg, name) + return pkg.Scope().Lookup(name).(*types.TypeName).Type() + case pointerType: + return types.NewPointer(r.typ()) + case sliceType: + return types.NewSlice(r.typ()) + case arrayType: + n := r.uint64() + return types.NewArray(r.typ(), int64(n)) + case chanType: + dir := chanDir(int(r.uint64())) + return types.NewChan(dir, r.typ()) + case mapType: + return types.NewMap(r.typ(), r.typ()) + case signatureType: + r.currPkg = r.pkg() + return r.signature(nil) + + case structType: + r.currPkg = r.pkg() + + fields := make([]*types.Var, r.uint64()) + tags := make([]string, len(fields)) + for i := range fields { + fpos := r.pos() + fname := r.ident() + ftyp := r.typ() + emb := r.bool() + tag := r.string() + + fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb) + tags[i] = tag + } + return types.NewStruct(fields, tags) + + case interfaceType: + r.currPkg = r.pkg() + + embeddeds := make([]types.Type, r.uint64()) + for i := range embeddeds { + _ = r.pos() + embeddeds[i] = r.typ() + } + + methods := make([]*types.Func, r.uint64()) + for i := range methods { + mpos := r.pos() + mname := r.ident() + + // TODO(mdempsky): Matches bimport.go, but I + // don't agree with this. + var recv *types.Var + if base != nil { + recv = types.NewVar(token.NoPos, r.currPkg, "", base) + } + + msig := r.signature(recv) + methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig) + } + + typ := newInterface(methods, embeddeds) + r.p.interfaceList = append(r.p.interfaceList, typ) + return typ + } +} + +func (r *importReader) kind() itag { + return itag(r.uint64()) +} + +func (r *importReader) signature(recv *types.Var) *types.Signature { + params := r.paramList() + results := r.paramList() + variadic := params.Len() > 0 && r.bool() + return types.NewSignature(recv, params, results, variadic) +} + +func (r *importReader) paramList() *types.Tuple { + xs := make([]*types.Var, r.uint64()) + for i := range xs { + xs[i] = r.param() + } + return types.NewTuple(xs...) +} + +func (r *importReader) param() *types.Var { + pos := r.pos() + name := r.ident() + typ := r.typ() + return types.NewParam(pos, r.currPkg, name, typ) +} + +func (r *importReader) bool() bool { + return r.uint64() != 0 +} + +func (r *importReader) int64() int64 { + n, err := binary.ReadVarint(&r.declReader) + if err != nil { + errorf("readVarint: %v", err) + } + return n +} + +func (r *importReader) uint64() uint64 { + n, err := binary.ReadUvarint(&r.declReader) + if err != nil { + errorf("readUvarint: %v", err) + } + return n +} + +func (r *importReader) byte() byte { + x, err := r.declReader.ReadByte() + if err != nil { + errorf("declReader.ReadByte: %v", err) + } + return x +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go new file mode 100644 index 0000000000..463f252271 --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go @@ -0,0 +1,21 @@ +// 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. + +// +build !go1.11 + +package gcimporter + +import "go/types" + +func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { + named := make([]*types.Named, len(embeddeds)) + for i, e := range embeddeds { + var ok bool + named[i], ok = e.(*types.Named) + if !ok { + panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11") + } + } + return types.NewInterface(methods, named) +} diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go new file mode 100644 index 0000000000..ab28b95cbb --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go @@ -0,0 +1,13 @@ +// 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. + +// +build go1.11 + +package gcimporter + +import "go/types" + +func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { + return types.NewInterfaceType(methods, embeddeds) +} diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go new file mode 100644 index 0000000000..ea15d57be1 --- /dev/null +++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -0,0 +1,173 @@ +// 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 packagesdriver fetches type sizes for go/packages and go/analysis. +package packagesdriver + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "go/types" + "log" + "os" + "os/exec" + "strings" + "time" +) + +var debug = false + +// GetSizes returns the sizes used by the underlying driver with the given parameters. +func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) { + // TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver. + const toolPrefix = "GOPACKAGESDRIVER=" + tool := "" + for _, env := range env { + if val := strings.TrimPrefix(env, toolPrefix); val != env { + tool = val + } + } + + if tool == "" { + var err error + tool, err = exec.LookPath("gopackagesdriver") + if err != nil { + // We did not find the driver, so use "go list". + tool = "off" + } + } + + if tool == "off" { + return GetSizesGolist(ctx, buildFlags, env, dir, usesExportData) + } + + req, err := json.Marshal(struct { + Command string `json:"command"` + Env []string `json:"env"` + BuildFlags []string `json:"build_flags"` + }{ + Command: "sizes", + Env: env, + BuildFlags: buildFlags, + }) + if err != nil { + return nil, fmt.Errorf("failed to encode message to driver tool: %v", err) + } + + buf := new(bytes.Buffer) + cmd := exec.CommandContext(ctx, tool) + cmd.Dir = dir + cmd.Env = env + cmd.Stdin = bytes.NewReader(req) + cmd.Stdout = buf + cmd.Stderr = new(bytes.Buffer) + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr) + } + var response struct { + // Sizes, if not nil, is the types.Sizes to use when type checking. + Sizes *types.StdSizes + } + if err := json.Unmarshal(buf.Bytes(), &response); err != nil { + return nil, err + } + return response.Sizes, nil +} + +func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) { + args := []string{"list", "-f", "{{context.GOARCH}} {{context.Compiler}}"} + args = append(args, buildFlags...) + args = append(args, "--", "unsafe") + stdout, err := InvokeGo(ctx, env, dir, usesExportData, args...) + var goarch, compiler string + if err != nil { + if strings.Contains(err.Error(), "cannot find main module") { + // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. + // TODO(matloob): Is this a problem in practice? + envout, enverr := InvokeGo(ctx, env, dir, usesExportData, "env", "GOARCH") + if enverr != nil { + return nil, err + } + goarch = strings.TrimSpace(envout.String()) + compiler = "gc" + } else { + return nil, err + } + } else { + fields := strings.Fields(stdout.String()) + if len(fields) < 2 { + return nil, fmt.Errorf("could not determine GOARCH and Go compiler") + } + goarch = fields[0] + compiler = fields[1] + } + return types.SizesFor(compiler, goarch), nil +} + +// InvokeGo returns the stdout of a go command invocation. +func InvokeGo(ctx context.Context, env []string, dir string, usesExportData bool, args ...string) (*bytes.Buffer, error) { + if debug { + defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(env, args...)) }(time.Now()) + } + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + cmd := exec.CommandContext(ctx, "go", args...) + // On darwin the cwd gets resolved to the real path, which breaks anything that + // expects the working directory to keep the original path, including the + // go command when dealing with modules. + // The Go stdlib has a special feature where if the cwd and the PWD are the + // same node then it trusts the PWD, so by setting it in the env for the child + // process we fix up all the paths returned by the go command. + cmd.Env = append(append([]string{}, env...), "PWD="+dir) + cmd.Dir = dir + cmd.Stdout = stdout + cmd.Stderr = stderr + if err := cmd.Run(); err != nil { + exitErr, ok := err.(*exec.ExitError) + if !ok { + // Catastrophic error: + // - executable not found + // - context cancellation + return nil, fmt.Errorf("couldn't exec 'go %v': %s %T", args, err, err) + } + + // Export mode entails a build. + // If that build fails, errors appear on stderr + // (despite the -e flag) and the Export field is blank. + // Do not fail in that case. + if !usesExportData { + return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr) + } + } + + // As of writing, go list -export prints some non-fatal compilation + // errors to stderr, even with -e set. We would prefer that it put + // them in the Package.Error JSON (see https://golang.org/issue/26319). + // In the meantime, there's nowhere good to put them, but they can + // be useful for debugging. Print them if $GOPACKAGESPRINTGOLISTERRORS + // is set. + if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTGOLISTERRORS") != "" { + fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(env, args...), stderr) + } + + // debugging + if false { + fmt.Fprintf(os.Stderr, "%s stdout: <<%s>>\n", cmdDebugStr(env, args...), stdout) + } + + return stdout, nil +} + +func cmdDebugStr(envlist []string, args ...string) string { + env := make(map[string]string) + for _, kv := range envlist { + split := strings.Split(kv, "=") + k, v := split[0], split[1] + env[k] = v + } + + return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], args) +} diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go new file mode 100644 index 0000000000..3799f8ed8b --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/doc.go @@ -0,0 +1,222 @@ +// 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 packages loads Go packages for inspection and analysis. + +The Load function takes as input a list of patterns and return a list of Package +structs describing individual packages matched by those patterns. +The LoadMode controls the amount of detail in the loaded packages. + +Load passes most patterns directly to the underlying build tool, +but all patterns with the prefix "query=", where query is a +non-empty string of letters from [a-z], are reserved and may be +interpreted as query operators. + +Two query operators are currently supported: "file" and "pattern". + +The query "file=path/to/file.go" matches the package or packages enclosing +the Go source file path/to/file.go. For example "file=~/go/src/fmt/print.go" +might return the packages "fmt" and "fmt [fmt.test]". + +The query "pattern=string" causes "string" to be passed directly to +the underlying build tool. In most cases this is unnecessary, +but an application can use Load("pattern=" + x) as an escaping mechanism +to ensure that x is not interpreted as a query operator if it contains '='. + +All other query operators are reserved for future use and currently +cause Load to report an error. + +The Package struct provides basic information about the package, including + + - ID, a unique identifier for the package in the returned set; + - GoFiles, the names of the package's Go source files; + - Imports, a map from source import strings to the Packages they name; + - Types, the type information for the package's exported symbols; + - Syntax, the parsed syntax trees for the package's source code; and + - TypeInfo, the result of a complete type-check of the package syntax trees. + +(See the documentation for type Package for the complete list of fields +and more detailed descriptions.) + +For example, + + Load(nil, "bytes", "unicode...") + +returns four Package structs describing the standard library packages +bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern +can match multiple packages and that a package might be matched by +multiple patterns: in general it is not possible to determine which +packages correspond to which patterns. + +Note that the list returned by Load contains only the packages matched +by the patterns. Their dependencies can be found by walking the import +graph using the Imports fields. + +The Load function can be configured by passing a pointer to a Config as +the first argument. A nil Config is equivalent to the zero Config, which +causes Load to run in LoadFiles mode, collecting minimal information. +See the documentation for type Config for details. + +As noted earlier, the Config.Mode controls the amount of detail +reported about the loaded packages, with each mode returning all the data of the +previous mode with some extra added. See the documentation for type LoadMode +for details. + +Most tools should pass their command-line arguments (after any flags) +uninterpreted to the loader, so that the loader can interpret them +according to the conventions of the underlying build system. +See the Example function for typical usage. + +*/ +package packages // import "golang.org/x/tools/go/packages" + +/* + +Motivation and design considerations + +The new package's design solves problems addressed by two existing +packages: go/build, which locates and describes packages, and +golang.org/x/tools/go/loader, which loads, parses and type-checks them. +The go/build.Package structure encodes too much of the 'go build' way +of organizing projects, leaving us in need of a data type that describes a +package of Go source code independent of the underlying build system. +We wanted something that works equally well with go build and vgo, and +also other build systems such as Bazel and Blaze, making it possible to +construct analysis tools that work in all these environments. +Tools such as errcheck and staticcheck were essentially unavailable to +the Go community at Google, and some of Google's internal tools for Go +are unavailable externally. +This new package provides a uniform way to obtain package metadata by +querying each of these build systems, optionally supporting their +preferred command-line notations for packages, so that tools integrate +neatly with users' build environments. The Metadata query function +executes an external query tool appropriate to the current workspace. + +Loading packages always returns the complete import graph "all the way down", +even if all you want is information about a single package, because the query +mechanisms of all the build systems we currently support ({go,vgo} list, and +blaze/bazel aspect-based query) cannot provide detailed information +about one package without visiting all its dependencies too, so there is +no additional asymptotic cost to providing transitive information. +(This property might not be true of a hypothetical 5th build system.) + +In calls to TypeCheck, all initial packages, and any package that +transitively depends on one of them, must be loaded from source. +Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from +source; D may be loaded from export data, and E may not be loaded at all +(though it's possible that D's export data mentions it, so a +types.Package may be created for it and exposed.) + +The old loader had a feature to suppress type-checking of function +bodies on a per-package basis, primarily intended to reduce the work of +obtaining type information for imported packages. Now that imports are +satisfied by export data, the optimization no longer seems necessary. + +Despite some early attempts, the old loader did not exploit export data, +instead always using the equivalent of WholeProgram mode. This was due +to the complexity of mixing source and export data packages (now +resolved by the upward traversal mentioned above), and because export data +files were nearly always missing or stale. Now that 'go build' supports +caching, all the underlying build systems can guarantee to produce +export data in a reasonable (amortized) time. + +Test "main" packages synthesized by the build system are now reported as +first-class packages, avoiding the need for clients (such as go/ssa) to +reinvent this generation logic. + +One way in which go/packages is simpler than the old loader is in its +treatment of in-package tests. In-package tests are packages that +consist of all the files of the library under test, plus the test files. +The old loader constructed in-package tests by a two-phase process of +mutation called "augmentation": first it would construct and type check +all the ordinary library packages and type-check the packages that +depend on them; then it would add more (test) files to the package and +type-check again. This two-phase approach had four major problems: +1) in processing the tests, the loader modified the library package, + leaving no way for a client application to see both the test + package and the library package; one would mutate into the other. +2) because test files can declare additional methods on types defined in + the library portion of the package, the dispatch of method calls in + the library portion was affected by the presence of the test files. + This should have been a clue that the packages were logically + different. +3) this model of "augmentation" assumed at most one in-package test + per library package, which is true of projects using 'go build', + but not other build systems. +4) because of the two-phase nature of test processing, all packages that + import the library package had to be processed before augmentation, + forcing a "one-shot" API and preventing the client from calling Load + in several times in sequence as is now possible in WholeProgram mode. + (TypeCheck mode has a similar one-shot restriction for a different reason.) + +Early drafts of this package supported "multi-shot" operation. +Although it allowed clients to make a sequence of calls (or concurrent +calls) to Load, building up the graph of Packages incrementally, +it was of marginal value: it complicated the API +(since it allowed some options to vary across calls but not others), +it complicated the implementation, +it cannot be made to work in Types mode, as explained above, +and it was less efficient than making one combined call (when this is possible). +Among the clients we have inspected, none made multiple calls to load +but could not be easily and satisfactorily modified to make only a single call. +However, applications changes may be required. +For example, the ssadump command loads the user-specified packages +and in addition the runtime package. It is tempting to simply append +"runtime" to the user-provided list, but that does not work if the user +specified an ad-hoc package such as [a.go b.go]. +Instead, ssadump no longer requests the runtime package, +but seeks it among the dependencies of the user-specified packages, +and emits an error if it is not found. + +Overlays: The Overlay field in the Config allows providing alternate contents +for Go source files, by providing a mapping from file path to contents. +go/packages will pull in new imports added in overlay files when go/packages +is run in LoadImports mode or greater. +Overlay support for the go list driver isn't complete yet: if the file doesn't +exist on disk, it will only be recognized in an overlay if it is a non-test file +and the package would be reported even without the overlay. + +Questions & Tasks + +- Add GOARCH/GOOS? + They are not portable concepts, but could be made portable. + Our goal has been to allow users to express themselves using the conventions + of the underlying build system: if the build system honors GOARCH + during a build and during a metadata query, then so should + applications built atop that query mechanism. + Conversely, if the target architecture of the build is determined by + command-line flags, the application can pass the relevant + flags through to the build system using a command such as: + myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin" + However, this approach is low-level, unwieldy, and non-portable. + GOOS and GOARCH seem important enough to warrant a dedicated option. + +- How should we handle partial failures such as a mixture of good and + malformed patterns, existing and non-existent packages, successful and + failed builds, import failures, import cycles, and so on, in a call to + Load? + +- Support bazel, blaze, and go1.10 list, not just go1.11 list. + +- Handle (and test) various partial success cases, e.g. + a mixture of good packages and: + invalid patterns + nonexistent packages + empty packages + packages with malformed package or import declarations + unreadable files + import cycles + other parse errors + type errors + Make sure we record errors at the correct place in the graph. + +- Missing packages among initial arguments are not reported. + Return bogus packages for them, like golist does. + +- "undeclared name" errors (for example) are reported out of source file + order. I suspect this is due to the breadth-first resolution now used + by go/types. Is that a bug? Discuss with gri. + +*/ diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go new file mode 100644 index 0000000000..b696b68709 --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/external.go @@ -0,0 +1,94 @@ +// 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. + +// This file enables an external tool to intercept package requests. +// If the tool is present then its results are used in preference to +// the go list command. + +package packages + +import ( + "bytes" + "encoding/json" + "fmt" + "os/exec" + "strings" +) + +// The Driver Protocol +// +// The driver, given the inputs to a call to Load, returns metadata about the packages specified. +// This allows for different build systems to support go/packages by telling go/packages how the +// packages' source is organized. +// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in +// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package +// documentation in doc.go for the full description of the patterns that need to be supported. +// A driver receives as a JSON-serialized driverRequest struct in standard input and will +// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output. + +// driverRequest is used to provide the portion of Load's Config that is needed by a driver. +type driverRequest struct { + Mode LoadMode `json:"mode"` + // Env specifies the environment the underlying build system should be run in. + Env []string `json:"env"` + // BuildFlags are flags that should be passed to the underlying build system. + BuildFlags []string `json:"build_flags"` + // Tests specifies whether the patterns should also return test packages. + Tests bool `json:"tests"` + // Overlay maps file paths (relative to the driver's working directory) to the byte contents + // of overlay files. + Overlay map[string][]byte `json:"overlay"` +} + +// findExternalDriver returns the file path of a tool that supplies +// the build system package structure, or "" if not found." +// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its +// value, otherwise it searches for a binary named gopackagesdriver on the PATH. +func findExternalDriver(cfg *Config) driver { + const toolPrefix = "GOPACKAGESDRIVER=" + tool := "" + for _, env := range cfg.Env { + if val := strings.TrimPrefix(env, toolPrefix); val != env { + tool = val + } + } + if tool != "" && tool == "off" { + return nil + } + if tool == "" { + var err error + tool, err = exec.LookPath("gopackagesdriver") + if err != nil { + return nil + } + } + return func(cfg *Config, words ...string) (*driverResponse, error) { + req, err := json.Marshal(driverRequest{ + Mode: cfg.Mode, + Env: cfg.Env, + BuildFlags: cfg.BuildFlags, + Tests: cfg.Tests, + Overlay: cfg.Overlay, + }) + if err != nil { + return nil, fmt.Errorf("failed to encode message to driver tool: %v", err) + } + + buf := new(bytes.Buffer) + cmd := exec.CommandContext(cfg.Context, tool, words...) + cmd.Dir = cfg.Dir + cmd.Env = cfg.Env + cmd.Stdin = bytes.NewReader(req) + cmd.Stdout = buf + cmd.Stderr = new(bytes.Buffer) + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr) + } + var response driverResponse + if err := json.Unmarshal(buf.Bytes(), &response); err != nil { + return nil, err + } + return &response, nil + } +} diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go new file mode 100644 index 0000000000..970e8ca8b0 --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -0,0 +1,1000 @@ +// 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 packages + +import ( + "bytes" + "encoding/json" + "fmt" + "go/types" + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/tools/go/internal/packagesdriver" + "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/semver" +) + +// debug controls verbose logging. +var debug, _ = strconv.ParseBool(os.Getenv("GOPACKAGESDEBUG")) + +// A goTooOldError reports that the go command +// found by exec.LookPath is too old to use the new go list behavior. +type goTooOldError struct { + error +} + +// responseDeduper wraps a driverResponse, deduplicating its contents. +type responseDeduper struct { + seenRoots map[string]bool + seenPackages map[string]*Package + dr *driverResponse +} + +// init fills in r with a driverResponse. +func (r *responseDeduper) init(dr *driverResponse) { + r.dr = dr + r.seenRoots = map[string]bool{} + r.seenPackages = map[string]*Package{} + for _, pkg := range dr.Packages { + r.seenPackages[pkg.ID] = pkg + } + for _, root := range dr.Roots { + r.seenRoots[root] = true + } +} + +func (r *responseDeduper) addPackage(p *Package) { + if r.seenPackages[p.ID] != nil { + return + } + r.seenPackages[p.ID] = p + r.dr.Packages = append(r.dr.Packages, p) +} + +func (r *responseDeduper) addRoot(id string) { + if r.seenRoots[id] { + return + } + r.seenRoots[id] = true + r.dr.Roots = append(r.dr.Roots, id) +} + +// goInfo contains global information from the go tool. +type goInfo struct { + rootDirs map[string]string + env goEnv +} + +type goEnv struct { + modulesOn bool +} + +func determineEnv(cfg *Config) goEnv { + buf, err := invokeGo(cfg, "env", "GOMOD") + if err != nil { + return goEnv{} + } + gomod := bytes.TrimSpace(buf.Bytes()) + + env := goEnv{} + env.modulesOn = len(gomod) > 0 + return env +} + +// goListDriver uses the go list command to interpret the patterns and produce +// the build system package structure. +// See driver for more details. +func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { + var sizes types.Sizes + var sizeserr error + var sizeswg sync.WaitGroup + if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 { + sizeswg.Add(1) + go func() { + sizes, sizeserr = getSizes(cfg) + sizeswg.Done() + }() + } + + // start fetching rootDirs + var info goInfo + var rootDirsReady, envReady = make(chan struct{}), make(chan struct{}) + go func() { + info.rootDirs = determineRootDirs(cfg) + close(rootDirsReady) + }() + go func() { + info.env = determineEnv(cfg) + close(envReady) + }() + getGoInfo := func() *goInfo { + <-rootDirsReady + <-envReady + return &info + } + + // always pass getGoInfo to golistDriver + golistDriver := func(cfg *Config, patterns ...string) (*driverResponse, error) { + return golistDriver(cfg, getGoInfo, patterns...) + } + + // Determine files requested in contains patterns + var containFiles []string + var packagesNamed []string + restPatterns := make([]string, 0, len(patterns)) + // Extract file= and other [querytype]= patterns. Report an error if querytype + // doesn't exist. +extractQueries: + for _, pattern := range patterns { + eqidx := strings.Index(pattern, "=") + if eqidx < 0 { + restPatterns = append(restPatterns, pattern) + } else { + query, value := pattern[:eqidx], pattern[eqidx+len("="):] + switch query { + case "file": + containFiles = append(containFiles, value) + case "pattern": + restPatterns = append(restPatterns, value) + case "iamashamedtousethedisabledqueryname": + packagesNamed = append(packagesNamed, value) + case "": // not a reserved query + restPatterns = append(restPatterns, pattern) + default: + for _, rune := range query { + if rune < 'a' || rune > 'z' { // not a reserved query + restPatterns = append(restPatterns, pattern) + continue extractQueries + } + } + // Reject all other patterns containing "=" + return nil, fmt.Errorf("invalid query type %q in query pattern %q", query, pattern) + } + } + } + + response := &responseDeduper{} + var err error + + // See if we have any patterns to pass through to go list. Zero initial + // patterns also requires a go list call, since it's the equivalent of + // ".". + if len(restPatterns) > 0 || len(patterns) == 0 { + dr, err := golistDriver(cfg, restPatterns...) + if err != nil { + return nil, err + } + response.init(dr) + } else { + response.init(&driverResponse{}) + } + + sizeswg.Wait() + if sizeserr != nil { + return nil, sizeserr + } + // types.SizesFor always returns nil or a *types.StdSizes + response.dr.Sizes, _ = sizes.(*types.StdSizes) + + var containsCandidates []string + + if len(containFiles) != 0 { + if err := runContainsQueries(cfg, golistDriver, response, containFiles, getGoInfo); err != nil { + return nil, err + } + } + + if len(packagesNamed) != 0 { + if err := runNamedQueries(cfg, golistDriver, response, packagesNamed); err != nil { + return nil, err + } + } + + modifiedPkgs, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) + if err != nil { + return nil, err + } + if len(containFiles) > 0 { + containsCandidates = append(containsCandidates, modifiedPkgs...) + containsCandidates = append(containsCandidates, needPkgs...) + } + if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs, getGoInfo); err != nil { + return nil, err + } + // Check candidate packages for containFiles. + if len(containFiles) > 0 { + for _, id := range containsCandidates { + pkg, ok := response.seenPackages[id] + if !ok { + response.addPackage(&Package{ + ID: id, + Errors: []Error{ + { + Kind: ListError, + Msg: fmt.Sprintf("package %s expected but not seen", id), + }, + }, + }) + continue + } + for _, f := range containFiles { + for _, g := range pkg.GoFiles { + if sameFile(f, g) { + response.addRoot(id) + } + } + } + } + } + + return response.dr, nil +} + +func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string, getGoInfo func() *goInfo) error { + if len(pkgs) == 0 { + return nil + } + drivercfg := *cfg + if getGoInfo().env.modulesOn { + drivercfg.BuildFlags = append(drivercfg.BuildFlags, "-mod=readonly") + } + dr, err := driver(&drivercfg, pkgs...) + + if err != nil { + return err + } + for _, pkg := range dr.Packages { + response.addPackage(pkg) + } + _, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) + if err != nil { + return err + } + if err := addNeededOverlayPackages(cfg, driver, response, needPkgs, getGoInfo); err != nil { + return err + } + return nil +} + +func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, queries []string, goInfo func() *goInfo) error { + for _, query := range queries { + // TODO(matloob): Do only one query per directory. + fdir := filepath.Dir(query) + // Pass absolute path of directory to go list so that it knows to treat it as a directory, + // not a package path. + pattern, err := filepath.Abs(fdir) + if err != nil { + return fmt.Errorf("could not determine absolute path of file= query path %q: %v", query, err) + } + dirResponse, err := driver(cfg, pattern) + if err != nil || (len(dirResponse.Packages) == 1 && len(dirResponse.Packages[0].Errors) == 1) { + // There was an error loading the package. Try to load the file as an ad-hoc package. + // Usually the error will appear in a returned package, but may not if we're in modules mode + // and the ad-hoc is located outside a module. + var queryErr error + dirResponse, queryErr = driver(cfg, query) + if queryErr != nil { + // Return the original error if the attempt to fall back failed. + return err + } + // Special case to handle issue #33482: + // If this is a file= query for ad-hoc packages where the file only exists on an overlay, + // and exists outside of a module, add the file in for the package. + if len(dirResponse.Packages) == 1 && len(dirResponse.Packages) == 1 && + dirResponse.Packages[0].ID == "command-line-arguments" && len(dirResponse.Packages[0].GoFiles) == 0 { + filename := filepath.Join(pattern, filepath.Base(query)) // avoid recomputing abspath + // TODO(matloob): check if the file is outside of a root dir? + for path := range cfg.Overlay { + if path == filename { + dirResponse.Packages[0].Errors = nil + dirResponse.Packages[0].GoFiles = []string{path} + dirResponse.Packages[0].CompiledGoFiles = []string{path} + } + } + } + } + isRoot := make(map[string]bool, len(dirResponse.Roots)) + for _, root := range dirResponse.Roots { + isRoot[root] = true + } + for _, pkg := range dirResponse.Packages { + // Add any new packages to the main set + // We don't bother to filter packages that will be dropped by the changes of roots, + // that will happen anyway during graph construction outside this function. + // Over-reporting packages is not a problem. + response.addPackage(pkg) + // if the package was not a root one, it cannot have the file + if !isRoot[pkg.ID] { + continue + } + for _, pkgFile := range pkg.GoFiles { + if filepath.Base(query) == filepath.Base(pkgFile) { + response.addRoot(pkg.ID) + break + } + } + } + } + return nil +} + +// modCacheRegexp splits a path in a module cache into module, module version, and package. +var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) + +func runNamedQueries(cfg *Config, driver driver, response *responseDeduper, queries []string) error { + // calling `go env` isn't free; bail out if there's nothing to do. + if len(queries) == 0 { + return nil + } + // Determine which directories are relevant to scan. + roots, modRoot, err := roots(cfg) + if err != nil { + return err + } + + // Scan the selected directories. Simple matches, from GOPATH/GOROOT + // or the local module, can simply be "go list"ed. Matches from the + // module cache need special treatment. + var matchesMu sync.Mutex + var simpleMatches, modCacheMatches []string + add := func(root gopathwalk.Root, dir string) { + // Walk calls this concurrently; protect the result slices. + matchesMu.Lock() + defer matchesMu.Unlock() + + path := dir + if dir != root.Path { + path = dir[len(root.Path)+1:] + } + if pathMatchesQueries(path, queries) { + switch root.Type { + case gopathwalk.RootModuleCache: + modCacheMatches = append(modCacheMatches, path) + case gopathwalk.RootCurrentModule: + // We'd need to read go.mod to find the full + // import path. Relative's easier. + rel, err := filepath.Rel(cfg.Dir, dir) + if err != nil { + // This ought to be impossible, since + // we found dir in the current module. + panic(err) + } + simpleMatches = append(simpleMatches, "./"+rel) + case gopathwalk.RootGOPATH, gopathwalk.RootGOROOT: + simpleMatches = append(simpleMatches, path) + } + } + } + + startWalk := time.Now() + gopathwalk.Walk(roots, add, gopathwalk.Options{ModulesEnabled: modRoot != "", Debug: debug}) + cfg.Logf("%v for walk", time.Since(startWalk)) + + // Weird special case: the top-level package in a module will be in + // whatever directory the user checked the repository out into. It's + // more reasonable for that to not match the package name. So, if there + // are any Go files in the mod root, query it just to be safe. + if modRoot != "" { + rel, err := filepath.Rel(cfg.Dir, modRoot) + if err != nil { + panic(err) // See above. + } + + files, err := ioutil.ReadDir(modRoot) + for _, f := range files { + if strings.HasSuffix(f.Name(), ".go") { + simpleMatches = append(simpleMatches, rel) + break + } + } + } + + addResponse := func(r *driverResponse) { + for _, pkg := range r.Packages { + response.addPackage(pkg) + for _, name := range queries { + if pkg.Name == name { + response.addRoot(pkg.ID) + break + } + } + } + } + + if len(simpleMatches) != 0 { + resp, err := driver(cfg, simpleMatches...) + if err != nil { + return err + } + addResponse(resp) + } + + // Module cache matches are tricky. We want to avoid downloading new + // versions of things, so we need to use the ones present in the cache. + // go list doesn't accept version specifiers, so we have to write out a + // temporary module, and do the list in that module. + if len(modCacheMatches) != 0 { + // Collect all the matches, deduplicating by major version + // and preferring the newest. + type modInfo struct { + mod string + major string + } + mods := make(map[modInfo]string) + var imports []string + for _, modPath := range modCacheMatches { + matches := modCacheRegexp.FindStringSubmatch(modPath) + mod, ver := filepath.ToSlash(matches[1]), matches[2] + importPath := filepath.ToSlash(filepath.Join(matches[1], matches[3])) + + major := semver.Major(ver) + if prevVer, ok := mods[modInfo{mod, major}]; !ok || semver.Compare(ver, prevVer) > 0 { + mods[modInfo{mod, major}] = ver + } + + imports = append(imports, importPath) + } + + // Build the temporary module. + var gomod bytes.Buffer + gomod.WriteString("module modquery\nrequire (\n") + for mod, version := range mods { + gomod.WriteString("\t" + mod.mod + " " + version + "\n") + } + gomod.WriteString(")\n") + + tmpCfg := *cfg + + // We're only trying to look at stuff in the module cache, so + // disable the network. This should speed things up, and has + // prevented errors in at least one case, #28518. + tmpCfg.Env = append(append([]string{"GOPROXY=off"}, cfg.Env...)) + + var err error + tmpCfg.Dir, err = ioutil.TempDir("", "gopackages-modquery") + if err != nil { + return err + } + defer os.RemoveAll(tmpCfg.Dir) + + if err := ioutil.WriteFile(filepath.Join(tmpCfg.Dir, "go.mod"), gomod.Bytes(), 0777); err != nil { + return fmt.Errorf("writing go.mod for module cache query: %v", err) + } + + // Run the query, using the import paths calculated from the matches above. + resp, err := driver(&tmpCfg, imports...) + if err != nil { + return fmt.Errorf("querying module cache matches: %v", err) + } + addResponse(resp) + } + + return nil +} + +func getSizes(cfg *Config) (types.Sizes, error) { + return packagesdriver.GetSizesGolist(cfg.Context, cfg.BuildFlags, cfg.Env, cfg.Dir, usesExportData(cfg)) +} + +// roots selects the appropriate paths to walk based on the passed-in configuration, +// particularly the environment and the presence of a go.mod in cfg.Dir's parents. +func roots(cfg *Config) ([]gopathwalk.Root, string, error) { + stdout, err := invokeGo(cfg, "env", "GOROOT", "GOPATH", "GOMOD") + if err != nil { + return nil, "", err + } + + fields := strings.Split(stdout.String(), "\n") + if len(fields) != 4 || len(fields[3]) != 0 { + return nil, "", fmt.Errorf("go env returned unexpected output: %q", stdout.String()) + } + goroot, gopath, gomod := fields[0], filepath.SplitList(fields[1]), fields[2] + var modDir string + if gomod != "" { + modDir = filepath.Dir(gomod) + } + + var roots []gopathwalk.Root + // Always add GOROOT. + roots = append(roots, gopathwalk.Root{filepath.Join(goroot, "/src"), gopathwalk.RootGOROOT}) + // If modules are enabled, scan the module dir. + if modDir != "" { + roots = append(roots, gopathwalk.Root{modDir, gopathwalk.RootCurrentModule}) + } + // Add either GOPATH/src or GOPATH/pkg/mod, depending on module mode. + for _, p := range gopath { + if modDir != "" { + roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache}) + } else { + roots = append(roots, gopathwalk.Root{filepath.Join(p, "/src"), gopathwalk.RootGOPATH}) + } + } + + return roots, modDir, nil +} + +// These functions were copied from goimports. See further documentation there. + +// pathMatchesQueries is adapted from pkgIsCandidate. +// TODO: is it reasonable to do Contains here, rather than an exact match on a path component? +func pathMatchesQueries(path string, queries []string) bool { + lastTwo := lastTwoComponents(path) + for _, query := range queries { + if strings.Contains(lastTwo, query) { + return true + } + if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(query) { + lastTwo = lowerASCIIAndRemoveHyphen(lastTwo) + if strings.Contains(lastTwo, query) { + return true + } + } + } + return false +} + +// lastTwoComponents returns at most the last two path components +// of v, using either / or \ as the path separator. +func lastTwoComponents(v string) string { + nslash := 0 + for i := len(v) - 1; i >= 0; i-- { + if v[i] == '/' || v[i] == '\\' { + nslash++ + if nslash == 2 { + return v[i:] + } + } + } + return v +} + +func hasHyphenOrUpperASCII(s string) bool { + for i := 0; i < len(s); i++ { + b := s[i] + if b == '-' || ('A' <= b && b <= 'Z') { + return true + } + } + return false +} + +func lowerASCIIAndRemoveHyphen(s string) (ret string) { + buf := make([]byte, 0, len(s)) + for i := 0; i < len(s); i++ { + b := s[i] + switch { + case b == '-': + continue + case 'A' <= b && b <= 'Z': + buf = append(buf, b+('a'-'A')) + default: + buf = append(buf, b) + } + } + return string(buf) +} + +// Fields must match go list; +// see $GOROOT/src/cmd/go/internal/load/pkg.go. +type jsonPackage struct { + ImportPath string + Dir string + Name string + Export string + GoFiles []string + CompiledGoFiles []string + CFiles []string + CgoFiles []string + CXXFiles []string + MFiles []string + HFiles []string + FFiles []string + SFiles []string + SwigFiles []string + SwigCXXFiles []string + SysoFiles []string + Imports []string + ImportMap map[string]string + Deps []string + TestGoFiles []string + TestImports []string + XTestGoFiles []string + XTestImports []string + ForTest string // q in a "p [q.test]" package, else "" + DepOnly bool + + Error *jsonPackageError +} + +type jsonPackageError struct { + ImportStack []string + Pos string + Err string +} + +func otherFiles(p *jsonPackage) [][]string { + return [][]string{p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.SwigFiles, p.SwigCXXFiles, p.SysoFiles} +} + +// golistDriver uses the "go list" command to expand the pattern +// words and return metadata for the specified packages. dir may be +// "" and env may be nil, as per os/exec.Command. +func golistDriver(cfg *Config, rootsDirs func() *goInfo, words ...string) (*driverResponse, error) { + // go list uses the following identifiers in ImportPath and Imports: + // + // "p" -- importable package or main (command) + // "q.test" -- q's test executable + // "p [q.test]" -- variant of p as built for q's test executable + // "q_test [q.test]" -- q's external test package + // + // The packages p that are built differently for a test q.test + // are q itself, plus any helpers used by the external test q_test, + // typically including "testing" and all its dependencies. + + // Run "go list" for complete + // information on the specified packages. + buf, err := invokeGo(cfg, golistargs(cfg, words)...) + if err != nil { + return nil, err + } + seen := make(map[string]*jsonPackage) + // Decode the JSON and convert it to Package form. + var response driverResponse + for dec := json.NewDecoder(buf); dec.More(); { + p := new(jsonPackage) + if err := dec.Decode(p); err != nil { + return nil, fmt.Errorf("JSON decoding failed: %v", err) + } + + if p.ImportPath == "" { + // The documentation for go list says that “[e]rroneous packages will have + // a non-empty ImportPath”. If for some reason it comes back empty, we + // prefer to error out rather than silently discarding data or handing + // back a package without any way to refer to it. + if p.Error != nil { + return nil, Error{ + Pos: p.Error.Pos, + Msg: p.Error.Err, + } + } + return nil, fmt.Errorf("package missing import path: %+v", p) + } + + // Work around https://golang.org/issue/33157: + // go list -e, when given an absolute path, will find the package contained at + // that directory. But when no package exists there, it will return a fake package + // with an error and the ImportPath set to the absolute path provided to go list. + // Try toto convert that absolute path to what its package path would be if it's + // contained in a known module or GOPATH entry. This will allow the package to be + // properly "reclaimed" when overlays are processed. + if filepath.IsAbs(p.ImportPath) && p.Error != nil { + pkgPath, ok := getPkgPath(p.ImportPath, rootsDirs) + if ok { + p.ImportPath = pkgPath + } + } + + if old, found := seen[p.ImportPath]; found { + if !reflect.DeepEqual(p, old) { + return nil, fmt.Errorf("internal error: go list gives conflicting information for package %v", p.ImportPath) + } + // skip the duplicate + continue + } + seen[p.ImportPath] = p + + pkg := &Package{ + Name: p.Name, + ID: p.ImportPath, + GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles), + CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles), + OtherFiles: absJoin(p.Dir, otherFiles(p)...), + } + + // Work around https://golang.org/issue/28749: + // cmd/go puts assembly, C, and C++ files in CompiledGoFiles. + // Filter out any elements of CompiledGoFiles that are also in OtherFiles. + // We have to keep this workaround in place until go1.12 is a distant memory. + if len(pkg.OtherFiles) > 0 { + other := make(map[string]bool, len(pkg.OtherFiles)) + for _, f := range pkg.OtherFiles { + other[f] = true + } + + out := pkg.CompiledGoFiles[:0] + for _, f := range pkg.CompiledGoFiles { + if other[f] { + continue + } + out = append(out, f) + } + pkg.CompiledGoFiles = out + } + + // Extract the PkgPath from the package's ID. + if i := strings.IndexByte(pkg.ID, ' '); i >= 0 { + pkg.PkgPath = pkg.ID[:i] + } else { + pkg.PkgPath = pkg.ID + } + + if pkg.PkgPath == "unsafe" { + pkg.GoFiles = nil // ignore fake unsafe.go file + } + + // Assume go list emits only absolute paths for Dir. + if p.Dir != "" && !filepath.IsAbs(p.Dir) { + log.Fatalf("internal error: go list returned non-absolute Package.Dir: %s", p.Dir) + } + + if p.Export != "" && !filepath.IsAbs(p.Export) { + pkg.ExportFile = filepath.Join(p.Dir, p.Export) + } else { + pkg.ExportFile = p.Export + } + + // imports + // + // Imports contains the IDs of all imported packages. + // ImportsMap records (path, ID) only where they differ. + ids := make(map[string]bool) + for _, id := range p.Imports { + ids[id] = true + } + pkg.Imports = make(map[string]*Package) + for path, id := range p.ImportMap { + pkg.Imports[path] = &Package{ID: id} // non-identity import + delete(ids, id) + } + for id := range ids { + if id == "C" { + continue + } + + pkg.Imports[id] = &Package{ID: id} // identity import + } + if !p.DepOnly { + response.Roots = append(response.Roots, pkg.ID) + } + + // Work around for pre-go.1.11 versions of go list. + // TODO(matloob): they should be handled by the fallback. + // Can we delete this? + if len(pkg.CompiledGoFiles) == 0 { + pkg.CompiledGoFiles = pkg.GoFiles + } + + if p.Error != nil { + pkg.Errors = append(pkg.Errors, Error{ + Pos: p.Error.Pos, + Msg: strings.TrimSpace(p.Error.Err), // Trim to work around golang.org/issue/32363. + }) + } + + response.Packages = append(response.Packages, pkg) + } + + return &response, nil +} + +// getPkgPath finds the package path of a directory if it's relative to a root directory. +func getPkgPath(dir string, goInfo func() *goInfo) (string, bool) { + for rdir, rpath := range goInfo().rootDirs { + // TODO(matloob): This doesn't properly handle symlinks. + r, err := filepath.Rel(rdir, dir) + if err != nil { + continue + } + if rpath != "" { + // We choose only ore root even though the directory even it can belong in multiple modules + // or GOPATH entries. This is okay because we only need to work with absolute dirs when a + // file is missing from disk, for instance when gopls calls go/packages in an overlay. + // Once the file is saved, gopls, or the next invocation of the tool will get the correct + // result straight from golist. + // TODO(matloob): Implement module tiebreaking? + return path.Join(rpath, filepath.ToSlash(r)), true + } + } + return "", false +} + +// absJoin absolutizes and flattens the lists of files. +func absJoin(dir string, fileses ...[]string) (res []string) { + for _, files := range fileses { + for _, file := range files { + if !filepath.IsAbs(file) { + file = filepath.Join(dir, file) + } + res = append(res, file) + } + } + return res +} + +func golistargs(cfg *Config, words []string) []string { + const findFlags = NeedImports | NeedTypes | NeedSyntax | NeedTypesInfo + fullargs := []string{ + "list", "-e", "-json", + fmt.Sprintf("-compiled=%t", cfg.Mode&(NeedCompiledGoFiles|NeedSyntax|NeedTypesInfo|NeedTypesSizes) != 0), + fmt.Sprintf("-test=%t", cfg.Tests), + fmt.Sprintf("-export=%t", usesExportData(cfg)), + fmt.Sprintf("-deps=%t", cfg.Mode&NeedDeps != 0 || + cfg.Mode&NeedTypesInfo != 0), // Dependencies are required to do typechecking on sources, which is required for the TypesInfo. + // go list doesn't let you pass -test and -find together, + // probably because you'd just get the TestMain. + fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0), + } + fullargs = append(fullargs, cfg.BuildFlags...) + fullargs = append(fullargs, "--") + fullargs = append(fullargs, words...) + return fullargs +} + +// invokeGo returns the stdout of a go command invocation. +func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + cmd := exec.CommandContext(cfg.Context, "go", args...) + // On darwin the cwd gets resolved to the real path, which breaks anything that + // expects the working directory to keep the original path, including the + // go command when dealing with modules. + // The Go stdlib has a special feature where if the cwd and the PWD are the + // same node then it trusts the PWD, so by setting it in the env for the child + // process we fix up all the paths returned by the go command. + cmd.Env = append(append([]string{}, cfg.Env...), "PWD="+cfg.Dir) + cmd.Dir = cfg.Dir + cmd.Stdout = stdout + cmd.Stderr = stderr + defer func(start time.Time) { + cfg.Logf("%s for %v, stderr: <<%s>>\n", time.Since(start), cmdDebugStr(cmd, args...), stderr) + }(time.Now()) + + if err := cmd.Run(); err != nil { + // Check for 'go' executable not being found. + if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { + return nil, fmt.Errorf("'go list' driver requires 'go', but %s", exec.ErrNotFound) + } + + exitErr, ok := err.(*exec.ExitError) + if !ok { + // Catastrophic error: + // - context cancellation + return nil, fmt.Errorf("couldn't exec 'go %v': %s %T", args, err, err) + } + + // Old go version? + if strings.Contains(stderr.String(), "flag provided but not defined") { + return nil, goTooOldError{fmt.Errorf("unsupported version of go: %s: %s", exitErr, stderr)} + } + + // Related to #24854 + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "unexpected directory layout") { + return nil, fmt.Errorf("%s", stderr.String()) + } + + // Is there an error running the C compiler in cgo? This will be reported in the "Error" field + // and should be suppressed by go list -e. + // + // This condition is not perfect yet because the error message can include other error messages than runtime/cgo. + if len(stderr.String()) > 0 && strings.HasPrefix(stderr.String(), "# runtime/cgo\n") { + return stdout, nil + } + + // This error only appears in stderr. See golang.org/cl/166398 for a fix in go list to show + // the error in the Err section of stdout in case -e option is provided. + // This fix is provided for backwards compatibility. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must be .go files") { + output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Similar to the previous error, but currently lacks a fix in Go. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must all be in one directory") { + output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Backwards compatibility for Go 1.11 because 1.12 and 1.13 put the directory in the ImportPath. + // If the package doesn't exist, put the absolute path of the directory into the error message, + // as Go 1.13 list does. + const noSuchDirectory = "no such directory" + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), noSuchDirectory) { + errstr := stderr.String() + abspath := strings.TrimSpace(errstr[strings.Index(errstr, noSuchDirectory)+len(noSuchDirectory):]) + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + abspath, strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Workaround for #29280: go list -e has incorrect behavior when an ad-hoc package doesn't exist. + // Note that the error message we look for in this case is different that the one looked for above. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no such file or directory") { + output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Workaround for an instance of golang.org/issue/26755: go list -e will return a non-zero exit + // status if there's a dependency on a package that doesn't exist. But it should return + // a zero exit status and set an error on that package. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") { + // try to extract package name from string + stderrStr := stderr.String() + var importPath string + colon := strings.Index(stderrStr, ":") + if colon > 0 && strings.HasPrefix(stderrStr, "go build ") { + importPath = stderrStr[len("go build "):colon] + } + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + importPath, strings.Trim(stderrStr, "\n")) + return bytes.NewBufferString(output), nil + } + + // Export mode entails a build. + // If that build fails, errors appear on stderr + // (despite the -e flag) and the Export field is blank. + // Do not fail in that case. + // The same is true if an ad-hoc package given to go list doesn't exist. + // TODO(matloob): Remove these once we can depend on go list to exit with a zero status with -e even when + // packages don't exist or a build fails. + if !usesExportData(cfg) && !containsGoFile(args) { + return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr) + } + } + + // As of writing, go list -export prints some non-fatal compilation + // errors to stderr, even with -e set. We would prefer that it put + // them in the Package.Error JSON (see https://golang.org/issue/26319). + // In the meantime, there's nowhere good to put them, but they can + // be useful for debugging. Print them if $GOPACKAGESPRINTGOLISTERRORS + // is set. + if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTGOLISTERRORS") != "" { + fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd, args...), stderr) + } + + // debugging + if false { + fmt.Fprintf(os.Stderr, "%s stdout: <<%s>>\n", cmdDebugStr(cmd, args...), stdout) + } + + return stdout, nil +} + +func containsGoFile(s []string) bool { + for _, f := range s { + if strings.HasSuffix(f, ".go") { + return true + } + } + return false +} + +func cmdDebugStr(cmd *exec.Cmd, args ...string) string { + env := make(map[string]string) + for _, kv := range cmd.Env { + split := strings.Split(kv, "=") + k, v := split[0], split[1] + env[k] = v + } + var quotedArgs []string + for _, arg := range args { + quotedArgs = append(quotedArgs, strconv.Quote(arg)) + } + + return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %s", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], strings.Join(quotedArgs, " ")) +} diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go new file mode 100644 index 0000000000..941b0f47d2 --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -0,0 +1,293 @@ +package packages + +import ( + "bytes" + "encoding/json" + "fmt" + "go/parser" + "go/token" + "path" + "path/filepath" + "strconv" + "strings" +) + +// processGolistOverlay provides rudimentary support for adding +// files that don't exist on disk to an overlay. The results can be +// sometimes incorrect. +// TODO(matloob): Handle unsupported cases, including the following: +// - determining the correct package to add given a new import path +func processGolistOverlay(cfg *Config, response *responseDeduper, rootDirs func() *goInfo) (modifiedPkgs, needPkgs []string, err error) { + havePkgs := make(map[string]string) // importPath -> non-test package ID + needPkgsSet := make(map[string]bool) + modifiedPkgsSet := make(map[string]bool) + + for _, pkg := range response.dr.Packages { + // This is an approximation of import path to id. This can be + // wrong for tests, vendored packages, and a number of other cases. + havePkgs[pkg.PkgPath] = pkg.ID + } + + // If no new imports are added, it is safe to avoid loading any needPkgs. + // Otherwise, it's hard to tell which package is actually being loaded + // (due to vendoring) and whether any modified package will show up + // in the transitive set of dependencies (because new imports are added, + // potentially modifying the transitive set of dependencies). + var overlayAddsImports bool + + for opath, contents := range cfg.Overlay { + base := filepath.Base(opath) + dir := filepath.Dir(opath) + var pkg *Package + var testVariantOf *Package // if opath is a test file, this is the package it is testing + var fileExists bool + isTest := strings.HasSuffix(opath, "_test.go") + pkgName, ok := extractPackageName(opath, contents) + if !ok { + // Don't bother adding a file that doesn't even have a parsable package statement + // to the overlay. + continue + } + nextPackage: + for _, p := range response.dr.Packages { + if pkgName != p.Name && p.ID != "command-line-arguments" { + continue + } + for _, f := range p.GoFiles { + if !sameFile(filepath.Dir(f), dir) { + continue + } + if isTest && !hasTestFiles(p) { + // TODO(matloob): Are there packages other than the 'production' variant + // of a package that this can match? This shouldn't match the test main package + // because the file is generated in another directory. + testVariantOf = p + continue nextPackage + } + pkg = p + if filepath.Base(f) == base { + fileExists = true + } + } + } + // The overlay could have included an entirely new package. + if pkg == nil { + // Try to find the module or gopath dir the file is contained in. + // Then for modules, add the module opath to the beginning. + var pkgPath string + for rdir, rpath := range rootDirs().rootDirs { + // TODO(matloob): This doesn't properly handle symlinks. + r, err := filepath.Rel(rdir, dir) + if err != nil { + continue + } + pkgPath = filepath.ToSlash(r) + if rpath != "" { + pkgPath = path.Join(rpath, pkgPath) + } + // We only create one new package even it can belong in multiple modules or GOPATH entries. + // This is okay because tools (such as the LSP) that use overlays will recompute the overlay + // once the file is saved, and golist will do the right thing. + // TODO(matloob): Implement module tiebreaking? + break + } + if pkgPath == "" { + continue + } + isXTest := strings.HasSuffix(pkgName, "_test") + if isXTest { + pkgPath += "_test" + } + id := pkgPath + if isTest && !isXTest { + id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) + } + // Try to reclaim a package with the same id if it exists in the response. + for _, p := range response.dr.Packages { + if reclaimPackage(p, id, opath, contents) { + pkg = p + break + } + } + // Otherwise, create a new package + if pkg == nil { + pkg = &Package{PkgPath: pkgPath, ID: id, Name: pkgName, Imports: make(map[string]*Package)} + response.addPackage(pkg) + havePkgs[pkg.PkgPath] = id + // Add the production package's sources for a test variant. + if isTest && !isXTest && testVariantOf != nil { + pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) + } + } + } + if !fileExists { + pkg.GoFiles = append(pkg.GoFiles, opath) + // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior + // if the file will be ignored due to its build tags. + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath) + modifiedPkgsSet[pkg.ID] = true + } + imports, err := extractImports(opath, contents) + if err != nil { + // Let the parser or type checker report errors later. + continue + } + for _, imp := range imports { + _, found := pkg.Imports[imp] + if !found { + overlayAddsImports = true + // TODO(matloob): Handle cases when the following block isn't correct. + // These include imports of test variants, imports of vendored packages, etc. + id, ok := havePkgs[imp] + if !ok { + id = imp + } + pkg.Imports[imp] = &Package{ID: id} + } + } + continue + } + + // toPkgPath tries to guess the package path given the id. + // This isn't always correct -- it's certainly wrong for + // vendored packages' paths. + toPkgPath := func(id string) string { + // TODO(matloob): Handle vendor paths. + i := strings.IndexByte(id, ' ') + if i >= 0 { + return id[:i] + } + return id + } + + // Do another pass now that new packages have been created to determine the + // set of missing packages. + for _, pkg := range response.dr.Packages { + for _, imp := range pkg.Imports { + pkgPath := toPkgPath(imp.ID) + if _, ok := havePkgs[pkgPath]; !ok { + needPkgsSet[pkgPath] = true + } + } + } + + if overlayAddsImports { + needPkgs = make([]string, 0, len(needPkgsSet)) + for pkg := range needPkgsSet { + needPkgs = append(needPkgs, pkg) + } + } + modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) + for pkg := range modifiedPkgsSet { + modifiedPkgs = append(modifiedPkgs, pkg) + } + return modifiedPkgs, needPkgs, err +} + +func hasTestFiles(p *Package) bool { + for _, f := range p.GoFiles { + if strings.HasSuffix(f, "_test.go") { + return true + } + } + return false +} + +// determineRootDirs returns a mapping from directories code can be contained in to the +// corresponding import path prefixes of those directories. +// Its result is used to try to determine the import path for a package containing +// an overlay file. +func determineRootDirs(cfg *Config) map[string]string { + // Assume modules first: + out, err := invokeGo(cfg, "list", "-m", "-json", "all") + if err != nil { + return determineRootDirsGOPATH(cfg) + } + m := map[string]string{} + type jsonMod struct{ Path, Dir string } + for dec := json.NewDecoder(out); dec.More(); { + mod := new(jsonMod) + if err := dec.Decode(mod); err != nil { + return m // Give up and return an empty map. Package won't be found for overlay. + } + if mod.Dir != "" && mod.Path != "" { + // This is a valid module; add it to the map. + m[mod.Dir] = mod.Path + } + } + return m +} + +func determineRootDirsGOPATH(cfg *Config) map[string]string { + m := map[string]string{} + out, err := invokeGo(cfg, "env", "GOPATH") + if err != nil { + // Could not determine root dir mapping. Everything is best-effort, so just return an empty map. + // When we try to find the import path for a directory, there will be no root-dir match and + // we'll give up. + return m + } + for _, p := range filepath.SplitList(string(bytes.TrimSpace(out.Bytes()))) { + m[filepath.Join(p, "src")] = "" + } + return m +} + +func extractImports(filename string, contents []byte) ([]string, error) { + f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? + if err != nil { + return nil, err + } + var res []string + for _, imp := range f.Imports { + quotedPath := imp.Path.Value + path, err := strconv.Unquote(quotedPath) + if err != nil { + return nil, err + } + res = append(res, path) + } + return res, nil +} + +// reclaimPackage attempts to reuse a package that failed to load in an overlay. +// +// If the package has errors and has no Name, GoFiles, or Imports, +// then it's possible that it doesn't yet exist on disk. +func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool { + // TODO(rstambler): Check the message of the actual error? + // It differs between $GOPATH and module mode. + if pkg.ID != id { + return false + } + if len(pkg.Errors) != 1 { + return false + } + if pkg.Name != "" || pkg.ExportFile != "" { + return false + } + if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 { + return false + } + if len(pkg.Imports) > 0 { + return false + } + pkgName, ok := extractPackageName(filename, contents) + if !ok { + return false + } + pkg.Name = pkgName + pkg.Errors = nil + return true +} + +func extractPackageName(filename string, contents []byte) (string, bool) { + // TODO(rstambler): Check the message of the actual error? + // It differs between $GOPATH and module mode. + f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset? + if err != nil { + return "", false + } + return f.Name.Name, true +} diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go new file mode 100644 index 0000000000..4ca2b11732 --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -0,0 +1,1100 @@ +// 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 packages + +// See doc.go for package documentation and implementation notes. + +import ( + "context" + "encoding/json" + "fmt" + "go/ast" + "go/parser" + "go/scanner" + "go/token" + "go/types" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + "sync" + + "golang.org/x/tools/go/gcexportdata" +) + +// A LoadMode controls the amount of detail to return when loading. +// The bits below can be combined to specify which fields should be +// filled in the result packages. +// The zero value is a special case, equivalent to combining +// the NeedName, NeedFiles, and NeedCompiledGoFiles bits. +// ID and Errors (if present) will always be filled. +// Load may return more information than requested. +type LoadMode int + +const ( + // NeedName adds Name and PkgPath. + NeedName LoadMode = 1 << iota + + // NeedFiles adds GoFiles and OtherFiles. + NeedFiles + + // NeedCompiledGoFiles adds CompiledGoFiles. + NeedCompiledGoFiles + + // NeedImports adds Imports. If NeedDeps is not set, the Imports field will contain + // "placeholder" Packages with only the ID set. + NeedImports + + // NeedDeps adds the fields requested by the LoadMode in the packages in Imports. If NeedImports + // is not set NeedDeps has no effect. + NeedDeps + + // NeedExportsFile adds ExportsFile. + NeedExportsFile + + // NeedTypes adds Types, Fset, and IllTyped. + NeedTypes + + // NeedSyntax adds Syntax. + NeedSyntax + + // NeedTypesInfo adds TypesInfo. + NeedTypesInfo + + // NeedTypesSizes adds TypesSizes. + NeedTypesSizes +) + +const ( + // Deprecated: LoadFiles exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. + LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles + + // Deprecated: LoadImports exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. + LoadImports = LoadFiles | NeedImports | NeedDeps + + // Deprecated: LoadTypes exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. + LoadTypes = LoadImports | NeedTypes | NeedTypesSizes + + // Deprecated: LoadSyntax exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. + LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo + + // Deprecated: LoadAllSyntax exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. + LoadAllSyntax = LoadSyntax +) + +// A Config specifies details about how packages should be loaded. +// The zero value is a valid configuration. +// Calls to Load do not modify this struct. +type Config struct { + // Mode controls the level of information returned for each package. + Mode LoadMode + + // Context specifies the context for the load operation. + // If the context is cancelled, the loader may stop early + // and return an ErrCancelled error. + // If Context is nil, the load cannot be cancelled. + Context context.Context + + // Logf is the logger for the config. + // If the user provides a logger, debug logging is enabled. + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the logger is nil, default to log.Printf. + Logf func(format string, args ...interface{}) + + // Dir is the directory in which to run the build system's query tool + // that provides information about the packages. + // If Dir is empty, the tool is run in the current directory. + Dir string + + // Env is the environment to use when invoking the build system's query tool. + // If Env is nil, the current environment is used. + // As in os/exec's Cmd, only the last value in the slice for + // each environment key is used. To specify the setting of only + // a few variables, append to the current environment, as in: + // + // opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386") + // + Env []string + + // BuildFlags is a list of command-line flags to be passed through to + // the build system's query tool. + BuildFlags []string + + // Fset provides source position information for syntax trees and types. + // If Fset is nil, Load will use a new fileset, but preserve Fset's value. + Fset *token.FileSet + + // ParseFile is called to read and parse each file + // when preparing a package's type-checked syntax tree. + // It must be safe to call ParseFile simultaneously from multiple goroutines. + // If ParseFile is nil, the loader will uses parser.ParseFile. + // + // ParseFile should parse the source from src and use filename only for + // recording position information. + // + // An application may supply a custom implementation of ParseFile + // to change the effective file contents or the behavior of the parser, + // or to modify the syntax tree. For example, selectively eliminating + // unwanted function bodies can significantly accelerate type checking. + ParseFile func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) + + // If Tests is set, the loader includes not just the packages + // matching a particular pattern but also any related test packages, + // including test-only variants of the package and the test executable. + // + // For example, when using the go command, loading "fmt" with Tests=true + // returns four packages, with IDs "fmt" (the standard package), + // "fmt [fmt.test]" (the package as compiled for the test), + // "fmt_test" (the test functions from source files in package fmt_test), + // and "fmt.test" (the test binary). + // + // In build systems with explicit names for tests, + // setting Tests may have no effect. + Tests bool + + // Overlay provides a mapping of absolute file paths to file contents. + // If the file with the given path already exists, the parser will use the + // alternative file contents provided by the map. + // + // Overlays provide incomplete support for when a given file doesn't + // already exist on disk. See the package doc above for more details. + Overlay map[string][]byte +} + +// driver is the type for functions that query the build system for the +// packages named by the patterns. +type driver func(cfg *Config, patterns ...string) (*driverResponse, error) + +// driverResponse contains the results for a driver query. +type driverResponse struct { + // Sizes, if not nil, is the types.Sizes to use when type checking. + Sizes *types.StdSizes + + // Roots is the set of package IDs that make up the root packages. + // We have to encode this separately because when we encode a single package + // we cannot know if it is one of the roots as that requires knowledge of the + // graph it is part of. + Roots []string `json:",omitempty"` + + // Packages is the full set of packages in the graph. + // The packages are not connected into a graph. + // The Imports if populated will be stubs that only have their ID set. + // Imports will be connected and then type and syntax information added in a + // later pass (see refine). + Packages []*Package +} + +// Load loads and returns the Go packages named by the given patterns. +// +// Config specifies loading options; +// nil behaves the same as an empty Config. +// +// Load returns an error if any of the patterns was invalid +// as defined by the underlying build system. +// It may return an empty list of packages without an error, +// for instance for an empty expansion of a valid wildcard. +// Errors associated with a particular package are recorded in the +// corresponding Package's Errors list, and do not cause Load to +// return an error. Clients may need to handle such errors before +// proceeding with further analysis. The PrintErrors function is +// provided for convenient display of all errors. +func Load(cfg *Config, patterns ...string) ([]*Package, error) { + l := newLoader(cfg) + response, err := defaultDriver(&l.Config, patterns...) + if err != nil { + return nil, err + } + l.sizes = response.Sizes + return l.refine(response.Roots, response.Packages...) +} + +// defaultDriver is a driver that looks for an external driver binary, and if +// it does not find it falls back to the built in go list driver. +func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) { + driver := findExternalDriver(cfg) + if driver == nil { + driver = goListDriver + } + return driver(cfg, patterns...) +} + +// A Package describes a loaded Go package. +type Package struct { + // ID is a unique identifier for a package, + // in a syntax provided by the underlying build system. + // + // Because the syntax varies based on the build system, + // clients should treat IDs as opaque and not attempt to + // interpret them. + ID string + + // Name is the package name as it appears in the package source code. + Name string + + // PkgPath is the package path as used by the go/types package. + PkgPath string + + // Errors contains any errors encountered querying the metadata + // of the package, or while parsing or type-checking its files. + Errors []Error + + // GoFiles lists the absolute file paths of the package's Go source files. + GoFiles []string + + // CompiledGoFiles lists the absolute file paths of the package's source + // files that were presented to the compiler. + // This may differ from GoFiles if files are processed before compilation. + CompiledGoFiles []string + + // OtherFiles lists the absolute file paths of the package's non-Go source files, + // including assembly, C, C++, Fortran, Objective-C, SWIG, and so on. + OtherFiles []string + + // ExportFile is the absolute path to a file containing type + // information for the package as provided by the build system. + ExportFile string + + // Imports maps import paths appearing in the package's Go source files + // to corresponding loaded Packages. + Imports map[string]*Package + + // Types provides type information for the package. + // The NeedTypes LoadMode bit sets this field for packages matching the + // patterns; type information for dependencies may be missing or incomplete, + // unless NeedDeps and NeedImports are also set. + Types *types.Package + + // Fset provides position information for Types, TypesInfo, and Syntax. + // It is set only when Types is set. + Fset *token.FileSet + + // IllTyped indicates whether the package or any dependency contains errors. + // It is set only when Types is set. + IllTyped bool + + // Syntax is the package's syntax trees, for the files listed in CompiledGoFiles. + // + // The NeedSyntax LoadMode bit populates this field for packages matching the patterns. + // If NeedDeps and NeedImports are also set, this field will also be populated + // for dependencies. + Syntax []*ast.File + + // TypesInfo provides type information about the package's syntax trees. + // It is set only when Syntax is set. + TypesInfo *types.Info + + // TypesSizes provides the effective size function for types in TypesInfo. + TypesSizes types.Sizes +} + +// An Error describes a problem with a package's metadata, syntax, or types. +type Error struct { + Pos string // "file:line:col" or "file:line" or "" or "-" + Msg string + Kind ErrorKind +} + +// ErrorKind describes the source of the error, allowing the user to +// differentiate between errors generated by the driver, the parser, or the +// type-checker. +type ErrorKind int + +const ( + UnknownError ErrorKind = iota + ListError + ParseError + TypeError +) + +func (err Error) Error() string { + pos := err.Pos + if pos == "" { + pos = "-" // like token.Position{}.String() + } + return pos + ": " + err.Msg +} + +// flatPackage is the JSON form of Package +// It drops all the type and syntax fields, and transforms the Imports +// +// TODO(adonovan): identify this struct with Package, effectively +// publishing the JSON protocol. +type flatPackage struct { + ID string + Name string `json:",omitempty"` + PkgPath string `json:",omitempty"` + Errors []Error `json:",omitempty"` + GoFiles []string `json:",omitempty"` + CompiledGoFiles []string `json:",omitempty"` + OtherFiles []string `json:",omitempty"` + ExportFile string `json:",omitempty"` + Imports map[string]string `json:",omitempty"` +} + +// MarshalJSON returns the Package in its JSON form. +// For the most part, the structure fields are written out unmodified, and +// the type and syntax fields are skipped. +// The imports are written out as just a map of path to package id. +// The errors are written using a custom type that tries to preserve the +// structure of error types we know about. +// +// This method exists to enable support for additional build systems. It is +// not intended for use by clients of the API and we may change the format. +func (p *Package) MarshalJSON() ([]byte, error) { + flat := &flatPackage{ + ID: p.ID, + Name: p.Name, + PkgPath: p.PkgPath, + Errors: p.Errors, + GoFiles: p.GoFiles, + CompiledGoFiles: p.CompiledGoFiles, + OtherFiles: p.OtherFiles, + ExportFile: p.ExportFile, + } + if len(p.Imports) > 0 { + flat.Imports = make(map[string]string, len(p.Imports)) + for path, ipkg := range p.Imports { + flat.Imports[path] = ipkg.ID + } + } + return json.Marshal(flat) +} + +// UnmarshalJSON reads in a Package from its JSON format. +// See MarshalJSON for details about the format accepted. +func (p *Package) UnmarshalJSON(b []byte) error { + flat := &flatPackage{} + if err := json.Unmarshal(b, &flat); err != nil { + return err + } + *p = Package{ + ID: flat.ID, + Name: flat.Name, + PkgPath: flat.PkgPath, + Errors: flat.Errors, + GoFiles: flat.GoFiles, + CompiledGoFiles: flat.CompiledGoFiles, + OtherFiles: flat.OtherFiles, + ExportFile: flat.ExportFile, + } + if len(flat.Imports) > 0 { + p.Imports = make(map[string]*Package, len(flat.Imports)) + for path, id := range flat.Imports { + p.Imports[path] = &Package{ID: id} + } + } + return nil +} + +func (p *Package) String() string { return p.ID } + +// loaderPackage augments Package with state used during the loading phase +type loaderPackage struct { + *Package + importErrors map[string]error // maps each bad import to its error + loadOnce sync.Once + color uint8 // for cycle detection + needsrc bool // load from source (Mode >= LoadTypes) + needtypes bool // type information is either requested or depended on + initial bool // package was matched by a pattern +} + +// loader holds the working state of a single call to load. +type loader struct { + pkgs map[string]*loaderPackage + Config + sizes types.Sizes + parseCache map[string]*parseValue + parseCacheMu sync.Mutex + exportMu sync.Mutex // enforces mutual exclusion of exportdata operations + + // TODO(matloob): Add an implied mode here and use that instead of mode. + // Implied mode would contain all the fields we need the data for so we can + // get the actually requested fields. We'll zero them out before returning + // packages to the user. This will make it easier for us to get the conditions + // where we need certain modes right. +} + +type parseValue struct { + f *ast.File + err error + ready chan struct{} +} + +func newLoader(cfg *Config) *loader { + ld := &loader{ + parseCache: map[string]*parseValue{}, + } + if cfg != nil { + ld.Config = *cfg + // If the user has provided a logger, use it. + ld.Config.Logf = cfg.Logf + } + if ld.Config.Logf == nil { + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the user has not provided a logger, default to log.Printf. + if debug { + ld.Config.Logf = log.Printf + } else { + ld.Config.Logf = func(format string, args ...interface{}) {} + } + } + if ld.Config.Mode == 0 { + ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility. + } + if ld.Config.Env == nil { + ld.Config.Env = os.Environ() + } + if ld.Context == nil { + ld.Context = context.Background() + } + if ld.Dir == "" { + if dir, err := os.Getwd(); err == nil { + ld.Dir = dir + } + } + + if ld.Mode&NeedTypes != 0 { + if ld.Fset == nil { + ld.Fset = token.NewFileSet() + } + + // ParseFile is required even in LoadTypes mode + // because we load source if export data is missing. + if ld.ParseFile == nil { + ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { + const mode = parser.AllErrors | parser.ParseComments + return parser.ParseFile(fset, filename, src, mode) + } + } + } + return ld +} + +// refine connects the supplied packages into a graph and then adds type and +// and syntax information as requested by the LoadMode. +func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { + rootMap := make(map[string]int, len(roots)) + for i, root := range roots { + rootMap[root] = i + } + ld.pkgs = make(map[string]*loaderPackage) + // first pass, fixup and build the map and roots + var initial = make([]*loaderPackage, len(roots)) + for _, pkg := range list { + rootIndex := -1 + if i, found := rootMap[pkg.ID]; found { + rootIndex = i + } + lpkg := &loaderPackage{ + Package: pkg, + needtypes: (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && rootIndex < 0) || rootIndex >= 0, + needsrc: (ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && ld.Mode&NeedDeps != 0 && rootIndex < 0) || rootIndex >= 0 || + len(ld.Overlay) > 0 || // Overlays can invalidate export data. TODO(matloob): make this check fine-grained based on dependencies on overlaid files + pkg.ExportFile == "" && pkg.PkgPath != "unsafe", + } + ld.pkgs[lpkg.ID] = lpkg + if rootIndex >= 0 { + initial[rootIndex] = lpkg + lpkg.initial = true + } + } + for i, root := range roots { + if initial[i] == nil { + return nil, fmt.Errorf("root package %v is missing", root) + } + } + + // Materialize the import graph. + + const ( + white = 0 // new + grey = 1 // in progress + black = 2 // complete + ) + + // visit traverses the import graph, depth-first, + // and materializes the graph as Packages.Imports. + // + // Valid imports are saved in the Packages.Import map. + // Invalid imports (cycles and missing nodes) are saved in the importErrors map. + // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG. + // + // visit returns whether the package needs src or has a transitive + // dependency on a package that does. These are the only packages + // for which we load source code. + var stack []*loaderPackage + var visit func(lpkg *loaderPackage) bool + var srcPkgs []*loaderPackage + visit = func(lpkg *loaderPackage) bool { + switch lpkg.color { + case black: + return lpkg.needsrc + case grey: + panic("internal error: grey node") + } + lpkg.color = grey + stack = append(stack, lpkg) // push + stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports + // If NeedTypesInfo we need dependencies (at least for the roots) to typecheck the package. + // If NeedImports isn't set, the imports fields will all be zeroed out. + // If NeedDeps isn't also set we want to keep the stubs. + if ld.Mode&NeedTypesInfo != 0 || (ld.Mode&NeedImports != 0 && ld.Mode&NeedDeps != 0) { + lpkg.Imports = make(map[string]*Package, len(stubs)) + for importPath, ipkg := range stubs { + var importErr error + imp := ld.pkgs[ipkg.ID] + if imp == nil { + // (includes package "C" when DisableCgo) + importErr = fmt.Errorf("missing package: %q", ipkg.ID) + } else if imp.color == grey { + importErr = fmt.Errorf("import cycle: %s", stack) + } + if importErr != nil { + if lpkg.importErrors == nil { + lpkg.importErrors = make(map[string]error) + } + lpkg.importErrors[importPath] = importErr + continue + } + + // If !NeedDeps, just fill Imports for the root. No need to recurse further. + if ld.Mode&NeedDeps != 0 { + if visit(imp) { + lpkg.needsrc = true + } + } + lpkg.Imports[importPath] = imp.Package + } + } + if lpkg.needsrc { + srcPkgs = append(srcPkgs, lpkg) + } + if ld.Mode&NeedTypesSizes != 0 { + lpkg.TypesSizes = ld.sizes + } + stack = stack[:len(stack)-1] // pop + lpkg.color = black + + return lpkg.needsrc + } + + if ld.Mode&(NeedImports|NeedDeps|NeedTypesInfo) == 0 { + // We do this to drop the stub import packages that we are not even going to try to resolve. + for _, lpkg := range initial { + lpkg.Imports = nil + } + } else { + // For each initial package, create its import DAG. + for _, lpkg := range initial { + visit(lpkg) + } + } + if ld.Mode&NeedDeps != 0 { // TODO(matloob): This is only the case if NeedTypes is also set, right? + for _, lpkg := range srcPkgs { + // Complete type information is required for the + // immediate dependencies of each source package. + for _, ipkg := range lpkg.Imports { + imp := ld.pkgs[ipkg.ID] + imp.needtypes = true + } + } + } + // Load type data if needed, starting at + // the initial packages (roots of the import DAG). + if ld.Mode&NeedTypes != 0 { + var wg sync.WaitGroup + for _, lpkg := range initial { + wg.Add(1) + go func(lpkg *loaderPackage) { + ld.loadRecursive(lpkg) + wg.Done() + }(lpkg) + } + wg.Wait() + } + + result := make([]*Package, len(initial)) + importPlaceholders := make(map[string]*Package) + for i, lpkg := range initial { + result[i] = lpkg.Package + } + for i := range ld.pkgs { + // Clear all unrequested fields, for extra de-Hyrum-ization. + if ld.Mode&NeedName == 0 { + ld.pkgs[i].Name = "" + ld.pkgs[i].PkgPath = "" + } + if ld.Mode&NeedFiles == 0 { + ld.pkgs[i].GoFiles = nil + ld.pkgs[i].OtherFiles = nil + } + if ld.Mode&NeedCompiledGoFiles == 0 { + ld.pkgs[i].CompiledGoFiles = nil + } + if ld.Mode&NeedImports == 0 { + ld.pkgs[i].Imports = nil + } + if ld.Mode&NeedExportsFile == 0 { + ld.pkgs[i].ExportFile = "" + } + if ld.Mode&NeedTypes == 0 { + ld.pkgs[i].Types = nil + ld.pkgs[i].Fset = nil + ld.pkgs[i].IllTyped = false + } + if ld.Mode&NeedSyntax == 0 { + ld.pkgs[i].Syntax = nil + } + if ld.Mode&NeedTypesInfo == 0 { + ld.pkgs[i].TypesInfo = nil + } + if ld.Mode&NeedTypesSizes == 0 { + ld.pkgs[i].TypesSizes = nil + } + if ld.Mode&NeedDeps == 0 { + for j, pkg := range ld.pkgs[i].Imports { + ph, ok := importPlaceholders[pkg.ID] + if !ok { + ph = &Package{ID: pkg.ID} + importPlaceholders[pkg.ID] = ph + } + ld.pkgs[i].Imports[j] = ph + } + } + } + return result, nil +} + +// loadRecursive loads the specified package and its dependencies, +// recursively, in parallel, in topological order. +// It is atomic and idempotent. +// Precondition: ld.Mode&NeedTypes. +func (ld *loader) loadRecursive(lpkg *loaderPackage) { + lpkg.loadOnce.Do(func() { + // Load the direct dependencies, in parallel. + var wg sync.WaitGroup + for _, ipkg := range lpkg.Imports { + imp := ld.pkgs[ipkg.ID] + wg.Add(1) + go func(imp *loaderPackage) { + ld.loadRecursive(imp) + wg.Done() + }(imp) + } + wg.Wait() + + ld.loadPackage(lpkg) + }) +} + +// loadPackage loads the specified package. +// It must be called only once per Package, +// after immediate dependencies are loaded. +// Precondition: ld.Mode & NeedTypes. +func (ld *loader) loadPackage(lpkg *loaderPackage) { + if lpkg.PkgPath == "unsafe" { + // Fill in the blanks to avoid surprises. + lpkg.Types = types.Unsafe + lpkg.Fset = ld.Fset + lpkg.Syntax = []*ast.File{} + lpkg.TypesInfo = new(types.Info) + lpkg.TypesSizes = ld.sizes + return + } + + // Call NewPackage directly with explicit name. + // This avoids skew between golist and go/types when the files' + // package declarations are inconsistent. + lpkg.Types = types.NewPackage(lpkg.PkgPath, lpkg.Name) + lpkg.Fset = ld.Fset + + // Subtle: we populate all Types fields with an empty Package + // before loading export data so that export data processing + // never has to create a types.Package for an indirect dependency, + // which would then require that such created packages be explicitly + // inserted back into the Import graph as a final step after export data loading. + // The Diamond test exercises this case. + if !lpkg.needtypes { + return + } + if !lpkg.needsrc { + ld.loadFromExportData(lpkg) + return // not a source package, don't get syntax trees + } + + appendError := func(err error) { + // Convert various error types into the one true Error. + var errs []Error + switch err := err.(type) { + case Error: + // from driver + errs = append(errs, err) + + case *os.PathError: + // from parser + errs = append(errs, Error{ + Pos: err.Path + ":1", + Msg: err.Err.Error(), + Kind: ParseError, + }) + + case scanner.ErrorList: + // from parser + for _, err := range err { + errs = append(errs, Error{ + Pos: err.Pos.String(), + Msg: err.Msg, + Kind: ParseError, + }) + } + + case types.Error: + // from type checker + errs = append(errs, Error{ + Pos: err.Fset.Position(err.Pos).String(), + Msg: err.Msg, + Kind: TypeError, + }) + + default: + // unexpected impoverished error from parser? + errs = append(errs, Error{ + Pos: "-", + Msg: err.Error(), + Kind: UnknownError, + }) + + // If you see this error message, please file a bug. + log.Printf("internal error: error %q (%T) without position", err, err) + } + + lpkg.Errors = append(lpkg.Errors, errs...) + } + + files, errs := ld.parseFiles(lpkg.CompiledGoFiles) + for _, err := range errs { + appendError(err) + } + + lpkg.Syntax = files + + lpkg.TypesInfo = &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Scopes: make(map[ast.Node]*types.Scope), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + } + lpkg.TypesSizes = ld.sizes + + importer := importerFunc(func(path string) (*types.Package, error) { + if path == "unsafe" { + return types.Unsafe, nil + } + + // The imports map is keyed by import path. + ipkg := lpkg.Imports[path] + if ipkg == nil { + if err := lpkg.importErrors[path]; err != nil { + return nil, err + } + // There was skew between the metadata and the + // import declarations, likely due to an edit + // race, or because the ParseFile feature was + // used to supply alternative file contents. + return nil, fmt.Errorf("no metadata for %s", path) + } + + if ipkg.Types != nil && ipkg.Types.Complete() { + return ipkg.Types, nil + } + log.Fatalf("internal error: nil Pkg importing %q from %q", path, lpkg) + panic("unreachable") + }) + + // type-check + tc := &types.Config{ + Importer: importer, + + // Type-check bodies of functions only in non-initial packages. + // Example: for import graph A->B->C and initial packages {A,C}, + // we can ignore function bodies in B. + IgnoreFuncBodies: (ld.Mode&(NeedDeps|NeedTypesInfo) == 0) && !lpkg.initial, + + Error: appendError, + Sizes: ld.sizes, + } + types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) + + lpkg.importErrors = nil // no longer needed + + // If !Cgo, the type-checker uses FakeImportC mode, so + // it doesn't invoke the importer for import "C", + // nor report an error for the import, + // or for any undefined C.f reference. + // We must detect this explicitly and correctly + // mark the package as IllTyped (by reporting an error). + // TODO(adonovan): if these errors are annoying, + // we could just set IllTyped quietly. + if tc.FakeImportC { + outer: + for _, f := range lpkg.Syntax { + for _, imp := range f.Imports { + if imp.Path.Value == `"C"` { + err := types.Error{Fset: ld.Fset, Pos: imp.Pos(), Msg: `import "C" ignored`} + appendError(err) + break outer + } + } + } + } + + // Record accumulated errors. + illTyped := len(lpkg.Errors) > 0 + if !illTyped { + for _, imp := range lpkg.Imports { + if imp.IllTyped { + illTyped = true + break + } + } + } + lpkg.IllTyped = illTyped +} + +// An importFunc is an implementation of the single-method +// types.Importer interface based on a function value. +type importerFunc func(path string) (*types.Package, error) + +func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } + +// We use a counting semaphore to limit +// the number of parallel I/O calls per process. +var ioLimit = make(chan bool, 20) + +func (ld *loader) parseFile(filename string) (*ast.File, error) { + ld.parseCacheMu.Lock() + v, ok := ld.parseCache[filename] + if ok { + // cache hit + ld.parseCacheMu.Unlock() + <-v.ready + } else { + // cache miss + v = &parseValue{ready: make(chan struct{})} + ld.parseCache[filename] = v + ld.parseCacheMu.Unlock() + + var src []byte + for f, contents := range ld.Config.Overlay { + if sameFile(f, filename) { + src = contents + } + } + var err error + if src == nil { + ioLimit <- true // wait + src, err = ioutil.ReadFile(filename) + <-ioLimit // signal + } + if err != nil { + v.err = err + } else { + v.f, v.err = ld.ParseFile(ld.Fset, filename, src) + } + + close(v.ready) + } + return v.f, v.err +} + +// parseFiles reads and parses the Go source files and returns the ASTs +// of the ones that could be at least partially parsed, along with a +// list of I/O and parse errors encountered. +// +// Because files are scanned in parallel, the token.Pos +// positions of the resulting ast.Files are not ordered. +// +func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) { + var wg sync.WaitGroup + n := len(filenames) + parsed := make([]*ast.File, n) + errors := make([]error, n) + for i, file := range filenames { + if ld.Config.Context.Err() != nil { + parsed[i] = nil + errors[i] = ld.Config.Context.Err() + continue + } + wg.Add(1) + go func(i int, filename string) { + parsed[i], errors[i] = ld.parseFile(filename) + wg.Done() + }(i, file) + } + wg.Wait() + + // Eliminate nils, preserving order. + var o int + for _, f := range parsed { + if f != nil { + parsed[o] = f + o++ + } + } + parsed = parsed[:o] + + o = 0 + for _, err := range errors { + if err != nil { + errors[o] = err + o++ + } + } + errors = errors[:o] + + return parsed, errors +} + +// sameFile returns true if x and y have the same basename and denote +// the same file. +// +func sameFile(x, y string) bool { + if x == y { + // It could be the case that y doesn't exist. + // For instance, it may be an overlay file that + // hasn't been written to disk. To handle that case + // let x == y through. (We added the exact absolute path + // string to the CompiledGoFiles list, so the unwritten + // overlay case implies x==y.) + return true + } + if strings.EqualFold(filepath.Base(x), filepath.Base(y)) { // (optimisation) + if xi, err := os.Stat(x); err == nil { + if yi, err := os.Stat(y); err == nil { + return os.SameFile(xi, yi) + } + } + } + return false +} + +// loadFromExportData returns type information for the specified +// package, loading it from an export data file on the first request. +func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error) { + if lpkg.PkgPath == "" { + log.Fatalf("internal error: Package %s has no PkgPath", lpkg) + } + + // Because gcexportdata.Read has the potential to create or + // modify the types.Package for each node in the transitive + // closure of dependencies of lpkg, all exportdata operations + // must be sequential. (Finer-grained locking would require + // changes to the gcexportdata API.) + // + // The exportMu lock guards the Package.Pkg field and the + // types.Package it points to, for each Package in the graph. + // + // Not all accesses to Package.Pkg need to be protected by exportMu: + // graph ordering ensures that direct dependencies of source + // packages are fully loaded before the importer reads their Pkg field. + ld.exportMu.Lock() + defer ld.exportMu.Unlock() + + if tpkg := lpkg.Types; tpkg != nil && tpkg.Complete() { + return tpkg, nil // cache hit + } + + lpkg.IllTyped = true // fail safe + + if lpkg.ExportFile == "" { + // Errors while building export data will have been printed to stderr. + return nil, fmt.Errorf("no export data file") + } + f, err := os.Open(lpkg.ExportFile) + if err != nil { + return nil, err + } + defer f.Close() + + // Read gc export data. + // + // We don't currently support gccgo export data because all + // underlying workspaces use the gc toolchain. (Even build + // systems that support gccgo don't use it for workspace + // queries.) + r, err := gcexportdata.NewReader(f) + if err != nil { + return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) + } + + // Build the view. + // + // The gcexportdata machinery has no concept of package ID. + // It identifies packages by their PkgPath, which although not + // globally unique is unique within the scope of one invocation + // of the linker, type-checker, or gcexportdata. + // + // So, we must build a PkgPath-keyed view of the global + // (conceptually ID-keyed) cache of packages and pass it to + // gcexportdata. The view must contain every existing + // package that might possibly be mentioned by the + // current package---its transitive closure. + // + // In loadPackage, we unconditionally create a types.Package for + // each dependency so that export data loading does not + // create new ones. + // + // TODO(adonovan): it would be simpler and more efficient + // if the export data machinery invoked a callback to + // get-or-create a package instead of a map. + // + view := make(map[string]*types.Package) // view seen by gcexportdata + seen := make(map[*loaderPackage]bool) // all visited packages + var visit func(pkgs map[string]*Package) + visit = func(pkgs map[string]*Package) { + for _, p := range pkgs { + lpkg := ld.pkgs[p.ID] + if !seen[lpkg] { + seen[lpkg] = true + view[lpkg.PkgPath] = lpkg.Types + visit(lpkg.Imports) + } + } + } + visit(lpkg.Imports) + + viewLen := len(view) + 1 // adding the self package + // Parse the export data. + // (May modify incomplete packages in view but not create new ones.) + tpkg, err := gcexportdata.Read(r, ld.Fset, view, lpkg.PkgPath) + if err != nil { + return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) + } + if viewLen != len(view) { + log.Fatalf("Unexpected package creation during export data loading") + } + + lpkg.Types = tpkg + lpkg.IllTyped = false + + return tpkg, nil +} + +func usesExportData(cfg *Config) bool { + return cfg.Mode&NeedExportsFile != 0 || + // If NeedTypes but not NeedTypesInfo we won't typecheck using sources, so we need export data. + (cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedTypesInfo == 0) || + // If NeedTypesInfo but not NeedDeps, we're typechecking a package using its sources plus its dependencies' export data + (cfg.Mode&NeedTypesInfo != 0 && cfg.Mode&NeedDeps == 0) +} diff --git a/vendor/golang.org/x/tools/go/packages/visit.go b/vendor/golang.org/x/tools/go/packages/visit.go new file mode 100644 index 0000000000..b13cb081fc --- /dev/null +++ b/vendor/golang.org/x/tools/go/packages/visit.go @@ -0,0 +1,55 @@ +package packages + +import ( + "fmt" + "os" + "sort" +) + +// Visit visits all the packages in the import graph whose roots are +// pkgs, calling the optional pre function the first time each package +// is encountered (preorder), and the optional post function after a +// package's dependencies have been visited (postorder). +// The boolean result of pre(pkg) determines whether +// the imports of package pkg are visited. +func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) { + seen := make(map[*Package]bool) + var visit func(*Package) + visit = func(pkg *Package) { + if !seen[pkg] { + seen[pkg] = true + + if pre == nil || pre(pkg) { + paths := make([]string, 0, len(pkg.Imports)) + for path := range pkg.Imports { + paths = append(paths, path) + } + sort.Strings(paths) // Imports is a map, this makes visit stable + for _, path := range paths { + visit(pkg.Imports[path]) + } + } + + if post != nil { + post(pkg) + } + } + } + for _, pkg := range pkgs { + visit(pkg) + } +} + +// PrintErrors prints to os.Stderr the accumulated errors of all +// packages in the import graph rooted at pkgs, dependencies first. +// PrintErrors returns the number of errors printed. +func PrintErrors(pkgs []*Package) int { + var n int + Visit(pkgs, nil, func(pkg *Package) { + for _, err := range pkg.Errors { + fmt.Fprintln(os.Stderr, err) + n++ + } + }) + return n +} diff --git a/vendor/golang.org/x/tools/imports/forward.go b/vendor/golang.org/x/tools/imports/forward.go new file mode 100644 index 0000000000..eef25969de --- /dev/null +++ b/vendor/golang.org/x/tools/imports/forward.go @@ -0,0 +1,62 @@ +// Package imports implements a Go pretty-printer (like package "go/format") +// that also adds or removes import statements as necessary. +package imports // import "golang.org/x/tools/imports" + +import ( + "go/build" + + intimp "golang.org/x/tools/internal/imports" +) + +// Options specifies options for processing files. +type Options struct { + Fragment bool // Accept fragment of a source file (no package statement) + AllErrors bool // Report all errors (not just the first 10 on different lines) + + Comments bool // Print comments (true if nil *Options provided) + TabIndent bool // Use tabs for indent (true if nil *Options provided) + TabWidth int // Tab width (8 if nil *Options provided) + + FormatOnly bool // Disable the insertion and deletion of imports +} + +// Debug controls verbose logging. +var Debug = false + +// LocalPrefix is a comma-separated string of import path prefixes, which, if +// set, instructs Process to sort the import paths with the given prefixes +// into another group after 3rd-party packages. +var LocalPrefix string + +// Process formats and adjusts imports for the provided file. +// If opt is nil the defaults are used. +// +// Note that filename's directory influences which imports can be chosen, +// so it is important that filename be accurate. +// To process data ``as if'' it were in filename, pass the data as a non-nil src. +func Process(filename string, src []byte, opt *Options) ([]byte, error) { + if opt == nil { + opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} + } + intopt := &intimp.Options{ + Env: &intimp.ProcessEnv{ + GOPATH: build.Default.GOPATH, + GOROOT: build.Default.GOROOT, + Debug: Debug, + LocalPrefix: LocalPrefix, + }, + AllErrors: opt.AllErrors, + Comments: opt.Comments, + FormatOnly: opt.FormatOnly, + Fragment: opt.Fragment, + TabIndent: opt.TabIndent, + TabWidth: opt.TabWidth, + } + return intimp.Process(filename, src, intopt) +} + +// VendorlessPath returns the devendorized version of the import path ipath. +// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b". +func VendorlessPath(ipath string) string { + return intimp.VendorlessPath(ipath) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go new file mode 100644 index 0000000000..7219c8e9ff --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go @@ -0,0 +1,196 @@ +// Copyright 2016 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 fastwalk provides a faster version of filepath.Walk for file system +// scanning tools. +package fastwalk + +import ( + "errors" + "os" + "path/filepath" + "runtime" + "sync" +) + +// TraverseLink is used as a return value from WalkFuncs to indicate that the +// symlink named in the call may be traversed. +var TraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") + +// SkipFiles is a used as a return value from WalkFuncs to indicate that the +// callback should not be called for any other files in the current directory. +// Child directories will still be traversed. +var SkipFiles = errors.New("fastwalk: skip remaining files in directory") + +// Walk is a faster implementation of filepath.Walk. +// +// filepath.Walk's design necessarily calls os.Lstat on each file, +// even if the caller needs less info. +// Many tools need only the type of each file. +// On some platforms, this information is provided directly by the readdir +// system call, avoiding the need to stat each file individually. +// fastwalk_unix.go contains a fork of the syscall routines. +// +// See golang.org/issue/16399 +// +// Walk walks the file tree rooted at root, calling walkFn for +// each file or directory in the tree, including root. +// +// If fastWalk returns filepath.SkipDir, the directory is skipped. +// +// Unlike filepath.Walk: +// * file stat calls must be done by the user. +// The only provided metadata is the file type, which does not include +// any permission bits. +// * multiple goroutines stat the filesystem concurrently. The provided +// walkFn must be safe for concurrent use. +// * fastWalk can follow symlinks if walkFn returns the TraverseLink +// sentinel error. It is the walkFn's responsibility to prevent +// fastWalk from going into symlink cycles. +func Walk(root string, walkFn func(path string, typ os.FileMode) error) error { + // TODO(bradfitz): make numWorkers configurable? We used a + // minimum of 4 to give the kernel more info about multiple + // things we want, in hopes its I/O scheduling can take + // advantage of that. Hopefully most are in cache. Maybe 4 is + // even too low of a minimum. Profile more. + numWorkers := 4 + if n := runtime.NumCPU(); n > numWorkers { + numWorkers = n + } + + // Make sure to wait for all workers to finish, otherwise + // walkFn could still be called after returning. This Wait call + // runs after close(e.donec) below. + var wg sync.WaitGroup + defer wg.Wait() + + w := &walker{ + fn: walkFn, + enqueuec: make(chan walkItem, numWorkers), // buffered for performance + workc: make(chan walkItem, numWorkers), // buffered for performance + donec: make(chan struct{}), + + // buffered for correctness & not leaking goroutines: + resc: make(chan error, numWorkers), + } + defer close(w.donec) + + for i := 0; i < numWorkers; i++ { + wg.Add(1) + go w.doWork(&wg) + } + todo := []walkItem{{dir: root}} + out := 0 + for { + workc := w.workc + var workItem walkItem + if len(todo) == 0 { + workc = nil + } else { + workItem = todo[len(todo)-1] + } + select { + case workc <- workItem: + todo = todo[:len(todo)-1] + out++ + case it := <-w.enqueuec: + todo = append(todo, it) + case err := <-w.resc: + out-- + if err != nil { + return err + } + if out == 0 && len(todo) == 0 { + // It's safe to quit here, as long as the buffered + // enqueue channel isn't also readable, which might + // happen if the worker sends both another unit of + // work and its result before the other select was + // scheduled and both w.resc and w.enqueuec were + // readable. + select { + case it := <-w.enqueuec: + todo = append(todo, it) + default: + return nil + } + } + } + } +} + +// doWork reads directories as instructed (via workc) and runs the +// user's callback function. +func (w *walker) doWork(wg *sync.WaitGroup) { + defer wg.Done() + for { + select { + case <-w.donec: + return + case it := <-w.workc: + select { + case <-w.donec: + return + case w.resc <- w.walk(it.dir, !it.callbackDone): + } + } + } +} + +type walker struct { + fn func(path string, typ os.FileMode) error + + donec chan struct{} // closed on fastWalk's return + workc chan walkItem // to workers + enqueuec chan walkItem // from workers + resc chan error // from workers +} + +type walkItem struct { + dir string + callbackDone bool // callback already called; don't do it again +} + +func (w *walker) enqueue(it walkItem) { + select { + case w.enqueuec <- it: + case <-w.donec: + } +} + +func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { + joined := dirName + string(os.PathSeparator) + baseName + if typ == os.ModeDir { + w.enqueue(walkItem{dir: joined}) + return nil + } + + err := w.fn(joined, typ) + if typ == os.ModeSymlink { + if err == TraverseLink { + // Set callbackDone so we don't call it twice for both the + // symlink-as-symlink and the symlink-as-directory later: + w.enqueue(walkItem{dir: joined, callbackDone: true}) + return nil + } + if err == filepath.SkipDir { + // Permit SkipDir on symlinks too. + return nil + } + } + return err +} + +func (w *walker) walk(root string, runUserCallback bool) error { + if runUserCallback { + err := w.fn(root, os.ModeDir) + if err == filepath.SkipDir { + return nil + } + if err != nil { + return err + } + } + + return readDir(root, w.onDirEnt) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go new file mode 100644 index 0000000000..ccffec5adc --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go @@ -0,0 +1,13 @@ +// Copyright 2016 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. + +// +build freebsd openbsd netbsd + +package fastwalk + +import "syscall" + +func direntInode(dirent *syscall.Dirent) uint64 { + return uint64(dirent.Fileno) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go new file mode 100644 index 0000000000..ab7fbc0a9a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go @@ -0,0 +1,14 @@ +// Copyright 2016 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. + +// +build linux darwin +// +build !appengine + +package fastwalk + +import "syscall" + +func direntInode(dirent *syscall.Dirent) uint64 { + return uint64(dirent.Ino) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go new file mode 100644 index 0000000000..a3b26a7bae --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go @@ -0,0 +1,13 @@ +// 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. + +// +build darwin freebsd openbsd netbsd + +package fastwalk + +import "syscall" + +func direntNamlen(dirent *syscall.Dirent) uint64 { + return uint64(dirent.Namlen) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go new file mode 100644 index 0000000000..e880d358b1 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go @@ -0,0 +1,29 @@ +// 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. + +// +build linux +// +build !appengine + +package fastwalk + +import ( + "bytes" + "syscall" + "unsafe" +) + +func direntNamlen(dirent *syscall.Dirent) uint64 { + const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) + nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) + const nameBufLen = uint16(len(nameBuf)) + limit := dirent.Reclen - fixedHdr + if limit > nameBufLen { + limit = nameBufLen + } + nameLen := bytes.IndexByte(nameBuf[:limit], 0) + if nameLen < 0 { + panic("failed to find terminating 0 byte in dirent") + } + return uint64(nameLen) +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go new file mode 100644 index 0000000000..a906b87595 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go @@ -0,0 +1,37 @@ +// Copyright 2016 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. + +// +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd + +package fastwalk + +import ( + "io/ioutil" + "os" +) + +// readDir calls fn for each directory entry in dirName. +// It does not descend into directories or follow symlinks. +// If fn returns a non-nil error, readDir returns with that error +// immediately. +func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { + fis, err := ioutil.ReadDir(dirName) + if err != nil { + return err + } + skipFiles := false + for _, fi := range fis { + if fi.Mode().IsRegular() && skipFiles { + continue + } + if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { + if err == SkipFiles { + skipFiles = true + continue + } + return err + } + } + return nil +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go new file mode 100644 index 0000000000..3369b1a0b2 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go @@ -0,0 +1,127 @@ +// Copyright 2016 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. + +// +build linux darwin freebsd openbsd netbsd +// +build !appengine + +package fastwalk + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +const blockSize = 8 << 10 + +// unknownFileMode is a sentinel (and bogus) os.FileMode +// value used to represent a syscall.DT_UNKNOWN Dirent.Type. +const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice + +func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { + fd, err := syscall.Open(dirName, 0, 0) + if err != nil { + return &os.PathError{Op: "open", Path: dirName, Err: err} + } + defer syscall.Close(fd) + + // The buffer must be at least a block long. + buf := make([]byte, blockSize) // stack-allocated; doesn't escape + bufp := 0 // starting read position in buf + nbuf := 0 // end valid data in buf + skipFiles := false + for { + if bufp >= nbuf { + bufp = 0 + nbuf, err = syscall.ReadDirent(fd, buf) + if err != nil { + return os.NewSyscallError("readdirent", err) + } + if nbuf <= 0 { + return nil + } + } + consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) + bufp += consumed + if name == "" || name == "." || name == ".." { + continue + } + // Fallback for filesystems (like old XFS) that don't + // support Dirent.Type and have DT_UNKNOWN (0) there + // instead. + if typ == unknownFileMode { + fi, err := os.Lstat(dirName + "/" + name) + if err != nil { + // It got deleted in the meantime. + if os.IsNotExist(err) { + continue + } + return err + } + typ = fi.Mode() & os.ModeType + } + if skipFiles && typ.IsRegular() { + continue + } + if err := fn(dirName, name, typ); err != nil { + if err == SkipFiles { + skipFiles = true + continue + } + return err + } + } +} + +func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { + // golang.org/issue/15653 + dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0])) + if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { + panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) + } + if len(buf) < int(dirent.Reclen) { + panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) + } + consumed = int(dirent.Reclen) + if direntInode(dirent) == 0 { // File absent in directory. + return + } + switch dirent.Type { + case syscall.DT_REG: + typ = 0 + case syscall.DT_DIR: + typ = os.ModeDir + case syscall.DT_LNK: + typ = os.ModeSymlink + case syscall.DT_BLK: + typ = os.ModeDevice + case syscall.DT_FIFO: + typ = os.ModeNamedPipe + case syscall.DT_SOCK: + typ = os.ModeSocket + case syscall.DT_UNKNOWN: + typ = unknownFileMode + default: + // Skip weird things. + // It's probably a DT_WHT (http://lwn.net/Articles/325369/) + // or something. Revisit if/when this package is moved outside + // of goimports. goimports only cares about regular files, + // symlinks, and directories. + return + } + + nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) + nameLen := direntNamlen(dirent) + + // Special cases for common things: + if nameLen == 1 && nameBuf[0] == '.' { + name = "." + } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { + name = ".." + } else { + name = string(nameBuf[:nameLen]) + } + return +} diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go new file mode 100644 index 0000000000..60eb67b697 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -0,0 +1,268 @@ +// 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 gopathwalk is like filepath.Walk but specialized for finding Go +// packages, particularly in $GOPATH and $GOROOT. +package gopathwalk + +import ( + "bufio" + "bytes" + "fmt" + "go/build" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + "golang.org/x/tools/internal/fastwalk" +) + +// Options controls the behavior of a Walk call. +type Options struct { + Debug bool // Enable debug logging + ModulesEnabled bool // Search module caches. Also disables legacy goimports ignore rules. +} + +// RootType indicates the type of a Root. +type RootType int + +const ( + RootUnknown RootType = iota + RootGOROOT + RootGOPATH + RootCurrentModule + RootModuleCache + RootOther +) + +// A Root is a starting point for a Walk. +type Root struct { + Path string + Type RootType +} + +// SrcDirsRoots returns the roots from build.Default.SrcDirs(). Not modules-compatible. +func SrcDirsRoots(ctx *build.Context) []Root { + var roots []Root + roots = append(roots, Root{filepath.Join(ctx.GOROOT, "src"), RootGOROOT}) + for _, p := range filepath.SplitList(ctx.GOPATH) { + roots = append(roots, Root{filepath.Join(p, "src"), RootGOPATH}) + } + return roots +} + +// Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. +// For each package found, add will be called (concurrently) with the absolute +// paths of the containing source directory and the package directory. +// add will be called concurrently. +func Walk(roots []Root, add func(root Root, dir string), opts Options) { + WalkSkip(roots, add, func(Root, string) bool { return false }, opts) +} + +// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. +// For each package found, add will be called (concurrently) with the absolute +// paths of the containing source directory and the package directory. +// For each directory that will be scanned, skip will be called (concurrently) +// with the absolute paths of the containing source directory and the directory. +// If skip returns false on a directory it will be processed. +// add will be called concurrently. +// skip will be called concurrently. +func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { + for _, root := range roots { + walkDir(root, add, skip, opts) + } +} + +func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) { + if _, err := os.Stat(root.Path); os.IsNotExist(err) { + if opts.Debug { + log.Printf("skipping nonexistent directory: %v", root.Path) + } + return + } + if opts.Debug { + log.Printf("scanning %s", root.Path) + } + w := &walker{ + root: root, + add: add, + skip: skip, + opts: opts, + } + w.init() + if err := fastwalk.Walk(root.Path, w.walk); err != nil { + log.Printf("gopathwalk: scanning directory %v: %v", root.Path, err) + } + + if opts.Debug { + log.Printf("scanned %s", root.Path) + } +} + +// walker is the callback for fastwalk.Walk. +type walker struct { + root Root // The source directory to scan. + add func(Root, string) // The callback that will be invoked for every possible Go package dir. + skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. + opts Options // Options passed to Walk by the user. + + ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. +} + +// init initializes the walker based on its Options. +func (w *walker) init() { + var ignoredPaths []string + if w.root.Type == RootModuleCache { + ignoredPaths = []string{"cache"} + } + if !w.opts.ModulesEnabled && w.root.Type == RootGOPATH { + ignoredPaths = w.getIgnoredDirs(w.root.Path) + ignoredPaths = append(ignoredPaths, "v", "mod") + } + + for _, p := range ignoredPaths { + full := filepath.Join(w.root.Path, p) + if fi, err := os.Stat(full); err == nil { + w.ignoredDirs = append(w.ignoredDirs, fi) + if w.opts.Debug { + log.Printf("Directory added to ignore list: %s", full) + } + } else if w.opts.Debug { + log.Printf("Error statting ignored directory: %v", err) + } + } +} + +// getIgnoredDirs reads an optional config file at /.goimportsignore +// of relative directories to ignore when scanning for go files. +// The provided path is one of the $GOPATH entries with "src" appended. +func (w *walker) getIgnoredDirs(path string) []string { + file := filepath.Join(path, ".goimportsignore") + slurp, err := ioutil.ReadFile(file) + if w.opts.Debug { + if err != nil { + log.Print(err) + } else { + log.Printf("Read %s", file) + } + } + if err != nil { + return nil + } + + var ignoredDirs []string + bs := bufio.NewScanner(bytes.NewReader(slurp)) + for bs.Scan() { + line := strings.TrimSpace(bs.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + ignoredDirs = append(ignoredDirs, line) + } + return ignoredDirs +} + +func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { + for _, ignoredDir := range w.ignoredDirs { + if os.SameFile(fi, ignoredDir) { + return true + } + } + if w.skip != nil { + // Check with the user specified callback. + return w.skip(w.root, dir) + } + return false +} + +func (w *walker) walk(path string, typ os.FileMode) error { + dir := filepath.Dir(path) + if typ.IsRegular() { + if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) { + // Doesn't make sense to have regular files + // directly in your $GOPATH/src or $GOROOT/src. + return fastwalk.SkipFiles + } + if !strings.HasSuffix(path, ".go") { + return nil + } + + w.add(w.root, dir) + return fastwalk.SkipFiles + } + if typ == os.ModeDir { + base := filepath.Base(path) + if base == "" || base[0] == '.' || base[0] == '_' || + base == "testdata" || + (w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") || + (!w.opts.ModulesEnabled && base == "node_modules") { + return filepath.SkipDir + } + fi, err := os.Lstat(path) + if err == nil && w.shouldSkipDir(fi, path) { + return filepath.SkipDir + } + return nil + } + if typ == os.ModeSymlink { + base := filepath.Base(path) + if strings.HasPrefix(base, ".#") { + // Emacs noise. + return nil + } + fi, err := os.Lstat(path) + if err != nil { + // Just ignore it. + return nil + } + if w.shouldTraverse(dir, fi) { + return fastwalk.TraverseLink + } + } + return nil +} + +// shouldTraverse reports whether the symlink fi, found in dir, +// should be followed. It makes sure symlinks were never visited +// before to avoid symlink loops. +func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool { + path := filepath.Join(dir, fi.Name()) + target, err := filepath.EvalSymlinks(path) + if err != nil { + return false + } + ts, err := os.Stat(target) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return false + } + if !ts.IsDir() { + return false + } + if w.shouldSkipDir(ts, dir) { + return false + } + // Check for symlink loops by statting each directory component + // and seeing if any are the same file as ts. + for { + parent := filepath.Dir(path) + if parent == path { + // Made it to the root without seeing a cycle. + // Use this symlink. + return true + } + parentInfo, err := os.Stat(parent) + if err != nil { + return false + } + if os.SameFile(ts, parentInfo) { + // Cycle. Don't traverse. + return false + } + path = parent + } + +} diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go new file mode 100644 index 0000000000..bcfbb07ed8 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -0,0 +1,1385 @@ +// Copyright 2013 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 imports + +import ( + "bytes" + "context" + "fmt" + "go/ast" + "go/build" + "go/parser" + "go/token" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" + "unicode" + "unicode/utf8" + + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/go/packages" + "golang.org/x/tools/internal/gopathwalk" +) + +// importToGroup is a list of functions which map from an import path to +// a group number. +var importToGroup = []func(env *ProcessEnv, importPath string) (num int, ok bool){ + func(env *ProcessEnv, importPath string) (num int, ok bool) { + if env.LocalPrefix == "" { + return + } + for _, p := range strings.Split(env.LocalPrefix, ",") { + if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath { + return 3, true + } + } + return + }, + func(_ *ProcessEnv, importPath string) (num int, ok bool) { + if strings.HasPrefix(importPath, "appengine") { + return 2, true + } + return + }, + func(_ *ProcessEnv, importPath string) (num int, ok bool) { + if strings.Contains(importPath, ".") { + return 1, true + } + return + }, +} + +func importGroup(env *ProcessEnv, importPath string) int { + for _, fn := range importToGroup { + if n, ok := fn(env, importPath); ok { + return n + } + } + return 0 +} + +type ImportFixType int + +const ( + AddImport ImportFixType = iota + DeleteImport + SetImportName +) + +type ImportFix struct { + // StmtInfo represents the import statement this fix will add, remove, or change. + StmtInfo ImportInfo + // IdentName is the identifier that this fix will add or remove. + IdentName string + // FixType is the type of fix this is (AddImport, DeleteImport, SetImportName). + FixType ImportFixType +} + +// An ImportInfo represents a single import statement. +type ImportInfo struct { + ImportPath string // import path, e.g. "crypto/rand". + Name string // import name, e.g. "crand", or "" if none. +} + +// A packageInfo represents what's known about a package. +type packageInfo struct { + name string // real package name, if known. + exports map[string]bool // known exports. +} + +// parseOtherFiles parses all the Go files in srcDir except filename, including +// test files if filename looks like a test. +func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File { + // This could use go/packages but it doesn't buy much, and it fails + // with https://golang.org/issue/26296 in LoadFiles mode in some cases. + considerTests := strings.HasSuffix(filename, "_test.go") + + fileBase := filepath.Base(filename) + packageFileInfos, err := ioutil.ReadDir(srcDir) + if err != nil { + return nil + } + + var files []*ast.File + for _, fi := range packageFileInfos { + if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") { + continue + } + if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") { + continue + } + + f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, 0) + if err != nil { + continue + } + + files = append(files, f) + } + + return files +} + +// addGlobals puts the names of package vars into the provided map. +func addGlobals(f *ast.File, globals map[string]bool) { + for _, decl := range f.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + + for _, spec := range genDecl.Specs { + valueSpec, ok := spec.(*ast.ValueSpec) + if !ok { + continue + } + globals[valueSpec.Names[0].Name] = true + } + } +} + +// collectReferences builds a map of selector expressions, from +// left hand side (X) to a set of right hand sides (Sel). +func collectReferences(f *ast.File) references { + refs := references{} + + var visitor visitFn + visitor = func(node ast.Node) ast.Visitor { + if node == nil { + return visitor + } + switch v := node.(type) { + case *ast.SelectorExpr: + xident, ok := v.X.(*ast.Ident) + if !ok { + break + } + if xident.Obj != nil { + // If the parser can resolve it, it's not a package ref. + break + } + if !ast.IsExported(v.Sel.Name) { + // Whatever this is, it's not exported from a package. + break + } + pkgName := xident.Name + r := refs[pkgName] + if r == nil { + r = make(map[string]bool) + refs[pkgName] = r + } + r[v.Sel.Name] = true + } + return visitor + } + ast.Walk(visitor, f) + return refs +} + +// collectImports returns all the imports in f. +// Unnamed imports (., _) and "C" are ignored. +func collectImports(f *ast.File) []*ImportInfo { + var imports []*ImportInfo + for _, imp := range f.Imports { + var name string + if imp.Name != nil { + name = imp.Name.Name + } + if imp.Path.Value == `"C"` || name == "_" || name == "." { + continue + } + path := strings.Trim(imp.Path.Value, `"`) + imports = append(imports, &ImportInfo{ + Name: name, + ImportPath: path, + }) + } + return imports +} + +// findMissingImport searches pass's candidates for an import that provides +// pkg, containing all of syms. +func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { + for _, candidate := range p.candidates { + pkgInfo, ok := p.knownPackages[candidate.ImportPath] + if !ok { + continue + } + if p.importIdentifier(candidate) != pkg { + continue + } + + allFound := true + for right := range syms { + if !pkgInfo.exports[right] { + allFound = false + break + } + } + + if allFound { + return candidate + } + } + return nil +} + +// references is set of references found in a Go file. The first map key is the +// left hand side of a selector expression, the second key is the right hand +// side, and the value should always be true. +type references map[string]map[string]bool + +// A pass contains all the inputs and state necessary to fix a file's imports. +// It can be modified in some ways during use; see comments below. +type pass struct { + // Inputs. These must be set before a call to load, and not modified after. + fset *token.FileSet // fset used to parse f and its siblings. + f *ast.File // the file being fixed. + srcDir string // the directory containing f. + env *ProcessEnv // the environment to use for go commands, etc. + loadRealPackageNames bool // if true, load package names from disk rather than guessing them. + otherFiles []*ast.File // sibling files. + + // Intermediate state, generated by load. + existingImports map[string]*ImportInfo + allRefs references + missingRefs references + + // Inputs to fix. These can be augmented between successive fix calls. + lastTry bool // indicates that this is the last call and fix should clean up as best it can. + candidates []*ImportInfo // candidate imports in priority order. + knownPackages map[string]*packageInfo // information about all known packages. +} + +// loadPackageNames saves the package names for everything referenced by imports. +func (p *pass) loadPackageNames(imports []*ImportInfo) error { + if p.env.Debug { + p.env.Logf("loading package names for %v packages", len(imports)) + defer func() { + p.env.Logf("done loading package names for %v packages", len(imports)) + }() + } + var unknown []string + for _, imp := range imports { + if _, ok := p.knownPackages[imp.ImportPath]; ok { + continue + } + unknown = append(unknown, imp.ImportPath) + } + + names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir) + if err != nil { + return err + } + + for path, name := range names { + p.knownPackages[path] = &packageInfo{ + name: name, + exports: map[string]bool{}, + } + } + return nil +} + +// importIdentifier returns the identifier that imp will introduce. It will +// guess if the package name has not been loaded, e.g. because the source +// is not available. +func (p *pass) importIdentifier(imp *ImportInfo) string { + if imp.Name != "" { + return imp.Name + } + known := p.knownPackages[imp.ImportPath] + if known != nil && known.name != "" { + return known.name + } + return importPathToAssumedName(imp.ImportPath) +} + +// load reads in everything necessary to run a pass, and reports whether the +// file already has all the imports it needs. It fills in p.missingRefs with the +// file's missing symbols, if any, or removes unused imports if not. +func (p *pass) load() ([]*ImportFix, bool) { + p.knownPackages = map[string]*packageInfo{} + p.missingRefs = references{} + p.existingImports = map[string]*ImportInfo{} + + // Load basic information about the file in question. + p.allRefs = collectReferences(p.f) + + // Load stuff from other files in the same package: + // global variables so we know they don't need resolving, and imports + // that we might want to mimic. + globals := map[string]bool{} + for _, otherFile := range p.otherFiles { + // Don't load globals from files that are in the same directory + // but a different package. Using them to suggest imports is OK. + if p.f.Name.Name == otherFile.Name.Name { + addGlobals(otherFile, globals) + } + p.candidates = append(p.candidates, collectImports(otherFile)...) + } + + // Resolve all the import paths we've seen to package names, and store + // f's imports by the identifier they introduce. + imports := collectImports(p.f) + if p.loadRealPackageNames { + err := p.loadPackageNames(append(imports, p.candidates...)) + if err != nil { + if p.env.Debug { + p.env.Logf("loading package names: %v", err) + } + return nil, false + } + } + for _, imp := range imports { + p.existingImports[p.importIdentifier(imp)] = imp + } + + // Find missing references. + for left, rights := range p.allRefs { + if globals[left] { + continue + } + _, ok := p.existingImports[left] + if !ok { + p.missingRefs[left] = rights + continue + } + } + if len(p.missingRefs) != 0 { + return nil, false + } + + return p.fix() +} + +// fix attempts to satisfy missing imports using p.candidates. If it finds +// everything, or if p.lastTry is true, it updates fixes to add the imports it found, +// delete anything unused, and update import names, and returns true. +func (p *pass) fix() ([]*ImportFix, bool) { + // Find missing imports. + var selected []*ImportInfo + for left, rights := range p.missingRefs { + if imp := p.findMissingImport(left, rights); imp != nil { + selected = append(selected, imp) + } + } + + if !p.lastTry && len(selected) != len(p.missingRefs) { + return nil, false + } + + // Found everything, or giving up. Add the new imports and remove any unused. + var fixes []*ImportFix + for _, imp := range p.existingImports { + // We deliberately ignore globals here, because we can't be sure + // they're in the same package. People do things like put multiple + // main packages in the same directory, and we don't want to + // remove imports if they happen to have the same name as a var in + // a different package. + if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { + fixes = append(fixes, &ImportFix{ + StmtInfo: *imp, + IdentName: p.importIdentifier(imp), + FixType: DeleteImport, + }) + continue + } + + // An existing import may need to update its import name to be correct. + if name := p.importSpecName(imp); name != imp.Name { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: name, + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: SetImportName, + }) + } + } + + for _, imp := range selected { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: p.importSpecName(imp), + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: AddImport, + }) + } + + return fixes, true +} + +// importSpecName gets the import name of imp in the import spec. +// +// When the import identifier matches the assumed import name, the import name does +// not appear in the import spec. +func (p *pass) importSpecName(imp *ImportInfo) string { + // If we did not load the real package names, or the name is already set, + // we just return the existing name. + if !p.loadRealPackageNames || imp.Name != "" { + return imp.Name + } + + ident := p.importIdentifier(imp) + if ident == importPathToAssumedName(imp.ImportPath) { + return "" // ident not needed since the assumed and real names are the same. + } + return ident +} + +// apply will perform the fixes on f in order. +func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) { + for _, fix := range fixes { + switch fix.FixType { + case DeleteImport: + astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case AddImport: + astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case SetImportName: + // Find the matching import path and change the name. + for _, spec := range f.Imports { + path := strings.Trim(spec.Path.Value, `"`) + if path == fix.StmtInfo.ImportPath { + spec.Name = &ast.Ident{ + Name: fix.StmtInfo.Name, + NamePos: spec.Pos(), + } + } + } + } + } +} + +// assumeSiblingImportsValid assumes that siblings' use of packages is valid, +// adding the exports they use. +func (p *pass) assumeSiblingImportsValid() { + for _, f := range p.otherFiles { + refs := collectReferences(f) + imports := collectImports(f) + importsByName := map[string]*ImportInfo{} + for _, imp := range imports { + importsByName[p.importIdentifier(imp)] = imp + } + for left, rights := range refs { + if imp, ok := importsByName[left]; ok { + if _, ok := stdlib[imp.ImportPath]; ok { + // We have the stdlib in memory; no need to guess. + rights = stdlib[imp.ImportPath] + } + p.addCandidate(imp, &packageInfo{ + // no name; we already know it. + exports: rights, + }) + } + } + } +} + +// addCandidate adds a candidate import to p, and merges in the information +// in pkg. +func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { + p.candidates = append(p.candidates, imp) + if existing, ok := p.knownPackages[imp.ImportPath]; ok { + if existing.name == "" { + existing.name = pkg.name + } + for export := range pkg.exports { + existing.exports[export] = true + } + } else { + p.knownPackages[imp.ImportPath] = pkg + } +} + +// fixImports adds and removes imports from f so that all its references are +// satisfied and there are no unused imports. +// +// This is declared as a variable rather than a function so goimports can +// easily be extended by adding a file with an init function. +var fixImports = fixImportsDefault + +func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error { + fixes, err := getFixes(fset, f, filename, env) + if err != nil { + return err + } + apply(fset, f, fixes) + return err +} + +// getFixes gets the import fixes that need to be made to f in order to fix the imports. +// It does not modify the ast. +func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { + abs, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + srcDir := filepath.Dir(abs) + if env.Debug { + env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) + } + + // First pass: looking only at f, and using the naive algorithm to + // derive package names from import paths, see if the file is already + // complete. We can't add any imports yet, because we don't know + // if missing references are actually package vars. + p := &pass{fset: fset, f: f, srcDir: srcDir} + if fixes, done := p.load(); done { + return fixes, nil + } + + otherFiles := parseOtherFiles(fset, srcDir, filename) + + // Second pass: add information from other files in the same package, + // like their package vars and imports. + p.otherFiles = otherFiles + if fixes, done := p.load(); done { + return fixes, nil + } + + // Now we can try adding imports from the stdlib. + p.assumeSiblingImportsValid() + addStdlibCandidates(p, p.missingRefs) + if fixes, done := p.fix(); done { + return fixes, nil + } + + // Third pass: get real package names where we had previously used + // the naive algorithm. This is the first step that will use the + // environment, so we provide it here for the first time. + p = &pass{fset: fset, f: f, srcDir: srcDir, env: env} + p.loadRealPackageNames = true + p.otherFiles = otherFiles + if fixes, done := p.load(); done { + return fixes, nil + } + + addStdlibCandidates(p, p.missingRefs) + p.assumeSiblingImportsValid() + if fixes, done := p.fix(); done { + return fixes, nil + } + + // Go look for candidates in $GOPATH, etc. We don't necessarily load + // the real exports of sibling imports, so keep assuming their contents. + if err := addExternalCandidates(p, p.missingRefs, filename); err != nil { + return nil, err + } + + p.lastTry = true + fixes, _ := p.fix() + return fixes, nil +} + +// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed. +func getAllCandidates(filename string, env *ProcessEnv) ([]ImportFix, error) { + // TODO(suzmue): scan for additional candidates and filter out + // current package. + + // Get the stdlib candidates and sort by import path. + var paths []string + for importPath := range stdlib { + paths = append(paths, importPath) + } + sort.Strings(paths) + + var imports []ImportFix + for _, importPath := range paths { + imports = append(imports, ImportFix{ + StmtInfo: ImportInfo{ + ImportPath: importPath, + }, + IdentName: path.Base(importPath), + FixType: AddImport, + }) + } + return imports, nil +} + +// ProcessEnv contains environment variables and settings that affect the use of +// the go command, the go/build package, etc. +type ProcessEnv struct { + LocalPrefix string + Debug bool + + // If non-empty, these will be used instead of the + // process-wide values. + GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS, GOSUMDB string + WorkingDir string + + // If true, use go/packages regardless of the environment. + ForceGoPackages bool + + // Logf is the default logger for the ProcessEnv. + Logf func(format string, args ...interface{}) + + resolver Resolver +} + +func (e *ProcessEnv) env() []string { + env := os.Environ() + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("GOPATH", e.GOPATH) + add("GOROOT", e.GOROOT) + add("GO111MODULE", e.GO111MODULE) + add("GOPROXY", e.GOPROXY) + add("GOFLAGS", e.GOFLAGS) + add("GOSUMDB", e.GOSUMDB) + if e.WorkingDir != "" { + add("PWD", e.WorkingDir) + } + return env +} + +func (e *ProcessEnv) GetResolver() Resolver { + if e.resolver != nil { + return e.resolver + } + if e.ForceGoPackages { + e.resolver = &goPackagesResolver{env: e} + return e.resolver + } + + out, err := e.invokeGo("env", "GOMOD") + if err != nil || len(bytes.TrimSpace(out.Bytes())) == 0 { + e.resolver = &gopathResolver{env: e} + return e.resolver + } + e.resolver = &ModuleResolver{env: e} + return e.resolver +} + +func (e *ProcessEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config { + return &packages.Config{ + Mode: mode, + Dir: e.WorkingDir, + Env: e.env(), + } +} + +func (e *ProcessEnv) buildContext() *build.Context { + ctx := build.Default + ctx.GOROOT = e.GOROOT + ctx.GOPATH = e.GOPATH + return &ctx +} + +func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) { + cmd := exec.Command("go", args...) + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + cmd.Stdout = stdout + cmd.Stderr = stderr + cmd.Env = e.env() + cmd.Dir = e.WorkingDir + + if e.Debug { + defer func(start time.Time) { e.Logf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) + } + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("running go: %v (stderr:\n%s)", err, stderr) + } + return stdout, nil +} + +func cmdDebugStr(cmd *exec.Cmd) string { + env := make(map[string]string) + for _, kv := range cmd.Env { + split := strings.Split(kv, "=") + k, v := split[0], split[1] + env[k] = v + } + + return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], cmd.Args) +} + +func addStdlibCandidates(pass *pass, refs references) { + add := func(pkg string) { + pass.addCandidate( + &ImportInfo{ImportPath: pkg}, + &packageInfo{name: path.Base(pkg), exports: stdlib[pkg]}) + } + for left := range refs { + if left == "rand" { + // Make sure we try crypto/rand before math/rand. + add("crypto/rand") + add("math/rand") + continue + } + for importPath := range stdlib { + if path.Base(importPath) == left { + add(importPath) + } + } + } +} + +// A Resolver does the build-system-specific parts of goimports. +type Resolver interface { + // loadPackageNames loads the package names in importPaths. + loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) + // scan finds (at least) the packages satisfying refs. The returned slice is unordered. + scan(refs references) ([]*pkg, error) + // loadExports returns the set of exported symbols in the package at dir. + // It returns an error if the package name in dir does not match expectPackage. + // loadExports may be called concurrently. + loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) +} + +// gopackagesResolver implements resolver for GOPATH and module workspaces using go/packages. +type goPackagesResolver struct { + env *ProcessEnv +} + +func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + if len(importPaths) == 0 { + return nil, nil + } + cfg := r.env.newPackagesConfig(packages.LoadFiles) + pkgs, err := packages.Load(cfg, importPaths...) + if err != nil { + return nil, err + } + names := map[string]string{} + for _, pkg := range pkgs { + names[VendorlessPath(pkg.PkgPath)] = pkg.Name + } + // We may not have found all the packages. Guess the rest. + for _, path := range importPaths { + if _, ok := names[path]; ok { + continue + } + names[path] = importPathToAssumedName(path) + } + return names, nil + +} + +func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) { + var loadQueries []string + for pkgName := range refs { + loadQueries = append(loadQueries, "iamashamedtousethedisabledqueryname="+pkgName) + } + sort.Strings(loadQueries) + cfg := r.env.newPackagesConfig(packages.LoadFiles) + goPackages, err := packages.Load(cfg, loadQueries...) + if err != nil { + return nil, err + } + + var scan []*pkg + for _, goPackage := range goPackages { + scan = append(scan, &pkg{ + dir: filepath.Dir(goPackage.CompiledGoFiles[0]), + importPathShort: VendorlessPath(goPackage.PkgPath), + goPackage: goPackage, + }) + } + return scan, nil +} + +func (r *goPackagesResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if pkg.goPackage == nil { + return nil, fmt.Errorf("goPackage not set") + } + exports := map[string]bool{} + fset := token.NewFileSet() + for _, fname := range pkg.goPackage.CompiledGoFiles { + f, err := parser.ParseFile(fset, fname, nil, 0) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", fname, err) + } + for name := range f.Scope.Objects { + if ast.IsExported(name) { + exports[name] = true + } + } + } + return exports, nil +} + +func addExternalCandidates(pass *pass, refs references, filename string) error { + dirScan, err := pass.env.GetResolver().scan(refs) + if err != nil { + return err + } + + // Search for imports matching potential package references. + type result struct { + imp *ImportInfo + pkg *packageInfo + } + results := make(chan result, len(refs)) + + ctx, cancel := context.WithCancel(context.TODO()) + var wg sync.WaitGroup + defer func() { + cancel() + wg.Wait() + }() + var ( + firstErr error + firstErrOnce sync.Once + ) + for pkgName, symbols := range refs { + wg.Add(1) + go func(pkgName string, symbols map[string]bool) { + defer wg.Done() + + found, err := findImport(ctx, pass, dirScan, pkgName, symbols, filename) + + if err != nil { + firstErrOnce.Do(func() { + firstErr = err + cancel() + }) + return + } + + if found == nil { + return // No matching package. + } + + imp := &ImportInfo{ + ImportPath: found.importPathShort, + } + + pkg := &packageInfo{ + name: pkgName, + exports: symbols, + } + results <- result{imp, pkg} + }(pkgName, symbols) + } + go func() { + wg.Wait() + close(results) + }() + + for result := range results { + pass.addCandidate(result.imp, result.pkg) + } + return firstErr +} + +// notIdentifier reports whether ch is an invalid identifier character. +func notIdentifier(ch rune) bool { + return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || + '0' <= ch && ch <= '9' || + ch == '_' || + ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch))) +} + +// importPathToAssumedName returns the assumed package name of an import path. +// It does this using only string parsing of the import path. +// It picks the last element of the path that does not look like a major +// version, and then picks the valid identifier off the start of that element. +// It is used to determine if a local rename should be added to an import for +// clarity. +// This function could be moved to a standard package and exported if we want +// for use in other tools. +func importPathToAssumedName(importPath string) string { + base := path.Base(importPath) + if strings.HasPrefix(base, "v") { + if _, err := strconv.Atoi(base[1:]); err == nil { + dir := path.Dir(importPath) + if dir != "." { + base = path.Base(dir) + } + } + } + base = strings.TrimPrefix(base, "go-") + if i := strings.IndexFunc(base, notIdentifier); i >= 0 { + base = base[:i] + } + return base +} + +// gopathResolver implements resolver for GOPATH workspaces. +type gopathResolver struct { + env *ProcessEnv +} + +func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + names := map[string]string{} + for _, path := range importPaths { + names[path] = importPathToName(r.env, path, srcDir) + } + return names, nil +} + +// importPathToName finds out the actual package name, as declared in its .go files. +// If there's a problem, it returns "". +func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) { + // Fast path for standard library without going to disk. + if _, ok := stdlib[importPath]; ok { + return path.Base(importPath) // stdlib packages always match their paths. + } + + buildPkg, err := env.buildContext().Import(importPath, srcDir, build.FindOnly) + if err != nil { + return "" + } + pkgName, err := packageDirToName(buildPkg.Dir) + if err != nil { + return "" + } + return pkgName +} + +// packageDirToName is a faster version of build.Import if +// the only thing desired is the package name. Given a directory, +// packageDirToName then only parses one file in the package, +// trusting that the files in the directory are consistent. +func packageDirToName(dir string) (packageName string, err error) { + d, err := os.Open(dir) + if err != nil { + return "", err + } + names, err := d.Readdirnames(-1) + d.Close() + if err != nil { + return "", err + } + sort.Strings(names) // to have predictable behavior + var lastErr error + var nfile int + for _, name := range names { + if !strings.HasSuffix(name, ".go") { + continue + } + if strings.HasSuffix(name, "_test.go") { + continue + } + nfile++ + fullFile := filepath.Join(dir, name) + + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly) + if err != nil { + lastErr = err + continue + } + pkgName := f.Name.Name + if pkgName == "documentation" { + // Special case from go/build.ImportDir, not + // handled by ctx.MatchFile. + continue + } + if pkgName == "main" { + // Also skip package main, assuming it's a +build ignore generator or example. + // Since you can't import a package main anyway, there's no harm here. + continue + } + return pkgName, nil + } + if lastErr != nil { + return "", lastErr + } + return "", fmt.Errorf("no importable package found in %d Go files", nfile) +} + +type pkg struct { + goPackage *packages.Package + dir string // absolute file path to pkg directory ("/usr/lib/go/src/net/http") + importPathShort string // vendorless import path ("net/http", "a/b") +} + +type pkgDistance struct { + pkg *pkg + distance int // relative distance to target +} + +// byDistanceOrImportPathShortLength sorts by relative distance breaking ties +// on the short import path length and then the import string itself. +type byDistanceOrImportPathShortLength []pkgDistance + +func (s byDistanceOrImportPathShortLength) Len() int { return len(s) } +func (s byDistanceOrImportPathShortLength) Less(i, j int) bool { + di, dj := s[i].distance, s[j].distance + if di == -1 { + return false + } + if dj == -1 { + return true + } + if di != dj { + return di < dj + } + + vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort + if len(vi) != len(vj) { + return len(vi) < len(vj) + } + return vi < vj +} +func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func distance(basepath, targetpath string) int { + p, err := filepath.Rel(basepath, targetpath) + if err != nil { + return -1 + } + if p == "." { + return 0 + } + return strings.Count(p, string(filepath.Separator)) + 1 +} + +func (r *gopathResolver) scan(_ references) ([]*pkg, error) { + dupCheck := make(map[string]bool) + var result []*pkg + + var mu sync.Mutex + + add := func(root gopathwalk.Root, dir string) { + mu.Lock() + defer mu.Unlock() + + if _, dup := dupCheck[dir]; dup { + return + } + dupCheck[dir] = true + importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):]) + result = append(result, &pkg{ + importPathShort: VendorlessPath(importpath), + dir: dir, + }) + } + gopathwalk.Walk(gopathwalk.SrcDirsRoots(r.env.buildContext()), add, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: false}) + return result, nil +} + +func (r *gopathResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + +// VendorlessPath returns the devendorized version of the import path ipath. +// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b". +func VendorlessPath(ipath string) string { + // Devendorize for use in import statement. + if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { + return ipath[i+len("/vendor/"):] + } + if strings.HasPrefix(ipath, "vendor/") { + return ipath[len("vendor/"):] + } + return ipath +} + +func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, expectPackage string, dir string) (map[string]bool, error) { + exports := make(map[string]bool) + + // Look for non-test, buildable .go files which could provide exports. + all, err := ioutil.ReadDir(dir) + if err != nil { + return nil, err + } + var files []os.FileInfo + for _, fi := range all { + name := fi.Name() + if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { + continue + } + match, err := env.buildContext().MatchFile(dir, fi.Name()) + if err != nil || !match { + continue + } + files = append(files, fi) + } + + if len(files) == 0 { + return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir) + } + + fset := token.NewFileSet() + for _, fi := range files { + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + fullFile := filepath.Join(dir, fi.Name()) + f, err := parser.ParseFile(fset, fullFile, nil, 0) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", fullFile, err) + } + pkgName := f.Name.Name + if pkgName == "documentation" { + // Special case from go/build.ImportDir, not + // handled by MatchFile above. + continue + } + if pkgName != expectPackage { + return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName) + } + for name := range f.Scope.Objects { + if ast.IsExported(name) { + exports[name] = true + } + } + } + + if env.Debug { + exportList := make([]string, 0, len(exports)) + for k := range exports { + exportList = append(exportList, k) + } + sort.Strings(exportList) + env.Logf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", ")) + } + return exports, nil +} + +// findImport searches for a package with the given symbols. +// If no package is found, findImport returns ("", false, nil) +func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) { + pkgDir, err := filepath.Abs(filename) + if err != nil { + return nil, err + } + pkgDir = filepath.Dir(pkgDir) + + // Find candidate packages, looking only at their directory names first. + var candidates []pkgDistance + for _, pkg := range dirScan { + if pkg.dir == pkgDir && pass.f.Name.Name == pkgName { + // The candidate is in the same directory and has the + // same package name. Don't try to import ourselves. + continue + } + if pkgIsCandidate(filename, pkgName, pkg) { + candidates = append(candidates, pkgDistance{ + pkg: pkg, + distance: distance(pkgDir, pkg.dir), + }) + } + } + + // Sort the candidates by their import package length, + // assuming that shorter package names are better than long + // ones. Note that this sorts by the de-vendored name, so + // there's no "penalty" for vendoring. + sort.Sort(byDistanceOrImportPathShortLength(candidates)) + if pass.env.Debug { + for i, c := range candidates { + pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) + } + } + + // Collect exports for packages with matching names. + + rescv := make([]chan *pkg, len(candidates)) + for i := range candidates { + rescv[i] = make(chan *pkg, 1) + } + const maxConcurrentPackageImport = 4 + loadExportsSem := make(chan struct{}, maxConcurrentPackageImport) + + ctx, cancel := context.WithCancel(ctx) + var wg sync.WaitGroup + defer func() { + cancel() + wg.Wait() + }() + + wg.Add(1) + go func() { + defer wg.Done() + for i, c := range candidates { + select { + case loadExportsSem <- struct{}{}: + case <-ctx.Done(): + return + } + + wg.Add(1) + go func(c pkgDistance, resc chan<- *pkg) { + defer func() { + <-loadExportsSem + wg.Done() + }() + + if pass.env.Debug { + pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName) + } + exports, err := pass.env.GetResolver().loadExports(ctx, pkgName, c.pkg) + if err != nil { + if pass.env.Debug { + pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) + } + resc <- nil + return + } + + // If it doesn't have the right + // symbols, send nil to mean no match. + for symbol := range symbols { + if !exports[symbol] { + resc <- nil + return + } + } + resc <- c.pkg + }(c, rescv[i]) + } + }() + + for _, resc := range rescv { + pkg := <-resc + if pkg == nil { + continue + } + return pkg, nil + } + return nil, nil +} + +// pkgIsCandidate reports whether pkg is a candidate for satisfying the +// finding which package pkgIdent in the file named by filename is trying +// to refer to. +// +// This check is purely lexical and is meant to be as fast as possible +// because it's run over all $GOPATH directories to filter out poor +// candidates in order to limit the CPU and I/O later parsing the +// exports in candidate packages. +// +// filename is the file being formatted. +// pkgIdent is the package being searched for, like "client" (if +// searching for "client.New") +func pkgIsCandidate(filename, pkgIdent string, pkg *pkg) bool { + // Check "internal" and "vendor" visibility: + if !canUse(filename, pkg.dir) { + return false + } + + // Speed optimization to minimize disk I/O: + // the last two components on disk must contain the + // package name somewhere. + // + // This permits mismatch naming like directory + // "go-foo" being package "foo", or "pkg.v3" being "pkg", + // or directory "google.golang.org/api/cloudbilling/v1" + // being package "cloudbilling", but doesn't + // permit a directory "foo" to be package + // "bar", which is strongly discouraged + // anyway. There's no reason goimports needs + // to be slow just to accommodate that. + lastTwo := lastTwoComponents(pkg.importPathShort) + if strings.Contains(lastTwo, pkgIdent) { + return true + } + if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) { + lastTwo = lowerASCIIAndRemoveHyphen(lastTwo) + if strings.Contains(lastTwo, pkgIdent) { + return true + } + } + + return false +} + +func hasHyphenOrUpperASCII(s string) bool { + for i := 0; i < len(s); i++ { + b := s[i] + if b == '-' || ('A' <= b && b <= 'Z') { + return true + } + } + return false +} + +func lowerASCIIAndRemoveHyphen(s string) (ret string) { + buf := make([]byte, 0, len(s)) + for i := 0; i < len(s); i++ { + b := s[i] + switch { + case b == '-': + continue + case 'A' <= b && b <= 'Z': + buf = append(buf, b+('a'-'A')) + default: + buf = append(buf, b) + } + } + return string(buf) +} + +// canUse reports whether the package in dir is usable from filename, +// respecting the Go "internal" and "vendor" visibility rules. +func canUse(filename, dir string) bool { + // Fast path check, before any allocations. If it doesn't contain vendor + // or internal, it's not tricky: + // Note that this can false-negative on directories like "notinternal", + // but we check it correctly below. This is just a fast path. + if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") { + return true + } + + dirSlash := filepath.ToSlash(dir) + if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") { + return true + } + // Vendor or internal directory only visible from children of parent. + // That means the path from the current directory to the target directory + // can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal + // or bar/vendor or bar/internal. + // After stripping all the leading ../, the only okay place to see vendor or internal + // is at the very beginning of the path. + absfile, err := filepath.Abs(filename) + if err != nil { + return false + } + absdir, err := filepath.Abs(dir) + if err != nil { + return false + } + rel, err := filepath.Rel(absfile, absdir) + if err != nil { + return false + } + relSlash := filepath.ToSlash(rel) + if i := strings.LastIndex(relSlash, "../"); i >= 0 { + relSlash = relSlash[i+len("../"):] + } + return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal") +} + +// lastTwoComponents returns at most the last two path components +// of v, using either / or \ as the path separator. +func lastTwoComponents(v string) string { + nslash := 0 + for i := len(v) - 1; i >= 0; i-- { + if v[i] == '/' || v[i] == '\\' { + nslash++ + if nslash == 2 { + return v[i:] + } + } + } + return v +} + +type visitFn func(node ast.Node) ast.Visitor + +func (fn visitFn) Visit(node ast.Node) ast.Visitor { + return fn(node) +} diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go new file mode 100644 index 0000000000..2c074cb2db --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/imports.go @@ -0,0 +1,388 @@ +// Copyright 2013 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. + +//go:generate go run mkstdlib.go + +// Package imports implements a Go pretty-printer (like package "go/format") +// that also adds or removes import statements as necessary. +package imports + +import ( + "bufio" + "bytes" + "fmt" + "go/ast" + "go/build" + "go/format" + "go/parser" + "go/printer" + "go/token" + "io" + "io/ioutil" + "log" + "regexp" + "strconv" + "strings" + + "golang.org/x/tools/go/ast/astutil" +) + +// Options is golang.org/x/tools/imports.Options with extra internal-only options. +type Options struct { + Env *ProcessEnv // The environment to use. Note: this contains the cached module and filesystem state. + + Fragment bool // Accept fragment of a source file (no package statement) + AllErrors bool // Report all errors (not just the first 10 on different lines) + + Comments bool // Print comments (true if nil *Options provided) + TabIndent bool // Use tabs for indent (true if nil *Options provided) + TabWidth int // Tab width (8 if nil *Options provided) + + FormatOnly bool // Disable the insertion and deletion of imports +} + +// Process implements golang.org/x/tools/imports.Process with explicit context in env. +func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, adjust, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + if !opt.FormatOnly { + if err := fixImports(fileSet, file, filename, opt.Env); err != nil { + return nil, err + } + } + return formatFile(fileSet, file, src, adjust, opt) +} + +// FixImports returns a list of fixes to the imports that, when applied, +// will leave the imports in the same state as Process. +// +// Note that filename's directory influences which imports can be chosen, +// so it is important that filename be accurate. +func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, _, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + return getFixes(fileSet, file, filename, opt.Env) +} + +// ApplyFix will apply all of the fixes to the file and format it. +func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, adjust, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + // Apply the fixes to the file. + apply(fileSet, file, fixes) + + return formatFile(fileSet, file, src, adjust, opt) +} + +// GetAllCandidates gets all of the standard library candidate packages to import in +// sorted order on import path. +func GetAllCandidates(filename string, opt *Options) (pkgs []ImportFix, err error) { + _, opt, err = initialize(filename, []byte{}, opt) + if err != nil { + return nil, err + } + return getAllCandidates(filename, opt.Env) +} + +// initialize sets the values for opt and src. +// If they are provided, they are not changed. Otherwise opt is set to the +// default values and src is read from the file system. +func initialize(filename string, src []byte, opt *Options) ([]byte, *Options, error) { + // Use defaults if opt is nil. + if opt == nil { + opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} + } + + // Set the env if the user has not provided it. + if opt.Env == nil { + opt.Env = &ProcessEnv{ + GOPATH: build.Default.GOPATH, + GOROOT: build.Default.GOROOT, + } + } + + // Set the logger if the user has not provided it. + if opt.Env.Logf == nil { + opt.Env.Logf = log.Printf + } + + if src == nil { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, nil, err + } + src = b + } + + return src, opt, nil +} + +func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { + mergeImports(opt.Env, fileSet, file) + sortImports(opt.Env, fileSet, file) + imps := astutil.Imports(fileSet, file) + var spacesBefore []string // import paths we need spaces before + for _, impSection := range imps { + // Within each block of contiguous imports, see if any + // import lines are in different group numbers. If so, + // we'll need to put a space between them so it's + // compatible with gofmt. + lastGroup := -1 + for _, importSpec := range impSection { + importPath, _ := strconv.Unquote(importSpec.Path.Value) + groupNum := importGroup(opt.Env, importPath) + if groupNum != lastGroup && lastGroup != -1 { + spacesBefore = append(spacesBefore, importPath) + } + lastGroup = groupNum + } + + } + + printerMode := printer.UseSpaces + if opt.TabIndent { + printerMode |= printer.TabIndent + } + printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} + + var buf bytes.Buffer + err := printConfig.Fprint(&buf, fileSet, file) + if err != nil { + return nil, err + } + out := buf.Bytes() + if adjust != nil { + out = adjust(src, out) + } + if len(spacesBefore) > 0 { + out, err = addImportSpaces(bytes.NewReader(out), spacesBefore) + if err != nil { + return nil, err + } + } + + out, err = format.Source(out) + if err != nil { + return nil, err + } + return out, nil +} + +// parse parses src, which was read from filename, +// as a Go source file or statement list. +func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) { + parserMode := parser.Mode(0) + if opt.Comments { + parserMode |= parser.ParseComments + } + if opt.AllErrors { + parserMode |= parser.AllErrors + } + + // Try as whole source file. + file, err := parser.ParseFile(fset, filename, src, parserMode) + if err == nil { + return file, nil, nil + } + // If the error is that the source file didn't begin with a + // package line and we accept fragmented input, fall through to + // try as a source fragment. Stop and return on any other error. + if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") { + return nil, nil, err + } + + // If this is a declaration list, make it a source file + // by inserting a package clause. + // Insert using a ;, not a newline, so that parse errors are on + // the correct line. + const prefix = "package main;" + psrc := append([]byte(prefix), src...) + file, err = parser.ParseFile(fset, filename, psrc, parserMode) + if err == nil { + // Gofmt will turn the ; into a \n. + // Do that ourselves now and update the file contents, + // so that positions and line numbers are correct going forward. + psrc[len(prefix)-1] = '\n' + fset.File(file.Package).SetLinesForContent(psrc) + + // If a main function exists, we will assume this is a main + // package and leave the file. + if containsMainFunc(file) { + return file, nil, nil + } + + adjust := func(orig, src []byte) []byte { + // Remove the package clause. + src = src[len(prefix):] + return matchSpace(orig, src) + } + return file, adjust, nil + } + // If the error is that the source file didn't begin with a + // declaration, fall through to try as a statement list. + // Stop and return on any other error. + if !strings.Contains(err.Error(), "expected declaration") { + return nil, nil, err + } + + // If this is a statement list, make it a source file + // by inserting a package clause and turning the list + // into a function body. This handles expressions too. + // Insert using a ;, not a newline, so that the line numbers + // in fsrc match the ones in src. + fsrc := append(append([]byte("package p; func _() {"), src...), '}') + file, err = parser.ParseFile(fset, filename, fsrc, parserMode) + if err == nil { + adjust := func(orig, src []byte) []byte { + // Remove the wrapping. + // Gofmt has turned the ; into a \n\n. + src = src[len("package p\n\nfunc _() {"):] + src = src[:len(src)-len("}\n")] + // Gofmt has also indented the function body one level. + // Remove that indent. + src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) + return matchSpace(orig, src) + } + return file, adjust, nil + } + + // Failed, and out of options. + return nil, nil, err +} + +// containsMainFunc checks if a file contains a function declaration with the +// function signature 'func main()' +func containsMainFunc(file *ast.File) bool { + for _, decl := range file.Decls { + if f, ok := decl.(*ast.FuncDecl); ok { + if f.Name.Name != "main" { + continue + } + + if len(f.Type.Params.List) != 0 { + continue + } + + if f.Type.Results != nil && len(f.Type.Results.List) != 0 { + continue + } + + return true + } + } + + return false +} + +func cutSpace(b []byte) (before, middle, after []byte) { + i := 0 + for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { + i++ + } + j := len(b) + for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { + j-- + } + if i <= j { + return b[:i], b[i:j], b[j:] + } + return nil, nil, b[j:] +} + +// matchSpace reformats src to use the same space context as orig. +// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src. +// 2) matchSpace copies the indentation of the first non-blank line in orig +// to every non-blank line in src. +// 3) matchSpace copies the trailing space from orig and uses it in place +// of src's trailing space. +func matchSpace(orig []byte, src []byte) []byte { + before, _, after := cutSpace(orig) + i := bytes.LastIndex(before, []byte{'\n'}) + before, indent := before[:i+1], before[i+1:] + + _, src, _ = cutSpace(src) + + var b bytes.Buffer + b.Write(before) + for len(src) > 0 { + line := src + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, src = line[:i+1], line[i+1:] + } else { + src = nil + } + if len(line) > 0 && line[0] != '\n' { // not blank + b.Write(indent) + } + b.Write(line) + } + b.Write(after) + return b.Bytes() +} + +var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`) + +func addImportSpaces(r io.Reader, breaks []string) ([]byte, error) { + var out bytes.Buffer + in := bufio.NewReader(r) + inImports := false + done := false + for { + s, err := in.ReadString('\n') + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + + if !inImports && !done && strings.HasPrefix(s, "import") { + inImports = true + } + if inImports && (strings.HasPrefix(s, "var") || + strings.HasPrefix(s, "func") || + strings.HasPrefix(s, "const") || + strings.HasPrefix(s, "type")) { + done = true + inImports = false + } + if inImports && len(breaks) > 0 { + if m := impLine.FindStringSubmatch(s); m != nil { + if m[1] == breaks[0] { + out.WriteByte('\n') + breaks = breaks[1:] + } + } + } + + fmt.Fprint(&out, s) + } + return out.Bytes(), nil +} diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go new file mode 100644 index 0000000000..271c7d2832 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/mod.go @@ -0,0 +1,486 @@ +package imports + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/module" +) + +// ModuleResolver implements resolver for modules using the go command as little +// as feasible. +type ModuleResolver struct { + env *ProcessEnv + moduleCacheDir string + + Initialized bool + Main *ModuleJSON + ModsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path... + ModsByDir []*ModuleJSON // ...or Dir. + + // moduleCacheInfo stores information about the module cache. + moduleCacheInfo *moduleCacheInfo +} + +type ModuleJSON struct { + Path string // module path + Version string // module version + Versions []string // available module versions (with -versions) + Replace *ModuleJSON // replaced by this module + Time *time.Time // time version was created + Update *ModuleJSON // available update, if any (with -u) + Main bool // is this the main module? + Indirect bool // is this module only an indirect dependency of main module? + Dir string // directory holding files for this module, if any + GoMod string // path to go.mod file for this module, if any + Error *ModuleErrorJSON // error loading module +} + +type ModuleErrorJSON struct { + Err string // the error itself +} + +func (r *ModuleResolver) init() error { + if r.Initialized { + return nil + } + stdout, err := r.env.invokeGo("list", "-m", "-json", "...") + if err != nil { + return err + } + for dec := json.NewDecoder(stdout); dec.More(); { + mod := &ModuleJSON{} + if err := dec.Decode(mod); err != nil { + return err + } + if mod.Dir == "" { + if r.env.Debug { + r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path) + } + // Can't do anything with a module that's not downloaded. + continue + } + r.ModsByModPath = append(r.ModsByModPath, mod) + r.ModsByDir = append(r.ModsByDir, mod) + if mod.Main { + r.Main = mod + } + } + + sort.Slice(r.ModsByModPath, func(i, j int) bool { + count := func(x int) int { + return strings.Count(r.ModsByModPath[x].Path, "/") + } + return count(j) < count(i) // descending order + }) + sort.Slice(r.ModsByDir, func(i, j int) bool { + count := func(x int) int { + return strings.Count(r.ModsByDir[x].Dir, "/") + } + return count(j) < count(i) // descending order + }) + + if r.moduleCacheInfo == nil { + r.moduleCacheInfo = &moduleCacheInfo{ + modCacheDirInfo: make(map[string]*directoryPackageInfo), + } + } + + r.Initialized = true + return nil +} + +// findPackage returns the module and directory that contains the package at +// the given import path, or returns nil, "" if no module is in scope. +func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) { + for _, m := range r.ModsByModPath { + if !strings.HasPrefix(importPath, m.Path) { + continue + } + pathInModule := importPath[len(m.Path):] + pkgDir := filepath.Join(m.Dir, pathInModule) + if r.dirIsNestedModule(pkgDir, m) { + continue + } + + if info, ok := r.moduleCacheInfo.Load(pkgDir); ok { + if packageScanned, err := info.reachedStatus(directoryScanned); packageScanned { + if err != nil { + // There was some error with scanning this directory. + // It does not contain a valid package. + continue + } + return m, pkgDir + } + } + + pkgFiles, err := ioutil.ReadDir(pkgDir) + if err != nil { + continue + } + + // A module only contains a package if it has buildable go + // files in that directory. If not, it could be provided by an + // outer module. See #29736. + for _, fi := range pkgFiles { + if ok, _ := r.env.buildContext().MatchFile(pkgDir, fi.Name()); ok { + return m, pkgDir + } + } + } + return nil, "" +} + +// findModuleByDir returns the module that contains dir, or nil if no such +// module is in scope. +func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON { + // This is quite tricky and may not be correct. dir could be: + // - a package in the main module. + // - a replace target underneath the main module's directory. + // - a nested module in the above. + // - a replace target somewhere totally random. + // - a nested module in the above. + // - in the mod cache. + // - in /vendor/ in -mod=vendor mode. + // - nested module? Dunno. + // Rumor has it that replace targets cannot contain other replace targets. + for _, m := range r.ModsByDir { + if !strings.HasPrefix(dir, m.Dir) { + continue + } + + if r.dirIsNestedModule(dir, m) { + continue + } + + return m + } + return nil +} + +// dirIsNestedModule reports if dir is contained in a nested module underneath +// mod, not actually in mod. +func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool { + if !strings.HasPrefix(dir, mod.Dir) { + return false + } + if r.dirInModuleCache(dir) { + // Nested modules in the module cache are pruned, + // so it cannot be a nested module. + return false + } + mf := r.findModFile(dir) + if mf == "" { + return false + } + return filepath.Dir(mf) != mod.Dir +} + +func (r *ModuleResolver) findModFile(dir string) string { + if r.dirInModuleCache(dir) { + matches := modCacheRegexp.FindStringSubmatch(dir) + index := strings.Index(dir, matches[1]+"@"+matches[2]) + return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod") + } + for { + f := filepath.Join(dir, "go.mod") + info, err := os.Stat(f) + if err == nil && !info.IsDir() { + return f + } + d := filepath.Dir(dir) + if len(d) >= len(dir) { + return "" // reached top of file system, no go.mod + } + dir = d + } +} + +func (r *ModuleResolver) dirInModuleCache(dir string) bool { + if r.moduleCacheDir == "" { + return false + } + return strings.HasPrefix(dir, r.moduleCacheDir) +} + +func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + if err := r.init(); err != nil { + return nil, err + } + names := map[string]string{} + for _, path := range importPaths { + _, packageDir := r.findPackage(path) + if packageDir == "" { + continue + } + name, err := packageDirToName(packageDir) + if err != nil { + continue + } + names[path] = name + } + return names, nil +} + +func (r *ModuleResolver) scan(_ references) ([]*pkg, error) { + if err := r.init(); err != nil { + return nil, err + } + + // Walk GOROOT, GOPATH/pkg/mod, and the main module. + roots := []gopathwalk.Root{ + {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT}, + } + if r.Main != nil { + roots = append(roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule}) + } + if r.moduleCacheDir == "" { + r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod") + } + roots = append(roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache}) + + // Walk replace targets, just in case they're not in any of the above. + for _, mod := range r.ModsByModPath { + if mod.Replace != nil { + roots = append(roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther}) + } + } + + var result []*pkg + dupCheck := make(map[string]bool) + var mu sync.Mutex + + // Packages in the module cache are immutable. If we have + // already seen this package on a previous scan of the module + // cache, return that result. + skip := func(root gopathwalk.Root, dir string) bool { + mu.Lock() + defer mu.Unlock() + // If we have already processed this directory on this walk, skip it. + if _, dup := dupCheck[dir]; dup { + return true + } + + // If we have saved this directory information, skip it. + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + return false + } + // This directory can be skipped as long as we have already scanned it. + // Packages with errors will continue to have errors, so there is no need + // to rescan them. + packageScanned, _ := info.reachedStatus(directoryScanned) + return packageScanned + } + + add := func(root gopathwalk.Root, dir string) { + mu.Lock() + defer mu.Unlock() + if _, dup := dupCheck[dir]; dup { + return + } + + info, err := r.scanDirForPackage(root, dir) + if err != nil { + return + } + if root.Type == gopathwalk.RootModuleCache { + // Save this package information in the cache and return. + // Packages from the module cache are added after Walk. + r.moduleCacheInfo.Store(dir, info) + return + } + + // Skip this package if there was an error loading package info. + if info.err != nil { + return + } + + // The rest of this function canonicalizes the packages using the results + // of initializing the resolver from 'go list -m'. + res, err := r.canonicalize(info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { + return + } + + result = append(result, res) + } + + gopathwalk.WalkSkip(roots, add, skip, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true}) + + // Add the packages from the modules in the mod cache that were skipped. + for _, dir := range r.moduleCacheInfo.Keys() { + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + continue + } + + // Skip this directory if we were not able to get the package information successfully. + if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { + continue + } + + res, err := r.canonicalize(info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { + continue + } + result = append(result, res) + } + + return result, nil +} + +// canonicalize gets the result of canonicalizing the packages using the results +// of initializing the resolver from 'go list -m'. +func (r *ModuleResolver) canonicalize(importPath, dir string, needsReplace bool) (res *pkg, err error) { + // Check if the directory is underneath a module that's in scope. + if mod := r.findModuleByDir(dir); mod != nil { + // It is. If dir is the target of a replace directive, + // our guessed import path is wrong. Use the real one. + if mod.Dir == dir { + importPath = mod.Path + } else { + dirInMod := dir[len(mod.Dir)+len("/"):] + importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) + } + } else if needsReplace { + return nil, fmt.Errorf("needed this package to be in scope: %s", dir) + } + + // We may have discovered a package that has a different version + // in scope already. Canonicalize to that one if possible. + if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { + dir = canonicalDir + } + return &pkg{ + importPathShort: VendorlessPath(importPath), + dir: dir, + }, nil +} + +func (r *ModuleResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if err := r.init(); err != nil { + return nil, err + } + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + +func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) (directoryPackageInfo, error) { + subdir := "" + if dir != root.Path { + subdir = dir[len(root.Path)+len("/"):] + } + importPath := filepath.ToSlash(subdir) + if strings.HasPrefix(importPath, "vendor/") { + // Ignore vendor dirs. If -mod=vendor is on, then things + // should mostly just work, but when it's not vendor/ + // is a mess. There's no easy way to tell if it's on. + // We can still find things in the mod cache and + // map them into /vendor when -mod=vendor is on. + return directoryPackageInfo{}, fmt.Errorf("vendor directory") + } + switch root.Type { + case gopathwalk.RootCurrentModule: + importPath = path.Join(r.Main.Path, filepath.ToSlash(subdir)) + case gopathwalk.RootModuleCache: + matches := modCacheRegexp.FindStringSubmatch(subdir) + if len(matches) == 0 { + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("invalid module cache path: %v", subdir), + }, nil + } + modPath, err := module.DecodePath(filepath.ToSlash(matches[1])) + if err != nil { + if r.env.Debug { + r.env.Logf("decoding module cache path %q: %v", subdir, err) + } + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("decoding module cache path %q: %v", subdir, err), + }, nil + } + importPath = path.Join(modPath, filepath.ToSlash(matches[3])) + case gopathwalk.RootGOROOT: + importPath = subdir + } + + // Check that this package is not obviously impossible to import. + modFile := r.findModFile(dir) + + var needsReplace bool + modBytes, err := ioutil.ReadFile(modFile) + if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) { + // The module's declared path does not match + // its expected path. It probably needs a + // replace directive we don't have. + needsReplace = true + } + + return directoryPackageInfo{ + status: directoryScanned, + dir: dir, + nonCanonicalImportPath: importPath, + needsReplace: needsReplace, + }, nil +} + +// modCacheRegexp splits a path in a module cache into module, module version, and package. +var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) + +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. +// +// Copied from cmd/go/internal/modfile. +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 +} diff --git a/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/vendor/golang.org/x/tools/internal/imports/mod_cache.go new file mode 100644 index 0000000000..f96b92d009 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/mod_cache.go @@ -0,0 +1,121 @@ +package imports + +import ( + "sync" +) + +// ModuleResolver implements Resolver for modules using the go command as little +// as feasible. +// +// To find packages to import, the resolver needs to know about all of the +// the packages that could be imported. This includes packages that are +// already in modules that are in (1) the current module, (2) replace targets, +// and (3) packages in the module cache. Packages in (1) and (2) may change over +// time, as the client may edit the current module and locally replaced modules. +// The module cache (which includes all of the packages in (3)) can only +// ever be added to. +// +// The resolver can thus save state about packages in the module cache +// and guarantee that this will not change over time. To obtain information +// about new modules added to the module cache, the module cache should be +// rescanned. +// +// It is OK to serve information about modules that have been deleted, +// as they do still exist. +// TODO(suzmue): can we share information with the caller about +// what module needs to be downloaded to import this package? + +type directoryPackageStatus int + +const ( + _ directoryPackageStatus = iota + directoryScanned +) + +type directoryPackageInfo struct { + // status indicates the extent to which this struct has been filled in. + status directoryPackageStatus + // err is non-nil when there was an error trying to reach status. + err error + + // Set when status > directoryScanned. + + // dir is the absolute directory of this package. + dir string + // nonCanonicalImportPath is the expected import path for this package. + // This may not be an import path that can be used to import this package. + nonCanonicalImportPath string + // needsReplace is true if the nonCanonicalImportPath does not match the + // the modules declared path, making it impossible to import without a + // replace directive. + needsReplace bool +} + +// reachedStatus returns true when info has a status at least target and any error associated with +// an attempt to reach target. +func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (bool, error) { + if info.err == nil { + return info.status >= target, nil + } + if info.status == target { + return true, info.err + } + return true, nil +} + +// moduleCacheInfo is a concurrency safe map for storing information about +// the directories in the module cache. +// +// The information in this cache is built incrementally. Entries are initialized in scan. +// No new keys should be added in any other functions, as all directories containing +// packages are identified in scan. +// +// Other functions, including loadExports and findPackage, may update entries in this cache +// as they discover new things about the directory. +// +// We do not need to protect the data in the cache for multiple writes, because it only stores +// module cache directories, which do not change. If two competing stores take place, there will be +// one store that wins. Although this could result in a loss of information it will not be incorrect +// and may just result in recomputing the same result later. +// +// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc) +type moduleCacheInfo struct { + mu sync.Mutex + // modCacheDirInfo stores information about packages in + // module cache directories. Keyed by absolute directory. + modCacheDirInfo map[string]*directoryPackageInfo +} + +// Store stores the package info for dir. +func (d *moduleCacheInfo) Store(dir string, info directoryPackageInfo) { + d.mu.Lock() + defer d.mu.Unlock() + d.modCacheDirInfo[dir] = &directoryPackageInfo{ + status: info.status, + err: info.err, + dir: info.dir, + nonCanonicalImportPath: info.nonCanonicalImportPath, + needsReplace: info.needsReplace, + } +} + +// Load returns a copy of the directoryPackageInfo for absolute directory dir. +func (d *moduleCacheInfo) Load(dir string) (directoryPackageInfo, bool) { + d.mu.Lock() + defer d.mu.Unlock() + info, ok := d.modCacheDirInfo[dir] + if !ok { + return directoryPackageInfo{}, false + } + return *info, true +} + +// Keys returns the keys currently present in d. +func (d *moduleCacheInfo) Keys() (keys []string) { + d.mu.Lock() + defer d.mu.Unlock() + for key := range d.modCacheDirInfo { + keys = append(keys, key) + } + return keys +} diff --git a/vendor/golang.org/x/tools/internal/imports/sortimports.go b/vendor/golang.org/x/tools/internal/imports/sortimports.go new file mode 100644 index 0000000000..226279471d --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/sortimports.go @@ -0,0 +1,280 @@ +// Copyright 2013 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. + +// Hacked up copy of go/ast/import.go + +package imports + +import ( + "go/ast" + "go/token" + "sort" + "strconv" +) + +// sortImports sorts runs of consecutive import lines in import blocks in f. +// It also removes duplicate imports when it is possible to do so without data loss. +func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { + for i, d := range f.Decls { + d, ok := d.(*ast.GenDecl) + if !ok || d.Tok != token.IMPORT { + // Not an import declaration, so we're done. + // Imports are always first. + break + } + + if len(d.Specs) == 0 { + // Empty import block, remove it. + f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) + } + + if !d.Lparen.IsValid() { + // Not a block: sorted by default. + continue + } + + // Identify and sort runs of specs on successive lines. + i := 0 + specs := d.Specs[:0] + for j, s := range d.Specs { + if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { + // j begins a new run. End this one. + specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:j])...) + i = j + } + } + specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:])...) + d.Specs = specs + + // Deduping can leave a blank line before the rparen; clean that up. + if len(d.Specs) > 0 { + lastSpec := d.Specs[len(d.Specs)-1] + lastLine := fset.Position(lastSpec.Pos()).Line + if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 { + fset.File(d.Rparen).MergeLine(rParenLine - 1) + } + } + } +} + +// mergeImports merges all the import declarations into the first one. +// Taken from golang.org/x/tools/ast/astutil. +func mergeImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { + if len(f.Decls) <= 1 { + return + } + + // Merge all the import declarations into the first one. + var first *ast.GenDecl + for i := 0; i < len(f.Decls); i++ { + decl := f.Decls[i] + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { + continue + } + if first == nil { + first = gen + continue // Don't touch the first one. + } + // We now know there is more than one package in this import + // declaration. Ensure that it ends up parenthesized. + first.Lparen = first.Pos() + // Move the imports of the other import declaration to the first one. + for _, spec := range gen.Specs { + spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() + first.Specs = append(first.Specs, spec) + } + f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) + i-- + } +} + +// declImports reports whether gen contains an import of path. +// Taken from golang.org/x/tools/ast/astutil. +func declImports(gen *ast.GenDecl, path string) bool { + if gen.Tok != token.IMPORT { + return false + } + for _, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + if importPath(impspec) == path { + return true + } + } + return false +} + +func importPath(s ast.Spec) string { + t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) + if err == nil { + return t + } + return "" +} + +func importName(s ast.Spec) string { + n := s.(*ast.ImportSpec).Name + if n == nil { + return "" + } + return n.Name +} + +func importComment(s ast.Spec) string { + c := s.(*ast.ImportSpec).Comment + if c == nil { + return "" + } + return c.Text() +} + +// collapse indicates whether prev may be removed, leaving only next. +func collapse(prev, next ast.Spec) bool { + if importPath(next) != importPath(prev) || importName(next) != importName(prev) { + return false + } + return prev.(*ast.ImportSpec).Comment == nil +} + +type posSpan struct { + Start token.Pos + End token.Pos +} + +func sortSpecs(env *ProcessEnv, fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { + // Can't short-circuit here even if specs are already sorted, + // since they might yet need deduplication. + // A lone import, however, may be safely ignored. + if len(specs) <= 1 { + return specs + } + + // Record positions for specs. + pos := make([]posSpan, len(specs)) + for i, s := range specs { + pos[i] = posSpan{s.Pos(), s.End()} + } + + // Identify comments in this range. + // Any comment from pos[0].Start to the final line counts. + lastLine := fset.Position(pos[len(pos)-1].End).Line + cstart := len(f.Comments) + cend := len(f.Comments) + for i, g := range f.Comments { + if g.Pos() < pos[0].Start { + continue + } + if i < cstart { + cstart = i + } + if fset.Position(g.End()).Line > lastLine { + cend = i + break + } + } + comments := f.Comments[cstart:cend] + + // Assign each comment to the import spec preceding it. + importComment := map[*ast.ImportSpec][]*ast.CommentGroup{} + specIndex := 0 + for _, g := range comments { + for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { + specIndex++ + } + s := specs[specIndex].(*ast.ImportSpec) + importComment[s] = append(importComment[s], g) + } + + // Sort the import specs by import path. + // Remove duplicates, when possible without data loss. + // Reassign the import paths to have the same position sequence. + // Reassign each comment to abut the end of its spec. + // Sort the comments by new position. + sort.Sort(byImportSpec{env, specs}) + + // Dedup. Thanks to our sorting, we can just consider + // adjacent pairs of imports. + deduped := specs[:0] + for i, s := range specs { + if i == len(specs)-1 || !collapse(s, specs[i+1]) { + deduped = append(deduped, s) + } else { + p := s.Pos() + fset.File(p).MergeLine(fset.Position(p).Line) + } + } + specs = deduped + + // Fix up comment positions + for i, s := range specs { + s := s.(*ast.ImportSpec) + if s.Name != nil { + s.Name.NamePos = pos[i].Start + } + s.Path.ValuePos = pos[i].Start + s.EndPos = pos[i].End + nextSpecPos := pos[i].End + + for _, g := range importComment[s] { + for _, c := range g.List { + c.Slash = pos[i].End + nextSpecPos = c.End() + } + } + if i < len(specs)-1 { + pos[i+1].Start = nextSpecPos + pos[i+1].End = nextSpecPos + } + } + + sort.Sort(byCommentPos(comments)) + + // Fixup comments can insert blank lines, because import specs are on different lines. + // We remove those blank lines here by merging import spec to the first import spec line. + firstSpecLine := fset.Position(specs[0].Pos()).Line + for _, s := range specs[1:] { + p := s.Pos() + line := fset.File(p).Line(p) + for previousLine := line - 1; previousLine >= firstSpecLine; { + fset.File(p).MergeLine(previousLine) + previousLine-- + } + } + return specs +} + +type byImportSpec struct { + env *ProcessEnv + specs []ast.Spec // slice of *ast.ImportSpec +} + +func (x byImportSpec) Len() int { return len(x.specs) } +func (x byImportSpec) Swap(i, j int) { x.specs[i], x.specs[j] = x.specs[j], x.specs[i] } +func (x byImportSpec) Less(i, j int) bool { + ipath := importPath(x.specs[i]) + jpath := importPath(x.specs[j]) + + igroup := importGroup(x.env, ipath) + jgroup := importGroup(x.env, jpath) + if igroup != jgroup { + return igroup < jgroup + } + + if ipath != jpath { + return ipath < jpath + } + iname := importName(x.specs[i]) + jname := importName(x.specs[j]) + + if iname != jname { + return iname < jname + } + return importComment(x.specs[i]) < importComment(x.specs[j]) +} + +type byCommentPos []*ast.CommentGroup + +func (x byCommentPos) Len() int { return len(x) } +func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/vendor/golang.org/x/tools/internal/imports/zstdlib.go new file mode 100644 index 0000000000..d81b8c5307 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/imports/zstdlib.go @@ -0,0 +1,10325 @@ +// Code generated by mkstdlib.go. DO NOT EDIT. + +package imports + +var stdlib = map[string]map[string]bool{ + "archive/tar": map[string]bool{ + "ErrFieldTooLong": true, + "ErrHeader": true, + "ErrWriteAfterClose": true, + "ErrWriteTooLong": true, + "FileInfoHeader": true, + "Format": true, + "FormatGNU": true, + "FormatPAX": true, + "FormatUSTAR": true, + "FormatUnknown": true, + "Header": true, + "NewReader": true, + "NewWriter": true, + "Reader": true, + "TypeBlock": true, + "TypeChar": true, + "TypeCont": true, + "TypeDir": true, + "TypeFifo": true, + "TypeGNULongLink": true, + "TypeGNULongName": true, + "TypeGNUSparse": true, + "TypeLink": true, + "TypeReg": true, + "TypeRegA": true, + "TypeSymlink": true, + "TypeXGlobalHeader": true, + "TypeXHeader": true, + "Writer": true, + }, + "archive/zip": map[string]bool{ + "Compressor": true, + "Decompressor": true, + "Deflate": true, + "ErrAlgorithm": true, + "ErrChecksum": true, + "ErrFormat": true, + "File": true, + "FileHeader": true, + "FileInfoHeader": true, + "NewReader": true, + "NewWriter": true, + "OpenReader": true, + "ReadCloser": true, + "Reader": true, + "RegisterCompressor": true, + "RegisterDecompressor": true, + "Store": true, + "Writer": true, + }, + "bufio": map[string]bool{ + "ErrAdvanceTooFar": true, + "ErrBufferFull": true, + "ErrFinalToken": true, + "ErrInvalidUnreadByte": true, + "ErrInvalidUnreadRune": true, + "ErrNegativeAdvance": true, + "ErrNegativeCount": true, + "ErrTooLong": true, + "MaxScanTokenSize": true, + "NewReadWriter": true, + "NewReader": true, + "NewReaderSize": true, + "NewScanner": true, + "NewWriter": true, + "NewWriterSize": true, + "ReadWriter": true, + "Reader": true, + "ScanBytes": true, + "ScanLines": true, + "ScanRunes": true, + "ScanWords": true, + "Scanner": true, + "SplitFunc": true, + "Writer": true, + }, + "bytes": map[string]bool{ + "Buffer": true, + "Compare": true, + "Contains": true, + "ContainsAny": true, + "ContainsRune": true, + "Count": true, + "Equal": true, + "EqualFold": true, + "ErrTooLarge": true, + "Fields": true, + "FieldsFunc": true, + "HasPrefix": true, + "HasSuffix": true, + "Index": true, + "IndexAny": true, + "IndexByte": true, + "IndexFunc": true, + "IndexRune": true, + "Join": true, + "LastIndex": true, + "LastIndexAny": true, + "LastIndexByte": true, + "LastIndexFunc": true, + "Map": true, + "MinRead": true, + "NewBuffer": true, + "NewBufferString": true, + "NewReader": true, + "Reader": true, + "Repeat": true, + "Replace": true, + "ReplaceAll": true, + "Runes": true, + "Split": true, + "SplitAfter": true, + "SplitAfterN": true, + "SplitN": true, + "Title": true, + "ToLower": true, + "ToLowerSpecial": true, + "ToTitle": true, + "ToTitleSpecial": true, + "ToUpper": true, + "ToUpperSpecial": true, + "Trim": true, + "TrimFunc": true, + "TrimLeft": true, + "TrimLeftFunc": true, + "TrimPrefix": true, + "TrimRight": true, + "TrimRightFunc": true, + "TrimSpace": true, + "TrimSuffix": true, + }, + "compress/bzip2": map[string]bool{ + "NewReader": true, + "StructuralError": true, + }, + "compress/flate": map[string]bool{ + "BestCompression": true, + "BestSpeed": true, + "CorruptInputError": true, + "DefaultCompression": true, + "HuffmanOnly": true, + "InternalError": true, + "NewReader": true, + "NewReaderDict": true, + "NewWriter": true, + "NewWriterDict": true, + "NoCompression": true, + "ReadError": true, + "Reader": true, + "Resetter": true, + "WriteError": true, + "Writer": true, + }, + "compress/gzip": map[string]bool{ + "BestCompression": true, + "BestSpeed": true, + "DefaultCompression": true, + "ErrChecksum": true, + "ErrHeader": true, + "Header": true, + "HuffmanOnly": true, + "NewReader": true, + "NewWriter": true, + "NewWriterLevel": true, + "NoCompression": true, + "Reader": true, + "Writer": true, + }, + "compress/lzw": map[string]bool{ + "LSB": true, + "MSB": true, + "NewReader": true, + "NewWriter": true, + "Order": true, + }, + "compress/zlib": map[string]bool{ + "BestCompression": true, + "BestSpeed": true, + "DefaultCompression": true, + "ErrChecksum": true, + "ErrDictionary": true, + "ErrHeader": true, + "HuffmanOnly": true, + "NewReader": true, + "NewReaderDict": true, + "NewWriter": true, + "NewWriterLevel": true, + "NewWriterLevelDict": true, + "NoCompression": true, + "Resetter": true, + "Writer": true, + }, + "container/heap": map[string]bool{ + "Fix": true, + "Init": true, + "Interface": true, + "Pop": true, + "Push": true, + "Remove": true, + }, + "container/list": map[string]bool{ + "Element": true, + "List": true, + "New": true, + }, + "container/ring": map[string]bool{ + "New": true, + "Ring": true, + }, + "context": map[string]bool{ + "Background": true, + "CancelFunc": true, + "Canceled": true, + "Context": true, + "DeadlineExceeded": true, + "TODO": true, + "WithCancel": true, + "WithDeadline": true, + "WithTimeout": true, + "WithValue": true, + }, + "crypto": map[string]bool{ + "BLAKE2b_256": true, + "BLAKE2b_384": true, + "BLAKE2b_512": true, + "BLAKE2s_256": true, + "Decrypter": true, + "DecrypterOpts": true, + "Hash": true, + "MD4": true, + "MD5": true, + "MD5SHA1": true, + "PrivateKey": true, + "PublicKey": true, + "RIPEMD160": true, + "RegisterHash": true, + "SHA1": true, + "SHA224": true, + "SHA256": true, + "SHA384": true, + "SHA3_224": true, + "SHA3_256": true, + "SHA3_384": true, + "SHA3_512": true, + "SHA512": true, + "SHA512_224": true, + "SHA512_256": true, + "Signer": true, + "SignerOpts": true, + }, + "crypto/aes": map[string]bool{ + "BlockSize": true, + "KeySizeError": true, + "NewCipher": true, + }, + "crypto/cipher": map[string]bool{ + "AEAD": true, + "Block": true, + "BlockMode": true, + "NewCBCDecrypter": true, + "NewCBCEncrypter": true, + "NewCFBDecrypter": true, + "NewCFBEncrypter": true, + "NewCTR": true, + "NewGCM": true, + "NewGCMWithNonceSize": true, + "NewGCMWithTagSize": true, + "NewOFB": true, + "Stream": true, + "StreamReader": true, + "StreamWriter": true, + }, + "crypto/des": map[string]bool{ + "BlockSize": true, + "KeySizeError": true, + "NewCipher": true, + "NewTripleDESCipher": true, + }, + "crypto/dsa": map[string]bool{ + "ErrInvalidPublicKey": true, + "GenerateKey": true, + "GenerateParameters": true, + "L1024N160": true, + "L2048N224": true, + "L2048N256": true, + "L3072N256": true, + "ParameterSizes": true, + "Parameters": true, + "PrivateKey": true, + "PublicKey": true, + "Sign": true, + "Verify": true, + }, + "crypto/ecdsa": map[string]bool{ + "GenerateKey": true, + "PrivateKey": true, + "PublicKey": true, + "Sign": true, + "Verify": true, + }, + "crypto/elliptic": map[string]bool{ + "Curve": true, + "CurveParams": true, + "GenerateKey": true, + "Marshal": true, + "P224": true, + "P256": true, + "P384": true, + "P521": true, + "Unmarshal": true, + }, + "crypto/hmac": map[string]bool{ + "Equal": true, + "New": true, + }, + "crypto/md5": map[string]bool{ + "BlockSize": true, + "New": true, + "Size": true, + "Sum": true, + }, + "crypto/rand": map[string]bool{ + "Int": true, + "Prime": true, + "Read": true, + "Reader": true, + }, + "crypto/rc4": map[string]bool{ + "Cipher": true, + "KeySizeError": true, + "NewCipher": true, + }, + "crypto/rsa": map[string]bool{ + "CRTValue": true, + "DecryptOAEP": true, + "DecryptPKCS1v15": true, + "DecryptPKCS1v15SessionKey": true, + "EncryptOAEP": true, + "EncryptPKCS1v15": true, + "ErrDecryption": true, + "ErrMessageTooLong": true, + "ErrVerification": true, + "GenerateKey": true, + "GenerateMultiPrimeKey": true, + "OAEPOptions": true, + "PKCS1v15DecryptOptions": true, + "PSSOptions": true, + "PSSSaltLengthAuto": true, + "PSSSaltLengthEqualsHash": true, + "PrecomputedValues": true, + "PrivateKey": true, + "PublicKey": true, + "SignPKCS1v15": true, + "SignPSS": true, + "VerifyPKCS1v15": true, + "VerifyPSS": true, + }, + "crypto/sha1": map[string]bool{ + "BlockSize": true, + "New": true, + "Size": true, + "Sum": true, + }, + "crypto/sha256": map[string]bool{ + "BlockSize": true, + "New": true, + "New224": true, + "Size": true, + "Size224": true, + "Sum224": true, + "Sum256": true, + }, + "crypto/sha512": map[string]bool{ + "BlockSize": true, + "New": true, + "New384": true, + "New512_224": true, + "New512_256": true, + "Size": true, + "Size224": true, + "Size256": true, + "Size384": true, + "Sum384": true, + "Sum512": true, + "Sum512_224": true, + "Sum512_256": true, + }, + "crypto/subtle": map[string]bool{ + "ConstantTimeByteEq": true, + "ConstantTimeCompare": true, + "ConstantTimeCopy": true, + "ConstantTimeEq": true, + "ConstantTimeLessOrEq": true, + "ConstantTimeSelect": true, + }, + "crypto/tls": map[string]bool{ + "Certificate": true, + "CertificateRequestInfo": true, + "Client": true, + "ClientAuthType": true, + "ClientHelloInfo": true, + "ClientSessionCache": true, + "ClientSessionState": true, + "Config": true, + "Conn": true, + "ConnectionState": true, + "CurveID": true, + "CurveP256": true, + "CurveP384": true, + "CurveP521": true, + "Dial": true, + "DialWithDialer": true, + "ECDSAWithP256AndSHA256": true, + "ECDSAWithP384AndSHA384": true, + "ECDSAWithP521AndSHA512": true, + "ECDSAWithSHA1": true, + "Listen": true, + "LoadX509KeyPair": true, + "NewLRUClientSessionCache": true, + "NewListener": true, + "NoClientCert": true, + "PKCS1WithSHA1": true, + "PKCS1WithSHA256": true, + "PKCS1WithSHA384": true, + "PKCS1WithSHA512": true, + "PSSWithSHA256": true, + "PSSWithSHA384": true, + "PSSWithSHA512": true, + "RecordHeaderError": true, + "RenegotiateFreelyAsClient": true, + "RenegotiateNever": true, + "RenegotiateOnceAsClient": true, + "RenegotiationSupport": true, + "RequestClientCert": true, + "RequireAndVerifyClientCert": true, + "RequireAnyClientCert": true, + "Server": true, + "SignatureScheme": true, + "TLS_AES_128_GCM_SHA256": true, + "TLS_AES_256_GCM_SHA384": true, + "TLS_CHACHA20_POLY1305_SHA256": true, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": true, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": true, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": true, + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": true, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": true, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": true, + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": true, + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": true, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": true, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": true, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": true, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": true, + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": true, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": true, + "TLS_ECDHE_RSA_WITH_RC4_128_SHA": true, + "TLS_FALLBACK_SCSV": true, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA": true, + "TLS_RSA_WITH_AES_128_CBC_SHA": true, + "TLS_RSA_WITH_AES_128_CBC_SHA256": true, + "TLS_RSA_WITH_AES_128_GCM_SHA256": true, + "TLS_RSA_WITH_AES_256_CBC_SHA": true, + "TLS_RSA_WITH_AES_256_GCM_SHA384": true, + "TLS_RSA_WITH_RC4_128_SHA": true, + "VerifyClientCertIfGiven": true, + "VersionSSL30": true, + "VersionTLS10": true, + "VersionTLS11": true, + "VersionTLS12": true, + "VersionTLS13": true, + "X25519": true, + "X509KeyPair": true, + }, + "crypto/x509": map[string]bool{ + "CANotAuthorizedForExtKeyUsage": true, + "CANotAuthorizedForThisName": true, + "CertPool": true, + "Certificate": true, + "CertificateInvalidError": true, + "CertificateRequest": true, + "ConstraintViolationError": true, + "CreateCertificate": true, + "CreateCertificateRequest": true, + "DSA": true, + "DSAWithSHA1": true, + "DSAWithSHA256": true, + "DecryptPEMBlock": true, + "ECDSA": true, + "ECDSAWithSHA1": true, + "ECDSAWithSHA256": true, + "ECDSAWithSHA384": true, + "ECDSAWithSHA512": true, + "EncryptPEMBlock": true, + "ErrUnsupportedAlgorithm": true, + "Expired": true, + "ExtKeyUsage": true, + "ExtKeyUsageAny": true, + "ExtKeyUsageClientAuth": true, + "ExtKeyUsageCodeSigning": true, + "ExtKeyUsageEmailProtection": true, + "ExtKeyUsageIPSECEndSystem": true, + "ExtKeyUsageIPSECTunnel": true, + "ExtKeyUsageIPSECUser": true, + "ExtKeyUsageMicrosoftCommercialCodeSigning": true, + "ExtKeyUsageMicrosoftKernelCodeSigning": true, + "ExtKeyUsageMicrosoftServerGatedCrypto": true, + "ExtKeyUsageNetscapeServerGatedCrypto": true, + "ExtKeyUsageOCSPSigning": true, + "ExtKeyUsageServerAuth": true, + "ExtKeyUsageTimeStamping": true, + "HostnameError": true, + "IncompatibleUsage": true, + "IncorrectPasswordError": true, + "InsecureAlgorithmError": true, + "InvalidReason": true, + "IsEncryptedPEMBlock": true, + "KeyUsage": true, + "KeyUsageCRLSign": true, + "KeyUsageCertSign": true, + "KeyUsageContentCommitment": true, + "KeyUsageDataEncipherment": true, + "KeyUsageDecipherOnly": true, + "KeyUsageDigitalSignature": true, + "KeyUsageEncipherOnly": true, + "KeyUsageKeyAgreement": true, + "KeyUsageKeyEncipherment": true, + "MD2WithRSA": true, + "MD5WithRSA": true, + "MarshalECPrivateKey": true, + "MarshalPKCS1PrivateKey": true, + "MarshalPKCS1PublicKey": true, + "MarshalPKCS8PrivateKey": true, + "MarshalPKIXPublicKey": true, + "NameConstraintsWithoutSANs": true, + "NameMismatch": true, + "NewCertPool": true, + "NotAuthorizedToSign": true, + "PEMCipher": true, + "PEMCipher3DES": true, + "PEMCipherAES128": true, + "PEMCipherAES192": true, + "PEMCipherAES256": true, + "PEMCipherDES": true, + "ParseCRL": true, + "ParseCertificate": true, + "ParseCertificateRequest": true, + "ParseCertificates": true, + "ParseDERCRL": true, + "ParseECPrivateKey": true, + "ParsePKCS1PrivateKey": true, + "ParsePKCS1PublicKey": true, + "ParsePKCS8PrivateKey": true, + "ParsePKIXPublicKey": true, + "PublicKeyAlgorithm": true, + "RSA": true, + "SHA1WithRSA": true, + "SHA256WithRSA": true, + "SHA256WithRSAPSS": true, + "SHA384WithRSA": true, + "SHA384WithRSAPSS": true, + "SHA512WithRSA": true, + "SHA512WithRSAPSS": true, + "SignatureAlgorithm": true, + "SystemCertPool": true, + "SystemRootsError": true, + "TooManyConstraints": true, + "TooManyIntermediates": true, + "UnconstrainedName": true, + "UnhandledCriticalExtension": true, + "UnknownAuthorityError": true, + "UnknownPublicKeyAlgorithm": true, + "UnknownSignatureAlgorithm": true, + "VerifyOptions": true, + }, + "crypto/x509/pkix": map[string]bool{ + "AlgorithmIdentifier": true, + "AttributeTypeAndValue": true, + "AttributeTypeAndValueSET": true, + "CertificateList": true, + "Extension": true, + "Name": true, + "RDNSequence": true, + "RelativeDistinguishedNameSET": true, + "RevokedCertificate": true, + "TBSCertificateList": true, + }, + "database/sql": map[string]bool{ + "ColumnType": true, + "Conn": true, + "DB": true, + "DBStats": true, + "Drivers": true, + "ErrConnDone": true, + "ErrNoRows": true, + "ErrTxDone": true, + "IsolationLevel": true, + "LevelDefault": true, + "LevelLinearizable": true, + "LevelReadCommitted": true, + "LevelReadUncommitted": true, + "LevelRepeatableRead": true, + "LevelSerializable": true, + "LevelSnapshot": true, + "LevelWriteCommitted": true, + "Named": true, + "NamedArg": true, + "NullBool": true, + "NullFloat64": true, + "NullInt64": true, + "NullString": true, + "Open": true, + "OpenDB": true, + "Out": true, + "RawBytes": true, + "Register": true, + "Result": true, + "Row": true, + "Rows": true, + "Scanner": true, + "Stmt": true, + "Tx": true, + "TxOptions": true, + }, + "database/sql/driver": map[string]bool{ + "Bool": true, + "ColumnConverter": true, + "Conn": true, + "ConnBeginTx": true, + "ConnPrepareContext": true, + "Connector": true, + "DefaultParameterConverter": true, + "Driver": true, + "DriverContext": true, + "ErrBadConn": true, + "ErrRemoveArgument": true, + "ErrSkip": true, + "Execer": true, + "ExecerContext": true, + "Int32": true, + "IsScanValue": true, + "IsValue": true, + "IsolationLevel": true, + "NamedValue": true, + "NamedValueChecker": true, + "NotNull": true, + "Null": true, + "Pinger": true, + "Queryer": true, + "QueryerContext": true, + "Result": true, + "ResultNoRows": true, + "Rows": true, + "RowsAffected": true, + "RowsColumnTypeDatabaseTypeName": true, + "RowsColumnTypeLength": true, + "RowsColumnTypeNullable": true, + "RowsColumnTypePrecisionScale": true, + "RowsColumnTypeScanType": true, + "RowsNextResultSet": true, + "SessionResetter": true, + "Stmt": true, + "StmtExecContext": true, + "StmtQueryContext": true, + "String": true, + "Tx": true, + "TxOptions": true, + "Value": true, + "ValueConverter": true, + "Valuer": true, + }, + "debug/dwarf": map[string]bool{ + "AddrType": true, + "ArrayType": true, + "Attr": true, + "AttrAbstractOrigin": true, + "AttrAccessibility": true, + "AttrAddrClass": true, + "AttrAllocated": true, + "AttrArtificial": true, + "AttrAssociated": true, + "AttrBaseTypes": true, + "AttrBitOffset": true, + "AttrBitSize": true, + "AttrByteSize": true, + "AttrCallColumn": true, + "AttrCallFile": true, + "AttrCallLine": true, + "AttrCalling": true, + "AttrCommonRef": true, + "AttrCompDir": true, + "AttrConstValue": true, + "AttrContainingType": true, + "AttrCount": true, + "AttrDataLocation": true, + "AttrDataMemberLoc": true, + "AttrDeclColumn": true, + "AttrDeclFile": true, + "AttrDeclLine": true, + "AttrDeclaration": true, + "AttrDefaultValue": true, + "AttrDescription": true, + "AttrDiscr": true, + "AttrDiscrList": true, + "AttrDiscrValue": true, + "AttrEncoding": true, + "AttrEntrypc": true, + "AttrExtension": true, + "AttrExternal": true, + "AttrFrameBase": true, + "AttrFriend": true, + "AttrHighpc": true, + "AttrIdentifierCase": true, + "AttrImport": true, + "AttrInline": true, + "AttrIsOptional": true, + "AttrLanguage": true, + "AttrLocation": true, + "AttrLowerBound": true, + "AttrLowpc": true, + "AttrMacroInfo": true, + "AttrName": true, + "AttrNamelistItem": true, + "AttrOrdering": true, + "AttrPriority": true, + "AttrProducer": true, + "AttrPrototyped": true, + "AttrRanges": true, + "AttrReturnAddr": true, + "AttrSegment": true, + "AttrSibling": true, + "AttrSpecification": true, + "AttrStartScope": true, + "AttrStaticLink": true, + "AttrStmtList": true, + "AttrStride": true, + "AttrStrideSize": true, + "AttrStringLength": true, + "AttrTrampoline": true, + "AttrType": true, + "AttrUpperBound": true, + "AttrUseLocation": true, + "AttrUseUTF8": true, + "AttrVarParam": true, + "AttrVirtuality": true, + "AttrVisibility": true, + "AttrVtableElemLoc": true, + "BasicType": true, + "BoolType": true, + "CharType": true, + "Class": true, + "ClassAddress": true, + "ClassBlock": true, + "ClassConstant": true, + "ClassExprLoc": true, + "ClassFlag": true, + "ClassLinePtr": true, + "ClassLocListPtr": true, + "ClassMacPtr": true, + "ClassRangeListPtr": true, + "ClassReference": true, + "ClassReferenceAlt": true, + "ClassReferenceSig": true, + "ClassString": true, + "ClassStringAlt": true, + "ClassUnknown": true, + "CommonType": true, + "ComplexType": true, + "Data": true, + "DecodeError": true, + "DotDotDotType": true, + "Entry": true, + "EnumType": true, + "EnumValue": true, + "ErrUnknownPC": true, + "Field": true, + "FloatType": true, + "FuncType": true, + "IntType": true, + "LineEntry": true, + "LineFile": true, + "LineReader": true, + "LineReaderPos": true, + "New": true, + "Offset": true, + "PtrType": true, + "QualType": true, + "Reader": true, + "StructField": true, + "StructType": true, + "Tag": true, + "TagAccessDeclaration": true, + "TagArrayType": true, + "TagBaseType": true, + "TagCatchDwarfBlock": true, + "TagClassType": true, + "TagCommonDwarfBlock": true, + "TagCommonInclusion": true, + "TagCompileUnit": true, + "TagCondition": true, + "TagConstType": true, + "TagConstant": true, + "TagDwarfProcedure": true, + "TagEntryPoint": true, + "TagEnumerationType": true, + "TagEnumerator": true, + "TagFileType": true, + "TagFormalParameter": true, + "TagFriend": true, + "TagImportedDeclaration": true, + "TagImportedModule": true, + "TagImportedUnit": true, + "TagInheritance": true, + "TagInlinedSubroutine": true, + "TagInterfaceType": true, + "TagLabel": true, + "TagLexDwarfBlock": true, + "TagMember": true, + "TagModule": true, + "TagMutableType": true, + "TagNamelist": true, + "TagNamelistItem": true, + "TagNamespace": true, + "TagPackedType": true, + "TagPartialUnit": true, + "TagPointerType": true, + "TagPtrToMemberType": true, + "TagReferenceType": true, + "TagRestrictType": true, + "TagRvalueReferenceType": true, + "TagSetType": true, + "TagSharedType": true, + "TagStringType": true, + "TagStructType": true, + "TagSubprogram": true, + "TagSubrangeType": true, + "TagSubroutineType": true, + "TagTemplateAlias": true, + "TagTemplateTypeParameter": true, + "TagTemplateValueParameter": true, + "TagThrownType": true, + "TagTryDwarfBlock": true, + "TagTypeUnit": true, + "TagTypedef": true, + "TagUnionType": true, + "TagUnspecifiedParameters": true, + "TagUnspecifiedType": true, + "TagVariable": true, + "TagVariant": true, + "TagVariantPart": true, + "TagVolatileType": true, + "TagWithStmt": true, + "Type": true, + "TypedefType": true, + "UcharType": true, + "UintType": true, + "UnspecifiedType": true, + "VoidType": true, + }, + "debug/elf": map[string]bool{ + "ARM_MAGIC_TRAMP_NUMBER": true, + "COMPRESS_HIOS": true, + "COMPRESS_HIPROC": true, + "COMPRESS_LOOS": true, + "COMPRESS_LOPROC": true, + "COMPRESS_ZLIB": true, + "Chdr32": true, + "Chdr64": true, + "Class": true, + "CompressionType": true, + "DF_BIND_NOW": true, + "DF_ORIGIN": true, + "DF_STATIC_TLS": true, + "DF_SYMBOLIC": true, + "DF_TEXTREL": true, + "DT_BIND_NOW": true, + "DT_DEBUG": true, + "DT_ENCODING": true, + "DT_FINI": true, + "DT_FINI_ARRAY": true, + "DT_FINI_ARRAYSZ": true, + "DT_FLAGS": true, + "DT_HASH": true, + "DT_HIOS": true, + "DT_HIPROC": true, + "DT_INIT": true, + "DT_INIT_ARRAY": true, + "DT_INIT_ARRAYSZ": true, + "DT_JMPREL": true, + "DT_LOOS": true, + "DT_LOPROC": true, + "DT_NEEDED": true, + "DT_NULL": true, + "DT_PLTGOT": true, + "DT_PLTREL": true, + "DT_PLTRELSZ": true, + "DT_PREINIT_ARRAY": true, + "DT_PREINIT_ARRAYSZ": true, + "DT_REL": true, + "DT_RELA": true, + "DT_RELAENT": true, + "DT_RELASZ": true, + "DT_RELENT": true, + "DT_RELSZ": true, + "DT_RPATH": true, + "DT_RUNPATH": true, + "DT_SONAME": true, + "DT_STRSZ": true, + "DT_STRTAB": true, + "DT_SYMBOLIC": true, + "DT_SYMENT": true, + "DT_SYMTAB": true, + "DT_TEXTREL": true, + "DT_VERNEED": true, + "DT_VERNEEDNUM": true, + "DT_VERSYM": true, + "Data": true, + "Dyn32": true, + "Dyn64": true, + "DynFlag": true, + "DynTag": true, + "EI_ABIVERSION": true, + "EI_CLASS": true, + "EI_DATA": true, + "EI_NIDENT": true, + "EI_OSABI": true, + "EI_PAD": true, + "EI_VERSION": true, + "ELFCLASS32": true, + "ELFCLASS64": true, + "ELFCLASSNONE": true, + "ELFDATA2LSB": true, + "ELFDATA2MSB": true, + "ELFDATANONE": true, + "ELFMAG": true, + "ELFOSABI_86OPEN": true, + "ELFOSABI_AIX": true, + "ELFOSABI_ARM": true, + "ELFOSABI_AROS": true, + "ELFOSABI_CLOUDABI": true, + "ELFOSABI_FENIXOS": true, + "ELFOSABI_FREEBSD": true, + "ELFOSABI_HPUX": true, + "ELFOSABI_HURD": true, + "ELFOSABI_IRIX": true, + "ELFOSABI_LINUX": true, + "ELFOSABI_MODESTO": true, + "ELFOSABI_NETBSD": true, + "ELFOSABI_NONE": true, + "ELFOSABI_NSK": true, + "ELFOSABI_OPENBSD": true, + "ELFOSABI_OPENVMS": true, + "ELFOSABI_SOLARIS": true, + "ELFOSABI_STANDALONE": true, + "ELFOSABI_TRU64": true, + "EM_386": true, + "EM_486": true, + "EM_56800EX": true, + "EM_68HC05": true, + "EM_68HC08": true, + "EM_68HC11": true, + "EM_68HC12": true, + "EM_68HC16": true, + "EM_68K": true, + "EM_78KOR": true, + "EM_8051": true, + "EM_860": true, + "EM_88K": true, + "EM_960": true, + "EM_AARCH64": true, + "EM_ALPHA": true, + "EM_ALPHA_STD": true, + "EM_ALTERA_NIOS2": true, + "EM_AMDGPU": true, + "EM_ARC": true, + "EM_ARCA": true, + "EM_ARC_COMPACT": true, + "EM_ARC_COMPACT2": true, + "EM_ARM": true, + "EM_AVR": true, + "EM_AVR32": true, + "EM_BA1": true, + "EM_BA2": true, + "EM_BLACKFIN": true, + "EM_BPF": true, + "EM_C166": true, + "EM_CDP": true, + "EM_CE": true, + "EM_CLOUDSHIELD": true, + "EM_COGE": true, + "EM_COLDFIRE": true, + "EM_COOL": true, + "EM_COREA_1ST": true, + "EM_COREA_2ND": true, + "EM_CR": true, + "EM_CR16": true, + "EM_CRAYNV2": true, + "EM_CRIS": true, + "EM_CRX": true, + "EM_CSR_KALIMBA": true, + "EM_CUDA": true, + "EM_CYPRESS_M8C": true, + "EM_D10V": true, + "EM_D30V": true, + "EM_DSP24": true, + "EM_DSPIC30F": true, + "EM_DXP": true, + "EM_ECOG1": true, + "EM_ECOG16": true, + "EM_ECOG1X": true, + "EM_ECOG2": true, + "EM_ETPU": true, + "EM_EXCESS": true, + "EM_F2MC16": true, + "EM_FIREPATH": true, + "EM_FR20": true, + "EM_FR30": true, + "EM_FT32": true, + "EM_FX66": true, + "EM_H8S": true, + "EM_H8_300": true, + "EM_H8_300H": true, + "EM_H8_500": true, + "EM_HUANY": true, + "EM_IA_64": true, + "EM_INTEL205": true, + "EM_INTEL206": true, + "EM_INTEL207": true, + "EM_INTEL208": true, + "EM_INTEL209": true, + "EM_IP2K": true, + "EM_JAVELIN": true, + "EM_K10M": true, + "EM_KM32": true, + "EM_KMX16": true, + "EM_KMX32": true, + "EM_KMX8": true, + "EM_KVARC": true, + "EM_L10M": true, + "EM_LANAI": true, + "EM_LATTICEMICO32": true, + "EM_M16C": true, + "EM_M32": true, + "EM_M32C": true, + "EM_M32R": true, + "EM_MANIK": true, + "EM_MAX": true, + "EM_MAXQ30": true, + "EM_MCHP_PIC": true, + "EM_MCST_ELBRUS": true, + "EM_ME16": true, + "EM_METAG": true, + "EM_MICROBLAZE": true, + "EM_MIPS": true, + "EM_MIPS_RS3_LE": true, + "EM_MIPS_RS4_BE": true, + "EM_MIPS_X": true, + "EM_MMA": true, + "EM_MMDSP_PLUS": true, + "EM_MMIX": true, + "EM_MN10200": true, + "EM_MN10300": true, + "EM_MOXIE": true, + "EM_MSP430": true, + "EM_NCPU": true, + "EM_NDR1": true, + "EM_NDS32": true, + "EM_NONE": true, + "EM_NORC": true, + "EM_NS32K": true, + "EM_OPEN8": true, + "EM_OPENRISC": true, + "EM_PARISC": true, + "EM_PCP": true, + "EM_PDP10": true, + "EM_PDP11": true, + "EM_PDSP": true, + "EM_PJ": true, + "EM_PPC": true, + "EM_PPC64": true, + "EM_PRISM": true, + "EM_QDSP6": true, + "EM_R32C": true, + "EM_RCE": true, + "EM_RH32": true, + "EM_RISCV": true, + "EM_RL78": true, + "EM_RS08": true, + "EM_RX": true, + "EM_S370": true, + "EM_S390": true, + "EM_SCORE7": true, + "EM_SEP": true, + "EM_SE_C17": true, + "EM_SE_C33": true, + "EM_SH": true, + "EM_SHARC": true, + "EM_SLE9X": true, + "EM_SNP1K": true, + "EM_SPARC": true, + "EM_SPARC32PLUS": true, + "EM_SPARCV9": true, + "EM_ST100": true, + "EM_ST19": true, + "EM_ST200": true, + "EM_ST7": true, + "EM_ST9PLUS": true, + "EM_STARCORE": true, + "EM_STM8": true, + "EM_STXP7X": true, + "EM_SVX": true, + "EM_TILE64": true, + "EM_TILEGX": true, + "EM_TILEPRO": true, + "EM_TINYJ": true, + "EM_TI_ARP32": true, + "EM_TI_C2000": true, + "EM_TI_C5500": true, + "EM_TI_C6000": true, + "EM_TI_PRU": true, + "EM_TMM_GPP": true, + "EM_TPC": true, + "EM_TRICORE": true, + "EM_TRIMEDIA": true, + "EM_TSK3000": true, + "EM_UNICORE": true, + "EM_V800": true, + "EM_V850": true, + "EM_VAX": true, + "EM_VIDEOCORE": true, + "EM_VIDEOCORE3": true, + "EM_VIDEOCORE5": true, + "EM_VISIUM": true, + "EM_VPP500": true, + "EM_X86_64": true, + "EM_XCORE": true, + "EM_XGATE": true, + "EM_XIMO16": true, + "EM_XTENSA": true, + "EM_Z80": true, + "EM_ZSP": true, + "ET_CORE": true, + "ET_DYN": true, + "ET_EXEC": true, + "ET_HIOS": true, + "ET_HIPROC": true, + "ET_LOOS": true, + "ET_LOPROC": true, + "ET_NONE": true, + "ET_REL": true, + "EV_CURRENT": true, + "EV_NONE": true, + "ErrNoSymbols": true, + "File": true, + "FileHeader": true, + "FormatError": true, + "Header32": true, + "Header64": true, + "ImportedSymbol": true, + "Machine": true, + "NT_FPREGSET": true, + "NT_PRPSINFO": true, + "NT_PRSTATUS": true, + "NType": true, + "NewFile": true, + "OSABI": true, + "Open": true, + "PF_MASKOS": true, + "PF_MASKPROC": true, + "PF_R": true, + "PF_W": true, + "PF_X": true, + "PT_DYNAMIC": true, + "PT_HIOS": true, + "PT_HIPROC": true, + "PT_INTERP": true, + "PT_LOAD": true, + "PT_LOOS": true, + "PT_LOPROC": true, + "PT_NOTE": true, + "PT_NULL": true, + "PT_PHDR": true, + "PT_SHLIB": true, + "PT_TLS": true, + "Prog": true, + "Prog32": true, + "Prog64": true, + "ProgFlag": true, + "ProgHeader": true, + "ProgType": true, + "R_386": true, + "R_386_16": true, + "R_386_32": true, + "R_386_32PLT": true, + "R_386_8": true, + "R_386_COPY": true, + "R_386_GLOB_DAT": true, + "R_386_GOT32": true, + "R_386_GOT32X": true, + "R_386_GOTOFF": true, + "R_386_GOTPC": true, + "R_386_IRELATIVE": true, + "R_386_JMP_SLOT": true, + "R_386_NONE": true, + "R_386_PC16": true, + "R_386_PC32": true, + "R_386_PC8": true, + "R_386_PLT32": true, + "R_386_RELATIVE": true, + "R_386_SIZE32": true, + "R_386_TLS_DESC": true, + "R_386_TLS_DESC_CALL": true, + "R_386_TLS_DTPMOD32": true, + "R_386_TLS_DTPOFF32": true, + "R_386_TLS_GD": true, + "R_386_TLS_GD_32": true, + "R_386_TLS_GD_CALL": true, + "R_386_TLS_GD_POP": true, + "R_386_TLS_GD_PUSH": true, + "R_386_TLS_GOTDESC": true, + "R_386_TLS_GOTIE": true, + "R_386_TLS_IE": true, + "R_386_TLS_IE_32": true, + "R_386_TLS_LDM": true, + "R_386_TLS_LDM_32": true, + "R_386_TLS_LDM_CALL": true, + "R_386_TLS_LDM_POP": true, + "R_386_TLS_LDM_PUSH": true, + "R_386_TLS_LDO_32": true, + "R_386_TLS_LE": true, + "R_386_TLS_LE_32": true, + "R_386_TLS_TPOFF": true, + "R_386_TLS_TPOFF32": true, + "R_390": true, + "R_390_12": true, + "R_390_16": true, + "R_390_20": true, + "R_390_32": true, + "R_390_64": true, + "R_390_8": true, + "R_390_COPY": true, + "R_390_GLOB_DAT": true, + "R_390_GOT12": true, + "R_390_GOT16": true, + "R_390_GOT20": true, + "R_390_GOT32": true, + "R_390_GOT64": true, + "R_390_GOTENT": true, + "R_390_GOTOFF": true, + "R_390_GOTOFF16": true, + "R_390_GOTOFF64": true, + "R_390_GOTPC": true, + "R_390_GOTPCDBL": true, + "R_390_GOTPLT12": true, + "R_390_GOTPLT16": true, + "R_390_GOTPLT20": true, + "R_390_GOTPLT32": true, + "R_390_GOTPLT64": true, + "R_390_GOTPLTENT": true, + "R_390_GOTPLTOFF16": true, + "R_390_GOTPLTOFF32": true, + "R_390_GOTPLTOFF64": true, + "R_390_JMP_SLOT": true, + "R_390_NONE": true, + "R_390_PC16": true, + "R_390_PC16DBL": true, + "R_390_PC32": true, + "R_390_PC32DBL": true, + "R_390_PC64": true, + "R_390_PLT16DBL": true, + "R_390_PLT32": true, + "R_390_PLT32DBL": true, + "R_390_PLT64": true, + "R_390_RELATIVE": true, + "R_390_TLS_DTPMOD": true, + "R_390_TLS_DTPOFF": true, + "R_390_TLS_GD32": true, + "R_390_TLS_GD64": true, + "R_390_TLS_GDCALL": true, + "R_390_TLS_GOTIE12": true, + "R_390_TLS_GOTIE20": true, + "R_390_TLS_GOTIE32": true, + "R_390_TLS_GOTIE64": true, + "R_390_TLS_IE32": true, + "R_390_TLS_IE64": true, + "R_390_TLS_IEENT": true, + "R_390_TLS_LDCALL": true, + "R_390_TLS_LDM32": true, + "R_390_TLS_LDM64": true, + "R_390_TLS_LDO32": true, + "R_390_TLS_LDO64": true, + "R_390_TLS_LE32": true, + "R_390_TLS_LE64": true, + "R_390_TLS_LOAD": true, + "R_390_TLS_TPOFF": true, + "R_AARCH64": true, + "R_AARCH64_ABS16": true, + "R_AARCH64_ABS32": true, + "R_AARCH64_ABS64": true, + "R_AARCH64_ADD_ABS_LO12_NC": true, + "R_AARCH64_ADR_GOT_PAGE": true, + "R_AARCH64_ADR_PREL_LO21": true, + "R_AARCH64_ADR_PREL_PG_HI21": true, + "R_AARCH64_ADR_PREL_PG_HI21_NC": true, + "R_AARCH64_CALL26": true, + "R_AARCH64_CONDBR19": true, + "R_AARCH64_COPY": true, + "R_AARCH64_GLOB_DAT": true, + "R_AARCH64_GOT_LD_PREL19": true, + "R_AARCH64_IRELATIVE": true, + "R_AARCH64_JUMP26": true, + "R_AARCH64_JUMP_SLOT": true, + "R_AARCH64_LD64_GOTOFF_LO15": true, + "R_AARCH64_LD64_GOTPAGE_LO15": true, + "R_AARCH64_LD64_GOT_LO12_NC": true, + "R_AARCH64_LDST128_ABS_LO12_NC": true, + "R_AARCH64_LDST16_ABS_LO12_NC": true, + "R_AARCH64_LDST32_ABS_LO12_NC": true, + "R_AARCH64_LDST64_ABS_LO12_NC": true, + "R_AARCH64_LDST8_ABS_LO12_NC": true, + "R_AARCH64_LD_PREL_LO19": true, + "R_AARCH64_MOVW_SABS_G0": true, + "R_AARCH64_MOVW_SABS_G1": true, + "R_AARCH64_MOVW_SABS_G2": true, + "R_AARCH64_MOVW_UABS_G0": true, + "R_AARCH64_MOVW_UABS_G0_NC": true, + "R_AARCH64_MOVW_UABS_G1": true, + "R_AARCH64_MOVW_UABS_G1_NC": true, + "R_AARCH64_MOVW_UABS_G2": true, + "R_AARCH64_MOVW_UABS_G2_NC": true, + "R_AARCH64_MOVW_UABS_G3": true, + "R_AARCH64_NONE": true, + "R_AARCH64_NULL": true, + "R_AARCH64_P32_ABS16": true, + "R_AARCH64_P32_ABS32": true, + "R_AARCH64_P32_ADD_ABS_LO12_NC": true, + "R_AARCH64_P32_ADR_GOT_PAGE": true, + "R_AARCH64_P32_ADR_PREL_LO21": true, + "R_AARCH64_P32_ADR_PREL_PG_HI21": true, + "R_AARCH64_P32_CALL26": true, + "R_AARCH64_P32_CONDBR19": true, + "R_AARCH64_P32_COPY": true, + "R_AARCH64_P32_GLOB_DAT": true, + "R_AARCH64_P32_GOT_LD_PREL19": true, + "R_AARCH64_P32_IRELATIVE": true, + "R_AARCH64_P32_JUMP26": true, + "R_AARCH64_P32_JUMP_SLOT": true, + "R_AARCH64_P32_LD32_GOT_LO12_NC": true, + "R_AARCH64_P32_LDST128_ABS_LO12_NC": true, + "R_AARCH64_P32_LDST16_ABS_LO12_NC": true, + "R_AARCH64_P32_LDST32_ABS_LO12_NC": true, + "R_AARCH64_P32_LDST64_ABS_LO12_NC": true, + "R_AARCH64_P32_LDST8_ABS_LO12_NC": true, + "R_AARCH64_P32_LD_PREL_LO19": true, + "R_AARCH64_P32_MOVW_SABS_G0": true, + "R_AARCH64_P32_MOVW_UABS_G0": true, + "R_AARCH64_P32_MOVW_UABS_G0_NC": true, + "R_AARCH64_P32_MOVW_UABS_G1": true, + "R_AARCH64_P32_PREL16": true, + "R_AARCH64_P32_PREL32": true, + "R_AARCH64_P32_RELATIVE": true, + "R_AARCH64_P32_TLSDESC": true, + "R_AARCH64_P32_TLSDESC_ADD_LO12_NC": true, + "R_AARCH64_P32_TLSDESC_ADR_PAGE21": true, + "R_AARCH64_P32_TLSDESC_ADR_PREL21": true, + "R_AARCH64_P32_TLSDESC_CALL": true, + "R_AARCH64_P32_TLSDESC_LD32_LO12_NC": true, + "R_AARCH64_P32_TLSDESC_LD_PREL19": true, + "R_AARCH64_P32_TLSGD_ADD_LO12_NC": true, + "R_AARCH64_P32_TLSGD_ADR_PAGE21": true, + "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21": true, + "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC": true, + "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19": true, + "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12": true, + "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12": true, + "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC": true, + "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0": true, + "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC": true, + "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1": true, + "R_AARCH64_P32_TLS_DTPMOD": true, + "R_AARCH64_P32_TLS_DTPREL": true, + "R_AARCH64_P32_TLS_TPREL": true, + "R_AARCH64_P32_TSTBR14": true, + "R_AARCH64_PREL16": true, + "R_AARCH64_PREL32": true, + "R_AARCH64_PREL64": true, + "R_AARCH64_RELATIVE": true, + "R_AARCH64_TLSDESC": true, + "R_AARCH64_TLSDESC_ADD": true, + "R_AARCH64_TLSDESC_ADD_LO12_NC": true, + "R_AARCH64_TLSDESC_ADR_PAGE21": true, + "R_AARCH64_TLSDESC_ADR_PREL21": true, + "R_AARCH64_TLSDESC_CALL": true, + "R_AARCH64_TLSDESC_LD64_LO12_NC": true, + "R_AARCH64_TLSDESC_LDR": true, + "R_AARCH64_TLSDESC_LD_PREL19": true, + "R_AARCH64_TLSDESC_OFF_G0_NC": true, + "R_AARCH64_TLSDESC_OFF_G1": true, + "R_AARCH64_TLSGD_ADD_LO12_NC": true, + "R_AARCH64_TLSGD_ADR_PAGE21": true, + "R_AARCH64_TLSGD_ADR_PREL21": true, + "R_AARCH64_TLSGD_MOVW_G0_NC": true, + "R_AARCH64_TLSGD_MOVW_G1": true, + "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21": true, + "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC": true, + "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19": true, + "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC": true, + "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1": true, + "R_AARCH64_TLSLD_ADR_PAGE21": true, + "R_AARCH64_TLSLD_ADR_PREL21": true, + "R_AARCH64_TLSLD_LDST128_DTPREL_LO12": true, + "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC": true, + "R_AARCH64_TLSLE_ADD_TPREL_HI12": true, + "R_AARCH64_TLSLE_ADD_TPREL_LO12": true, + "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC": true, + "R_AARCH64_TLSLE_LDST128_TPREL_LO12": true, + "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC": true, + "R_AARCH64_TLSLE_MOVW_TPREL_G0": true, + "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC": true, + "R_AARCH64_TLSLE_MOVW_TPREL_G1": true, + "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC": true, + "R_AARCH64_TLSLE_MOVW_TPREL_G2": true, + "R_AARCH64_TLS_DTPMOD64": true, + "R_AARCH64_TLS_DTPREL64": true, + "R_AARCH64_TLS_TPREL64": true, + "R_AARCH64_TSTBR14": true, + "R_ALPHA": true, + "R_ALPHA_BRADDR": true, + "R_ALPHA_COPY": true, + "R_ALPHA_GLOB_DAT": true, + "R_ALPHA_GPDISP": true, + "R_ALPHA_GPREL32": true, + "R_ALPHA_GPRELHIGH": true, + "R_ALPHA_GPRELLOW": true, + "R_ALPHA_GPVALUE": true, + "R_ALPHA_HINT": true, + "R_ALPHA_IMMED_BR_HI32": true, + "R_ALPHA_IMMED_GP_16": true, + "R_ALPHA_IMMED_GP_HI32": true, + "R_ALPHA_IMMED_LO32": true, + "R_ALPHA_IMMED_SCN_HI32": true, + "R_ALPHA_JMP_SLOT": true, + "R_ALPHA_LITERAL": true, + "R_ALPHA_LITUSE": true, + "R_ALPHA_NONE": true, + "R_ALPHA_OP_PRSHIFT": true, + "R_ALPHA_OP_PSUB": true, + "R_ALPHA_OP_PUSH": true, + "R_ALPHA_OP_STORE": true, + "R_ALPHA_REFLONG": true, + "R_ALPHA_REFQUAD": true, + "R_ALPHA_RELATIVE": true, + "R_ALPHA_SREL16": true, + "R_ALPHA_SREL32": true, + "R_ALPHA_SREL64": true, + "R_ARM": true, + "R_ARM_ABS12": true, + "R_ARM_ABS16": true, + "R_ARM_ABS32": true, + "R_ARM_ABS32_NOI": true, + "R_ARM_ABS8": true, + "R_ARM_ALU_PCREL_15_8": true, + "R_ARM_ALU_PCREL_23_15": true, + "R_ARM_ALU_PCREL_7_0": true, + "R_ARM_ALU_PC_G0": true, + "R_ARM_ALU_PC_G0_NC": true, + "R_ARM_ALU_PC_G1": true, + "R_ARM_ALU_PC_G1_NC": true, + "R_ARM_ALU_PC_G2": true, + "R_ARM_ALU_SBREL_19_12_NC": true, + "R_ARM_ALU_SBREL_27_20_CK": true, + "R_ARM_ALU_SB_G0": true, + "R_ARM_ALU_SB_G0_NC": true, + "R_ARM_ALU_SB_G1": true, + "R_ARM_ALU_SB_G1_NC": true, + "R_ARM_ALU_SB_G2": true, + "R_ARM_AMP_VCALL9": true, + "R_ARM_BASE_ABS": true, + "R_ARM_CALL": true, + "R_ARM_COPY": true, + "R_ARM_GLOB_DAT": true, + "R_ARM_GNU_VTENTRY": true, + "R_ARM_GNU_VTINHERIT": true, + "R_ARM_GOT32": true, + "R_ARM_GOTOFF": true, + "R_ARM_GOTOFF12": true, + "R_ARM_GOTPC": true, + "R_ARM_GOTRELAX": true, + "R_ARM_GOT_ABS": true, + "R_ARM_GOT_BREL12": true, + "R_ARM_GOT_PREL": true, + "R_ARM_IRELATIVE": true, + "R_ARM_JUMP24": true, + "R_ARM_JUMP_SLOT": true, + "R_ARM_LDC_PC_G0": true, + "R_ARM_LDC_PC_G1": true, + "R_ARM_LDC_PC_G2": true, + "R_ARM_LDC_SB_G0": true, + "R_ARM_LDC_SB_G1": true, + "R_ARM_LDC_SB_G2": true, + "R_ARM_LDRS_PC_G0": true, + "R_ARM_LDRS_PC_G1": true, + "R_ARM_LDRS_PC_G2": true, + "R_ARM_LDRS_SB_G0": true, + "R_ARM_LDRS_SB_G1": true, + "R_ARM_LDRS_SB_G2": true, + "R_ARM_LDR_PC_G1": true, + "R_ARM_LDR_PC_G2": true, + "R_ARM_LDR_SBREL_11_10_NC": true, + "R_ARM_LDR_SB_G0": true, + "R_ARM_LDR_SB_G1": true, + "R_ARM_LDR_SB_G2": true, + "R_ARM_ME_TOO": true, + "R_ARM_MOVT_ABS": true, + "R_ARM_MOVT_BREL": true, + "R_ARM_MOVT_PREL": true, + "R_ARM_MOVW_ABS_NC": true, + "R_ARM_MOVW_BREL": true, + "R_ARM_MOVW_BREL_NC": true, + "R_ARM_MOVW_PREL_NC": true, + "R_ARM_NONE": true, + "R_ARM_PC13": true, + "R_ARM_PC24": true, + "R_ARM_PLT32": true, + "R_ARM_PLT32_ABS": true, + "R_ARM_PREL31": true, + "R_ARM_PRIVATE_0": true, + "R_ARM_PRIVATE_1": true, + "R_ARM_PRIVATE_10": true, + "R_ARM_PRIVATE_11": true, + "R_ARM_PRIVATE_12": true, + "R_ARM_PRIVATE_13": true, + "R_ARM_PRIVATE_14": true, + "R_ARM_PRIVATE_15": true, + "R_ARM_PRIVATE_2": true, + "R_ARM_PRIVATE_3": true, + "R_ARM_PRIVATE_4": true, + "R_ARM_PRIVATE_5": true, + "R_ARM_PRIVATE_6": true, + "R_ARM_PRIVATE_7": true, + "R_ARM_PRIVATE_8": true, + "R_ARM_PRIVATE_9": true, + "R_ARM_RABS32": true, + "R_ARM_RBASE": true, + "R_ARM_REL32": true, + "R_ARM_REL32_NOI": true, + "R_ARM_RELATIVE": true, + "R_ARM_RPC24": true, + "R_ARM_RREL32": true, + "R_ARM_RSBREL32": true, + "R_ARM_RXPC25": true, + "R_ARM_SBREL31": true, + "R_ARM_SBREL32": true, + "R_ARM_SWI24": true, + "R_ARM_TARGET1": true, + "R_ARM_TARGET2": true, + "R_ARM_THM_ABS5": true, + "R_ARM_THM_ALU_ABS_G0_NC": true, + "R_ARM_THM_ALU_ABS_G1_NC": true, + "R_ARM_THM_ALU_ABS_G2_NC": true, + "R_ARM_THM_ALU_ABS_G3": true, + "R_ARM_THM_ALU_PREL_11_0": true, + "R_ARM_THM_GOT_BREL12": true, + "R_ARM_THM_JUMP11": true, + "R_ARM_THM_JUMP19": true, + "R_ARM_THM_JUMP24": true, + "R_ARM_THM_JUMP6": true, + "R_ARM_THM_JUMP8": true, + "R_ARM_THM_MOVT_ABS": true, + "R_ARM_THM_MOVT_BREL": true, + "R_ARM_THM_MOVT_PREL": true, + "R_ARM_THM_MOVW_ABS_NC": true, + "R_ARM_THM_MOVW_BREL": true, + "R_ARM_THM_MOVW_BREL_NC": true, + "R_ARM_THM_MOVW_PREL_NC": true, + "R_ARM_THM_PC12": true, + "R_ARM_THM_PC22": true, + "R_ARM_THM_PC8": true, + "R_ARM_THM_RPC22": true, + "R_ARM_THM_SWI8": true, + "R_ARM_THM_TLS_CALL": true, + "R_ARM_THM_TLS_DESCSEQ16": true, + "R_ARM_THM_TLS_DESCSEQ32": true, + "R_ARM_THM_XPC22": true, + "R_ARM_TLS_CALL": true, + "R_ARM_TLS_DESCSEQ": true, + "R_ARM_TLS_DTPMOD32": true, + "R_ARM_TLS_DTPOFF32": true, + "R_ARM_TLS_GD32": true, + "R_ARM_TLS_GOTDESC": true, + "R_ARM_TLS_IE12GP": true, + "R_ARM_TLS_IE32": true, + "R_ARM_TLS_LDM32": true, + "R_ARM_TLS_LDO12": true, + "R_ARM_TLS_LDO32": true, + "R_ARM_TLS_LE12": true, + "R_ARM_TLS_LE32": true, + "R_ARM_TLS_TPOFF32": true, + "R_ARM_V4BX": true, + "R_ARM_XPC25": true, + "R_INFO": true, + "R_INFO32": true, + "R_MIPS": true, + "R_MIPS_16": true, + "R_MIPS_26": true, + "R_MIPS_32": true, + "R_MIPS_64": true, + "R_MIPS_ADD_IMMEDIATE": true, + "R_MIPS_CALL16": true, + "R_MIPS_CALL_HI16": true, + "R_MIPS_CALL_LO16": true, + "R_MIPS_DELETE": true, + "R_MIPS_GOT16": true, + "R_MIPS_GOT_DISP": true, + "R_MIPS_GOT_HI16": true, + "R_MIPS_GOT_LO16": true, + "R_MIPS_GOT_OFST": true, + "R_MIPS_GOT_PAGE": true, + "R_MIPS_GPREL16": true, + "R_MIPS_GPREL32": true, + "R_MIPS_HI16": true, + "R_MIPS_HIGHER": true, + "R_MIPS_HIGHEST": true, + "R_MIPS_INSERT_A": true, + "R_MIPS_INSERT_B": true, + "R_MIPS_JALR": true, + "R_MIPS_LITERAL": true, + "R_MIPS_LO16": true, + "R_MIPS_NONE": true, + "R_MIPS_PC16": true, + "R_MIPS_PJUMP": true, + "R_MIPS_REL16": true, + "R_MIPS_REL32": true, + "R_MIPS_RELGOT": true, + "R_MIPS_SCN_DISP": true, + "R_MIPS_SHIFT5": true, + "R_MIPS_SHIFT6": true, + "R_MIPS_SUB": true, + "R_MIPS_TLS_DTPMOD32": true, + "R_MIPS_TLS_DTPMOD64": true, + "R_MIPS_TLS_DTPREL32": true, + "R_MIPS_TLS_DTPREL64": true, + "R_MIPS_TLS_DTPREL_HI16": true, + "R_MIPS_TLS_DTPREL_LO16": true, + "R_MIPS_TLS_GD": true, + "R_MIPS_TLS_GOTTPREL": true, + "R_MIPS_TLS_LDM": true, + "R_MIPS_TLS_TPREL32": true, + "R_MIPS_TLS_TPREL64": true, + "R_MIPS_TLS_TPREL_HI16": true, + "R_MIPS_TLS_TPREL_LO16": true, + "R_PPC": true, + "R_PPC64": true, + "R_PPC64_ADDR14": true, + "R_PPC64_ADDR14_BRNTAKEN": true, + "R_PPC64_ADDR14_BRTAKEN": true, + "R_PPC64_ADDR16": true, + "R_PPC64_ADDR16_DS": true, + "R_PPC64_ADDR16_HA": true, + "R_PPC64_ADDR16_HI": true, + "R_PPC64_ADDR16_HIGH": true, + "R_PPC64_ADDR16_HIGHA": true, + "R_PPC64_ADDR16_HIGHER": true, + "R_PPC64_ADDR16_HIGHERA": true, + "R_PPC64_ADDR16_HIGHEST": true, + "R_PPC64_ADDR16_HIGHESTA": true, + "R_PPC64_ADDR16_LO": true, + "R_PPC64_ADDR16_LO_DS": true, + "R_PPC64_ADDR24": true, + "R_PPC64_ADDR32": true, + "R_PPC64_ADDR64": true, + "R_PPC64_ADDR64_LOCAL": true, + "R_PPC64_DTPMOD64": true, + "R_PPC64_DTPREL16": true, + "R_PPC64_DTPREL16_DS": true, + "R_PPC64_DTPREL16_HA": true, + "R_PPC64_DTPREL16_HI": true, + "R_PPC64_DTPREL16_HIGH": true, + "R_PPC64_DTPREL16_HIGHA": true, + "R_PPC64_DTPREL16_HIGHER": true, + "R_PPC64_DTPREL16_HIGHERA": true, + "R_PPC64_DTPREL16_HIGHEST": true, + "R_PPC64_DTPREL16_HIGHESTA": true, + "R_PPC64_DTPREL16_LO": true, + "R_PPC64_DTPREL16_LO_DS": true, + "R_PPC64_DTPREL64": true, + "R_PPC64_ENTRY": true, + "R_PPC64_GOT16": true, + "R_PPC64_GOT16_DS": true, + "R_PPC64_GOT16_HA": true, + "R_PPC64_GOT16_HI": true, + "R_PPC64_GOT16_LO": true, + "R_PPC64_GOT16_LO_DS": true, + "R_PPC64_GOT_DTPREL16_DS": true, + "R_PPC64_GOT_DTPREL16_HA": true, + "R_PPC64_GOT_DTPREL16_HI": true, + "R_PPC64_GOT_DTPREL16_LO_DS": true, + "R_PPC64_GOT_TLSGD16": true, + "R_PPC64_GOT_TLSGD16_HA": true, + "R_PPC64_GOT_TLSGD16_HI": true, + "R_PPC64_GOT_TLSGD16_LO": true, + "R_PPC64_GOT_TLSLD16": true, + "R_PPC64_GOT_TLSLD16_HA": true, + "R_PPC64_GOT_TLSLD16_HI": true, + "R_PPC64_GOT_TLSLD16_LO": true, + "R_PPC64_GOT_TPREL16_DS": true, + "R_PPC64_GOT_TPREL16_HA": true, + "R_PPC64_GOT_TPREL16_HI": true, + "R_PPC64_GOT_TPREL16_LO_DS": true, + "R_PPC64_IRELATIVE": true, + "R_PPC64_JMP_IREL": true, + "R_PPC64_JMP_SLOT": true, + "R_PPC64_NONE": true, + "R_PPC64_PLT16_LO_DS": true, + "R_PPC64_PLTGOT16": true, + "R_PPC64_PLTGOT16_DS": true, + "R_PPC64_PLTGOT16_HA": true, + "R_PPC64_PLTGOT16_HI": true, + "R_PPC64_PLTGOT16_LO": true, + "R_PPC64_PLTGOT_LO_DS": true, + "R_PPC64_REL14": true, + "R_PPC64_REL14_BRNTAKEN": true, + "R_PPC64_REL14_BRTAKEN": true, + "R_PPC64_REL16": true, + "R_PPC64_REL16DX_HA": true, + "R_PPC64_REL16_HA": true, + "R_PPC64_REL16_HI": true, + "R_PPC64_REL16_LO": true, + "R_PPC64_REL24": true, + "R_PPC64_REL24_NOTOC": true, + "R_PPC64_REL32": true, + "R_PPC64_REL64": true, + "R_PPC64_SECTOFF_DS": true, + "R_PPC64_SECTOFF_LO_DS": true, + "R_PPC64_TLS": true, + "R_PPC64_TLSGD": true, + "R_PPC64_TLSLD": true, + "R_PPC64_TOC": true, + "R_PPC64_TOC16": true, + "R_PPC64_TOC16_DS": true, + "R_PPC64_TOC16_HA": true, + "R_PPC64_TOC16_HI": true, + "R_PPC64_TOC16_LO": true, + "R_PPC64_TOC16_LO_DS": true, + "R_PPC64_TOCSAVE": true, + "R_PPC64_TPREL16": true, + "R_PPC64_TPREL16_DS": true, + "R_PPC64_TPREL16_HA": true, + "R_PPC64_TPREL16_HI": true, + "R_PPC64_TPREL16_HIGH": true, + "R_PPC64_TPREL16_HIGHA": true, + "R_PPC64_TPREL16_HIGHER": true, + "R_PPC64_TPREL16_HIGHERA": true, + "R_PPC64_TPREL16_HIGHEST": true, + "R_PPC64_TPREL16_HIGHESTA": true, + "R_PPC64_TPREL16_LO": true, + "R_PPC64_TPREL16_LO_DS": true, + "R_PPC64_TPREL64": true, + "R_PPC_ADDR14": true, + "R_PPC_ADDR14_BRNTAKEN": true, + "R_PPC_ADDR14_BRTAKEN": true, + "R_PPC_ADDR16": true, + "R_PPC_ADDR16_HA": true, + "R_PPC_ADDR16_HI": true, + "R_PPC_ADDR16_LO": true, + "R_PPC_ADDR24": true, + "R_PPC_ADDR32": true, + "R_PPC_COPY": true, + "R_PPC_DTPMOD32": true, + "R_PPC_DTPREL16": true, + "R_PPC_DTPREL16_HA": true, + "R_PPC_DTPREL16_HI": true, + "R_PPC_DTPREL16_LO": true, + "R_PPC_DTPREL32": true, + "R_PPC_EMB_BIT_FLD": true, + "R_PPC_EMB_MRKREF": true, + "R_PPC_EMB_NADDR16": true, + "R_PPC_EMB_NADDR16_HA": true, + "R_PPC_EMB_NADDR16_HI": true, + "R_PPC_EMB_NADDR16_LO": true, + "R_PPC_EMB_NADDR32": true, + "R_PPC_EMB_RELSDA": true, + "R_PPC_EMB_RELSEC16": true, + "R_PPC_EMB_RELST_HA": true, + "R_PPC_EMB_RELST_HI": true, + "R_PPC_EMB_RELST_LO": true, + "R_PPC_EMB_SDA21": true, + "R_PPC_EMB_SDA2I16": true, + "R_PPC_EMB_SDA2REL": true, + "R_PPC_EMB_SDAI16": true, + "R_PPC_GLOB_DAT": true, + "R_PPC_GOT16": true, + "R_PPC_GOT16_HA": true, + "R_PPC_GOT16_HI": true, + "R_PPC_GOT16_LO": true, + "R_PPC_GOT_TLSGD16": true, + "R_PPC_GOT_TLSGD16_HA": true, + "R_PPC_GOT_TLSGD16_HI": true, + "R_PPC_GOT_TLSGD16_LO": true, + "R_PPC_GOT_TLSLD16": true, + "R_PPC_GOT_TLSLD16_HA": true, + "R_PPC_GOT_TLSLD16_HI": true, + "R_PPC_GOT_TLSLD16_LO": true, + "R_PPC_GOT_TPREL16": true, + "R_PPC_GOT_TPREL16_HA": true, + "R_PPC_GOT_TPREL16_HI": true, + "R_PPC_GOT_TPREL16_LO": true, + "R_PPC_JMP_SLOT": true, + "R_PPC_LOCAL24PC": true, + "R_PPC_NONE": true, + "R_PPC_PLT16_HA": true, + "R_PPC_PLT16_HI": true, + "R_PPC_PLT16_LO": true, + "R_PPC_PLT32": true, + "R_PPC_PLTREL24": true, + "R_PPC_PLTREL32": true, + "R_PPC_REL14": true, + "R_PPC_REL14_BRNTAKEN": true, + "R_PPC_REL14_BRTAKEN": true, + "R_PPC_REL24": true, + "R_PPC_REL32": true, + "R_PPC_RELATIVE": true, + "R_PPC_SDAREL16": true, + "R_PPC_SECTOFF": true, + "R_PPC_SECTOFF_HA": true, + "R_PPC_SECTOFF_HI": true, + "R_PPC_SECTOFF_LO": true, + "R_PPC_TLS": true, + "R_PPC_TPREL16": true, + "R_PPC_TPREL16_HA": true, + "R_PPC_TPREL16_HI": true, + "R_PPC_TPREL16_LO": true, + "R_PPC_TPREL32": true, + "R_PPC_UADDR16": true, + "R_PPC_UADDR32": true, + "R_RISCV": true, + "R_RISCV_32": true, + "R_RISCV_32_PCREL": true, + "R_RISCV_64": true, + "R_RISCV_ADD16": true, + "R_RISCV_ADD32": true, + "R_RISCV_ADD64": true, + "R_RISCV_ADD8": true, + "R_RISCV_ALIGN": true, + "R_RISCV_BRANCH": true, + "R_RISCV_CALL": true, + "R_RISCV_CALL_PLT": true, + "R_RISCV_COPY": true, + "R_RISCV_GNU_VTENTRY": true, + "R_RISCV_GNU_VTINHERIT": true, + "R_RISCV_GOT_HI20": true, + "R_RISCV_GPREL_I": true, + "R_RISCV_GPREL_S": true, + "R_RISCV_HI20": true, + "R_RISCV_JAL": true, + "R_RISCV_JUMP_SLOT": true, + "R_RISCV_LO12_I": true, + "R_RISCV_LO12_S": true, + "R_RISCV_NONE": true, + "R_RISCV_PCREL_HI20": true, + "R_RISCV_PCREL_LO12_I": true, + "R_RISCV_PCREL_LO12_S": true, + "R_RISCV_RELATIVE": true, + "R_RISCV_RELAX": true, + "R_RISCV_RVC_BRANCH": true, + "R_RISCV_RVC_JUMP": true, + "R_RISCV_RVC_LUI": true, + "R_RISCV_SET16": true, + "R_RISCV_SET32": true, + "R_RISCV_SET6": true, + "R_RISCV_SET8": true, + "R_RISCV_SUB16": true, + "R_RISCV_SUB32": true, + "R_RISCV_SUB6": true, + "R_RISCV_SUB64": true, + "R_RISCV_SUB8": true, + "R_RISCV_TLS_DTPMOD32": true, + "R_RISCV_TLS_DTPMOD64": true, + "R_RISCV_TLS_DTPREL32": true, + "R_RISCV_TLS_DTPREL64": true, + "R_RISCV_TLS_GD_HI20": true, + "R_RISCV_TLS_GOT_HI20": true, + "R_RISCV_TLS_TPREL32": true, + "R_RISCV_TLS_TPREL64": true, + "R_RISCV_TPREL_ADD": true, + "R_RISCV_TPREL_HI20": true, + "R_RISCV_TPREL_I": true, + "R_RISCV_TPREL_LO12_I": true, + "R_RISCV_TPREL_LO12_S": true, + "R_RISCV_TPREL_S": true, + "R_SPARC": true, + "R_SPARC_10": true, + "R_SPARC_11": true, + "R_SPARC_13": true, + "R_SPARC_16": true, + "R_SPARC_22": true, + "R_SPARC_32": true, + "R_SPARC_5": true, + "R_SPARC_6": true, + "R_SPARC_64": true, + "R_SPARC_7": true, + "R_SPARC_8": true, + "R_SPARC_COPY": true, + "R_SPARC_DISP16": true, + "R_SPARC_DISP32": true, + "R_SPARC_DISP64": true, + "R_SPARC_DISP8": true, + "R_SPARC_GLOB_DAT": true, + "R_SPARC_GLOB_JMP": true, + "R_SPARC_GOT10": true, + "R_SPARC_GOT13": true, + "R_SPARC_GOT22": true, + "R_SPARC_H44": true, + "R_SPARC_HH22": true, + "R_SPARC_HI22": true, + "R_SPARC_HIPLT22": true, + "R_SPARC_HIX22": true, + "R_SPARC_HM10": true, + "R_SPARC_JMP_SLOT": true, + "R_SPARC_L44": true, + "R_SPARC_LM22": true, + "R_SPARC_LO10": true, + "R_SPARC_LOPLT10": true, + "R_SPARC_LOX10": true, + "R_SPARC_M44": true, + "R_SPARC_NONE": true, + "R_SPARC_OLO10": true, + "R_SPARC_PC10": true, + "R_SPARC_PC22": true, + "R_SPARC_PCPLT10": true, + "R_SPARC_PCPLT22": true, + "R_SPARC_PCPLT32": true, + "R_SPARC_PC_HH22": true, + "R_SPARC_PC_HM10": true, + "R_SPARC_PC_LM22": true, + "R_SPARC_PLT32": true, + "R_SPARC_PLT64": true, + "R_SPARC_REGISTER": true, + "R_SPARC_RELATIVE": true, + "R_SPARC_UA16": true, + "R_SPARC_UA32": true, + "R_SPARC_UA64": true, + "R_SPARC_WDISP16": true, + "R_SPARC_WDISP19": true, + "R_SPARC_WDISP22": true, + "R_SPARC_WDISP30": true, + "R_SPARC_WPLT30": true, + "R_SYM32": true, + "R_SYM64": true, + "R_TYPE32": true, + "R_TYPE64": true, + "R_X86_64": true, + "R_X86_64_16": true, + "R_X86_64_32": true, + "R_X86_64_32S": true, + "R_X86_64_64": true, + "R_X86_64_8": true, + "R_X86_64_COPY": true, + "R_X86_64_DTPMOD64": true, + "R_X86_64_DTPOFF32": true, + "R_X86_64_DTPOFF64": true, + "R_X86_64_GLOB_DAT": true, + "R_X86_64_GOT32": true, + "R_X86_64_GOT64": true, + "R_X86_64_GOTOFF64": true, + "R_X86_64_GOTPC32": true, + "R_X86_64_GOTPC32_TLSDESC": true, + "R_X86_64_GOTPC64": true, + "R_X86_64_GOTPCREL": true, + "R_X86_64_GOTPCREL64": true, + "R_X86_64_GOTPCRELX": true, + "R_X86_64_GOTPLT64": true, + "R_X86_64_GOTTPOFF": true, + "R_X86_64_IRELATIVE": true, + "R_X86_64_JMP_SLOT": true, + "R_X86_64_NONE": true, + "R_X86_64_PC16": true, + "R_X86_64_PC32": true, + "R_X86_64_PC32_BND": true, + "R_X86_64_PC64": true, + "R_X86_64_PC8": true, + "R_X86_64_PLT32": true, + "R_X86_64_PLT32_BND": true, + "R_X86_64_PLTOFF64": true, + "R_X86_64_RELATIVE": true, + "R_X86_64_RELATIVE64": true, + "R_X86_64_REX_GOTPCRELX": true, + "R_X86_64_SIZE32": true, + "R_X86_64_SIZE64": true, + "R_X86_64_TLSDESC": true, + "R_X86_64_TLSDESC_CALL": true, + "R_X86_64_TLSGD": true, + "R_X86_64_TLSLD": true, + "R_X86_64_TPOFF32": true, + "R_X86_64_TPOFF64": true, + "Rel32": true, + "Rel64": true, + "Rela32": true, + "Rela64": true, + "SHF_ALLOC": true, + "SHF_COMPRESSED": true, + "SHF_EXECINSTR": true, + "SHF_GROUP": true, + "SHF_INFO_LINK": true, + "SHF_LINK_ORDER": true, + "SHF_MASKOS": true, + "SHF_MASKPROC": true, + "SHF_MERGE": true, + "SHF_OS_NONCONFORMING": true, + "SHF_STRINGS": true, + "SHF_TLS": true, + "SHF_WRITE": true, + "SHN_ABS": true, + "SHN_COMMON": true, + "SHN_HIOS": true, + "SHN_HIPROC": true, + "SHN_HIRESERVE": true, + "SHN_LOOS": true, + "SHN_LOPROC": true, + "SHN_LORESERVE": true, + "SHN_UNDEF": true, + "SHN_XINDEX": true, + "SHT_DYNAMIC": true, + "SHT_DYNSYM": true, + "SHT_FINI_ARRAY": true, + "SHT_GNU_ATTRIBUTES": true, + "SHT_GNU_HASH": true, + "SHT_GNU_LIBLIST": true, + "SHT_GNU_VERDEF": true, + "SHT_GNU_VERNEED": true, + "SHT_GNU_VERSYM": true, + "SHT_GROUP": true, + "SHT_HASH": true, + "SHT_HIOS": true, + "SHT_HIPROC": true, + "SHT_HIUSER": true, + "SHT_INIT_ARRAY": true, + "SHT_LOOS": true, + "SHT_LOPROC": true, + "SHT_LOUSER": true, + "SHT_NOBITS": true, + "SHT_NOTE": true, + "SHT_NULL": true, + "SHT_PREINIT_ARRAY": true, + "SHT_PROGBITS": true, + "SHT_REL": true, + "SHT_RELA": true, + "SHT_SHLIB": true, + "SHT_STRTAB": true, + "SHT_SYMTAB": true, + "SHT_SYMTAB_SHNDX": true, + "STB_GLOBAL": true, + "STB_HIOS": true, + "STB_HIPROC": true, + "STB_LOCAL": true, + "STB_LOOS": true, + "STB_LOPROC": true, + "STB_WEAK": true, + "STT_COMMON": true, + "STT_FILE": true, + "STT_FUNC": true, + "STT_HIOS": true, + "STT_HIPROC": true, + "STT_LOOS": true, + "STT_LOPROC": true, + "STT_NOTYPE": true, + "STT_OBJECT": true, + "STT_SECTION": true, + "STT_TLS": true, + "STV_DEFAULT": true, + "STV_HIDDEN": true, + "STV_INTERNAL": true, + "STV_PROTECTED": true, + "ST_BIND": true, + "ST_INFO": true, + "ST_TYPE": true, + "ST_VISIBILITY": true, + "Section": true, + "Section32": true, + "Section64": true, + "SectionFlag": true, + "SectionHeader": true, + "SectionIndex": true, + "SectionType": true, + "Sym32": true, + "Sym32Size": true, + "Sym64": true, + "Sym64Size": true, + "SymBind": true, + "SymType": true, + "SymVis": true, + "Symbol": true, + "Type": true, + "Version": true, + }, + "debug/gosym": map[string]bool{ + "DecodingError": true, + "Func": true, + "LineTable": true, + "NewLineTable": true, + "NewTable": true, + "Obj": true, + "Sym": true, + "Table": true, + "UnknownFileError": true, + "UnknownLineError": true, + }, + "debug/macho": map[string]bool{ + "ARM64_RELOC_ADDEND": true, + "ARM64_RELOC_BRANCH26": true, + "ARM64_RELOC_GOT_LOAD_PAGE21": true, + "ARM64_RELOC_GOT_LOAD_PAGEOFF12": true, + "ARM64_RELOC_PAGE21": true, + "ARM64_RELOC_PAGEOFF12": true, + "ARM64_RELOC_POINTER_TO_GOT": true, + "ARM64_RELOC_SUBTRACTOR": true, + "ARM64_RELOC_TLVP_LOAD_PAGE21": true, + "ARM64_RELOC_TLVP_LOAD_PAGEOFF12": true, + "ARM64_RELOC_UNSIGNED": true, + "ARM_RELOC_BR24": true, + "ARM_RELOC_HALF": true, + "ARM_RELOC_HALF_SECTDIFF": true, + "ARM_RELOC_LOCAL_SECTDIFF": true, + "ARM_RELOC_PAIR": true, + "ARM_RELOC_PB_LA_PTR": true, + "ARM_RELOC_SECTDIFF": true, + "ARM_RELOC_VANILLA": true, + "ARM_THUMB_32BIT_BRANCH": true, + "ARM_THUMB_RELOC_BR22": true, + "Cpu": true, + "Cpu386": true, + "CpuAmd64": true, + "CpuArm": true, + "CpuArm64": true, + "CpuPpc": true, + "CpuPpc64": true, + "Dylib": true, + "DylibCmd": true, + "Dysymtab": true, + "DysymtabCmd": true, + "ErrNotFat": true, + "FatArch": true, + "FatArchHeader": true, + "FatFile": true, + "File": true, + "FileHeader": true, + "FlagAllModsBound": true, + "FlagAllowStackExecution": true, + "FlagAppExtensionSafe": true, + "FlagBindAtLoad": true, + "FlagBindsToWeak": true, + "FlagCanonical": true, + "FlagDeadStrippableDylib": true, + "FlagDyldLink": true, + "FlagForceFlat": true, + "FlagHasTLVDescriptors": true, + "FlagIncrLink": true, + "FlagLazyInit": true, + "FlagNoFixPrebinding": true, + "FlagNoHeapExecution": true, + "FlagNoMultiDefs": true, + "FlagNoReexportedDylibs": true, + "FlagNoUndefs": true, + "FlagPIE": true, + "FlagPrebindable": true, + "FlagPrebound": true, + "FlagRootSafe": true, + "FlagSetuidSafe": true, + "FlagSplitSegs": true, + "FlagSubsectionsViaSymbols": true, + "FlagTwoLevel": true, + "FlagWeakDefines": true, + "FormatError": true, + "GENERIC_RELOC_LOCAL_SECTDIFF": true, + "GENERIC_RELOC_PAIR": true, + "GENERIC_RELOC_PB_LA_PTR": true, + "GENERIC_RELOC_SECTDIFF": true, + "GENERIC_RELOC_TLV": true, + "GENERIC_RELOC_VANILLA": true, + "Load": true, + "LoadBytes": true, + "LoadCmd": true, + "LoadCmdDylib": true, + "LoadCmdDylinker": true, + "LoadCmdDysymtab": true, + "LoadCmdRpath": true, + "LoadCmdSegment": true, + "LoadCmdSegment64": true, + "LoadCmdSymtab": true, + "LoadCmdThread": true, + "LoadCmdUnixThread": true, + "Magic32": true, + "Magic64": true, + "MagicFat": true, + "NewFatFile": true, + "NewFile": true, + "Nlist32": true, + "Nlist64": true, + "Open": true, + "OpenFat": true, + "Regs386": true, + "RegsAMD64": true, + "Reloc": true, + "RelocTypeARM": true, + "RelocTypeARM64": true, + "RelocTypeGeneric": true, + "RelocTypeX86_64": true, + "Rpath": true, + "RpathCmd": true, + "Section": true, + "Section32": true, + "Section64": true, + "SectionHeader": true, + "Segment": true, + "Segment32": true, + "Segment64": true, + "SegmentHeader": true, + "Symbol": true, + "Symtab": true, + "SymtabCmd": true, + "Thread": true, + "Type": true, + "TypeBundle": true, + "TypeDylib": true, + "TypeExec": true, + "TypeObj": true, + "X86_64_RELOC_BRANCH": true, + "X86_64_RELOC_GOT": true, + "X86_64_RELOC_GOT_LOAD": true, + "X86_64_RELOC_SIGNED": true, + "X86_64_RELOC_SIGNED_1": true, + "X86_64_RELOC_SIGNED_2": true, + "X86_64_RELOC_SIGNED_4": true, + "X86_64_RELOC_SUBTRACTOR": true, + "X86_64_RELOC_TLV": true, + "X86_64_RELOC_UNSIGNED": true, + }, + "debug/pe": map[string]bool{ + "COFFSymbol": true, + "COFFSymbolSize": true, + "DataDirectory": true, + "File": true, + "FileHeader": true, + "FormatError": true, + "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE": true, + "IMAGE_DIRECTORY_ENTRY_BASERELOC": true, + "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT": true, + "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR": true, + "IMAGE_DIRECTORY_ENTRY_DEBUG": true, + "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT": true, + "IMAGE_DIRECTORY_ENTRY_EXCEPTION": true, + "IMAGE_DIRECTORY_ENTRY_EXPORT": true, + "IMAGE_DIRECTORY_ENTRY_GLOBALPTR": true, + "IMAGE_DIRECTORY_ENTRY_IAT": true, + "IMAGE_DIRECTORY_ENTRY_IMPORT": true, + "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG": true, + "IMAGE_DIRECTORY_ENTRY_RESOURCE": true, + "IMAGE_DIRECTORY_ENTRY_SECURITY": true, + "IMAGE_DIRECTORY_ENTRY_TLS": true, + "IMAGE_FILE_MACHINE_AM33": true, + "IMAGE_FILE_MACHINE_AMD64": true, + "IMAGE_FILE_MACHINE_ARM": true, + "IMAGE_FILE_MACHINE_ARM64": true, + "IMAGE_FILE_MACHINE_ARMNT": true, + "IMAGE_FILE_MACHINE_EBC": true, + "IMAGE_FILE_MACHINE_I386": true, + "IMAGE_FILE_MACHINE_IA64": true, + "IMAGE_FILE_MACHINE_M32R": true, + "IMAGE_FILE_MACHINE_MIPS16": true, + "IMAGE_FILE_MACHINE_MIPSFPU": true, + "IMAGE_FILE_MACHINE_MIPSFPU16": true, + "IMAGE_FILE_MACHINE_POWERPC": true, + "IMAGE_FILE_MACHINE_POWERPCFP": true, + "IMAGE_FILE_MACHINE_R4000": true, + "IMAGE_FILE_MACHINE_SH3": true, + "IMAGE_FILE_MACHINE_SH3DSP": true, + "IMAGE_FILE_MACHINE_SH4": true, + "IMAGE_FILE_MACHINE_SH5": true, + "IMAGE_FILE_MACHINE_THUMB": true, + "IMAGE_FILE_MACHINE_UNKNOWN": true, + "IMAGE_FILE_MACHINE_WCEMIPSV2": true, + "ImportDirectory": true, + "NewFile": true, + "Open": true, + "OptionalHeader32": true, + "OptionalHeader64": true, + "Reloc": true, + "Section": true, + "SectionHeader": true, + "SectionHeader32": true, + "StringTable": true, + "Symbol": true, + }, + "debug/plan9obj": map[string]bool{ + "File": true, + "FileHeader": true, + "Magic386": true, + "Magic64": true, + "MagicAMD64": true, + "MagicARM": true, + "NewFile": true, + "Open": true, + "Section": true, + "SectionHeader": true, + "Sym": true, + }, + "encoding": map[string]bool{ + "BinaryMarshaler": true, + "BinaryUnmarshaler": true, + "TextMarshaler": true, + "TextUnmarshaler": true, + }, + "encoding/ascii85": map[string]bool{ + "CorruptInputError": true, + "Decode": true, + "Encode": true, + "MaxEncodedLen": true, + "NewDecoder": true, + "NewEncoder": true, + }, + "encoding/asn1": map[string]bool{ + "BitString": true, + "ClassApplication": true, + "ClassContextSpecific": true, + "ClassPrivate": true, + "ClassUniversal": true, + "Enumerated": true, + "Flag": true, + "Marshal": true, + "MarshalWithParams": true, + "NullBytes": true, + "NullRawValue": true, + "ObjectIdentifier": true, + "RawContent": true, + "RawValue": true, + "StructuralError": true, + "SyntaxError": true, + "TagBitString": true, + "TagBoolean": true, + "TagEnum": true, + "TagGeneralString": true, + "TagGeneralizedTime": true, + "TagIA5String": true, + "TagInteger": true, + "TagNull": true, + "TagNumericString": true, + "TagOID": true, + "TagOctetString": true, + "TagPrintableString": true, + "TagSequence": true, + "TagSet": true, + "TagT61String": true, + "TagUTCTime": true, + "TagUTF8String": true, + "Unmarshal": true, + "UnmarshalWithParams": true, + }, + "encoding/base32": map[string]bool{ + "CorruptInputError": true, + "Encoding": true, + "HexEncoding": true, + "NewDecoder": true, + "NewEncoder": true, + "NewEncoding": true, + "NoPadding": true, + "StdEncoding": true, + "StdPadding": true, + }, + "encoding/base64": map[string]bool{ + "CorruptInputError": true, + "Encoding": true, + "NewDecoder": true, + "NewEncoder": true, + "NewEncoding": true, + "NoPadding": true, + "RawStdEncoding": true, + "RawURLEncoding": true, + "StdEncoding": true, + "StdPadding": true, + "URLEncoding": true, + }, + "encoding/binary": map[string]bool{ + "BigEndian": true, + "ByteOrder": true, + "LittleEndian": true, + "MaxVarintLen16": true, + "MaxVarintLen32": true, + "MaxVarintLen64": true, + "PutUvarint": true, + "PutVarint": true, + "Read": true, + "ReadUvarint": true, + "ReadVarint": true, + "Size": true, + "Uvarint": true, + "Varint": true, + "Write": true, + }, + "encoding/csv": map[string]bool{ + "ErrBareQuote": true, + "ErrFieldCount": true, + "ErrQuote": true, + "ErrTrailingComma": true, + "NewReader": true, + "NewWriter": true, + "ParseError": true, + "Reader": true, + "Writer": true, + }, + "encoding/gob": map[string]bool{ + "CommonType": true, + "Decoder": true, + "Encoder": true, + "GobDecoder": true, + "GobEncoder": true, + "NewDecoder": true, + "NewEncoder": true, + "Register": true, + "RegisterName": true, + }, + "encoding/hex": map[string]bool{ + "Decode": true, + "DecodeString": true, + "DecodedLen": true, + "Dump": true, + "Dumper": true, + "Encode": true, + "EncodeToString": true, + "EncodedLen": true, + "ErrLength": true, + "InvalidByteError": true, + "NewDecoder": true, + "NewEncoder": true, + }, + "encoding/json": map[string]bool{ + "Compact": true, + "Decoder": true, + "Delim": true, + "Encoder": true, + "HTMLEscape": true, + "Indent": true, + "InvalidUTF8Error": true, + "InvalidUnmarshalError": true, + "Marshal": true, + "MarshalIndent": true, + "Marshaler": true, + "MarshalerError": true, + "NewDecoder": true, + "NewEncoder": true, + "Number": true, + "RawMessage": true, + "SyntaxError": true, + "Token": true, + "Unmarshal": true, + "UnmarshalFieldError": true, + "UnmarshalTypeError": true, + "Unmarshaler": true, + "UnsupportedTypeError": true, + "UnsupportedValueError": true, + "Valid": true, + }, + "encoding/pem": map[string]bool{ + "Block": true, + "Decode": true, + "Encode": true, + "EncodeToMemory": true, + }, + "encoding/xml": map[string]bool{ + "Attr": true, + "CharData": true, + "Comment": true, + "CopyToken": true, + "Decoder": true, + "Directive": true, + "Encoder": true, + "EndElement": true, + "Escape": true, + "EscapeText": true, + "HTMLAutoClose": true, + "HTMLEntity": true, + "Header": true, + "Marshal": true, + "MarshalIndent": true, + "Marshaler": true, + "MarshalerAttr": true, + "Name": true, + "NewDecoder": true, + "NewEncoder": true, + "NewTokenDecoder": true, + "ProcInst": true, + "StartElement": true, + "SyntaxError": true, + "TagPathError": true, + "Token": true, + "TokenReader": true, + "Unmarshal": true, + "UnmarshalError": true, + "Unmarshaler": true, + "UnmarshalerAttr": true, + "UnsupportedTypeError": true, + }, + "errors": map[string]bool{ + "New": true, + }, + "expvar": map[string]bool{ + "Do": true, + "Float": true, + "Func": true, + "Get": true, + "Handler": true, + "Int": true, + "KeyValue": true, + "Map": true, + "NewFloat": true, + "NewInt": true, + "NewMap": true, + "NewString": true, + "Publish": true, + "String": true, + "Var": true, + }, + "flag": map[string]bool{ + "Arg": true, + "Args": true, + "Bool": true, + "BoolVar": true, + "CommandLine": true, + "ContinueOnError": true, + "Duration": true, + "DurationVar": true, + "ErrHelp": true, + "ErrorHandling": true, + "ExitOnError": true, + "Flag": true, + "FlagSet": true, + "Float64": true, + "Float64Var": true, + "Getter": true, + "Int": true, + "Int64": true, + "Int64Var": true, + "IntVar": true, + "Lookup": true, + "NArg": true, + "NFlag": true, + "NewFlagSet": true, + "PanicOnError": true, + "Parse": true, + "Parsed": true, + "PrintDefaults": true, + "Set": true, + "String": true, + "StringVar": true, + "Uint": true, + "Uint64": true, + "Uint64Var": true, + "UintVar": true, + "UnquoteUsage": true, + "Usage": true, + "Value": true, + "Var": true, + "Visit": true, + "VisitAll": true, + }, + "fmt": map[string]bool{ + "Errorf": true, + "Formatter": true, + "Fprint": true, + "Fprintf": true, + "Fprintln": true, + "Fscan": true, + "Fscanf": true, + "Fscanln": true, + "GoStringer": true, + "Print": true, + "Printf": true, + "Println": true, + "Scan": true, + "ScanState": true, + "Scanf": true, + "Scanln": true, + "Scanner": true, + "Sprint": true, + "Sprintf": true, + "Sprintln": true, + "Sscan": true, + "Sscanf": true, + "Sscanln": true, + "State": true, + "Stringer": true, + }, + "go/ast": map[string]bool{ + "ArrayType": true, + "AssignStmt": true, + "Bad": true, + "BadDecl": true, + "BadExpr": true, + "BadStmt": true, + "BasicLit": true, + "BinaryExpr": true, + "BlockStmt": true, + "BranchStmt": true, + "CallExpr": true, + "CaseClause": true, + "ChanDir": true, + "ChanType": true, + "CommClause": true, + "Comment": true, + "CommentGroup": true, + "CommentMap": true, + "CompositeLit": true, + "Con": true, + "DeclStmt": true, + "DeferStmt": true, + "Ellipsis": true, + "EmptyStmt": true, + "ExprStmt": true, + "Field": true, + "FieldFilter": true, + "FieldList": true, + "File": true, + "FileExports": true, + "Filter": true, + "FilterDecl": true, + "FilterFile": true, + "FilterFuncDuplicates": true, + "FilterImportDuplicates": true, + "FilterPackage": true, + "FilterUnassociatedComments": true, + "ForStmt": true, + "Fprint": true, + "Fun": true, + "FuncDecl": true, + "FuncLit": true, + "FuncType": true, + "GenDecl": true, + "GoStmt": true, + "Ident": true, + "IfStmt": true, + "ImportSpec": true, + "Importer": true, + "IncDecStmt": true, + "IndexExpr": true, + "Inspect": true, + "InterfaceType": true, + "IsExported": true, + "KeyValueExpr": true, + "LabeledStmt": true, + "Lbl": true, + "MapType": true, + "MergeMode": true, + "MergePackageFiles": true, + "NewCommentMap": true, + "NewIdent": true, + "NewObj": true, + "NewPackage": true, + "NewScope": true, + "Node": true, + "NotNilFilter": true, + "ObjKind": true, + "Object": true, + "Package": true, + "PackageExports": true, + "ParenExpr": true, + "Pkg": true, + "Print": true, + "RECV": true, + "RangeStmt": true, + "ReturnStmt": true, + "SEND": true, + "Scope": true, + "SelectStmt": true, + "SelectorExpr": true, + "SendStmt": true, + "SliceExpr": true, + "SortImports": true, + "StarExpr": true, + "StructType": true, + "SwitchStmt": true, + "Typ": true, + "TypeAssertExpr": true, + "TypeSpec": true, + "TypeSwitchStmt": true, + "UnaryExpr": true, + "ValueSpec": true, + "Var": true, + "Visitor": true, + "Walk": true, + }, + "go/build": map[string]bool{ + "AllowBinary": true, + "ArchChar": true, + "Context": true, + "Default": true, + "FindOnly": true, + "IgnoreVendor": true, + "Import": true, + "ImportComment": true, + "ImportDir": true, + "ImportMode": true, + "IsLocalImport": true, + "MultiplePackageError": true, + "NoGoError": true, + "Package": true, + "ToolDir": true, + }, + "go/constant": map[string]bool{ + "BinaryOp": true, + "BitLen": true, + "Bool": true, + "BoolVal": true, + "Bytes": true, + "Compare": true, + "Complex": true, + "Denom": true, + "Float": true, + "Float32Val": true, + "Float64Val": true, + "Imag": true, + "Int": true, + "Int64Val": true, + "Kind": true, + "MakeBool": true, + "MakeFloat64": true, + "MakeFromBytes": true, + "MakeFromLiteral": true, + "MakeImag": true, + "MakeInt64": true, + "MakeString": true, + "MakeUint64": true, + "MakeUnknown": true, + "Num": true, + "Real": true, + "Shift": true, + "Sign": true, + "String": true, + "StringVal": true, + "ToComplex": true, + "ToFloat": true, + "ToInt": true, + "Uint64Val": true, + "UnaryOp": true, + "Unknown": true, + }, + "go/doc": map[string]bool{ + "AllDecls": true, + "AllMethods": true, + "Example": true, + "Examples": true, + "Filter": true, + "Func": true, + "IllegalPrefixes": true, + "IsPredeclared": true, + "Mode": true, + "New": true, + "Note": true, + "Package": true, + "PreserveAST": true, + "Synopsis": true, + "ToHTML": true, + "ToText": true, + "Type": true, + "Value": true, + }, + "go/format": map[string]bool{ + "Node": true, + "Source": true, + }, + "go/importer": map[string]bool{ + "Default": true, + "For": true, + "ForCompiler": true, + "Lookup": true, + }, + "go/parser": map[string]bool{ + "AllErrors": true, + "DeclarationErrors": true, + "ImportsOnly": true, + "Mode": true, + "PackageClauseOnly": true, + "ParseComments": true, + "ParseDir": true, + "ParseExpr": true, + "ParseExprFrom": true, + "ParseFile": true, + "SpuriousErrors": true, + "Trace": true, + }, + "go/printer": map[string]bool{ + "CommentedNode": true, + "Config": true, + "Fprint": true, + "Mode": true, + "RawFormat": true, + "SourcePos": true, + "TabIndent": true, + "UseSpaces": true, + }, + "go/scanner": map[string]bool{ + "Error": true, + "ErrorHandler": true, + "ErrorList": true, + "Mode": true, + "PrintError": true, + "ScanComments": true, + "Scanner": true, + }, + "go/token": map[string]bool{ + "ADD": true, + "ADD_ASSIGN": true, + "AND": true, + "AND_ASSIGN": true, + "AND_NOT": true, + "AND_NOT_ASSIGN": true, + "ARROW": true, + "ASSIGN": true, + "BREAK": true, + "CASE": true, + "CHAN": true, + "CHAR": true, + "COLON": true, + "COMMA": true, + "COMMENT": true, + "CONST": true, + "CONTINUE": true, + "DEC": true, + "DEFAULT": true, + "DEFER": true, + "DEFINE": true, + "ELLIPSIS": true, + "ELSE": true, + "EOF": true, + "EQL": true, + "FALLTHROUGH": true, + "FLOAT": true, + "FOR": true, + "FUNC": true, + "File": true, + "FileSet": true, + "GEQ": true, + "GO": true, + "GOTO": true, + "GTR": true, + "HighestPrec": true, + "IDENT": true, + "IF": true, + "ILLEGAL": true, + "IMAG": true, + "IMPORT": true, + "INC": true, + "INT": true, + "INTERFACE": true, + "LAND": true, + "LBRACE": true, + "LBRACK": true, + "LEQ": true, + "LOR": true, + "LPAREN": true, + "LSS": true, + "Lookup": true, + "LowestPrec": true, + "MAP": true, + "MUL": true, + "MUL_ASSIGN": true, + "NEQ": true, + "NOT": true, + "NewFileSet": true, + "NoPos": true, + "OR": true, + "OR_ASSIGN": true, + "PACKAGE": true, + "PERIOD": true, + "Pos": true, + "Position": true, + "QUO": true, + "QUO_ASSIGN": true, + "RANGE": true, + "RBRACE": true, + "RBRACK": true, + "REM": true, + "REM_ASSIGN": true, + "RETURN": true, + "RPAREN": true, + "SELECT": true, + "SEMICOLON": true, + "SHL": true, + "SHL_ASSIGN": true, + "SHR": true, + "SHR_ASSIGN": true, + "STRING": true, + "STRUCT": true, + "SUB": true, + "SUB_ASSIGN": true, + "SWITCH": true, + "TYPE": true, + "Token": true, + "UnaryPrec": true, + "VAR": true, + "XOR": true, + "XOR_ASSIGN": true, + }, + "go/types": map[string]bool{ + "Array": true, + "AssertableTo": true, + "AssignableTo": true, + "Basic": true, + "BasicInfo": true, + "BasicKind": true, + "Bool": true, + "Builtin": true, + "Byte": true, + "Chan": true, + "ChanDir": true, + "Checker": true, + "Comparable": true, + "Complex128": true, + "Complex64": true, + "Config": true, + "Const": true, + "ConvertibleTo": true, + "DefPredeclaredTestFuncs": true, + "Default": true, + "Error": true, + "Eval": true, + "ExprString": true, + "FieldVal": true, + "Float32": true, + "Float64": true, + "Func": true, + "Id": true, + "Identical": true, + "IdenticalIgnoreTags": true, + "Implements": true, + "ImportMode": true, + "Importer": true, + "ImporterFrom": true, + "Info": true, + "Initializer": true, + "Int": true, + "Int16": true, + "Int32": true, + "Int64": true, + "Int8": true, + "Interface": true, + "Invalid": true, + "IsBoolean": true, + "IsComplex": true, + "IsConstType": true, + "IsFloat": true, + "IsInteger": true, + "IsInterface": true, + "IsNumeric": true, + "IsOrdered": true, + "IsString": true, + "IsUnsigned": true, + "IsUntyped": true, + "Label": true, + "LookupFieldOrMethod": true, + "Map": true, + "MethodExpr": true, + "MethodSet": true, + "MethodVal": true, + "MissingMethod": true, + "Named": true, + "NewArray": true, + "NewChan": true, + "NewChecker": true, + "NewConst": true, + "NewField": true, + "NewFunc": true, + "NewInterface": true, + "NewInterfaceType": true, + "NewLabel": true, + "NewMap": true, + "NewMethodSet": true, + "NewNamed": true, + "NewPackage": true, + "NewParam": true, + "NewPkgName": true, + "NewPointer": true, + "NewScope": true, + "NewSignature": true, + "NewSlice": true, + "NewStruct": true, + "NewTuple": true, + "NewTypeName": true, + "NewVar": true, + "Nil": true, + "ObjectString": true, + "Package": true, + "PkgName": true, + "Pointer": true, + "Qualifier": true, + "RecvOnly": true, + "RelativeTo": true, + "Rune": true, + "Scope": true, + "Selection": true, + "SelectionKind": true, + "SelectionString": true, + "SendOnly": true, + "SendRecv": true, + "Signature": true, + "Sizes": true, + "SizesFor": true, + "Slice": true, + "StdSizes": true, + "String": true, + "Struct": true, + "Tuple": true, + "Typ": true, + "Type": true, + "TypeAndValue": true, + "TypeName": true, + "TypeString": true, + "Uint": true, + "Uint16": true, + "Uint32": true, + "Uint64": true, + "Uint8": true, + "Uintptr": true, + "Universe": true, + "Unsafe": true, + "UnsafePointer": true, + "UntypedBool": true, + "UntypedComplex": true, + "UntypedFloat": true, + "UntypedInt": true, + "UntypedNil": true, + "UntypedRune": true, + "UntypedString": true, + "Var": true, + "WriteExpr": true, + "WriteSignature": true, + "WriteType": true, + }, + "hash": map[string]bool{ + "Hash": true, + "Hash32": true, + "Hash64": true, + }, + "hash/adler32": map[string]bool{ + "Checksum": true, + "New": true, + "Size": true, + }, + "hash/crc32": map[string]bool{ + "Castagnoli": true, + "Checksum": true, + "ChecksumIEEE": true, + "IEEE": true, + "IEEETable": true, + "Koopman": true, + "MakeTable": true, + "New": true, + "NewIEEE": true, + "Size": true, + "Table": true, + "Update": true, + }, + "hash/crc64": map[string]bool{ + "Checksum": true, + "ECMA": true, + "ISO": true, + "MakeTable": true, + "New": true, + "Size": true, + "Table": true, + "Update": true, + }, + "hash/fnv": map[string]bool{ + "New128": true, + "New128a": true, + "New32": true, + "New32a": true, + "New64": true, + "New64a": true, + }, + "html": map[string]bool{ + "EscapeString": true, + "UnescapeString": true, + }, + "html/template": map[string]bool{ + "CSS": true, + "ErrAmbigContext": true, + "ErrBadHTML": true, + "ErrBranchEnd": true, + "ErrEndContext": true, + "ErrNoSuchTemplate": true, + "ErrOutputContext": true, + "ErrPartialCharset": true, + "ErrPartialEscape": true, + "ErrPredefinedEscaper": true, + "ErrRangeLoopReentry": true, + "ErrSlashAmbig": true, + "Error": true, + "ErrorCode": true, + "FuncMap": true, + "HTML": true, + "HTMLAttr": true, + "HTMLEscape": true, + "HTMLEscapeString": true, + "HTMLEscaper": true, + "IsTrue": true, + "JS": true, + "JSEscape": true, + "JSEscapeString": true, + "JSEscaper": true, + "JSStr": true, + "Must": true, + "New": true, + "OK": true, + "ParseFiles": true, + "ParseGlob": true, + "Srcset": true, + "Template": true, + "URL": true, + "URLQueryEscaper": true, + }, + "image": map[string]bool{ + "Alpha": true, + "Alpha16": true, + "Black": true, + "CMYK": true, + "Config": true, + "Decode": true, + "DecodeConfig": true, + "ErrFormat": true, + "Gray": true, + "Gray16": true, + "Image": true, + "NRGBA": true, + "NRGBA64": true, + "NYCbCrA": true, + "NewAlpha": true, + "NewAlpha16": true, + "NewCMYK": true, + "NewGray": true, + "NewGray16": true, + "NewNRGBA": true, + "NewNRGBA64": true, + "NewNYCbCrA": true, + "NewPaletted": true, + "NewRGBA": true, + "NewRGBA64": true, + "NewUniform": true, + "NewYCbCr": true, + "Opaque": true, + "Paletted": true, + "PalettedImage": true, + "Point": true, + "Pt": true, + "RGBA": true, + "RGBA64": true, + "Rect": true, + "Rectangle": true, + "RegisterFormat": true, + "Transparent": true, + "Uniform": true, + "White": true, + "YCbCr": true, + "YCbCrSubsampleRatio": true, + "YCbCrSubsampleRatio410": true, + "YCbCrSubsampleRatio411": true, + "YCbCrSubsampleRatio420": true, + "YCbCrSubsampleRatio422": true, + "YCbCrSubsampleRatio440": true, + "YCbCrSubsampleRatio444": true, + "ZP": true, + "ZR": true, + }, + "image/color": map[string]bool{ + "Alpha": true, + "Alpha16": true, + "Alpha16Model": true, + "AlphaModel": true, + "Black": true, + "CMYK": true, + "CMYKModel": true, + "CMYKToRGB": true, + "Color": true, + "Gray": true, + "Gray16": true, + "Gray16Model": true, + "GrayModel": true, + "Model": true, + "ModelFunc": true, + "NRGBA": true, + "NRGBA64": true, + "NRGBA64Model": true, + "NRGBAModel": true, + "NYCbCrA": true, + "NYCbCrAModel": true, + "Opaque": true, + "Palette": true, + "RGBA": true, + "RGBA64": true, + "RGBA64Model": true, + "RGBAModel": true, + "RGBToCMYK": true, + "RGBToYCbCr": true, + "Transparent": true, + "White": true, + "YCbCr": true, + "YCbCrModel": true, + "YCbCrToRGB": true, + }, + "image/color/palette": map[string]bool{ + "Plan9": true, + "WebSafe": true, + }, + "image/draw": map[string]bool{ + "Draw": true, + "DrawMask": true, + "Drawer": true, + "FloydSteinberg": true, + "Image": true, + "Op": true, + "Over": true, + "Quantizer": true, + "Src": true, + }, + "image/gif": map[string]bool{ + "Decode": true, + "DecodeAll": true, + "DecodeConfig": true, + "DisposalBackground": true, + "DisposalNone": true, + "DisposalPrevious": true, + "Encode": true, + "EncodeAll": true, + "GIF": true, + "Options": true, + }, + "image/jpeg": map[string]bool{ + "Decode": true, + "DecodeConfig": true, + "DefaultQuality": true, + "Encode": true, + "FormatError": true, + "Options": true, + "Reader": true, + "UnsupportedError": true, + }, + "image/png": map[string]bool{ + "BestCompression": true, + "BestSpeed": true, + "CompressionLevel": true, + "Decode": true, + "DecodeConfig": true, + "DefaultCompression": true, + "Encode": true, + "Encoder": true, + "EncoderBuffer": true, + "EncoderBufferPool": true, + "FormatError": true, + "NoCompression": true, + "UnsupportedError": true, + }, + "index/suffixarray": map[string]bool{ + "Index": true, + "New": true, + }, + "io": map[string]bool{ + "ByteReader": true, + "ByteScanner": true, + "ByteWriter": true, + "Closer": true, + "Copy": true, + "CopyBuffer": true, + "CopyN": true, + "EOF": true, + "ErrClosedPipe": true, + "ErrNoProgress": true, + "ErrShortBuffer": true, + "ErrShortWrite": true, + "ErrUnexpectedEOF": true, + "LimitReader": true, + "LimitedReader": true, + "MultiReader": true, + "MultiWriter": true, + "NewSectionReader": true, + "Pipe": true, + "PipeReader": true, + "PipeWriter": true, + "ReadAtLeast": true, + "ReadCloser": true, + "ReadFull": true, + "ReadSeeker": true, + "ReadWriteCloser": true, + "ReadWriteSeeker": true, + "ReadWriter": true, + "Reader": true, + "ReaderAt": true, + "ReaderFrom": true, + "RuneReader": true, + "RuneScanner": true, + "SectionReader": true, + "SeekCurrent": true, + "SeekEnd": true, + "SeekStart": true, + "Seeker": true, + "StringWriter": true, + "TeeReader": true, + "WriteCloser": true, + "WriteSeeker": true, + "WriteString": true, + "Writer": true, + "WriterAt": true, + "WriterTo": true, + }, + "io/ioutil": map[string]bool{ + "Discard": true, + "NopCloser": true, + "ReadAll": true, + "ReadDir": true, + "ReadFile": true, + "TempDir": true, + "TempFile": true, + "WriteFile": true, + }, + "log": map[string]bool{ + "Fatal": true, + "Fatalf": true, + "Fatalln": true, + "Flags": true, + "LUTC": true, + "Ldate": true, + "Llongfile": true, + "Lmicroseconds": true, + "Logger": true, + "Lshortfile": true, + "LstdFlags": true, + "Ltime": true, + "New": true, + "Output": true, + "Panic": true, + "Panicf": true, + "Panicln": true, + "Prefix": true, + "Print": true, + "Printf": true, + "Println": true, + "SetFlags": true, + "SetOutput": true, + "SetPrefix": true, + }, + "log/syslog": map[string]bool{ + "Dial": true, + "LOG_ALERT": true, + "LOG_AUTH": true, + "LOG_AUTHPRIV": true, + "LOG_CRIT": true, + "LOG_CRON": true, + "LOG_DAEMON": true, + "LOG_DEBUG": true, + "LOG_EMERG": true, + "LOG_ERR": true, + "LOG_FTP": true, + "LOG_INFO": true, + "LOG_KERN": true, + "LOG_LOCAL0": true, + "LOG_LOCAL1": true, + "LOG_LOCAL2": true, + "LOG_LOCAL3": true, + "LOG_LOCAL4": true, + "LOG_LOCAL5": true, + "LOG_LOCAL6": true, + "LOG_LOCAL7": true, + "LOG_LPR": true, + "LOG_MAIL": true, + "LOG_NEWS": true, + "LOG_NOTICE": true, + "LOG_SYSLOG": true, + "LOG_USER": true, + "LOG_UUCP": true, + "LOG_WARNING": true, + "New": true, + "NewLogger": true, + "Priority": true, + "Writer": true, + }, + "math": map[string]bool{ + "Abs": true, + "Acos": true, + "Acosh": true, + "Asin": true, + "Asinh": true, + "Atan": true, + "Atan2": true, + "Atanh": true, + "Cbrt": true, + "Ceil": true, + "Copysign": true, + "Cos": true, + "Cosh": true, + "Dim": true, + "E": true, + "Erf": true, + "Erfc": true, + "Erfcinv": true, + "Erfinv": true, + "Exp": true, + "Exp2": true, + "Expm1": true, + "Float32bits": true, + "Float32frombits": true, + "Float64bits": true, + "Float64frombits": true, + "Floor": true, + "Frexp": true, + "Gamma": true, + "Hypot": true, + "Ilogb": true, + "Inf": true, + "IsInf": true, + "IsNaN": true, + "J0": true, + "J1": true, + "Jn": true, + "Ldexp": true, + "Lgamma": true, + "Ln10": true, + "Ln2": true, + "Log": true, + "Log10": true, + "Log10E": true, + "Log1p": true, + "Log2": true, + "Log2E": true, + "Logb": true, + "Max": true, + "MaxFloat32": true, + "MaxFloat64": true, + "MaxInt16": true, + "MaxInt32": true, + "MaxInt64": true, + "MaxInt8": true, + "MaxUint16": true, + "MaxUint32": true, + "MaxUint64": true, + "MaxUint8": true, + "Min": true, + "MinInt16": true, + "MinInt32": true, + "MinInt64": true, + "MinInt8": true, + "Mod": true, + "Modf": true, + "NaN": true, + "Nextafter": true, + "Nextafter32": true, + "Phi": true, + "Pi": true, + "Pow": true, + "Pow10": true, + "Remainder": true, + "Round": true, + "RoundToEven": true, + "Signbit": true, + "Sin": true, + "Sincos": true, + "Sinh": true, + "SmallestNonzeroFloat32": true, + "SmallestNonzeroFloat64": true, + "Sqrt": true, + "Sqrt2": true, + "SqrtE": true, + "SqrtPhi": true, + "SqrtPi": true, + "Tan": true, + "Tanh": true, + "Trunc": true, + "Y0": true, + "Y1": true, + "Yn": true, + }, + "math/big": map[string]bool{ + "Above": true, + "Accuracy": true, + "AwayFromZero": true, + "Below": true, + "ErrNaN": true, + "Exact": true, + "Float": true, + "Int": true, + "Jacobi": true, + "MaxBase": true, + "MaxExp": true, + "MaxPrec": true, + "MinExp": true, + "NewFloat": true, + "NewInt": true, + "NewRat": true, + "ParseFloat": true, + "Rat": true, + "RoundingMode": true, + "ToNearestAway": true, + "ToNearestEven": true, + "ToNegativeInf": true, + "ToPositiveInf": true, + "ToZero": true, + "Word": true, + }, + "math/bits": map[string]bool{ + "Add": true, + "Add32": true, + "Add64": true, + "Div": true, + "Div32": true, + "Div64": true, + "LeadingZeros": true, + "LeadingZeros16": true, + "LeadingZeros32": true, + "LeadingZeros64": true, + "LeadingZeros8": true, + "Len": true, + "Len16": true, + "Len32": true, + "Len64": true, + "Len8": true, + "Mul": true, + "Mul32": true, + "Mul64": true, + "OnesCount": true, + "OnesCount16": true, + "OnesCount32": true, + "OnesCount64": true, + "OnesCount8": true, + "Reverse": true, + "Reverse16": true, + "Reverse32": true, + "Reverse64": true, + "Reverse8": true, + "ReverseBytes": true, + "ReverseBytes16": true, + "ReverseBytes32": true, + "ReverseBytes64": true, + "RotateLeft": true, + "RotateLeft16": true, + "RotateLeft32": true, + "RotateLeft64": true, + "RotateLeft8": true, + "Sub": true, + "Sub32": true, + "Sub64": true, + "TrailingZeros": true, + "TrailingZeros16": true, + "TrailingZeros32": true, + "TrailingZeros64": true, + "TrailingZeros8": true, + "UintSize": true, + }, + "math/cmplx": map[string]bool{ + "Abs": true, + "Acos": true, + "Acosh": true, + "Asin": true, + "Asinh": true, + "Atan": true, + "Atanh": true, + "Conj": true, + "Cos": true, + "Cosh": true, + "Cot": true, + "Exp": true, + "Inf": true, + "IsInf": true, + "IsNaN": true, + "Log": true, + "Log10": true, + "NaN": true, + "Phase": true, + "Polar": true, + "Pow": true, + "Rect": true, + "Sin": true, + "Sinh": true, + "Sqrt": true, + "Tan": true, + "Tanh": true, + }, + "math/rand": map[string]bool{ + "ExpFloat64": true, + "Float32": true, + "Float64": true, + "Int": true, + "Int31": true, + "Int31n": true, + "Int63": true, + "Int63n": true, + "Intn": true, + "New": true, + "NewSource": true, + "NewZipf": true, + "NormFloat64": true, + "Perm": true, + "Rand": true, + "Read": true, + "Seed": true, + "Shuffle": true, + "Source": true, + "Source64": true, + "Uint32": true, + "Uint64": true, + "Zipf": true, + }, + "mime": map[string]bool{ + "AddExtensionType": true, + "BEncoding": true, + "ErrInvalidMediaParameter": true, + "ExtensionsByType": true, + "FormatMediaType": true, + "ParseMediaType": true, + "QEncoding": true, + "TypeByExtension": true, + "WordDecoder": true, + "WordEncoder": true, + }, + "mime/multipart": map[string]bool{ + "ErrMessageTooLarge": true, + "File": true, + "FileHeader": true, + "Form": true, + "NewReader": true, + "NewWriter": true, + "Part": true, + "Reader": true, + "Writer": true, + }, + "mime/quotedprintable": map[string]bool{ + "NewReader": true, + "NewWriter": true, + "Reader": true, + "Writer": true, + }, + "net": map[string]bool{ + "Addr": true, + "AddrError": true, + "Buffers": true, + "CIDRMask": true, + "Conn": true, + "DNSConfigError": true, + "DNSError": true, + "DefaultResolver": true, + "Dial": true, + "DialIP": true, + "DialTCP": true, + "DialTimeout": true, + "DialUDP": true, + "DialUnix": true, + "Dialer": true, + "ErrWriteToConnected": true, + "Error": true, + "FileConn": true, + "FileListener": true, + "FilePacketConn": true, + "FlagBroadcast": true, + "FlagLoopback": true, + "FlagMulticast": true, + "FlagPointToPoint": true, + "FlagUp": true, + "Flags": true, + "HardwareAddr": true, + "IP": true, + "IPAddr": true, + "IPConn": true, + "IPMask": true, + "IPNet": true, + "IPv4": true, + "IPv4Mask": true, + "IPv4allrouter": true, + "IPv4allsys": true, + "IPv4bcast": true, + "IPv4len": true, + "IPv4zero": true, + "IPv6interfacelocalallnodes": true, + "IPv6len": true, + "IPv6linklocalallnodes": true, + "IPv6linklocalallrouters": true, + "IPv6loopback": true, + "IPv6unspecified": true, + "IPv6zero": true, + "Interface": true, + "InterfaceAddrs": true, + "InterfaceByIndex": true, + "InterfaceByName": true, + "Interfaces": true, + "InvalidAddrError": true, + "JoinHostPort": true, + "Listen": true, + "ListenConfig": true, + "ListenIP": true, + "ListenMulticastUDP": true, + "ListenPacket": true, + "ListenTCP": true, + "ListenUDP": true, + "ListenUnix": true, + "ListenUnixgram": true, + "Listener": true, + "LookupAddr": true, + "LookupCNAME": true, + "LookupHost": true, + "LookupIP": true, + "LookupMX": true, + "LookupNS": true, + "LookupPort": true, + "LookupSRV": true, + "LookupTXT": true, + "MX": true, + "NS": true, + "OpError": true, + "PacketConn": true, + "ParseCIDR": true, + "ParseError": true, + "ParseIP": true, + "ParseMAC": true, + "Pipe": true, + "ResolveIPAddr": true, + "ResolveTCPAddr": true, + "ResolveUDPAddr": true, + "ResolveUnixAddr": true, + "Resolver": true, + "SRV": true, + "SplitHostPort": true, + "TCPAddr": true, + "TCPConn": true, + "TCPListener": true, + "UDPAddr": true, + "UDPConn": true, + "UnixAddr": true, + "UnixConn": true, + "UnixListener": true, + "UnknownNetworkError": true, + }, + "net/http": map[string]bool{ + "CanonicalHeaderKey": true, + "Client": true, + "CloseNotifier": true, + "ConnState": true, + "Cookie": true, + "CookieJar": true, + "DefaultClient": true, + "DefaultMaxHeaderBytes": true, + "DefaultMaxIdleConnsPerHost": true, + "DefaultServeMux": true, + "DefaultTransport": true, + "DetectContentType": true, + "Dir": true, + "ErrAbortHandler": true, + "ErrBodyNotAllowed": true, + "ErrBodyReadAfterClose": true, + "ErrContentLength": true, + "ErrHandlerTimeout": true, + "ErrHeaderTooLong": true, + "ErrHijacked": true, + "ErrLineTooLong": true, + "ErrMissingBoundary": true, + "ErrMissingContentLength": true, + "ErrMissingFile": true, + "ErrNoCookie": true, + "ErrNoLocation": true, + "ErrNotMultipart": true, + "ErrNotSupported": true, + "ErrServerClosed": true, + "ErrShortBody": true, + "ErrSkipAltProtocol": true, + "ErrUnexpectedTrailer": true, + "ErrUseLastResponse": true, + "ErrWriteAfterFlush": true, + "Error": true, + "File": true, + "FileServer": true, + "FileSystem": true, + "Flusher": true, + "Get": true, + "Handle": true, + "HandleFunc": true, + "Handler": true, + "HandlerFunc": true, + "Head": true, + "Header": true, + "Hijacker": true, + "ListenAndServe": true, + "ListenAndServeTLS": true, + "LocalAddrContextKey": true, + "MaxBytesReader": true, + "MethodConnect": true, + "MethodDelete": true, + "MethodGet": true, + "MethodHead": true, + "MethodOptions": true, + "MethodPatch": true, + "MethodPost": true, + "MethodPut": true, + "MethodTrace": true, + "NewFileTransport": true, + "NewRequest": true, + "NewServeMux": true, + "NoBody": true, + "NotFound": true, + "NotFoundHandler": true, + "ParseHTTPVersion": true, + "ParseTime": true, + "Post": true, + "PostForm": true, + "ProtocolError": true, + "ProxyFromEnvironment": true, + "ProxyURL": true, + "PushOptions": true, + "Pusher": true, + "ReadRequest": true, + "ReadResponse": true, + "Redirect": true, + "RedirectHandler": true, + "Request": true, + "Response": true, + "ResponseWriter": true, + "RoundTripper": true, + "SameSite": true, + "SameSiteDefaultMode": true, + "SameSiteLaxMode": true, + "SameSiteStrictMode": true, + "Serve": true, + "ServeContent": true, + "ServeFile": true, + "ServeMux": true, + "ServeTLS": true, + "Server": true, + "ServerContextKey": true, + "SetCookie": true, + "StateActive": true, + "StateClosed": true, + "StateHijacked": true, + "StateIdle": true, + "StateNew": true, + "StatusAccepted": true, + "StatusAlreadyReported": true, + "StatusBadGateway": true, + "StatusBadRequest": true, + "StatusConflict": true, + "StatusContinue": true, + "StatusCreated": true, + "StatusExpectationFailed": true, + "StatusFailedDependency": true, + "StatusForbidden": true, + "StatusFound": true, + "StatusGatewayTimeout": true, + "StatusGone": true, + "StatusHTTPVersionNotSupported": true, + "StatusIMUsed": true, + "StatusInsufficientStorage": true, + "StatusInternalServerError": true, + "StatusLengthRequired": true, + "StatusLocked": true, + "StatusLoopDetected": true, + "StatusMethodNotAllowed": true, + "StatusMisdirectedRequest": true, + "StatusMovedPermanently": true, + "StatusMultiStatus": true, + "StatusMultipleChoices": true, + "StatusNetworkAuthenticationRequired": true, + "StatusNoContent": true, + "StatusNonAuthoritativeInfo": true, + "StatusNotAcceptable": true, + "StatusNotExtended": true, + "StatusNotFound": true, + "StatusNotImplemented": true, + "StatusNotModified": true, + "StatusOK": true, + "StatusPartialContent": true, + "StatusPaymentRequired": true, + "StatusPermanentRedirect": true, + "StatusPreconditionFailed": true, + "StatusPreconditionRequired": true, + "StatusProcessing": true, + "StatusProxyAuthRequired": true, + "StatusRequestEntityTooLarge": true, + "StatusRequestHeaderFieldsTooLarge": true, + "StatusRequestTimeout": true, + "StatusRequestURITooLong": true, + "StatusRequestedRangeNotSatisfiable": true, + "StatusResetContent": true, + "StatusSeeOther": true, + "StatusServiceUnavailable": true, + "StatusSwitchingProtocols": true, + "StatusTeapot": true, + "StatusTemporaryRedirect": true, + "StatusText": true, + "StatusTooEarly": true, + "StatusTooManyRequests": true, + "StatusUnauthorized": true, + "StatusUnavailableForLegalReasons": true, + "StatusUnprocessableEntity": true, + "StatusUnsupportedMediaType": true, + "StatusUpgradeRequired": true, + "StatusUseProxy": true, + "StatusVariantAlsoNegotiates": true, + "StripPrefix": true, + "TimeFormat": true, + "TimeoutHandler": true, + "TrailerPrefix": true, + "Transport": true, + }, + "net/http/cgi": map[string]bool{ + "Handler": true, + "Request": true, + "RequestFromMap": true, + "Serve": true, + }, + "net/http/cookiejar": map[string]bool{ + "Jar": true, + "New": true, + "Options": true, + "PublicSuffixList": true, + }, + "net/http/fcgi": map[string]bool{ + "ErrConnClosed": true, + "ErrRequestAborted": true, + "ProcessEnv": true, + "Serve": true, + }, + "net/http/httptest": map[string]bool{ + "DefaultRemoteAddr": true, + "NewRecorder": true, + "NewRequest": true, + "NewServer": true, + "NewTLSServer": true, + "NewUnstartedServer": true, + "ResponseRecorder": true, + "Server": true, + }, + "net/http/httptrace": map[string]bool{ + "ClientTrace": true, + "ContextClientTrace": true, + "DNSDoneInfo": true, + "DNSStartInfo": true, + "GotConnInfo": true, + "WithClientTrace": true, + "WroteRequestInfo": true, + }, + "net/http/httputil": map[string]bool{ + "BufferPool": true, + "ClientConn": true, + "DumpRequest": true, + "DumpRequestOut": true, + "DumpResponse": true, + "ErrClosed": true, + "ErrLineTooLong": true, + "ErrPersistEOF": true, + "ErrPipeline": true, + "NewChunkedReader": true, + "NewChunkedWriter": true, + "NewClientConn": true, + "NewProxyClientConn": true, + "NewServerConn": true, + "NewSingleHostReverseProxy": true, + "ReverseProxy": true, + "ServerConn": true, + }, + "net/http/pprof": map[string]bool{ + "Cmdline": true, + "Handler": true, + "Index": true, + "Profile": true, + "Symbol": true, + "Trace": true, + }, + "net/mail": map[string]bool{ + "Address": true, + "AddressParser": true, + "ErrHeaderNotPresent": true, + "Header": true, + "Message": true, + "ParseAddress": true, + "ParseAddressList": true, + "ParseDate": true, + "ReadMessage": true, + }, + "net/rpc": map[string]bool{ + "Accept": true, + "Call": true, + "Client": true, + "ClientCodec": true, + "DefaultDebugPath": true, + "DefaultRPCPath": true, + "DefaultServer": true, + "Dial": true, + "DialHTTP": true, + "DialHTTPPath": true, + "ErrShutdown": true, + "HandleHTTP": true, + "NewClient": true, + "NewClientWithCodec": true, + "NewServer": true, + "Register": true, + "RegisterName": true, + "Request": true, + "Response": true, + "ServeCodec": true, + "ServeConn": true, + "ServeRequest": true, + "Server": true, + "ServerCodec": true, + "ServerError": true, + }, + "net/rpc/jsonrpc": map[string]bool{ + "Dial": true, + "NewClient": true, + "NewClientCodec": true, + "NewServerCodec": true, + "ServeConn": true, + }, + "net/smtp": map[string]bool{ + "Auth": true, + "CRAMMD5Auth": true, + "Client": true, + "Dial": true, + "NewClient": true, + "PlainAuth": true, + "SendMail": true, + "ServerInfo": true, + }, + "net/textproto": map[string]bool{ + "CanonicalMIMEHeaderKey": true, + "Conn": true, + "Dial": true, + "Error": true, + "MIMEHeader": true, + "NewConn": true, + "NewReader": true, + "NewWriter": true, + "Pipeline": true, + "ProtocolError": true, + "Reader": true, + "TrimBytes": true, + "TrimString": true, + "Writer": true, + }, + "net/url": map[string]bool{ + "Error": true, + "EscapeError": true, + "InvalidHostError": true, + "Parse": true, + "ParseQuery": true, + "ParseRequestURI": true, + "PathEscape": true, + "PathUnescape": true, + "QueryEscape": true, + "QueryUnescape": true, + "URL": true, + "User": true, + "UserPassword": true, + "Userinfo": true, + "Values": true, + }, + "os": map[string]bool{ + "Args": true, + "Chdir": true, + "Chmod": true, + "Chown": true, + "Chtimes": true, + "Clearenv": true, + "Create": true, + "DevNull": true, + "Environ": true, + "ErrClosed": true, + "ErrExist": true, + "ErrInvalid": true, + "ErrNoDeadline": true, + "ErrNotExist": true, + "ErrPermission": true, + "Executable": true, + "Exit": true, + "Expand": true, + "ExpandEnv": true, + "File": true, + "FileInfo": true, + "FileMode": true, + "FindProcess": true, + "Getegid": true, + "Getenv": true, + "Geteuid": true, + "Getgid": true, + "Getgroups": true, + "Getpagesize": true, + "Getpid": true, + "Getppid": true, + "Getuid": true, + "Getwd": true, + "Hostname": true, + "Interrupt": true, + "IsExist": true, + "IsNotExist": true, + "IsPathSeparator": true, + "IsPermission": true, + "IsTimeout": true, + "Kill": true, + "Lchown": true, + "Link": true, + "LinkError": true, + "LookupEnv": true, + "Lstat": true, + "Mkdir": true, + "MkdirAll": true, + "ModeAppend": true, + "ModeCharDevice": true, + "ModeDevice": true, + "ModeDir": true, + "ModeExclusive": true, + "ModeIrregular": true, + "ModeNamedPipe": true, + "ModePerm": true, + "ModeSetgid": true, + "ModeSetuid": true, + "ModeSocket": true, + "ModeSticky": true, + "ModeSymlink": true, + "ModeTemporary": true, + "ModeType": true, + "NewFile": true, + "NewSyscallError": true, + "O_APPEND": true, + "O_CREATE": true, + "O_EXCL": true, + "O_RDONLY": true, + "O_RDWR": true, + "O_SYNC": true, + "O_TRUNC": true, + "O_WRONLY": true, + "Open": true, + "OpenFile": true, + "PathError": true, + "PathListSeparator": true, + "PathSeparator": true, + "Pipe": true, + "ProcAttr": true, + "Process": true, + "ProcessState": true, + "Readlink": true, + "Remove": true, + "RemoveAll": true, + "Rename": true, + "SEEK_CUR": true, + "SEEK_END": true, + "SEEK_SET": true, + "SameFile": true, + "Setenv": true, + "Signal": true, + "StartProcess": true, + "Stat": true, + "Stderr": true, + "Stdin": true, + "Stdout": true, + "Symlink": true, + "SyscallError": true, + "TempDir": true, + "Truncate": true, + "Unsetenv": true, + "UserCacheDir": true, + "UserHomeDir": true, + }, + "os/exec": map[string]bool{ + "Cmd": true, + "Command": true, + "CommandContext": true, + "ErrNotFound": true, + "Error": true, + "ExitError": true, + "LookPath": true, + }, + "os/signal": map[string]bool{ + "Ignore": true, + "Ignored": true, + "Notify": true, + "Reset": true, + "Stop": true, + }, + "os/user": map[string]bool{ + "Current": true, + "Group": true, + "Lookup": true, + "LookupGroup": true, + "LookupGroupId": true, + "LookupId": true, + "UnknownGroupError": true, + "UnknownGroupIdError": true, + "UnknownUserError": true, + "UnknownUserIdError": true, + "User": true, + }, + "path": map[string]bool{ + "Base": true, + "Clean": true, + "Dir": true, + "ErrBadPattern": true, + "Ext": true, + "IsAbs": true, + "Join": true, + "Match": true, + "Split": true, + }, + "path/filepath": map[string]bool{ + "Abs": true, + "Base": true, + "Clean": true, + "Dir": true, + "ErrBadPattern": true, + "EvalSymlinks": true, + "Ext": true, + "FromSlash": true, + "Glob": true, + "HasPrefix": true, + "IsAbs": true, + "Join": true, + "ListSeparator": true, + "Match": true, + "Rel": true, + "Separator": true, + "SkipDir": true, + "Split": true, + "SplitList": true, + "ToSlash": true, + "VolumeName": true, + "Walk": true, + "WalkFunc": true, + }, + "plugin": map[string]bool{ + "Open": true, + "Plugin": true, + "Symbol": true, + }, + "reflect": map[string]bool{ + "Append": true, + "AppendSlice": true, + "Array": true, + "ArrayOf": true, + "Bool": true, + "BothDir": true, + "Chan": true, + "ChanDir": true, + "ChanOf": true, + "Complex128": true, + "Complex64": true, + "Copy": true, + "DeepEqual": true, + "Float32": true, + "Float64": true, + "Func": true, + "FuncOf": true, + "Indirect": true, + "Int": true, + "Int16": true, + "Int32": true, + "Int64": true, + "Int8": true, + "Interface": true, + "Invalid": true, + "Kind": true, + "MakeChan": true, + "MakeFunc": true, + "MakeMap": true, + "MakeMapWithSize": true, + "MakeSlice": true, + "Map": true, + "MapIter": true, + "MapOf": true, + "Method": true, + "New": true, + "NewAt": true, + "Ptr": true, + "PtrTo": true, + "RecvDir": true, + "Select": true, + "SelectCase": true, + "SelectDefault": true, + "SelectDir": true, + "SelectRecv": true, + "SelectSend": true, + "SendDir": true, + "Slice": true, + "SliceHeader": true, + "SliceOf": true, + "String": true, + "StringHeader": true, + "Struct": true, + "StructField": true, + "StructOf": true, + "StructTag": true, + "Swapper": true, + "TypeOf": true, + "Uint": true, + "Uint16": true, + "Uint32": true, + "Uint64": true, + "Uint8": true, + "Uintptr": true, + "UnsafePointer": true, + "Value": true, + "ValueError": true, + "ValueOf": true, + "Zero": true, + }, + "regexp": map[string]bool{ + "Compile": true, + "CompilePOSIX": true, + "Match": true, + "MatchReader": true, + "MatchString": true, + "MustCompile": true, + "MustCompilePOSIX": true, + "QuoteMeta": true, + "Regexp": true, + }, + "regexp/syntax": map[string]bool{ + "ClassNL": true, + "Compile": true, + "DotNL": true, + "EmptyBeginLine": true, + "EmptyBeginText": true, + "EmptyEndLine": true, + "EmptyEndText": true, + "EmptyNoWordBoundary": true, + "EmptyOp": true, + "EmptyOpContext": true, + "EmptyWordBoundary": true, + "ErrInternalError": true, + "ErrInvalidCharClass": true, + "ErrInvalidCharRange": true, + "ErrInvalidEscape": true, + "ErrInvalidNamedCapture": true, + "ErrInvalidPerlOp": true, + "ErrInvalidRepeatOp": true, + "ErrInvalidRepeatSize": true, + "ErrInvalidUTF8": true, + "ErrMissingBracket": true, + "ErrMissingParen": true, + "ErrMissingRepeatArgument": true, + "ErrTrailingBackslash": true, + "ErrUnexpectedParen": true, + "Error": true, + "ErrorCode": true, + "Flags": true, + "FoldCase": true, + "Inst": true, + "InstAlt": true, + "InstAltMatch": true, + "InstCapture": true, + "InstEmptyWidth": true, + "InstFail": true, + "InstMatch": true, + "InstNop": true, + "InstOp": true, + "InstRune": true, + "InstRune1": true, + "InstRuneAny": true, + "InstRuneAnyNotNL": true, + "IsWordChar": true, + "Literal": true, + "MatchNL": true, + "NonGreedy": true, + "OneLine": true, + "Op": true, + "OpAlternate": true, + "OpAnyChar": true, + "OpAnyCharNotNL": true, + "OpBeginLine": true, + "OpBeginText": true, + "OpCapture": true, + "OpCharClass": true, + "OpConcat": true, + "OpEmptyMatch": true, + "OpEndLine": true, + "OpEndText": true, + "OpLiteral": true, + "OpNoMatch": true, + "OpNoWordBoundary": true, + "OpPlus": true, + "OpQuest": true, + "OpRepeat": true, + "OpStar": true, + "OpWordBoundary": true, + "POSIX": true, + "Parse": true, + "Perl": true, + "PerlX": true, + "Prog": true, + "Regexp": true, + "Simple": true, + "UnicodeGroups": true, + "WasDollar": true, + }, + "runtime": map[string]bool{ + "BlockProfile": true, + "BlockProfileRecord": true, + "Breakpoint": true, + "CPUProfile": true, + "Caller": true, + "Callers": true, + "CallersFrames": true, + "Compiler": true, + "Error": true, + "Frame": true, + "Frames": true, + "Func": true, + "FuncForPC": true, + "GC": true, + "GOARCH": true, + "GOMAXPROCS": true, + "GOOS": true, + "GOROOT": true, + "Goexit": true, + "GoroutineProfile": true, + "Gosched": true, + "KeepAlive": true, + "LockOSThread": true, + "MemProfile": true, + "MemProfileRate": true, + "MemProfileRecord": true, + "MemStats": true, + "MutexProfile": true, + "NumCPU": true, + "NumCgoCall": true, + "NumGoroutine": true, + "ReadMemStats": true, + "ReadTrace": true, + "SetBlockProfileRate": true, + "SetCPUProfileRate": true, + "SetCgoTraceback": true, + "SetFinalizer": true, + "SetMutexProfileFraction": true, + "Stack": true, + "StackRecord": true, + "StartTrace": true, + "StopTrace": true, + "ThreadCreateProfile": true, + "TypeAssertionError": true, + "UnlockOSThread": true, + "Version": true, + }, + "runtime/debug": map[string]bool{ + "BuildInfo": true, + "FreeOSMemory": true, + "GCStats": true, + "Module": true, + "PrintStack": true, + "ReadBuildInfo": true, + "ReadGCStats": true, + "SetGCPercent": true, + "SetMaxStack": true, + "SetMaxThreads": true, + "SetPanicOnFault": true, + "SetTraceback": true, + "Stack": true, + "WriteHeapDump": true, + }, + "runtime/pprof": map[string]bool{ + "Do": true, + "ForLabels": true, + "Label": true, + "LabelSet": true, + "Labels": true, + "Lookup": true, + "NewProfile": true, + "Profile": true, + "Profiles": true, + "SetGoroutineLabels": true, + "StartCPUProfile": true, + "StopCPUProfile": true, + "WithLabels": true, + "WriteHeapProfile": true, + }, + "runtime/trace": map[string]bool{ + "IsEnabled": true, + "Log": true, + "Logf": true, + "NewTask": true, + "Region": true, + "Start": true, + "StartRegion": true, + "Stop": true, + "Task": true, + "WithRegion": true, + }, + "sort": map[string]bool{ + "Float64Slice": true, + "Float64s": true, + "Float64sAreSorted": true, + "IntSlice": true, + "Interface": true, + "Ints": true, + "IntsAreSorted": true, + "IsSorted": true, + "Reverse": true, + "Search": true, + "SearchFloat64s": true, + "SearchInts": true, + "SearchStrings": true, + "Slice": true, + "SliceIsSorted": true, + "SliceStable": true, + "Sort": true, + "Stable": true, + "StringSlice": true, + "Strings": true, + "StringsAreSorted": true, + }, + "strconv": map[string]bool{ + "AppendBool": true, + "AppendFloat": true, + "AppendInt": true, + "AppendQuote": true, + "AppendQuoteRune": true, + "AppendQuoteRuneToASCII": true, + "AppendQuoteRuneToGraphic": true, + "AppendQuoteToASCII": true, + "AppendQuoteToGraphic": true, + "AppendUint": true, + "Atoi": true, + "CanBackquote": true, + "ErrRange": true, + "ErrSyntax": true, + "FormatBool": true, + "FormatFloat": true, + "FormatInt": true, + "FormatUint": true, + "IntSize": true, + "IsGraphic": true, + "IsPrint": true, + "Itoa": true, + "NumError": true, + "ParseBool": true, + "ParseFloat": true, + "ParseInt": true, + "ParseUint": true, + "Quote": true, + "QuoteRune": true, + "QuoteRuneToASCII": true, + "QuoteRuneToGraphic": true, + "QuoteToASCII": true, + "QuoteToGraphic": true, + "Unquote": true, + "UnquoteChar": true, + }, + "strings": map[string]bool{ + "Builder": true, + "Compare": true, + "Contains": true, + "ContainsAny": true, + "ContainsRune": true, + "Count": true, + "EqualFold": true, + "Fields": true, + "FieldsFunc": true, + "HasPrefix": true, + "HasSuffix": true, + "Index": true, + "IndexAny": true, + "IndexByte": true, + "IndexFunc": true, + "IndexRune": true, + "Join": true, + "LastIndex": true, + "LastIndexAny": true, + "LastIndexByte": true, + "LastIndexFunc": true, + "Map": true, + "NewReader": true, + "NewReplacer": true, + "Reader": true, + "Repeat": true, + "Replace": true, + "ReplaceAll": true, + "Replacer": true, + "Split": true, + "SplitAfter": true, + "SplitAfterN": true, + "SplitN": true, + "Title": true, + "ToLower": true, + "ToLowerSpecial": true, + "ToTitle": true, + "ToTitleSpecial": true, + "ToUpper": true, + "ToUpperSpecial": true, + "Trim": true, + "TrimFunc": true, + "TrimLeft": true, + "TrimLeftFunc": true, + "TrimPrefix": true, + "TrimRight": true, + "TrimRightFunc": true, + "TrimSpace": true, + "TrimSuffix": true, + }, + "sync": map[string]bool{ + "Cond": true, + "Locker": true, + "Map": true, + "Mutex": true, + "NewCond": true, + "Once": true, + "Pool": true, + "RWMutex": true, + "WaitGroup": true, + }, + "sync/atomic": map[string]bool{ + "AddInt32": true, + "AddInt64": true, + "AddUint32": true, + "AddUint64": true, + "AddUintptr": true, + "CompareAndSwapInt32": true, + "CompareAndSwapInt64": true, + "CompareAndSwapPointer": true, + "CompareAndSwapUint32": true, + "CompareAndSwapUint64": true, + "CompareAndSwapUintptr": true, + "LoadInt32": true, + "LoadInt64": true, + "LoadPointer": true, + "LoadUint32": true, + "LoadUint64": true, + "LoadUintptr": true, + "StoreInt32": true, + "StoreInt64": true, + "StorePointer": true, + "StoreUint32": true, + "StoreUint64": true, + "StoreUintptr": true, + "SwapInt32": true, + "SwapInt64": true, + "SwapPointer": true, + "SwapUint32": true, + "SwapUint64": true, + "SwapUintptr": true, + "Value": true, + }, + "syscall": map[string]bool{ + "AF_ALG": true, + "AF_APPLETALK": true, + "AF_ARP": true, + "AF_ASH": true, + "AF_ATM": true, + "AF_ATMPVC": true, + "AF_ATMSVC": true, + "AF_AX25": true, + "AF_BLUETOOTH": true, + "AF_BRIDGE": true, + "AF_CAIF": true, + "AF_CAN": true, + "AF_CCITT": true, + "AF_CHAOS": true, + "AF_CNT": true, + "AF_COIP": true, + "AF_DATAKIT": true, + "AF_DECnet": true, + "AF_DLI": true, + "AF_E164": true, + "AF_ECMA": true, + "AF_ECONET": true, + "AF_ENCAP": true, + "AF_FILE": true, + "AF_HYLINK": true, + "AF_IEEE80211": true, + "AF_IEEE802154": true, + "AF_IMPLINK": true, + "AF_INET": true, + "AF_INET6": true, + "AF_INET6_SDP": true, + "AF_INET_SDP": true, + "AF_IPX": true, + "AF_IRDA": true, + "AF_ISDN": true, + "AF_ISO": true, + "AF_IUCV": true, + "AF_KEY": true, + "AF_LAT": true, + "AF_LINK": true, + "AF_LLC": true, + "AF_LOCAL": true, + "AF_MAX": true, + "AF_MPLS": true, + "AF_NATM": true, + "AF_NDRV": true, + "AF_NETBEUI": true, + "AF_NETBIOS": true, + "AF_NETGRAPH": true, + "AF_NETLINK": true, + "AF_NETROM": true, + "AF_NS": true, + "AF_OROUTE": true, + "AF_OSI": true, + "AF_PACKET": true, + "AF_PHONET": true, + "AF_PPP": true, + "AF_PPPOX": true, + "AF_PUP": true, + "AF_RDS": true, + "AF_RESERVED_36": true, + "AF_ROSE": true, + "AF_ROUTE": true, + "AF_RXRPC": true, + "AF_SCLUSTER": true, + "AF_SECURITY": true, + "AF_SIP": true, + "AF_SLOW": true, + "AF_SNA": true, + "AF_SYSTEM": true, + "AF_TIPC": true, + "AF_UNIX": true, + "AF_UNSPEC": true, + "AF_VENDOR00": true, + "AF_VENDOR01": true, + "AF_VENDOR02": true, + "AF_VENDOR03": true, + "AF_VENDOR04": true, + "AF_VENDOR05": true, + "AF_VENDOR06": true, + "AF_VENDOR07": true, + "AF_VENDOR08": true, + "AF_VENDOR09": true, + "AF_VENDOR10": true, + "AF_VENDOR11": true, + "AF_VENDOR12": true, + "AF_VENDOR13": true, + "AF_VENDOR14": true, + "AF_VENDOR15": true, + "AF_VENDOR16": true, + "AF_VENDOR17": true, + "AF_VENDOR18": true, + "AF_VENDOR19": true, + "AF_VENDOR20": true, + "AF_VENDOR21": true, + "AF_VENDOR22": true, + "AF_VENDOR23": true, + "AF_VENDOR24": true, + "AF_VENDOR25": true, + "AF_VENDOR26": true, + "AF_VENDOR27": true, + "AF_VENDOR28": true, + "AF_VENDOR29": true, + "AF_VENDOR30": true, + "AF_VENDOR31": true, + "AF_VENDOR32": true, + "AF_VENDOR33": true, + "AF_VENDOR34": true, + "AF_VENDOR35": true, + "AF_VENDOR36": true, + "AF_VENDOR37": true, + "AF_VENDOR38": true, + "AF_VENDOR39": true, + "AF_VENDOR40": true, + "AF_VENDOR41": true, + "AF_VENDOR42": true, + "AF_VENDOR43": true, + "AF_VENDOR44": true, + "AF_VENDOR45": true, + "AF_VENDOR46": true, + "AF_VENDOR47": true, + "AF_WANPIPE": true, + "AF_X25": true, + "AI_CANONNAME": true, + "AI_NUMERICHOST": true, + "AI_PASSIVE": true, + "APPLICATION_ERROR": true, + "ARPHRD_ADAPT": true, + "ARPHRD_APPLETLK": true, + "ARPHRD_ARCNET": true, + "ARPHRD_ASH": true, + "ARPHRD_ATM": true, + "ARPHRD_AX25": true, + "ARPHRD_BIF": true, + "ARPHRD_CHAOS": true, + "ARPHRD_CISCO": true, + "ARPHRD_CSLIP": true, + "ARPHRD_CSLIP6": true, + "ARPHRD_DDCMP": true, + "ARPHRD_DLCI": true, + "ARPHRD_ECONET": true, + "ARPHRD_EETHER": true, + "ARPHRD_ETHER": true, + "ARPHRD_EUI64": true, + "ARPHRD_FCAL": true, + "ARPHRD_FCFABRIC": true, + "ARPHRD_FCPL": true, + "ARPHRD_FCPP": true, + "ARPHRD_FDDI": true, + "ARPHRD_FRAD": true, + "ARPHRD_FRELAY": true, + "ARPHRD_HDLC": true, + "ARPHRD_HIPPI": true, + "ARPHRD_HWX25": true, + "ARPHRD_IEEE1394": true, + "ARPHRD_IEEE802": true, + "ARPHRD_IEEE80211": true, + "ARPHRD_IEEE80211_PRISM": true, + "ARPHRD_IEEE80211_RADIOTAP": true, + "ARPHRD_IEEE802154": true, + "ARPHRD_IEEE802154_PHY": true, + "ARPHRD_IEEE802_TR": true, + "ARPHRD_INFINIBAND": true, + "ARPHRD_IPDDP": true, + "ARPHRD_IPGRE": true, + "ARPHRD_IRDA": true, + "ARPHRD_LAPB": true, + "ARPHRD_LOCALTLK": true, + "ARPHRD_LOOPBACK": true, + "ARPHRD_METRICOM": true, + "ARPHRD_NETROM": true, + "ARPHRD_NONE": true, + "ARPHRD_PIMREG": true, + "ARPHRD_PPP": true, + "ARPHRD_PRONET": true, + "ARPHRD_RAWHDLC": true, + "ARPHRD_ROSE": true, + "ARPHRD_RSRVD": true, + "ARPHRD_SIT": true, + "ARPHRD_SKIP": true, + "ARPHRD_SLIP": true, + "ARPHRD_SLIP6": true, + "ARPHRD_STRIP": true, + "ARPHRD_TUNNEL": true, + "ARPHRD_TUNNEL6": true, + "ARPHRD_VOID": true, + "ARPHRD_X25": true, + "AUTHTYPE_CLIENT": true, + "AUTHTYPE_SERVER": true, + "Accept": true, + "Accept4": true, + "AcceptEx": true, + "Access": true, + "Acct": true, + "AddrinfoW": true, + "Adjtime": true, + "Adjtimex": true, + "AttachLsf": true, + "B0": true, + "B1000000": true, + "B110": true, + "B115200": true, + "B1152000": true, + "B1200": true, + "B134": true, + "B14400": true, + "B150": true, + "B1500000": true, + "B1800": true, + "B19200": true, + "B200": true, + "B2000000": true, + "B230400": true, + "B2400": true, + "B2500000": true, + "B28800": true, + "B300": true, + "B3000000": true, + "B3500000": true, + "B38400": true, + "B4000000": true, + "B460800": true, + "B4800": true, + "B50": true, + "B500000": true, + "B57600": true, + "B576000": true, + "B600": true, + "B7200": true, + "B75": true, + "B76800": true, + "B921600": true, + "B9600": true, + "BASE_PROTOCOL": true, + "BIOCFEEDBACK": true, + "BIOCFLUSH": true, + "BIOCGBLEN": true, + "BIOCGDIRECTION": true, + "BIOCGDIRFILT": true, + "BIOCGDLT": true, + "BIOCGDLTLIST": true, + "BIOCGETBUFMODE": true, + "BIOCGETIF": true, + "BIOCGETZMAX": true, + "BIOCGFEEDBACK": true, + "BIOCGFILDROP": true, + "BIOCGHDRCMPLT": true, + "BIOCGRSIG": true, + "BIOCGRTIMEOUT": true, + "BIOCGSEESENT": true, + "BIOCGSTATS": true, + "BIOCGSTATSOLD": true, + "BIOCGTSTAMP": true, + "BIOCIMMEDIATE": true, + "BIOCLOCK": true, + "BIOCPROMISC": true, + "BIOCROTZBUF": true, + "BIOCSBLEN": true, + "BIOCSDIRECTION": true, + "BIOCSDIRFILT": true, + "BIOCSDLT": true, + "BIOCSETBUFMODE": true, + "BIOCSETF": true, + "BIOCSETFNR": true, + "BIOCSETIF": true, + "BIOCSETWF": true, + "BIOCSETZBUF": true, + "BIOCSFEEDBACK": true, + "BIOCSFILDROP": true, + "BIOCSHDRCMPLT": true, + "BIOCSRSIG": true, + "BIOCSRTIMEOUT": true, + "BIOCSSEESENT": true, + "BIOCSTCPF": true, + "BIOCSTSTAMP": true, + "BIOCSUDPF": true, + "BIOCVERSION": true, + "BPF_A": true, + "BPF_ABS": true, + "BPF_ADD": true, + "BPF_ALIGNMENT": true, + "BPF_ALIGNMENT32": true, + "BPF_ALU": true, + "BPF_AND": true, + "BPF_B": true, + "BPF_BUFMODE_BUFFER": true, + "BPF_BUFMODE_ZBUF": true, + "BPF_DFLTBUFSIZE": true, + "BPF_DIRECTION_IN": true, + "BPF_DIRECTION_OUT": true, + "BPF_DIV": true, + "BPF_H": true, + "BPF_IMM": true, + "BPF_IND": true, + "BPF_JA": true, + "BPF_JEQ": true, + "BPF_JGE": true, + "BPF_JGT": true, + "BPF_JMP": true, + "BPF_JSET": true, + "BPF_K": true, + "BPF_LD": true, + "BPF_LDX": true, + "BPF_LEN": true, + "BPF_LSH": true, + "BPF_MAJOR_VERSION": true, + "BPF_MAXBUFSIZE": true, + "BPF_MAXINSNS": true, + "BPF_MEM": true, + "BPF_MEMWORDS": true, + "BPF_MINBUFSIZE": true, + "BPF_MINOR_VERSION": true, + "BPF_MISC": true, + "BPF_MSH": true, + "BPF_MUL": true, + "BPF_NEG": true, + "BPF_OR": true, + "BPF_RELEASE": true, + "BPF_RET": true, + "BPF_RSH": true, + "BPF_ST": true, + "BPF_STX": true, + "BPF_SUB": true, + "BPF_TAX": true, + "BPF_TXA": true, + "BPF_T_BINTIME": true, + "BPF_T_BINTIME_FAST": true, + "BPF_T_BINTIME_MONOTONIC": true, + "BPF_T_BINTIME_MONOTONIC_FAST": true, + "BPF_T_FAST": true, + "BPF_T_FLAG_MASK": true, + "BPF_T_FORMAT_MASK": true, + "BPF_T_MICROTIME": true, + "BPF_T_MICROTIME_FAST": true, + "BPF_T_MICROTIME_MONOTONIC": true, + "BPF_T_MICROTIME_MONOTONIC_FAST": true, + "BPF_T_MONOTONIC": true, + "BPF_T_MONOTONIC_FAST": true, + "BPF_T_NANOTIME": true, + "BPF_T_NANOTIME_FAST": true, + "BPF_T_NANOTIME_MONOTONIC": true, + "BPF_T_NANOTIME_MONOTONIC_FAST": true, + "BPF_T_NONE": true, + "BPF_T_NORMAL": true, + "BPF_W": true, + "BPF_X": true, + "BRKINT": true, + "Bind": true, + "BindToDevice": true, + "BpfBuflen": true, + "BpfDatalink": true, + "BpfHdr": true, + "BpfHeadercmpl": true, + "BpfInsn": true, + "BpfInterface": true, + "BpfJump": true, + "BpfProgram": true, + "BpfStat": true, + "BpfStats": true, + "BpfStmt": true, + "BpfTimeout": true, + "BpfTimeval": true, + "BpfVersion": true, + "BpfZbuf": true, + "BpfZbufHeader": true, + "ByHandleFileInformation": true, + "BytePtrFromString": true, + "ByteSliceFromString": true, + "CCR0_FLUSH": true, + "CERT_CHAIN_POLICY_AUTHENTICODE": true, + "CERT_CHAIN_POLICY_AUTHENTICODE_TS": true, + "CERT_CHAIN_POLICY_BASE": true, + "CERT_CHAIN_POLICY_BASIC_CONSTRAINTS": true, + "CERT_CHAIN_POLICY_EV": true, + "CERT_CHAIN_POLICY_MICROSOFT_ROOT": true, + "CERT_CHAIN_POLICY_NT_AUTH": true, + "CERT_CHAIN_POLICY_SSL": true, + "CERT_E_CN_NO_MATCH": true, + "CERT_E_EXPIRED": true, + "CERT_E_PURPOSE": true, + "CERT_E_ROLE": true, + "CERT_E_UNTRUSTEDROOT": true, + "CERT_STORE_ADD_ALWAYS": true, + "CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG": true, + "CERT_STORE_PROV_MEMORY": true, + "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT": true, + "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT": true, + "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT": true, + "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT": true, + "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT": true, + "CERT_TRUST_INVALID_BASIC_CONSTRAINTS": true, + "CERT_TRUST_INVALID_EXTENSION": true, + "CERT_TRUST_INVALID_NAME_CONSTRAINTS": true, + "CERT_TRUST_INVALID_POLICY_CONSTRAINTS": true, + "CERT_TRUST_IS_CYCLIC": true, + "CERT_TRUST_IS_EXPLICIT_DISTRUST": true, + "CERT_TRUST_IS_NOT_SIGNATURE_VALID": true, + "CERT_TRUST_IS_NOT_TIME_VALID": true, + "CERT_TRUST_IS_NOT_VALID_FOR_USAGE": true, + "CERT_TRUST_IS_OFFLINE_REVOCATION": true, + "CERT_TRUST_IS_REVOKED": true, + "CERT_TRUST_IS_UNTRUSTED_ROOT": true, + "CERT_TRUST_NO_ERROR": true, + "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY": true, + "CERT_TRUST_REVOCATION_STATUS_UNKNOWN": true, + "CFLUSH": true, + "CLOCAL": true, + "CLONE_CHILD_CLEARTID": true, + "CLONE_CHILD_SETTID": true, + "CLONE_CSIGNAL": true, + "CLONE_DETACHED": true, + "CLONE_FILES": true, + "CLONE_FS": true, + "CLONE_IO": true, + "CLONE_NEWIPC": true, + "CLONE_NEWNET": true, + "CLONE_NEWNS": true, + "CLONE_NEWPID": true, + "CLONE_NEWUSER": true, + "CLONE_NEWUTS": true, + "CLONE_PARENT": true, + "CLONE_PARENT_SETTID": true, + "CLONE_PID": true, + "CLONE_PTRACE": true, + "CLONE_SETTLS": true, + "CLONE_SIGHAND": true, + "CLONE_SYSVSEM": true, + "CLONE_THREAD": true, + "CLONE_UNTRACED": true, + "CLONE_VFORK": true, + "CLONE_VM": true, + "CPUID_CFLUSH": true, + "CREAD": true, + "CREATE_ALWAYS": true, + "CREATE_NEW": true, + "CREATE_NEW_PROCESS_GROUP": true, + "CREATE_UNICODE_ENVIRONMENT": true, + "CRYPT_DEFAULT_CONTAINER_OPTIONAL": true, + "CRYPT_DELETEKEYSET": true, + "CRYPT_MACHINE_KEYSET": true, + "CRYPT_NEWKEYSET": true, + "CRYPT_SILENT": true, + "CRYPT_VERIFYCONTEXT": true, + "CS5": true, + "CS6": true, + "CS7": true, + "CS8": true, + "CSIZE": true, + "CSTART": true, + "CSTATUS": true, + "CSTOP": true, + "CSTOPB": true, + "CSUSP": true, + "CTL_MAXNAME": true, + "CTL_NET": true, + "CTL_QUERY": true, + "CTRL_BREAK_EVENT": true, + "CTRL_C_EVENT": true, + "CancelIo": true, + "CancelIoEx": true, + "CertAddCertificateContextToStore": true, + "CertChainContext": true, + "CertChainElement": true, + "CertChainPara": true, + "CertChainPolicyPara": true, + "CertChainPolicyStatus": true, + "CertCloseStore": true, + "CertContext": true, + "CertCreateCertificateContext": true, + "CertEnhKeyUsage": true, + "CertEnumCertificatesInStore": true, + "CertFreeCertificateChain": true, + "CertFreeCertificateContext": true, + "CertGetCertificateChain": true, + "CertInfo": true, + "CertOpenStore": true, + "CertOpenSystemStore": true, + "CertRevocationCrlInfo": true, + "CertRevocationInfo": true, + "CertSimpleChain": true, + "CertTrustListInfo": true, + "CertTrustStatus": true, + "CertUsageMatch": true, + "CertVerifyCertificateChainPolicy": true, + "Chdir": true, + "CheckBpfVersion": true, + "Chflags": true, + "Chmod": true, + "Chown": true, + "Chroot": true, + "Clearenv": true, + "Close": true, + "CloseHandle": true, + "CloseOnExec": true, + "Closesocket": true, + "CmsgLen": true, + "CmsgSpace": true, + "Cmsghdr": true, + "CommandLineToArgv": true, + "ComputerName": true, + "Conn": true, + "Connect": true, + "ConnectEx": true, + "ConvertSidToStringSid": true, + "ConvertStringSidToSid": true, + "CopySid": true, + "Creat": true, + "CreateDirectory": true, + "CreateFile": true, + "CreateFileMapping": true, + "CreateHardLink": true, + "CreateIoCompletionPort": true, + "CreatePipe": true, + "CreateProcess": true, + "CreateProcessAsUser": true, + "CreateSymbolicLink": true, + "CreateToolhelp32Snapshot": true, + "Credential": true, + "CryptAcquireContext": true, + "CryptGenRandom": true, + "CryptReleaseContext": true, + "DIOCBSFLUSH": true, + "DIOCOSFPFLUSH": true, + "DLL": true, + "DLLError": true, + "DLT_A429": true, + "DLT_A653_ICM": true, + "DLT_AIRONET_HEADER": true, + "DLT_AOS": true, + "DLT_APPLE_IP_OVER_IEEE1394": true, + "DLT_ARCNET": true, + "DLT_ARCNET_LINUX": true, + "DLT_ATM_CLIP": true, + "DLT_ATM_RFC1483": true, + "DLT_AURORA": true, + "DLT_AX25": true, + "DLT_AX25_KISS": true, + "DLT_BACNET_MS_TP": true, + "DLT_BLUETOOTH_HCI_H4": true, + "DLT_BLUETOOTH_HCI_H4_WITH_PHDR": true, + "DLT_CAN20B": true, + "DLT_CAN_SOCKETCAN": true, + "DLT_CHAOS": true, + "DLT_CHDLC": true, + "DLT_CISCO_IOS": true, + "DLT_C_HDLC": true, + "DLT_C_HDLC_WITH_DIR": true, + "DLT_DBUS": true, + "DLT_DECT": true, + "DLT_DOCSIS": true, + "DLT_DVB_CI": true, + "DLT_ECONET": true, + "DLT_EN10MB": true, + "DLT_EN3MB": true, + "DLT_ENC": true, + "DLT_ERF": true, + "DLT_ERF_ETH": true, + "DLT_ERF_POS": true, + "DLT_FC_2": true, + "DLT_FC_2_WITH_FRAME_DELIMS": true, + "DLT_FDDI": true, + "DLT_FLEXRAY": true, + "DLT_FRELAY": true, + "DLT_FRELAY_WITH_DIR": true, + "DLT_GCOM_SERIAL": true, + "DLT_GCOM_T1E1": true, + "DLT_GPF_F": true, + "DLT_GPF_T": true, + "DLT_GPRS_LLC": true, + "DLT_GSMTAP_ABIS": true, + "DLT_GSMTAP_UM": true, + "DLT_HDLC": true, + "DLT_HHDLC": true, + "DLT_HIPPI": true, + "DLT_IBM_SN": true, + "DLT_IBM_SP": true, + "DLT_IEEE802": true, + "DLT_IEEE802_11": true, + "DLT_IEEE802_11_RADIO": true, + "DLT_IEEE802_11_RADIO_AVS": true, + "DLT_IEEE802_15_4": true, + "DLT_IEEE802_15_4_LINUX": true, + "DLT_IEEE802_15_4_NOFCS": true, + "DLT_IEEE802_15_4_NONASK_PHY": true, + "DLT_IEEE802_16_MAC_CPS": true, + "DLT_IEEE802_16_MAC_CPS_RADIO": true, + "DLT_IPFILTER": true, + "DLT_IPMB": true, + "DLT_IPMB_LINUX": true, + "DLT_IPNET": true, + "DLT_IPOIB": true, + "DLT_IPV4": true, + "DLT_IPV6": true, + "DLT_IP_OVER_FC": true, + "DLT_JUNIPER_ATM1": true, + "DLT_JUNIPER_ATM2": true, + "DLT_JUNIPER_ATM_CEMIC": true, + "DLT_JUNIPER_CHDLC": true, + "DLT_JUNIPER_ES": true, + "DLT_JUNIPER_ETHER": true, + "DLT_JUNIPER_FIBRECHANNEL": true, + "DLT_JUNIPER_FRELAY": true, + "DLT_JUNIPER_GGSN": true, + "DLT_JUNIPER_ISM": true, + "DLT_JUNIPER_MFR": true, + "DLT_JUNIPER_MLFR": true, + "DLT_JUNIPER_MLPPP": true, + "DLT_JUNIPER_MONITOR": true, + "DLT_JUNIPER_PIC_PEER": true, + "DLT_JUNIPER_PPP": true, + "DLT_JUNIPER_PPPOE": true, + "DLT_JUNIPER_PPPOE_ATM": true, + "DLT_JUNIPER_SERVICES": true, + "DLT_JUNIPER_SRX_E2E": true, + "DLT_JUNIPER_ST": true, + "DLT_JUNIPER_VP": true, + "DLT_JUNIPER_VS": true, + "DLT_LAPB_WITH_DIR": true, + "DLT_LAPD": true, + "DLT_LIN": true, + "DLT_LINUX_EVDEV": true, + "DLT_LINUX_IRDA": true, + "DLT_LINUX_LAPD": true, + "DLT_LINUX_PPP_WITHDIRECTION": true, + "DLT_LINUX_SLL": true, + "DLT_LOOP": true, + "DLT_LTALK": true, + "DLT_MATCHING_MAX": true, + "DLT_MATCHING_MIN": true, + "DLT_MFR": true, + "DLT_MOST": true, + "DLT_MPEG_2_TS": true, + "DLT_MPLS": true, + "DLT_MTP2": true, + "DLT_MTP2_WITH_PHDR": true, + "DLT_MTP3": true, + "DLT_MUX27010": true, + "DLT_NETANALYZER": true, + "DLT_NETANALYZER_TRANSPARENT": true, + "DLT_NFC_LLCP": true, + "DLT_NFLOG": true, + "DLT_NG40": true, + "DLT_NULL": true, + "DLT_PCI_EXP": true, + "DLT_PFLOG": true, + "DLT_PFSYNC": true, + "DLT_PPI": true, + "DLT_PPP": true, + "DLT_PPP_BSDOS": true, + "DLT_PPP_ETHER": true, + "DLT_PPP_PPPD": true, + "DLT_PPP_SERIAL": true, + "DLT_PPP_WITH_DIR": true, + "DLT_PPP_WITH_DIRECTION": true, + "DLT_PRISM_HEADER": true, + "DLT_PRONET": true, + "DLT_RAIF1": true, + "DLT_RAW": true, + "DLT_RAWAF_MASK": true, + "DLT_RIO": true, + "DLT_SCCP": true, + "DLT_SITA": true, + "DLT_SLIP": true, + "DLT_SLIP_BSDOS": true, + "DLT_STANAG_5066_D_PDU": true, + "DLT_SUNATM": true, + "DLT_SYMANTEC_FIREWALL": true, + "DLT_TZSP": true, + "DLT_USB": true, + "DLT_USB_LINUX": true, + "DLT_USB_LINUX_MMAPPED": true, + "DLT_USER0": true, + "DLT_USER1": true, + "DLT_USER10": true, + "DLT_USER11": true, + "DLT_USER12": true, + "DLT_USER13": true, + "DLT_USER14": true, + "DLT_USER15": true, + "DLT_USER2": true, + "DLT_USER3": true, + "DLT_USER4": true, + "DLT_USER5": true, + "DLT_USER6": true, + "DLT_USER7": true, + "DLT_USER8": true, + "DLT_USER9": true, + "DLT_WIHART": true, + "DLT_X2E_SERIAL": true, + "DLT_X2E_XORAYA": true, + "DNSMXData": true, + "DNSPTRData": true, + "DNSRecord": true, + "DNSSRVData": true, + "DNSTXTData": true, + "DNS_INFO_NO_RECORDS": true, + "DNS_TYPE_A": true, + "DNS_TYPE_A6": true, + "DNS_TYPE_AAAA": true, + "DNS_TYPE_ADDRS": true, + "DNS_TYPE_AFSDB": true, + "DNS_TYPE_ALL": true, + "DNS_TYPE_ANY": true, + "DNS_TYPE_ATMA": true, + "DNS_TYPE_AXFR": true, + "DNS_TYPE_CERT": true, + "DNS_TYPE_CNAME": true, + "DNS_TYPE_DHCID": true, + "DNS_TYPE_DNAME": true, + "DNS_TYPE_DNSKEY": true, + "DNS_TYPE_DS": true, + "DNS_TYPE_EID": true, + "DNS_TYPE_GID": true, + "DNS_TYPE_GPOS": true, + "DNS_TYPE_HINFO": true, + "DNS_TYPE_ISDN": true, + "DNS_TYPE_IXFR": true, + "DNS_TYPE_KEY": true, + "DNS_TYPE_KX": true, + "DNS_TYPE_LOC": true, + "DNS_TYPE_MAILA": true, + "DNS_TYPE_MAILB": true, + "DNS_TYPE_MB": true, + "DNS_TYPE_MD": true, + "DNS_TYPE_MF": true, + "DNS_TYPE_MG": true, + "DNS_TYPE_MINFO": true, + "DNS_TYPE_MR": true, + "DNS_TYPE_MX": true, + "DNS_TYPE_NAPTR": true, + "DNS_TYPE_NBSTAT": true, + "DNS_TYPE_NIMLOC": true, + "DNS_TYPE_NS": true, + "DNS_TYPE_NSAP": true, + "DNS_TYPE_NSAPPTR": true, + "DNS_TYPE_NSEC": true, + "DNS_TYPE_NULL": true, + "DNS_TYPE_NXT": true, + "DNS_TYPE_OPT": true, + "DNS_TYPE_PTR": true, + "DNS_TYPE_PX": true, + "DNS_TYPE_RP": true, + "DNS_TYPE_RRSIG": true, + "DNS_TYPE_RT": true, + "DNS_TYPE_SIG": true, + "DNS_TYPE_SINK": true, + "DNS_TYPE_SOA": true, + "DNS_TYPE_SRV": true, + "DNS_TYPE_TEXT": true, + "DNS_TYPE_TKEY": true, + "DNS_TYPE_TSIG": true, + "DNS_TYPE_UID": true, + "DNS_TYPE_UINFO": true, + "DNS_TYPE_UNSPEC": true, + "DNS_TYPE_WINS": true, + "DNS_TYPE_WINSR": true, + "DNS_TYPE_WKS": true, + "DNS_TYPE_X25": true, + "DT_BLK": true, + "DT_CHR": true, + "DT_DIR": true, + "DT_FIFO": true, + "DT_LNK": true, + "DT_REG": true, + "DT_SOCK": true, + "DT_UNKNOWN": true, + "DT_WHT": true, + "DUPLICATE_CLOSE_SOURCE": true, + "DUPLICATE_SAME_ACCESS": true, + "DeleteFile": true, + "DetachLsf": true, + "DeviceIoControl": true, + "Dirent": true, + "DnsNameCompare": true, + "DnsQuery": true, + "DnsRecordListFree": true, + "DnsSectionAdditional": true, + "DnsSectionAnswer": true, + "DnsSectionAuthority": true, + "DnsSectionQuestion": true, + "Dup": true, + "Dup2": true, + "Dup3": true, + "DuplicateHandle": true, + "E2BIG": true, + "EACCES": true, + "EADDRINUSE": true, + "EADDRNOTAVAIL": true, + "EADV": true, + "EAFNOSUPPORT": true, + "EAGAIN": true, + "EALREADY": true, + "EAUTH": true, + "EBADARCH": true, + "EBADE": true, + "EBADEXEC": true, + "EBADF": true, + "EBADFD": true, + "EBADMACHO": true, + "EBADMSG": true, + "EBADR": true, + "EBADRPC": true, + "EBADRQC": true, + "EBADSLT": true, + "EBFONT": true, + "EBUSY": true, + "ECANCELED": true, + "ECAPMODE": true, + "ECHILD": true, + "ECHO": true, + "ECHOCTL": true, + "ECHOE": true, + "ECHOK": true, + "ECHOKE": true, + "ECHONL": true, + "ECHOPRT": true, + "ECHRNG": true, + "ECOMM": true, + "ECONNABORTED": true, + "ECONNREFUSED": true, + "ECONNRESET": true, + "EDEADLK": true, + "EDEADLOCK": true, + "EDESTADDRREQ": true, + "EDEVERR": true, + "EDOM": true, + "EDOOFUS": true, + "EDOTDOT": true, + "EDQUOT": true, + "EEXIST": true, + "EFAULT": true, + "EFBIG": true, + "EFER_LMA": true, + "EFER_LME": true, + "EFER_NXE": true, + "EFER_SCE": true, + "EFTYPE": true, + "EHOSTDOWN": true, + "EHOSTUNREACH": true, + "EHWPOISON": true, + "EIDRM": true, + "EILSEQ": true, + "EINPROGRESS": true, + "EINTR": true, + "EINVAL": true, + "EIO": true, + "EIPSEC": true, + "EISCONN": true, + "EISDIR": true, + "EISNAM": true, + "EKEYEXPIRED": true, + "EKEYREJECTED": true, + "EKEYREVOKED": true, + "EL2HLT": true, + "EL2NSYNC": true, + "EL3HLT": true, + "EL3RST": true, + "ELAST": true, + "ELF_NGREG": true, + "ELF_PRARGSZ": true, + "ELIBACC": true, + "ELIBBAD": true, + "ELIBEXEC": true, + "ELIBMAX": true, + "ELIBSCN": true, + "ELNRNG": true, + "ELOOP": true, + "EMEDIUMTYPE": true, + "EMFILE": true, + "EMLINK": true, + "EMSGSIZE": true, + "EMT_TAGOVF": true, + "EMULTIHOP": true, + "EMUL_ENABLED": true, + "EMUL_LINUX": true, + "EMUL_LINUX32": true, + "EMUL_MAXID": true, + "EMUL_NATIVE": true, + "ENAMETOOLONG": true, + "ENAVAIL": true, + "ENDRUNDISC": true, + "ENEEDAUTH": true, + "ENETDOWN": true, + "ENETRESET": true, + "ENETUNREACH": true, + "ENFILE": true, + "ENOANO": true, + "ENOATTR": true, + "ENOBUFS": true, + "ENOCSI": true, + "ENODATA": true, + "ENODEV": true, + "ENOENT": true, + "ENOEXEC": true, + "ENOKEY": true, + "ENOLCK": true, + "ENOLINK": true, + "ENOMEDIUM": true, + "ENOMEM": true, + "ENOMSG": true, + "ENONET": true, + "ENOPKG": true, + "ENOPOLICY": true, + "ENOPROTOOPT": true, + "ENOSPC": true, + "ENOSR": true, + "ENOSTR": true, + "ENOSYS": true, + "ENOTBLK": true, + "ENOTCAPABLE": true, + "ENOTCONN": true, + "ENOTDIR": true, + "ENOTEMPTY": true, + "ENOTNAM": true, + "ENOTRECOVERABLE": true, + "ENOTSOCK": true, + "ENOTSUP": true, + "ENOTTY": true, + "ENOTUNIQ": true, + "ENXIO": true, + "EN_SW_CTL_INF": true, + "EN_SW_CTL_PREC": true, + "EN_SW_CTL_ROUND": true, + "EN_SW_DATACHAIN": true, + "EN_SW_DENORM": true, + "EN_SW_INVOP": true, + "EN_SW_OVERFLOW": true, + "EN_SW_PRECLOSS": true, + "EN_SW_UNDERFLOW": true, + "EN_SW_ZERODIV": true, + "EOPNOTSUPP": true, + "EOVERFLOW": true, + "EOWNERDEAD": true, + "EPERM": true, + "EPFNOSUPPORT": true, + "EPIPE": true, + "EPOLLERR": true, + "EPOLLET": true, + "EPOLLHUP": true, + "EPOLLIN": true, + "EPOLLMSG": true, + "EPOLLONESHOT": true, + "EPOLLOUT": true, + "EPOLLPRI": true, + "EPOLLRDBAND": true, + "EPOLLRDHUP": true, + "EPOLLRDNORM": true, + "EPOLLWRBAND": true, + "EPOLLWRNORM": true, + "EPOLL_CLOEXEC": true, + "EPOLL_CTL_ADD": true, + "EPOLL_CTL_DEL": true, + "EPOLL_CTL_MOD": true, + "EPOLL_NONBLOCK": true, + "EPROCLIM": true, + "EPROCUNAVAIL": true, + "EPROGMISMATCH": true, + "EPROGUNAVAIL": true, + "EPROTO": true, + "EPROTONOSUPPORT": true, + "EPROTOTYPE": true, + "EPWROFF": true, + "ERANGE": true, + "EREMCHG": true, + "EREMOTE": true, + "EREMOTEIO": true, + "ERESTART": true, + "ERFKILL": true, + "EROFS": true, + "ERPCMISMATCH": true, + "ERROR_ACCESS_DENIED": true, + "ERROR_ALREADY_EXISTS": true, + "ERROR_BROKEN_PIPE": true, + "ERROR_BUFFER_OVERFLOW": true, + "ERROR_DIR_NOT_EMPTY": true, + "ERROR_ENVVAR_NOT_FOUND": true, + "ERROR_FILE_EXISTS": true, + "ERROR_FILE_NOT_FOUND": true, + "ERROR_HANDLE_EOF": true, + "ERROR_INSUFFICIENT_BUFFER": true, + "ERROR_IO_PENDING": true, + "ERROR_MOD_NOT_FOUND": true, + "ERROR_MORE_DATA": true, + "ERROR_NETNAME_DELETED": true, + "ERROR_NOT_FOUND": true, + "ERROR_NO_MORE_FILES": true, + "ERROR_OPERATION_ABORTED": true, + "ERROR_PATH_NOT_FOUND": true, + "ERROR_PRIVILEGE_NOT_HELD": true, + "ERROR_PROC_NOT_FOUND": true, + "ESHLIBVERS": true, + "ESHUTDOWN": true, + "ESOCKTNOSUPPORT": true, + "ESPIPE": true, + "ESRCH": true, + "ESRMNT": true, + "ESTALE": true, + "ESTRPIPE": true, + "ETHERCAP_JUMBO_MTU": true, + "ETHERCAP_VLAN_HWTAGGING": true, + "ETHERCAP_VLAN_MTU": true, + "ETHERMIN": true, + "ETHERMTU": true, + "ETHERMTU_JUMBO": true, + "ETHERTYPE_8023": true, + "ETHERTYPE_AARP": true, + "ETHERTYPE_ACCTON": true, + "ETHERTYPE_AEONIC": true, + "ETHERTYPE_ALPHA": true, + "ETHERTYPE_AMBER": true, + "ETHERTYPE_AMOEBA": true, + "ETHERTYPE_AOE": true, + "ETHERTYPE_APOLLO": true, + "ETHERTYPE_APOLLODOMAIN": true, + "ETHERTYPE_APPLETALK": true, + "ETHERTYPE_APPLITEK": true, + "ETHERTYPE_ARGONAUT": true, + "ETHERTYPE_ARP": true, + "ETHERTYPE_AT": true, + "ETHERTYPE_ATALK": true, + "ETHERTYPE_ATOMIC": true, + "ETHERTYPE_ATT": true, + "ETHERTYPE_ATTSTANFORD": true, + "ETHERTYPE_AUTOPHON": true, + "ETHERTYPE_AXIS": true, + "ETHERTYPE_BCLOOP": true, + "ETHERTYPE_BOFL": true, + "ETHERTYPE_CABLETRON": true, + "ETHERTYPE_CHAOS": true, + "ETHERTYPE_COMDESIGN": true, + "ETHERTYPE_COMPUGRAPHIC": true, + "ETHERTYPE_COUNTERPOINT": true, + "ETHERTYPE_CRONUS": true, + "ETHERTYPE_CRONUSVLN": true, + "ETHERTYPE_DCA": true, + "ETHERTYPE_DDE": true, + "ETHERTYPE_DEBNI": true, + "ETHERTYPE_DECAM": true, + "ETHERTYPE_DECCUST": true, + "ETHERTYPE_DECDIAG": true, + "ETHERTYPE_DECDNS": true, + "ETHERTYPE_DECDTS": true, + "ETHERTYPE_DECEXPER": true, + "ETHERTYPE_DECLAST": true, + "ETHERTYPE_DECLTM": true, + "ETHERTYPE_DECMUMPS": true, + "ETHERTYPE_DECNETBIOS": true, + "ETHERTYPE_DELTACON": true, + "ETHERTYPE_DIDDLE": true, + "ETHERTYPE_DLOG1": true, + "ETHERTYPE_DLOG2": true, + "ETHERTYPE_DN": true, + "ETHERTYPE_DOGFIGHT": true, + "ETHERTYPE_DSMD": true, + "ETHERTYPE_ECMA": true, + "ETHERTYPE_ENCRYPT": true, + "ETHERTYPE_ES": true, + "ETHERTYPE_EXCELAN": true, + "ETHERTYPE_EXPERDATA": true, + "ETHERTYPE_FLIP": true, + "ETHERTYPE_FLOWCONTROL": true, + "ETHERTYPE_FRARP": true, + "ETHERTYPE_GENDYN": true, + "ETHERTYPE_HAYES": true, + "ETHERTYPE_HIPPI_FP": true, + "ETHERTYPE_HITACHI": true, + "ETHERTYPE_HP": true, + "ETHERTYPE_IEEEPUP": true, + "ETHERTYPE_IEEEPUPAT": true, + "ETHERTYPE_IMLBL": true, + "ETHERTYPE_IMLBLDIAG": true, + "ETHERTYPE_IP": true, + "ETHERTYPE_IPAS": true, + "ETHERTYPE_IPV6": true, + "ETHERTYPE_IPX": true, + "ETHERTYPE_IPXNEW": true, + "ETHERTYPE_KALPANA": true, + "ETHERTYPE_LANBRIDGE": true, + "ETHERTYPE_LANPROBE": true, + "ETHERTYPE_LAT": true, + "ETHERTYPE_LBACK": true, + "ETHERTYPE_LITTLE": true, + "ETHERTYPE_LLDP": true, + "ETHERTYPE_LOGICRAFT": true, + "ETHERTYPE_LOOPBACK": true, + "ETHERTYPE_MATRA": true, + "ETHERTYPE_MAX": true, + "ETHERTYPE_MERIT": true, + "ETHERTYPE_MICP": true, + "ETHERTYPE_MOPDL": true, + "ETHERTYPE_MOPRC": true, + "ETHERTYPE_MOTOROLA": true, + "ETHERTYPE_MPLS": true, + "ETHERTYPE_MPLS_MCAST": true, + "ETHERTYPE_MUMPS": true, + "ETHERTYPE_NBPCC": true, + "ETHERTYPE_NBPCLAIM": true, + "ETHERTYPE_NBPCLREQ": true, + "ETHERTYPE_NBPCLRSP": true, + "ETHERTYPE_NBPCREQ": true, + "ETHERTYPE_NBPCRSP": true, + "ETHERTYPE_NBPDG": true, + "ETHERTYPE_NBPDGB": true, + "ETHERTYPE_NBPDLTE": true, + "ETHERTYPE_NBPRAR": true, + "ETHERTYPE_NBPRAS": true, + "ETHERTYPE_NBPRST": true, + "ETHERTYPE_NBPSCD": true, + "ETHERTYPE_NBPVCD": true, + "ETHERTYPE_NBS": true, + "ETHERTYPE_NCD": true, + "ETHERTYPE_NESTAR": true, + "ETHERTYPE_NETBEUI": true, + "ETHERTYPE_NOVELL": true, + "ETHERTYPE_NS": true, + "ETHERTYPE_NSAT": true, + "ETHERTYPE_NSCOMPAT": true, + "ETHERTYPE_NTRAILER": true, + "ETHERTYPE_OS9": true, + "ETHERTYPE_OS9NET": true, + "ETHERTYPE_PACER": true, + "ETHERTYPE_PAE": true, + "ETHERTYPE_PCS": true, + "ETHERTYPE_PLANNING": true, + "ETHERTYPE_PPP": true, + "ETHERTYPE_PPPOE": true, + "ETHERTYPE_PPPOEDISC": true, + "ETHERTYPE_PRIMENTS": true, + "ETHERTYPE_PUP": true, + "ETHERTYPE_PUPAT": true, + "ETHERTYPE_QINQ": true, + "ETHERTYPE_RACAL": true, + "ETHERTYPE_RATIONAL": true, + "ETHERTYPE_RAWFR": true, + "ETHERTYPE_RCL": true, + "ETHERTYPE_RDP": true, + "ETHERTYPE_RETIX": true, + "ETHERTYPE_REVARP": true, + "ETHERTYPE_SCA": true, + "ETHERTYPE_SECTRA": true, + "ETHERTYPE_SECUREDATA": true, + "ETHERTYPE_SGITW": true, + "ETHERTYPE_SG_BOUNCE": true, + "ETHERTYPE_SG_DIAG": true, + "ETHERTYPE_SG_NETGAMES": true, + "ETHERTYPE_SG_RESV": true, + "ETHERTYPE_SIMNET": true, + "ETHERTYPE_SLOW": true, + "ETHERTYPE_SLOWPROTOCOLS": true, + "ETHERTYPE_SNA": true, + "ETHERTYPE_SNMP": true, + "ETHERTYPE_SONIX": true, + "ETHERTYPE_SPIDER": true, + "ETHERTYPE_SPRITE": true, + "ETHERTYPE_STP": true, + "ETHERTYPE_TALARIS": true, + "ETHERTYPE_TALARISMC": true, + "ETHERTYPE_TCPCOMP": true, + "ETHERTYPE_TCPSM": true, + "ETHERTYPE_TEC": true, + "ETHERTYPE_TIGAN": true, + "ETHERTYPE_TRAIL": true, + "ETHERTYPE_TRANSETHER": true, + "ETHERTYPE_TYMSHARE": true, + "ETHERTYPE_UBBST": true, + "ETHERTYPE_UBDEBUG": true, + "ETHERTYPE_UBDIAGLOOP": true, + "ETHERTYPE_UBDL": true, + "ETHERTYPE_UBNIU": true, + "ETHERTYPE_UBNMC": true, + "ETHERTYPE_VALID": true, + "ETHERTYPE_VARIAN": true, + "ETHERTYPE_VAXELN": true, + "ETHERTYPE_VEECO": true, + "ETHERTYPE_VEXP": true, + "ETHERTYPE_VGLAB": true, + "ETHERTYPE_VINES": true, + "ETHERTYPE_VINESECHO": true, + "ETHERTYPE_VINESLOOP": true, + "ETHERTYPE_VITAL": true, + "ETHERTYPE_VLAN": true, + "ETHERTYPE_VLTLMAN": true, + "ETHERTYPE_VPROD": true, + "ETHERTYPE_VURESERVED": true, + "ETHERTYPE_WATERLOO": true, + "ETHERTYPE_WELLFLEET": true, + "ETHERTYPE_X25": true, + "ETHERTYPE_X75": true, + "ETHERTYPE_XNSSM": true, + "ETHERTYPE_XTP": true, + "ETHER_ADDR_LEN": true, + "ETHER_ALIGN": true, + "ETHER_CRC_LEN": true, + "ETHER_CRC_POLY_BE": true, + "ETHER_CRC_POLY_LE": true, + "ETHER_HDR_LEN": true, + "ETHER_MAX_DIX_LEN": true, + "ETHER_MAX_LEN": true, + "ETHER_MAX_LEN_JUMBO": true, + "ETHER_MIN_LEN": true, + "ETHER_PPPOE_ENCAP_LEN": true, + "ETHER_TYPE_LEN": true, + "ETHER_VLAN_ENCAP_LEN": true, + "ETH_P_1588": true, + "ETH_P_8021Q": true, + "ETH_P_802_2": true, + "ETH_P_802_3": true, + "ETH_P_AARP": true, + "ETH_P_ALL": true, + "ETH_P_AOE": true, + "ETH_P_ARCNET": true, + "ETH_P_ARP": true, + "ETH_P_ATALK": true, + "ETH_P_ATMFATE": true, + "ETH_P_ATMMPOA": true, + "ETH_P_AX25": true, + "ETH_P_BPQ": true, + "ETH_P_CAIF": true, + "ETH_P_CAN": true, + "ETH_P_CONTROL": true, + "ETH_P_CUST": true, + "ETH_P_DDCMP": true, + "ETH_P_DEC": true, + "ETH_P_DIAG": true, + "ETH_P_DNA_DL": true, + "ETH_P_DNA_RC": true, + "ETH_P_DNA_RT": true, + "ETH_P_DSA": true, + "ETH_P_ECONET": true, + "ETH_P_EDSA": true, + "ETH_P_FCOE": true, + "ETH_P_FIP": true, + "ETH_P_HDLC": true, + "ETH_P_IEEE802154": true, + "ETH_P_IEEEPUP": true, + "ETH_P_IEEEPUPAT": true, + "ETH_P_IP": true, + "ETH_P_IPV6": true, + "ETH_P_IPX": true, + "ETH_P_IRDA": true, + "ETH_P_LAT": true, + "ETH_P_LINK_CTL": true, + "ETH_P_LOCALTALK": true, + "ETH_P_LOOP": true, + "ETH_P_MOBITEX": true, + "ETH_P_MPLS_MC": true, + "ETH_P_MPLS_UC": true, + "ETH_P_PAE": true, + "ETH_P_PAUSE": true, + "ETH_P_PHONET": true, + "ETH_P_PPPTALK": true, + "ETH_P_PPP_DISC": true, + "ETH_P_PPP_MP": true, + "ETH_P_PPP_SES": true, + "ETH_P_PUP": true, + "ETH_P_PUPAT": true, + "ETH_P_RARP": true, + "ETH_P_SCA": true, + "ETH_P_SLOW": true, + "ETH_P_SNAP": true, + "ETH_P_TEB": true, + "ETH_P_TIPC": true, + "ETH_P_TRAILER": true, + "ETH_P_TR_802_2": true, + "ETH_P_WAN_PPP": true, + "ETH_P_WCCP": true, + "ETH_P_X25": true, + "ETIME": true, + "ETIMEDOUT": true, + "ETOOMANYREFS": true, + "ETXTBSY": true, + "EUCLEAN": true, + "EUNATCH": true, + "EUSERS": true, + "EVFILT_AIO": true, + "EVFILT_FS": true, + "EVFILT_LIO": true, + "EVFILT_MACHPORT": true, + "EVFILT_PROC": true, + "EVFILT_READ": true, + "EVFILT_SIGNAL": true, + "EVFILT_SYSCOUNT": true, + "EVFILT_THREADMARKER": true, + "EVFILT_TIMER": true, + "EVFILT_USER": true, + "EVFILT_VM": true, + "EVFILT_VNODE": true, + "EVFILT_WRITE": true, + "EV_ADD": true, + "EV_CLEAR": true, + "EV_DELETE": true, + "EV_DISABLE": true, + "EV_DISPATCH": true, + "EV_DROP": true, + "EV_ENABLE": true, + "EV_EOF": true, + "EV_ERROR": true, + "EV_FLAG0": true, + "EV_FLAG1": true, + "EV_ONESHOT": true, + "EV_OOBAND": true, + "EV_POLL": true, + "EV_RECEIPT": true, + "EV_SYSFLAGS": true, + "EWINDOWS": true, + "EWOULDBLOCK": true, + "EXDEV": true, + "EXFULL": true, + "EXTA": true, + "EXTB": true, + "EXTPROC": true, + "Environ": true, + "EpollCreate": true, + "EpollCreate1": true, + "EpollCtl": true, + "EpollEvent": true, + "EpollWait": true, + "Errno": true, + "EscapeArg": true, + "Exchangedata": true, + "Exec": true, + "Exit": true, + "ExitProcess": true, + "FD_CLOEXEC": true, + "FD_SETSIZE": true, + "FILE_ACTION_ADDED": true, + "FILE_ACTION_MODIFIED": true, + "FILE_ACTION_REMOVED": true, + "FILE_ACTION_RENAMED_NEW_NAME": true, + "FILE_ACTION_RENAMED_OLD_NAME": true, + "FILE_APPEND_DATA": true, + "FILE_ATTRIBUTE_ARCHIVE": true, + "FILE_ATTRIBUTE_DIRECTORY": true, + "FILE_ATTRIBUTE_HIDDEN": true, + "FILE_ATTRIBUTE_NORMAL": true, + "FILE_ATTRIBUTE_READONLY": true, + "FILE_ATTRIBUTE_REPARSE_POINT": true, + "FILE_ATTRIBUTE_SYSTEM": true, + "FILE_BEGIN": true, + "FILE_CURRENT": true, + "FILE_END": true, + "FILE_FLAG_BACKUP_SEMANTICS": true, + "FILE_FLAG_OPEN_REPARSE_POINT": true, + "FILE_FLAG_OVERLAPPED": true, + "FILE_LIST_DIRECTORY": true, + "FILE_MAP_COPY": true, + "FILE_MAP_EXECUTE": true, + "FILE_MAP_READ": true, + "FILE_MAP_WRITE": true, + "FILE_NOTIFY_CHANGE_ATTRIBUTES": true, + "FILE_NOTIFY_CHANGE_CREATION": true, + "FILE_NOTIFY_CHANGE_DIR_NAME": true, + "FILE_NOTIFY_CHANGE_FILE_NAME": true, + "FILE_NOTIFY_CHANGE_LAST_ACCESS": true, + "FILE_NOTIFY_CHANGE_LAST_WRITE": true, + "FILE_NOTIFY_CHANGE_SIZE": true, + "FILE_SHARE_DELETE": true, + "FILE_SHARE_READ": true, + "FILE_SHARE_WRITE": true, + "FILE_SKIP_COMPLETION_PORT_ON_SUCCESS": true, + "FILE_SKIP_SET_EVENT_ON_HANDLE": true, + "FILE_TYPE_CHAR": true, + "FILE_TYPE_DISK": true, + "FILE_TYPE_PIPE": true, + "FILE_TYPE_REMOTE": true, + "FILE_TYPE_UNKNOWN": true, + "FILE_WRITE_ATTRIBUTES": true, + "FLUSHO": true, + "FORMAT_MESSAGE_ALLOCATE_BUFFER": true, + "FORMAT_MESSAGE_ARGUMENT_ARRAY": true, + "FORMAT_MESSAGE_FROM_HMODULE": true, + "FORMAT_MESSAGE_FROM_STRING": true, + "FORMAT_MESSAGE_FROM_SYSTEM": true, + "FORMAT_MESSAGE_IGNORE_INSERTS": true, + "FORMAT_MESSAGE_MAX_WIDTH_MASK": true, + "FSCTL_GET_REPARSE_POINT": true, + "F_ADDFILESIGS": true, + "F_ADDSIGS": true, + "F_ALLOCATEALL": true, + "F_ALLOCATECONTIG": true, + "F_CANCEL": true, + "F_CHKCLEAN": true, + "F_CLOSEM": true, + "F_DUP2FD": true, + "F_DUP2FD_CLOEXEC": true, + "F_DUPFD": true, + "F_DUPFD_CLOEXEC": true, + "F_EXLCK": true, + "F_FLUSH_DATA": true, + "F_FREEZE_FS": true, + "F_FSCTL": true, + "F_FSDIRMASK": true, + "F_FSIN": true, + "F_FSINOUT": true, + "F_FSOUT": true, + "F_FSPRIV": true, + "F_FSVOID": true, + "F_FULLFSYNC": true, + "F_GETFD": true, + "F_GETFL": true, + "F_GETLEASE": true, + "F_GETLK": true, + "F_GETLK64": true, + "F_GETLKPID": true, + "F_GETNOSIGPIPE": true, + "F_GETOWN": true, + "F_GETOWN_EX": true, + "F_GETPATH": true, + "F_GETPATH_MTMINFO": true, + "F_GETPIPE_SZ": true, + "F_GETPROTECTIONCLASS": true, + "F_GETSIG": true, + "F_GLOBAL_NOCACHE": true, + "F_LOCK": true, + "F_LOG2PHYS": true, + "F_LOG2PHYS_EXT": true, + "F_MARKDEPENDENCY": true, + "F_MAXFD": true, + "F_NOCACHE": true, + "F_NODIRECT": true, + "F_NOTIFY": true, + "F_OGETLK": true, + "F_OK": true, + "F_OSETLK": true, + "F_OSETLKW": true, + "F_PARAM_MASK": true, + "F_PARAM_MAX": true, + "F_PATHPKG_CHECK": true, + "F_PEOFPOSMODE": true, + "F_PREALLOCATE": true, + "F_RDADVISE": true, + "F_RDAHEAD": true, + "F_RDLCK": true, + "F_READAHEAD": true, + "F_READBOOTSTRAP": true, + "F_SETBACKINGSTORE": true, + "F_SETFD": true, + "F_SETFL": true, + "F_SETLEASE": true, + "F_SETLK": true, + "F_SETLK64": true, + "F_SETLKW": true, + "F_SETLKW64": true, + "F_SETLK_REMOTE": true, + "F_SETNOSIGPIPE": true, + "F_SETOWN": true, + "F_SETOWN_EX": true, + "F_SETPIPE_SZ": true, + "F_SETPROTECTIONCLASS": true, + "F_SETSIG": true, + "F_SETSIZE": true, + "F_SHLCK": true, + "F_TEST": true, + "F_THAW_FS": true, + "F_TLOCK": true, + "F_ULOCK": true, + "F_UNLCK": true, + "F_UNLCKSYS": true, + "F_VOLPOSMODE": true, + "F_WRITEBOOTSTRAP": true, + "F_WRLCK": true, + "Faccessat": true, + "Fallocate": true, + "Fbootstraptransfer_t": true, + "Fchdir": true, + "Fchflags": true, + "Fchmod": true, + "Fchmodat": true, + "Fchown": true, + "Fchownat": true, + "FcntlFlock": true, + "FdSet": true, + "Fdatasync": true, + "FileNotifyInformation": true, + "Filetime": true, + "FindClose": true, + "FindFirstFile": true, + "FindNextFile": true, + "Flock": true, + "Flock_t": true, + "FlushBpf": true, + "FlushFileBuffers": true, + "FlushViewOfFile": true, + "ForkExec": true, + "ForkLock": true, + "FormatMessage": true, + "Fpathconf": true, + "FreeAddrInfoW": true, + "FreeEnvironmentStrings": true, + "FreeLibrary": true, + "Fsid": true, + "Fstat": true, + "Fstatat": true, + "Fstatfs": true, + "Fstore_t": true, + "Fsync": true, + "Ftruncate": true, + "FullPath": true, + "Futimes": true, + "Futimesat": true, + "GENERIC_ALL": true, + "GENERIC_EXECUTE": true, + "GENERIC_READ": true, + "GENERIC_WRITE": true, + "GUID": true, + "GetAcceptExSockaddrs": true, + "GetAdaptersInfo": true, + "GetAddrInfoW": true, + "GetCommandLine": true, + "GetComputerName": true, + "GetConsoleMode": true, + "GetCurrentDirectory": true, + "GetCurrentProcess": true, + "GetEnvironmentStrings": true, + "GetEnvironmentVariable": true, + "GetExitCodeProcess": true, + "GetFileAttributes": true, + "GetFileAttributesEx": true, + "GetFileExInfoStandard": true, + "GetFileExMaxInfoLevel": true, + "GetFileInformationByHandle": true, + "GetFileType": true, + "GetFullPathName": true, + "GetHostByName": true, + "GetIfEntry": true, + "GetLastError": true, + "GetLengthSid": true, + "GetLongPathName": true, + "GetProcAddress": true, + "GetProcessTimes": true, + "GetProtoByName": true, + "GetQueuedCompletionStatus": true, + "GetServByName": true, + "GetShortPathName": true, + "GetStartupInfo": true, + "GetStdHandle": true, + "GetSystemTimeAsFileTime": true, + "GetTempPath": true, + "GetTimeZoneInformation": true, + "GetTokenInformation": true, + "GetUserNameEx": true, + "GetUserProfileDirectory": true, + "GetVersion": true, + "Getcwd": true, + "Getdents": true, + "Getdirentries": true, + "Getdtablesize": true, + "Getegid": true, + "Getenv": true, + "Geteuid": true, + "Getfsstat": true, + "Getgid": true, + "Getgroups": true, + "Getpagesize": true, + "Getpeername": true, + "Getpgid": true, + "Getpgrp": true, + "Getpid": true, + "Getppid": true, + "Getpriority": true, + "Getrlimit": true, + "Getrusage": true, + "Getsid": true, + "Getsockname": true, + "Getsockopt": true, + "GetsockoptByte": true, + "GetsockoptICMPv6Filter": true, + "GetsockoptIPMreq": true, + "GetsockoptIPMreqn": true, + "GetsockoptIPv6MTUInfo": true, + "GetsockoptIPv6Mreq": true, + "GetsockoptInet4Addr": true, + "GetsockoptInt": true, + "GetsockoptUcred": true, + "Gettid": true, + "Gettimeofday": true, + "Getuid": true, + "Getwd": true, + "Getxattr": true, + "HANDLE_FLAG_INHERIT": true, + "HKEY_CLASSES_ROOT": true, + "HKEY_CURRENT_CONFIG": true, + "HKEY_CURRENT_USER": true, + "HKEY_DYN_DATA": true, + "HKEY_LOCAL_MACHINE": true, + "HKEY_PERFORMANCE_DATA": true, + "HKEY_USERS": true, + "HUPCL": true, + "Handle": true, + "Hostent": true, + "ICANON": true, + "ICMP6_FILTER": true, + "ICMPV6_FILTER": true, + "ICMPv6Filter": true, + "ICRNL": true, + "IEXTEN": true, + "IFAN_ARRIVAL": true, + "IFAN_DEPARTURE": true, + "IFA_ADDRESS": true, + "IFA_ANYCAST": true, + "IFA_BROADCAST": true, + "IFA_CACHEINFO": true, + "IFA_F_DADFAILED": true, + "IFA_F_DEPRECATED": true, + "IFA_F_HOMEADDRESS": true, + "IFA_F_NODAD": true, + "IFA_F_OPTIMISTIC": true, + "IFA_F_PERMANENT": true, + "IFA_F_SECONDARY": true, + "IFA_F_TEMPORARY": true, + "IFA_F_TENTATIVE": true, + "IFA_LABEL": true, + "IFA_LOCAL": true, + "IFA_MAX": true, + "IFA_MULTICAST": true, + "IFA_ROUTE": true, + "IFA_UNSPEC": true, + "IFF_ALLMULTI": true, + "IFF_ALTPHYS": true, + "IFF_AUTOMEDIA": true, + "IFF_BROADCAST": true, + "IFF_CANTCHANGE": true, + "IFF_CANTCONFIG": true, + "IFF_DEBUG": true, + "IFF_DRV_OACTIVE": true, + "IFF_DRV_RUNNING": true, + "IFF_DYING": true, + "IFF_DYNAMIC": true, + "IFF_LINK0": true, + "IFF_LINK1": true, + "IFF_LINK2": true, + "IFF_LOOPBACK": true, + "IFF_MASTER": true, + "IFF_MONITOR": true, + "IFF_MULTICAST": true, + "IFF_NOARP": true, + "IFF_NOTRAILERS": true, + "IFF_NO_PI": true, + "IFF_OACTIVE": true, + "IFF_ONE_QUEUE": true, + "IFF_POINTOPOINT": true, + "IFF_POINTTOPOINT": true, + "IFF_PORTSEL": true, + "IFF_PPROMISC": true, + "IFF_PROMISC": true, + "IFF_RENAMING": true, + "IFF_RUNNING": true, + "IFF_SIMPLEX": true, + "IFF_SLAVE": true, + "IFF_SMART": true, + "IFF_STATICARP": true, + "IFF_TAP": true, + "IFF_TUN": true, + "IFF_TUN_EXCL": true, + "IFF_UP": true, + "IFF_VNET_HDR": true, + "IFLA_ADDRESS": true, + "IFLA_BROADCAST": true, + "IFLA_COST": true, + "IFLA_IFALIAS": true, + "IFLA_IFNAME": true, + "IFLA_LINK": true, + "IFLA_LINKINFO": true, + "IFLA_LINKMODE": true, + "IFLA_MAP": true, + "IFLA_MASTER": true, + "IFLA_MAX": true, + "IFLA_MTU": true, + "IFLA_NET_NS_PID": true, + "IFLA_OPERSTATE": true, + "IFLA_PRIORITY": true, + "IFLA_PROTINFO": true, + "IFLA_QDISC": true, + "IFLA_STATS": true, + "IFLA_TXQLEN": true, + "IFLA_UNSPEC": true, + "IFLA_WEIGHT": true, + "IFLA_WIRELESS": true, + "IFNAMSIZ": true, + "IFT_1822": true, + "IFT_A12MPPSWITCH": true, + "IFT_AAL2": true, + "IFT_AAL5": true, + "IFT_ADSL": true, + "IFT_AFLANE8023": true, + "IFT_AFLANE8025": true, + "IFT_ARAP": true, + "IFT_ARCNET": true, + "IFT_ARCNETPLUS": true, + "IFT_ASYNC": true, + "IFT_ATM": true, + "IFT_ATMDXI": true, + "IFT_ATMFUNI": true, + "IFT_ATMIMA": true, + "IFT_ATMLOGICAL": true, + "IFT_ATMRADIO": true, + "IFT_ATMSUBINTERFACE": true, + "IFT_ATMVCIENDPT": true, + "IFT_ATMVIRTUAL": true, + "IFT_BGPPOLICYACCOUNTING": true, + "IFT_BLUETOOTH": true, + "IFT_BRIDGE": true, + "IFT_BSC": true, + "IFT_CARP": true, + "IFT_CCTEMUL": true, + "IFT_CELLULAR": true, + "IFT_CEPT": true, + "IFT_CES": true, + "IFT_CHANNEL": true, + "IFT_CNR": true, + "IFT_COFFEE": true, + "IFT_COMPOSITELINK": true, + "IFT_DCN": true, + "IFT_DIGITALPOWERLINE": true, + "IFT_DIGITALWRAPPEROVERHEADCHANNEL": true, + "IFT_DLSW": true, + "IFT_DOCSCABLEDOWNSTREAM": true, + "IFT_DOCSCABLEMACLAYER": true, + "IFT_DOCSCABLEUPSTREAM": true, + "IFT_DOCSCABLEUPSTREAMCHANNEL": true, + "IFT_DS0": true, + "IFT_DS0BUNDLE": true, + "IFT_DS1FDL": true, + "IFT_DS3": true, + "IFT_DTM": true, + "IFT_DUMMY": true, + "IFT_DVBASILN": true, + "IFT_DVBASIOUT": true, + "IFT_DVBRCCDOWNSTREAM": true, + "IFT_DVBRCCMACLAYER": true, + "IFT_DVBRCCUPSTREAM": true, + "IFT_ECONET": true, + "IFT_ENC": true, + "IFT_EON": true, + "IFT_EPLRS": true, + "IFT_ESCON": true, + "IFT_ETHER": true, + "IFT_FAITH": true, + "IFT_FAST": true, + "IFT_FASTETHER": true, + "IFT_FASTETHERFX": true, + "IFT_FDDI": true, + "IFT_FIBRECHANNEL": true, + "IFT_FRAMERELAYINTERCONNECT": true, + "IFT_FRAMERELAYMPI": true, + "IFT_FRDLCIENDPT": true, + "IFT_FRELAY": true, + "IFT_FRELAYDCE": true, + "IFT_FRF16MFRBUNDLE": true, + "IFT_FRFORWARD": true, + "IFT_G703AT2MB": true, + "IFT_G703AT64K": true, + "IFT_GIF": true, + "IFT_GIGABITETHERNET": true, + "IFT_GR303IDT": true, + "IFT_GR303RDT": true, + "IFT_H323GATEKEEPER": true, + "IFT_H323PROXY": true, + "IFT_HDH1822": true, + "IFT_HDLC": true, + "IFT_HDSL2": true, + "IFT_HIPERLAN2": true, + "IFT_HIPPI": true, + "IFT_HIPPIINTERFACE": true, + "IFT_HOSTPAD": true, + "IFT_HSSI": true, + "IFT_HY": true, + "IFT_IBM370PARCHAN": true, + "IFT_IDSL": true, + "IFT_IEEE1394": true, + "IFT_IEEE80211": true, + "IFT_IEEE80212": true, + "IFT_IEEE8023ADLAG": true, + "IFT_IFGSN": true, + "IFT_IMT": true, + "IFT_INFINIBAND": true, + "IFT_INTERLEAVE": true, + "IFT_IP": true, + "IFT_IPFORWARD": true, + "IFT_IPOVERATM": true, + "IFT_IPOVERCDLC": true, + "IFT_IPOVERCLAW": true, + "IFT_IPSWITCH": true, + "IFT_IPXIP": true, + "IFT_ISDN": true, + "IFT_ISDNBASIC": true, + "IFT_ISDNPRIMARY": true, + "IFT_ISDNS": true, + "IFT_ISDNU": true, + "IFT_ISO88022LLC": true, + "IFT_ISO88023": true, + "IFT_ISO88024": true, + "IFT_ISO88025": true, + "IFT_ISO88025CRFPINT": true, + "IFT_ISO88025DTR": true, + "IFT_ISO88025FIBER": true, + "IFT_ISO88026": true, + "IFT_ISUP": true, + "IFT_L2VLAN": true, + "IFT_L3IPVLAN": true, + "IFT_L3IPXVLAN": true, + "IFT_LAPB": true, + "IFT_LAPD": true, + "IFT_LAPF": true, + "IFT_LINEGROUP": true, + "IFT_LOCALTALK": true, + "IFT_LOOP": true, + "IFT_MEDIAMAILOVERIP": true, + "IFT_MFSIGLINK": true, + "IFT_MIOX25": true, + "IFT_MODEM": true, + "IFT_MPC": true, + "IFT_MPLS": true, + "IFT_MPLSTUNNEL": true, + "IFT_MSDSL": true, + "IFT_MVL": true, + "IFT_MYRINET": true, + "IFT_NFAS": true, + "IFT_NSIP": true, + "IFT_OPTICALCHANNEL": true, + "IFT_OPTICALTRANSPORT": true, + "IFT_OTHER": true, + "IFT_P10": true, + "IFT_P80": true, + "IFT_PARA": true, + "IFT_PDP": true, + "IFT_PFLOG": true, + "IFT_PFLOW": true, + "IFT_PFSYNC": true, + "IFT_PLC": true, + "IFT_PON155": true, + "IFT_PON622": true, + "IFT_POS": true, + "IFT_PPP": true, + "IFT_PPPMULTILINKBUNDLE": true, + "IFT_PROPATM": true, + "IFT_PROPBWAP2MP": true, + "IFT_PROPCNLS": true, + "IFT_PROPDOCSWIRELESSDOWNSTREAM": true, + "IFT_PROPDOCSWIRELESSMACLAYER": true, + "IFT_PROPDOCSWIRELESSUPSTREAM": true, + "IFT_PROPMUX": true, + "IFT_PROPVIRTUAL": true, + "IFT_PROPWIRELESSP2P": true, + "IFT_PTPSERIAL": true, + "IFT_PVC": true, + "IFT_Q2931": true, + "IFT_QLLC": true, + "IFT_RADIOMAC": true, + "IFT_RADSL": true, + "IFT_REACHDSL": true, + "IFT_RFC1483": true, + "IFT_RS232": true, + "IFT_RSRB": true, + "IFT_SDLC": true, + "IFT_SDSL": true, + "IFT_SHDSL": true, + "IFT_SIP": true, + "IFT_SIPSIG": true, + "IFT_SIPTG": true, + "IFT_SLIP": true, + "IFT_SMDSDXI": true, + "IFT_SMDSICIP": true, + "IFT_SONET": true, + "IFT_SONETOVERHEADCHANNEL": true, + "IFT_SONETPATH": true, + "IFT_SONETVT": true, + "IFT_SRP": true, + "IFT_SS7SIGLINK": true, + "IFT_STACKTOSTACK": true, + "IFT_STARLAN": true, + "IFT_STF": true, + "IFT_T1": true, + "IFT_TDLC": true, + "IFT_TELINK": true, + "IFT_TERMPAD": true, + "IFT_TR008": true, + "IFT_TRANSPHDLC": true, + "IFT_TUNNEL": true, + "IFT_ULTRA": true, + "IFT_USB": true, + "IFT_V11": true, + "IFT_V35": true, + "IFT_V36": true, + "IFT_V37": true, + "IFT_VDSL": true, + "IFT_VIRTUALIPADDRESS": true, + "IFT_VIRTUALTG": true, + "IFT_VOICEDID": true, + "IFT_VOICEEM": true, + "IFT_VOICEEMFGD": true, + "IFT_VOICEENCAP": true, + "IFT_VOICEFGDEANA": true, + "IFT_VOICEFXO": true, + "IFT_VOICEFXS": true, + "IFT_VOICEOVERATM": true, + "IFT_VOICEOVERCABLE": true, + "IFT_VOICEOVERFRAMERELAY": true, + "IFT_VOICEOVERIP": true, + "IFT_X213": true, + "IFT_X25": true, + "IFT_X25DDN": true, + "IFT_X25HUNTGROUP": true, + "IFT_X25MLP": true, + "IFT_X25PLE": true, + "IFT_XETHER": true, + "IGNBRK": true, + "IGNCR": true, + "IGNORE": true, + "IGNPAR": true, + "IMAXBEL": true, + "INFINITE": true, + "INLCR": true, + "INPCK": true, + "INVALID_FILE_ATTRIBUTES": true, + "IN_ACCESS": true, + "IN_ALL_EVENTS": true, + "IN_ATTRIB": true, + "IN_CLASSA_HOST": true, + "IN_CLASSA_MAX": true, + "IN_CLASSA_NET": true, + "IN_CLASSA_NSHIFT": true, + "IN_CLASSB_HOST": true, + "IN_CLASSB_MAX": true, + "IN_CLASSB_NET": true, + "IN_CLASSB_NSHIFT": true, + "IN_CLASSC_HOST": true, + "IN_CLASSC_NET": true, + "IN_CLASSC_NSHIFT": true, + "IN_CLASSD_HOST": true, + "IN_CLASSD_NET": true, + "IN_CLASSD_NSHIFT": true, + "IN_CLOEXEC": true, + "IN_CLOSE": true, + "IN_CLOSE_NOWRITE": true, + "IN_CLOSE_WRITE": true, + "IN_CREATE": true, + "IN_DELETE": true, + "IN_DELETE_SELF": true, + "IN_DONT_FOLLOW": true, + "IN_EXCL_UNLINK": true, + "IN_IGNORED": true, + "IN_ISDIR": true, + "IN_LINKLOCALNETNUM": true, + "IN_LOOPBACKNET": true, + "IN_MASK_ADD": true, + "IN_MODIFY": true, + "IN_MOVE": true, + "IN_MOVED_FROM": true, + "IN_MOVED_TO": true, + "IN_MOVE_SELF": true, + "IN_NONBLOCK": true, + "IN_ONESHOT": true, + "IN_ONLYDIR": true, + "IN_OPEN": true, + "IN_Q_OVERFLOW": true, + "IN_RFC3021_HOST": true, + "IN_RFC3021_MASK": true, + "IN_RFC3021_NET": true, + "IN_RFC3021_NSHIFT": true, + "IN_UNMOUNT": true, + "IOC_IN": true, + "IOC_INOUT": true, + "IOC_OUT": true, + "IOC_VENDOR": true, + "IOC_WS2": true, + "IO_REPARSE_TAG_SYMLINK": true, + "IPMreq": true, + "IPMreqn": true, + "IPPROTO_3PC": true, + "IPPROTO_ADFS": true, + "IPPROTO_AH": true, + "IPPROTO_AHIP": true, + "IPPROTO_APES": true, + "IPPROTO_ARGUS": true, + "IPPROTO_AX25": true, + "IPPROTO_BHA": true, + "IPPROTO_BLT": true, + "IPPROTO_BRSATMON": true, + "IPPROTO_CARP": true, + "IPPROTO_CFTP": true, + "IPPROTO_CHAOS": true, + "IPPROTO_CMTP": true, + "IPPROTO_COMP": true, + "IPPROTO_CPHB": true, + "IPPROTO_CPNX": true, + "IPPROTO_DCCP": true, + "IPPROTO_DDP": true, + "IPPROTO_DGP": true, + "IPPROTO_DIVERT": true, + "IPPROTO_DIVERT_INIT": true, + "IPPROTO_DIVERT_RESP": true, + "IPPROTO_DONE": true, + "IPPROTO_DSTOPTS": true, + "IPPROTO_EGP": true, + "IPPROTO_EMCON": true, + "IPPROTO_ENCAP": true, + "IPPROTO_EON": true, + "IPPROTO_ESP": true, + "IPPROTO_ETHERIP": true, + "IPPROTO_FRAGMENT": true, + "IPPROTO_GGP": true, + "IPPROTO_GMTP": true, + "IPPROTO_GRE": true, + "IPPROTO_HELLO": true, + "IPPROTO_HMP": true, + "IPPROTO_HOPOPTS": true, + "IPPROTO_ICMP": true, + "IPPROTO_ICMPV6": true, + "IPPROTO_IDP": true, + "IPPROTO_IDPR": true, + "IPPROTO_IDRP": true, + "IPPROTO_IGMP": true, + "IPPROTO_IGP": true, + "IPPROTO_IGRP": true, + "IPPROTO_IL": true, + "IPPROTO_INLSP": true, + "IPPROTO_INP": true, + "IPPROTO_IP": true, + "IPPROTO_IPCOMP": true, + "IPPROTO_IPCV": true, + "IPPROTO_IPEIP": true, + "IPPROTO_IPIP": true, + "IPPROTO_IPPC": true, + "IPPROTO_IPV4": true, + "IPPROTO_IPV6": true, + "IPPROTO_IPV6_ICMP": true, + "IPPROTO_IRTP": true, + "IPPROTO_KRYPTOLAN": true, + "IPPROTO_LARP": true, + "IPPROTO_LEAF1": true, + "IPPROTO_LEAF2": true, + "IPPROTO_MAX": true, + "IPPROTO_MAXID": true, + "IPPROTO_MEAS": true, + "IPPROTO_MH": true, + "IPPROTO_MHRP": true, + "IPPROTO_MICP": true, + "IPPROTO_MOBILE": true, + "IPPROTO_MPLS": true, + "IPPROTO_MTP": true, + "IPPROTO_MUX": true, + "IPPROTO_ND": true, + "IPPROTO_NHRP": true, + "IPPROTO_NONE": true, + "IPPROTO_NSP": true, + "IPPROTO_NVPII": true, + "IPPROTO_OLD_DIVERT": true, + "IPPROTO_OSPFIGP": true, + "IPPROTO_PFSYNC": true, + "IPPROTO_PGM": true, + "IPPROTO_PIGP": true, + "IPPROTO_PIM": true, + "IPPROTO_PRM": true, + "IPPROTO_PUP": true, + "IPPROTO_PVP": true, + "IPPROTO_RAW": true, + "IPPROTO_RCCMON": true, + "IPPROTO_RDP": true, + "IPPROTO_ROUTING": true, + "IPPROTO_RSVP": true, + "IPPROTO_RVD": true, + "IPPROTO_SATEXPAK": true, + "IPPROTO_SATMON": true, + "IPPROTO_SCCSP": true, + "IPPROTO_SCTP": true, + "IPPROTO_SDRP": true, + "IPPROTO_SEND": true, + "IPPROTO_SEP": true, + "IPPROTO_SKIP": true, + "IPPROTO_SPACER": true, + "IPPROTO_SRPC": true, + "IPPROTO_ST": true, + "IPPROTO_SVMTP": true, + "IPPROTO_SWIPE": true, + "IPPROTO_TCF": true, + "IPPROTO_TCP": true, + "IPPROTO_TLSP": true, + "IPPROTO_TP": true, + "IPPROTO_TPXX": true, + "IPPROTO_TRUNK1": true, + "IPPROTO_TRUNK2": true, + "IPPROTO_TTP": true, + "IPPROTO_UDP": true, + "IPPROTO_UDPLITE": true, + "IPPROTO_VINES": true, + "IPPROTO_VISA": true, + "IPPROTO_VMTP": true, + "IPPROTO_VRRP": true, + "IPPROTO_WBEXPAK": true, + "IPPROTO_WBMON": true, + "IPPROTO_WSN": true, + "IPPROTO_XNET": true, + "IPPROTO_XTP": true, + "IPV6_2292DSTOPTS": true, + "IPV6_2292HOPLIMIT": true, + "IPV6_2292HOPOPTS": true, + "IPV6_2292NEXTHOP": true, + "IPV6_2292PKTINFO": true, + "IPV6_2292PKTOPTIONS": true, + "IPV6_2292RTHDR": true, + "IPV6_ADDRFORM": true, + "IPV6_ADD_MEMBERSHIP": true, + "IPV6_AUTHHDR": true, + "IPV6_AUTH_LEVEL": true, + "IPV6_AUTOFLOWLABEL": true, + "IPV6_BINDANY": true, + "IPV6_BINDV6ONLY": true, + "IPV6_BOUND_IF": true, + "IPV6_CHECKSUM": true, + "IPV6_DEFAULT_MULTICAST_HOPS": true, + "IPV6_DEFAULT_MULTICAST_LOOP": true, + "IPV6_DEFHLIM": true, + "IPV6_DONTFRAG": true, + "IPV6_DROP_MEMBERSHIP": true, + "IPV6_DSTOPTS": true, + "IPV6_ESP_NETWORK_LEVEL": true, + "IPV6_ESP_TRANS_LEVEL": true, + "IPV6_FAITH": true, + "IPV6_FLOWINFO_MASK": true, + "IPV6_FLOWLABEL_MASK": true, + "IPV6_FRAGTTL": true, + "IPV6_FW_ADD": true, + "IPV6_FW_DEL": true, + "IPV6_FW_FLUSH": true, + "IPV6_FW_GET": true, + "IPV6_FW_ZERO": true, + "IPV6_HLIMDEC": true, + "IPV6_HOPLIMIT": true, + "IPV6_HOPOPTS": true, + "IPV6_IPCOMP_LEVEL": true, + "IPV6_IPSEC_POLICY": true, + "IPV6_JOIN_ANYCAST": true, + "IPV6_JOIN_GROUP": true, + "IPV6_LEAVE_ANYCAST": true, + "IPV6_LEAVE_GROUP": true, + "IPV6_MAXHLIM": true, + "IPV6_MAXOPTHDR": true, + "IPV6_MAXPACKET": true, + "IPV6_MAX_GROUP_SRC_FILTER": true, + "IPV6_MAX_MEMBERSHIPS": true, + "IPV6_MAX_SOCK_SRC_FILTER": true, + "IPV6_MIN_MEMBERSHIPS": true, + "IPV6_MMTU": true, + "IPV6_MSFILTER": true, + "IPV6_MTU": true, + "IPV6_MTU_DISCOVER": true, + "IPV6_MULTICAST_HOPS": true, + "IPV6_MULTICAST_IF": true, + "IPV6_MULTICAST_LOOP": true, + "IPV6_NEXTHOP": true, + "IPV6_OPTIONS": true, + "IPV6_PATHMTU": true, + "IPV6_PIPEX": true, + "IPV6_PKTINFO": true, + "IPV6_PMTUDISC_DO": true, + "IPV6_PMTUDISC_DONT": true, + "IPV6_PMTUDISC_PROBE": true, + "IPV6_PMTUDISC_WANT": true, + "IPV6_PORTRANGE": true, + "IPV6_PORTRANGE_DEFAULT": true, + "IPV6_PORTRANGE_HIGH": true, + "IPV6_PORTRANGE_LOW": true, + "IPV6_PREFER_TEMPADDR": true, + "IPV6_RECVDSTOPTS": true, + "IPV6_RECVDSTPORT": true, + "IPV6_RECVERR": true, + "IPV6_RECVHOPLIMIT": true, + "IPV6_RECVHOPOPTS": true, + "IPV6_RECVPATHMTU": true, + "IPV6_RECVPKTINFO": true, + "IPV6_RECVRTHDR": true, + "IPV6_RECVTCLASS": true, + "IPV6_ROUTER_ALERT": true, + "IPV6_RTABLE": true, + "IPV6_RTHDR": true, + "IPV6_RTHDRDSTOPTS": true, + "IPV6_RTHDR_LOOSE": true, + "IPV6_RTHDR_STRICT": true, + "IPV6_RTHDR_TYPE_0": true, + "IPV6_RXDSTOPTS": true, + "IPV6_RXHOPOPTS": true, + "IPV6_SOCKOPT_RESERVED1": true, + "IPV6_TCLASS": true, + "IPV6_UNICAST_HOPS": true, + "IPV6_USE_MIN_MTU": true, + "IPV6_V6ONLY": true, + "IPV6_VERSION": true, + "IPV6_VERSION_MASK": true, + "IPV6_XFRM_POLICY": true, + "IP_ADD_MEMBERSHIP": true, + "IP_ADD_SOURCE_MEMBERSHIP": true, + "IP_AUTH_LEVEL": true, + "IP_BINDANY": true, + "IP_BLOCK_SOURCE": true, + "IP_BOUND_IF": true, + "IP_DEFAULT_MULTICAST_LOOP": true, + "IP_DEFAULT_MULTICAST_TTL": true, + "IP_DF": true, + "IP_DIVERTFL": true, + "IP_DONTFRAG": true, + "IP_DROP_MEMBERSHIP": true, + "IP_DROP_SOURCE_MEMBERSHIP": true, + "IP_DUMMYNET3": true, + "IP_DUMMYNET_CONFIGURE": true, + "IP_DUMMYNET_DEL": true, + "IP_DUMMYNET_FLUSH": true, + "IP_DUMMYNET_GET": true, + "IP_EF": true, + "IP_ERRORMTU": true, + "IP_ESP_NETWORK_LEVEL": true, + "IP_ESP_TRANS_LEVEL": true, + "IP_FAITH": true, + "IP_FREEBIND": true, + "IP_FW3": true, + "IP_FW_ADD": true, + "IP_FW_DEL": true, + "IP_FW_FLUSH": true, + "IP_FW_GET": true, + "IP_FW_NAT_CFG": true, + "IP_FW_NAT_DEL": true, + "IP_FW_NAT_GET_CONFIG": true, + "IP_FW_NAT_GET_LOG": true, + "IP_FW_RESETLOG": true, + "IP_FW_TABLE_ADD": true, + "IP_FW_TABLE_DEL": true, + "IP_FW_TABLE_FLUSH": true, + "IP_FW_TABLE_GETSIZE": true, + "IP_FW_TABLE_LIST": true, + "IP_FW_ZERO": true, + "IP_HDRINCL": true, + "IP_IPCOMP_LEVEL": true, + "IP_IPSECFLOWINFO": true, + "IP_IPSEC_LOCAL_AUTH": true, + "IP_IPSEC_LOCAL_CRED": true, + "IP_IPSEC_LOCAL_ID": true, + "IP_IPSEC_POLICY": true, + "IP_IPSEC_REMOTE_AUTH": true, + "IP_IPSEC_REMOTE_CRED": true, + "IP_IPSEC_REMOTE_ID": true, + "IP_MAXPACKET": true, + "IP_MAX_GROUP_SRC_FILTER": true, + "IP_MAX_MEMBERSHIPS": true, + "IP_MAX_SOCK_MUTE_FILTER": true, + "IP_MAX_SOCK_SRC_FILTER": true, + "IP_MAX_SOURCE_FILTER": true, + "IP_MF": true, + "IP_MINFRAGSIZE": true, + "IP_MINTTL": true, + "IP_MIN_MEMBERSHIPS": true, + "IP_MSFILTER": true, + "IP_MSS": true, + "IP_MTU": true, + "IP_MTU_DISCOVER": true, + "IP_MULTICAST_IF": true, + "IP_MULTICAST_IFINDEX": true, + "IP_MULTICAST_LOOP": true, + "IP_MULTICAST_TTL": true, + "IP_MULTICAST_VIF": true, + "IP_NAT__XXX": true, + "IP_OFFMASK": true, + "IP_OLD_FW_ADD": true, + "IP_OLD_FW_DEL": true, + "IP_OLD_FW_FLUSH": true, + "IP_OLD_FW_GET": true, + "IP_OLD_FW_RESETLOG": true, + "IP_OLD_FW_ZERO": true, + "IP_ONESBCAST": true, + "IP_OPTIONS": true, + "IP_ORIGDSTADDR": true, + "IP_PASSSEC": true, + "IP_PIPEX": true, + "IP_PKTINFO": true, + "IP_PKTOPTIONS": true, + "IP_PMTUDISC": true, + "IP_PMTUDISC_DO": true, + "IP_PMTUDISC_DONT": true, + "IP_PMTUDISC_PROBE": true, + "IP_PMTUDISC_WANT": true, + "IP_PORTRANGE": true, + "IP_PORTRANGE_DEFAULT": true, + "IP_PORTRANGE_HIGH": true, + "IP_PORTRANGE_LOW": true, + "IP_RECVDSTADDR": true, + "IP_RECVDSTPORT": true, + "IP_RECVERR": true, + "IP_RECVIF": true, + "IP_RECVOPTS": true, + "IP_RECVORIGDSTADDR": true, + "IP_RECVPKTINFO": true, + "IP_RECVRETOPTS": true, + "IP_RECVRTABLE": true, + "IP_RECVTOS": true, + "IP_RECVTTL": true, + "IP_RETOPTS": true, + "IP_RF": true, + "IP_ROUTER_ALERT": true, + "IP_RSVP_OFF": true, + "IP_RSVP_ON": true, + "IP_RSVP_VIF_OFF": true, + "IP_RSVP_VIF_ON": true, + "IP_RTABLE": true, + "IP_SENDSRCADDR": true, + "IP_STRIPHDR": true, + "IP_TOS": true, + "IP_TRAFFIC_MGT_BACKGROUND": true, + "IP_TRANSPARENT": true, + "IP_TTL": true, + "IP_UNBLOCK_SOURCE": true, + "IP_XFRM_POLICY": true, + "IPv6MTUInfo": true, + "IPv6Mreq": true, + "ISIG": true, + "ISTRIP": true, + "IUCLC": true, + "IUTF8": true, + "IXANY": true, + "IXOFF": true, + "IXON": true, + "IfAddrmsg": true, + "IfAnnounceMsghdr": true, + "IfData": true, + "IfInfomsg": true, + "IfMsghdr": true, + "IfaMsghdr": true, + "IfmaMsghdr": true, + "IfmaMsghdr2": true, + "ImplementsGetwd": true, + "Inet4Pktinfo": true, + "Inet6Pktinfo": true, + "InotifyAddWatch": true, + "InotifyEvent": true, + "InotifyInit": true, + "InotifyInit1": true, + "InotifyRmWatch": true, + "InterfaceAddrMessage": true, + "InterfaceAnnounceMessage": true, + "InterfaceInfo": true, + "InterfaceMessage": true, + "InterfaceMulticastAddrMessage": true, + "InvalidHandle": true, + "Ioperm": true, + "Iopl": true, + "Iovec": true, + "IpAdapterInfo": true, + "IpAddrString": true, + "IpAddressString": true, + "IpMaskString": true, + "Issetugid": true, + "KEY_ALL_ACCESS": true, + "KEY_CREATE_LINK": true, + "KEY_CREATE_SUB_KEY": true, + "KEY_ENUMERATE_SUB_KEYS": true, + "KEY_EXECUTE": true, + "KEY_NOTIFY": true, + "KEY_QUERY_VALUE": true, + "KEY_READ": true, + "KEY_SET_VALUE": true, + "KEY_WOW64_32KEY": true, + "KEY_WOW64_64KEY": true, + "KEY_WRITE": true, + "Kevent": true, + "Kevent_t": true, + "Kill": true, + "Klogctl": true, + "Kqueue": true, + "LANG_ENGLISH": true, + "LAYERED_PROTOCOL": true, + "LCNT_OVERLOAD_FLUSH": true, + "LINUX_REBOOT_CMD_CAD_OFF": true, + "LINUX_REBOOT_CMD_CAD_ON": true, + "LINUX_REBOOT_CMD_HALT": true, + "LINUX_REBOOT_CMD_KEXEC": true, + "LINUX_REBOOT_CMD_POWER_OFF": true, + "LINUX_REBOOT_CMD_RESTART": true, + "LINUX_REBOOT_CMD_RESTART2": true, + "LINUX_REBOOT_CMD_SW_SUSPEND": true, + "LINUX_REBOOT_MAGIC1": true, + "LINUX_REBOOT_MAGIC2": true, + "LOCK_EX": true, + "LOCK_NB": true, + "LOCK_SH": true, + "LOCK_UN": true, + "LazyDLL": true, + "LazyProc": true, + "Lchown": true, + "Linger": true, + "Link": true, + "Listen": true, + "Listxattr": true, + "LoadCancelIoEx": true, + "LoadConnectEx": true, + "LoadCreateSymbolicLink": true, + "LoadDLL": true, + "LoadGetAddrInfo": true, + "LoadLibrary": true, + "LoadSetFileCompletionNotificationModes": true, + "LocalFree": true, + "Log2phys_t": true, + "LookupAccountName": true, + "LookupAccountSid": true, + "LookupSID": true, + "LsfJump": true, + "LsfSocket": true, + "LsfStmt": true, + "Lstat": true, + "MADV_AUTOSYNC": true, + "MADV_CAN_REUSE": true, + "MADV_CORE": true, + "MADV_DOFORK": true, + "MADV_DONTFORK": true, + "MADV_DONTNEED": true, + "MADV_FREE": true, + "MADV_FREE_REUSABLE": true, + "MADV_FREE_REUSE": true, + "MADV_HUGEPAGE": true, + "MADV_HWPOISON": true, + "MADV_MERGEABLE": true, + "MADV_NOCORE": true, + "MADV_NOHUGEPAGE": true, + "MADV_NORMAL": true, + "MADV_NOSYNC": true, + "MADV_PROTECT": true, + "MADV_RANDOM": true, + "MADV_REMOVE": true, + "MADV_SEQUENTIAL": true, + "MADV_SPACEAVAIL": true, + "MADV_UNMERGEABLE": true, + "MADV_WILLNEED": true, + "MADV_ZERO_WIRED_PAGES": true, + "MAP_32BIT": true, + "MAP_ALIGNED_SUPER": true, + "MAP_ALIGNMENT_16MB": true, + "MAP_ALIGNMENT_1TB": true, + "MAP_ALIGNMENT_256TB": true, + "MAP_ALIGNMENT_4GB": true, + "MAP_ALIGNMENT_64KB": true, + "MAP_ALIGNMENT_64PB": true, + "MAP_ALIGNMENT_MASK": true, + "MAP_ALIGNMENT_SHIFT": true, + "MAP_ANON": true, + "MAP_ANONYMOUS": true, + "MAP_COPY": true, + "MAP_DENYWRITE": true, + "MAP_EXECUTABLE": true, + "MAP_FILE": true, + "MAP_FIXED": true, + "MAP_FLAGMASK": true, + "MAP_GROWSDOWN": true, + "MAP_HASSEMAPHORE": true, + "MAP_HUGETLB": true, + "MAP_INHERIT": true, + "MAP_INHERIT_COPY": true, + "MAP_INHERIT_DEFAULT": true, + "MAP_INHERIT_DONATE_COPY": true, + "MAP_INHERIT_NONE": true, + "MAP_INHERIT_SHARE": true, + "MAP_JIT": true, + "MAP_LOCKED": true, + "MAP_NOCACHE": true, + "MAP_NOCORE": true, + "MAP_NOEXTEND": true, + "MAP_NONBLOCK": true, + "MAP_NORESERVE": true, + "MAP_NOSYNC": true, + "MAP_POPULATE": true, + "MAP_PREFAULT_READ": true, + "MAP_PRIVATE": true, + "MAP_RENAME": true, + "MAP_RESERVED0080": true, + "MAP_RESERVED0100": true, + "MAP_SHARED": true, + "MAP_STACK": true, + "MAP_TRYFIXED": true, + "MAP_TYPE": true, + "MAP_WIRED": true, + "MAXIMUM_REPARSE_DATA_BUFFER_SIZE": true, + "MAXLEN_IFDESCR": true, + "MAXLEN_PHYSADDR": true, + "MAX_ADAPTER_ADDRESS_LENGTH": true, + "MAX_ADAPTER_DESCRIPTION_LENGTH": true, + "MAX_ADAPTER_NAME_LENGTH": true, + "MAX_COMPUTERNAME_LENGTH": true, + "MAX_INTERFACE_NAME_LEN": true, + "MAX_LONG_PATH": true, + "MAX_PATH": true, + "MAX_PROTOCOL_CHAIN": true, + "MCL_CURRENT": true, + "MCL_FUTURE": true, + "MNT_DETACH": true, + "MNT_EXPIRE": true, + "MNT_FORCE": true, + "MSG_BCAST": true, + "MSG_CMSG_CLOEXEC": true, + "MSG_COMPAT": true, + "MSG_CONFIRM": true, + "MSG_CONTROLMBUF": true, + "MSG_CTRUNC": true, + "MSG_DONTROUTE": true, + "MSG_DONTWAIT": true, + "MSG_EOF": true, + "MSG_EOR": true, + "MSG_ERRQUEUE": true, + "MSG_FASTOPEN": true, + "MSG_FIN": true, + "MSG_FLUSH": true, + "MSG_HAVEMORE": true, + "MSG_HOLD": true, + "MSG_IOVUSRSPACE": true, + "MSG_LENUSRSPACE": true, + "MSG_MCAST": true, + "MSG_MORE": true, + "MSG_NAMEMBUF": true, + "MSG_NBIO": true, + "MSG_NEEDSA": true, + "MSG_NOSIGNAL": true, + "MSG_NOTIFICATION": true, + "MSG_OOB": true, + "MSG_PEEK": true, + "MSG_PROXY": true, + "MSG_RCVMORE": true, + "MSG_RST": true, + "MSG_SEND": true, + "MSG_SYN": true, + "MSG_TRUNC": true, + "MSG_TRYHARD": true, + "MSG_USERFLAGS": true, + "MSG_WAITALL": true, + "MSG_WAITFORONE": true, + "MSG_WAITSTREAM": true, + "MS_ACTIVE": true, + "MS_ASYNC": true, + "MS_BIND": true, + "MS_DEACTIVATE": true, + "MS_DIRSYNC": true, + "MS_INVALIDATE": true, + "MS_I_VERSION": true, + "MS_KERNMOUNT": true, + "MS_KILLPAGES": true, + "MS_MANDLOCK": true, + "MS_MGC_MSK": true, + "MS_MGC_VAL": true, + "MS_MOVE": true, + "MS_NOATIME": true, + "MS_NODEV": true, + "MS_NODIRATIME": true, + "MS_NOEXEC": true, + "MS_NOSUID": true, + "MS_NOUSER": true, + "MS_POSIXACL": true, + "MS_PRIVATE": true, + "MS_RDONLY": true, + "MS_REC": true, + "MS_RELATIME": true, + "MS_REMOUNT": true, + "MS_RMT_MASK": true, + "MS_SHARED": true, + "MS_SILENT": true, + "MS_SLAVE": true, + "MS_STRICTATIME": true, + "MS_SYNC": true, + "MS_SYNCHRONOUS": true, + "MS_UNBINDABLE": true, + "Madvise": true, + "MapViewOfFile": true, + "MaxTokenInfoClass": true, + "Mclpool": true, + "MibIfRow": true, + "Mkdir": true, + "Mkdirat": true, + "Mkfifo": true, + "Mknod": true, + "Mknodat": true, + "Mlock": true, + "Mlockall": true, + "Mmap": true, + "Mount": true, + "MoveFile": true, + "Mprotect": true, + "Msghdr": true, + "Munlock": true, + "Munlockall": true, + "Munmap": true, + "MustLoadDLL": true, + "NAME_MAX": true, + "NETLINK_ADD_MEMBERSHIP": true, + "NETLINK_AUDIT": true, + "NETLINK_BROADCAST_ERROR": true, + "NETLINK_CONNECTOR": true, + "NETLINK_DNRTMSG": true, + "NETLINK_DROP_MEMBERSHIP": true, + "NETLINK_ECRYPTFS": true, + "NETLINK_FIB_LOOKUP": true, + "NETLINK_FIREWALL": true, + "NETLINK_GENERIC": true, + "NETLINK_INET_DIAG": true, + "NETLINK_IP6_FW": true, + "NETLINK_ISCSI": true, + "NETLINK_KOBJECT_UEVENT": true, + "NETLINK_NETFILTER": true, + "NETLINK_NFLOG": true, + "NETLINK_NO_ENOBUFS": true, + "NETLINK_PKTINFO": true, + "NETLINK_RDMA": true, + "NETLINK_ROUTE": true, + "NETLINK_SCSITRANSPORT": true, + "NETLINK_SELINUX": true, + "NETLINK_UNUSED": true, + "NETLINK_USERSOCK": true, + "NETLINK_XFRM": true, + "NET_RT_DUMP": true, + "NET_RT_DUMP2": true, + "NET_RT_FLAGS": true, + "NET_RT_IFLIST": true, + "NET_RT_IFLIST2": true, + "NET_RT_IFLISTL": true, + "NET_RT_IFMALIST": true, + "NET_RT_MAXID": true, + "NET_RT_OIFLIST": true, + "NET_RT_OOIFLIST": true, + "NET_RT_STAT": true, + "NET_RT_STATS": true, + "NET_RT_TABLE": true, + "NET_RT_TRASH": true, + "NLA_ALIGNTO": true, + "NLA_F_NESTED": true, + "NLA_F_NET_BYTEORDER": true, + "NLA_HDRLEN": true, + "NLMSG_ALIGNTO": true, + "NLMSG_DONE": true, + "NLMSG_ERROR": true, + "NLMSG_HDRLEN": true, + "NLMSG_MIN_TYPE": true, + "NLMSG_NOOP": true, + "NLMSG_OVERRUN": true, + "NLM_F_ACK": true, + "NLM_F_APPEND": true, + "NLM_F_ATOMIC": true, + "NLM_F_CREATE": true, + "NLM_F_DUMP": true, + "NLM_F_ECHO": true, + "NLM_F_EXCL": true, + "NLM_F_MATCH": true, + "NLM_F_MULTI": true, + "NLM_F_REPLACE": true, + "NLM_F_REQUEST": true, + "NLM_F_ROOT": true, + "NOFLSH": true, + "NOTE_ABSOLUTE": true, + "NOTE_ATTRIB": true, + "NOTE_CHILD": true, + "NOTE_DELETE": true, + "NOTE_EOF": true, + "NOTE_EXEC": true, + "NOTE_EXIT": true, + "NOTE_EXITSTATUS": true, + "NOTE_EXTEND": true, + "NOTE_FFAND": true, + "NOTE_FFCOPY": true, + "NOTE_FFCTRLMASK": true, + "NOTE_FFLAGSMASK": true, + "NOTE_FFNOP": true, + "NOTE_FFOR": true, + "NOTE_FORK": true, + "NOTE_LINK": true, + "NOTE_LOWAT": true, + "NOTE_NONE": true, + "NOTE_NSECONDS": true, + "NOTE_PCTRLMASK": true, + "NOTE_PDATAMASK": true, + "NOTE_REAP": true, + "NOTE_RENAME": true, + "NOTE_RESOURCEEND": true, + "NOTE_REVOKE": true, + "NOTE_SECONDS": true, + "NOTE_SIGNAL": true, + "NOTE_TRACK": true, + "NOTE_TRACKERR": true, + "NOTE_TRIGGER": true, + "NOTE_TRUNCATE": true, + "NOTE_USECONDS": true, + "NOTE_VM_ERROR": true, + "NOTE_VM_PRESSURE": true, + "NOTE_VM_PRESSURE_SUDDEN_TERMINATE": true, + "NOTE_VM_PRESSURE_TERMINATE": true, + "NOTE_WRITE": true, + "NameCanonical": true, + "NameCanonicalEx": true, + "NameDisplay": true, + "NameDnsDomain": true, + "NameFullyQualifiedDN": true, + "NameSamCompatible": true, + "NameServicePrincipal": true, + "NameUniqueId": true, + "NameUnknown": true, + "NameUserPrincipal": true, + "Nanosleep": true, + "NetApiBufferFree": true, + "NetGetJoinInformation": true, + "NetSetupDomainName": true, + "NetSetupUnjoined": true, + "NetSetupUnknownStatus": true, + "NetSetupWorkgroupName": true, + "NetUserGetInfo": true, + "NetlinkMessage": true, + "NetlinkRIB": true, + "NetlinkRouteAttr": true, + "NetlinkRouteRequest": true, + "NewCallback": true, + "NewCallbackCDecl": true, + "NewLazyDLL": true, + "NlAttr": true, + "NlMsgerr": true, + "NlMsghdr": true, + "NsecToFiletime": true, + "NsecToTimespec": true, + "NsecToTimeval": true, + "Ntohs": true, + "OCRNL": true, + "OFDEL": true, + "OFILL": true, + "OFIOGETBMAP": true, + "OID_PKIX_KP_SERVER_AUTH": true, + "OID_SERVER_GATED_CRYPTO": true, + "OID_SGC_NETSCAPE": true, + "OLCUC": true, + "ONLCR": true, + "ONLRET": true, + "ONOCR": true, + "ONOEOT": true, + "OPEN_ALWAYS": true, + "OPEN_EXISTING": true, + "OPOST": true, + "O_ACCMODE": true, + "O_ALERT": true, + "O_ALT_IO": true, + "O_APPEND": true, + "O_ASYNC": true, + "O_CLOEXEC": true, + "O_CREAT": true, + "O_DIRECT": true, + "O_DIRECTORY": true, + "O_DSYNC": true, + "O_EVTONLY": true, + "O_EXCL": true, + "O_EXEC": true, + "O_EXLOCK": true, + "O_FSYNC": true, + "O_LARGEFILE": true, + "O_NDELAY": true, + "O_NOATIME": true, + "O_NOCTTY": true, + "O_NOFOLLOW": true, + "O_NONBLOCK": true, + "O_NOSIGPIPE": true, + "O_POPUP": true, + "O_RDONLY": true, + "O_RDWR": true, + "O_RSYNC": true, + "O_SHLOCK": true, + "O_SYMLINK": true, + "O_SYNC": true, + "O_TRUNC": true, + "O_TTY_INIT": true, + "O_WRONLY": true, + "Open": true, + "OpenCurrentProcessToken": true, + "OpenProcess": true, + "OpenProcessToken": true, + "Openat": true, + "Overlapped": true, + "PACKET_ADD_MEMBERSHIP": true, + "PACKET_BROADCAST": true, + "PACKET_DROP_MEMBERSHIP": true, + "PACKET_FASTROUTE": true, + "PACKET_HOST": true, + "PACKET_LOOPBACK": true, + "PACKET_MR_ALLMULTI": true, + "PACKET_MR_MULTICAST": true, + "PACKET_MR_PROMISC": true, + "PACKET_MULTICAST": true, + "PACKET_OTHERHOST": true, + "PACKET_OUTGOING": true, + "PACKET_RECV_OUTPUT": true, + "PACKET_RX_RING": true, + "PACKET_STATISTICS": true, + "PAGE_EXECUTE_READ": true, + "PAGE_EXECUTE_READWRITE": true, + "PAGE_EXECUTE_WRITECOPY": true, + "PAGE_READONLY": true, + "PAGE_READWRITE": true, + "PAGE_WRITECOPY": true, + "PARENB": true, + "PARMRK": true, + "PARODD": true, + "PENDIN": true, + "PFL_HIDDEN": true, + "PFL_MATCHES_PROTOCOL_ZERO": true, + "PFL_MULTIPLE_PROTO_ENTRIES": true, + "PFL_NETWORKDIRECT_PROVIDER": true, + "PFL_RECOMMENDED_PROTO_ENTRY": true, + "PF_FLUSH": true, + "PKCS_7_ASN_ENCODING": true, + "PMC5_PIPELINE_FLUSH": true, + "PRIO_PGRP": true, + "PRIO_PROCESS": true, + "PRIO_USER": true, + "PRI_IOFLUSH": true, + "PROCESS_QUERY_INFORMATION": true, + "PROCESS_TERMINATE": true, + "PROT_EXEC": true, + "PROT_GROWSDOWN": true, + "PROT_GROWSUP": true, + "PROT_NONE": true, + "PROT_READ": true, + "PROT_WRITE": true, + "PROV_DH_SCHANNEL": true, + "PROV_DSS": true, + "PROV_DSS_DH": true, + "PROV_EC_ECDSA_FULL": true, + "PROV_EC_ECDSA_SIG": true, + "PROV_EC_ECNRA_FULL": true, + "PROV_EC_ECNRA_SIG": true, + "PROV_FORTEZZA": true, + "PROV_INTEL_SEC": true, + "PROV_MS_EXCHANGE": true, + "PROV_REPLACE_OWF": true, + "PROV_RNG": true, + "PROV_RSA_AES": true, + "PROV_RSA_FULL": true, + "PROV_RSA_SCHANNEL": true, + "PROV_RSA_SIG": true, + "PROV_SPYRUS_LYNKS": true, + "PROV_SSL": true, + "PR_CAPBSET_DROP": true, + "PR_CAPBSET_READ": true, + "PR_CLEAR_SECCOMP_FILTER": true, + "PR_ENDIAN_BIG": true, + "PR_ENDIAN_LITTLE": true, + "PR_ENDIAN_PPC_LITTLE": true, + "PR_FPEMU_NOPRINT": true, + "PR_FPEMU_SIGFPE": true, + "PR_FP_EXC_ASYNC": true, + "PR_FP_EXC_DISABLED": true, + "PR_FP_EXC_DIV": true, + "PR_FP_EXC_INV": true, + "PR_FP_EXC_NONRECOV": true, + "PR_FP_EXC_OVF": true, + "PR_FP_EXC_PRECISE": true, + "PR_FP_EXC_RES": true, + "PR_FP_EXC_SW_ENABLE": true, + "PR_FP_EXC_UND": true, + "PR_GET_DUMPABLE": true, + "PR_GET_ENDIAN": true, + "PR_GET_FPEMU": true, + "PR_GET_FPEXC": true, + "PR_GET_KEEPCAPS": true, + "PR_GET_NAME": true, + "PR_GET_PDEATHSIG": true, + "PR_GET_SECCOMP": true, + "PR_GET_SECCOMP_FILTER": true, + "PR_GET_SECUREBITS": true, + "PR_GET_TIMERSLACK": true, + "PR_GET_TIMING": true, + "PR_GET_TSC": true, + "PR_GET_UNALIGN": true, + "PR_MCE_KILL": true, + "PR_MCE_KILL_CLEAR": true, + "PR_MCE_KILL_DEFAULT": true, + "PR_MCE_KILL_EARLY": true, + "PR_MCE_KILL_GET": true, + "PR_MCE_KILL_LATE": true, + "PR_MCE_KILL_SET": true, + "PR_SECCOMP_FILTER_EVENT": true, + "PR_SECCOMP_FILTER_SYSCALL": true, + "PR_SET_DUMPABLE": true, + "PR_SET_ENDIAN": true, + "PR_SET_FPEMU": true, + "PR_SET_FPEXC": true, + "PR_SET_KEEPCAPS": true, + "PR_SET_NAME": true, + "PR_SET_PDEATHSIG": true, + "PR_SET_PTRACER": true, + "PR_SET_SECCOMP": true, + "PR_SET_SECCOMP_FILTER": true, + "PR_SET_SECUREBITS": true, + "PR_SET_TIMERSLACK": true, + "PR_SET_TIMING": true, + "PR_SET_TSC": true, + "PR_SET_UNALIGN": true, + "PR_TASK_PERF_EVENTS_DISABLE": true, + "PR_TASK_PERF_EVENTS_ENABLE": true, + "PR_TIMING_STATISTICAL": true, + "PR_TIMING_TIMESTAMP": true, + "PR_TSC_ENABLE": true, + "PR_TSC_SIGSEGV": true, + "PR_UNALIGN_NOPRINT": true, + "PR_UNALIGN_SIGBUS": true, + "PTRACE_ARCH_PRCTL": true, + "PTRACE_ATTACH": true, + "PTRACE_CONT": true, + "PTRACE_DETACH": true, + "PTRACE_EVENT_CLONE": true, + "PTRACE_EVENT_EXEC": true, + "PTRACE_EVENT_EXIT": true, + "PTRACE_EVENT_FORK": true, + "PTRACE_EVENT_VFORK": true, + "PTRACE_EVENT_VFORK_DONE": true, + "PTRACE_GETCRUNCHREGS": true, + "PTRACE_GETEVENTMSG": true, + "PTRACE_GETFPREGS": true, + "PTRACE_GETFPXREGS": true, + "PTRACE_GETHBPREGS": true, + "PTRACE_GETREGS": true, + "PTRACE_GETREGSET": true, + "PTRACE_GETSIGINFO": true, + "PTRACE_GETVFPREGS": true, + "PTRACE_GETWMMXREGS": true, + "PTRACE_GET_THREAD_AREA": true, + "PTRACE_KILL": true, + "PTRACE_OLDSETOPTIONS": true, + "PTRACE_O_MASK": true, + "PTRACE_O_TRACECLONE": true, + "PTRACE_O_TRACEEXEC": true, + "PTRACE_O_TRACEEXIT": true, + "PTRACE_O_TRACEFORK": true, + "PTRACE_O_TRACESYSGOOD": true, + "PTRACE_O_TRACEVFORK": true, + "PTRACE_O_TRACEVFORKDONE": true, + "PTRACE_PEEKDATA": true, + "PTRACE_PEEKTEXT": true, + "PTRACE_PEEKUSR": true, + "PTRACE_POKEDATA": true, + "PTRACE_POKETEXT": true, + "PTRACE_POKEUSR": true, + "PTRACE_SETCRUNCHREGS": true, + "PTRACE_SETFPREGS": true, + "PTRACE_SETFPXREGS": true, + "PTRACE_SETHBPREGS": true, + "PTRACE_SETOPTIONS": true, + "PTRACE_SETREGS": true, + "PTRACE_SETREGSET": true, + "PTRACE_SETSIGINFO": true, + "PTRACE_SETVFPREGS": true, + "PTRACE_SETWMMXREGS": true, + "PTRACE_SET_SYSCALL": true, + "PTRACE_SET_THREAD_AREA": true, + "PTRACE_SINGLEBLOCK": true, + "PTRACE_SINGLESTEP": true, + "PTRACE_SYSCALL": true, + "PTRACE_SYSEMU": true, + "PTRACE_SYSEMU_SINGLESTEP": true, + "PTRACE_TRACEME": true, + "PT_ATTACH": true, + "PT_ATTACHEXC": true, + "PT_CONTINUE": true, + "PT_DATA_ADDR": true, + "PT_DENY_ATTACH": true, + "PT_DETACH": true, + "PT_FIRSTMACH": true, + "PT_FORCEQUOTA": true, + "PT_KILL": true, + "PT_MASK": true, + "PT_READ_D": true, + "PT_READ_I": true, + "PT_READ_U": true, + "PT_SIGEXC": true, + "PT_STEP": true, + "PT_TEXT_ADDR": true, + "PT_TEXT_END_ADDR": true, + "PT_THUPDATE": true, + "PT_TRACE_ME": true, + "PT_WRITE_D": true, + "PT_WRITE_I": true, + "PT_WRITE_U": true, + "ParseDirent": true, + "ParseNetlinkMessage": true, + "ParseNetlinkRouteAttr": true, + "ParseRoutingMessage": true, + "ParseRoutingSockaddr": true, + "ParseSocketControlMessage": true, + "ParseUnixCredentials": true, + "ParseUnixRights": true, + "PathMax": true, + "Pathconf": true, + "Pause": true, + "Pipe": true, + "Pipe2": true, + "PivotRoot": true, + "Pointer": true, + "PostQueuedCompletionStatus": true, + "Pread": true, + "Proc": true, + "ProcAttr": true, + "Process32First": true, + "Process32Next": true, + "ProcessEntry32": true, + "ProcessInformation": true, + "Protoent": true, + "PtraceAttach": true, + "PtraceCont": true, + "PtraceDetach": true, + "PtraceGetEventMsg": true, + "PtraceGetRegs": true, + "PtracePeekData": true, + "PtracePeekText": true, + "PtracePokeData": true, + "PtracePokeText": true, + "PtraceRegs": true, + "PtraceSetOptions": true, + "PtraceSetRegs": true, + "PtraceSingleStep": true, + "PtraceSyscall": true, + "Pwrite": true, + "REG_BINARY": true, + "REG_DWORD": true, + "REG_DWORD_BIG_ENDIAN": true, + "REG_DWORD_LITTLE_ENDIAN": true, + "REG_EXPAND_SZ": true, + "REG_FULL_RESOURCE_DESCRIPTOR": true, + "REG_LINK": true, + "REG_MULTI_SZ": true, + "REG_NONE": true, + "REG_QWORD": true, + "REG_QWORD_LITTLE_ENDIAN": true, + "REG_RESOURCE_LIST": true, + "REG_RESOURCE_REQUIREMENTS_LIST": true, + "REG_SZ": true, + "RLIMIT_AS": true, + "RLIMIT_CORE": true, + "RLIMIT_CPU": true, + "RLIMIT_DATA": true, + "RLIMIT_FSIZE": true, + "RLIMIT_NOFILE": true, + "RLIMIT_STACK": true, + "RLIM_INFINITY": true, + "RTAX_ADVMSS": true, + "RTAX_AUTHOR": true, + "RTAX_BRD": true, + "RTAX_CWND": true, + "RTAX_DST": true, + "RTAX_FEATURES": true, + "RTAX_FEATURE_ALLFRAG": true, + "RTAX_FEATURE_ECN": true, + "RTAX_FEATURE_SACK": true, + "RTAX_FEATURE_TIMESTAMP": true, + "RTAX_GATEWAY": true, + "RTAX_GENMASK": true, + "RTAX_HOPLIMIT": true, + "RTAX_IFA": true, + "RTAX_IFP": true, + "RTAX_INITCWND": true, + "RTAX_INITRWND": true, + "RTAX_LABEL": true, + "RTAX_LOCK": true, + "RTAX_MAX": true, + "RTAX_MTU": true, + "RTAX_NETMASK": true, + "RTAX_REORDERING": true, + "RTAX_RTO_MIN": true, + "RTAX_RTT": true, + "RTAX_RTTVAR": true, + "RTAX_SRC": true, + "RTAX_SRCMASK": true, + "RTAX_SSTHRESH": true, + "RTAX_TAG": true, + "RTAX_UNSPEC": true, + "RTAX_WINDOW": true, + "RTA_ALIGNTO": true, + "RTA_AUTHOR": true, + "RTA_BRD": true, + "RTA_CACHEINFO": true, + "RTA_DST": true, + "RTA_FLOW": true, + "RTA_GATEWAY": true, + "RTA_GENMASK": true, + "RTA_IFA": true, + "RTA_IFP": true, + "RTA_IIF": true, + "RTA_LABEL": true, + "RTA_MAX": true, + "RTA_METRICS": true, + "RTA_MULTIPATH": true, + "RTA_NETMASK": true, + "RTA_OIF": true, + "RTA_PREFSRC": true, + "RTA_PRIORITY": true, + "RTA_SRC": true, + "RTA_SRCMASK": true, + "RTA_TABLE": true, + "RTA_TAG": true, + "RTA_UNSPEC": true, + "RTCF_DIRECTSRC": true, + "RTCF_DOREDIRECT": true, + "RTCF_LOG": true, + "RTCF_MASQ": true, + "RTCF_NAT": true, + "RTCF_VALVE": true, + "RTF_ADDRCLASSMASK": true, + "RTF_ADDRCONF": true, + "RTF_ALLONLINK": true, + "RTF_ANNOUNCE": true, + "RTF_BLACKHOLE": true, + "RTF_BROADCAST": true, + "RTF_CACHE": true, + "RTF_CLONED": true, + "RTF_CLONING": true, + "RTF_CONDEMNED": true, + "RTF_DEFAULT": true, + "RTF_DELCLONE": true, + "RTF_DONE": true, + "RTF_DYNAMIC": true, + "RTF_FLOW": true, + "RTF_FMASK": true, + "RTF_GATEWAY": true, + "RTF_GWFLAG_COMPAT": true, + "RTF_HOST": true, + "RTF_IFREF": true, + "RTF_IFSCOPE": true, + "RTF_INTERFACE": true, + "RTF_IRTT": true, + "RTF_LINKRT": true, + "RTF_LLDATA": true, + "RTF_LLINFO": true, + "RTF_LOCAL": true, + "RTF_MASK": true, + "RTF_MODIFIED": true, + "RTF_MPATH": true, + "RTF_MPLS": true, + "RTF_MSS": true, + "RTF_MTU": true, + "RTF_MULTICAST": true, + "RTF_NAT": true, + "RTF_NOFORWARD": true, + "RTF_NONEXTHOP": true, + "RTF_NOPMTUDISC": true, + "RTF_PERMANENT_ARP": true, + "RTF_PINNED": true, + "RTF_POLICY": true, + "RTF_PRCLONING": true, + "RTF_PROTO1": true, + "RTF_PROTO2": true, + "RTF_PROTO3": true, + "RTF_REINSTATE": true, + "RTF_REJECT": true, + "RTF_RNH_LOCKED": true, + "RTF_SOURCE": true, + "RTF_SRC": true, + "RTF_STATIC": true, + "RTF_STICKY": true, + "RTF_THROW": true, + "RTF_TUNNEL": true, + "RTF_UP": true, + "RTF_USETRAILERS": true, + "RTF_WASCLONED": true, + "RTF_WINDOW": true, + "RTF_XRESOLVE": true, + "RTM_ADD": true, + "RTM_BASE": true, + "RTM_CHANGE": true, + "RTM_CHGADDR": true, + "RTM_DELACTION": true, + "RTM_DELADDR": true, + "RTM_DELADDRLABEL": true, + "RTM_DELETE": true, + "RTM_DELLINK": true, + "RTM_DELMADDR": true, + "RTM_DELNEIGH": true, + "RTM_DELQDISC": true, + "RTM_DELROUTE": true, + "RTM_DELRULE": true, + "RTM_DELTCLASS": true, + "RTM_DELTFILTER": true, + "RTM_DESYNC": true, + "RTM_F_CLONED": true, + "RTM_F_EQUALIZE": true, + "RTM_F_NOTIFY": true, + "RTM_F_PREFIX": true, + "RTM_GET": true, + "RTM_GET2": true, + "RTM_GETACTION": true, + "RTM_GETADDR": true, + "RTM_GETADDRLABEL": true, + "RTM_GETANYCAST": true, + "RTM_GETDCB": true, + "RTM_GETLINK": true, + "RTM_GETMULTICAST": true, + "RTM_GETNEIGH": true, + "RTM_GETNEIGHTBL": true, + "RTM_GETQDISC": true, + "RTM_GETROUTE": true, + "RTM_GETRULE": true, + "RTM_GETTCLASS": true, + "RTM_GETTFILTER": true, + "RTM_IEEE80211": true, + "RTM_IFANNOUNCE": true, + "RTM_IFINFO": true, + "RTM_IFINFO2": true, + "RTM_LLINFO_UPD": true, + "RTM_LOCK": true, + "RTM_LOSING": true, + "RTM_MAX": true, + "RTM_MAXSIZE": true, + "RTM_MISS": true, + "RTM_NEWACTION": true, + "RTM_NEWADDR": true, + "RTM_NEWADDRLABEL": true, + "RTM_NEWLINK": true, + "RTM_NEWMADDR": true, + "RTM_NEWMADDR2": true, + "RTM_NEWNDUSEROPT": true, + "RTM_NEWNEIGH": true, + "RTM_NEWNEIGHTBL": true, + "RTM_NEWPREFIX": true, + "RTM_NEWQDISC": true, + "RTM_NEWROUTE": true, + "RTM_NEWRULE": true, + "RTM_NEWTCLASS": true, + "RTM_NEWTFILTER": true, + "RTM_NR_FAMILIES": true, + "RTM_NR_MSGTYPES": true, + "RTM_OIFINFO": true, + "RTM_OLDADD": true, + "RTM_OLDDEL": true, + "RTM_OOIFINFO": true, + "RTM_REDIRECT": true, + "RTM_RESOLVE": true, + "RTM_RTTUNIT": true, + "RTM_SETDCB": true, + "RTM_SETGATE": true, + "RTM_SETLINK": true, + "RTM_SETNEIGHTBL": true, + "RTM_VERSION": true, + "RTNH_ALIGNTO": true, + "RTNH_F_DEAD": true, + "RTNH_F_ONLINK": true, + "RTNH_F_PERVASIVE": true, + "RTNLGRP_IPV4_IFADDR": true, + "RTNLGRP_IPV4_MROUTE": true, + "RTNLGRP_IPV4_ROUTE": true, + "RTNLGRP_IPV4_RULE": true, + "RTNLGRP_IPV6_IFADDR": true, + "RTNLGRP_IPV6_IFINFO": true, + "RTNLGRP_IPV6_MROUTE": true, + "RTNLGRP_IPV6_PREFIX": true, + "RTNLGRP_IPV6_ROUTE": true, + "RTNLGRP_IPV6_RULE": true, + "RTNLGRP_LINK": true, + "RTNLGRP_ND_USEROPT": true, + "RTNLGRP_NEIGH": true, + "RTNLGRP_NONE": true, + "RTNLGRP_NOTIFY": true, + "RTNLGRP_TC": true, + "RTN_ANYCAST": true, + "RTN_BLACKHOLE": true, + "RTN_BROADCAST": true, + "RTN_LOCAL": true, + "RTN_MAX": true, + "RTN_MULTICAST": true, + "RTN_NAT": true, + "RTN_PROHIBIT": true, + "RTN_THROW": true, + "RTN_UNICAST": true, + "RTN_UNREACHABLE": true, + "RTN_UNSPEC": true, + "RTN_XRESOLVE": true, + "RTPROT_BIRD": true, + "RTPROT_BOOT": true, + "RTPROT_DHCP": true, + "RTPROT_DNROUTED": true, + "RTPROT_GATED": true, + "RTPROT_KERNEL": true, + "RTPROT_MRT": true, + "RTPROT_NTK": true, + "RTPROT_RA": true, + "RTPROT_REDIRECT": true, + "RTPROT_STATIC": true, + "RTPROT_UNSPEC": true, + "RTPROT_XORP": true, + "RTPROT_ZEBRA": true, + "RTV_EXPIRE": true, + "RTV_HOPCOUNT": true, + "RTV_MTU": true, + "RTV_RPIPE": true, + "RTV_RTT": true, + "RTV_RTTVAR": true, + "RTV_SPIPE": true, + "RTV_SSTHRESH": true, + "RTV_WEIGHT": true, + "RT_CACHING_CONTEXT": true, + "RT_CLASS_DEFAULT": true, + "RT_CLASS_LOCAL": true, + "RT_CLASS_MAIN": true, + "RT_CLASS_MAX": true, + "RT_CLASS_UNSPEC": true, + "RT_DEFAULT_FIB": true, + "RT_NORTREF": true, + "RT_SCOPE_HOST": true, + "RT_SCOPE_LINK": true, + "RT_SCOPE_NOWHERE": true, + "RT_SCOPE_SITE": true, + "RT_SCOPE_UNIVERSE": true, + "RT_TABLEID_MAX": true, + "RT_TABLE_COMPAT": true, + "RT_TABLE_DEFAULT": true, + "RT_TABLE_LOCAL": true, + "RT_TABLE_MAIN": true, + "RT_TABLE_MAX": true, + "RT_TABLE_UNSPEC": true, + "RUSAGE_CHILDREN": true, + "RUSAGE_SELF": true, + "RUSAGE_THREAD": true, + "Radvisory_t": true, + "RawConn": true, + "RawSockaddr": true, + "RawSockaddrAny": true, + "RawSockaddrDatalink": true, + "RawSockaddrInet4": true, + "RawSockaddrInet6": true, + "RawSockaddrLinklayer": true, + "RawSockaddrNetlink": true, + "RawSockaddrUnix": true, + "RawSyscall": true, + "RawSyscall6": true, + "Read": true, + "ReadConsole": true, + "ReadDirectoryChanges": true, + "ReadDirent": true, + "ReadFile": true, + "Readlink": true, + "Reboot": true, + "Recvfrom": true, + "Recvmsg": true, + "RegCloseKey": true, + "RegEnumKeyEx": true, + "RegOpenKeyEx": true, + "RegQueryInfoKey": true, + "RegQueryValueEx": true, + "RemoveDirectory": true, + "Removexattr": true, + "Rename": true, + "Renameat": true, + "Revoke": true, + "Rlimit": true, + "Rmdir": true, + "RouteMessage": true, + "RouteRIB": true, + "RtAttr": true, + "RtGenmsg": true, + "RtMetrics": true, + "RtMsg": true, + "RtMsghdr": true, + "RtNexthop": true, + "Rusage": true, + "SCM_BINTIME": true, + "SCM_CREDENTIALS": true, + "SCM_CREDS": true, + "SCM_RIGHTS": true, + "SCM_TIMESTAMP": true, + "SCM_TIMESTAMPING": true, + "SCM_TIMESTAMPNS": true, + "SCM_TIMESTAMP_MONOTONIC": true, + "SHUT_RD": true, + "SHUT_RDWR": true, + "SHUT_WR": true, + "SID": true, + "SIDAndAttributes": true, + "SIGABRT": true, + "SIGALRM": true, + "SIGBUS": true, + "SIGCHLD": true, + "SIGCLD": true, + "SIGCONT": true, + "SIGEMT": true, + "SIGFPE": true, + "SIGHUP": true, + "SIGILL": true, + "SIGINFO": true, + "SIGINT": true, + "SIGIO": true, + "SIGIOT": true, + "SIGKILL": true, + "SIGLIBRT": true, + "SIGLWP": true, + "SIGPIPE": true, + "SIGPOLL": true, + "SIGPROF": true, + "SIGPWR": true, + "SIGQUIT": true, + "SIGSEGV": true, + "SIGSTKFLT": true, + "SIGSTOP": true, + "SIGSYS": true, + "SIGTERM": true, + "SIGTHR": true, + "SIGTRAP": true, + "SIGTSTP": true, + "SIGTTIN": true, + "SIGTTOU": true, + "SIGUNUSED": true, + "SIGURG": true, + "SIGUSR1": true, + "SIGUSR2": true, + "SIGVTALRM": true, + "SIGWINCH": true, + "SIGXCPU": true, + "SIGXFSZ": true, + "SIOCADDDLCI": true, + "SIOCADDMULTI": true, + "SIOCADDRT": true, + "SIOCAIFADDR": true, + "SIOCAIFGROUP": true, + "SIOCALIFADDR": true, + "SIOCARPIPLL": true, + "SIOCATMARK": true, + "SIOCAUTOADDR": true, + "SIOCAUTONETMASK": true, + "SIOCBRDGADD": true, + "SIOCBRDGADDS": true, + "SIOCBRDGARL": true, + "SIOCBRDGDADDR": true, + "SIOCBRDGDEL": true, + "SIOCBRDGDELS": true, + "SIOCBRDGFLUSH": true, + "SIOCBRDGFRL": true, + "SIOCBRDGGCACHE": true, + "SIOCBRDGGFD": true, + "SIOCBRDGGHT": true, + "SIOCBRDGGIFFLGS": true, + "SIOCBRDGGMA": true, + "SIOCBRDGGPARAM": true, + "SIOCBRDGGPRI": true, + "SIOCBRDGGRL": true, + "SIOCBRDGGSIFS": true, + "SIOCBRDGGTO": true, + "SIOCBRDGIFS": true, + "SIOCBRDGRTS": true, + "SIOCBRDGSADDR": true, + "SIOCBRDGSCACHE": true, + "SIOCBRDGSFD": true, + "SIOCBRDGSHT": true, + "SIOCBRDGSIFCOST": true, + "SIOCBRDGSIFFLGS": true, + "SIOCBRDGSIFPRIO": true, + "SIOCBRDGSMA": true, + "SIOCBRDGSPRI": true, + "SIOCBRDGSPROTO": true, + "SIOCBRDGSTO": true, + "SIOCBRDGSTXHC": true, + "SIOCDARP": true, + "SIOCDELDLCI": true, + "SIOCDELMULTI": true, + "SIOCDELRT": true, + "SIOCDEVPRIVATE": true, + "SIOCDIFADDR": true, + "SIOCDIFGROUP": true, + "SIOCDIFPHYADDR": true, + "SIOCDLIFADDR": true, + "SIOCDRARP": true, + "SIOCGARP": true, + "SIOCGDRVSPEC": true, + "SIOCGETKALIVE": true, + "SIOCGETLABEL": true, + "SIOCGETPFLOW": true, + "SIOCGETPFSYNC": true, + "SIOCGETSGCNT": true, + "SIOCGETVIFCNT": true, + "SIOCGETVLAN": true, + "SIOCGHIWAT": true, + "SIOCGIFADDR": true, + "SIOCGIFADDRPREF": true, + "SIOCGIFALIAS": true, + "SIOCGIFALTMTU": true, + "SIOCGIFASYNCMAP": true, + "SIOCGIFBOND": true, + "SIOCGIFBR": true, + "SIOCGIFBRDADDR": true, + "SIOCGIFCAP": true, + "SIOCGIFCONF": true, + "SIOCGIFCOUNT": true, + "SIOCGIFDATA": true, + "SIOCGIFDESCR": true, + "SIOCGIFDEVMTU": true, + "SIOCGIFDLT": true, + "SIOCGIFDSTADDR": true, + "SIOCGIFENCAP": true, + "SIOCGIFFIB": true, + "SIOCGIFFLAGS": true, + "SIOCGIFGATTR": true, + "SIOCGIFGENERIC": true, + "SIOCGIFGMEMB": true, + "SIOCGIFGROUP": true, + "SIOCGIFHARDMTU": true, + "SIOCGIFHWADDR": true, + "SIOCGIFINDEX": true, + "SIOCGIFKPI": true, + "SIOCGIFMAC": true, + "SIOCGIFMAP": true, + "SIOCGIFMEDIA": true, + "SIOCGIFMEM": true, + "SIOCGIFMETRIC": true, + "SIOCGIFMTU": true, + "SIOCGIFNAME": true, + "SIOCGIFNETMASK": true, + "SIOCGIFPDSTADDR": true, + "SIOCGIFPFLAGS": true, + "SIOCGIFPHYS": true, + "SIOCGIFPRIORITY": true, + "SIOCGIFPSRCADDR": true, + "SIOCGIFRDOMAIN": true, + "SIOCGIFRTLABEL": true, + "SIOCGIFSLAVE": true, + "SIOCGIFSTATUS": true, + "SIOCGIFTIMESLOT": true, + "SIOCGIFTXQLEN": true, + "SIOCGIFVLAN": true, + "SIOCGIFWAKEFLAGS": true, + "SIOCGIFXFLAGS": true, + "SIOCGLIFADDR": true, + "SIOCGLIFPHYADDR": true, + "SIOCGLIFPHYRTABLE": true, + "SIOCGLIFPHYTTL": true, + "SIOCGLINKSTR": true, + "SIOCGLOWAT": true, + "SIOCGPGRP": true, + "SIOCGPRIVATE_0": true, + "SIOCGPRIVATE_1": true, + "SIOCGRARP": true, + "SIOCGSPPPPARAMS": true, + "SIOCGSTAMP": true, + "SIOCGSTAMPNS": true, + "SIOCGVH": true, + "SIOCGVNETID": true, + "SIOCIFCREATE": true, + "SIOCIFCREATE2": true, + "SIOCIFDESTROY": true, + "SIOCIFGCLONERS": true, + "SIOCINITIFADDR": true, + "SIOCPROTOPRIVATE": true, + "SIOCRSLVMULTI": true, + "SIOCRTMSG": true, + "SIOCSARP": true, + "SIOCSDRVSPEC": true, + "SIOCSETKALIVE": true, + "SIOCSETLABEL": true, + "SIOCSETPFLOW": true, + "SIOCSETPFSYNC": true, + "SIOCSETVLAN": true, + "SIOCSHIWAT": true, + "SIOCSIFADDR": true, + "SIOCSIFADDRPREF": true, + "SIOCSIFALTMTU": true, + "SIOCSIFASYNCMAP": true, + "SIOCSIFBOND": true, + "SIOCSIFBR": true, + "SIOCSIFBRDADDR": true, + "SIOCSIFCAP": true, + "SIOCSIFDESCR": true, + "SIOCSIFDSTADDR": true, + "SIOCSIFENCAP": true, + "SIOCSIFFIB": true, + "SIOCSIFFLAGS": true, + "SIOCSIFGATTR": true, + "SIOCSIFGENERIC": true, + "SIOCSIFHWADDR": true, + "SIOCSIFHWBROADCAST": true, + "SIOCSIFKPI": true, + "SIOCSIFLINK": true, + "SIOCSIFLLADDR": true, + "SIOCSIFMAC": true, + "SIOCSIFMAP": true, + "SIOCSIFMEDIA": true, + "SIOCSIFMEM": true, + "SIOCSIFMETRIC": true, + "SIOCSIFMTU": true, + "SIOCSIFNAME": true, + "SIOCSIFNETMASK": true, + "SIOCSIFPFLAGS": true, + "SIOCSIFPHYADDR": true, + "SIOCSIFPHYS": true, + "SIOCSIFPRIORITY": true, + "SIOCSIFRDOMAIN": true, + "SIOCSIFRTLABEL": true, + "SIOCSIFRVNET": true, + "SIOCSIFSLAVE": true, + "SIOCSIFTIMESLOT": true, + "SIOCSIFTXQLEN": true, + "SIOCSIFVLAN": true, + "SIOCSIFVNET": true, + "SIOCSIFXFLAGS": true, + "SIOCSLIFPHYADDR": true, + "SIOCSLIFPHYRTABLE": true, + "SIOCSLIFPHYTTL": true, + "SIOCSLINKSTR": true, + "SIOCSLOWAT": true, + "SIOCSPGRP": true, + "SIOCSRARP": true, + "SIOCSSPPPPARAMS": true, + "SIOCSVH": true, + "SIOCSVNETID": true, + "SIOCZIFDATA": true, + "SIO_GET_EXTENSION_FUNCTION_POINTER": true, + "SIO_GET_INTERFACE_LIST": true, + "SIO_KEEPALIVE_VALS": true, + "SIO_UDP_CONNRESET": true, + "SOCK_CLOEXEC": true, + "SOCK_DCCP": true, + "SOCK_DGRAM": true, + "SOCK_FLAGS_MASK": true, + "SOCK_MAXADDRLEN": true, + "SOCK_NONBLOCK": true, + "SOCK_NOSIGPIPE": true, + "SOCK_PACKET": true, + "SOCK_RAW": true, + "SOCK_RDM": true, + "SOCK_SEQPACKET": true, + "SOCK_STREAM": true, + "SOL_AAL": true, + "SOL_ATM": true, + "SOL_DECNET": true, + "SOL_ICMPV6": true, + "SOL_IP": true, + "SOL_IPV6": true, + "SOL_IRDA": true, + "SOL_PACKET": true, + "SOL_RAW": true, + "SOL_SOCKET": true, + "SOL_TCP": true, + "SOL_X25": true, + "SOMAXCONN": true, + "SO_ACCEPTCONN": true, + "SO_ACCEPTFILTER": true, + "SO_ATTACH_FILTER": true, + "SO_BINDANY": true, + "SO_BINDTODEVICE": true, + "SO_BINTIME": true, + "SO_BROADCAST": true, + "SO_BSDCOMPAT": true, + "SO_DEBUG": true, + "SO_DETACH_FILTER": true, + "SO_DOMAIN": true, + "SO_DONTROUTE": true, + "SO_DONTTRUNC": true, + "SO_ERROR": true, + "SO_KEEPALIVE": true, + "SO_LABEL": true, + "SO_LINGER": true, + "SO_LINGER_SEC": true, + "SO_LISTENINCQLEN": true, + "SO_LISTENQLEN": true, + "SO_LISTENQLIMIT": true, + "SO_MARK": true, + "SO_NETPROC": true, + "SO_NKE": true, + "SO_NOADDRERR": true, + "SO_NOHEADER": true, + "SO_NOSIGPIPE": true, + "SO_NOTIFYCONFLICT": true, + "SO_NO_CHECK": true, + "SO_NO_DDP": true, + "SO_NO_OFFLOAD": true, + "SO_NP_EXTENSIONS": true, + "SO_NREAD": true, + "SO_NWRITE": true, + "SO_OOBINLINE": true, + "SO_OVERFLOWED": true, + "SO_PASSCRED": true, + "SO_PASSSEC": true, + "SO_PEERCRED": true, + "SO_PEERLABEL": true, + "SO_PEERNAME": true, + "SO_PEERSEC": true, + "SO_PRIORITY": true, + "SO_PROTOCOL": true, + "SO_PROTOTYPE": true, + "SO_RANDOMPORT": true, + "SO_RCVBUF": true, + "SO_RCVBUFFORCE": true, + "SO_RCVLOWAT": true, + "SO_RCVTIMEO": true, + "SO_RESTRICTIONS": true, + "SO_RESTRICT_DENYIN": true, + "SO_RESTRICT_DENYOUT": true, + "SO_RESTRICT_DENYSET": true, + "SO_REUSEADDR": true, + "SO_REUSEPORT": true, + "SO_REUSESHAREUID": true, + "SO_RTABLE": true, + "SO_RXQ_OVFL": true, + "SO_SECURITY_AUTHENTICATION": true, + "SO_SECURITY_ENCRYPTION_NETWORK": true, + "SO_SECURITY_ENCRYPTION_TRANSPORT": true, + "SO_SETFIB": true, + "SO_SNDBUF": true, + "SO_SNDBUFFORCE": true, + "SO_SNDLOWAT": true, + "SO_SNDTIMEO": true, + "SO_SPLICE": true, + "SO_TIMESTAMP": true, + "SO_TIMESTAMPING": true, + "SO_TIMESTAMPNS": true, + "SO_TIMESTAMP_MONOTONIC": true, + "SO_TYPE": true, + "SO_UPCALLCLOSEWAIT": true, + "SO_UPDATE_ACCEPT_CONTEXT": true, + "SO_UPDATE_CONNECT_CONTEXT": true, + "SO_USELOOPBACK": true, + "SO_USER_COOKIE": true, + "SO_VENDOR": true, + "SO_WANTMORE": true, + "SO_WANTOOBFLAG": true, + "SSLExtraCertChainPolicyPara": true, + "STANDARD_RIGHTS_ALL": true, + "STANDARD_RIGHTS_EXECUTE": true, + "STANDARD_RIGHTS_READ": true, + "STANDARD_RIGHTS_REQUIRED": true, + "STANDARD_RIGHTS_WRITE": true, + "STARTF_USESHOWWINDOW": true, + "STARTF_USESTDHANDLES": true, + "STD_ERROR_HANDLE": true, + "STD_INPUT_HANDLE": true, + "STD_OUTPUT_HANDLE": true, + "SUBLANG_ENGLISH_US": true, + "SW_FORCEMINIMIZE": true, + "SW_HIDE": true, + "SW_MAXIMIZE": true, + "SW_MINIMIZE": true, + "SW_NORMAL": true, + "SW_RESTORE": true, + "SW_SHOW": true, + "SW_SHOWDEFAULT": true, + "SW_SHOWMAXIMIZED": true, + "SW_SHOWMINIMIZED": true, + "SW_SHOWMINNOACTIVE": true, + "SW_SHOWNA": true, + "SW_SHOWNOACTIVATE": true, + "SW_SHOWNORMAL": true, + "SYMBOLIC_LINK_FLAG_DIRECTORY": true, + "SYNCHRONIZE": true, + "SYSCTL_VERSION": true, + "SYSCTL_VERS_0": true, + "SYSCTL_VERS_1": true, + "SYSCTL_VERS_MASK": true, + "SYS_ABORT2": true, + "SYS_ACCEPT": true, + "SYS_ACCEPT4": true, + "SYS_ACCEPT_NOCANCEL": true, + "SYS_ACCESS": true, + "SYS_ACCESS_EXTENDED": true, + "SYS_ACCT": true, + "SYS_ADD_KEY": true, + "SYS_ADD_PROFIL": true, + "SYS_ADJFREQ": true, + "SYS_ADJTIME": true, + "SYS_ADJTIMEX": true, + "SYS_AFS_SYSCALL": true, + "SYS_AIO_CANCEL": true, + "SYS_AIO_ERROR": true, + "SYS_AIO_FSYNC": true, + "SYS_AIO_READ": true, + "SYS_AIO_RETURN": true, + "SYS_AIO_SUSPEND": true, + "SYS_AIO_SUSPEND_NOCANCEL": true, + "SYS_AIO_WRITE": true, + "SYS_ALARM": true, + "SYS_ARCH_PRCTL": true, + "SYS_ARM_FADVISE64_64": true, + "SYS_ARM_SYNC_FILE_RANGE": true, + "SYS_ATGETMSG": true, + "SYS_ATPGETREQ": true, + "SYS_ATPGETRSP": true, + "SYS_ATPSNDREQ": true, + "SYS_ATPSNDRSP": true, + "SYS_ATPUTMSG": true, + "SYS_ATSOCKET": true, + "SYS_AUDIT": true, + "SYS_AUDITCTL": true, + "SYS_AUDITON": true, + "SYS_AUDIT_SESSION_JOIN": true, + "SYS_AUDIT_SESSION_PORT": true, + "SYS_AUDIT_SESSION_SELF": true, + "SYS_BDFLUSH": true, + "SYS_BIND": true, + "SYS_BINDAT": true, + "SYS_BREAK": true, + "SYS_BRK": true, + "SYS_BSDTHREAD_CREATE": true, + "SYS_BSDTHREAD_REGISTER": true, + "SYS_BSDTHREAD_TERMINATE": true, + "SYS_CAPGET": true, + "SYS_CAPSET": true, + "SYS_CAP_ENTER": true, + "SYS_CAP_FCNTLS_GET": true, + "SYS_CAP_FCNTLS_LIMIT": true, + "SYS_CAP_GETMODE": true, + "SYS_CAP_GETRIGHTS": true, + "SYS_CAP_IOCTLS_GET": true, + "SYS_CAP_IOCTLS_LIMIT": true, + "SYS_CAP_NEW": true, + "SYS_CAP_RIGHTS_GET": true, + "SYS_CAP_RIGHTS_LIMIT": true, + "SYS_CHDIR": true, + "SYS_CHFLAGS": true, + "SYS_CHFLAGSAT": true, + "SYS_CHMOD": true, + "SYS_CHMOD_EXTENDED": true, + "SYS_CHOWN": true, + "SYS_CHOWN32": true, + "SYS_CHROOT": true, + "SYS_CHUD": true, + "SYS_CLOCK_ADJTIME": true, + "SYS_CLOCK_GETCPUCLOCKID2": true, + "SYS_CLOCK_GETRES": true, + "SYS_CLOCK_GETTIME": true, + "SYS_CLOCK_NANOSLEEP": true, + "SYS_CLOCK_SETTIME": true, + "SYS_CLONE": true, + "SYS_CLOSE": true, + "SYS_CLOSEFROM": true, + "SYS_CLOSE_NOCANCEL": true, + "SYS_CONNECT": true, + "SYS_CONNECTAT": true, + "SYS_CONNECT_NOCANCEL": true, + "SYS_COPYFILE": true, + "SYS_CPUSET": true, + "SYS_CPUSET_GETAFFINITY": true, + "SYS_CPUSET_GETID": true, + "SYS_CPUSET_SETAFFINITY": true, + "SYS_CPUSET_SETID": true, + "SYS_CREAT": true, + "SYS_CREATE_MODULE": true, + "SYS_CSOPS": true, + "SYS_DELETE": true, + "SYS_DELETE_MODULE": true, + "SYS_DUP": true, + "SYS_DUP2": true, + "SYS_DUP3": true, + "SYS_EACCESS": true, + "SYS_EPOLL_CREATE": true, + "SYS_EPOLL_CREATE1": true, + "SYS_EPOLL_CTL": true, + "SYS_EPOLL_CTL_OLD": true, + "SYS_EPOLL_PWAIT": true, + "SYS_EPOLL_WAIT": true, + "SYS_EPOLL_WAIT_OLD": true, + "SYS_EVENTFD": true, + "SYS_EVENTFD2": true, + "SYS_EXCHANGEDATA": true, + "SYS_EXECVE": true, + "SYS_EXIT": true, + "SYS_EXIT_GROUP": true, + "SYS_EXTATTRCTL": true, + "SYS_EXTATTR_DELETE_FD": true, + "SYS_EXTATTR_DELETE_FILE": true, + "SYS_EXTATTR_DELETE_LINK": true, + "SYS_EXTATTR_GET_FD": true, + "SYS_EXTATTR_GET_FILE": true, + "SYS_EXTATTR_GET_LINK": true, + "SYS_EXTATTR_LIST_FD": true, + "SYS_EXTATTR_LIST_FILE": true, + "SYS_EXTATTR_LIST_LINK": true, + "SYS_EXTATTR_SET_FD": true, + "SYS_EXTATTR_SET_FILE": true, + "SYS_EXTATTR_SET_LINK": true, + "SYS_FACCESSAT": true, + "SYS_FADVISE64": true, + "SYS_FADVISE64_64": true, + "SYS_FALLOCATE": true, + "SYS_FANOTIFY_INIT": true, + "SYS_FANOTIFY_MARK": true, + "SYS_FCHDIR": true, + "SYS_FCHFLAGS": true, + "SYS_FCHMOD": true, + "SYS_FCHMODAT": true, + "SYS_FCHMOD_EXTENDED": true, + "SYS_FCHOWN": true, + "SYS_FCHOWN32": true, + "SYS_FCHOWNAT": true, + "SYS_FCHROOT": true, + "SYS_FCNTL": true, + "SYS_FCNTL64": true, + "SYS_FCNTL_NOCANCEL": true, + "SYS_FDATASYNC": true, + "SYS_FEXECVE": true, + "SYS_FFCLOCK_GETCOUNTER": true, + "SYS_FFCLOCK_GETESTIMATE": true, + "SYS_FFCLOCK_SETESTIMATE": true, + "SYS_FFSCTL": true, + "SYS_FGETATTRLIST": true, + "SYS_FGETXATTR": true, + "SYS_FHOPEN": true, + "SYS_FHSTAT": true, + "SYS_FHSTATFS": true, + "SYS_FILEPORT_MAKEFD": true, + "SYS_FILEPORT_MAKEPORT": true, + "SYS_FKTRACE": true, + "SYS_FLISTXATTR": true, + "SYS_FLOCK": true, + "SYS_FORK": true, + "SYS_FPATHCONF": true, + "SYS_FREEBSD6_FTRUNCATE": true, + "SYS_FREEBSD6_LSEEK": true, + "SYS_FREEBSD6_MMAP": true, + "SYS_FREEBSD6_PREAD": true, + "SYS_FREEBSD6_PWRITE": true, + "SYS_FREEBSD6_TRUNCATE": true, + "SYS_FREMOVEXATTR": true, + "SYS_FSCTL": true, + "SYS_FSETATTRLIST": true, + "SYS_FSETXATTR": true, + "SYS_FSGETPATH": true, + "SYS_FSTAT": true, + "SYS_FSTAT64": true, + "SYS_FSTAT64_EXTENDED": true, + "SYS_FSTATAT": true, + "SYS_FSTATAT64": true, + "SYS_FSTATFS": true, + "SYS_FSTATFS64": true, + "SYS_FSTATV": true, + "SYS_FSTATVFS1": true, + "SYS_FSTAT_EXTENDED": true, + "SYS_FSYNC": true, + "SYS_FSYNC_NOCANCEL": true, + "SYS_FSYNC_RANGE": true, + "SYS_FTIME": true, + "SYS_FTRUNCATE": true, + "SYS_FTRUNCATE64": true, + "SYS_FUTEX": true, + "SYS_FUTIMENS": true, + "SYS_FUTIMES": true, + "SYS_FUTIMESAT": true, + "SYS_GETATTRLIST": true, + "SYS_GETAUDIT": true, + "SYS_GETAUDIT_ADDR": true, + "SYS_GETAUID": true, + "SYS_GETCONTEXT": true, + "SYS_GETCPU": true, + "SYS_GETCWD": true, + "SYS_GETDENTS": true, + "SYS_GETDENTS64": true, + "SYS_GETDIRENTRIES": true, + "SYS_GETDIRENTRIES64": true, + "SYS_GETDIRENTRIESATTR": true, + "SYS_GETDTABLECOUNT": true, + "SYS_GETDTABLESIZE": true, + "SYS_GETEGID": true, + "SYS_GETEGID32": true, + "SYS_GETEUID": true, + "SYS_GETEUID32": true, + "SYS_GETFH": true, + "SYS_GETFSSTAT": true, + "SYS_GETFSSTAT64": true, + "SYS_GETGID": true, + "SYS_GETGID32": true, + "SYS_GETGROUPS": true, + "SYS_GETGROUPS32": true, + "SYS_GETHOSTUUID": true, + "SYS_GETITIMER": true, + "SYS_GETLCID": true, + "SYS_GETLOGIN": true, + "SYS_GETLOGINCLASS": true, + "SYS_GETPEERNAME": true, + "SYS_GETPGID": true, + "SYS_GETPGRP": true, + "SYS_GETPID": true, + "SYS_GETPMSG": true, + "SYS_GETPPID": true, + "SYS_GETPRIORITY": true, + "SYS_GETRESGID": true, + "SYS_GETRESGID32": true, + "SYS_GETRESUID": true, + "SYS_GETRESUID32": true, + "SYS_GETRLIMIT": true, + "SYS_GETRTABLE": true, + "SYS_GETRUSAGE": true, + "SYS_GETSGROUPS": true, + "SYS_GETSID": true, + "SYS_GETSOCKNAME": true, + "SYS_GETSOCKOPT": true, + "SYS_GETTHRID": true, + "SYS_GETTID": true, + "SYS_GETTIMEOFDAY": true, + "SYS_GETUID": true, + "SYS_GETUID32": true, + "SYS_GETVFSSTAT": true, + "SYS_GETWGROUPS": true, + "SYS_GETXATTR": true, + "SYS_GET_KERNEL_SYMS": true, + "SYS_GET_MEMPOLICY": true, + "SYS_GET_ROBUST_LIST": true, + "SYS_GET_THREAD_AREA": true, + "SYS_GTTY": true, + "SYS_IDENTITYSVC": true, + "SYS_IDLE": true, + "SYS_INITGROUPS": true, + "SYS_INIT_MODULE": true, + "SYS_INOTIFY_ADD_WATCH": true, + "SYS_INOTIFY_INIT": true, + "SYS_INOTIFY_INIT1": true, + "SYS_INOTIFY_RM_WATCH": true, + "SYS_IOCTL": true, + "SYS_IOPERM": true, + "SYS_IOPL": true, + "SYS_IOPOLICYSYS": true, + "SYS_IOPRIO_GET": true, + "SYS_IOPRIO_SET": true, + "SYS_IO_CANCEL": true, + "SYS_IO_DESTROY": true, + "SYS_IO_GETEVENTS": true, + "SYS_IO_SETUP": true, + "SYS_IO_SUBMIT": true, + "SYS_IPC": true, + "SYS_ISSETUGID": true, + "SYS_JAIL": true, + "SYS_JAIL_ATTACH": true, + "SYS_JAIL_GET": true, + "SYS_JAIL_REMOVE": true, + "SYS_JAIL_SET": true, + "SYS_KDEBUG_TRACE": true, + "SYS_KENV": true, + "SYS_KEVENT": true, + "SYS_KEVENT64": true, + "SYS_KEXEC_LOAD": true, + "SYS_KEYCTL": true, + "SYS_KILL": true, + "SYS_KLDFIND": true, + "SYS_KLDFIRSTMOD": true, + "SYS_KLDLOAD": true, + "SYS_KLDNEXT": true, + "SYS_KLDSTAT": true, + "SYS_KLDSYM": true, + "SYS_KLDUNLOAD": true, + "SYS_KLDUNLOADF": true, + "SYS_KQUEUE": true, + "SYS_KQUEUE1": true, + "SYS_KTIMER_CREATE": true, + "SYS_KTIMER_DELETE": true, + "SYS_KTIMER_GETOVERRUN": true, + "SYS_KTIMER_GETTIME": true, + "SYS_KTIMER_SETTIME": true, + "SYS_KTRACE": true, + "SYS_LCHFLAGS": true, + "SYS_LCHMOD": true, + "SYS_LCHOWN": true, + "SYS_LCHOWN32": true, + "SYS_LGETFH": true, + "SYS_LGETXATTR": true, + "SYS_LINK": true, + "SYS_LINKAT": true, + "SYS_LIO_LISTIO": true, + "SYS_LISTEN": true, + "SYS_LISTXATTR": true, + "SYS_LLISTXATTR": true, + "SYS_LOCK": true, + "SYS_LOOKUP_DCOOKIE": true, + "SYS_LPATHCONF": true, + "SYS_LREMOVEXATTR": true, + "SYS_LSEEK": true, + "SYS_LSETXATTR": true, + "SYS_LSTAT": true, + "SYS_LSTAT64": true, + "SYS_LSTAT64_EXTENDED": true, + "SYS_LSTATV": true, + "SYS_LSTAT_EXTENDED": true, + "SYS_LUTIMES": true, + "SYS_MAC_SYSCALL": true, + "SYS_MADVISE": true, + "SYS_MADVISE1": true, + "SYS_MAXSYSCALL": true, + "SYS_MBIND": true, + "SYS_MIGRATE_PAGES": true, + "SYS_MINCORE": true, + "SYS_MINHERIT": true, + "SYS_MKCOMPLEX": true, + "SYS_MKDIR": true, + "SYS_MKDIRAT": true, + "SYS_MKDIR_EXTENDED": true, + "SYS_MKFIFO": true, + "SYS_MKFIFOAT": true, + "SYS_MKFIFO_EXTENDED": true, + "SYS_MKNOD": true, + "SYS_MKNODAT": true, + "SYS_MLOCK": true, + "SYS_MLOCKALL": true, + "SYS_MMAP": true, + "SYS_MMAP2": true, + "SYS_MODCTL": true, + "SYS_MODFIND": true, + "SYS_MODFNEXT": true, + "SYS_MODIFY_LDT": true, + "SYS_MODNEXT": true, + "SYS_MODSTAT": true, + "SYS_MODWATCH": true, + "SYS_MOUNT": true, + "SYS_MOVE_PAGES": true, + "SYS_MPROTECT": true, + "SYS_MPX": true, + "SYS_MQUERY": true, + "SYS_MQ_GETSETATTR": true, + "SYS_MQ_NOTIFY": true, + "SYS_MQ_OPEN": true, + "SYS_MQ_TIMEDRECEIVE": true, + "SYS_MQ_TIMEDSEND": true, + "SYS_MQ_UNLINK": true, + "SYS_MREMAP": true, + "SYS_MSGCTL": true, + "SYS_MSGGET": true, + "SYS_MSGRCV": true, + "SYS_MSGRCV_NOCANCEL": true, + "SYS_MSGSND": true, + "SYS_MSGSND_NOCANCEL": true, + "SYS_MSGSYS": true, + "SYS_MSYNC": true, + "SYS_MSYNC_NOCANCEL": true, + "SYS_MUNLOCK": true, + "SYS_MUNLOCKALL": true, + "SYS_MUNMAP": true, + "SYS_NAME_TO_HANDLE_AT": true, + "SYS_NANOSLEEP": true, + "SYS_NEWFSTATAT": true, + "SYS_NFSCLNT": true, + "SYS_NFSSERVCTL": true, + "SYS_NFSSVC": true, + "SYS_NFSTAT": true, + "SYS_NICE": true, + "SYS_NLSTAT": true, + "SYS_NMOUNT": true, + "SYS_NSTAT": true, + "SYS_NTP_ADJTIME": true, + "SYS_NTP_GETTIME": true, + "SYS_OABI_SYSCALL_BASE": true, + "SYS_OBREAK": true, + "SYS_OLDFSTAT": true, + "SYS_OLDLSTAT": true, + "SYS_OLDOLDUNAME": true, + "SYS_OLDSTAT": true, + "SYS_OLDUNAME": true, + "SYS_OPEN": true, + "SYS_OPENAT": true, + "SYS_OPENBSD_POLL": true, + "SYS_OPEN_BY_HANDLE_AT": true, + "SYS_OPEN_EXTENDED": true, + "SYS_OPEN_NOCANCEL": true, + "SYS_OVADVISE": true, + "SYS_PACCEPT": true, + "SYS_PATHCONF": true, + "SYS_PAUSE": true, + "SYS_PCICONFIG_IOBASE": true, + "SYS_PCICONFIG_READ": true, + "SYS_PCICONFIG_WRITE": true, + "SYS_PDFORK": true, + "SYS_PDGETPID": true, + "SYS_PDKILL": true, + "SYS_PERF_EVENT_OPEN": true, + "SYS_PERSONALITY": true, + "SYS_PID_HIBERNATE": true, + "SYS_PID_RESUME": true, + "SYS_PID_SHUTDOWN_SOCKETS": true, + "SYS_PID_SUSPEND": true, + "SYS_PIPE": true, + "SYS_PIPE2": true, + "SYS_PIVOT_ROOT": true, + "SYS_PMC_CONTROL": true, + "SYS_PMC_GET_INFO": true, + "SYS_POLL": true, + "SYS_POLLTS": true, + "SYS_POLL_NOCANCEL": true, + "SYS_POSIX_FADVISE": true, + "SYS_POSIX_FALLOCATE": true, + "SYS_POSIX_OPENPT": true, + "SYS_POSIX_SPAWN": true, + "SYS_PPOLL": true, + "SYS_PRCTL": true, + "SYS_PREAD": true, + "SYS_PREAD64": true, + "SYS_PREADV": true, + "SYS_PREAD_NOCANCEL": true, + "SYS_PRLIMIT64": true, + "SYS_PROCCTL": true, + "SYS_PROCESS_POLICY": true, + "SYS_PROCESS_VM_READV": true, + "SYS_PROCESS_VM_WRITEV": true, + "SYS_PROC_INFO": true, + "SYS_PROF": true, + "SYS_PROFIL": true, + "SYS_PSELECT": true, + "SYS_PSELECT6": true, + "SYS_PSET_ASSIGN": true, + "SYS_PSET_CREATE": true, + "SYS_PSET_DESTROY": true, + "SYS_PSYNCH_CVBROAD": true, + "SYS_PSYNCH_CVCLRPREPOST": true, + "SYS_PSYNCH_CVSIGNAL": true, + "SYS_PSYNCH_CVWAIT": true, + "SYS_PSYNCH_MUTEXDROP": true, + "SYS_PSYNCH_MUTEXWAIT": true, + "SYS_PSYNCH_RW_DOWNGRADE": true, + "SYS_PSYNCH_RW_LONGRDLOCK": true, + "SYS_PSYNCH_RW_RDLOCK": true, + "SYS_PSYNCH_RW_UNLOCK": true, + "SYS_PSYNCH_RW_UNLOCK2": true, + "SYS_PSYNCH_RW_UPGRADE": true, + "SYS_PSYNCH_RW_WRLOCK": true, + "SYS_PSYNCH_RW_YIELDWRLOCK": true, + "SYS_PTRACE": true, + "SYS_PUTPMSG": true, + "SYS_PWRITE": true, + "SYS_PWRITE64": true, + "SYS_PWRITEV": true, + "SYS_PWRITE_NOCANCEL": true, + "SYS_QUERY_MODULE": true, + "SYS_QUOTACTL": true, + "SYS_RASCTL": true, + "SYS_RCTL_ADD_RULE": true, + "SYS_RCTL_GET_LIMITS": true, + "SYS_RCTL_GET_RACCT": true, + "SYS_RCTL_GET_RULES": true, + "SYS_RCTL_REMOVE_RULE": true, + "SYS_READ": true, + "SYS_READAHEAD": true, + "SYS_READDIR": true, + "SYS_READLINK": true, + "SYS_READLINKAT": true, + "SYS_READV": true, + "SYS_READV_NOCANCEL": true, + "SYS_READ_NOCANCEL": true, + "SYS_REBOOT": true, + "SYS_RECV": true, + "SYS_RECVFROM": true, + "SYS_RECVFROM_NOCANCEL": true, + "SYS_RECVMMSG": true, + "SYS_RECVMSG": true, + "SYS_RECVMSG_NOCANCEL": true, + "SYS_REMAP_FILE_PAGES": true, + "SYS_REMOVEXATTR": true, + "SYS_RENAME": true, + "SYS_RENAMEAT": true, + "SYS_REQUEST_KEY": true, + "SYS_RESTART_SYSCALL": true, + "SYS_REVOKE": true, + "SYS_RFORK": true, + "SYS_RMDIR": true, + "SYS_RTPRIO": true, + "SYS_RTPRIO_THREAD": true, + "SYS_RT_SIGACTION": true, + "SYS_RT_SIGPENDING": true, + "SYS_RT_SIGPROCMASK": true, + "SYS_RT_SIGQUEUEINFO": true, + "SYS_RT_SIGRETURN": true, + "SYS_RT_SIGSUSPEND": true, + "SYS_RT_SIGTIMEDWAIT": true, + "SYS_RT_TGSIGQUEUEINFO": true, + "SYS_SBRK": true, + "SYS_SCHED_GETAFFINITY": true, + "SYS_SCHED_GETPARAM": true, + "SYS_SCHED_GETSCHEDULER": true, + "SYS_SCHED_GET_PRIORITY_MAX": true, + "SYS_SCHED_GET_PRIORITY_MIN": true, + "SYS_SCHED_RR_GET_INTERVAL": true, + "SYS_SCHED_SETAFFINITY": true, + "SYS_SCHED_SETPARAM": true, + "SYS_SCHED_SETSCHEDULER": true, + "SYS_SCHED_YIELD": true, + "SYS_SCTP_GENERIC_RECVMSG": true, + "SYS_SCTP_GENERIC_SENDMSG": true, + "SYS_SCTP_GENERIC_SENDMSG_IOV": true, + "SYS_SCTP_PEELOFF": true, + "SYS_SEARCHFS": true, + "SYS_SECURITY": true, + "SYS_SELECT": true, + "SYS_SELECT_NOCANCEL": true, + "SYS_SEMCONFIG": true, + "SYS_SEMCTL": true, + "SYS_SEMGET": true, + "SYS_SEMOP": true, + "SYS_SEMSYS": true, + "SYS_SEMTIMEDOP": true, + "SYS_SEM_CLOSE": true, + "SYS_SEM_DESTROY": true, + "SYS_SEM_GETVALUE": true, + "SYS_SEM_INIT": true, + "SYS_SEM_OPEN": true, + "SYS_SEM_POST": true, + "SYS_SEM_TRYWAIT": true, + "SYS_SEM_UNLINK": true, + "SYS_SEM_WAIT": true, + "SYS_SEM_WAIT_NOCANCEL": true, + "SYS_SEND": true, + "SYS_SENDFILE": true, + "SYS_SENDFILE64": true, + "SYS_SENDMMSG": true, + "SYS_SENDMSG": true, + "SYS_SENDMSG_NOCANCEL": true, + "SYS_SENDTO": true, + "SYS_SENDTO_NOCANCEL": true, + "SYS_SETATTRLIST": true, + "SYS_SETAUDIT": true, + "SYS_SETAUDIT_ADDR": true, + "SYS_SETAUID": true, + "SYS_SETCONTEXT": true, + "SYS_SETDOMAINNAME": true, + "SYS_SETEGID": true, + "SYS_SETEUID": true, + "SYS_SETFIB": true, + "SYS_SETFSGID": true, + "SYS_SETFSGID32": true, + "SYS_SETFSUID": true, + "SYS_SETFSUID32": true, + "SYS_SETGID": true, + "SYS_SETGID32": true, + "SYS_SETGROUPS": true, + "SYS_SETGROUPS32": true, + "SYS_SETHOSTNAME": true, + "SYS_SETITIMER": true, + "SYS_SETLCID": true, + "SYS_SETLOGIN": true, + "SYS_SETLOGINCLASS": true, + "SYS_SETNS": true, + "SYS_SETPGID": true, + "SYS_SETPRIORITY": true, + "SYS_SETPRIVEXEC": true, + "SYS_SETREGID": true, + "SYS_SETREGID32": true, + "SYS_SETRESGID": true, + "SYS_SETRESGID32": true, + "SYS_SETRESUID": true, + "SYS_SETRESUID32": true, + "SYS_SETREUID": true, + "SYS_SETREUID32": true, + "SYS_SETRLIMIT": true, + "SYS_SETRTABLE": true, + "SYS_SETSGROUPS": true, + "SYS_SETSID": true, + "SYS_SETSOCKOPT": true, + "SYS_SETTID": true, + "SYS_SETTID_WITH_PID": true, + "SYS_SETTIMEOFDAY": true, + "SYS_SETUID": true, + "SYS_SETUID32": true, + "SYS_SETWGROUPS": true, + "SYS_SETXATTR": true, + "SYS_SET_MEMPOLICY": true, + "SYS_SET_ROBUST_LIST": true, + "SYS_SET_THREAD_AREA": true, + "SYS_SET_TID_ADDRESS": true, + "SYS_SGETMASK": true, + "SYS_SHARED_REGION_CHECK_NP": true, + "SYS_SHARED_REGION_MAP_AND_SLIDE_NP": true, + "SYS_SHMAT": true, + "SYS_SHMCTL": true, + "SYS_SHMDT": true, + "SYS_SHMGET": true, + "SYS_SHMSYS": true, + "SYS_SHM_OPEN": true, + "SYS_SHM_UNLINK": true, + "SYS_SHUTDOWN": true, + "SYS_SIGACTION": true, + "SYS_SIGALTSTACK": true, + "SYS_SIGNAL": true, + "SYS_SIGNALFD": true, + "SYS_SIGNALFD4": true, + "SYS_SIGPENDING": true, + "SYS_SIGPROCMASK": true, + "SYS_SIGQUEUE": true, + "SYS_SIGQUEUEINFO": true, + "SYS_SIGRETURN": true, + "SYS_SIGSUSPEND": true, + "SYS_SIGSUSPEND_NOCANCEL": true, + "SYS_SIGTIMEDWAIT": true, + "SYS_SIGWAIT": true, + "SYS_SIGWAITINFO": true, + "SYS_SOCKET": true, + "SYS_SOCKETCALL": true, + "SYS_SOCKETPAIR": true, + "SYS_SPLICE": true, + "SYS_SSETMASK": true, + "SYS_SSTK": true, + "SYS_STACK_SNAPSHOT": true, + "SYS_STAT": true, + "SYS_STAT64": true, + "SYS_STAT64_EXTENDED": true, + "SYS_STATFS": true, + "SYS_STATFS64": true, + "SYS_STATV": true, + "SYS_STATVFS1": true, + "SYS_STAT_EXTENDED": true, + "SYS_STIME": true, + "SYS_STTY": true, + "SYS_SWAPCONTEXT": true, + "SYS_SWAPCTL": true, + "SYS_SWAPOFF": true, + "SYS_SWAPON": true, + "SYS_SYMLINK": true, + "SYS_SYMLINKAT": true, + "SYS_SYNC": true, + "SYS_SYNCFS": true, + "SYS_SYNC_FILE_RANGE": true, + "SYS_SYSARCH": true, + "SYS_SYSCALL": true, + "SYS_SYSCALL_BASE": true, + "SYS_SYSFS": true, + "SYS_SYSINFO": true, + "SYS_SYSLOG": true, + "SYS_TEE": true, + "SYS_TGKILL": true, + "SYS_THREAD_SELFID": true, + "SYS_THR_CREATE": true, + "SYS_THR_EXIT": true, + "SYS_THR_KILL": true, + "SYS_THR_KILL2": true, + "SYS_THR_NEW": true, + "SYS_THR_SELF": true, + "SYS_THR_SET_NAME": true, + "SYS_THR_SUSPEND": true, + "SYS_THR_WAKE": true, + "SYS_TIME": true, + "SYS_TIMERFD_CREATE": true, + "SYS_TIMERFD_GETTIME": true, + "SYS_TIMERFD_SETTIME": true, + "SYS_TIMER_CREATE": true, + "SYS_TIMER_DELETE": true, + "SYS_TIMER_GETOVERRUN": true, + "SYS_TIMER_GETTIME": true, + "SYS_TIMER_SETTIME": true, + "SYS_TIMES": true, + "SYS_TKILL": true, + "SYS_TRUNCATE": true, + "SYS_TRUNCATE64": true, + "SYS_TUXCALL": true, + "SYS_UGETRLIMIT": true, + "SYS_ULIMIT": true, + "SYS_UMASK": true, + "SYS_UMASK_EXTENDED": true, + "SYS_UMOUNT": true, + "SYS_UMOUNT2": true, + "SYS_UNAME": true, + "SYS_UNDELETE": true, + "SYS_UNLINK": true, + "SYS_UNLINKAT": true, + "SYS_UNMOUNT": true, + "SYS_UNSHARE": true, + "SYS_USELIB": true, + "SYS_USTAT": true, + "SYS_UTIME": true, + "SYS_UTIMENSAT": true, + "SYS_UTIMES": true, + "SYS_UTRACE": true, + "SYS_UUIDGEN": true, + "SYS_VADVISE": true, + "SYS_VFORK": true, + "SYS_VHANGUP": true, + "SYS_VM86": true, + "SYS_VM86OLD": true, + "SYS_VMSPLICE": true, + "SYS_VM_PRESSURE_MONITOR": true, + "SYS_VSERVER": true, + "SYS_WAIT4": true, + "SYS_WAIT4_NOCANCEL": true, + "SYS_WAIT6": true, + "SYS_WAITEVENT": true, + "SYS_WAITID": true, + "SYS_WAITID_NOCANCEL": true, + "SYS_WAITPID": true, + "SYS_WATCHEVENT": true, + "SYS_WORKQ_KERNRETURN": true, + "SYS_WORKQ_OPEN": true, + "SYS_WRITE": true, + "SYS_WRITEV": true, + "SYS_WRITEV_NOCANCEL": true, + "SYS_WRITE_NOCANCEL": true, + "SYS_YIELD": true, + "SYS__LLSEEK": true, + "SYS__LWP_CONTINUE": true, + "SYS__LWP_CREATE": true, + "SYS__LWP_CTL": true, + "SYS__LWP_DETACH": true, + "SYS__LWP_EXIT": true, + "SYS__LWP_GETNAME": true, + "SYS__LWP_GETPRIVATE": true, + "SYS__LWP_KILL": true, + "SYS__LWP_PARK": true, + "SYS__LWP_SELF": true, + "SYS__LWP_SETNAME": true, + "SYS__LWP_SETPRIVATE": true, + "SYS__LWP_SUSPEND": true, + "SYS__LWP_UNPARK": true, + "SYS__LWP_UNPARK_ALL": true, + "SYS__LWP_WAIT": true, + "SYS__LWP_WAKEUP": true, + "SYS__NEWSELECT": true, + "SYS__PSET_BIND": true, + "SYS__SCHED_GETAFFINITY": true, + "SYS__SCHED_GETPARAM": true, + "SYS__SCHED_SETAFFINITY": true, + "SYS__SCHED_SETPARAM": true, + "SYS__SYSCTL": true, + "SYS__UMTX_LOCK": true, + "SYS__UMTX_OP": true, + "SYS__UMTX_UNLOCK": true, + "SYS___ACL_ACLCHECK_FD": true, + "SYS___ACL_ACLCHECK_FILE": true, + "SYS___ACL_ACLCHECK_LINK": true, + "SYS___ACL_DELETE_FD": true, + "SYS___ACL_DELETE_FILE": true, + "SYS___ACL_DELETE_LINK": true, + "SYS___ACL_GET_FD": true, + "SYS___ACL_GET_FILE": true, + "SYS___ACL_GET_LINK": true, + "SYS___ACL_SET_FD": true, + "SYS___ACL_SET_FILE": true, + "SYS___ACL_SET_LINK": true, + "SYS___CLONE": true, + "SYS___DISABLE_THREADSIGNAL": true, + "SYS___GETCWD": true, + "SYS___GETLOGIN": true, + "SYS___GET_TCB": true, + "SYS___MAC_EXECVE": true, + "SYS___MAC_GETFSSTAT": true, + "SYS___MAC_GET_FD": true, + "SYS___MAC_GET_FILE": true, + "SYS___MAC_GET_LCID": true, + "SYS___MAC_GET_LCTX": true, + "SYS___MAC_GET_LINK": true, + "SYS___MAC_GET_MOUNT": true, + "SYS___MAC_GET_PID": true, + "SYS___MAC_GET_PROC": true, + "SYS___MAC_MOUNT": true, + "SYS___MAC_SET_FD": true, + "SYS___MAC_SET_FILE": true, + "SYS___MAC_SET_LCTX": true, + "SYS___MAC_SET_LINK": true, + "SYS___MAC_SET_PROC": true, + "SYS___MAC_SYSCALL": true, + "SYS___OLD_SEMWAIT_SIGNAL": true, + "SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL": true, + "SYS___POSIX_CHOWN": true, + "SYS___POSIX_FCHOWN": true, + "SYS___POSIX_LCHOWN": true, + "SYS___POSIX_RENAME": true, + "SYS___PTHREAD_CANCELED": true, + "SYS___PTHREAD_CHDIR": true, + "SYS___PTHREAD_FCHDIR": true, + "SYS___PTHREAD_KILL": true, + "SYS___PTHREAD_MARKCANCEL": true, + "SYS___PTHREAD_SIGMASK": true, + "SYS___QUOTACTL": true, + "SYS___SEMCTL": true, + "SYS___SEMWAIT_SIGNAL": true, + "SYS___SEMWAIT_SIGNAL_NOCANCEL": true, + "SYS___SETLOGIN": true, + "SYS___SETUGID": true, + "SYS___SET_TCB": true, + "SYS___SIGACTION_SIGTRAMP": true, + "SYS___SIGTIMEDWAIT": true, + "SYS___SIGWAIT": true, + "SYS___SIGWAIT_NOCANCEL": true, + "SYS___SYSCTL": true, + "SYS___TFORK": true, + "SYS___THREXIT": true, + "SYS___THRSIGDIVERT": true, + "SYS___THRSLEEP": true, + "SYS___THRWAKEUP": true, + "S_ARCH1": true, + "S_ARCH2": true, + "S_BLKSIZE": true, + "S_IEXEC": true, + "S_IFBLK": true, + "S_IFCHR": true, + "S_IFDIR": true, + "S_IFIFO": true, + "S_IFLNK": true, + "S_IFMT": true, + "S_IFREG": true, + "S_IFSOCK": true, + "S_IFWHT": true, + "S_IREAD": true, + "S_IRGRP": true, + "S_IROTH": true, + "S_IRUSR": true, + "S_IRWXG": true, + "S_IRWXO": true, + "S_IRWXU": true, + "S_ISGID": true, + "S_ISTXT": true, + "S_ISUID": true, + "S_ISVTX": true, + "S_IWGRP": true, + "S_IWOTH": true, + "S_IWRITE": true, + "S_IWUSR": true, + "S_IXGRP": true, + "S_IXOTH": true, + "S_IXUSR": true, + "S_LOGIN_SET": true, + "SecurityAttributes": true, + "Seek": true, + "Select": true, + "Sendfile": true, + "Sendmsg": true, + "SendmsgN": true, + "Sendto": true, + "Servent": true, + "SetBpf": true, + "SetBpfBuflen": true, + "SetBpfDatalink": true, + "SetBpfHeadercmpl": true, + "SetBpfImmediate": true, + "SetBpfInterface": true, + "SetBpfPromisc": true, + "SetBpfTimeout": true, + "SetCurrentDirectory": true, + "SetEndOfFile": true, + "SetEnvironmentVariable": true, + "SetFileAttributes": true, + "SetFileCompletionNotificationModes": true, + "SetFilePointer": true, + "SetFileTime": true, + "SetHandleInformation": true, + "SetKevent": true, + "SetLsfPromisc": true, + "SetNonblock": true, + "Setdomainname": true, + "Setegid": true, + "Setenv": true, + "Seteuid": true, + "Setfsgid": true, + "Setfsuid": true, + "Setgid": true, + "Setgroups": true, + "Sethostname": true, + "Setlogin": true, + "Setpgid": true, + "Setpriority": true, + "Setprivexec": true, + "Setregid": true, + "Setresgid": true, + "Setresuid": true, + "Setreuid": true, + "Setrlimit": true, + "Setsid": true, + "Setsockopt": true, + "SetsockoptByte": true, + "SetsockoptICMPv6Filter": true, + "SetsockoptIPMreq": true, + "SetsockoptIPMreqn": true, + "SetsockoptIPv6Mreq": true, + "SetsockoptInet4Addr": true, + "SetsockoptInt": true, + "SetsockoptLinger": true, + "SetsockoptString": true, + "SetsockoptTimeval": true, + "Settimeofday": true, + "Setuid": true, + "Setxattr": true, + "Shutdown": true, + "SidTypeAlias": true, + "SidTypeComputer": true, + "SidTypeDeletedAccount": true, + "SidTypeDomain": true, + "SidTypeGroup": true, + "SidTypeInvalid": true, + "SidTypeLabel": true, + "SidTypeUnknown": true, + "SidTypeUser": true, + "SidTypeWellKnownGroup": true, + "Signal": true, + "SizeofBpfHdr": true, + "SizeofBpfInsn": true, + "SizeofBpfProgram": true, + "SizeofBpfStat": true, + "SizeofBpfVersion": true, + "SizeofBpfZbuf": true, + "SizeofBpfZbufHeader": true, + "SizeofCmsghdr": true, + "SizeofICMPv6Filter": true, + "SizeofIPMreq": true, + "SizeofIPMreqn": true, + "SizeofIPv6MTUInfo": true, + "SizeofIPv6Mreq": true, + "SizeofIfAddrmsg": true, + "SizeofIfAnnounceMsghdr": true, + "SizeofIfData": true, + "SizeofIfInfomsg": true, + "SizeofIfMsghdr": true, + "SizeofIfaMsghdr": true, + "SizeofIfmaMsghdr": true, + "SizeofIfmaMsghdr2": true, + "SizeofInet4Pktinfo": true, + "SizeofInet6Pktinfo": true, + "SizeofInotifyEvent": true, + "SizeofLinger": true, + "SizeofMsghdr": true, + "SizeofNlAttr": true, + "SizeofNlMsgerr": true, + "SizeofNlMsghdr": true, + "SizeofRtAttr": true, + "SizeofRtGenmsg": true, + "SizeofRtMetrics": true, + "SizeofRtMsg": true, + "SizeofRtMsghdr": true, + "SizeofRtNexthop": true, + "SizeofSockFilter": true, + "SizeofSockFprog": true, + "SizeofSockaddrAny": true, + "SizeofSockaddrDatalink": true, + "SizeofSockaddrInet4": true, + "SizeofSockaddrInet6": true, + "SizeofSockaddrLinklayer": true, + "SizeofSockaddrNetlink": true, + "SizeofSockaddrUnix": true, + "SizeofTCPInfo": true, + "SizeofUcred": true, + "SlicePtrFromStrings": true, + "SockFilter": true, + "SockFprog": true, + "SockaddrDatalink": true, + "SockaddrGen": true, + "SockaddrInet4": true, + "SockaddrInet6": true, + "SockaddrLinklayer": true, + "SockaddrNetlink": true, + "SockaddrUnix": true, + "Socket": true, + "SocketControlMessage": true, + "SocketDisableIPv6": true, + "Socketpair": true, + "Splice": true, + "StartProcess": true, + "StartupInfo": true, + "Stat": true, + "Stat_t": true, + "Statfs": true, + "Statfs_t": true, + "Stderr": true, + "Stdin": true, + "Stdout": true, + "StringBytePtr": true, + "StringByteSlice": true, + "StringSlicePtr": true, + "StringToSid": true, + "StringToUTF16": true, + "StringToUTF16Ptr": true, + "Symlink": true, + "Sync": true, + "SyncFileRange": true, + "SysProcAttr": true, + "SysProcIDMap": true, + "Syscall": true, + "Syscall12": true, + "Syscall15": true, + "Syscall18": true, + "Syscall6": true, + "Syscall9": true, + "Sysctl": true, + "SysctlUint32": true, + "Sysctlnode": true, + "Sysinfo": true, + "Sysinfo_t": true, + "Systemtime": true, + "TCGETS": true, + "TCIFLUSH": true, + "TCIOFLUSH": true, + "TCOFLUSH": true, + "TCPInfo": true, + "TCPKeepalive": true, + "TCP_CA_NAME_MAX": true, + "TCP_CONGCTL": true, + "TCP_CONGESTION": true, + "TCP_CONNECTIONTIMEOUT": true, + "TCP_CORK": true, + "TCP_DEFER_ACCEPT": true, + "TCP_INFO": true, + "TCP_KEEPALIVE": true, + "TCP_KEEPCNT": true, + "TCP_KEEPIDLE": true, + "TCP_KEEPINIT": true, + "TCP_KEEPINTVL": true, + "TCP_LINGER2": true, + "TCP_MAXBURST": true, + "TCP_MAXHLEN": true, + "TCP_MAXOLEN": true, + "TCP_MAXSEG": true, + "TCP_MAXWIN": true, + "TCP_MAX_SACK": true, + "TCP_MAX_WINSHIFT": true, + "TCP_MD5SIG": true, + "TCP_MD5SIG_MAXKEYLEN": true, + "TCP_MINMSS": true, + "TCP_MINMSSOVERLOAD": true, + "TCP_MSS": true, + "TCP_NODELAY": true, + "TCP_NOOPT": true, + "TCP_NOPUSH": true, + "TCP_NSTATES": true, + "TCP_QUICKACK": true, + "TCP_RXT_CONNDROPTIME": true, + "TCP_RXT_FINDROP": true, + "TCP_SACK_ENABLE": true, + "TCP_SYNCNT": true, + "TCP_VENDOR": true, + "TCP_WINDOW_CLAMP": true, + "TCSAFLUSH": true, + "TCSETS": true, + "TF_DISCONNECT": true, + "TF_REUSE_SOCKET": true, + "TF_USE_DEFAULT_WORKER": true, + "TF_USE_KERNEL_APC": true, + "TF_USE_SYSTEM_THREAD": true, + "TF_WRITE_BEHIND": true, + "TH32CS_INHERIT": true, + "TH32CS_SNAPALL": true, + "TH32CS_SNAPHEAPLIST": true, + "TH32CS_SNAPMODULE": true, + "TH32CS_SNAPMODULE32": true, + "TH32CS_SNAPPROCESS": true, + "TH32CS_SNAPTHREAD": true, + "TIME_ZONE_ID_DAYLIGHT": true, + "TIME_ZONE_ID_STANDARD": true, + "TIME_ZONE_ID_UNKNOWN": true, + "TIOCCBRK": true, + "TIOCCDTR": true, + "TIOCCONS": true, + "TIOCDCDTIMESTAMP": true, + "TIOCDRAIN": true, + "TIOCDSIMICROCODE": true, + "TIOCEXCL": true, + "TIOCEXT": true, + "TIOCFLAG_CDTRCTS": true, + "TIOCFLAG_CLOCAL": true, + "TIOCFLAG_CRTSCTS": true, + "TIOCFLAG_MDMBUF": true, + "TIOCFLAG_PPS": true, + "TIOCFLAG_SOFTCAR": true, + "TIOCFLUSH": true, + "TIOCGDEV": true, + "TIOCGDRAINWAIT": true, + "TIOCGETA": true, + "TIOCGETD": true, + "TIOCGFLAGS": true, + "TIOCGICOUNT": true, + "TIOCGLCKTRMIOS": true, + "TIOCGLINED": true, + "TIOCGPGRP": true, + "TIOCGPTN": true, + "TIOCGQSIZE": true, + "TIOCGRANTPT": true, + "TIOCGRS485": true, + "TIOCGSERIAL": true, + "TIOCGSID": true, + "TIOCGSIZE": true, + "TIOCGSOFTCAR": true, + "TIOCGTSTAMP": true, + "TIOCGWINSZ": true, + "TIOCINQ": true, + "TIOCIXOFF": true, + "TIOCIXON": true, + "TIOCLINUX": true, + "TIOCMBIC": true, + "TIOCMBIS": true, + "TIOCMGDTRWAIT": true, + "TIOCMGET": true, + "TIOCMIWAIT": true, + "TIOCMODG": true, + "TIOCMODS": true, + "TIOCMSDTRWAIT": true, + "TIOCMSET": true, + "TIOCM_CAR": true, + "TIOCM_CD": true, + "TIOCM_CTS": true, + "TIOCM_DCD": true, + "TIOCM_DSR": true, + "TIOCM_DTR": true, + "TIOCM_LE": true, + "TIOCM_RI": true, + "TIOCM_RNG": true, + "TIOCM_RTS": true, + "TIOCM_SR": true, + "TIOCM_ST": true, + "TIOCNOTTY": true, + "TIOCNXCL": true, + "TIOCOUTQ": true, + "TIOCPKT": true, + "TIOCPKT_DATA": true, + "TIOCPKT_DOSTOP": true, + "TIOCPKT_FLUSHREAD": true, + "TIOCPKT_FLUSHWRITE": true, + "TIOCPKT_IOCTL": true, + "TIOCPKT_NOSTOP": true, + "TIOCPKT_START": true, + "TIOCPKT_STOP": true, + "TIOCPTMASTER": true, + "TIOCPTMGET": true, + "TIOCPTSNAME": true, + "TIOCPTYGNAME": true, + "TIOCPTYGRANT": true, + "TIOCPTYUNLK": true, + "TIOCRCVFRAME": true, + "TIOCREMOTE": true, + "TIOCSBRK": true, + "TIOCSCONS": true, + "TIOCSCTTY": true, + "TIOCSDRAINWAIT": true, + "TIOCSDTR": true, + "TIOCSERCONFIG": true, + "TIOCSERGETLSR": true, + "TIOCSERGETMULTI": true, + "TIOCSERGSTRUCT": true, + "TIOCSERGWILD": true, + "TIOCSERSETMULTI": true, + "TIOCSERSWILD": true, + "TIOCSER_TEMT": true, + "TIOCSETA": true, + "TIOCSETAF": true, + "TIOCSETAW": true, + "TIOCSETD": true, + "TIOCSFLAGS": true, + "TIOCSIG": true, + "TIOCSLCKTRMIOS": true, + "TIOCSLINED": true, + "TIOCSPGRP": true, + "TIOCSPTLCK": true, + "TIOCSQSIZE": true, + "TIOCSRS485": true, + "TIOCSSERIAL": true, + "TIOCSSIZE": true, + "TIOCSSOFTCAR": true, + "TIOCSTART": true, + "TIOCSTAT": true, + "TIOCSTI": true, + "TIOCSTOP": true, + "TIOCSTSTAMP": true, + "TIOCSWINSZ": true, + "TIOCTIMESTAMP": true, + "TIOCUCNTL": true, + "TIOCVHANGUP": true, + "TIOCXMTFRAME": true, + "TOKEN_ADJUST_DEFAULT": true, + "TOKEN_ADJUST_GROUPS": true, + "TOKEN_ADJUST_PRIVILEGES": true, + "TOKEN_ADJUST_SESSIONID": true, + "TOKEN_ALL_ACCESS": true, + "TOKEN_ASSIGN_PRIMARY": true, + "TOKEN_DUPLICATE": true, + "TOKEN_EXECUTE": true, + "TOKEN_IMPERSONATE": true, + "TOKEN_QUERY": true, + "TOKEN_QUERY_SOURCE": true, + "TOKEN_READ": true, + "TOKEN_WRITE": true, + "TOSTOP": true, + "TRUNCATE_EXISTING": true, + "TUNATTACHFILTER": true, + "TUNDETACHFILTER": true, + "TUNGETFEATURES": true, + "TUNGETIFF": true, + "TUNGETSNDBUF": true, + "TUNGETVNETHDRSZ": true, + "TUNSETDEBUG": true, + "TUNSETGROUP": true, + "TUNSETIFF": true, + "TUNSETLINK": true, + "TUNSETNOCSUM": true, + "TUNSETOFFLOAD": true, + "TUNSETOWNER": true, + "TUNSETPERSIST": true, + "TUNSETSNDBUF": true, + "TUNSETTXFILTER": true, + "TUNSETVNETHDRSZ": true, + "Tee": true, + "TerminateProcess": true, + "Termios": true, + "Tgkill": true, + "Time": true, + "Time_t": true, + "Times": true, + "Timespec": true, + "TimespecToNsec": true, + "Timeval": true, + "Timeval32": true, + "TimevalToNsec": true, + "Timex": true, + "Timezoneinformation": true, + "Tms": true, + "Token": true, + "TokenAccessInformation": true, + "TokenAuditPolicy": true, + "TokenDefaultDacl": true, + "TokenElevation": true, + "TokenElevationType": true, + "TokenGroups": true, + "TokenGroupsAndPrivileges": true, + "TokenHasRestrictions": true, + "TokenImpersonationLevel": true, + "TokenIntegrityLevel": true, + "TokenLinkedToken": true, + "TokenLogonSid": true, + "TokenMandatoryPolicy": true, + "TokenOrigin": true, + "TokenOwner": true, + "TokenPrimaryGroup": true, + "TokenPrivileges": true, + "TokenRestrictedSids": true, + "TokenSandBoxInert": true, + "TokenSessionId": true, + "TokenSessionReference": true, + "TokenSource": true, + "TokenStatistics": true, + "TokenType": true, + "TokenUIAccess": true, + "TokenUser": true, + "TokenVirtualizationAllowed": true, + "TokenVirtualizationEnabled": true, + "Tokenprimarygroup": true, + "Tokenuser": true, + "TranslateAccountName": true, + "TranslateName": true, + "TransmitFile": true, + "TransmitFileBuffers": true, + "Truncate": true, + "UNIX_PATH_MAX": true, + "USAGE_MATCH_TYPE_AND": true, + "USAGE_MATCH_TYPE_OR": true, + "UTF16FromString": true, + "UTF16PtrFromString": true, + "UTF16ToString": true, + "Ucred": true, + "Umask": true, + "Uname": true, + "Undelete": true, + "UnixCredentials": true, + "UnixRights": true, + "Unlink": true, + "Unlinkat": true, + "UnmapViewOfFile": true, + "Unmount": true, + "Unsetenv": true, + "Unshare": true, + "UserInfo10": true, + "Ustat": true, + "Ustat_t": true, + "Utimbuf": true, + "Utime": true, + "Utimes": true, + "UtimesNano": true, + "Utsname": true, + "VDISCARD": true, + "VDSUSP": true, + "VEOF": true, + "VEOL": true, + "VEOL2": true, + "VERASE": true, + "VERASE2": true, + "VINTR": true, + "VKILL": true, + "VLNEXT": true, + "VMIN": true, + "VQUIT": true, + "VREPRINT": true, + "VSTART": true, + "VSTATUS": true, + "VSTOP": true, + "VSUSP": true, + "VSWTC": true, + "VT0": true, + "VT1": true, + "VTDLY": true, + "VTIME": true, + "VWERASE": true, + "VirtualLock": true, + "VirtualUnlock": true, + "WAIT_ABANDONED": true, + "WAIT_FAILED": true, + "WAIT_OBJECT_0": true, + "WAIT_TIMEOUT": true, + "WALL": true, + "WALLSIG": true, + "WALTSIG": true, + "WCLONE": true, + "WCONTINUED": true, + "WCOREFLAG": true, + "WEXITED": true, + "WLINUXCLONE": true, + "WNOHANG": true, + "WNOTHREAD": true, + "WNOWAIT": true, + "WNOZOMBIE": true, + "WOPTSCHECKED": true, + "WORDSIZE": true, + "WSABuf": true, + "WSACleanup": true, + "WSADESCRIPTION_LEN": true, + "WSAData": true, + "WSAEACCES": true, + "WSAECONNABORTED": true, + "WSAECONNRESET": true, + "WSAEnumProtocols": true, + "WSAID_CONNECTEX": true, + "WSAIoctl": true, + "WSAPROTOCOL_LEN": true, + "WSAProtocolChain": true, + "WSAProtocolInfo": true, + "WSARecv": true, + "WSARecvFrom": true, + "WSASYS_STATUS_LEN": true, + "WSASend": true, + "WSASendTo": true, + "WSASendto": true, + "WSAStartup": true, + "WSTOPPED": true, + "WTRAPPED": true, + "WUNTRACED": true, + "Wait4": true, + "WaitForSingleObject": true, + "WaitStatus": true, + "Win32FileAttributeData": true, + "Win32finddata": true, + "Write": true, + "WriteConsole": true, + "WriteFile": true, + "X509_ASN_ENCODING": true, + "XCASE": true, + "XP1_CONNECTIONLESS": true, + "XP1_CONNECT_DATA": true, + "XP1_DISCONNECT_DATA": true, + "XP1_EXPEDITED_DATA": true, + "XP1_GRACEFUL_CLOSE": true, + "XP1_GUARANTEED_DELIVERY": true, + "XP1_GUARANTEED_ORDER": true, + "XP1_IFS_HANDLES": true, + "XP1_MESSAGE_ORIENTED": true, + "XP1_MULTIPOINT_CONTROL_PLANE": true, + "XP1_MULTIPOINT_DATA_PLANE": true, + "XP1_PARTIAL_MESSAGE": true, + "XP1_PSEUDO_STREAM": true, + "XP1_QOS_SUPPORTED": true, + "XP1_SAN_SUPPORT_SDP": true, + "XP1_SUPPORT_BROADCAST": true, + "XP1_SUPPORT_MULTIPOINT": true, + "XP1_UNI_RECV": true, + "XP1_UNI_SEND": true, + }, + "syscall/js": map[string]bool{ + "Error": true, + "Func": true, + "FuncOf": true, + "Global": true, + "Null": true, + "Type": true, + "TypeBoolean": true, + "TypeFunction": true, + "TypeNull": true, + "TypeNumber": true, + "TypeObject": true, + "TypeString": true, + "TypeSymbol": true, + "TypeUndefined": true, + "TypedArray": true, + "TypedArrayOf": true, + "Undefined": true, + "Value": true, + "ValueError": true, + "ValueOf": true, + "Wrapper": true, + }, + "testing": map[string]bool{ + "AllocsPerRun": true, + "B": true, + "Benchmark": true, + "BenchmarkResult": true, + "Cover": true, + "CoverBlock": true, + "CoverMode": true, + "Coverage": true, + "InternalBenchmark": true, + "InternalExample": true, + "InternalTest": true, + "M": true, + "Main": true, + "MainStart": true, + "PB": true, + "RegisterCover": true, + "RunBenchmarks": true, + "RunExamples": true, + "RunTests": true, + "Short": true, + "T": true, + "Verbose": true, + }, + "testing/iotest": map[string]bool{ + "DataErrReader": true, + "ErrTimeout": true, + "HalfReader": true, + "NewReadLogger": true, + "NewWriteLogger": true, + "OneByteReader": true, + "TimeoutReader": true, + "TruncateWriter": true, + }, + "testing/quick": map[string]bool{ + "Check": true, + "CheckEqual": true, + "CheckEqualError": true, + "CheckError": true, + "Config": true, + "Generator": true, + "SetupError": true, + "Value": true, + }, + "text/scanner": map[string]bool{ + "Char": true, + "Comment": true, + "EOF": true, + "Float": true, + "GoTokens": true, + "GoWhitespace": true, + "Ident": true, + "Int": true, + "Position": true, + "RawString": true, + "ScanChars": true, + "ScanComments": true, + "ScanFloats": true, + "ScanIdents": true, + "ScanInts": true, + "ScanRawStrings": true, + "ScanStrings": true, + "Scanner": true, + "SkipComments": true, + "String": true, + "TokenString": true, + }, + "text/tabwriter": map[string]bool{ + "AlignRight": true, + "Debug": true, + "DiscardEmptyColumns": true, + "Escape": true, + "FilterHTML": true, + "NewWriter": true, + "StripEscape": true, + "TabIndent": true, + "Writer": true, + }, + "text/template": map[string]bool{ + "ExecError": true, + "FuncMap": true, + "HTMLEscape": true, + "HTMLEscapeString": true, + "HTMLEscaper": true, + "IsTrue": true, + "JSEscape": true, + "JSEscapeString": true, + "JSEscaper": true, + "Must": true, + "New": true, + "ParseFiles": true, + "ParseGlob": true, + "Template": true, + "URLQueryEscaper": true, + }, + "text/template/parse": map[string]bool{ + "ActionNode": true, + "BoolNode": true, + "BranchNode": true, + "ChainNode": true, + "CommandNode": true, + "DotNode": true, + "FieldNode": true, + "IdentifierNode": true, + "IfNode": true, + "IsEmptyTree": true, + "ListNode": true, + "New": true, + "NewIdentifier": true, + "NilNode": true, + "Node": true, + "NodeAction": true, + "NodeBool": true, + "NodeChain": true, + "NodeCommand": true, + "NodeDot": true, + "NodeField": true, + "NodeIdentifier": true, + "NodeIf": true, + "NodeList": true, + "NodeNil": true, + "NodeNumber": true, + "NodePipe": true, + "NodeRange": true, + "NodeString": true, + "NodeTemplate": true, + "NodeText": true, + "NodeType": true, + "NodeVariable": true, + "NodeWith": true, + "NumberNode": true, + "Parse": true, + "PipeNode": true, + "Pos": true, + "RangeNode": true, + "StringNode": true, + "TemplateNode": true, + "TextNode": true, + "Tree": true, + "VariableNode": true, + "WithNode": true, + }, + "time": map[string]bool{ + "ANSIC": true, + "After": true, + "AfterFunc": true, + "April": true, + "August": true, + "Date": true, + "December": true, + "Duration": true, + "February": true, + "FixedZone": true, + "Friday": true, + "Hour": true, + "January": true, + "July": true, + "June": true, + "Kitchen": true, + "LoadLocation": true, + "LoadLocationFromTZData": true, + "Local": true, + "Location": true, + "March": true, + "May": true, + "Microsecond": true, + "Millisecond": true, + "Minute": true, + "Monday": true, + "Month": true, + "Nanosecond": true, + "NewTicker": true, + "NewTimer": true, + "November": true, + "Now": true, + "October": true, + "Parse": true, + "ParseDuration": true, + "ParseError": true, + "ParseInLocation": true, + "RFC1123": true, + "RFC1123Z": true, + "RFC3339": true, + "RFC3339Nano": true, + "RFC822": true, + "RFC822Z": true, + "RFC850": true, + "RubyDate": true, + "Saturday": true, + "Second": true, + "September": true, + "Since": true, + "Sleep": true, + "Stamp": true, + "StampMicro": true, + "StampMilli": true, + "StampNano": true, + "Sunday": true, + "Thursday": true, + "Tick": true, + "Ticker": true, + "Time": true, + "Timer": true, + "Tuesday": true, + "UTC": true, + "Unix": true, + "UnixDate": true, + "Until": true, + "Wednesday": true, + "Weekday": true, + }, + "unicode": map[string]bool{ + "ASCII_Hex_Digit": true, + "Adlam": true, + "Ahom": true, + "Anatolian_Hieroglyphs": true, + "Arabic": true, + "Armenian": true, + "Avestan": true, + "AzeriCase": true, + "Balinese": true, + "Bamum": true, + "Bassa_Vah": true, + "Batak": true, + "Bengali": true, + "Bhaiksuki": true, + "Bidi_Control": true, + "Bopomofo": true, + "Brahmi": true, + "Braille": true, + "Buginese": true, + "Buhid": true, + "C": true, + "Canadian_Aboriginal": true, + "Carian": true, + "CaseRange": true, + "CaseRanges": true, + "Categories": true, + "Caucasian_Albanian": true, + "Cc": true, + "Cf": true, + "Chakma": true, + "Cham": true, + "Cherokee": true, + "Co": true, + "Common": true, + "Coptic": true, + "Cs": true, + "Cuneiform": true, + "Cypriot": true, + "Cyrillic": true, + "Dash": true, + "Deprecated": true, + "Deseret": true, + "Devanagari": true, + "Diacritic": true, + "Digit": true, + "Duployan": true, + "Egyptian_Hieroglyphs": true, + "Elbasan": true, + "Ethiopic": true, + "Extender": true, + "FoldCategory": true, + "FoldScript": true, + "Georgian": true, + "Glagolitic": true, + "Gothic": true, + "Grantha": true, + "GraphicRanges": true, + "Greek": true, + "Gujarati": true, + "Gurmukhi": true, + "Han": true, + "Hangul": true, + "Hanunoo": true, + "Hatran": true, + "Hebrew": true, + "Hex_Digit": true, + "Hiragana": true, + "Hyphen": true, + "IDS_Binary_Operator": true, + "IDS_Trinary_Operator": true, + "Ideographic": true, + "Imperial_Aramaic": true, + "In": true, + "Inherited": true, + "Inscriptional_Pahlavi": true, + "Inscriptional_Parthian": true, + "Is": true, + "IsControl": true, + "IsDigit": true, + "IsGraphic": true, + "IsLetter": true, + "IsLower": true, + "IsMark": true, + "IsNumber": true, + "IsOneOf": true, + "IsPrint": true, + "IsPunct": true, + "IsSpace": true, + "IsSymbol": true, + "IsTitle": true, + "IsUpper": true, + "Javanese": true, + "Join_Control": true, + "Kaithi": true, + "Kannada": true, + "Katakana": true, + "Kayah_Li": true, + "Kharoshthi": true, + "Khmer": true, + "Khojki": true, + "Khudawadi": true, + "L": true, + "Lao": true, + "Latin": true, + "Lepcha": true, + "Letter": true, + "Limbu": true, + "Linear_A": true, + "Linear_B": true, + "Lisu": true, + "Ll": true, + "Lm": true, + "Lo": true, + "Logical_Order_Exception": true, + "Lower": true, + "LowerCase": true, + "Lt": true, + "Lu": true, + "Lycian": true, + "Lydian": true, + "M": true, + "Mahajani": true, + "Malayalam": true, + "Mandaic": true, + "Manichaean": true, + "Marchen": true, + "Mark": true, + "Masaram_Gondi": true, + "MaxASCII": true, + "MaxCase": true, + "MaxLatin1": true, + "MaxRune": true, + "Mc": true, + "Me": true, + "Meetei_Mayek": true, + "Mende_Kikakui": true, + "Meroitic_Cursive": true, + "Meroitic_Hieroglyphs": true, + "Miao": true, + "Mn": true, + "Modi": true, + "Mongolian": true, + "Mro": true, + "Multani": true, + "Myanmar": true, + "N": true, + "Nabataean": true, + "Nd": true, + "New_Tai_Lue": true, + "Newa": true, + "Nko": true, + "Nl": true, + "No": true, + "Noncharacter_Code_Point": true, + "Number": true, + "Nushu": true, + "Ogham": true, + "Ol_Chiki": true, + "Old_Hungarian": true, + "Old_Italic": true, + "Old_North_Arabian": true, + "Old_Permic": true, + "Old_Persian": true, + "Old_South_Arabian": true, + "Old_Turkic": true, + "Oriya": true, + "Osage": true, + "Osmanya": true, + "Other": true, + "Other_Alphabetic": true, + "Other_Default_Ignorable_Code_Point": true, + "Other_Grapheme_Extend": true, + "Other_ID_Continue": true, + "Other_ID_Start": true, + "Other_Lowercase": true, + "Other_Math": true, + "Other_Uppercase": true, + "P": true, + "Pahawh_Hmong": true, + "Palmyrene": true, + "Pattern_Syntax": true, + "Pattern_White_Space": true, + "Pau_Cin_Hau": true, + "Pc": true, + "Pd": true, + "Pe": true, + "Pf": true, + "Phags_Pa": true, + "Phoenician": true, + "Pi": true, + "Po": true, + "Prepended_Concatenation_Mark": true, + "PrintRanges": true, + "Properties": true, + "Ps": true, + "Psalter_Pahlavi": true, + "Punct": true, + "Quotation_Mark": true, + "Radical": true, + "Range16": true, + "Range32": true, + "RangeTable": true, + "Regional_Indicator": true, + "Rejang": true, + "ReplacementChar": true, + "Runic": true, + "S": true, + "STerm": true, + "Samaritan": true, + "Saurashtra": true, + "Sc": true, + "Scripts": true, + "Sentence_Terminal": true, + "Sharada": true, + "Shavian": true, + "Siddham": true, + "SignWriting": true, + "SimpleFold": true, + "Sinhala": true, + "Sk": true, + "Sm": true, + "So": true, + "Soft_Dotted": true, + "Sora_Sompeng": true, + "Soyombo": true, + "Space": true, + "SpecialCase": true, + "Sundanese": true, + "Syloti_Nagri": true, + "Symbol": true, + "Syriac": true, + "Tagalog": true, + "Tagbanwa": true, + "Tai_Le": true, + "Tai_Tham": true, + "Tai_Viet": true, + "Takri": true, + "Tamil": true, + "Tangut": true, + "Telugu": true, + "Terminal_Punctuation": true, + "Thaana": true, + "Thai": true, + "Tibetan": true, + "Tifinagh": true, + "Tirhuta": true, + "Title": true, + "TitleCase": true, + "To": true, + "ToLower": true, + "ToTitle": true, + "ToUpper": true, + "TurkishCase": true, + "Ugaritic": true, + "Unified_Ideograph": true, + "Upper": true, + "UpperCase": true, + "UpperLower": true, + "Vai": true, + "Variation_Selector": true, + "Version": true, + "Warang_Citi": true, + "White_Space": true, + "Yi": true, + "Z": true, + "Zanabazar_Square": true, + "Zl": true, + "Zp": true, + "Zs": true, + }, + "unicode/utf16": map[string]bool{ + "Decode": true, + "DecodeRune": true, + "Encode": true, + "EncodeRune": true, + "IsSurrogate": true, + }, + "unicode/utf8": map[string]bool{ + "DecodeLastRune": true, + "DecodeLastRuneInString": true, + "DecodeRune": true, + "DecodeRuneInString": true, + "EncodeRune": true, + "FullRune": true, + "FullRuneInString": true, + "MaxRune": true, + "RuneCount": true, + "RuneCountInString": true, + "RuneError": true, + "RuneLen": true, + "RuneSelf": true, + "RuneStart": true, + "UTFMax": true, + "Valid": true, + "ValidRune": true, + "ValidString": true, + }, + "unsafe": map[string]bool{ + "Alignof": true, + "ArbitraryType": true, + "Offsetof": true, + "Pointer": true, + "Sizeof": true, + }, +} diff --git a/vendor/golang.org/x/tools/internal/module/module.go b/vendor/golang.org/x/tools/internal/module/module.go new file mode 100644 index 0000000000..9a4edb9dec --- /dev/null +++ b/vendor/golang.org/x/tools/internal/module/module.go @@ -0,0 +1,540 @@ +// 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" + + "golang.org/x/tools/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 || i == len(path) || 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 +} diff --git a/vendor/golang.org/x/tools/internal/semver/semver.go b/vendor/golang.org/x/tools/internal/semver/semver.go new file mode 100644 index 0000000000..4af7118e55 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/semver/semver.go @@ -0,0 +1,388 @@ +// 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:] +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d40ce668db..4df5dd666c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2,6 +2,9 @@ ## explicit github.com/Azure/go-ansiterm github.com/Azure/go-ansiterm/winterm +# github.com/BurntSushi/toml v0.3.1 +## explicit +github.com/BurntSushi/toml # github.com/Microsoft/go-winio v0.4.5 ## explicit github.com/Microsoft/go-winio @@ -192,15 +195,52 @@ github.com/fsouza/go-dockerclient/external/golang.org/x/sys/unix # github.com/ghodss/yaml v1.0.0 ## explicit github.com/ghodss/yaml +# github.com/gobuffalo/buffalo-plugins v1.11.0 +## explicit +github.com/gobuffalo/buffalo-plugins/plugins +github.com/gobuffalo/buffalo-plugins/plugins/plugdeps # github.com/gobuffalo/envy v1.6.12 ## explicit github.com/gobuffalo/envy +# github.com/gobuffalo/events v1.1.9 +## explicit +github.com/gobuffalo/events +# github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794 +## explicit +github.com/gobuffalo/flect +github.com/gobuffalo/flect/name +# github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5 +## explicit +github.com/gobuffalo/genny +github.com/gobuffalo/genny/movinglater/gotools +github.com/gobuffalo/genny/movinglater/gotools/goimports +github.com/gobuffalo/genny/movinglater/gotools/gomods +# github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c +## explicit +github.com/gobuffalo/logger +# github.com/gobuffalo/mapi v1.0.1 +## explicit +github.com/gobuffalo/mapi +# github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d +## explicit +github.com/gobuffalo/meta # github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687 ## explicit github.com/gobuffalo/packd # github.com/gobuffalo/packr v1.22.0 ## explicit github.com/gobuffalo/packr +github.com/gobuffalo/packr/builder +github.com/gobuffalo/packr/packr +github.com/gobuffalo/packr/packr/cmd +# github.com/gobuffalo/packr/v2 v2.0.0-rc.15 +## explicit +github.com/gobuffalo/packr/v2/file +github.com/gobuffalo/packr/v2/file/resolver +github.com/gobuffalo/packr/v2/file/resolver/encoding/hex +github.com/gobuffalo/packr/v2/jam/parser +github.com/gobuffalo/packr/v2/jam/store +github.com/gobuffalo/packr/v2/plog # github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f ## explicit github.com/gobuffalo/syncx @@ -283,6 +323,9 @@ github.com/headzoo/surf/util github.com/inconshreveable/go-update github.com/inconshreveable/go-update/internal/binarydist github.com/inconshreveable/go-update/internal/osext +# github.com/inconshreveable/mousetrap v1.0.0 +## explicit +github.com/inconshreveable/mousetrap # github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 ## explicit github.com/jehiah/go-strftime @@ -295,9 +338,21 @@ github.com/joho/godotenv # github.com/json-iterator/go v1.1.5 ## explicit github.com/json-iterator/go +# github.com/karrick/godirwalk v1.7.8 +## explicit +github.com/karrick/godirwalk # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 ## explicit github.com/kballard/go-shellquote +# github.com/konsorten/go-windows-terminal-sequences v1.0.3 +## explicit +github.com/konsorten/go-windows-terminal-sequences +# github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 +## explicit +github.com/markbates/oncer +# github.com/markbates/safe v1.0.1 +## explicit +github.com/markbates/safe # github.com/mattn/go-colorable v0.1.9 ## explicit; go 1.13 github.com/mattn/go-colorable @@ -355,6 +410,12 @@ github.com/segmentio/analytics-go # github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c ## explicit github.com/segmentio/backo-go +# github.com/sirupsen/logrus v1.6.0 +## explicit; go 1.13 +github.com/sirupsen/logrus +# github.com/spf13/cobra v1.0.0 +## explicit; go 1.12 +github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag @@ -406,6 +467,9 @@ golang.org/x/net/internal/iana golang.org/x/net/internal/socket golang.org/x/net/ipv4 golang.org/x/net/ipv6 +# golang.org/x/sync v0.0.0-20190423024810-112230192c58 +## explicit +golang.org/x/sync/errgroup # golang.org/x/sys v0.0.0-20220913153101-76c7481b5158 ## explicit; go 1.17 golang.org/x/sys/cpu @@ -425,6 +489,19 @@ golang.org/x/text/unicode/norm # golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 ## explicit golang.org/x/time/rate +# golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 +## explicit; go 1.11 +golang.org/x/tools/go/ast/astutil +golang.org/x/tools/go/gcexportdata +golang.org/x/tools/go/internal/gcimporter +golang.org/x/tools/go/internal/packagesdriver +golang.org/x/tools/go/packages +golang.org/x/tools/imports +golang.org/x/tools/internal/fastwalk +golang.org/x/tools/internal/gopathwalk +golang.org/x/tools/internal/imports +golang.org/x/tools/internal/module +golang.org/x/tools/internal/semver # gopkg.in/cheggaaa/pb.v1 v1.0.28 ## explicit gopkg.in/cheggaaa/pb.v1