mirror of
https://github.com/prometheus-community/postgres_exporter
synced 2025-04-01 22:48:15 +00:00
Update for Prometheus Community
Add standard Prometheus build setup * CircleCI config * Makefile * Go modules * Golang-CI Lint * promu config * Remove /vendor * Remove mage build * Update READMEs https://github.com/prometheus-community/postgres_exporter/issues/478 Signed-off-by: Ben Kochie <superq@gmail.com>
This commit is contained in:
parent
8531abac46
commit
b67b69acd3
57
.circleci/config.yml
Normal file
57
.circleci/config.yml
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
prometheus: prometheus/prometheus@0.8.0
|
||||
|
||||
executors:
|
||||
# This must match .promu.yml.
|
||||
golang:
|
||||
docker:
|
||||
- image: circleci/golang:1.15
|
||||
|
||||
jobs:
|
||||
test:
|
||||
executor: golang
|
||||
|
||||
steps:
|
||||
- prometheus/setup_environment
|
||||
- run: make
|
||||
- prometheus/store_artifact:
|
||||
file: postgres_exporter
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
postgres_exporter:
|
||||
jobs:
|
||||
- test:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- prometheus/build:
|
||||
name: build
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- prometheus/publish_master:
|
||||
context: org-context
|
||||
docker_hub_organization: prometheuscommunity
|
||||
quay_io_organization: prometheuscommunity
|
||||
requires:
|
||||
- test
|
||||
- build
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- prometheus/publish_release:
|
||||
context: org-context
|
||||
docker_hub_organization: prometheuscommunity
|
||||
quay_io_organization: prometheuscommunity
|
||||
requires:
|
||||
- test
|
||||
- build
|
||||
filters:
|
||||
tags:
|
||||
only: /^v.*/
|
||||
branches:
|
||||
ignore: /.*/
|
@ -1,2 +0,0 @@
|
||||
*
|
||||
!bin/
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@
|
||||
/.metrics.*.added
|
||||
/.metrics.*.removed
|
||||
/tools/src
|
||||
/vendor
|
||||
|
10
.golangci.yml
Normal file
10
.golangci.yml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: _test.go
|
||||
linters:
|
||||
- errcheck
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
exclude: scripts/errcheck_excludes.txt
|
19
.promu.yml
Normal file
19
.promu.yml
Normal file
@ -0,0 +1,19 @@
|
||||
go:
|
||||
# This must match .circle/config.yml.
|
||||
version: 1.15
|
||||
repository:
|
||||
path: github.com/prometheus-community/postgres_exporter
|
||||
build:
|
||||
binaries:
|
||||
- name: postgres_exporter
|
||||
path: ./cmd/postgres_exporter
|
||||
flags: -a -tags 'netgo static_build'
|
||||
ldflags: |
|
||||
-X github.com/prometheus/common/version.Version={{.Version}}
|
||||
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
||||
-X github.com/prometheus/common/version.Branch={{.Branch}}
|
||||
-X github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
|
||||
-X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
|
||||
tarball:
|
||||
files:
|
||||
- LICENSE
|
46
.travis.yml
46
.travis.yml
@ -1,46 +0,0 @@
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
language: go
|
||||
go:
|
||||
- '1.11'
|
||||
before_install:
|
||||
- go get -v github.com/mattn/goveralls
|
||||
- sudo wget -O /usr/local/bin/p2 https://github.com/wrouesnel/p2cli/releases/download/r4/p2
|
||||
&& sudo chmod +x /usr/local/bin/p2
|
||||
- sudo wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/1.9.0-rc4/docker-compose-Linux-x86_64
|
||||
&& sudo chmod +x /usr/local/bin/docker-compose
|
||||
- sudo apt-get update && sudo apt-get install postgresql-client-common
|
||||
script:
|
||||
- "./gh-assets-clone.sh"
|
||||
- go run mage.go -v all
|
||||
- "$HOME/gopath/bin/goveralls -coverprofile=cover.out -service=travis-ci"
|
||||
- go run mage.go docker
|
||||
after_success:
|
||||
- docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- if [ ! -z "$TRAVIS_TAG" ]; then docker tag wrouesnel/postgres_exporter:latest wrouesnel/postgres_exporter:$TRAVIS_TAG
|
||||
; docker push wrouesnel/postgres_exporter:$TRAVIS_TAG ; fi
|
||||
- if [ "$TRAVIS_BRANCH" == "master" ]; then docker push wrouesnel/postgres_exporter
|
||||
; fi
|
||||
- "./postgres-metrics-get-changes.sh .assets-branch/metriclists"
|
||||
- if [ "$TRAVIS_BRANCH" == "master" ]; then ./gh-metrics-push.sh ; fi
|
||||
env:
|
||||
global:
|
||||
- DOCKER_USER=wrouesnel
|
||||
- GIT_ASSETS_BRANCH=assets
|
||||
- secure: sl1d85bipYhHlHTZ4fwkWrZ07px+lPMQrKPaiyQ9i5tylQAcMqwDroK0pb5HIyIl6PEx72D5atQWnEqluA/0rFt3SxqxtvT+wj6CPmmZfh2fUSol7I07QzAsi95d7q0fg2mStDdfs134Uu+JjxGKEGRu2SL3Zq+LKpaNPtIZVBqrCYYAySLiEJx+DEOfwt1ktn/qHapV5d5FYdfd7trfV411NITyA8AGk6Gy0HztRDGbfcoLOsM+CnVi1p59uUL9ck/hL2DbsB44qDKeWQaruMLwWNDETu+EVwHlDEHGBPb+wdDALnW+Ts3CAUpuGXftHV35XLLbH7NXOnS6QiH938ycfPf3INY51lV7cL6bNtFWDKMAIcPf4wQO2ts4qFhuiUeFdo7qrC6uEI5Fy/sELBgWl4O2opVY3Tf8s8OO/DSb4Cxy6solKgaETkl6EcShaEj7H/Cn7vT0+SLKCpSQlvVQXDLGg6eZTyBA+OWNElE0UvWV7znxWBlke+9NARIl4FcB/SY4A6v1ztpandHWMjNLLxZyVxFEswfU9hvf0qL9SW38OJ5cIK8pvmH2QWG7Xg/j0B3o7SHMdsM+pcSwrzsM6OENgvxPNBb/DinmMyQKxTCVcVmMo7uIS89RIylvN79E8U6NagdFkiLfa3xEHq8zCzEkHi3bsLRvytgT2X0=
|
||||
- secure: 1JL8KcgkLueQ2DLL81UMYzIHX3qm1TjcO40QL2ZOfdirFWBshOiTwTXeWj5qZaGBzoVV5ezhyZaBY+t3/pObslm20ERce879hEw+TSnKN30wfBqNyv2r7rfsbKkXauultb8RNu9y/9XS0DCEyGdSTQh9UaCa4z6ulu39hffDddrGQjwW1P2gT3Npu1cDYd1iSO36rrA6yXjaoN8OW8U4znKVjOGnarxxFnXJkiYv2PfIrZA6BpL3d0syJtWDyr1G+B48oK9VK+fBV9K0G0E67fJvqB3ANXN3D41il3S+cs8Ulcd7hF+LWxpMsP2r1/XHYSDw3Iiz0QFKKzoyxNdipvdjAVDxrWylyLnmTBYzXk41kRv88mKVLBQM1dbzsLXYcsE2pgIZxxq9OHGZ5CUJ8t0oz5D9oXMUy4QOMQ36jZdvD048aB7DGp4EF2J7ILIhUZrHHErOlXotnsYvNMvamNwqB5Jg4NC+y5QHxERJ+HK5oPrLy+iCb2kmWatSB6vO5OeX/F7IRiqtZghJRddEeMdQ1a6H0GeV1BF7Hx8j3TPMJ66qSAb0RA1lQQCN4l+/YMEWmQD8amf1O5NY116waf+Co4qkvt3c4QctQOMwu3Ra7uLlp6GG61OmHhPTCGSv/LZp6CVtROLY5IltKv7qBzksjvXkO1SzhJOxi0JkZmg=
|
||||
branches:
|
||||
except:
|
||||
- assets
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: rwlge/Rs3wnWyfKRhD9fd5GviVe0foYUp20DY3AjKdDjhtwScA1EeR9QHOkB3raze52en0+KkpqlLCWbt3q4CRT7+ku1DNKhd6VWALdTZ1RPJYvNlU6CKJdRnWUJsECmSBsShXlbiYR8axqNVedzFPFGKzS9gYlFN6rr7pez/JZhxqucopZ6I+TkRHMELrFXyQK7/Y2bNRCLC4a+rGsjKeLLtYXbRXCmS0G4BSJEBRk7d69fIRzBApCMfrcLftgHzPuPth616yyUusQSCQYvaZ5tlwrPP8/E0wG3SVJVeDCMuDOSBZ9M6vNzR8W8VR/hxQamegn1OQgC5kNOaLZCTcJ5xguRouqb+FNFBqrd/Zi6vESo7RiVLULawzwxkh9sIPa3WZYDb3VK/Z/cpggUeR7wAu0S5ZYEvJHRefIZpqofZEHzDE3Blqp5yErz05e/zmjpd6HHK3f/UHmRRYfbulkvGT3aL/dlq5GcFvuxVC/vTL2VPvg9cGbqtf7PakC5IhoHpDs35tOyLxifOBLHvkwtGSxEfsCohIG8Hz2XFD83EsxgOiKSXVPLNd6yxjdqZj7OeAKFFU3bzGndnRbDIXaf987IN1imgUtP6wegfImoRStqxN4gEwwIMFsZCF86Ug4eLhlajLbWhudriDxDPBM/F9950aVxLwmWh9l5cRI=
|
||||
file_glob: true
|
||||
file: release/*
|
||||
on:
|
||||
tags: true
|
||||
branch: master
|
||||
repo: wrouesnel/postgres_exporter
|
20
Dockerfile
20
Dockerfile
@ -1,12 +1,12 @@
|
||||
FROM debian:10-slim
|
||||
RUN useradd -u 20001 postgres_exporter
|
||||
ARG ARCH="amd64"
|
||||
ARG OS="linux"
|
||||
FROM quay.io/prometheus/busybox-${OS}-${ARCH}:latest
|
||||
LABEL maintainer="The Prometheus Authors <prometheus-developers@googlegroups.com>"
|
||||
|
||||
USER postgres_exporter
|
||||
ARG ARCH="amd64"
|
||||
ARG OS="linux"
|
||||
COPY .build/${OS}-${ARCH}/postgres_exporter /bin/postgres_exporter
|
||||
|
||||
ARG binary
|
||||
|
||||
COPY $binary /postgres_exporter
|
||||
|
||||
EXPOSE 9187
|
||||
|
||||
ENTRYPOINT [ "/postgres_exporter" ]
|
||||
EXPOSE 9187
|
||||
USER nobody
|
||||
ENTRYPOINT [ "/bin/postgres_exporter" ]
|
||||
|
10
Makefile
Normal file
10
Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
# Ensure that 'all' is the default target otherwise it will be the first target from Makefile.common.
|
||||
all::
|
||||
|
||||
# Needs to be defined before including Makefile.common to auto-generate targets
|
||||
DOCKER_ARCHS ?= amd64 armv7 arm64 ppc64le
|
||||
DOCKER_REPO ?= prometheuscommunity
|
||||
|
||||
include Makefile.common
|
||||
|
||||
DOCKER_IMAGE_NAME ?= postgres-exporter
|
@ -69,12 +69,21 @@ else
|
||||
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
|
||||
endif
|
||||
|
||||
PROMU_VERSION ?= 0.4.0
|
||||
GOTEST := $(GO) test
|
||||
GOTEST_DIR :=
|
||||
ifneq ($(CIRCLE_JOB),)
|
||||
ifneq ($(shell which gotestsum),)
|
||||
GOTEST_DIR := test-results
|
||||
GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
|
||||
endif
|
||||
endif
|
||||
|
||||
PROMU_VERSION ?= 0.7.0
|
||||
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
|
||||
|
||||
GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT_OPTS ?=
|
||||
GOLANGCI_LINT_VERSION ?= v1.16.0
|
||||
GOLANGCI_LINT_VERSION ?= v1.36.0
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
|
||||
# windows isn't included here because of the path separator being different.
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
|
||||
@ -86,6 +95,8 @@ endif
|
||||
PREFIX ?= $(shell pwd)
|
||||
BIN_DIR ?= $(shell pwd)
|
||||
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
|
||||
DOCKERFILE_PATH ?= ./Dockerfile
|
||||
DOCKERBUILD_CONTEXT ?= ./
|
||||
DOCKER_REPO ?= prom
|
||||
|
||||
DOCKER_ARCHS ?= amd64
|
||||
@ -139,15 +150,29 @@ else
|
||||
$(GO) get $(GOOPTS) -t ./...
|
||||
endif
|
||||
|
||||
.PHONY: update-go-deps
|
||||
update-go-deps:
|
||||
@echo ">> updating Go dependencies"
|
||||
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
|
||||
$(GO) get $$m; \
|
||||
done
|
||||
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
|
||||
ifneq (,$(wildcard vendor))
|
||||
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
|
||||
endif
|
||||
|
||||
.PHONY: common-test-short
|
||||
common-test-short:
|
||||
common-test-short: $(GOTEST_DIR)
|
||||
@echo ">> running short tests"
|
||||
GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
|
||||
GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs)
|
||||
|
||||
.PHONY: common-test
|
||||
common-test:
|
||||
common-test: $(GOTEST_DIR)
|
||||
@echo ">> running all tests"
|
||||
GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
|
||||
GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)
|
||||
|
||||
$(GOTEST_DIR):
|
||||
@mkdir -p $@
|
||||
|
||||
.PHONY: common-format
|
||||
common-format:
|
||||
@ -199,7 +224,7 @@ endif
|
||||
.PHONY: common-build
|
||||
common-build: promu
|
||||
@echo ">> building binaries"
|
||||
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
|
||||
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)
|
||||
|
||||
.PHONY: common-tarball
|
||||
common-tarball: promu
|
||||
@ -210,19 +235,22 @@ common-tarball: promu
|
||||
common-docker: $(BUILD_DOCKER_ARCHS)
|
||||
$(BUILD_DOCKER_ARCHS): common-docker-%:
|
||||
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
|
||||
-f $(DOCKERFILE_PATH) \
|
||||
--build-arg ARCH="$*" \
|
||||
--build-arg OS="linux" \
|
||||
.
|
||||
$(DOCKERBUILD_CONTEXT)
|
||||
|
||||
.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
|
||||
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
|
||||
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
|
||||
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
|
||||
|
||||
DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
|
||||
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
|
||||
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
|
||||
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
|
||||
|
||||
.PHONY: common-docker-manifest
|
||||
common-docker-manifest:
|
||||
@ -247,7 +275,9 @@ proto:
|
||||
ifdef GOLANGCI_LINT
|
||||
$(GOLANGCI_LINT):
|
||||
mkdir -p $(FIRST_GOPATH)/bin
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
|
||||
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \
|
||||
| sed -e '/install -d/d' \
|
||||
| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
|
||||
endif
|
||||
|
||||
ifdef GOVENDOR
|
@ -3,7 +3,7 @@
|
||||
### When using postgres-exporter with Amazon Web Services' RDS, the
|
||||
rolname "rdsadmin" and datname "rdsadmin" must be excluded.
|
||||
|
||||
I had success running docker container 'wrouesnel/postgres_exporter:latest'
|
||||
I had success running docker container 'quay.io/prometheuscommunity/postgres-exporter:latest'
|
||||
with queries.yaml as the PG_EXPORTER_EXTEND_QUERY_PATH. errors
|
||||
mentioned in issue#335 appeared and I had to modify the
|
||||
'pg_stat_statements' query with the following:
|
||||
@ -24,7 +24,7 @@ Running postgres-exporter in a container like so:
|
||||
-e PG_EXPORTER_DISABLE_DEFAULT_METRICS=true \
|
||||
-e PG_EXPORTER_DISABLE_SETTINGS_METRICS=true \
|
||||
-e PG_EXPORTER_EXTEND_QUERY_PATH='/var/lib/postgresql/queries.yaml' \
|
||||
wrouesnel/postgres_exporter
|
||||
quay.io/prometheuscommunity/postgres-exporter
|
||||
```
|
||||
|
||||
### Expected changes to RDS:
|
||||
|
46
README.md
46
README.md
@ -1,7 +1,7 @@
|
||||
[](https://travis-ci.org/wrouesnel/postgres_exporter)
|
||||
[](https://coveralls.io/github/wrouesnel/postgres_exporter?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/wrouesnel/postgres_exporter)
|
||||
[](https://hub.docker.com/r/wrouesnel/postgres_exporter/tags)
|
||||
[](https://circleci.com/gh/prometheus-community/postgres_exporter)
|
||||
[](https://coveralls.io/github/prometheus-community/postgres_exporter?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/prometheus-community/postgres_exporter)
|
||||
[](https://hub.docker.com/r/prometheuscommunity/postgres-exporter/tags)
|
||||
|
||||
# PostgreSQL Server Exporter
|
||||
|
||||
@ -15,31 +15,30 @@ This package is available for Docker:
|
||||
# Start an example database
|
||||
docker run --net=host -it --rm -e POSTGRES_PASSWORD=password postgres
|
||||
# Connect to it
|
||||
docker run --net=host -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" wrouesnel/postgres_exporter
|
||||
docker run \
|
||||
--net=host \
|
||||
-e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" \
|
||||
quay.io/prometheuscommunity/postgres-exporter
|
||||
```
|
||||
|
||||
## Building and running
|
||||
|
||||
The build system is based on [Mage](https://magefile.org)
|
||||
git clone https://github.com/prometheus-community/postgres_exporter.git
|
||||
cd postgres_exporter
|
||||
make build
|
||||
./postgres_exporter <flags>
|
||||
|
||||
The default make file behavior is to build the binary:
|
||||
```
|
||||
$ go get github.com/wrouesnel/postgres_exporter
|
||||
$ cd ${GOPATH-$HOME/go}/src/github.com/wrouesnel/postgres_exporter
|
||||
$ go run mage.go binary
|
||||
$ export DATA_SOURCE_NAME="postgresql://login:password@hostname:port/dbname"
|
||||
$ ./postgres_exporter <flags>
|
||||
```
|
||||
To build the Docker image:
|
||||
|
||||
To build the dockerfile, run `go run mage.go docker`.
|
||||
make promu
|
||||
promu crossbuild -p linux/amd64 -p linux/armv7 -p linux/amd64 -p linux/ppc64le
|
||||
make docker
|
||||
|
||||
This will build the docker image as `wrouesnel/postgres_exporter:latest`. This
|
||||
is a minimal docker image containing *just* postgres_exporter. By default no SSL
|
||||
certificates are included, if you need to use SSL you should either bind-mount
|
||||
`/etc/ssl/certs/ca-certificates.crt` or derive a new image containing them.
|
||||
This will build the docker image as `prometheuscommunity/postgres_exporter:${branch}`.
|
||||
|
||||
### Vendoring
|
||||
Package vendoring is handled with [`govendor`](https://github.com/kardianos/govendor)
|
||||
|
||||
Package vendoring is handled with Go modules.
|
||||
|
||||
### Flags
|
||||
|
||||
@ -277,10 +276,3 @@ GRANT SELECT ON postgres_exporter.pg_stat_statements TO postgres_exporter;
|
||||
> ```
|
||||
> DATA_SOURCE_NAME=postgresql://postgres_exporter:password@localhost:5432/postgres?sslmode=disable
|
||||
> ```
|
||||
|
||||
# Hacking
|
||||
* To build a copy for your current architecture run `go run mage.go binary`.
|
||||
This will create a symlink to the just built binary in the root directory.
|
||||
* To build release tar balls run `go run mage.go release`.
|
||||
* Build system is a bit temperamental at the moment since the conversion to mage - I am working on getting it
|
||||
to be a perfect out of the box experience, but am time-constrained on it at the moment.
|
||||
|
@ -1,3 +1,16 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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 (
|
||||
|
@ -1,3 +1,16 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build !integration
|
||||
|
||||
package main
|
||||
|
@ -1,3 +1,16 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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 (
|
||||
@ -1260,7 +1273,7 @@ func newDesc(subsystem, name, help string, labels prometheus.Labels) *prometheus
|
||||
}
|
||||
|
||||
func queryDatabases(server *Server) ([]string, error) {
|
||||
rows, err := server.db.Query("SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false AND datname != current_database()") // nolint: safesql
|
||||
rows, err := server.db.Query("SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false AND datname != current_database()")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error retrieving databases: %v", err)
|
||||
}
|
||||
@ -1299,9 +1312,9 @@ func queryNamespaceMapping(server *Server, namespace string, mapping MetricMapNa
|
||||
if !found {
|
||||
// I've no idea how to avoid this properly at the moment, but this is
|
||||
// an admin tool so you're not injecting SQL right?
|
||||
rows, err = server.db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace)) // nolint: gas, safesql
|
||||
rows, err = server.db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace)) // nolint: gas
|
||||
} else {
|
||||
rows, err = server.db.Query(query) // nolint: safesql
|
||||
rows, err = server.db.Query(query)
|
||||
}
|
||||
if err != nil {
|
||||
return []prometheus.Metric{}, []error{}, fmt.Errorf("Error running query on database %q: %s %v", server, namespace, err)
|
||||
|
@ -1,3 +1,16 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// These are specialized integration tests. We only build them when we're doing
|
||||
// a lot of additional work to keep the external docker environment they require
|
||||
// working.
|
||||
@ -75,7 +88,7 @@ func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
|
||||
}
|
||||
|
||||
// TestInvalidDsnDoesntCrash tests that specifying an invalid DSN doesn't crash
|
||||
// the exporter. Related to https://github.com/wrouesnel/postgres_exporter/issues/93
|
||||
// the exporter. Related to https://github.com/prometheus-community/postgres_exporter/issues/93
|
||||
// although not a replication of the scenario.
|
||||
func (s *IntegrationSuite) TestInvalidDsnDoesntCrash(c *C) {
|
||||
// Setup a dummy channel to consume metrics
|
||||
|
@ -1,3 +1,16 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// 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.
|
||||
|
||||
// +build !integration
|
||||
|
||||
package main
|
||||
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
||||
module github.com/prometheus-community/postgres_exporter
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/common v0.17.0
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
432
go.sum
Normal file
432
go.sum
Normal file
@ -0,0 +1,432 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.17.0 h1:kDIZLI74SS+3tedSvEkykgBkD7txMxaJAPj8DtJUKYA=
|
||||
github.com/prometheus/common v0.17.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
|
||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
11
mage.go
11
mage.go
@ -1,11 +0,0 @@
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/magefile/mage/mage"
|
||||
)
|
||||
|
||||
func main() { os.Exit(mage.Main()) }
|
788
magefile.go
788
magefile.go
@ -1,788 +0,0 @@
|
||||
// +build mage
|
||||
// Self-contained go-project magefile.
|
||||
|
||||
// nolint: deadcode
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/magefile/mage/mg"
|
||||
"github.com/magefile/mage/sh"
|
||||
"github.com/magefile/mage/target"
|
||||
|
||||
"errors"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
|
||||
"github.com/mholt/archiver"
|
||||
)
|
||||
|
||||
var curDir = func() string {
|
||||
name, _ := os.Getwd()
|
||||
return name
|
||||
}()
|
||||
|
||||
const constCoverageDir = ".coverage"
|
||||
const constToolDir = "tools"
|
||||
const constBinDir = "bin"
|
||||
const constReleaseDir = "release"
|
||||
const constCmdDir = "cmd"
|
||||
const constCoverFile = "cover.out"
|
||||
const constAssets = "assets"
|
||||
const constAssetsGenerated = "assets/generated"
|
||||
|
||||
var coverageDir = mustStr(filepath.Abs(path.Join(curDir, constCoverageDir)))
|
||||
var toolDir = mustStr(filepath.Abs(path.Join(curDir, constToolDir)))
|
||||
var binDir = mustStr(filepath.Abs(path.Join(curDir, constBinDir)))
|
||||
var releaseDir = mustStr(filepath.Abs(path.Join(curDir, constReleaseDir)))
|
||||
var cmdDir = mustStr(filepath.Abs(path.Join(curDir, constCmdDir)))
|
||||
var assetsGenerated = mustStr(filepath.Abs(path.Join(curDir, constAssetsGenerated)))
|
||||
|
||||
// Calculate file paths
|
||||
var toolsGoPath = toolDir
|
||||
var toolsSrcDir = mustStr(filepath.Abs(path.Join(toolDir, "src")))
|
||||
var toolsBinDir = mustStr(filepath.Abs(path.Join(toolDir, "bin")))
|
||||
var toolsVendorDir = mustStr(filepath.Abs(path.Join(toolDir, "vendor")))
|
||||
|
||||
var outputDirs = []string{binDir, releaseDir, toolsGoPath, toolsBinDir,
|
||||
toolsVendorDir, assetsGenerated, coverageDir}
|
||||
|
||||
var toolsEnv = map[string]string{"GOPATH": toolsGoPath}
|
||||
|
||||
var containerName = func() string {
|
||||
if name := os.Getenv("CONTAINER_NAME"); name != "" {
|
||||
return name
|
||||
}
|
||||
return "wrouesnel/postgres_exporter:latest"
|
||||
}()
|
||||
|
||||
type Platform struct {
|
||||
OS string
|
||||
Arch string
|
||||
BinSuffix string
|
||||
}
|
||||
|
||||
func (p *Platform) String() string {
|
||||
return fmt.Sprintf("%s-%s", p.OS, p.Arch)
|
||||
}
|
||||
|
||||
func (p *Platform) PlatformDir() string {
|
||||
platformDir := path.Join(binDir, fmt.Sprintf("%s_%s_%s", productName, versionShort, p.String()))
|
||||
return platformDir
|
||||
}
|
||||
|
||||
func (p *Platform) PlatformBin(cmd string) string {
|
||||
platformBin := fmt.Sprintf("%s%s", cmd, p.BinSuffix)
|
||||
return path.Join(p.PlatformDir(), platformBin)
|
||||
}
|
||||
|
||||
func (p *Platform) ArchiveDir() string {
|
||||
return fmt.Sprintf("%s_%s_%s", productName, versionShort, p.String())
|
||||
}
|
||||
|
||||
func (p *Platform) ReleaseBase() string {
|
||||
return path.Join(releaseDir, fmt.Sprintf("%s_%s_%s", productName, versionShort, p.String()))
|
||||
}
|
||||
|
||||
// Supported platforms
|
||||
var platforms []Platform = []Platform{
|
||||
{"linux", "amd64", ""},
|
||||
{"linux", "386", ""},
|
||||
{"linux", "arm64", ""},
|
||||
{"linux", "mips64le", ""},
|
||||
{"darwin", "amd64", ""},
|
||||
{"darwin", "386", ""},
|
||||
{"windows", "amd64", ".exe"},
|
||||
{"windows", "386", ".exe"},
|
||||
{"freebsd", "amd64", ""},
|
||||
}
|
||||
|
||||
// productName can be overridden by environ product name
|
||||
var productName = func() string {
|
||||
if name := os.Getenv("PRODUCT_NAME"); name != "" {
|
||||
return name
|
||||
}
|
||||
name, _ := os.Getwd()
|
||||
return path.Base(name)
|
||||
}()
|
||||
|
||||
// Source files
|
||||
var goSrc []string
|
||||
var goDirs []string
|
||||
var goPkgs []string
|
||||
var goCmds []string
|
||||
|
||||
var branch = func() string {
|
||||
if v := os.Getenv("BRANCH"); v != "" {
|
||||
return v
|
||||
}
|
||||
out, _ := sh.Output("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
|
||||
return out
|
||||
}()
|
||||
|
||||
var buildDate = func() string {
|
||||
if v := os.Getenv("BUILDDATE"); v != "" {
|
||||
return v
|
||||
}
|
||||
return time.Now().Format("2006-01-02T15:04:05-0700")
|
||||
}()
|
||||
|
||||
var revision = func() string {
|
||||
if v := os.Getenv("REVISION"); v != "" {
|
||||
return v
|
||||
}
|
||||
out, _ := sh.Output("git", "rev-parse", "HEAD")
|
||||
|
||||
return out
|
||||
}()
|
||||
|
||||
var version = func() string {
|
||||
if v := os.Getenv("VERSION"); v != "" {
|
||||
return v
|
||||
}
|
||||
out, _ := sh.Output("git", "describe", "--dirty")
|
||||
|
||||
if out == "" {
|
||||
return "v0.0.0"
|
||||
}
|
||||
|
||||
return out
|
||||
}()
|
||||
|
||||
var versionShort = func() string {
|
||||
if v := os.Getenv("VERSION_SHORT"); v != "" {
|
||||
return v
|
||||
}
|
||||
out, _ := sh.Output("git", "describe", "--abbrev=0")
|
||||
|
||||
if out == "" {
|
||||
return "v0.0.0"
|
||||
}
|
||||
|
||||
return out
|
||||
}()
|
||||
|
||||
var concurrency = func() int {
|
||||
if v := os.Getenv("CONCURRENCY"); v != "" {
|
||||
pv, err := strconv.ParseUint(v, 10, bits.UintSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(pv)
|
||||
}
|
||||
return runtime.NumCPU()
|
||||
}()
|
||||
|
||||
var linterDeadline = func() time.Duration {
|
||||
if v := os.Getenv("LINTER_DEADLINE"); v != "" {
|
||||
d, _ := time.ParseDuration(v)
|
||||
if d != 0 {
|
||||
return d
|
||||
}
|
||||
}
|
||||
return time.Second * 60
|
||||
}()
|
||||
|
||||
func Log(args ...interface{}) {
|
||||
if mg.Verbose() {
|
||||
fmt.Println(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Set environment
|
||||
os.Setenv("PATH", fmt.Sprintf("%s:%s", toolsBinDir, os.Getenv("PATH")))
|
||||
Log("Build PATH: ", os.Getenv("PATH"))
|
||||
Log("Concurrency:", concurrency)
|
||||
goSrc = func() []string {
|
||||
results := new([]string)
|
||||
filepath.Walk(".", func(relpath string, info os.FileInfo, err error) error {
|
||||
// Ensure absolute path so globs work
|
||||
path, err := filepath.Abs(relpath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Look for files
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exclusions
|
||||
for _, exclusion := range []string{toolDir, binDir, releaseDir, coverageDir} {
|
||||
if strings.HasPrefix(path, exclusion) {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(path, "/vendor/") {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.Contains(path, ".git") {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(path, ".go") {
|
||||
return nil
|
||||
}
|
||||
|
||||
*results = append(*results, path)
|
||||
return nil
|
||||
})
|
||||
return *results
|
||||
}()
|
||||
goDirs = func() []string {
|
||||
resultMap := make(map[string]struct{})
|
||||
for _, path := range goSrc {
|
||||
absDir, err := filepath.Abs(filepath.Dir(path))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resultMap[absDir] = struct{}{}
|
||||
}
|
||||
results := []string{}
|
||||
for k := range resultMap {
|
||||
results = append(results, k)
|
||||
}
|
||||
return results
|
||||
}()
|
||||
goPkgs = func() []string {
|
||||
results := []string{}
|
||||
out, err := sh.Output("go", "list", "./...")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if !strings.Contains(line, "/vendor/") {
|
||||
results = append(results, line)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}()
|
||||
goCmds = func() []string {
|
||||
results := []string{}
|
||||
|
||||
finfos, err := ioutil.ReadDir(cmdDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, finfo := range finfos {
|
||||
results = append(results, finfo.Name())
|
||||
}
|
||||
return results
|
||||
}()
|
||||
|
||||
// Ensure output dirs exist
|
||||
for _, dir := range outputDirs {
|
||||
os.MkdirAll(dir, os.FileMode(0777))
|
||||
}
|
||||
}
|
||||
|
||||
func mustStr(r string, err error) string {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func getCoreTools() []string {
|
||||
staticTools := []string{
|
||||
"github.com/kardianos/govendor",
|
||||
"github.com/wadey/gocovmerge",
|
||||
"github.com/mattn/goveralls",
|
||||
"github.com/tmthrgd/go-bindata/go-bindata",
|
||||
"github.com/GoASTScanner/gas/cmd/gas", // workaround for Ast scanner
|
||||
"github.com/alecthomas/gometalinter",
|
||||
}
|
||||
return staticTools
|
||||
}
|
||||
|
||||
func getMetalinters() []string {
|
||||
// Gometalinter should now be on the command line
|
||||
dynamicTools := []string{}
|
||||
|
||||
goMetalinterHelp, _ := sh.Output("gometalinter", "--help")
|
||||
linterRx := regexp.MustCompile(`\s+\w+:\s*\((.+)\)`)
|
||||
for _, l := range strings.Split(goMetalinterHelp, "\n") {
|
||||
linter := linterRx.FindStringSubmatch(l)
|
||||
if len(linter) > 1 {
|
||||
dynamicTools = append(dynamicTools, linter[1])
|
||||
}
|
||||
}
|
||||
return dynamicTools
|
||||
}
|
||||
|
||||
func ensureVendorSrcLink() error {
|
||||
Log("Symlink vendor to tools dir")
|
||||
if err := sh.Rm(toolsSrcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Symlink(toolsVendorDir, toolsSrcDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// concurrencyLimitedBuild executes a certain number of commands limited by concurrency
|
||||
func concurrencyLimitedBuild(buildCmds ...interface{}) error {
|
||||
resultsCh := make(chan error, len(buildCmds))
|
||||
concurrencyControl := make(chan struct{}, concurrency)
|
||||
for _, buildCmd := range buildCmds {
|
||||
go func(buildCmd interface{}) {
|
||||
concurrencyControl <- struct{}{}
|
||||
resultsCh <- buildCmd.(func() error)()
|
||||
<-concurrencyControl
|
||||
|
||||
}(buildCmd)
|
||||
}
|
||||
// Doesn't work at the moment
|
||||
// mg.Deps(buildCmds...)
|
||||
results := []error{}
|
||||
var resultErr error = nil
|
||||
for len(results) < len(buildCmds) {
|
||||
err := <-resultsCh
|
||||
results = append(results, err)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
resultErr = errors.New("parallel build failed")
|
||||
}
|
||||
fmt.Printf("Finished %v of %v\n", len(results), len(buildCmds))
|
||||
}
|
||||
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// Tools builds build tools of the project and is depended on by all other build targets.
|
||||
func Tools() (err error) {
|
||||
// Catch panics and convert to errors
|
||||
defer func() {
|
||||
if perr := recover(); perr != nil {
|
||||
err = perr.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := ensureVendorSrcLink(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toolBuild := func(toolType string, tools ...string) error {
|
||||
toolTargets := []interface{}{}
|
||||
for _, toolImport := range tools {
|
||||
toolParts := strings.Split(toolImport, "/")
|
||||
toolBin := path.Join(toolsBinDir, toolParts[len(toolParts)-1])
|
||||
Log("Check for changes:", toolBin, toolsVendorDir)
|
||||
changed, terr := target.Dir(toolBin, toolsVendorDir)
|
||||
if terr != nil {
|
||||
if !os.IsNotExist(terr) {
|
||||
panic(terr)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
localToolImport := toolImport
|
||||
f := func() error { return sh.RunWith(toolsEnv, "go", "install", "-v", localToolImport) }
|
||||
toolTargets = append(toolTargets, f)
|
||||
}
|
||||
}
|
||||
|
||||
Log("Build", toolType, "tools")
|
||||
if berr := concurrencyLimitedBuild(toolTargets...); berr != nil {
|
||||
return berr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if berr := toolBuild("static", getCoreTools()...); berr != nil {
|
||||
return berr
|
||||
}
|
||||
|
||||
if berr := toolBuild("static", getMetalinters()...); berr != nil {
|
||||
return berr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTools automatically updates tool dependencies to the latest version.
|
||||
func UpdateTools() error {
|
||||
if err := ensureVendorSrcLink(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure govendor is up to date without doing anything
|
||||
govendorPkg := "github.com/kardianos/govendor"
|
||||
govendorParts := strings.Split(govendorPkg, "/")
|
||||
govendorBin := path.Join(toolsBinDir, govendorParts[len(govendorParts)-1])
|
||||
|
||||
sh.RunWith(toolsEnv, "go", "get", "-v", "-u", govendorPkg)
|
||||
|
||||
if changed, cerr := target.Dir(govendorBin, toolsSrcDir); changed || os.IsNotExist(cerr) {
|
||||
if err := sh.RunWith(toolsEnv, "go", "install", "-v", govendorPkg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if cerr != nil {
|
||||
panic(cerr)
|
||||
}
|
||||
|
||||
// Set current directory so govendor has the right path
|
||||
previousPwd, wderr := os.Getwd()
|
||||
if wderr != nil {
|
||||
return wderr
|
||||
}
|
||||
if err := os.Chdir(toolDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// govendor fetch core tools
|
||||
for _, toolImport := range append(getCoreTools(), getMetalinters()...) {
|
||||
sh.RunV("govendor", "fetch", "-v", toolImport)
|
||||
}
|
||||
|
||||
// change back to original working directory
|
||||
if err := os.Chdir(previousPwd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assets builds binary assets to be bundled into the binary.
|
||||
func Assets() error {
|
||||
mg.Deps(Tools)
|
||||
|
||||
if err := os.MkdirAll("assets/generated", os.FileMode(0777)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sh.RunV("go-bindata", "-pkg=assets", "-o", "assets/bindata.go", "-ignore=bindata.go",
|
||||
"-ignore=.*.map$", "-prefix=assets/generated", "assets/generated/...")
|
||||
}
|
||||
|
||||
// Lint runs gometalinter for code quality. CI will run this before accepting PRs.
|
||||
func Lint() error {
|
||||
mg.Deps(Tools)
|
||||
args := []string{"-j", fmt.Sprintf("%v", concurrency), fmt.Sprintf("--deadline=%s",
|
||||
linterDeadline.String()), "--enable-all", "--line-length=120",
|
||||
"--disable=gocyclo", "--disable=testify", "--disable=test", "--disable=lll", "--exclude=assets/bindata.go"}
|
||||
return sh.RunV("gometalinter", append(args, goDirs...)...)
|
||||
}
|
||||
|
||||
// Style checks formatting of the file. CI will run this before acceptiing PRs.
|
||||
func Style() error {
|
||||
mg.Deps(Tools)
|
||||
args := []string{"--disable-all", "--enable=gofmt", "--enable=goimports"}
|
||||
return sh.RunV("gometalinter", append(args, goSrc...)...)
|
||||
}
|
||||
|
||||
// Fmt automatically formats all source code files
|
||||
func Fmt() error {
|
||||
mg.Deps(Tools)
|
||||
fmtErr := sh.RunV("gofmt", append([]string{"-s", "-w"}, goSrc...)...)
|
||||
if fmtErr != nil {
|
||||
return fmtErr
|
||||
}
|
||||
impErr := sh.RunV("goimports", append([]string{"-w"}, goSrc...)...)
|
||||
if impErr != nil {
|
||||
return fmtErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listCoverageFiles() ([]string, error) {
|
||||
result := []string{}
|
||||
finfos, derr := ioutil.ReadDir(coverageDir)
|
||||
if derr != nil {
|
||||
return result, derr
|
||||
}
|
||||
for _, finfo := range finfos {
|
||||
result = append(result, path.Join(coverageDir, finfo.Name()))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Test run test suite
|
||||
func Test() error {
|
||||
mg.Deps(Tools)
|
||||
|
||||
// Ensure coverage directory exists
|
||||
if err := os.MkdirAll(coverageDir, os.FileMode(0777)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clean up coverage directory
|
||||
coverFiles, derr := listCoverageFiles()
|
||||
if derr != nil {
|
||||
return derr
|
||||
}
|
||||
for _, coverFile := range coverFiles {
|
||||
if err := sh.Rm(coverFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Run tests
|
||||
coverProfiles := []string{}
|
||||
for _, pkg := range goPkgs {
|
||||
coverProfile := path.Join(coverageDir, fmt.Sprintf("%s%s", strings.Replace(pkg, "/", "-", -1), ".out"))
|
||||
testErr := sh.Run("go", "test", "-v", "-covermode", "count", fmt.Sprintf("-coverprofile=%s", coverProfile),
|
||||
pkg)
|
||||
if testErr != nil {
|
||||
return testErr
|
||||
}
|
||||
coverProfiles = append(coverProfiles, coverProfile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build the intgration test binary
|
||||
func IntegrationTestBinary() error {
|
||||
changed, err := target.Path("postgres_exporter_integration_test", goSrc...)
|
||||
if (changed && (err == nil)) || os.IsNotExist(err) {
|
||||
return sh.RunWith(map[string]string{"CGO_ENABLED": "0"}, "go", "test", "./cmd/postgres_exporter",
|
||||
"-c", "-tags", "integration",
|
||||
"-a", "-ldflags", "-extldflags '-static'",
|
||||
"-X", fmt.Sprintf("main.Branch=%s", branch),
|
||||
"-X", fmt.Sprintf("main.BuildDate=%s", buildDate),
|
||||
"-X", fmt.Sprintf("main.Revision=%s", revision),
|
||||
"-X", fmt.Sprintf("main.VersionShort=%s", versionShort),
|
||||
"-o", "postgres_exporter_integration_test", "-cover", "-covermode", "count")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// TestIntegration runs integration tests
|
||||
func TestIntegration() error {
|
||||
mg.Deps(Binary, IntegrationTestBinary)
|
||||
|
||||
exporterPath := mustStr(filepath.Abs("postgres_exporter"))
|
||||
testBinaryPath := mustStr(filepath.Abs("postgres_exporter_integration_test"))
|
||||
testScriptPath := mustStr(filepath.Abs("postgres_exporter_integration_test_script"))
|
||||
|
||||
integrationCoverageProfile := path.Join(coverageDir, "cover.integration.out")
|
||||
|
||||
return sh.RunV("cmd/postgres_exporter/tests/test-smoke", exporterPath,
|
||||
fmt.Sprintf("%s %s %s", testScriptPath, testBinaryPath, integrationCoverageProfile))
|
||||
}
|
||||
|
||||
// Coverage sums up the coverage profiles in .coverage. It does not clean up after itself or before.
|
||||
func Coverage() error {
|
||||
// Clean up coverage directory
|
||||
coverFiles, derr := listCoverageFiles()
|
||||
if derr != nil {
|
||||
return derr
|
||||
}
|
||||
|
||||
mergedCoverage, err := sh.Output("gocovmerge", coverFiles...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(constCoverFile, []byte(mergedCoverage), os.FileMode(0777))
|
||||
}
|
||||
|
||||
// All runs a full suite suitable for CI
|
||||
func All() error {
|
||||
mg.SerialDeps(Style, Lint, Test, TestIntegration, Coverage, Release)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Release builds release archives under the release/ directory
|
||||
func Release() error {
|
||||
mg.Deps(ReleaseBin)
|
||||
|
||||
for _, platform := range platforms {
|
||||
owd, wderr := os.Getwd()
|
||||
if wderr != nil {
|
||||
return wderr
|
||||
}
|
||||
os.Chdir(binDir)
|
||||
|
||||
if platform.OS == "windows" {
|
||||
// build a zip binary as well
|
||||
err := archiver.Zip.Make(fmt.Sprintf("%s.zip", platform.ReleaseBase()), []string{platform.ArchiveDir()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// build tar gz
|
||||
err := archiver.TarGz.Make(fmt.Sprintf("%s.tar.gz", platform.ReleaseBase()), []string{platform.ArchiveDir()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Chdir(owd)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeBuilder(cmd string, platform Platform) func() error {
|
||||
f := func() error {
|
||||
// Depend on assets
|
||||
mg.Deps(Assets)
|
||||
|
||||
cmdSrc := fmt.Sprintf("./%s/%s", mustStr(filepath.Rel(curDir, cmdDir)), cmd)
|
||||
|
||||
Log("Make platform binary directory:", platform.PlatformDir())
|
||||
if err := os.MkdirAll(platform.PlatformDir(), os.FileMode(0777)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Log("Checking for changes:", platform.PlatformBin(cmd))
|
||||
if changed, err := target.Path(platform.PlatformBin(cmd), goSrc...); !changed {
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Building", platform.PlatformBin(cmd))
|
||||
return sh.RunWith(map[string]string{"CGO_ENABLED": "0", "GOOS": platform.OS, "GOARCH": platform.Arch},
|
||||
"go", "build", "-a", "-ldflags", fmt.Sprintf("-extldflags '-static' -X main.Version=%s", version),
|
||||
"-o", platform.PlatformBin(cmd), cmdSrc)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func getCurrentPlatform() *Platform {
|
||||
var curPlatform *Platform
|
||||
for _, p := range platforms {
|
||||
if p.OS == runtime.GOOS && p.Arch == runtime.GOARCH {
|
||||
storedP := p
|
||||
curPlatform = &storedP
|
||||
}
|
||||
}
|
||||
Log("Determined current platform:", curPlatform)
|
||||
return curPlatform
|
||||
}
|
||||
|
||||
// Binary build a binary for the current platform
|
||||
func Binary() error {
|
||||
curPlatform := getCurrentPlatform()
|
||||
if curPlatform == nil {
|
||||
return errors.New("current platform is not supported")
|
||||
}
|
||||
|
||||
for _, cmd := range goCmds {
|
||||
err := makeBuilder(cmd, *curPlatform)()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make a root symlink to the build
|
||||
cmdPath := path.Join(curDir, cmd)
|
||||
os.Remove(cmdPath)
|
||||
if err := os.Symlink(curPlatform.PlatformBin(cmd), cmdPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseBin builds cross-platform release binaries under the bin/ directory
|
||||
func ReleaseBin() error {
|
||||
buildCmds := []interface{}{}
|
||||
|
||||
for _, cmd := range goCmds {
|
||||
for _, platform := range platforms {
|
||||
buildCmds = append(buildCmds, makeBuilder(cmd, platform))
|
||||
}
|
||||
}
|
||||
|
||||
resultsCh := make(chan error, len(buildCmds))
|
||||
concurrencyControl := make(chan struct{}, concurrency)
|
||||
for _, buildCmd := range buildCmds {
|
||||
go func(buildCmd interface{}) {
|
||||
concurrencyControl <- struct{}{}
|
||||
resultsCh <- buildCmd.(func() error)()
|
||||
<-concurrencyControl
|
||||
|
||||
}(buildCmd)
|
||||
}
|
||||
// Doesn't work at the moment
|
||||
// mg.Deps(buildCmds...)
|
||||
results := []error{}
|
||||
var resultErr error = nil
|
||||
for len(results) < len(buildCmds) {
|
||||
err := <-resultsCh
|
||||
results = append(results, err)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
resultErr = errors.New("parallel build failed")
|
||||
}
|
||||
fmt.Printf("Finished %v of %v\n", len(results), len(buildCmds))
|
||||
}
|
||||
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// Docker builds the docker image
|
||||
func Docker() error {
|
||||
mg.Deps(Binary)
|
||||
p := getCurrentPlatform()
|
||||
if p == nil {
|
||||
return errors.New("current platform is not supported")
|
||||
}
|
||||
|
||||
return sh.RunV("docker", "build",
|
||||
fmt.Sprintf("--build-arg=binary=%s",
|
||||
mustStr(filepath.Rel(curDir, p.PlatformBin("postgres_exporter")))),
|
||||
"-t", containerName, ".")
|
||||
}
|
||||
|
||||
// Clean deletes build output and cleans up the working directory
|
||||
func Clean() error {
|
||||
for _, name := range goCmds {
|
||||
if err := sh.Rm(path.Join(binDir, name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range outputDirs {
|
||||
if err := sh.Rm(name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug prints the value of internal state variables
|
||||
func Debug() error {
|
||||
fmt.Println("Source Files:", goSrc)
|
||||
fmt.Println("Packages:", goPkgs)
|
||||
fmt.Println("Directories:", goDirs)
|
||||
fmt.Println("Command Paths:", goCmds)
|
||||
fmt.Println("Output Dirs:", outputDirs)
|
||||
fmt.Println("Tool Src Dir:", toolsSrcDir)
|
||||
fmt.Println("Tool Vendor Dir:", toolsVendorDir)
|
||||
fmt.Println("Tool GOPATH:", toolsGoPath)
|
||||
fmt.Println("PATH:", os.Getenv("PATH"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Autogen configure local git repository with commit hooks
|
||||
func Autogen() error {
|
||||
fmt.Println("Installing git hooks in local repository...")
|
||||
return os.Link(path.Join(curDir, toolDir, "pre-commit"), ".git/hooks/pre-commit")
|
||||
}
|
0
scripts/errcheck_excludes.txt
Normal file
0
scripts/errcheck_excludes.txt
Normal file
4
tools/.gitignore
vendored
4
tools/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
/pkg
|
||||
/bin
|
||||
/tools.deps
|
||||
/metatools.deps
|
@ -1,9 +0,0 @@
|
||||
|
||||
Vendored versions of the build tooling.
|
||||
|
||||
gocovmerge is used to merge coverage reports for uploading to a service like
|
||||
coveralls, and gometalinter conveniently incorporates multiple Go linters.
|
||||
|
||||
By vendoring both, we gain a self-contained build system.
|
||||
|
||||
Run `make all` to build, and `make update` to update.
|
7
tools/vendor/github.com/Bowery/prompt/CONTRIBUTORS.md
generated
vendored
7
tools/vendor/github.com/Bowery/prompt/CONTRIBUTORS.md
generated
vendored
@ -1,7 +0,0 @@
|
||||
- [Larz Conwell](https://github.com/larzconwell)
|
||||
- [Steve Kaliski](https://github.com/sjkaliski)
|
||||
- [NHOrus](https://github.com/NHOrus)
|
||||
- [Attila Fülöp](https://github.com/AttilaFueloep)
|
||||
- [Gereon Frey](https://github.com/gfrey)
|
||||
- [Aaron Bieber](https://github.com/qbit)
|
||||
- [Ricky Medina](https://github.com/r-medina)
|
21
tools/vendor/github.com/Bowery/prompt/LICENSE
generated
vendored
21
tools/vendor/github.com/Bowery/prompt/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 Bowery, Inc.
|
||||
|
||||
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.
|
38
tools/vendor/github.com/Bowery/prompt/README.md
generated
vendored
38
tools/vendor/github.com/Bowery/prompt/README.md
generated
vendored
@ -1,38 +0,0 @@
|
||||
# Prompt
|
||||
|
||||
[](https://circleci.com/gh/Bowery/prompt/tree/master)
|
||||
|
||||
[](https://godoc.org/github.com/Bowery/prompt)
|
||||
|
||||
Prompt is a cross platform line-editing prompting library. Read the GoDoc page
|
||||
for more info and for API details.
|
||||
|
||||
## Features
|
||||
- Keyboard shortcuts in prompts
|
||||
- History support
|
||||
- Secure password prompt
|
||||
- Custom prompt support
|
||||
- Fallback prompt for unsupported terminals
|
||||
- ANSI conversion for Windows
|
||||
|
||||
## Todo
|
||||
- Multi-line prompt as a Terminal option
|
||||
- Make refresh less jittery on Windows([possible reason](https://github.com/Bowery/prompt/blob/master/output_windows.go#L108))
|
||||
- Multi-byte character support on Windows
|
||||
- `AnsiWriter` should execute the equivalent ANSI escape code functionality on Windows
|
||||
- Support for more ANSI escape codes on Windows.
|
||||
- More keyboard shortcuts from Readlines shortcut list
|
||||
|
||||
## Contributing
|
||||
|
||||
Make sure Go is setup and running the latest release version, and make sure your `GOPATH` is setup properly.
|
||||
|
||||
Follow the guidelines [here](https://guides.github.com/activities/contributing-to-open-source/#contributing).
|
||||
|
||||
Please be sure to `gofmt` any code before doing commits. You can simply run `gofmt -w .` to format all the code in the directory.
|
||||
|
||||
Lastly don't forget to add your name to [`CONTRIBUTORS.md`](https://github.com/Bowery/prompt/blob/master/CONTRIBUTORS.md)
|
||||
|
||||
## License
|
||||
|
||||
Prompt is MIT licensed, details can be found [here](https://raw.githubusercontent.com/Bowery/prompt/master/LICENSE).
|
39
tools/vendor/github.com/Bowery/prompt/ansi_unix.go
generated
vendored
39
tools/vendor/github.com/Bowery/prompt/ansi_unix.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly solaris
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// AnsiReader is an io.Reader that wraps an *os.File.
|
||||
type AnsiReader struct {
|
||||
file *os.File
|
||||
}
|
||||
|
||||
// NewAnsiReader creates a AnsiReader from the given input file.
|
||||
func NewAnsiReader(in *os.File) *AnsiReader {
|
||||
return &AnsiReader{file: in}
|
||||
}
|
||||
|
||||
// Read reads data from the input file into b.
|
||||
func (ar *AnsiReader) Read(b []byte) (int, error) {
|
||||
return ar.file.Read(b)
|
||||
}
|
||||
|
||||
// AnsiWriter is an io.Writer that wraps an *os.File.
|
||||
type AnsiWriter struct {
|
||||
file *os.File
|
||||
}
|
||||
|
||||
// NewAnsiWriter creates a AnsiWriter from the given output file.
|
||||
func NewAnsiWriter(out *os.File) *AnsiWriter {
|
||||
return &AnsiWriter{file: out}
|
||||
}
|
||||
|
||||
// Write writes data from b into the input file.
|
||||
func (aw *AnsiWriter) Write(b []byte) (int, error) {
|
||||
return aw.file.Write(b)
|
||||
}
|
510
tools/vendor/github.com/Bowery/prompt/ansi_windows.go
generated
vendored
510
tools/vendor/github.com/Bowery/prompt/ansi_windows.go
generated
vendored
@ -1,510 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// keyEventType is the key event type for an input record.
|
||||
const keyEventType = 0x0001
|
||||
|
||||
var (
|
||||
readConsoleInput = kernel.NewProc("ReadConsoleInputW")
|
||||
)
|
||||
|
||||
// inputRecord describes a input event from a console.
|
||||
type inputRecord struct {
|
||||
eventType uint16
|
||||
// Magic to get around the union C type, cast
|
||||
// event to the type using unsafe.Pointer.
|
||||
_ [2]byte
|
||||
event [16]byte
|
||||
}
|
||||
|
||||
// keyEventRecord describes a keyboard event.
|
||||
type keyEventRecord struct {
|
||||
keyDown int32
|
||||
repeatCount uint16
|
||||
virtualKeyCode uint16
|
||||
virtualScanCode uint16
|
||||
char uint16
|
||||
controlKeyState uint32
|
||||
}
|
||||
|
||||
// AnsiReader is an io.Reader that reads from a given file and converts Windows
|
||||
// key codes to their equivalent ANSI escape codes.
|
||||
type AnsiReader struct {
|
||||
fd uintptr
|
||||
buf []rune
|
||||
}
|
||||
|
||||
// NewAnsiReader creates a AnsiReader from the given input file.
|
||||
func NewAnsiReader(in *os.File) *AnsiReader {
|
||||
return &AnsiReader{fd: in.Fd()}
|
||||
}
|
||||
|
||||
// Read reads data from the input converting to ANSI escape codes that can be
|
||||
// read over multiple Reads.
|
||||
func (ar *AnsiReader) Read(b []byte) (int, error) {
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if len(ar.buf) == 0 {
|
||||
var runes []rune
|
||||
var read uint32
|
||||
rec := new(inputRecord)
|
||||
|
||||
for runes == nil {
|
||||
ret, _, err := readConsoleInput.Call(ar.fd, uintptr(unsafe.Pointer(rec)),
|
||||
1, uintptr(unsafe.Pointer(&read)))
|
||||
if ret == 0 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if rec.eventType != keyEventType {
|
||||
continue
|
||||
}
|
||||
|
||||
ke := (*keyEventRecord)(unsafe.Pointer(&rec.event))
|
||||
if ke.keyDown == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
shift := false
|
||||
if ke.controlKeyState&shiftKey != 0 {
|
||||
shift = true
|
||||
}
|
||||
|
||||
ctrl := false
|
||||
if ke.controlKeyState&leftCtrlKey != 0 || ke.controlKeyState&rightCtrlKey != 0 {
|
||||
ctrl = true
|
||||
}
|
||||
|
||||
alt := false
|
||||
if ke.controlKeyState&leftAltKey != 0 || ke.controlKeyState&rightAltKey != 0 {
|
||||
alt = true
|
||||
}
|
||||
|
||||
// Backspace, Return, Space.
|
||||
if ke.char == ctrlH || ke.char == returnKey || ke.char == spaceKey {
|
||||
code := string(returnKey)
|
||||
if ke.char == ctrlH {
|
||||
code = string(backKey)
|
||||
} else if ke.char == spaceKey {
|
||||
code = string(spaceKey)
|
||||
}
|
||||
|
||||
if alt {
|
||||
code = string(escKey) + code
|
||||
}
|
||||
|
||||
runes = []rune(code)
|
||||
break
|
||||
}
|
||||
|
||||
// Generate runes for the chars and key codes.
|
||||
if ke.char > 0 {
|
||||
runes = []rune{rune(ke.char)}
|
||||
} else {
|
||||
code := string(escKey)
|
||||
|
||||
switch ke.virtualKeyCode {
|
||||
case f1Key:
|
||||
if ctrl {
|
||||
continue
|
||||
}
|
||||
|
||||
code += ar.shortFunction("P", shift, ctrl, alt)
|
||||
case f2Key:
|
||||
code += ar.shortFunction("Q", shift, ctrl, alt)
|
||||
case f3Key:
|
||||
code += ar.shortFunction("R", shift, ctrl, alt)
|
||||
case f4Key:
|
||||
code += ar.shortFunction("S", shift, ctrl, alt)
|
||||
case f5Key:
|
||||
code += ar.longFunction("15", shift, ctrl, alt)
|
||||
case f6Key:
|
||||
code += ar.longFunction("17", shift, ctrl, alt)
|
||||
case f7Key:
|
||||
code += ar.longFunction("18", shift, ctrl, alt)
|
||||
case f8Key:
|
||||
code += ar.longFunction("19", shift, ctrl, alt)
|
||||
case f9Key:
|
||||
code += ar.longFunction("20", shift, ctrl, alt)
|
||||
case f10Key:
|
||||
code += ar.longFunction("21", shift, ctrl, alt)
|
||||
case f11Key:
|
||||
code += ar.longFunction("23", shift, ctrl, alt)
|
||||
case f12Key:
|
||||
code += ar.longFunction("24", shift, ctrl, alt)
|
||||
case insertKey:
|
||||
if shift || ctrl {
|
||||
continue
|
||||
}
|
||||
|
||||
code += ar.longFunction("2", shift, ctrl, alt)
|
||||
case deleteKey:
|
||||
code += ar.longFunction("3", shift, ctrl, alt)
|
||||
case homeKey:
|
||||
code += "OH"
|
||||
case endKey:
|
||||
code += "OF"
|
||||
case pgupKey:
|
||||
if shift {
|
||||
continue
|
||||
}
|
||||
|
||||
code += ar.longFunction("5", shift, ctrl, alt)
|
||||
case pgdownKey:
|
||||
if shift {
|
||||
continue
|
||||
}
|
||||
|
||||
code += ar.longFunction("6", shift, ctrl, alt)
|
||||
case upKey:
|
||||
code += ar.arrow("A", shift, ctrl, alt)
|
||||
case downKey:
|
||||
code += ar.arrow("B", shift, ctrl, alt)
|
||||
case leftKey:
|
||||
code += ar.arrow("D", shift, ctrl, alt)
|
||||
case rightKey:
|
||||
code += ar.arrow("C", shift, ctrl, alt)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
runes = []rune(code)
|
||||
}
|
||||
}
|
||||
|
||||
ar.buf = runes
|
||||
}
|
||||
|
||||
// Get items from the buffer.
|
||||
var n int
|
||||
for i, r := range ar.buf {
|
||||
if utf8.RuneLen(r) > len(b) {
|
||||
ar.buf = ar.buf[i:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
nr := utf8.EncodeRune(b, r)
|
||||
b = b[nr:]
|
||||
n += nr
|
||||
}
|
||||
|
||||
ar.buf = nil
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// shortFunction creates a short function code.
|
||||
func (ar *AnsiReader) shortFunction(ident string, shift, ctrl, alt bool) string {
|
||||
code := "O"
|
||||
|
||||
if shift {
|
||||
code += "1;2"
|
||||
} else if ctrl {
|
||||
code += "1;5"
|
||||
} else if alt {
|
||||
code += "1;3"
|
||||
}
|
||||
|
||||
return code + ident
|
||||
}
|
||||
|
||||
// longFunction creates a long function code.
|
||||
func (ar *AnsiReader) longFunction(ident string, shift, ctrl, alt bool) string {
|
||||
code := "["
|
||||
code += ident
|
||||
|
||||
if shift {
|
||||
code += ";2"
|
||||
} else if ctrl {
|
||||
code += ";5"
|
||||
} else if alt {
|
||||
code += ";3"
|
||||
}
|
||||
|
||||
return code + "~"
|
||||
}
|
||||
|
||||
// arrow creates an arrow code.
|
||||
func (ar *AnsiReader) arrow(ident string, shift, ctrl, alt bool) string {
|
||||
code := "["
|
||||
|
||||
if shift {
|
||||
code += "1;2"
|
||||
} else if ctrl {
|
||||
code += "1;5"
|
||||
} else if alt {
|
||||
code += "1;3"
|
||||
}
|
||||
|
||||
return code + ident
|
||||
}
|
||||
|
||||
// AnsiWriter is an io.Writer that writes to a given file and converts ANSI
|
||||
// escape codes to their equivalent Windows functionality.
|
||||
type AnsiWriter struct {
|
||||
file *os.File
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// NewAnsiWriter creates a AnsiWriter from the given output.
|
||||
func NewAnsiWriter(out *os.File) *AnsiWriter {
|
||||
return &AnsiWriter{file: out}
|
||||
}
|
||||
|
||||
// Write writes the buffer filtering out ANSI escape codes and converting to
|
||||
// the Windows functionality needed. ANSI escape codes may be found over multiple
|
||||
// Writes.
|
||||
func (aw *AnsiWriter) Write(b []byte) (int, error) {
|
||||
needsProcessing := bytes.Contains(b, []byte(string(escKey)))
|
||||
if len(aw.buf) > 0 {
|
||||
needsProcessing = true
|
||||
}
|
||||
|
||||
if !needsProcessing {
|
||||
return aw.file.Write(b)
|
||||
}
|
||||
var p []byte
|
||||
|
||||
for _, char := range b {
|
||||
// Found the beginning of an escape.
|
||||
if char == escKey {
|
||||
aw.buf = append(aw.buf, char)
|
||||
continue
|
||||
}
|
||||
|
||||
// Funtion identifiers.
|
||||
if len(aw.buf) == 1 && (char == '_' || char == 'P' || char == '[' ||
|
||||
char == ']' || char == '^' || char == ' ' || char == '#' ||
|
||||
char == '%' || char == '(' || char == ')' || char == '*' ||
|
||||
char == '+') {
|
||||
aw.buf = append(aw.buf, char)
|
||||
continue
|
||||
}
|
||||
|
||||
// Cursor functions.
|
||||
if len(aw.buf) == 1 && (char == '7' || char == '8') {
|
||||
// Add another char before because finish skips 2 items.
|
||||
aw.buf = append(aw.buf, '_', char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Keyboard functions.
|
||||
if len(aw.buf) == 1 && (char == '=' || char == '>') {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Bottom left function.
|
||||
if len(aw.buf) == 1 && char == 'F' {
|
||||
// Add extra char for finish.
|
||||
aw.buf = append(aw.buf, '_', char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Reset function.
|
||||
if len(aw.buf) == 1 && char == 'c' {
|
||||
// Add extra char for finish.
|
||||
aw.buf = append(aw.buf, '_', char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Space functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == ' ' && (char == 'F' || char == 'G' ||
|
||||
char == 'L' || char == 'M' || char == 'N') {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Number functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == '#' && (char >= '3' && char <= '6') ||
|
||||
char == '8' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Percentage functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == '%' && (char == '@' || char == 'G') {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Character set functions.
|
||||
if len(aw.buf) >= 2 && (aw.buf[1] == '(' || aw.buf[1] == ')' ||
|
||||
aw.buf[1] == '*' || aw.buf[1] == '+') && (char == '0' ||
|
||||
(char >= '4' && char <= '7') || char == '=' || (char >= 'A' &&
|
||||
char <= 'C') || char == 'E' || char == 'H' || char == 'K' ||
|
||||
char == 'Q' || char == 'R' || char == 'Y') {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// APC functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == '_' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
// End of APC.
|
||||
if char == '\\' && aw.buf[len(aw.buf)-1] == escKey {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// DC functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == 'P' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
// End of DC.
|
||||
if char == '\\' && aw.buf[len(aw.buf)-1] == escKey {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// CSI functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == '[' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
// End of CSI.
|
||||
if char == '@' || (char >= 'A' && char <= 'M') || char == 'P' ||
|
||||
char == 'S' || char == 'T' || char == 'X' || char == 'Z' ||
|
||||
char == '`' || (char >= 'b' && char <= 'd') || (char >= 'f' &&
|
||||
char <= 'i') || (char >= 'l' && char <= 'n') || (char >= 'p' &&
|
||||
char <= 't') || char == 'w' || char == 'x' || char == 'z' ||
|
||||
char == '{' || char == '|' {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// OSC functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == ']' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
// Capture incomplete code.
|
||||
if len(aw.buf) == 4 && aw.buf[2] == '0' && char == ';' {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// End of OSC.
|
||||
if (char == '\\' && aw.buf[len(aw.buf)-1] == escKey) || char == ctrlG {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// PM functions.
|
||||
if len(aw.buf) >= 2 && aw.buf[1] == '^' {
|
||||
aw.buf = append(aw.buf, char)
|
||||
|
||||
// End of PM.
|
||||
if char == '\\' && aw.buf[len(aw.buf)-1] == escKey {
|
||||
err := aw.finish(nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Normal character, resets escape buffer.
|
||||
if len(aw.buf) > 0 {
|
||||
aw.buf = nil
|
||||
}
|
||||
p = append(p, char)
|
||||
}
|
||||
|
||||
_, err := aw.file.Write(p)
|
||||
return len(b), err
|
||||
}
|
||||
|
||||
// finish finishes an ANSI escape code and calls the parsing function. Afterwards
|
||||
// the escape buffer is emptied.
|
||||
func (aw *AnsiWriter) finish(parse func([]byte) error) error {
|
||||
var err error
|
||||
|
||||
if parse != nil {
|
||||
err = parse(aw.buf[2:])
|
||||
}
|
||||
|
||||
aw.buf = nil
|
||||
return err
|
||||
}
|
152
tools/vendor/github.com/Bowery/prompt/buffer.go
generated
vendored
152
tools/vendor/github.com/Bowery/prompt/buffer.go
generated
vendored
@ -1,152 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Buffer contains state for line editing and writing.
|
||||
type Buffer struct {
|
||||
Out *os.File
|
||||
Prompt string
|
||||
Echo bool
|
||||
Cols int
|
||||
pos int
|
||||
size int
|
||||
data []rune
|
||||
}
|
||||
|
||||
// NewBuffer creates a buffer writing to out if echo is true.
|
||||
func NewBuffer(prompt string, out *os.File, echo bool) *Buffer {
|
||||
return &Buffer{
|
||||
Out: out,
|
||||
Prompt: prompt,
|
||||
Echo: echo,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the data as a string.
|
||||
func (buf *Buffer) String() string {
|
||||
return string(buf.data[:buf.size])
|
||||
}
|
||||
|
||||
// Insert inserts characters at the cursors position.
|
||||
func (buf *Buffer) Insert(rs ...rune) error {
|
||||
rsLen := len(rs)
|
||||
total := buf.size + rsLen
|
||||
|
||||
if total > len(buf.data) {
|
||||
buf.data = append(buf.data, make([]rune, rsLen)...)
|
||||
}
|
||||
|
||||
// Shift characters to make room in the correct pos.
|
||||
if buf.size != buf.pos {
|
||||
copy(buf.data[buf.pos+rsLen:buf.size+rsLen], buf.data[buf.pos:buf.size])
|
||||
}
|
||||
|
||||
for _, r := range rs {
|
||||
buf.data[buf.pos] = r
|
||||
buf.pos++
|
||||
buf.size++
|
||||
}
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// Set sets the content in the buffer.
|
||||
func (buf *Buffer) Set(rs ...rune) error {
|
||||
rsLen := len(rs)
|
||||
buf.data = rs
|
||||
buf.pos = rsLen
|
||||
buf.size = rsLen
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// Start moves the cursor to the start.
|
||||
func (buf *Buffer) Start() error {
|
||||
if buf.pos <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf.pos = 0
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// End moves the cursor to the end.
|
||||
func (buf *Buffer) End() error {
|
||||
if buf.pos >= buf.size {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf.pos = buf.size
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// Left moves the cursor one character left.
|
||||
func (buf *Buffer) Left() error {
|
||||
if buf.pos <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf.pos--
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// Right moves the cursor one character right.
|
||||
func (buf *Buffer) Right() error {
|
||||
if buf.pos >= buf.size {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf.pos++
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// Del removes the character at the cursor position.
|
||||
func (buf *Buffer) Del() error {
|
||||
if buf.pos >= buf.size {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shift characters after position back one.
|
||||
copy(buf.data[buf.pos:], buf.data[buf.pos+1:buf.size])
|
||||
buf.size--
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// DelLeft removes the character to the left.
|
||||
func (buf *Buffer) DelLeft() error {
|
||||
if buf.pos <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shift characters from position back one.
|
||||
copy(buf.data[buf.pos-1:], buf.data[buf.pos:buf.size])
|
||||
buf.pos--
|
||||
buf.size--
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// EndLine ends the line with CRLF.
|
||||
func (buf *Buffer) EndLine() error {
|
||||
_, err := buf.Out.Write(crlf)
|
||||
return err
|
||||
}
|
||||
|
||||
// toBytes converts a slice of runes to its equivalent in bytes.
|
||||
func toBytes(runes []rune) []byte {
|
||||
var bytes []byte
|
||||
char := make([]byte, utf8.UTFMax)
|
||||
|
||||
for _, r := range runes {
|
||||
n := utf8.EncodeRune(char, r)
|
||||
bytes = append(bytes, char[:n]...)
|
||||
}
|
||||
|
||||
return bytes
|
||||
}
|
76
tools/vendor/github.com/Bowery/prompt/buffer_unix.go
generated
vendored
76
tools/vendor/github.com/Bowery/prompt/buffer_unix.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly solaris
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Refresh rewrites the prompt and buffer.
|
||||
func (buf *Buffer) Refresh() error {
|
||||
// If we're not echoing just write prompt.
|
||||
if !buf.Echo {
|
||||
_, err := buf.Out.Write(mvLeftEdge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write([]byte(buf.Prompt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write(delRight)
|
||||
return err
|
||||
}
|
||||
|
||||
prLen := len(buf.Prompt)
|
||||
start := 0
|
||||
size := buf.size
|
||||
pos := buf.pos
|
||||
|
||||
// Get slice range that should be visible.
|
||||
for prLen+pos >= buf.Cols {
|
||||
start++
|
||||
size--
|
||||
pos--
|
||||
}
|
||||
for prLen+size > buf.Cols {
|
||||
size--
|
||||
}
|
||||
|
||||
_, err := buf.Out.Write(mvLeftEdge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write([]byte(buf.Prompt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write(toBytes(buf.data[start : size+start]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write(delRight)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write([]byte(fmt.Sprintf(mvToCol, pos+prLen)))
|
||||
return err
|
||||
}
|
||||
|
||||
// ClsScreen clears the screen and refreshes.
|
||||
func (buf *Buffer) ClsScreen() error {
|
||||
_, err := buf.Out.Write(clsScreen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
150
tools/vendor/github.com/Bowery/prompt/buffer_windows.go
generated
vendored
150
tools/vendor/github.com/Bowery/prompt/buffer_windows.go
generated
vendored
@ -1,150 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
fillConsoleOutputCharacter = kernel.NewProc("FillConsoleOutputCharacterW")
|
||||
setConsoleCursorPosition = kernel.NewProc("SetConsoleCursorPosition")
|
||||
)
|
||||
|
||||
// Refresh rewrites the prompt and buffer.
|
||||
func (buf *Buffer) Refresh() error {
|
||||
csbi := new(consoleScreenBufferInfo)
|
||||
ret, _, err := getConsoleScreenBufferInfo.Call(buf.Out.Fd(),
|
||||
uintptr(unsafe.Pointer(csbi)))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not echoing just write prompt.
|
||||
if !buf.Echo {
|
||||
err = buf.delLine(csbi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = buf.mvLeftEdge(csbi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write([]byte(buf.Prompt))
|
||||
return err
|
||||
}
|
||||
|
||||
prLen := len(buf.Prompt)
|
||||
start := 0
|
||||
size := buf.size
|
||||
pos := buf.pos
|
||||
|
||||
// Get slice range that should be visible.
|
||||
for prLen+pos >= buf.Cols {
|
||||
start++
|
||||
size--
|
||||
pos--
|
||||
}
|
||||
for prLen+size > buf.Cols {
|
||||
size--
|
||||
}
|
||||
|
||||
err = buf.delLine(csbi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = buf.mvLeftEdge(csbi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write([]byte(buf.Prompt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.Out.Write(toBytes(buf.data[start : size+start]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return buf.mvToCol(csbi, pos+prLen)
|
||||
}
|
||||
|
||||
// ClsScreen clears the screen and refreshes.
|
||||
func (buf *Buffer) ClsScreen() error {
|
||||
var written uint32
|
||||
coords := new(coord)
|
||||
|
||||
csbi := new(consoleScreenBufferInfo)
|
||||
ret, _, err := getConsoleScreenBufferInfo.Call(buf.Out.Fd(),
|
||||
uintptr(unsafe.Pointer(csbi)))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear everything from 0,0.
|
||||
ret, _, err = fillConsoleOutputCharacter.Call(buf.Out.Fd(), uintptr(' '),
|
||||
uintptr(csbi.size.x*csbi.size.y), uintptr(*(*int32)(unsafe.Pointer(coords))),
|
||||
uintptr(unsafe.Pointer(&written)))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set cursor at 0,0.
|
||||
ret, _, err = setConsoleCursorPosition.Call(buf.Out.Fd(),
|
||||
uintptr(*(*int32)(unsafe.Pointer(coords))))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return buf.Refresh()
|
||||
}
|
||||
|
||||
// delLine deletes the line the csbi cursor is positioned on.
|
||||
// TODO: Possible refresh jittering reason, instead we should copy the Unix
|
||||
// code and write over contents and then remove everything to the right.
|
||||
func (buf *Buffer) delLine(csbi *consoleScreenBufferInfo) error {
|
||||
var written uint32
|
||||
coords := &coord{y: csbi.cursorPosition.y}
|
||||
|
||||
ret, _, err := fillConsoleOutputCharacter.Call(buf.Out.Fd(), uintptr(' '),
|
||||
uintptr(csbi.size.x), uintptr(*(*int32)(unsafe.Pointer(coords))),
|
||||
uintptr(unsafe.Pointer(&written)))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mvLeftEdge moves the cursor to the beginning of the line the csbi cursor
|
||||
// is positioned on.
|
||||
func (buf *Buffer) mvLeftEdge(csbi *consoleScreenBufferInfo) error {
|
||||
coords := &coord{y: csbi.cursorPosition.y}
|
||||
|
||||
ret, _, err := setConsoleCursorPosition.Call(buf.Out.Fd(),
|
||||
uintptr(*(*int32)(unsafe.Pointer(coords))))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mvTolCol moves the cursor to the col on the line the csbi cursor is
|
||||
// positioned on.
|
||||
func (buf *Buffer) mvToCol(csbi *consoleScreenBufferInfo, x int) error {
|
||||
coords := &coord{x: int16(x), y: csbi.cursorPosition.y}
|
||||
|
||||
ret, _, err := setConsoleCursorPosition.Call(buf.Out.Fd(),
|
||||
uintptr(*(*int32)(unsafe.Pointer(coords))))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
15
tools/vendor/github.com/Bowery/prompt/ioctl_bsd.go
generated
vendored
15
tools/vendor/github.com/Bowery/prompt/ioctl_bsd.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
tcgets = unix.TIOCGETA
|
||||
tcsets = unix.TIOCSETA
|
||||
tcsetsf = unix.TIOCSETAF
|
||||
)
|
13
tools/vendor/github.com/Bowery/prompt/ioctl_linux.go
generated
vendored
13
tools/vendor/github.com/Bowery/prompt/ioctl_linux.go
generated
vendored
@ -1,13 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
tcgets = unix.TCGETS
|
||||
tcsets = unix.TCSETS
|
||||
tcsetsf = unix.TCSETSF
|
||||
)
|
41
tools/vendor/github.com/Bowery/prompt/ioctl_solaris.go
generated
vendored
41
tools/vendor/github.com/Bowery/prompt/ioctl_solaris.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
tcgets = unix.TCGETS
|
||||
tcsetsf = unix.TCSETSF
|
||||
tcsets = unix.TCSETS
|
||||
)
|
||||
|
||||
// terminalSize retrieves the cols/rows for the terminal connected to out.
|
||||
func terminalSize(out *os.File) (int, int, error) {
|
||||
ws, err := unix.IoctlGetWinsize(int(out.Fd()), unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int(ws.Col), int(ws.Row), nil
|
||||
}
|
||||
|
||||
// getTermios retrieves the termios settings for the terminal descriptor.
|
||||
func getTermios(fd uintptr) (*unix.Termios, error) {
|
||||
return unix.IoctlGetTermios(int(fd), tcgets)
|
||||
}
|
||||
|
||||
// setTermios sets the termios settings for the terminal descriptor,
|
||||
// optionally flushing the buffer before setting.
|
||||
func setTermios(fd uintptr, flush bool, mode *unix.Termios) error {
|
||||
req := tcsets
|
||||
if flush {
|
||||
req = tcsetsf
|
||||
}
|
||||
|
||||
return unix.IoctlSetTermios(int(fd), req, mode)
|
||||
}
|
62
tools/vendor/github.com/Bowery/prompt/ioctl_unix.go
generated
vendored
62
tools/vendor/github.com/Bowery/prompt/ioctl_unix.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// winsize contains the size for the terminal.
|
||||
type winsize struct {
|
||||
rows uint16
|
||||
cols uint16
|
||||
_ uint32
|
||||
}
|
||||
|
||||
// terminalSize retrieves the cols/rows for the terminal connected to out.
|
||||
func terminalSize(out *os.File) (int, int, error) {
|
||||
ws := new(winsize)
|
||||
|
||||
_, _, err := unix.Syscall(unix.SYS_IOCTL, out.Fd(),
|
||||
uintptr(unix.TIOCGWINSZ), uintptr(unsafe.Pointer(ws)))
|
||||
if err != 0 {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int(ws.cols), int(ws.rows), nil
|
||||
}
|
||||
|
||||
// getTermios retrieves the termios settings for the terminal descriptor.
|
||||
func getTermios(fd uintptr) (*unix.Termios, error) {
|
||||
termios := new(unix.Termios)
|
||||
|
||||
_, _, err := unix.Syscall(unix.SYS_IOCTL, fd, tcgets,
|
||||
uintptr(unsafe.Pointer(termios)))
|
||||
if err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return termios, nil
|
||||
}
|
||||
|
||||
// setTermios sets the termios settings for the terminal descriptor,
|
||||
// optionally flushing the buffer before setting.
|
||||
func setTermios(fd uintptr, flush bool, mode *unix.Termios) error {
|
||||
req := tcsets
|
||||
if flush {
|
||||
req = tcsetsf
|
||||
}
|
||||
|
||||
_, _, err := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(req),
|
||||
uintptr(unsafe.Pointer(mode)))
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
41
tools/vendor/github.com/Bowery/prompt/keys.go
generated
vendored
41
tools/vendor/github.com/Bowery/prompt/keys.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
// Line ending in raw mode.
|
||||
var crlf = []byte("\r\n")
|
||||
|
||||
const (
|
||||
backKey = '\u007f'
|
||||
escKey = '\u001B'
|
||||
spaceKey = '\u0020'
|
||||
)
|
||||
|
||||
const (
|
||||
ctrlA = iota + 1
|
||||
ctrlB
|
||||
ctrlC
|
||||
ctrlD
|
||||
ctrlE
|
||||
ctrlF
|
||||
ctrlG
|
||||
ctrlH
|
||||
tabKey
|
||||
ctrlJ
|
||||
ctrlK
|
||||
ctrlL
|
||||
returnKey
|
||||
ctrlN
|
||||
ctrlO
|
||||
ctrlP
|
||||
ctrlQ
|
||||
ctrlR
|
||||
ctrlS
|
||||
ctrlT
|
||||
ctrlU
|
||||
ctrlV
|
||||
ctrlW
|
||||
ctrlX
|
||||
ctrlY
|
||||
ctrlZ
|
||||
)
|
13
tools/vendor/github.com/Bowery/prompt/keys_unix.go
generated
vendored
13
tools/vendor/github.com/Bowery/prompt/keys_unix.go
generated
vendored
@ -1,13 +0,0 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly solaris
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
const mvToCol = "\u001b[0G\u001b[%dC"
|
||||
|
||||
var (
|
||||
mvLeftEdge = []byte("\u001b[0G")
|
||||
clsScreen = []byte("\u001b[H\u001b[2J")
|
||||
delRight = []byte("\u001b[0K")
|
||||
)
|
34
tools/vendor/github.com/Bowery/prompt/keys_windows.go
generated
vendored
34
tools/vendor/github.com/Bowery/prompt/keys_windows.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
const (
|
||||
f1Key = 0x70 + iota
|
||||
f2Key
|
||||
f3Key
|
||||
f4Key
|
||||
f5Key
|
||||
f6Key
|
||||
f7Key
|
||||
f8Key
|
||||
f9Key
|
||||
f10Key
|
||||
f11Key
|
||||
f12Key
|
||||
|
||||
homeKey = 0x24
|
||||
endKey = 0x23
|
||||
upKey = 0x26
|
||||
downKey = 0x28
|
||||
rightKey = 0x27
|
||||
leftKey = 0x25
|
||||
insertKey = 0x2d
|
||||
pgupKey = 0x21
|
||||
pgdownKey = 0x22
|
||||
deleteKey = 0x2e
|
||||
leftAltKey = 0x2
|
||||
rightAltKey = 0x1
|
||||
leftCtrlKey = 0x8
|
||||
rightCtrlKey = 0x4
|
||||
shiftKey = 0x10
|
||||
)
|
85
tools/vendor/github.com/Bowery/prompt/prompt.go
generated
vendored
85
tools/vendor/github.com/Bowery/prompt/prompt.go
generated
vendored
@ -1,85 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
// Package prompt implements a cross platform line-editing prompt. It also
|
||||
// provides routines to use ANSI escape sequences across platforms for
|
||||
// terminal connected io.Readers/io.Writers.
|
||||
//
|
||||
// If os.Stdin isn't connected to a terminal or (on Unix)if the terminal
|
||||
// doesn't support the ANSI escape sequences needed a fallback prompt is
|
||||
// provided that doesn't do line-editing. Unix terminals that are not supported
|
||||
// will have the TERM environment variable set to either "dumb" or "cons25".
|
||||
//
|
||||
// The keyboard shortcuts are similar to those found in the Readline library:
|
||||
//
|
||||
// - Enter / CTRL+D
|
||||
// - End the line.
|
||||
// - CTRL+C
|
||||
// - End the line, return error `ErrCTRLC`.
|
||||
// - Backspace
|
||||
// - Remove the character to the left.
|
||||
// - CTRL+L
|
||||
// - Clear the screen(keeping the current lines content).
|
||||
// - Home / End
|
||||
// - Jump to the beginning/end of the line.
|
||||
// - Up arrow / Down arrow
|
||||
// - Go back and forward in the history.
|
||||
// - Left arrow / Right arrow
|
||||
// - Move left/right one character.
|
||||
// - Delete
|
||||
// - Remove the character to the right.
|
||||
package prompt
|
||||
|
||||
// Basic is a wrapper around Terminal.Basic.
|
||||
func Basic(prefix string, required bool) (string, error) {
|
||||
term, err := NewTerminal()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer term.Close()
|
||||
|
||||
return term.Basic(prefix, required)
|
||||
}
|
||||
|
||||
// BasicDefault is a wrapper around Terminal.BasicDefault.
|
||||
func BasicDefault(prefix, def string) (string, error) {
|
||||
term, err := NewTerminal()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer term.Close()
|
||||
|
||||
return term.BasicDefault(prefix, def)
|
||||
}
|
||||
|
||||
// Ask is a wrapper around Terminal.Ask.
|
||||
func Ask(question string) (bool, error) {
|
||||
term, err := NewTerminal()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer term.Close()
|
||||
|
||||
return term.Ask(question)
|
||||
}
|
||||
|
||||
// Custom is a wrapper around Terminal.Custom.
|
||||
func Custom(prefix string, test func(string) (string, bool)) (string, error) {
|
||||
term, err := NewTerminal()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer term.Close()
|
||||
|
||||
return term.Custom(prefix, test)
|
||||
}
|
||||
|
||||
// Password is a wrapper around Terminal.Password.
|
||||
func Password(prefix string) (string, error) {
|
||||
term, err := NewTerminal()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer term.Close()
|
||||
|
||||
return term.Password(prefix)
|
||||
}
|
471
tools/vendor/github.com/Bowery/prompt/term.go
generated
vendored
471
tools/vendor/github.com/Bowery/prompt/term.go
generated
vendored
@ -1,471 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCTRLC is returned when CTRL+C is pressed stopping the prompt.
|
||||
ErrCTRLC = errors.New("Interrupted (CTRL+C)")
|
||||
// ErrEOF is returned when CTRL+D is pressed stopping the prompt.
|
||||
ErrEOF = errors.New("EOF (CTRL+D)")
|
||||
)
|
||||
|
||||
// Possible events that may occur when reading from input.
|
||||
const (
|
||||
evChar = iota
|
||||
evSkip
|
||||
evReturn
|
||||
evEOF
|
||||
evCtrlC
|
||||
evBack
|
||||
evClear
|
||||
evHome
|
||||
evEnd
|
||||
evUp
|
||||
evDown
|
||||
evRight
|
||||
evLeft
|
||||
evDel
|
||||
)
|
||||
|
||||
// IsNotTerminal checks if an error is related to the input not being a terminal.
|
||||
func IsNotTerminal(err error) bool {
|
||||
return isNotTerminal(err)
|
||||
}
|
||||
|
||||
// TerminalSize retrieves the columns/rows for the terminal connected to out.
|
||||
func TerminalSize(out *os.File) (int, int, error) {
|
||||
return terminalSize(out)
|
||||
}
|
||||
|
||||
// Terminal contains the state for raw terminal input.
|
||||
type Terminal struct {
|
||||
In *os.File
|
||||
Out *os.File
|
||||
History []string
|
||||
histIdx int
|
||||
simpleReader *bufio.Reader
|
||||
t *terminal
|
||||
}
|
||||
|
||||
// NewTerminal creates a terminal and sets it to raw input mode.
|
||||
func NewTerminal() (*Terminal, error) {
|
||||
in := os.Stdin
|
||||
|
||||
term, err := newTerminal(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Terminal{
|
||||
In: in,
|
||||
Out: os.Stdout,
|
||||
History: make([]string, 0, 10),
|
||||
histIdx: -1,
|
||||
t: term,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Basic gets input and if required tests to ensure input was given.
|
||||
func (term *Terminal) Basic(prefix string, required bool) (string, error) {
|
||||
return term.Custom(prefix, func(input string) (string, bool) {
|
||||
if required && input == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return input, true
|
||||
})
|
||||
}
|
||||
|
||||
// BasicDefault gets input and if empty uses the given default.
|
||||
func (term *Terminal) BasicDefault(prefix, def string) (string, error) {
|
||||
return term.Custom(prefix+"(Default: "+def+")", func(input string) (string, bool) {
|
||||
if input == "" {
|
||||
input = def
|
||||
}
|
||||
|
||||
return input, true
|
||||
})
|
||||
}
|
||||
|
||||
// Ask gets input and checks if it's truthy or not, and returns that
|
||||
// in a boolean fashion.
|
||||
func (term *Terminal) Ask(question string) (bool, error) {
|
||||
input, err := term.Custom(question+"?(y/n)", func(input string) (string, bool) {
|
||||
if input == "" {
|
||||
return "", false
|
||||
}
|
||||
input = strings.ToLower(input)
|
||||
|
||||
if input == "y" || input == "yes" {
|
||||
return "yes", true
|
||||
}
|
||||
|
||||
return "", true
|
||||
})
|
||||
|
||||
var ok bool
|
||||
if input != "" {
|
||||
ok = true
|
||||
}
|
||||
|
||||
return ok, err
|
||||
}
|
||||
|
||||
// Custom gets input and calls the given test function with the input to
|
||||
// check if the input is valid, a true return will return the string.
|
||||
func (term *Terminal) Custom(prefix string, test func(string) (string, bool)) (string, error) {
|
||||
var err error
|
||||
var input string
|
||||
var ok bool
|
||||
|
||||
for !ok {
|
||||
input, err = term.GetPrompt(prefix)
|
||||
if err != nil && err != io.EOF {
|
||||
return "", err
|
||||
}
|
||||
|
||||
input, ok = test(input)
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// Password retrieves a password from stdin without echoing it.
|
||||
func (term *Terminal) Password(prefix string) (string, error) {
|
||||
var err error
|
||||
var input string
|
||||
|
||||
for input == "" {
|
||||
input, err = term.GetPassword(prefix)
|
||||
if err != nil && err != io.EOF {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// GetPrompt gets a line with the prefix and echos input.
|
||||
func (term *Terminal) GetPrompt(prefix string) (string, error) {
|
||||
if !term.t.supportsEditing {
|
||||
return term.simplePrompt(prefix)
|
||||
}
|
||||
|
||||
buf := NewBuffer(prefix, term.Out, true)
|
||||
return term.prompt(buf, NewAnsiReader(term.In))
|
||||
}
|
||||
|
||||
// GetPassword gets a line with the prefix and doesn't echo input.
|
||||
func (term *Terminal) GetPassword(prefix string) (string, error) {
|
||||
if !term.t.supportsEditing {
|
||||
return term.simplePrompt(prefix)
|
||||
}
|
||||
|
||||
buf := NewBuffer(prefix, term.Out, false)
|
||||
return term.password(buf, NewAnsiReader(term.In))
|
||||
}
|
||||
|
||||
func (term *Terminal) Close() error {
|
||||
return term.t.Close()
|
||||
}
|
||||
|
||||
// simplePrompt is a fallback prompt without line editing support.
|
||||
func (term *Terminal) simplePrompt(prefix string) (string, error) {
|
||||
if term.simpleReader == nil {
|
||||
term.simpleReader = bufio.NewReader(term.In)
|
||||
}
|
||||
|
||||
_, err := term.Out.Write([]byte(prefix))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
line, err := term.simpleReader.ReadString('\n')
|
||||
line = strings.TrimRight(line, "\r\n ")
|
||||
line = strings.TrimLeft(line, " ")
|
||||
|
||||
return line, err
|
||||
}
|
||||
|
||||
// setup initializes a prompt.
|
||||
func (term *Terminal) setup(buf *Buffer, in io.Reader) (*bufio.Reader, error) {
|
||||
cols, _, err := TerminalSize(buf.Out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf.Cols = cols
|
||||
input := bufio.NewReader(in)
|
||||
|
||||
err = buf.Refresh()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// read reads a rune and parses ANSI escape sequences found
|
||||
func (term *Terminal) read(in *bufio.Reader) (int, rune, error) {
|
||||
char, _, err := in.ReadRune()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
switch char {
|
||||
default:
|
||||
// Standard chars.
|
||||
return evChar, char, nil
|
||||
case tabKey, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlH, ctrlJ, ctrlK, ctrlN,
|
||||
ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX,
|
||||
ctrlY, ctrlZ:
|
||||
// Skip.
|
||||
return evSkip, char, nil
|
||||
case returnKey:
|
||||
// End of line.
|
||||
return evReturn, char, nil
|
||||
case ctrlD:
|
||||
// End of file.
|
||||
return evEOF, char, nil
|
||||
case ctrlC:
|
||||
// End of line, interrupted.
|
||||
return evCtrlC, char, nil
|
||||
case backKey:
|
||||
// Backspace.
|
||||
return evBack, char, nil
|
||||
case ctrlL:
|
||||
// Clear screen.
|
||||
return evClear, char, nil
|
||||
case escKey:
|
||||
// Functions like arrows, home, etc.
|
||||
esc := make([]byte, 2)
|
||||
_, err = in.Read(esc)
|
||||
if err != nil {
|
||||
return -1, char, err
|
||||
}
|
||||
|
||||
// Home, end.
|
||||
if esc[0] == 'O' {
|
||||
switch esc[1] {
|
||||
case 'H':
|
||||
// Home.
|
||||
return evHome, char, nil
|
||||
case 'F':
|
||||
// End.
|
||||
return evEnd, char, nil
|
||||
}
|
||||
|
||||
return evSkip, char, nil
|
||||
}
|
||||
|
||||
// Arrows, delete, pgup, pgdown, insert.
|
||||
if esc[0] == '[' {
|
||||
switch esc[1] {
|
||||
case 'A':
|
||||
// Up.
|
||||
return evUp, char, nil
|
||||
case 'B':
|
||||
// Down.
|
||||
return evDown, char, nil
|
||||
case 'C':
|
||||
// Right.
|
||||
return evRight, char, nil
|
||||
case 'D':
|
||||
// Left.
|
||||
return evLeft, char, nil
|
||||
}
|
||||
|
||||
// Delete, pgup, pgdown, insert.
|
||||
if esc[1] > '0' && esc[1] < '7' {
|
||||
extEsc := make([]byte, 3)
|
||||
_, err = in.Read(extEsc)
|
||||
if err != nil {
|
||||
return -1, char, err
|
||||
}
|
||||
|
||||
if extEsc[0] == '~' {
|
||||
switch esc[1] {
|
||||
case '2', '5', '6':
|
||||
// Insert, pgup, pgdown.
|
||||
return evSkip, char, err
|
||||
case '3':
|
||||
// Delete.
|
||||
return evDel, char, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return evSkip, char, nil
|
||||
}
|
||||
|
||||
// prompt reads from in and parses ANSI escapes writing to buf.
|
||||
func (term *Terminal) prompt(buf *Buffer, in io.Reader) (string, error) {
|
||||
input, err := term.setup(buf, in)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
term.History = append(term.History, "")
|
||||
term.histIdx = len(term.History) - 1
|
||||
curHistIdx := term.histIdx
|
||||
|
||||
for {
|
||||
typ, char, err := term.read(input)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case evChar:
|
||||
err = buf.Insert(char)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
term.History[curHistIdx] = buf.String()
|
||||
case evSkip:
|
||||
continue
|
||||
case evReturn:
|
||||
err = buf.EndLine()
|
||||
return buf.String(), err
|
||||
case evEOF:
|
||||
err = buf.EndLine()
|
||||
if err == nil {
|
||||
err = ErrEOF
|
||||
}
|
||||
|
||||
return buf.String(), err
|
||||
case evCtrlC:
|
||||
err = buf.EndLine()
|
||||
if err == nil {
|
||||
err = ErrCTRLC
|
||||
}
|
||||
|
||||
return buf.String(), err
|
||||
case evBack:
|
||||
err = buf.DelLeft()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
term.History[curHistIdx] = buf.String()
|
||||
case evClear:
|
||||
err = buf.ClsScreen()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evHome:
|
||||
err = buf.Start()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evEnd:
|
||||
err = buf.End()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evUp:
|
||||
idx := term.histIdx
|
||||
if term.histIdx > 0 {
|
||||
idx--
|
||||
}
|
||||
|
||||
err = buf.Set([]rune(term.History[idx])...)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
term.histIdx = idx
|
||||
case evDown:
|
||||
idx := term.histIdx
|
||||
if term.histIdx < len(term.History)-1 {
|
||||
idx++
|
||||
}
|
||||
|
||||
err = buf.Set([]rune(term.History[idx])...)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
term.histIdx = idx
|
||||
case evRight:
|
||||
err = buf.Right()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evLeft:
|
||||
err = buf.Left()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evDel:
|
||||
err = buf.Del()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
term.History[curHistIdx] = buf.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// password reads from in and parses restricted ANSI escapes writing to buf.
|
||||
func (term *Terminal) password(buf *Buffer, in io.Reader) (string, error) {
|
||||
input, err := term.setup(buf, in)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
typ, char, err := term.read(input)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case evChar:
|
||||
err = buf.Insert(char)
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evSkip, evHome, evEnd, evUp, evDown, evRight, evLeft, evDel:
|
||||
continue
|
||||
case evReturn:
|
||||
err = buf.EndLine()
|
||||
return buf.String(), err
|
||||
case evEOF:
|
||||
err = buf.EndLine()
|
||||
if err == nil {
|
||||
err = ErrEOF
|
||||
}
|
||||
|
||||
return buf.String(), err
|
||||
case evCtrlC:
|
||||
err = buf.EndLine()
|
||||
if err == nil {
|
||||
err = ErrCTRLC
|
||||
}
|
||||
|
||||
return buf.String(), err
|
||||
case evBack:
|
||||
err = buf.DelLeft()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
case evClear:
|
||||
err = buf.ClsScreen()
|
||||
if err != nil {
|
||||
return buf.String(), err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
tools/vendor/github.com/Bowery/prompt/term_unix.go
generated
vendored
96
tools/vendor/github.com/Bowery/prompt/term_unix.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly solaris
|
||||
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// List of unsupported $TERM values.
|
||||
var unsupported = []string{"", "dumb", "cons25"}
|
||||
|
||||
// supportsEditing checks if the terminal supports ansi escapes.
|
||||
func supportsEditing() bool {
|
||||
term := os.Getenv("TERM")
|
||||
|
||||
for _, t := range unsupported {
|
||||
if t == term {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// isNotTerminal checks if an error is related to the input not being a terminal.
|
||||
func isNotTerminal(err error) bool {
|
||||
return err == unix.ENOTTY
|
||||
}
|
||||
|
||||
// terminal contains the private fields for a Unix terminal.
|
||||
type terminal struct {
|
||||
supportsEditing bool
|
||||
fd uintptr
|
||||
origMode unix.Termios
|
||||
}
|
||||
|
||||
// newTerminal creates a terminal and sets it to raw input mode.
|
||||
func newTerminal(in *os.File) (*terminal, error) {
|
||||
term := &terminal{fd: in.Fd()}
|
||||
|
||||
if !supportsEditing() {
|
||||
return term, nil
|
||||
}
|
||||
|
||||
t, err := getTermios(term.fd)
|
||||
if err != nil {
|
||||
if IsNotTerminal(err) {
|
||||
return term, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
term.origMode = *t
|
||||
mode := term.origMode
|
||||
term.supportsEditing = true
|
||||
|
||||
// Set new mode flags, for reference see cfmakeraw(3).
|
||||
mode.Iflag &^= (unix.BRKINT | unix.IGNBRK | unix.ICRNL |
|
||||
unix.INLCR | unix.IGNCR | unix.ISTRIP | unix.IXON |
|
||||
unix.PARMRK)
|
||||
|
||||
mode.Oflag &^= unix.OPOST
|
||||
|
||||
mode.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON |
|
||||
unix.ISIG | unix.IEXTEN)
|
||||
|
||||
mode.Cflag &^= (unix.CSIZE | unix.PARENB)
|
||||
mode.Cflag |= unix.CS8
|
||||
|
||||
// Set controls; min num of bytes, and timeouts.
|
||||
mode.Cc[unix.VMIN] = 1
|
||||
mode.Cc[unix.VTIME] = 0
|
||||
|
||||
err = setTermios(term.fd, true, &mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return term, nil
|
||||
}
|
||||
|
||||
// Close disables the terminals raw input.
|
||||
func (term *terminal) Close() error {
|
||||
if term.supportsEditing {
|
||||
err := setTermios(term.fd, false, &term.origMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
116
tools/vendor/github.com/Bowery/prompt/term_windows.go
generated
vendored
116
tools/vendor/github.com/Bowery/prompt/term_windows.go
generated
vendored
@ -1,116 +0,0 @@
|
||||
// Copyright 2013-2015 Bowery, Inc.
|
||||
|
||||
package prompt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Flags to control the terminals mode.
|
||||
const (
|
||||
echoInputFlag = 0x0004
|
||||
insertModeFlag = 0x0020
|
||||
lineInputFlag = 0x0002
|
||||
mouseInputFlag = 0x0010
|
||||
processedInputFlag = 0x0001
|
||||
windowInputFlag = 0x0008
|
||||
)
|
||||
|
||||
// Error number returned for an invalid handle.
|
||||
const errnoInvalidHandle = 0x6
|
||||
|
||||
var (
|
||||
kernel = syscall.NewLazyDLL("kernel32.dll")
|
||||
getConsoleScreenBufferInfo = kernel.NewProc("GetConsoleScreenBufferInfo")
|
||||
setConsoleMode = kernel.NewProc("SetConsoleMode")
|
||||
)
|
||||
|
||||
// consoleScreenBufferInfo contains various fields for the terminal.
|
||||
type consoleScreenBufferInfo struct {
|
||||
size coord
|
||||
cursorPosition coord
|
||||
attributes uint16
|
||||
window smallRect
|
||||
maximumWindowSize coord
|
||||
}
|
||||
|
||||
// coord contains coords for positioning.
|
||||
type coord struct {
|
||||
x int16
|
||||
y int16
|
||||
}
|
||||
|
||||
// smallRect contains positions for the window edges.
|
||||
type smallRect struct {
|
||||
left int16
|
||||
top int16
|
||||
right int16
|
||||
bottom int16
|
||||
}
|
||||
|
||||
// terminalSize retrieves the cols/rows for the terminal connected to out.
|
||||
func terminalSize(out *os.File) (int, int, error) {
|
||||
csbi := new(consoleScreenBufferInfo)
|
||||
|
||||
ret, _, err := getConsoleScreenBufferInfo.Call(out.Fd(), uintptr(unsafe.Pointer(csbi)))
|
||||
if ret == 0 {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
// Results are always off by one.
|
||||
cols := csbi.window.right - csbi.window.left + 1
|
||||
rows := csbi.window.bottom - csbi.window.top + 1
|
||||
|
||||
return int(cols), int(rows), nil
|
||||
}
|
||||
|
||||
// isNotTerminal checks if an error is related to the input not being a terminal.
|
||||
func isNotTerminal(err error) bool {
|
||||
errno, ok := err.(syscall.Errno)
|
||||
|
||||
return ok && errno == errnoInvalidHandle
|
||||
}
|
||||
|
||||
// terminal contains the private fields for a Windows terminal.
|
||||
type terminal struct {
|
||||
supportsEditing bool
|
||||
fd uintptr
|
||||
origMode uint32
|
||||
}
|
||||
|
||||
// newTerminal creates a terminal and sets it to raw input mode.
|
||||
func newTerminal(in *os.File) (*terminal, error) {
|
||||
term := &terminal{fd: in.Fd()}
|
||||
|
||||
err := syscall.GetConsoleMode(syscall.Handle(term.fd), &term.origMode)
|
||||
if err != nil {
|
||||
return term, nil
|
||||
}
|
||||
mode := term.origMode
|
||||
term.supportsEditing = true
|
||||
|
||||
// Set new mode flags.
|
||||
mode &^= (echoInputFlag | insertModeFlag | lineInputFlag | mouseInputFlag |
|
||||
processedInputFlag | windowInputFlag)
|
||||
|
||||
ret, _, err := setConsoleMode.Call(term.fd, uintptr(mode))
|
||||
if ret == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return term, nil
|
||||
}
|
||||
|
||||
// Close disables the terminals raw input.
|
||||
func (term *terminal) Close() error {
|
||||
if term.supportsEditing {
|
||||
ret, _, err := setConsoleMode.Call(term.fd, uintptr(term.origMode))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
23
tools/vendor/github.com/GoASTScanner/gas/Dockerfile
generated
vendored
23
tools/vendor/github.com/GoASTScanner/gas/Dockerfile
generated
vendored
@ -1,23 +0,0 @@
|
||||
# Docker version must be 17.05 or higher to allow multistage build
|
||||
# See build and run instructions in README.md
|
||||
|
||||
# Builds Gas for utilization
|
||||
FROM golang:1.8.1-alpine as builder
|
||||
ENV workspace /go/src/github.com/GoASTScanner/gas
|
||||
ENV GOPATH /go
|
||||
COPY . $workspace
|
||||
WORKDIR $workspace
|
||||
|
||||
RUN go vet $(go list ./... | grep -v /vendor/)
|
||||
RUN CGO_ENABLED=0 go build -o gas .
|
||||
|
||||
########################################################
|
||||
|
||||
# Runs Gas on all Go files in the current directory when
|
||||
# 'docker run' command in README is given
|
||||
FROM alpine:3.6
|
||||
|
||||
COPY --from=builder /go/src/github.com/GoASTScanner/gas/gas /
|
||||
|
||||
# Mounted directory should be placed into the workdir
|
||||
CMD /gas $(find . -path ./vendor -prune -o -type f -name "*.go")
|
154
tools/vendor/github.com/GoASTScanner/gas/LICENSE.txt
generated
vendored
154
tools/vendor/github.com/GoASTScanner/gas/LICENSE.txt
generated
vendored
@ -1,154 +0,0 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||
License, each Contributor hereby grants to You a perpetual, worldwide,
|
||||
non-exclusive, no-charge, royalty-free, irrevocable copyright license to
|
||||
reproduce, prepare Derivative Works of, publicly display, publicly perform,
|
||||
sublicense, and distribute the Work and such Derivative Works in Source or
|
||||
Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License,
|
||||
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||
license to make, have made, use, offer to sell, sell, import, and otherwise
|
||||
transfer the Work, where such license applies only to those patent claims
|
||||
licensable by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s) with the Work
|
||||
to which such Contribution(s) was submitted. If You institute patent litigation
|
||||
against any entity (including a cross-claim or counterclaim in a lawsuit)
|
||||
alleging that the Work or a Contribution incorporated within the Work
|
||||
constitutes direct or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate as of the date
|
||||
such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or
|
||||
Derivative Works thereof in any medium, with or without modifications, and in
|
||||
Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and 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 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.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
134
tools/vendor/github.com/GoASTScanner/gas/README.md
generated
vendored
134
tools/vendor/github.com/GoASTScanner/gas/README.md
generated
vendored
@ -1,134 +0,0 @@
|
||||
|
||||
|
||||
## GAS - Go AST Scanner
|
||||
|
||||
Inspects source code for security problems by scanning the Go AST.
|
||||
|
||||
### License
|
||||
|
||||
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 [here](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
### Project status
|
||||
|
||||
[](https://travis-ci.org/GoASTScanner/gas)
|
||||
[](https://godoc.org/github.com/GoASTScanner/gas)
|
||||
|
||||
Gas is still in alpha and accepting feedback from early adopters. We do
|
||||
not consider it production ready at this time.
|
||||
|
||||
### Install
|
||||
|
||||
`$ go get github.com/GoASTScanner/gas/cmd/gas/...`
|
||||
|
||||
### Usage
|
||||
|
||||
Gas can be configured to only run a subset of rules, to exclude certain file
|
||||
paths, and produce reports in different formats. By default all rules will be
|
||||
run against the supplied input files. To recursively scan from the current
|
||||
directory you can supply './...' as the input argument.
|
||||
|
||||
#### Selecting rules
|
||||
|
||||
By default Gas will run all rules against the supplied file paths. It is however possible to select a subset of rules to run via the '-include=' flag,
|
||||
or to specify a set of rules to explicitly exclude using the '-exclude=' flag.
|
||||
|
||||
##### Available rules
|
||||
|
||||
- G101: Look for hardcoded credentials
|
||||
- G102: Bind to all interfaces
|
||||
- G103: Audit the use of unsafe block
|
||||
- G104: Audit errors not checked
|
||||
- G105: Audit the use of math/big.Int.Exp
|
||||
- G106: Audit the use of ssh.InsecureIgnoreHostKey
|
||||
- G201: SQL query construction using format string
|
||||
- G202: SQL query construction using string concatenation
|
||||
- G203: Use of unescaped data in HTML templates
|
||||
- G204: Audit use of command execution
|
||||
- G301: Poor file permissions used when creating a directory
|
||||
- G302: Poor file permisions used with chmod
|
||||
- G303: Creating tempfile using a predictable path
|
||||
- G401: Detect the usage of DES, RC4, or MD5
|
||||
- G402: Look for bad TLS connection settings
|
||||
- G403: Ensure minimum RSA key length of 2048 bits
|
||||
- G404: Insecure random number source (rand)
|
||||
- G501: Import blacklist: crypto/md5
|
||||
- G502: Import blacklist: crypto/des
|
||||
- G503: Import blacklist: crypto/rc4
|
||||
- G504: Import blacklist: net/http/cgi
|
||||
|
||||
|
||||
```
|
||||
# Run a specific set of rules
|
||||
$ gas -include=G101,G203,G401 ./...
|
||||
|
||||
# Run everything except for rule G303
|
||||
$ gas -exclude=G303 ./...
|
||||
```
|
||||
|
||||
#### Excluding files:
|
||||
|
||||
Gas will ignore dependencies in your vendor directory any files
|
||||
that are not considered build artifacts by the compiler (so test files).
|
||||
|
||||
#### Annotating code
|
||||
|
||||
As with all automated detection tools there will be cases of false positives. In cases where Gas reports a failure that has been manually verified as being safe it is possible to annotate the code with a '#nosec' comment.
|
||||
|
||||
The annotation causes Gas to stop processing any further nodes within the
|
||||
AST so can apply to a whole block or more granularly to a single expression.
|
||||
|
||||
```go
|
||||
|
||||
import "md5" // #nosec
|
||||
|
||||
|
||||
func main(){
|
||||
|
||||
/* #nosec */
|
||||
if x > y {
|
||||
h := md5.New() // this will also be ignored
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In some cases you may also want to revisit places where #nosec annotations
|
||||
have been used. To run the scanner and ignore any #nosec annotations you
|
||||
can do the following:
|
||||
|
||||
```
|
||||
$ gas -nosec=true ./...
|
||||
```
|
||||
|
||||
### Output formats
|
||||
|
||||
Gas currently supports text, json, yaml, csv and JUnit XML output formats. By default
|
||||
results will be reported to stdout, but can also be written to an output
|
||||
file. The output format is controlled by the '-fmt' flag, and the output file is controlled by the '-out' flag as follows:
|
||||
|
||||
```
|
||||
# Write output in json format to results.json
|
||||
$ gas -fmt=json -out=results.json *.go
|
||||
```
|
||||
|
||||
### Generate TLS rule
|
||||
|
||||
The configuration of TLS rule can be generated from [Mozilla's TLS ciphers recommendation](https://statics.tls.security.mozilla.org/server-side-tls-conf.json).
|
||||
|
||||
|
||||
First you need to install the generator tool:
|
||||
|
||||
```
|
||||
go get github.com/GoASTScanner/gas/cmd/tlsconfig/...
|
||||
```
|
||||
|
||||
You can invoke now the `go generate` in the root of the project:
|
||||
|
||||
```
|
||||
go generate ./...
|
||||
```
|
||||
|
||||
This will generate the `rules/tls_config.go` file with will contain the current ciphers recommendation from Mozilla.
|
197
tools/vendor/github.com/GoASTScanner/gas/analyzer.go
generated
vendored
197
tools/vendor/github.com/GoASTScanner/gas/analyzer.go
generated
vendored
@ -1,197 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 gas holds the central scanning logic used by GAS
|
||||
package gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
// The Context is populated with data parsed from the source code as it is scanned.
|
||||
// It is passed through to all rule functions as they are called. Rules may use
|
||||
// this data in conjunction withe the encoutered AST node.
|
||||
type Context struct {
|
||||
FileSet *token.FileSet
|
||||
Comments ast.CommentMap
|
||||
Info *types.Info
|
||||
Pkg *types.Package
|
||||
Root *ast.File
|
||||
Config map[string]interface{}
|
||||
Imports *ImportTracker
|
||||
}
|
||||
|
||||
// Metrics used when reporting information about a scanning run.
|
||||
type Metrics struct {
|
||||
NumFiles int `json:"files"`
|
||||
NumLines int `json:"lines"`
|
||||
NumNosec int `json:"nosec"`
|
||||
NumFound int `json:"found"`
|
||||
}
|
||||
|
||||
// Analyzer object is the main object of GAS. It has methods traverse an AST
|
||||
// and invoke the correct checking rules as on each node as required.
|
||||
type Analyzer struct {
|
||||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
issues []*Issue
|
||||
stats *Metrics
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new anaylzer.
|
||||
func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer {
|
||||
ignoreNoSec := false
|
||||
if setting, err := conf.GetGlobal("nosec"); err == nil {
|
||||
ignoreNoSec = setting == "true" || setting == "enabled"
|
||||
}
|
||||
if logger == nil {
|
||||
logger = log.New(os.Stderr, "[gas]", log.LstdFlags)
|
||||
}
|
||||
return &Analyzer{
|
||||
ignoreNosec: ignoreNoSec,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadRules instantiates all the rules to be used when analyzing source
|
||||
// packages
|
||||
func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
||||
for _, builder := range ruleDefinitions {
|
||||
r, nodes := builder(gas.config)
|
||||
gas.ruleset.Register(r, nodes...)
|
||||
}
|
||||
}
|
||||
|
||||
// Process kicks off the analysis process for a given package
|
||||
func (gas *Analyzer) Process(packagePaths ...string) error {
|
||||
packageConfig := loader.Config{
|
||||
Build: &build.Default,
|
||||
ParserMode: parser.ParseComments,
|
||||
AllowErrors: true,
|
||||
}
|
||||
for _, packagePath := range packagePaths {
|
||||
abspath, err := filepath.Abs(packagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gas.logger.Println("Searching directory:", abspath)
|
||||
|
||||
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var packageFiles []string
|
||||
for _, filename := range basePackage.GoFiles {
|
||||
packageFiles = append(packageFiles, path.Join(packagePath, filename))
|
||||
}
|
||||
|
||||
packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
|
||||
}
|
||||
|
||||
builtPackage, err := packageConfig.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range builtPackage.Created {
|
||||
gas.logger.Println("Checking package:", pkg.String())
|
||||
for _, file := range pkg.Files {
|
||||
gas.logger.Println("Checking file:", builtPackage.Fset.File(file.Pos()).Name())
|
||||
gas.context.FileSet = builtPackage.Fset
|
||||
gas.context.Config = gas.config
|
||||
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, file, file.Comments)
|
||||
gas.context.Root = file
|
||||
gas.context.Info = &pkg.Info
|
||||
gas.context.Pkg = pkg.Pkg
|
||||
gas.context.Imports = NewImportTracker()
|
||||
gas.context.Imports.TrackPackages(gas.context.Pkg.Imports()...)
|
||||
ast.Walk(gas, file)
|
||||
gas.stats.NumFiles++
|
||||
gas.stats.NumLines += builtPackage.Fset.File(file.Pos()).LineCount()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
|
||||
func (gas *Analyzer) ignore(n ast.Node) bool {
|
||||
if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec {
|
||||
for _, group := range groups {
|
||||
if strings.Contains(group.Text(), "#nosec") {
|
||||
gas.stats.NumNosec++
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Visit runs the GAS visitor logic over an AST created by parsing go code.
|
||||
// Rule methods added with AddRule will be invoked as necessary.
|
||||
func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
if !gas.ignore(n) {
|
||||
|
||||
// Track aliased and initialization imports
|
||||
gas.context.Imports.TrackImport(n)
|
||||
|
||||
for _, rule := range gas.ruleset.RegisteredFor(n) {
|
||||
issue, err := rule.Match(n, gas.context)
|
||||
if err != nil {
|
||||
file, line := GetLocation(n, gas.context)
|
||||
file = path.Base(file)
|
||||
gas.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
|
||||
}
|
||||
if issue != nil {
|
||||
gas.issues = append(gas.issues, issue)
|
||||
gas.stats.NumFound++
|
||||
}
|
||||
}
|
||||
return gas
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Report returns the current issues discovered and the metrics about the scan
|
||||
func (gas *Analyzer) Report() ([]*Issue, *Metrics) {
|
||||
return gas.issues, gas.stats
|
||||
}
|
||||
|
||||
// Reset clears state such as context, issues and metrics from the configured analyzer
|
||||
func (gas *Analyzer) Reset() {
|
||||
gas.context = &Context{}
|
||||
gas.issues = make([]*Issue, 0, 16)
|
||||
gas.stats = &Metrics{}
|
||||
}
|
78
tools/vendor/github.com/GoASTScanner/gas/call_list.go
generated
vendored
78
tools/vendor/github.com/GoASTScanner/gas/call_list.go
generated
vendored
@ -1,78 +0,0 @@
|
||||
//
|
||||
// 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 gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
)
|
||||
|
||||
type set map[string]bool
|
||||
|
||||
// CallList is used to check for usage of specific packages
|
||||
// and functions.
|
||||
type CallList map[string]set
|
||||
|
||||
// NewCallList creates a new empty CallList
|
||||
func NewCallList() CallList {
|
||||
return make(CallList)
|
||||
}
|
||||
|
||||
// AddAll will add several calls to the call list at once
|
||||
func (c CallList) AddAll(selector string, idents ...string) {
|
||||
for _, ident := range idents {
|
||||
c.Add(selector, ident)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a selector and call to the call list
|
||||
func (c CallList) Add(selector, ident string) {
|
||||
if _, ok := c[selector]; !ok {
|
||||
c[selector] = make(set)
|
||||
}
|
||||
c[selector][ident] = true
|
||||
}
|
||||
|
||||
// Contains returns true if the package and function are
|
||||
/// members of this call list.
|
||||
func (c CallList) Contains(selector, ident string) bool {
|
||||
if idents, ok := c[selector]; ok {
|
||||
_, found := idents[ident]
|
||||
return found
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsCallExpr resolves the call expression name and type
|
||||
/// or package and determines if it exists within the CallList
|
||||
func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) *ast.CallExpr {
|
||||
selector, ident, err := GetCallInfo(n, ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use only explicit path to reduce conflicts
|
||||
if path, ok := GetImportPath(selector, ctx); ok && c.Contains(path, ident) {
|
||||
return n.(*ast.CallExpr)
|
||||
}
|
||||
|
||||
/*
|
||||
// Try direct resolution
|
||||
if c.Contains(selector, ident) {
|
||||
log.Printf("c.Contains == true, %s, %s.", selector, ident)
|
||||
return n.(*ast.CallExpr)
|
||||
}
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
87
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/filelist.go
generated
vendored
87
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/filelist.go
generated
vendored
@ -1,87 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ryanuber/go-glob"
|
||||
)
|
||||
|
||||
// fileList uses a map for patterns to ensure each pattern only
|
||||
// appears once
|
||||
type fileList struct {
|
||||
patterns map[string]struct{}
|
||||
}
|
||||
|
||||
func newFileList(paths ...string) *fileList {
|
||||
f := &fileList{
|
||||
patterns: make(map[string]struct{}),
|
||||
}
|
||||
for _, p := range paths {
|
||||
f.patterns[p] = struct{}{}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *fileList) String() string {
|
||||
ps := make([]string, 0, len(f.patterns))
|
||||
for p := range f.patterns {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
sort.Strings(ps)
|
||||
return strings.Join(ps, ", ")
|
||||
}
|
||||
|
||||
func (f *fileList) Set(path string) error {
|
||||
if path == "" {
|
||||
// don't bother adding the empty path
|
||||
return nil
|
||||
}
|
||||
f.patterns[path] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f fileList) Contains(path string) bool {
|
||||
for p := range f.patterns {
|
||||
if strings.Contains(p, glob.GLOB) {
|
||||
if glob.Glob(p, path) {
|
||||
if logger != nil {
|
||||
logger.Printf("skipping: %s\n", path)
|
||||
}
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// check if only a sub-folder of the path is excluded
|
||||
if strings.Contains(path, p) {
|
||||
if logger != nil {
|
||||
logger.Printf("skipping: %s\n", path)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
func (f fileList) Dump() {
|
||||
for k, _ := range f.paths {
|
||||
println(k)
|
||||
}
|
||||
}
|
||||
*/
|
254
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/main.go
generated
vendored
254
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/main.go
generated
vendored
@ -1,254 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/GoASTScanner/gas/output"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
"github.com/kisielk/gotool"
|
||||
)
|
||||
|
||||
const (
|
||||
usageText = `
|
||||
GAS - Go AST Scanner
|
||||
|
||||
Gas analyzes Go source code to look for common programming mistakes that
|
||||
can lead to security problems.
|
||||
|
||||
USAGE:
|
||||
|
||||
# Check a single package
|
||||
$ gas $GOPATH/src/github.com/example/project
|
||||
|
||||
# Check all packages under the current directory and save results in
|
||||
# json format.
|
||||
$ gas -fmt=json -out=results.json ./...
|
||||
|
||||
# Run a specific set of rules (by default all rules will be run):
|
||||
$ gas -include=G101,G203,G401 ./...
|
||||
|
||||
# Run all rules except the provided
|
||||
$ gas -exclude=G101 $GOPATH/src/github.com/example/project/...
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
// #nosec flag
|
||||
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
|
||||
|
||||
// format output
|
||||
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, or text")
|
||||
|
||||
// output file
|
||||
flagOutput = flag.String("out", "", "Set output file for results")
|
||||
|
||||
// config file
|
||||
flagConfig = flag.String("conf", "", "Path to optional config file")
|
||||
|
||||
// quiet
|
||||
flagQuiet = flag.Bool("quiet", false, "Only show output when errors are found")
|
||||
|
||||
// rules to explicitly include
|
||||
flagRulesInclude = flag.String("include", "", "Comma separated list of rules IDs to include. (see rule list)")
|
||||
|
||||
// rules to explicitly exclude
|
||||
flagRulesExclude = flag.String("exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
|
||||
// log to file or stderr
|
||||
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
||||
|
||||
// sort the issues by severity
|
||||
flagSortIssues = flag.Bool("sort", true, "Sort issues by severity")
|
||||
|
||||
logger *log.Logger
|
||||
)
|
||||
|
||||
// #nosec
|
||||
func usage() {
|
||||
|
||||
fmt.Fprintln(os.Stderr, usageText)
|
||||
fmt.Fprint(os.Stderr, "OPTIONS:\n\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprint(os.Stderr, "\n\nRULES:\n\n")
|
||||
|
||||
// sorted rule list for ease of reading
|
||||
rl := rules.Generate()
|
||||
keys := make([]string, 0, len(rl))
|
||||
for key := range rl {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := rl[k]
|
||||
fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.Description)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
func loadConfig(configFile string) (gas.Config, error) {
|
||||
config := gas.NewConfig()
|
||||
if configFile != "" {
|
||||
file, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := config.ReadFrom(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if *flagIgnoreNoSec {
|
||||
config.SetGlobal("nosec", "true")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func loadRules(include, exclude string) rules.RuleList {
|
||||
var filters []rules.RuleFilter
|
||||
if include != "" {
|
||||
logger.Printf("including rules: %s", include)
|
||||
including := strings.Split(include, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(false, including...))
|
||||
} else {
|
||||
logger.Println("including rules: default")
|
||||
}
|
||||
|
||||
if exclude != "" {
|
||||
logger.Printf("excluding rules: %s", exclude)
|
||||
excluding := strings.Split(exclude, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(true, excluding...))
|
||||
} else {
|
||||
logger.Println("excluding rules: default")
|
||||
}
|
||||
return rules.Generate(filters...)
|
||||
}
|
||||
|
||||
func saveOutput(filename, format string, issues []*gas.Issue, metrics *gas.Metrics) error {
|
||||
if filename != "" {
|
||||
outfile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outfile.Close()
|
||||
err = output.CreateReport(outfile, format, issues, metrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := output.CreateReport(os.Stdout, format, issues, metrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Setup usage description
|
||||
flag.Usage = usage
|
||||
|
||||
// Parse command line arguments
|
||||
flag.Parse()
|
||||
|
||||
// Ensure at least one file was specified
|
||||
if flag.NArg() == 0 {
|
||||
fmt.Fprintf(os.Stderr, "\nError: FILE [FILE...] or './...' expected\n") // #nosec
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Setup logging
|
||||
logWriter := os.Stderr
|
||||
if *flagLogfile != "" {
|
||||
var e error
|
||||
logWriter, e = os.Create(*flagLogfile)
|
||||
if e != nil {
|
||||
flag.Usage()
|
||||
log.Fatal(e)
|
||||
}
|
||||
}
|
||||
logger = log.New(logWriter, "[gas] ", log.LstdFlags)
|
||||
|
||||
// Load config
|
||||
config, err := loadConfig(*flagConfig)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Load enabled rule definitions
|
||||
ruleDefinitions := loadRules(*flagRulesInclude, *flagRulesExclude)
|
||||
if len(ruleDefinitions) <= 0 {
|
||||
logger.Fatal("cannot continue: no rules are configured.")
|
||||
}
|
||||
|
||||
// Create the analyzer
|
||||
analyzer := gas.NewAnalyzer(config, logger)
|
||||
analyzer.LoadRules(ruleDefinitions.Builders()...)
|
||||
|
||||
vendor := regexp.MustCompile(`[\\/]vendor([\\/]|$)`)
|
||||
|
||||
var packages []string
|
||||
// Iterate over packages on the import paths
|
||||
for _, pkg := range gotool.ImportPaths(flag.Args()) {
|
||||
|
||||
// Skip vendor directory
|
||||
if vendor.MatchString(pkg) {
|
||||
continue
|
||||
}
|
||||
packages = append(packages, pkg)
|
||||
}
|
||||
|
||||
if err := analyzer.Process(packages...); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Collect the results
|
||||
issues, metrics := analyzer.Report()
|
||||
|
||||
issuesFound := len(issues) > 0
|
||||
// Exit quietly if nothing was found
|
||||
if !issuesFound && *flagQuiet {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Sort the issue by severity
|
||||
if *flagSortIssues {
|
||||
sortIssues(issues)
|
||||
}
|
||||
|
||||
// Create output report
|
||||
if err := saveOutput(*flagOutput, *flagFormat, issues, metrics); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Finialize logging
|
||||
logWriter.Close() // #nosec
|
||||
|
||||
// Do we have an issue? If so exit 1
|
||||
if issuesFound {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
20
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/sort_issues.go
generated
vendored
20
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/sort_issues.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type sortBySeverity []*gas.Issue
|
||||
|
||||
func (s sortBySeverity) Len() int { return len(s) }
|
||||
|
||||
func (s sortBySeverity) Less(i, j int) bool { return s[i].Severity > s[i].Severity }
|
||||
|
||||
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// sortIssues sorts the issues by severity in descending order
|
||||
func sortIssues(issues []*gas.Issue) {
|
||||
sort.Sort(sortBySeverity(issues))
|
||||
}
|
88
tools/vendor/github.com/GoASTScanner/gas/config.go
generated
vendored
88
tools/vendor/github.com/GoASTScanner/gas/config.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
package gas
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// Globals are applicable to all rules and used for general
|
||||
// configuration settings for gas.
|
||||
Globals = "global"
|
||||
)
|
||||
|
||||
// Config is used to provide configuration and customization to each of the rules.
|
||||
type Config map[string]interface{}
|
||||
|
||||
// NewConfig initializes a new configuration instance. The configuration data then
|
||||
// needs to be loaded via c.ReadFrom(strings.NewReader("config data"))
|
||||
// or from a *os.File.
|
||||
func NewConfig() Config {
|
||||
cfg := make(Config)
|
||||
cfg[Globals] = make(map[string]string)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// ReadFrom implements the io.ReaderFrom interface. This
|
||||
// should be used with io.Reader to load configuration from
|
||||
//file or from string etc.
|
||||
func (c Config) ReadFrom(r io.Reader) (int64, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
if err = json.Unmarshal(data, &c); err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return int64(len(data)), nil
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriteTo interface. This should
|
||||
// be used to save or print out the configuration information.
|
||||
func (c Config) WriteTo(w io.Writer) (int64, error) {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return io.Copy(w, bytes.NewReader(data))
|
||||
}
|
||||
|
||||
// Get returns the configuration section for the supplied key
|
||||
func (c Config) Get(section string) (interface{}, error) {
|
||||
settings, found := c[section]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Section %s not in configuration", section)
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// Set section in the configuration to specified value
|
||||
func (c Config) Set(section string, value interface{}) {
|
||||
c[section] = value
|
||||
}
|
||||
|
||||
// GetGlobal returns value associated with global configuration option
|
||||
func (c Config) GetGlobal(option string) (string, error) {
|
||||
if globals, ok := c[Globals]; ok {
|
||||
if settings, ok := globals.(map[string]string); ok {
|
||||
if value, ok := settings[option]; ok {
|
||||
return value, nil
|
||||
}
|
||||
return "", fmt.Errorf("global setting for %s not found", option)
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("no global config options found")
|
||||
|
||||
}
|
||||
|
||||
// SetGlobal associates a value with a global configuration ooption
|
||||
func (c Config) SetGlobal(option, value string) {
|
||||
if globals, ok := c[Globals]; ok {
|
||||
if settings, ok := globals.(map[string]string); ok {
|
||||
settings[option] = value
|
||||
}
|
||||
}
|
||||
}
|
195
tools/vendor/github.com/GoASTScanner/gas/helpers.go
generated
vendored
195
tools/vendor/github.com/GoASTScanner/gas/helpers.go
generated
vendored
@ -1,195 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 gas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// MatchCallByPackage ensures that the specified package is imported,
|
||||
// adjusts the name for any aliases and ignores cases that are
|
||||
// initialization only imports.
|
||||
//
|
||||
// Usage:
|
||||
// node, matched := MatchCallByPackage(n, ctx, "math/rand", "Read")
|
||||
//
|
||||
func MatchCallByPackage(n ast.Node, c *Context, pkg string, names ...string) (*ast.CallExpr, bool) {
|
||||
|
||||
importedName, found := GetImportedName(pkg, c)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if callExpr, ok := n.(*ast.CallExpr); ok {
|
||||
packageName, callName, err := GetCallInfo(callExpr, c)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
if packageName == importedName {
|
||||
for _, name := range names {
|
||||
if callName == name {
|
||||
return callExpr, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// MatchCallByType ensures that the node is a call expression to a
|
||||
// specific object type.
|
||||
//
|
||||
// Usage:
|
||||
// node, matched := MatchCallByType(n, ctx, "bytes.Buffer", "WriteTo", "Write")
|
||||
//
|
||||
func MatchCallByType(n ast.Node, ctx *Context, requiredType string, calls ...string) (*ast.CallExpr, bool) {
|
||||
if callExpr, ok := n.(*ast.CallExpr); ok {
|
||||
typeName, callName, err := GetCallInfo(callExpr, ctx)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
if typeName == requiredType {
|
||||
for _, call := range calls {
|
||||
if call == callName {
|
||||
return callExpr, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// MatchCompLit will match an ast.CompositeLit based on the supplied type
|
||||
func MatchCompLit(n ast.Node, ctx *Context, required string) *ast.CompositeLit {
|
||||
if complit, ok := n.(*ast.CompositeLit); ok {
|
||||
typeOf := ctx.Info.TypeOf(complit)
|
||||
if typeOf.String() == required {
|
||||
return complit
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetInt will read and return an integer value from an ast.BasicLit
|
||||
func GetInt(n ast.Node) (int64, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.INT {
|
||||
return strconv.ParseInt(node.Value, 0, 64)
|
||||
}
|
||||
return 0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetFloat will read and return a float value from an ast.BasicLit
|
||||
func GetFloat(n ast.Node) (float64, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.FLOAT {
|
||||
return strconv.ParseFloat(node.Value, 64)
|
||||
}
|
||||
return 0.0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetChar will read and return a char value from an ast.BasicLit
|
||||
func GetChar(n ast.Node) (byte, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.CHAR {
|
||||
return node.Value[0], nil
|
||||
}
|
||||
return 0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetString will read and return a string value from an ast.BasicLit
|
||||
func GetString(n ast.Node) (string, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.STRING {
|
||||
return strconv.Unquote(node.Value)
|
||||
}
|
||||
return "", fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetCallObject returns the object and call expression and associated
|
||||
// object for a given AST node. nil, nil will be returned if the
|
||||
// object cannot be resolved.
|
||||
func GetCallObject(n ast.Node, ctx *Context) (*ast.CallExpr, types.Object) {
|
||||
switch node := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
switch fn := node.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
return node, ctx.Info.Uses[fn]
|
||||
case *ast.SelectorExpr:
|
||||
return node, ctx.Info.Uses[fn.Sel]
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetCallInfo returns the package or type and name associated with a
|
||||
// call expression.
|
||||
func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
|
||||
switch node := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
switch fn := node.Fun.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
switch expr := fn.X.(type) {
|
||||
case *ast.Ident:
|
||||
if expr.Obj != nil && expr.Obj.Kind == ast.Var {
|
||||
t := ctx.Info.TypeOf(expr)
|
||||
if t != nil {
|
||||
return t.String(), fn.Sel.Name, nil
|
||||
}
|
||||
return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
|
||||
}
|
||||
return expr.Name, fn.Sel.Name, nil
|
||||
}
|
||||
case *ast.Ident:
|
||||
return ctx.Pkg.Name(), fn.Name, nil
|
||||
}
|
||||
}
|
||||
return "", "", fmt.Errorf("unable to determine call info")
|
||||
}
|
||||
|
||||
// GetImportedName returns the name used for the package within the
|
||||
// code. It will resolve aliases and ignores initalization only imports.
|
||||
func GetImportedName(path string, ctx *Context) (string, bool) {
|
||||
importName, imported := ctx.Imports.Imported[path]
|
||||
if !imported {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if _, initonly := ctx.Imports.InitOnly[path]; initonly {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if alias, ok := ctx.Imports.Aliased[path]; ok {
|
||||
importName = alias
|
||||
}
|
||||
return importName, true
|
||||
}
|
||||
|
||||
// GetImportPath resolves the full import path of an identifer based on
|
||||
// the imports in the current context.
|
||||
func GetImportPath(name string, ctx *Context) (string, bool) {
|
||||
for path := range ctx.Imports.Imported {
|
||||
if imported, ok := GetImportedName(path, ctx); ok && imported == name {
|
||||
return path, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// GetLocation returns the filename and line number of an ast.Node
|
||||
func GetLocation(n ast.Node, ctx *Context) (string, int) {
|
||||
fobj := ctx.FileSet.File(n.Pos())
|
||||
return fobj.Name(), fobj.Line(n.Pos())
|
||||
}
|
67
tools/vendor/github.com/GoASTScanner/gas/import_tracker.go
generated
vendored
67
tools/vendor/github.com/GoASTScanner/gas/import_tracker.go
generated
vendored
@ -1,67 +0,0 @@
|
||||
// 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 gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ImportTracker is used to normalize the packages that have been imported
|
||||
// by a source file. It is able to differentiate between plain imports, aliased
|
||||
// imports and init only imports.
|
||||
type ImportTracker struct {
|
||||
Imported map[string]string
|
||||
Aliased map[string]string
|
||||
InitOnly map[string]bool
|
||||
}
|
||||
|
||||
// NewImportTracker creates an empty Import tracker instance
|
||||
func NewImportTracker() *ImportTracker {
|
||||
return &ImportTracker{
|
||||
make(map[string]string),
|
||||
make(map[string]string),
|
||||
make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// TrackPackages tracks all the imports used by the supplied packages
|
||||
func (t *ImportTracker) TrackPackages(pkgs ...*types.Package) {
|
||||
for _, pkg := range pkgs {
|
||||
t.Imported[pkg.Path()] = pkg.Name()
|
||||
// Transient imports
|
||||
//for _, imp := range pkg.Imports() {
|
||||
// t.Imported[imp.Path()] = imp.Name()
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// TrackImport tracks imports and handles the 'unsafe' import
|
||||
func (t *ImportTracker) TrackImport(n ast.Node) {
|
||||
if imported, ok := n.(*ast.ImportSpec); ok {
|
||||
path := strings.Trim(imported.Path.Value, `"`)
|
||||
if imported.Name != nil {
|
||||
if imported.Name.Name == "_" {
|
||||
// Initialization only import
|
||||
t.InitOnly[path] = true
|
||||
} else {
|
||||
// Aliased import
|
||||
t.Aliased[path] = imported.Name.Name
|
||||
}
|
||||
}
|
||||
if path == "unsafe" {
|
||||
t.Imported[path] = path
|
||||
}
|
||||
}
|
||||
}
|
118
tools/vendor/github.com/GoASTScanner/gas/issue.go
generated
vendored
118
tools/vendor/github.com/GoASTScanner/gas/issue.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 gas
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Score type used by severity and confidence values
|
||||
type Score int
|
||||
|
||||
const (
|
||||
// Low severity or confidence
|
||||
Low Score = iota
|
||||
// Medium severity or confidence
|
||||
Medium
|
||||
// High severity or confidence
|
||||
High
|
||||
)
|
||||
|
||||
// Issue is returnd by a GAS rule if it discovers an issue with the scanned code.
|
||||
type Issue struct {
|
||||
Severity Score `json:"severity"` // issue severity (how problematic it is)
|
||||
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
|
||||
What string `json:"details"` // Human readable explanation
|
||||
File string `json:"file"` // File name we found it in
|
||||
Code string `json:"code"` // Impacted code line
|
||||
Line string `json:"line"` // Line number in file
|
||||
}
|
||||
|
||||
// MetaData is embedded in all GAS rules. The Severity, Confidence and What message
|
||||
// will be passed tbhrough to reported issues.
|
||||
type MetaData struct {
|
||||
Severity Score
|
||||
Confidence Score
|
||||
What string
|
||||
}
|
||||
|
||||
// MarshalJSON is used convert a Score object into a JSON representation
|
||||
func (c Score) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(c.String())
|
||||
}
|
||||
|
||||
// String converts a Score into a string
|
||||
func (c Score) String() string {
|
||||
switch c {
|
||||
case High:
|
||||
return "HIGH"
|
||||
case Medium:
|
||||
return "MEDIUM"
|
||||
case Low:
|
||||
return "LOW"
|
||||
}
|
||||
return "UNDEFINED"
|
||||
}
|
||||
|
||||
func codeSnippet(file *os.File, start int64, end int64, n ast.Node) (string, error) {
|
||||
if n == nil {
|
||||
return "", fmt.Errorf("Invalid AST node provided")
|
||||
}
|
||||
|
||||
size := (int)(end - start) // Go bug, os.File.Read should return int64 ...
|
||||
file.Seek(start, 0) // #nosec
|
||||
|
||||
buf := make([]byte, size)
|
||||
if nread, err := file.Read(buf); err != nil || nread != size {
|
||||
return "", fmt.Errorf("Unable to read code")
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// NewIssue creates a new Issue
|
||||
func NewIssue(ctx *Context, node ast.Node, desc string, severity Score, confidence Score) *Issue {
|
||||
var code string
|
||||
fobj := ctx.FileSet.File(node.Pos())
|
||||
name := fobj.Name()
|
||||
|
||||
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
||||
line := strconv.Itoa(start)
|
||||
if start != end {
|
||||
line = fmt.Sprintf("%d-%d", start, end)
|
||||
}
|
||||
|
||||
if file, err := os.Open(fobj.Name()); err == nil {
|
||||
defer file.Close()
|
||||
s := (int64)(fobj.Position(node.Pos()).Offset) // Go bug, should be int64
|
||||
e := (int64)(fobj.Position(node.End()).Offset) // Go bug, should be int64
|
||||
code, err = codeSnippet(file, s, e, node)
|
||||
if err != nil {
|
||||
code = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
return &Issue{
|
||||
File: name,
|
||||
Line: line,
|
||||
What: desc,
|
||||
Confidence: confidence,
|
||||
Severity: severity,
|
||||
Code: code,
|
||||
}
|
||||
}
|
168
tools/vendor/github.com/GoASTScanner/gas/output/formatter.go
generated
vendored
168
tools/vendor/github.com/GoASTScanner/gas/output/formatter.go
generated
vendored
@ -1,168 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 output
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
htmlTemplate "html/template"
|
||||
"io"
|
||||
plainTemplate "text/template"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// ReportFormat enumrates the output format for reported issues
|
||||
type ReportFormat int
|
||||
|
||||
const (
|
||||
// ReportText is the default format that writes to stdout
|
||||
ReportText ReportFormat = iota // Plain text format
|
||||
|
||||
// ReportJSON set the output format to json
|
||||
ReportJSON // Json format
|
||||
|
||||
// ReportCSV set the output format to csv
|
||||
ReportCSV // CSV format
|
||||
|
||||
// ReportJUnitXML set the output format to junit xml
|
||||
ReportJUnitXML // JUnit XML format
|
||||
)
|
||||
|
||||
var text = `Results:
|
||||
{{ range $index, $issue := .Issues }}
|
||||
[{{ $issue.File }}:{{ $issue.Line }}] - {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
> {{ $issue.Code }}
|
||||
|
||||
{{ end }}
|
||||
Summary:
|
||||
Files: {{.Stats.NumFiles}}
|
||||
Lines: {{.Stats.NumLines}}
|
||||
Nosec: {{.Stats.NumNosec}}
|
||||
Issues: {{.Stats.NumFound}}
|
||||
|
||||
`
|
||||
|
||||
type reportInfo struct {
|
||||
Issues []*gas.Issue
|
||||
Stats *gas.Metrics
|
||||
}
|
||||
|
||||
// CreateReport generates a report based for the supplied issues and metrics given
|
||||
// the specified format. The formats currently accepted are: json, csv, html and text.
|
||||
func CreateReport(w io.Writer, format string, issues []*gas.Issue, metrics *gas.Metrics) error {
|
||||
data := &reportInfo{
|
||||
Issues: issues,
|
||||
Stats: metrics,
|
||||
}
|
||||
var err error
|
||||
switch format {
|
||||
case "json":
|
||||
err = reportJSON(w, data)
|
||||
case "yaml":
|
||||
err = reportYAML(w, data)
|
||||
case "csv":
|
||||
err = reportCSV(w, data)
|
||||
case "junit-xml":
|
||||
err = reportJUnitXML(w, data)
|
||||
case "html":
|
||||
err = reportFromHTMLTemplate(w, html, data)
|
||||
case "text":
|
||||
err = reportFromPlaintextTemplate(w, text, data)
|
||||
default:
|
||||
err = reportFromPlaintextTemplate(w, text, data)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func reportJSON(w io.Writer, data *reportInfo) error {
|
||||
raw, err := json.MarshalIndent(data, "", "\t")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = w.Write(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func reportYAML(w io.Writer, data *reportInfo) error {
|
||||
raw, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(raw)
|
||||
return err
|
||||
}
|
||||
|
||||
func reportCSV(w io.Writer, data *reportInfo) error {
|
||||
out := csv.NewWriter(w)
|
||||
defer out.Flush()
|
||||
for _, issue := range data.Issues {
|
||||
err := out.Write([]string{
|
||||
issue.File,
|
||||
issue.Line,
|
||||
issue.What,
|
||||
issue.Severity.String(),
|
||||
issue.Confidence.String(),
|
||||
issue.Code,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportJUnitXML(w io.Writer, data *reportInfo) error {
|
||||
groupedData := groupDataByRules(data)
|
||||
junitXMLStruct := createJUnitXMLStruct(groupedData)
|
||||
|
||||
raw, err := xml.MarshalIndent(junitXMLStruct, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xmlHeader := []byte("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||
raw = append(xmlHeader, raw...)
|
||||
_, err = w.Write(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *reportInfo) error {
|
||||
t, e := plainTemplate.New("gas").Parse(reportTemplate)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return t.Execute(w, data)
|
||||
}
|
||||
|
||||
func reportFromHTMLTemplate(w io.Writer, reportTemplate string, data *reportInfo) error {
|
||||
t, e := htmlTemplate.New("gas").Parse(reportTemplate)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return t.Execute(w, data)
|
||||
}
|
74
tools/vendor/github.com/GoASTScanner/gas/output/junit_xml_format.go
generated
vendored
74
tools/vendor/github.com/GoASTScanner/gas/output/junit_xml_format.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
htmlLib "html"
|
||||
"strconv"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type junitXMLReport struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
Testsuites []testsuite `xml:"testsuite"`
|
||||
}
|
||||
|
||||
type testsuite struct {
|
||||
XMLName xml.Name `xml:"testsuite"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests int `xml:"tests,attr"`
|
||||
Testcases []testcase `xml:"testcase"`
|
||||
}
|
||||
|
||||
type testcase struct {
|
||||
XMLName xml.Name `xml:"testcase"`
|
||||
Name string `xml:"name,attr"`
|
||||
Failure failure `xml:"failure"`
|
||||
}
|
||||
|
||||
type failure struct {
|
||||
XMLName xml.Name `xml:"failure"`
|
||||
Message string `xml:"message,attr"`
|
||||
Text string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
func generatePlaintext(issue *gas.Issue) string {
|
||||
return "Results:\n" +
|
||||
"[" + issue.File + ":" + issue.Line + "] - " +
|
||||
issue.What + " (Confidence: " + strconv.Itoa(int(issue.Confidence)) +
|
||||
", Severity: " + strconv.Itoa(int(issue.Severity)) + ")\n" + "> " + htmlLib.EscapeString(issue.Code)
|
||||
}
|
||||
|
||||
func groupDataByRules(data *reportInfo) map[string][]*gas.Issue {
|
||||
groupedData := make(map[string][]*gas.Issue)
|
||||
for _, issue := range data.Issues {
|
||||
if _, ok := groupedData[issue.What]; ok {
|
||||
groupedData[issue.What] = append(groupedData[issue.What], issue)
|
||||
} else {
|
||||
groupedData[issue.What] = []*gas.Issue{issue}
|
||||
}
|
||||
}
|
||||
return groupedData
|
||||
}
|
||||
|
||||
func createJUnitXMLStruct(groupedData map[string][]*gas.Issue) junitXMLReport {
|
||||
var xmlReport junitXMLReport
|
||||
for what, issues := range groupedData {
|
||||
testsuite := testsuite{
|
||||
Name: what,
|
||||
Tests: len(issues),
|
||||
}
|
||||
for _, issue := range issues {
|
||||
testcase := testcase{
|
||||
Name: issue.File,
|
||||
Failure: failure{
|
||||
Message: "Found 1 vulnerability. See stacktrace for details.",
|
||||
Text: generatePlaintext(issue),
|
||||
},
|
||||
}
|
||||
testsuite.Testcases = append(testsuite.Testcases, testcase)
|
||||
}
|
||||
xmlReport.Testsuites = append(xmlReport.Testsuites, testsuite)
|
||||
}
|
||||
return xmlReport
|
||||
}
|
401
tools/vendor/github.com/GoASTScanner/gas/output/template.go
generated
vendored
401
tools/vendor/github.com/GoASTScanner/gas/output/template.go
generated
vendored
@ -1,401 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 output
|
||||
|
||||
const html = `
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Go AST Scanner</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.1/css/bulma.min.css" integrity="sha256-DRcOKg8NK1KkSkcymcGmxOtS/lAn0lHWJXRa15gMHHk=" crossorigin="anonymous"/>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js" integrity="sha256-cLWs9L+cjZg8CjGHMpJqUgKKouPlmoMP/0wIdPtaPGs=" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js" integrity="sha256-JIW8lNqN2EtqC6ggNZYnAdKMJXRQfkPMvdRt+b0/Jxc=" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.17.0/babel.min.js" integrity="sha256-1IWWLlCKFGFj/cjryvC7GDF5wRYnf9tSvNVVEj8Bm+o=" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
div.issue div.tag, div.panel-block input[type="checkbox"] {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
label.disabled {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
nav.panel select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.break-word {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
var data = {{ . }};
|
||||
</script>
|
||||
<script type="text/babel">
|
||||
var IssueTag = React.createClass({
|
||||
render: function() {
|
||||
var level = ""
|
||||
if (this.props.level === "HIGH") {
|
||||
level = "is-danger";
|
||||
}
|
||||
if (this.props.level === "MEDIUM") {
|
||||
level = "is-warning";
|
||||
}
|
||||
return (
|
||||
<div className={ "tag " + level }>
|
||||
{ this.props.label }: { this.props.level }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Issue = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="issue box">
|
||||
<div className="is-pulled-right">
|
||||
<IssueTag label="Severity" level={ this.props.data.severity }/>
|
||||
<IssueTag label="Confidence" level={ this.props.data.confidence }/>
|
||||
</div>
|
||||
<p>
|
||||
<strong className="break-word">
|
||||
{ this.props.data.file } (line { this.props.data.line })
|
||||
</strong>
|
||||
<br/>
|
||||
{ this.props.data.details }
|
||||
</p>
|
||||
<figure className="highlight">
|
||||
<pre>
|
||||
<code className="golang hljs">
|
||||
{ this.props.data.code }
|
||||
</code>
|
||||
</pre>
|
||||
</figure>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Stats = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<p className="help">
|
||||
Scanned { this.props.data.metrics.files.toLocaleString() } files
|
||||
with { this.props.data.metrics.lines.toLocaleString() } lines of code.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Issues = React.createClass({
|
||||
render: function() {
|
||||
if (this.props.data.metrics.files === 0) {
|
||||
return (
|
||||
<div className="notification">
|
||||
No source files found. Do you even Go?
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.data.issues.length === 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className="notification">
|
||||
Awesome! No issues found!
|
||||
</div>
|
||||
<Stats data={ this.props.data } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
var issues = this.props.data.issues
|
||||
.filter(function(issue) {
|
||||
return this.props.severity.includes(issue.severity);
|
||||
}.bind(this))
|
||||
.filter(function(issue) {
|
||||
return this.props.confidence.includes(issue.confidence);
|
||||
}.bind(this))
|
||||
.filter(function(issue) {
|
||||
if (this.props.issueType) {
|
||||
return issue.details.toLowerCase().startsWith(this.props.issueType.toLowerCase());
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}.bind(this))
|
||||
.map(function(issue) {
|
||||
return (<Issue data={issue} />);
|
||||
}.bind(this));
|
||||
|
||||
if (issues.length === 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className="notification">
|
||||
No issues matched given filters
|
||||
(of total { this.props.data.issues.length } issues).
|
||||
</div>
|
||||
<Stats data={ this.props.data } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="issues">
|
||||
{ issues }
|
||||
<Stats data={ this.props.data } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var LevelSelector = React.createClass({
|
||||
handleChange: function(level) {
|
||||
return function(e) {
|
||||
var updated = this.props.selected
|
||||
.filter(function(item) { return item != level; });
|
||||
if (e.target.checked) {
|
||||
updated.push(level);
|
||||
}
|
||||
this.props.onChange(updated);
|
||||
}.bind(this);
|
||||
},
|
||||
render: function() {
|
||||
var highDisabled = !this.props.available.includes("HIGH");
|
||||
var mediumDisabled = !this.props.available.includes("MEDIUM");
|
||||
var lowDisabled = !this.props.available.includes("LOW");
|
||||
|
||||
return (
|
||||
<span>
|
||||
<label className={"label checkbox " + (highDisabled ? "disabled" : "") }>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={ this.props.selected.includes("HIGH") }
|
||||
disabled={ highDisabled }
|
||||
onChange={ this.handleChange("HIGH") }/>
|
||||
High
|
||||
</label>
|
||||
<label className={"label checkbox " + (mediumDisabled ? "disabled" : "") }>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={ this.props.selected.includes("MEDIUM") }
|
||||
disabled={ mediumDisabled }
|
||||
onChange={ this.handleChange("MEDIUM") }/>
|
||||
Medium
|
||||
</label>
|
||||
<label className={"label checkbox " + (lowDisabled ? "disabled" : "") }>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={ this.props.selected.includes("LOW") }
|
||||
disabled={ lowDisabled }
|
||||
onChange={ this.handleChange("LOW") }/>
|
||||
Low
|
||||
</label>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Navigation = React.createClass({
|
||||
updateSeverity: function(vals) {
|
||||
this.props.onSeverity(vals);
|
||||
},
|
||||
updateConfidence: function(vals) {
|
||||
this.props.onConfidence(vals);
|
||||
},
|
||||
updateIssueType: function(e) {
|
||||
if (e.target.value == "all") {
|
||||
this.props.onIssueType(null);
|
||||
} else {
|
||||
this.props.onIssueType(e.target.value);
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
var issueTypes = this.props.allIssueTypes
|
||||
.map(function(it) {
|
||||
return (
|
||||
<option value={ it } selected={ this.props.issueType == it }>
|
||||
{ it }
|
||||
</option>
|
||||
);
|
||||
}.bind(this));
|
||||
|
||||
return (
|
||||
<nav className="panel">
|
||||
<div className="panel-heading">
|
||||
Filters
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<strong>
|
||||
Severity
|
||||
</strong>
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<LevelSelector
|
||||
selected={ this.props.severity }
|
||||
available={ this.props.allSeverities }
|
||||
onChange={ this.updateSeverity } />
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<strong>
|
||||
Confidence
|
||||
</strong>
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<LevelSelector
|
||||
selected={ this.props.confidence }
|
||||
available={ this.props.allConfidences }
|
||||
onChange={ this.updateConfidence } />
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<strong>
|
||||
Issue Type
|
||||
</strong>
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<select onChange={ this.updateIssueType }>
|
||||
<option value="all" selected={ !this.props.issueType }>
|
||||
(all)
|
||||
</option>
|
||||
{ issueTypes }
|
||||
</select>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var IssueBrowser = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
this.updateIssues(this.props.data);
|
||||
},
|
||||
handleSeverity: function(val) {
|
||||
this.updateIssueTypes(this.props.data.issues, val, this.state.confidence);
|
||||
this.setState({severity: val});
|
||||
},
|
||||
handleConfidence: function(val) {
|
||||
this.updateIssueTypes(this.props.data.issues, this.state.severity, val);
|
||||
this.setState({confidence: val});
|
||||
},
|
||||
handleIssueType: function(val) {
|
||||
this.setState({issueType: val});
|
||||
},
|
||||
updateIssues: function(data) {
|
||||
if (!data) {
|
||||
this.setState({data: data});
|
||||
return;
|
||||
}
|
||||
|
||||
var allSeverities = data.issues
|
||||
.map(function(issue) {
|
||||
return issue.severity
|
||||
})
|
||||
.sort()
|
||||
.filter(function(item, pos, ary) {
|
||||
return !pos || item != ary[pos - 1];
|
||||
});
|
||||
|
||||
var allConfidences = data.issues
|
||||
.map(function(issue) {
|
||||
return issue.confidence
|
||||
})
|
||||
.sort()
|
||||
.filter(function(item, pos, ary) {
|
||||
return !pos || item != ary[pos - 1];
|
||||
});
|
||||
|
||||
var selectedSeverities = allSeverities;
|
||||
var selectedConfidences = allConfidences;
|
||||
|
||||
this.updateIssueTypes(data.issues, selectedSeverities, selectedConfidences);
|
||||
|
||||
this.setState({
|
||||
data: data,
|
||||
severity: selectedSeverities,
|
||||
allSeverities: allSeverities,
|
||||
confidence: selectedConfidences,
|
||||
allConfidences: allConfidences,
|
||||
issueType: null
|
||||
});
|
||||
},
|
||||
updateIssueTypes: function(issues, severities, confidences) {
|
||||
var allTypes = issues
|
||||
.filter(function(issue) {
|
||||
return severities.includes(issue.severity);
|
||||
})
|
||||
.filter(function(issue) {
|
||||
return confidences.includes(issue.confidence);
|
||||
})
|
||||
.map(function(issue) {
|
||||
return issue.details;
|
||||
})
|
||||
.sort()
|
||||
.filter(function(item, pos, ary) {
|
||||
return !pos || item != ary[pos - 1];
|
||||
});
|
||||
|
||||
if (this.state.issueType && !allTypes.includes(this.state.issueType)) {
|
||||
this.setState({issueType: null});
|
||||
}
|
||||
|
||||
this.setState({allIssueTypes: allTypes});
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div className="content">
|
||||
<div className="columns">
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation
|
||||
severity={ this.state.severity }
|
||||
confidence={ this.state.confidence }
|
||||
issueType={ this.state.issueType }
|
||||
allSeverities={ this.state.allSeverities }
|
||||
allConfidences={ this.state.allConfidences }
|
||||
allIssueTypes={ this.state.allIssueTypes }
|
||||
onSeverity={ this.handleSeverity }
|
||||
onConfidence={ this.handleConfidence }
|
||||
onIssueType={ this.handleIssueType }
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-three-quarters">
|
||||
<Issues
|
||||
data={ this.props.data }
|
||||
severity={ this.state.severity }
|
||||
confidence={ this.state.confidence }
|
||||
issueType={ this.state.issueType }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ReactDOM.render(
|
||||
<IssueBrowser data={ data } />,
|
||||
document.getElementById("content")
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
82
tools/vendor/github.com/GoASTScanner/gas/resolve.go
generated
vendored
82
tools/vendor/github.com/GoASTScanner/gas/resolve.go
generated
vendored
@ -1,82 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 gas
|
||||
|
||||
import "go/ast"
|
||||
|
||||
func resolveIdent(n *ast.Ident, c *Context) bool {
|
||||
|
||||
if n.Obj == nil || n.Obj.Kind != ast.Var {
|
||||
return true
|
||||
}
|
||||
if node, ok := n.Obj.Decl.(ast.Node); ok {
|
||||
return TryResolve(node, c)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func resolveAssign(n *ast.AssignStmt, c *Context) bool {
|
||||
for _, arg := range n.Rhs {
|
||||
if !TryResolve(arg, c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func resolveCompLit(n *ast.CompositeLit, c *Context) bool {
|
||||
for _, arg := range n.Elts {
|
||||
if !TryResolve(arg, c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func resolveBinExpr(n *ast.BinaryExpr, c *Context) bool {
|
||||
return (TryResolve(n.X, c) && TryResolve(n.Y, c))
|
||||
}
|
||||
|
||||
func resolveCallExpr(n *ast.CallExpr, c *Context) bool {
|
||||
// TODO(tkelsey): next step, full function resolution
|
||||
return false
|
||||
}
|
||||
|
||||
// TryResolve will attempt, given a subtree starting at some ATS node, to resolve
|
||||
// all values contained within to a known constant. It is used to check for any
|
||||
// unkown values in compound expressions.
|
||||
func TryResolve(n ast.Node, c *Context) bool {
|
||||
switch node := n.(type) {
|
||||
case *ast.BasicLit:
|
||||
return true
|
||||
|
||||
case *ast.CompositeLit:
|
||||
return resolveCompLit(node, c)
|
||||
|
||||
case *ast.Ident:
|
||||
return resolveIdent(node, c)
|
||||
|
||||
case *ast.AssignStmt:
|
||||
return resolveAssign(node, c)
|
||||
|
||||
case *ast.CallExpr:
|
||||
return resolveCallExpr(node, c)
|
||||
|
||||
case *ast.BinaryExpr:
|
||||
return resolveBinExpr(node, c)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
58
tools/vendor/github.com/GoASTScanner/gas/rule.go
generated
vendored
58
tools/vendor/github.com/GoASTScanner/gas/rule.go
generated
vendored
@ -1,58 +0,0 @@
|
||||
// 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 gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// The Rule interface used by all rules supported by GAS.
|
||||
type Rule interface {
|
||||
Match(ast.Node, *Context) (*Issue, error)
|
||||
}
|
||||
|
||||
// RuleBuilder is used to register a rule definition with the analyzer
|
||||
type RuleBuilder func(c Config) (Rule, []ast.Node)
|
||||
|
||||
// A RuleSet maps lists of rules to the type of AST node they should be run on.
|
||||
// The anaylzer will only invoke rules contained in the list associated with the
|
||||
// type of AST node it is currently visiting.
|
||||
type RuleSet map[reflect.Type][]Rule
|
||||
|
||||
// NewRuleSet constructs a new RuleSet
|
||||
func NewRuleSet() RuleSet {
|
||||
return make(RuleSet)
|
||||
}
|
||||
|
||||
// Register adds a trigger for the supplied rule for the the
|
||||
// specified ast nodes.
|
||||
func (r RuleSet) Register(rule Rule, nodes ...ast.Node) {
|
||||
for _, n := range nodes {
|
||||
t := reflect.TypeOf(n)
|
||||
if rules, ok := r[t]; ok {
|
||||
r[t] = append(rules, rule)
|
||||
} else {
|
||||
r[t] = []Rule{rule}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisteredFor will return all rules that are registered for a
|
||||
// specified ast node.
|
||||
func (r RuleSet) RegisteredFor(n ast.Node) []Rule {
|
||||
if rules, found := r[reflect.TypeOf(n)]; found {
|
||||
return rules
|
||||
}
|
||||
return []Rule{}
|
||||
}
|
47
tools/vendor/github.com/GoASTScanner/gas/rules/big.go
generated
vendored
47
tools/vendor/github.com/GoASTScanner/gas/rules/big.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type usingBigExp struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *usingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matched := gas.MatchCallByType(n, c, r.pkg, r.calls...); matched {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewUsingBigExp detects issues with modulus == 0 for Bignum
|
||||
func NewUsingBigExp(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &usingBigExp{
|
||||
pkg: "*math/big.Int",
|
||||
calls: []string{"Exp"},
|
||||
MetaData: gas.MetaData{
|
||||
What: "Use of math/big.Int.Exp function should be audited for modulus == 0",
|
||||
Severity: gas.Low,
|
||||
Confidence: gas.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
59
tools/vendor/github.com/GoASTScanner/gas/rules/bind.go
generated
vendored
59
tools/vendor/github.com/GoASTScanner/gas/rules/bind.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
||||
type bindsToAllNetworkInterfaces struct {
|
||||
gas.MetaData
|
||||
calls gas.CallList
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
callExpr := r.calls.ContainsCallExpr(n, c)
|
||||
if callExpr == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if arg, err := gas.GetString(callExpr.Args[1]); err == nil {
|
||||
if r.pattern.MatchString(arg) {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
|
||||
// listen on all network interfaces.
|
||||
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("net", "Listen")
|
||||
calls.Add("crypto/tls", "Listen")
|
||||
return &bindsToAllNetworkInterfaces{
|
||||
calls: calls,
|
||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "Binds to all network interfaces",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
82
tools/vendor/github.com/GoASTScanner/gas/rules/blacklist.go
generated
vendored
82
tools/vendor/github.com/GoASTScanner/gas/rules/blacklist.go
generated
vendored
@ -1,82 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type blacklistedImport struct {
|
||||
gas.MetaData
|
||||
Blacklisted map[string]string
|
||||
}
|
||||
|
||||
func unquote(original string) string {
|
||||
copy := strings.TrimSpace(original)
|
||||
copy = strings.TrimLeft(copy, `"`)
|
||||
return strings.TrimRight(copy, `"`)
|
||||
}
|
||||
|
||||
func (r *blacklistedImport) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node, ok := n.(*ast.ImportSpec); ok {
|
||||
if description, ok := r.Blacklisted[unquote(node.Path.Value)]; ok {
|
||||
return gas.NewIssue(c, node, description, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewBlacklistedImports reports when a blacklisted import is being used.
|
||||
// Typically when a deprecated technology is being used.
|
||||
func NewBlacklistedImports(conf gas.Config, blacklist map[string]string) (gas.Rule, []ast.Node) {
|
||||
return &blacklistedImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
},
|
||||
Blacklisted: blacklist,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
}
|
||||
|
||||
// NewBlacklistedImportMD5 fails if MD5 is imported
|
||||
func NewBlacklistedImportMD5(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/md5": "Blacklisted import crypto/md5: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
// NewBlacklistedImportDES fails if DES is imported
|
||||
func NewBlacklistedImportDES(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/des": "Blacklisted import crypto/des: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
// NewBlacklistedImportRC4 fails if DES is imported
|
||||
func NewBlacklistedImportRC4(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/rc4": "Blacklisted import crypto/rc4: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
// NewBlacklistedImportCGI fails if CGI is imported
|
||||
func NewBlacklistedImportCGI(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"net/http/cgi": "Blacklisted import net/http/cgi: Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||
})
|
||||
}
|
98
tools/vendor/github.com/GoASTScanner/gas/rules/errors.go
generated
vendored
98
tools/vendor/github.com/GoASTScanner/gas/rules/errors.go
generated
vendored
@ -1,98 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type noErrorCheck struct {
|
||||
gas.MetaData
|
||||
whitelist gas.CallList
|
||||
}
|
||||
|
||||
func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
||||
if tv := ctx.Info.TypeOf(callExpr); tv != nil {
|
||||
switch t := tv.(type) {
|
||||
case *types.Tuple:
|
||||
for pos := 0; pos < t.Len(); pos++ {
|
||||
variable := t.At(pos)
|
||||
if variable != nil && variable.Type().String() == "error" {
|
||||
return pos
|
||||
}
|
||||
}
|
||||
case *types.Named:
|
||||
if t.String() == "error" {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
switch stmt := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
for _, expr := range stmt.Rhs {
|
||||
if callExpr, ok := expr.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(expr, ctx) == nil {
|
||||
pos := returnsError(callExpr, ctx)
|
||||
if pos < 0 || pos >= len(stmt.Lhs) {
|
||||
return nil, nil
|
||||
}
|
||||
if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
|
||||
return gas.NewIssue(ctx, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
case *ast.ExprStmt:
|
||||
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
|
||||
pos := returnsError(callExpr, ctx)
|
||||
if pos >= 0 {
|
||||
return gas.NewIssue(ctx, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewNoErrorCheck detects if the returned error is unchecked
|
||||
func NewNoErrorCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
|
||||
// TODO(gm) Come up with sensible defaults here. Or flip it to use a
|
||||
// black list instead.
|
||||
whitelist := gas.NewCallList()
|
||||
whitelist.AddAll("bytes.Buffer", "Write", "WriteByte", "WriteRune", "WriteString")
|
||||
whitelist.AddAll("fmt", "Print", "Printf", "Println", "Fprint", "Fprintf", "Fprintln")
|
||||
whitelist.Add("io.PipeWriter", "CloseWithError")
|
||||
|
||||
if configured, ok := conf["G104"]; ok {
|
||||
if whitelisted, ok := configured.(map[string][]string); ok {
|
||||
for key, val := range whitelisted {
|
||||
whitelist.AddAll(key, val...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &noErrorCheck{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Low,
|
||||
Confidence: gas.High,
|
||||
What: "Errors unhandled.",
|
||||
},
|
||||
whitelist: whitelist,
|
||||
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ExprStmt)(nil)}
|
||||
}
|
89
tools/vendor/github.com/GoASTScanner/gas/rules/fileperms.go
generated
vendored
89
tools/vendor/github.com/GoASTScanner/gas/rules/fileperms.go
generated
vendored
@ -1,89 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"strconv"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type filePermissions struct {
|
||||
gas.MetaData
|
||||
mode int64
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
|
||||
var mode = defaultMode
|
||||
if value, ok := conf[configKey]; ok {
|
||||
switch value.(type) {
|
||||
case int64:
|
||||
mode = value.(int64)
|
||||
case string:
|
||||
if m, e := strconv.ParseInt(value.(string), 0, 64); e != nil {
|
||||
mode = defaultMode
|
||||
} else {
|
||||
mode = m
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
func (r *filePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if callexpr, matched := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matched {
|
||||
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
||||
if mode, err := gas.GetInt(modeArg); err == nil && mode > r.mode {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewFilePerms creates a rule to detect file creation with a more permissive than configured
|
||||
// permission mask.
|
||||
func NewFilePerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G302", 0600)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkg: "os",
|
||||
calls: []string{"OpenFile", "Chmod"},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
||||
// NewMkdirPerms creates a rule to detect directory creation with more permissive than
|
||||
// configured permission mask.
|
||||
func NewMkdirPerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G301", 0750)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkg: "os",
|
||||
calls: []string{"Mkdir", "MkdirAll"},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
150
tools/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go
generated
vendored
150
tools/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go
generated
vendored
@ -1,150 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/nbutton23/zxcvbn-go"
|
||||
)
|
||||
|
||||
type credentials struct {
|
||||
gas.MetaData
|
||||
pattern *regexp.Regexp
|
||||
entropyThreshold float64
|
||||
perCharThreshold float64
|
||||
truncate int
|
||||
ignoreEntropy bool
|
||||
}
|
||||
|
||||
func truncate(s string, n int) string {
|
||||
if n > len(s) {
|
||||
return s
|
||||
}
|
||||
return s[:n]
|
||||
}
|
||||
|
||||
func (r *credentials) isHighEntropyString(str string) bool {
|
||||
s := truncate(str, r.truncate)
|
||||
info := zxcvbn.PasswordStrength(s, []string{})
|
||||
entropyPerChar := info.Entropy / float64(len(s))
|
||||
return (info.Entropy >= r.entropyThreshold ||
|
||||
(info.Entropy >= (r.entropyThreshold/2) &&
|
||||
entropyPerChar >= r.perCharThreshold))
|
||||
}
|
||||
|
||||
func (r *credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
switch node := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
return r.matchAssign(node, ctx)
|
||||
case *ast.GenDecl:
|
||||
return r.matchGenDecl(node, ctx)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
|
||||
for _, i := range assign.Lhs {
|
||||
if ident, ok := i.(*ast.Ident); ok {
|
||||
if r.pattern.MatchString(ident.Name) {
|
||||
for _, e := range assign.Rhs {
|
||||
if val, err := gas.GetString(e); err == nil {
|
||||
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
||||
return gas.NewIssue(ctx, assign, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
|
||||
if decl.Tok != token.CONST && decl.Tok != token.VAR {
|
||||
return nil, nil
|
||||
}
|
||||
for _, spec := range decl.Specs {
|
||||
if valueSpec, ok := spec.(*ast.ValueSpec); ok {
|
||||
for index, ident := range valueSpec.Names {
|
||||
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
|
||||
// const foo, bar = "same value"
|
||||
if len(valueSpec.Values) <= index {
|
||||
index = len(valueSpec.Values) - 1
|
||||
}
|
||||
if val, err := gas.GetString(valueSpec.Values[index]); err == nil {
|
||||
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
||||
return gas.NewIssue(ctx, valueSpec, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewHardcodedCredentials attempts to find high entropy string constants being
|
||||
// assigned to variables that appear to be related to credentials.
|
||||
func NewHardcodedCredentials(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
||||
entropyThreshold := 80.0
|
||||
perCharThreshold := 3.0
|
||||
ignoreEntropy := false
|
||||
var truncateString = 16
|
||||
if val, ok := conf["G101"]; ok {
|
||||
conf := val.(map[string]string)
|
||||
if configPattern, ok := conf["pattern"]; ok {
|
||||
pattern = configPattern
|
||||
}
|
||||
if configIgnoreEntropy, ok := conf["ignore_entropy"]; ok {
|
||||
if parsedBool, err := strconv.ParseBool(configIgnoreEntropy); err == nil {
|
||||
ignoreEntropy = parsedBool
|
||||
}
|
||||
}
|
||||
if configEntropyThreshold, ok := conf["entropy_threshold"]; ok {
|
||||
if parsedNum, err := strconv.ParseFloat(configEntropyThreshold, 64); err == nil {
|
||||
entropyThreshold = parsedNum
|
||||
}
|
||||
}
|
||||
if configCharThreshold, ok := conf["per_char_threshold"]; ok {
|
||||
if parsedNum, err := strconv.ParseFloat(configCharThreshold, 64); err == nil {
|
||||
perCharThreshold = parsedNum
|
||||
}
|
||||
}
|
||||
if configTruncate, ok := conf["truncate"]; ok {
|
||||
if parsedInt, err := strconv.Atoi(configTruncate); err == nil {
|
||||
truncateString = parsedInt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &credentials{
|
||||
pattern: regexp.MustCompile(pattern),
|
||||
entropyThreshold: entropyThreshold,
|
||||
perCharThreshold: perCharThreshold,
|
||||
ignoreEntropy: ignoreEntropy,
|
||||
truncate: truncateString,
|
||||
MetaData: gas.MetaData{
|
||||
What: "Potential hardcoded credentials",
|
||||
Confidence: gas.Low,
|
||||
Severity: gas.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.GenDecl)(nil)}
|
||||
}
|
50
tools/vendor/github.com/GoASTScanner/gas/rules/rand.go
generated
vendored
50
tools/vendor/github.com/GoASTScanner/gas/rules/rand.go
generated
vendored
@ -1,50 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type weakRand struct {
|
||||
gas.MetaData
|
||||
funcNames []string
|
||||
packagePath string
|
||||
}
|
||||
|
||||
func (w *weakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
for _, funcName := range w.funcNames {
|
||||
if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
||||
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
|
||||
func NewWeakRandCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &weakRand{
|
||||
funcNames: []string{"Read", "Int"},
|
||||
packagePath: "math/rand",
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
Confidence: gas.Medium,
|
||||
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
53
tools/vendor/github.com/GoASTScanner/gas/rules/rsa.go
generated
vendored
53
tools/vendor/github.com/GoASTScanner/gas/rules/rsa.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type weakKeyStrength struct {
|
||||
gas.MetaData
|
||||
calls gas.CallList
|
||||
bits int
|
||||
}
|
||||
|
||||
func (w *weakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if callExpr := w.calls.ContainsCallExpr(n, c); callExpr != nil {
|
||||
if bits, err := gas.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
|
||||
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits
|
||||
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("crypto/rsa", "GenerateKey")
|
||||
bits := 2048
|
||||
return &weakKeyStrength{
|
||||
calls: calls,
|
||||
bits: bits,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
102
tools/vendor/github.com/GoASTScanner/gas/rules/rulelist.go
generated
vendored
102
tools/vendor/github.com/GoASTScanner/gas/rules/rulelist.go
generated
vendored
@ -1,102 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// RuleDefinition contains the description of a rule and a mechanism to
|
||||
// create it.
|
||||
type RuleDefinition struct {
|
||||
Description string
|
||||
Create gas.RuleBuilder
|
||||
}
|
||||
|
||||
// RuleList is a mapping of rule ID's to rule definitions
|
||||
type RuleList map[string]RuleDefinition
|
||||
|
||||
// Builders returns all the create methods for a given rule list
|
||||
func (rl RuleList) Builders() []gas.RuleBuilder {
|
||||
builders := make([]gas.RuleBuilder, 0, len(rl))
|
||||
for _, def := range rl {
|
||||
builders = append(builders, def.Create)
|
||||
}
|
||||
return builders
|
||||
}
|
||||
|
||||
// RuleFilter can be used to include or exclude a rule depending on the return
|
||||
// value of the function
|
||||
type RuleFilter func(string) bool
|
||||
|
||||
// NewRuleFilter is a closure that will include/exclude the rule ID's based on
|
||||
// the supplied boolean value.
|
||||
func NewRuleFilter(action bool, ruleIDs ...string) RuleFilter {
|
||||
rulelist := make(map[string]bool)
|
||||
for _, rule := range ruleIDs {
|
||||
rulelist[rule] = true
|
||||
}
|
||||
return func(rule string) bool {
|
||||
if _, found := rulelist[rule]; found {
|
||||
return action
|
||||
}
|
||||
return !action
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the list of rules to use
|
||||
func Generate(filters ...RuleFilter) RuleList {
|
||||
rules := map[string]RuleDefinition{
|
||||
// misc
|
||||
"G101": {"Look for hardcoded credentials", NewHardcodedCredentials},
|
||||
"G102": {"Bind to all interfaces", NewBindsToAllNetworkInterfaces},
|
||||
"G103": {"Audit the use of unsafe block", NewUsingUnsafe},
|
||||
"G104": {"Audit errors not checked", NewNoErrorCheck},
|
||||
"G105": {"Audit the use of big.Exp function", NewUsingBigExp},
|
||||
"G106": {"Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey},
|
||||
|
||||
// injection
|
||||
"G201": {"SQL query construction using format string", NewSQLStrFormat},
|
||||
"G202": {"SQL query construction using string concatenation", NewSQLStrConcat},
|
||||
"G203": {"Use of unescaped data in HTML templates", NewTemplateCheck},
|
||||
"G204": {"Audit use of command execution", NewSubproc},
|
||||
|
||||
// filesystem
|
||||
"G301": {"Poor file permissions used when creating a directory", NewMkdirPerms},
|
||||
"G302": {"Poor file permisions used when creation file or using chmod", NewFilePerms},
|
||||
"G303": {"Creating tempfile using a predictable path", NewBadTempFile},
|
||||
|
||||
// crypto
|
||||
"G401": {"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
|
||||
"G402": {"Look for bad TLS connection settings", NewIntermediateTLSCheck},
|
||||
"G403": {"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
|
||||
"G404": {"Insecure random number source (rand)", NewWeakRandCheck},
|
||||
|
||||
// blacklist
|
||||
"G501": {"Import blacklist: crypto/md5", NewBlacklistedImportMD5},
|
||||
"G502": {"Import blacklist: crypto/des", NewBlacklistedImportDES},
|
||||
"G503": {"Import blacklist: crypto/rc4", NewBlacklistedImportRC4},
|
||||
"G504": {"Import blacklist: net/http/cgi", NewBlacklistedImportCGI},
|
||||
}
|
||||
|
||||
for rule := range rules {
|
||||
for _, filter := range filters {
|
||||
if filter(rule) {
|
||||
delete(rules, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}
|
125
tools/vendor/github.com/GoASTScanner/gas/rules/sql.go
generated
vendored
125
tools/vendor/github.com/GoASTScanner/gas/rules/sql.go
generated
vendored
@ -1,125 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type sqlStatement struct {
|
||||
gas.MetaData
|
||||
|
||||
// Contains a list of patterns which must all match for the rule to match.
|
||||
patterns []*regexp.Regexp
|
||||
}
|
||||
|
||||
// See if the string matches the patterns for the statement.
|
||||
func (s sqlStatement) MatchPatterns(str string) bool {
|
||||
for _, pattern := range s.patterns {
|
||||
if !pattern.MatchString(str) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type sqlStrConcat struct {
|
||||
sqlStatement
|
||||
}
|
||||
|
||||
// see if we can figure out what it is
|
||||
func (s *sqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||
if n.Obj != nil {
|
||||
return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Look for "SELECT * FROM table WHERE " + " ' OR 1=1"
|
||||
func (s *sqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node, ok := n.(*ast.BinaryExpr); ok {
|
||||
if start, ok := node.X.(*ast.BasicLit); ok {
|
||||
if str, e := gas.GetString(start); e == nil {
|
||||
if !s.MatchPatterns(str) {
|
||||
return nil, nil
|
||||
}
|
||||
if _, ok := node.Y.(*ast.BasicLit); ok {
|
||||
return nil, nil // string cat OK
|
||||
}
|
||||
if second, ok := node.Y.(*ast.Ident); ok && s.checkObject(second) {
|
||||
return nil, nil
|
||||
}
|
||||
return gas.NewIssue(c, n, s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
|
||||
func NewSQLStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &sqlStrConcat{
|
||||
sqlStatement: sqlStatement{
|
||||
patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||
},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "SQL string concatenation",
|
||||
},
|
||||
},
|
||||
}, []ast.Node{(*ast.BinaryExpr)(nil)}
|
||||
}
|
||||
|
||||
type sqlStrFormat struct {
|
||||
sqlStatement
|
||||
calls gas.CallList
|
||||
}
|
||||
|
||||
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
||||
func (s *sqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
|
||||
// TODO(gm) improve confidence if database/sql is being used
|
||||
if node := s.calls.ContainsCallExpr(n, c); node != nil {
|
||||
if arg, e := gas.GetString(node.Args[0]); s.MatchPatterns(arg) && e == nil {
|
||||
return gas.NewIssue(c, n, s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
|
||||
func NewSQLStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
rule := &sqlStrFormat{
|
||||
calls: gas.NewCallList(),
|
||||
sqlStatement: sqlStatement{
|
||||
patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
|
||||
regexp.MustCompile("%[^bdoxXfFp]"),
|
||||
},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "SQL string formatting",
|
||||
},
|
||||
},
|
||||
}
|
||||
rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
33
tools/vendor/github.com/GoASTScanner/gas/rules/ssh.go
generated
vendored
33
tools/vendor/github.com/GoASTScanner/gas/rules/ssh.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type sshHostKey struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *sshHostKey) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSSHHostKey rule detects the use of insecure ssh HostKeyCallback.
|
||||
func NewSSHHostKey(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &sshHostKey{
|
||||
pkg: "golang.org/x/crypto/ssh",
|
||||
calls: []string{"InsecureIgnoreHostKey"},
|
||||
MetaData: gas.MetaData{
|
||||
What: "Use of ssh InsecureIgnoreHostKey should be audited",
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
58
tools/vendor/github.com/GoASTScanner/gas/rules/subproc.go
generated
vendored
58
tools/vendor/github.com/GoASTScanner/gas/rules/subproc.go
generated
vendored
@ -1,58 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type subprocess struct {
|
||||
gas.CallList
|
||||
}
|
||||
|
||||
// TODO(gm) The only real potential for command injection with a Go project
|
||||
// is something like this:
|
||||
//
|
||||
// syscall.Exec("/bin/sh", []string{"-c", tainted})
|
||||
//
|
||||
// E.g. Input is correctly escaped but the execution context being used
|
||||
// is unsafe. For example:
|
||||
//
|
||||
// syscall.Exec("echo", "foobar" + tainted)
|
||||
func (r *subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := r.ContainsCallExpr(n, c); node != nil {
|
||||
for _, arg := range node.Args {
|
||||
if ident, ok := arg.(*ast.Ident); ok {
|
||||
obj := c.Info.ObjectOf(ident)
|
||||
if _, ok := obj.(*types.Var); ok && !gas.TryResolve(ident, c) {
|
||||
return gas.NewIssue(c, n, "Subprocess launched with variable", gas.Medium, gas.High), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return gas.NewIssue(c, n, "Subprocess launching should be audited", gas.Low, gas.High), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSubproc detects cases where we are forking out to an external process
|
||||
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
rule := &subprocess{gas.NewCallList()}
|
||||
rule.Add("os/exec", "Command")
|
||||
rule.Add("syscall", "Exec")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
53
tools/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go
generated
vendored
53
tools/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type badTempFile struct {
|
||||
gas.MetaData
|
||||
calls gas.CallList
|
||||
args *regexp.Regexp
|
||||
}
|
||||
|
||||
func (t *badTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := t.calls.ContainsCallExpr(n, c); node != nil {
|
||||
if arg, e := gas.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil {
|
||||
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewBadTempFile detects direct writes to predictable path in temporary directory
|
||||
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("io/ioutil", "WriteFile")
|
||||
calls.Add("os", "Create")
|
||||
return &badTempFile{
|
||||
calls: calls,
|
||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
56
tools/vendor/github.com/GoASTScanner/gas/rules/templates.go
generated
vendored
56
tools/vendor/github.com/GoASTScanner/gas/rules/templates.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type templateCheck struct {
|
||||
gas.MetaData
|
||||
calls gas.CallList
|
||||
}
|
||||
|
||||
func (t *templateCheck) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := t.calls.ContainsCallExpr(n, c); node != nil {
|
||||
for _, arg := range node.Args {
|
||||
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
|
||||
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewTemplateCheck constructs the template check rule. This rule is used to
|
||||
// find use of tempaltes where HTML/JS escaping is not being used
|
||||
func NewTemplateCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("html/template", "HTML")
|
||||
calls.Add("html/template", "HTMLAttr")
|
||||
calls.Add("html/template", "JS")
|
||||
calls.Add("html/template", "URL")
|
||||
return &templateCheck{
|
||||
calls: calls,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.Low,
|
||||
What: "this method will not auto-escape HTML. Verify data is well formed.",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
125
tools/vendor/github.com/GoASTScanner/gas/rules/tls.go
generated
vendored
125
tools/vendor/github.com/GoASTScanner/gas/rules/tls.go
generated
vendored
@ -1,125 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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.
|
||||
|
||||
//go:generate tlsconfig
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type insecureConfigTLS struct {
|
||||
MinVersion int16
|
||||
MaxVersion int16
|
||||
requiredType string
|
||||
goodCiphers []string
|
||||
}
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gas.Context) *gas.Issue {
|
||||
|
||||
if ciphers, ok := n.(*ast.CompositeLit); ok {
|
||||
for _, cipher := range ciphers.Elts {
|
||||
if ident, ok := cipher.(*ast.SelectorExpr); ok {
|
||||
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
|
||||
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
|
||||
return gas.NewIssue(c, ident, err, gas.High, gas.High)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gas.Context) *gas.Issue {
|
||||
if ident, ok := n.Key.(*ast.Ident); ok {
|
||||
switch ident.Name {
|
||||
|
||||
case "InsecureSkipVerify":
|
||||
if node, ok := n.Value.(*ast.Ident); ok {
|
||||
if node.Name != "false" {
|
||||
return gas.NewIssue(c, n, "TLS InsecureSkipVerify set true.", gas.High, gas.High)
|
||||
}
|
||||
} else {
|
||||
// TODO(tk): symbol tab look up to get the actual value
|
||||
return gas.NewIssue(c, n, "TLS InsecureSkipVerify may be true.", gas.High, gas.Low)
|
||||
}
|
||||
|
||||
case "PreferServerCipherSuites":
|
||||
if node, ok := n.Value.(*ast.Ident); ok {
|
||||
if node.Name == "false" {
|
||||
return gas.NewIssue(c, n, "TLS PreferServerCipherSuites set false.", gas.Medium, gas.High)
|
||||
}
|
||||
} else {
|
||||
// TODO(tk): symbol tab look up to get the actual value
|
||||
return gas.NewIssue(c, n, "TLS PreferServerCipherSuites may be false.", gas.Medium, gas.Low)
|
||||
}
|
||||
|
||||
case "MinVersion":
|
||||
if ival, ierr := gas.GetInt(n.Value); ierr == nil {
|
||||
if (int16)(ival) < t.MinVersion {
|
||||
return gas.NewIssue(c, n, "TLS MinVersion too low.", gas.High, gas.High)
|
||||
}
|
||||
// TODO(tk): symbol tab look up to get the actual value
|
||||
return gas.NewIssue(c, n, "TLS MinVersion may be too low.", gas.High, gas.Low)
|
||||
}
|
||||
|
||||
case "MaxVersion":
|
||||
if ival, ierr := gas.GetInt(n.Value); ierr == nil {
|
||||
if (int16)(ival) < t.MaxVersion {
|
||||
return gas.NewIssue(c, n, "TLS MaxVersion too low.", gas.High, gas.High)
|
||||
}
|
||||
// TODO(tk): symbol tab look up to get the actual value
|
||||
return gas.NewIssue(c, n, "TLS MaxVersion may be too low.", gas.High, gas.Low)
|
||||
}
|
||||
|
||||
case "CipherSuites":
|
||||
if ret := t.processTLSCipherSuites(n.Value, c); ret != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
|
||||
actualType := c.Info.TypeOf(complit.Type)
|
||||
if actualType != nil && actualType.String() == t.requiredType {
|
||||
for _, elt := range complit.Elts {
|
||||
if kve, ok := elt.(*ast.KeyValueExpr); ok {
|
||||
issue := t.processTLSConfVal(kve, c)
|
||||
if issue != nil {
|
||||
return issue, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
132
tools/vendor/github.com/GoASTScanner/gas/rules/tls_config.go
generated
vendored
132
tools/vendor/github.com/GoASTScanner/gas/rules/tls_config.go
generated
vendored
@ -1,132 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// NewModernTLSCheck creates a check for Modern TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewModernTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0303,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
// NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewIntermediateTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0301,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
// NewOldTLSCheck creates a check for Old TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewOldTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0300,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
|
||||
"TLS_RSA_WITH_SEED_CBC_SHA",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
48
tools/vendor/github.com/GoASTScanner/gas/rules/unsafe.go
generated
vendored
48
tools/vendor/github.com/GoASTScanner/gas/rules/unsafe.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type usingUnsafe struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *usingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewUsingUnsafe rule detects the use of the unsafe package. This is only
|
||||
// really useful for auditing purposes.
|
||||
func NewUsingUnsafe(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &usingUnsafe{
|
||||
pkg: "unsafe",
|
||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||
MetaData: gas.MetaData{
|
||||
What: "Use of unsafe calls should be audited",
|
||||
Severity: gas.Low,
|
||||
Confidence: gas.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
53
tools/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go
generated
vendored
53
tools/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// 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 rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type usesWeakCryptography struct {
|
||||
gas.MetaData
|
||||
blacklist map[string][]string
|
||||
}
|
||||
|
||||
func (r *usesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
|
||||
for pkg, funcs := range r.blacklist {
|
||||
if _, matched := gas.MatchCallByPackage(n, c, pkg, funcs...); matched {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewUsesWeakCryptography detects uses of des.* md5.* or rc4.*
|
||||
func NewUsesWeakCryptography(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := make(map[string][]string)
|
||||
calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"}
|
||||
calls["crypto/md5"] = []string{"New", "Sum"}
|
||||
calls["crypto/rc4"] = []string{"NewCipher"}
|
||||
rule := &usesWeakCryptography{
|
||||
blacklist: calls,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "Use of weak cryptographic primitive",
|
||||
},
|
||||
}
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
27
tools/vendor/github.com/alecthomas/gocyclo/LICENSE
generated
vendored
27
tools/vendor/github.com/alecthomas/gocyclo/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2013 Frederik Zipp. 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 the copyright owner 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.
|
31
tools/vendor/github.com/alecthomas/gocyclo/README.md
generated
vendored
31
tools/vendor/github.com/alecthomas/gocyclo/README.md
generated
vendored
@ -1,31 +0,0 @@
|
||||
Gocyclo calculates cyclomatic complexities of functions in Go source code.
|
||||
|
||||
The cyclomatic complexity of a function is calculated according to the
|
||||
following rules:
|
||||
|
||||
1 is the base complexity of a function
|
||||
+1 for each 'if', 'for', 'case', '&&' or '||'
|
||||
|
||||
To install, run
|
||||
|
||||
$ go get github.com/fzipp/gocyclo
|
||||
|
||||
and put the resulting binary in one of your PATH directories if
|
||||
`$GOPATH/bin` isn't already in your PATH.
|
||||
|
||||
Usage:
|
||||
|
||||
$ gocyclo [<flag> ...] <Go file or directory> ...
|
||||
|
||||
Examples:
|
||||
|
||||
$ gocyclo .
|
||||
$ gocyclo main.go
|
||||
$ gocyclo -top 10 src/
|
||||
$ gocyclo -over 25 docker
|
||||
$ gocyclo -avg .
|
||||
|
||||
The output fields for each line are:
|
||||
|
||||
<complexity> <package> <function> <file:row:column>
|
||||
|
222
tools/vendor/github.com/alecthomas/gocyclo/gocyclo.go
generated
vendored
222
tools/vendor/github.com/alecthomas/gocyclo/gocyclo.go
generated
vendored
@ -1,222 +0,0 @@
|
||||
// Copyright 2013 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Gocyclo calculates the cyclomatic complexities of functions and
|
||||
// methods in Go source code.
|
||||
//
|
||||
// Usage:
|
||||
// gocyclo [<flag> ...] <Go file or directory> ...
|
||||
//
|
||||
// Flags
|
||||
// -over N show functions with complexity > N only and
|
||||
// return exit code 1 if the output is non-empty
|
||||
// -top N show the top N most complex functions only
|
||||
// -avg show the average complexity
|
||||
//
|
||||
// The output fields for each line are:
|
||||
// <complexity> <package> <function> <file:row:column>
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const usageDoc = `Calculate cyclomatic complexities of Go functions.
|
||||
usage:
|
||||
gocyclo [<flag> ...] <Go file or directory> ...
|
||||
|
||||
Flags
|
||||
-over N show functions with complexity > N only and
|
||||
return exit code 1 if the set is non-empty
|
||||
-top N show the top N most complex functions only
|
||||
-avg show the average complexity over all functions,
|
||||
not depending on whether -over or -top are set
|
||||
|
||||
The output fields for each line are:
|
||||
<complexity> <package> <function> <file:row:column>
|
||||
`
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, usageDoc)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var (
|
||||
over = flag.Int("over", 0, "show functions with complexity > N only")
|
||||
top = flag.Int("top", -1, "show the top N most complex functions only")
|
||||
avg = flag.Bool("avg", false, "show the average complexity")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
if len(args) == 0 {
|
||||
usage()
|
||||
}
|
||||
|
||||
stats := analyze(args)
|
||||
sort.Sort(byComplexity(stats))
|
||||
written := writeStats(os.Stdout, stats)
|
||||
|
||||
if *avg {
|
||||
showAverage(stats)
|
||||
}
|
||||
|
||||
if *over > 0 && written > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func analyze(paths []string) []stat {
|
||||
stats := make([]stat, 0)
|
||||
for _, path := range paths {
|
||||
if isDir(path) {
|
||||
stats = analyzeDir(path, stats)
|
||||
} else {
|
||||
stats = analyzeFile(path, stats)
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func isDir(filename string) bool {
|
||||
fi, err := os.Stat(filename)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
func analyzeFile(fname string, stats []stat) []stat {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, fname, nil, 0)
|
||||
if err != nil {
|
||||
exitError(err)
|
||||
}
|
||||
return buildStats(f, fset, stats)
|
||||
}
|
||||
|
||||
func analyzeDir(dirname string, stats []stat) []stat {
|
||||
files, _ := filepath.Glob(filepath.Join(dirname, "*.go"))
|
||||
for _, file := range files {
|
||||
stats = analyzeFile(file, stats)
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func exitError(err error) {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func writeStats(w io.Writer, sortedStats []stat) int {
|
||||
for i, stat := range sortedStats {
|
||||
if i == *top {
|
||||
return i
|
||||
}
|
||||
if stat.Complexity <= *over {
|
||||
return i
|
||||
}
|
||||
fmt.Fprintln(w, stat)
|
||||
}
|
||||
return len(sortedStats)
|
||||
}
|
||||
|
||||
func showAverage(stats []stat) {
|
||||
fmt.Printf("Average: %.3g\n", average(stats))
|
||||
}
|
||||
|
||||
func average(stats []stat) float64 {
|
||||
total := 0
|
||||
for _, s := range stats {
|
||||
total += s.Complexity
|
||||
}
|
||||
return float64(total) / float64(len(stats))
|
||||
}
|
||||
|
||||
type stat struct {
|
||||
PkgName string
|
||||
FuncName string
|
||||
Complexity int
|
||||
Pos token.Position
|
||||
}
|
||||
|
||||
func (s stat) String() string {
|
||||
return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
|
||||
}
|
||||
|
||||
type byComplexity []stat
|
||||
|
||||
func (s byComplexity) Len() int { return len(s) }
|
||||
func (s byComplexity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byComplexity) Less(i, j int) bool {
|
||||
return s[i].Complexity >= s[j].Complexity
|
||||
}
|
||||
|
||||
func buildStats(f *ast.File, fset *token.FileSet, stats []stat) []stat {
|
||||
for _, decl := range f.Decls {
|
||||
if fn, ok := decl.(*ast.FuncDecl); ok {
|
||||
stats = append(stats, stat{
|
||||
PkgName: f.Name.Name,
|
||||
FuncName: funcName(fn),
|
||||
Complexity: complexity(fn),
|
||||
Pos: fset.Position(fn.Pos()),
|
||||
})
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
// funcName returns the name representation of a function or method:
|
||||
// "(Type).Name" for methods or simply "Name" for functions.
|
||||
func funcName(fn *ast.FuncDecl) string {
|
||||
if fn.Recv != nil {
|
||||
typ := fn.Recv.List[0].Type
|
||||
return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
|
||||
}
|
||||
return fn.Name.Name
|
||||
}
|
||||
|
||||
// recvString returns a string representation of recv of the
|
||||
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
|
||||
func recvString(recv ast.Expr) string {
|
||||
switch t := recv.(type) {
|
||||
case *ast.Ident:
|
||||
return t.Name
|
||||
case *ast.StarExpr:
|
||||
return "*" + recvString(t.X)
|
||||
}
|
||||
return "BADRECV"
|
||||
}
|
||||
|
||||
// complexity calculates the cyclomatic complexity of a function.
|
||||
func complexity(fn *ast.FuncDecl) int {
|
||||
v := complexityVisitor{}
|
||||
ast.Walk(&v, fn)
|
||||
return v.Complexity
|
||||
}
|
||||
|
||||
type complexityVisitor struct {
|
||||
// Complexity is the cyclomatic complexity
|
||||
Complexity int
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
|
||||
switch n := n.(type) {
|
||||
case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause:
|
||||
v.Complexity++
|
||||
case *ast.BinaryExpr:
|
||||
if n.Op == token.LAND || n.Op == token.LOR {
|
||||
v.Complexity++
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
56
tools/vendor/github.com/alecthomas/gometalinter/CONTRIBUTING.md
generated
vendored
56
tools/vendor/github.com/alecthomas/gometalinter/CONTRIBUTING.md
generated
vendored
@ -1,56 +0,0 @@
|
||||
### Please only report errors with gometalinter itself
|
||||
|
||||
gometalinter relies on underlying linters to detect issues in source code.
|
||||
If your issue seems to be related to an underlying linter, please report an
|
||||
issue against that linter rather than gometalinter. For a full list of linters
|
||||
and their repositories please see the [README](README.md).
|
||||
|
||||
### Do you want to upgrade a vendored linter?
|
||||
|
||||
Please send a PR. We use [GVT](https://github.com/FiloSottile/gvt). It should be as simple as:
|
||||
|
||||
```
|
||||
go get github.com/FiloSottile/gvt
|
||||
cd _linters
|
||||
gvt update <linter>
|
||||
git add <paths>
|
||||
```
|
||||
|
||||
### Before you report an issue
|
||||
|
||||
Sometimes gometalinter will not report issues that you think it should. There
|
||||
are three things to try in that case:
|
||||
|
||||
#### 1. Update to the latest build of gometalinter and all linters
|
||||
|
||||
go get -u github.com/alecthomas/gometalinter
|
||||
gometalinter --install
|
||||
|
||||
If you're lucky, this will fix the problem.
|
||||
|
||||
#### 2. Analyse the debug output
|
||||
|
||||
If that doesn't help, the problem may be elsewhere (in no particular order):
|
||||
|
||||
1. Upstream linter has changed its output or semantics.
|
||||
2. gometalinter is not invoking the tool correctly.
|
||||
3. gometalinter regular expression matches are not correct for a linter.
|
||||
4. Linter is exceeding the deadline.
|
||||
|
||||
To find out what's going on run in debug mode:
|
||||
|
||||
gometalinter --debug
|
||||
|
||||
This will show all output from the linters and should indicate why it is
|
||||
failing.
|
||||
|
||||
#### 3. Run linters manually
|
||||
|
||||
The output of `gometalinter --debug` should show the exact commands gometalinter
|
||||
is running. Run these commands from the command line to determine if the linter
|
||||
or gometaliner is at fault.
|
||||
|
||||
#### 4. Report an issue.
|
||||
|
||||
Failing all else, if the problem looks like a bug please file an issue and
|
||||
include the output of `gometalinter --debug`
|
19
tools/vendor/github.com/alecthomas/gometalinter/COPYING
generated
vendored
19
tools/vendor/github.com/alecthomas/gometalinter/COPYING
generated
vendored
@ -1,19 +0,0 @@
|
||||
Copyright (C) 2012 Alec Thomas
|
||||
|
||||
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.
|
376
tools/vendor/github.com/alecthomas/gometalinter/README.md
generated
vendored
376
tools/vendor/github.com/alecthomas/gometalinter/README.md
generated
vendored
@ -1,376 +0,0 @@
|
||||
# Go Meta Linter
|
||||
[](https://travis-ci.org/alecthomas/gometalinter) [](https://gitter.im/alecthomas/Lobby)
|
||||
|
||||
<!-- MarkdownTOC -->
|
||||
|
||||
- [Installing](#installing)
|
||||
- [Editor integration](#editor-integration)
|
||||
- [Supported linters](#supported-linters)
|
||||
- [Configuration file](#configuration-file)
|
||||
- [`Format` key](#format-key)
|
||||
- [Format Methods](#format-methods)
|
||||
- [Adding Custom linters](#adding-custom-linters)
|
||||
- [Comment directives](#comment-directives)
|
||||
- [Quickstart](#quickstart)
|
||||
- [FAQ](#faq)
|
||||
- [Exit status](#exit-status)
|
||||
- [What's the best way to use `gometalinter` in CI?](#whats-the-best-way-to-use-gometalinter-in-ci)
|
||||
- [How do I make `gometalinter` work with Go 1.5 vendoring?](#how-do-i-make-gometalinter-work-with-go-15-vendoring)
|
||||
- [Why does `gometalinter --install` install a fork of gocyclo?](#why-does-gometalinter---install-install-a-fork-of-gocyclo)
|
||||
- [Gometalinter is not working](#gometalinter-is-not-working)
|
||||
- [1. Update to the latest build of gometalinter and all linters](#1-update-to-the-latest-build-of-gometalinter-and-all-linters)
|
||||
- [2. Analyse the debug output](#2-analyse-the-debug-output)
|
||||
- [3. Report an issue.](#3-report-an-issue)
|
||||
- [How do I filter issues between two git refs?](#how-do-i-filter-issues-between-two-git-refs)
|
||||
- [Checkstyle XML format](#checkstyle-xml-format)
|
||||
|
||||
<!-- /MarkdownTOC -->
|
||||
|
||||
|
||||
The number of tools for statically checking Go source for errors and warnings
|
||||
is impressive.
|
||||
|
||||
This is a tool that concurrently runs a whole bunch of those linters and
|
||||
normalises their output to a standard format:
|
||||
|
||||
<file>:<line>:[<column>]: <message> (<linter>)
|
||||
|
||||
eg.
|
||||
|
||||
stutter.go:9::warning: unused global variable unusedGlobal (varcheck)
|
||||
stutter.go:12:6:warning: exported type MyStruct should have comment or be unexported (golint)
|
||||
|
||||
It is intended for use with editor/IDE integration.
|
||||
|
||||
## Installing
|
||||
|
||||
There are two options for installing gometalinter.
|
||||
|
||||
1. Install a stable version, eg. `go get -u gopkg.in/alecthomas/gometalinter.v2`.
|
||||
I will generally only tag a new stable version when it has passed the Travis
|
||||
regression tests. The downside is that the binary will be called `gometalinter.v2`.
|
||||
2. Install from HEAD with: `go get -u github.com/alecthomas/gometalinter`.
|
||||
This has the downside that changes to gometalinter may break.
|
||||
|
||||
## Editor integration
|
||||
|
||||
- [SublimeLinter plugin](https://github.com/alecthomas/SublimeLinter-contrib-gometalinter).
|
||||
- [Atom go-plus package](https://atom.io/packages/go-plus).
|
||||
- [Emacs Flycheck checker](https://github.com/favadi/flycheck-gometalinter).
|
||||
- [Go for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=lukehoban.Go).
|
||||
- Vim/Neovim
|
||||
- [Neomake](https://github.com/neomake/neomake).
|
||||
- [Syntastic](https://github.com/scrooloose/syntastic/wiki/Go:---gometalinter) `let g:syntastic_go_checkers = ['gometalinter']`.
|
||||
- [ale](https://github.com/w0rp/ale) `let g:ale_linters = {'go': ['gometalinter']}`
|
||||
- [vim-go](https://github.com/fatih/vim-go) with the `:GoMetaLinter` command.
|
||||
|
||||
## Supported linters
|
||||
|
||||
- [go vet](https://golang.org/cmd/vet/) - Reports potential errors that otherwise compile.
|
||||
- [go tool vet --shadow](https://golang.org/cmd/vet/#hdr-Shadowed_variables) - Reports variables that may have been unintentionally shadowed.
|
||||
- [gotype](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis similar to the Go compiler.
|
||||
- [gotype -x](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis in external test packages (similar to the Go compiler).
|
||||
- [deadcode](https://github.com/tsenart/deadcode) - Finds unused code.
|
||||
- [gocyclo](https://github.com/alecthomas/gocyclo) - Computes the cyclomatic complexity of functions.
|
||||
- [golint](https://github.com/golang/lint) - Google's (mostly stylistic) linter.
|
||||
- [varcheck](https://github.com/opennota/check) - Find unused global variables and constants.
|
||||
- [structcheck](https://github.com/opennota/check) - Find unused struct fields.
|
||||
- [maligned](https://github.com/mdempsky/maligned) - Detect structs that would take less memory if their fields were sorted.
|
||||
- [errcheck](https://github.com/kisielk/errcheck) - Check that error return values are used.
|
||||
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - Run staticcheck, gosimple and unused, sharing work.
|
||||
- [dupl](https://github.com/mibk/dupl) - Reports potentially duplicated code.
|
||||
- [ineffassign](https://github.com/gordonklaus/ineffassign/blob/master/list) - Detect when assignments to *existing* variables are not used.
|
||||
- [interfacer](https://github.com/mvdan/interfacer) - Suggest narrower interfaces that can be used.
|
||||
- [unconvert](https://github.com/mdempsky/unconvert) - Detect redundant type conversions.
|
||||
- [goconst](https://github.com/jgautheron/goconst) - Finds repeated strings that could be replaced by a constant.
|
||||
- [gas](https://github.com/GoASTScanner/gas) - Inspects source code for security problems by scanning the Go AST.
|
||||
|
||||
Disabled by default (enable with `--enable=<linter>`):
|
||||
|
||||
- [testify](https://github.com/stretchr/testify) - Show location of failed testify assertions.
|
||||
- [test](http://golang.org/pkg/testing/) - Show location of test failures from the stdlib testing module.
|
||||
- [gofmt -s](https://golang.org/cmd/gofmt/) - Checks if the code is properly formatted and could not be further simplified.
|
||||
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Checks missing or unreferenced package imports.
|
||||
- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Report simplifications in code.
|
||||
- [lll](https://github.com/walle/lll) - Report long lines (see `--line-length=N`).
|
||||
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words.
|
||||
- [nakedret](https://github.com/alexkohler/nakedret) - Finds naked returns.
|
||||
- [unparam](https://github.com/mvdan/unparam) - Find unused function parameters.
|
||||
- [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused) - Find unused variables.
|
||||
- [safesql](https://github.com/stripe/safesql) - Finds potential SQL injection vulnerabilities.
|
||||
- [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) - Statically detect bugs, both obvious and subtle ones.
|
||||
|
||||
Additional linters can be added through the command line with `--linter=NAME:COMMAND:PATTERN` (see [below](#details)).
|
||||
|
||||
## Configuration file
|
||||
|
||||
gometalinter now supports a JSON configuration file called `.gometalinter.json` that can
|
||||
be placed at the root of your project. The configuration file will be automatically loaded
|
||||
from the working directory or any parent directory and can be overridden by passing
|
||||
`--config=<file>` or ignored with `--no-config`. The format of this file is determined by
|
||||
the `Config` struct in [config.go](https://github.com/alecthomas/gometalinter/blob/master/config.go).
|
||||
|
||||
The configuration file mostly corresponds to command-line flags, with the following exceptions:
|
||||
|
||||
- Linters defined in the configuration file will overlay existing definitions, not replace them.
|
||||
- "Enable" defines the exact set of linters that will be enabled (default
|
||||
linters are disabled). `--help` displays the list of default linters with the exact names
|
||||
you must use.
|
||||
|
||||
Here is an example configuration file:
|
||||
|
||||
```json
|
||||
{
|
||||
"Enable": ["deadcode", "unconvert"]
|
||||
}
|
||||
```
|
||||
|
||||
If a `.gometalinter.json` file is loaded, individual options can still be overridden by
|
||||
passing command-line flags. All flags are parsed in order, meaning configuration passed
|
||||
with the `--config` flag will override any command-line flags passed before and be
|
||||
overridden by flags passed after.
|
||||
|
||||
|
||||
#### `Format` key
|
||||
|
||||
The default `Format` key places the different fields of an `Issue` into a template. this
|
||||
corresponds to the `--format` option command-line flag.
|
||||
|
||||
Default `Format`:
|
||||
```
|
||||
Format: "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
|
||||
```
|
||||
|
||||
#### Format Methods
|
||||
|
||||
* `{{.Path.Relative}}` - equivalent to `{{.Path}}` which outputs a relative path to the file
|
||||
* `{{.Path.Abs}}` - outputs an absolute path to the file
|
||||
|
||||
### Adding Custom linters
|
||||
|
||||
Linters can be added and customized from the config file using the `Linters` field.
|
||||
Linters supports the following fields:
|
||||
|
||||
* `Command` - the path to the linter binary and any default arguments
|
||||
* `Pattern` - a regular expression used to parse the linter output
|
||||
* `IsFast` - if the linter should be run when the `--fast` flag is used
|
||||
* `PartitionStrategy` - how paths args should be passed to the linter command:
|
||||
* `directories` - call the linter once with a list of all the directories
|
||||
* `files` - call the linter once with a list of all the files
|
||||
* `packages` - call the linter once with a list of all the package paths
|
||||
* `files-by-package` - call the linter once per package with a list of the
|
||||
files in the package.
|
||||
* `single-directory` - call the linter once per directory
|
||||
|
||||
The config for default linters can be overridden by using the name of the
|
||||
linter.
|
||||
|
||||
Additional linters can be configured via the command line using the format
|
||||
`NAME:COMMAND:PATTERN`.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ gometalinter --linter='vet:go tool vet -printfuncs=Infof,Debugf,Warningf,Errorf:PATH:LINE:MESSAGE' .
|
||||
```
|
||||
|
||||
## Comment directives
|
||||
|
||||
gometalinter supports suppression of linter messages via comment directives. The
|
||||
form of the directive is:
|
||||
|
||||
```
|
||||
// nolint[: <linter>[, <linter>, ...]]
|
||||
```
|
||||
|
||||
Suppression works in the following way:
|
||||
|
||||
1. Line-level suppression
|
||||
|
||||
A comment directive suppresses any linter messages on that line.
|
||||
|
||||
eg. In this example any messages for `a := 10` will be suppressed and errcheck
|
||||
messages for `defer r.Close()` will also be suppressed.
|
||||
|
||||
```go
|
||||
a := 10 // nolint
|
||||
a = 2
|
||||
defer r.Close() // nolint: errcheck
|
||||
```
|
||||
|
||||
2. Statement-level suppression
|
||||
|
||||
A comment directive at the same indentation level as a statement it
|
||||
immediately precedes will also suppress any linter messages in that entire
|
||||
statement.
|
||||
|
||||
eg. In this example all messages for `SomeFunc()` will be suppressed.
|
||||
|
||||
```go
|
||||
// nolint
|
||||
func SomeFunc() {
|
||||
}
|
||||
```
|
||||
|
||||
Implementation details: gometalinter now performs parsing of Go source code,
|
||||
to extract linter directives and associate them with line ranges. To avoid
|
||||
unnecessary processing, parsing is on-demand: the first time a linter emits a
|
||||
message for a file, that file is parsed for directives.
|
||||
|
||||
## Quickstart
|
||||
|
||||
Install gometalinter (see above).
|
||||
|
||||
Install all known linters:
|
||||
|
||||
```
|
||||
$ gometalinter --install
|
||||
Installing:
|
||||
structcheck
|
||||
maligned
|
||||
nakedret
|
||||
deadcode
|
||||
gocyclo
|
||||
ineffassign
|
||||
dupl
|
||||
golint
|
||||
gotype
|
||||
goimports
|
||||
errcheck
|
||||
varcheck
|
||||
interfacer
|
||||
goconst
|
||||
gosimple
|
||||
staticcheck
|
||||
unparam
|
||||
unused
|
||||
misspell
|
||||
lll
|
||||
gas
|
||||
safesql
|
||||
```
|
||||
|
||||
Run it:
|
||||
|
||||
```
|
||||
$ cd example
|
||||
$ gometalinter ./...
|
||||
stutter.go:13::warning: unused struct field MyStruct.Unused (structcheck)
|
||||
stutter.go:9::warning: unused global variable unusedGlobal (varcheck)
|
||||
stutter.go:12:6:warning: exported type MyStruct should have comment or be unexported (golint)
|
||||
stutter.go:16:6:warning: exported type PublicUndocumented should have comment or be unexported (golint)
|
||||
stutter.go:8:1:warning: unusedGlobal is unused (deadcode)
|
||||
stutter.go:12:1:warning: MyStruct is unused (deadcode)
|
||||
stutter.go:16:1:warning: PublicUndocumented is unused (deadcode)
|
||||
stutter.go:20:1:warning: duplicateDefer is unused (deadcode)
|
||||
stutter.go:21:15:warning: error return value not checked (defer a.Close()) (errcheck)
|
||||
stutter.go:22:15:warning: error return value not checked (defer a.Close()) (errcheck)
|
||||
stutter.go:27:6:warning: error return value not checked (doit() // test for errcheck) (errcheck)
|
||||
stutter.go:29::error: unreachable code (vet)
|
||||
stutter.go:26::error: missing argument for Printf("%d"): format reads arg 1, have only 0 args (vet)
|
||||
```
|
||||
|
||||
|
||||
Gometalinter also supports the commonly seen `<path>/...` recursive path
|
||||
format. Note that this can be *very* slow, and you may need to increase the linter `--deadline` to allow linters to complete.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Exit status
|
||||
|
||||
gometalinter sets two bits of the exit status to indicate different issues:
|
||||
|
||||
| Bit | Meaning
|
||||
|-----|----------
|
||||
| 0 | A linter generated an issue.
|
||||
| 1 | An underlying error occurred; eg. a linter failed to execute. In this situation a warning will also be displayed.
|
||||
|
||||
eg. linter only = 1, underlying only = 2, linter + underlying = 3
|
||||
|
||||
### What's the best way to use `gometalinter` in CI?
|
||||
|
||||
There are two main problems running in a CI:
|
||||
|
||||
1. <s>Linters break, causing `gometalinter --install --update` to error</s> (this is no longer an issue as all linters are vendored).
|
||||
2. `gometalinter` adds a new linter.
|
||||
|
||||
I have solved 1 by vendoring the linters.
|
||||
|
||||
For 2, the best option is to disable all linters, then explicitly enable the
|
||||
ones you want:
|
||||
|
||||
gometalinter --disable-all --enable=errcheck --enable=vet --enable=vetshadow ...
|
||||
|
||||
### How do I make `gometalinter` work with Go 1.5 vendoring?
|
||||
|
||||
`gometalinter` has a `--vendor` flag that just sets `GO15VENDOREXPERIMENT=1`, however the
|
||||
underlying tools must support it. Ensure that all of the linters are up to date and built with Go 1.5
|
||||
(`gometalinter --install --force`) then run `gometalinter --vendor .`. That should be it.
|
||||
|
||||
### Why does `gometalinter --install` install a fork of gocyclo?
|
||||
|
||||
I forked `gocyclo` because the upstream behaviour is to recursively check all
|
||||
subdirectories even when just a single directory is specified. This made it
|
||||
unusably slow when vendoring. The recursive behaviour can be achieved with
|
||||
gometalinter by explicitly specifying `<path>/...`. There is a
|
||||
[pull request](https://github.com/fzipp/gocyclo/pull/1) open.
|
||||
|
||||
### Gometalinter is not working
|
||||
|
||||
That's more of a statement than a question, but okay.
|
||||
|
||||
Sometimes gometalinter will not report issues that you think it should. There
|
||||
are three things to try in that case:
|
||||
|
||||
#### 1. Update to the latest build of gometalinter and all linters
|
||||
|
||||
go get -u github.com/alecthomas/gometalinter
|
||||
gometalinter --install
|
||||
|
||||
If you're lucky, this will fix the problem.
|
||||
|
||||
#### 2. Analyse the debug output
|
||||
|
||||
If that doesn't help, the problem may be elsewhere (in no particular order):
|
||||
|
||||
1. Upstream linter has changed its output or semantics.
|
||||
2. gometalinter is not invoking the tool correctly.
|
||||
3. gometalinter regular expression matches are not correct for a linter.
|
||||
4. Linter is exceeding the deadline.
|
||||
|
||||
To find out what's going on run in debug mode:
|
||||
|
||||
gometalinter --debug
|
||||
|
||||
This will show all output from the linters and should indicate why it is
|
||||
failing.
|
||||
|
||||
#### 3. Report an issue.
|
||||
|
||||
Failing all else, if the problem looks like a bug please file an issue and
|
||||
include the output of `gometalinter --debug`.
|
||||
|
||||
### How do I filter issues between two git refs?
|
||||
|
||||
[revgrep](https://github.com/bradleyfalzon/revgrep) can be used to filter the output of `gometalinter`
|
||||
to show issues on lines that have changed between two git refs, such as unstaged changes, changes in
|
||||
`HEAD` vs `master` and between `master` and `origin/master`. See the project's documentation and `-help`
|
||||
usage for more information.
|
||||
|
||||
```
|
||||
go get -u github.com/bradleyfalzon/revgrep/...
|
||||
gometalinter |& revgrep # If unstaged changes or untracked files, those issues are shown.
|
||||
gometalinter |& revgrep # Else show issues in the last commit.
|
||||
gometalinter |& revgrep master # Show issues between master and HEAD (or any other reference).
|
||||
gometalinter |& revgrep origin/master # Show issues that haven't been pushed.
|
||||
```
|
||||
|
||||
## Checkstyle XML format
|
||||
|
||||
`gometalinter` supports [checkstyle](http://checkstyle.sourceforge.net/)
|
||||
compatible XML output format. It is triggered with `--checkstyle` flag:
|
||||
|
||||
gometalinter --checkstyle
|
||||
|
||||
Checkstyle format can be used to integrate gometalinter with Jenkins CI with the
|
||||
help of [Checkstyle Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin).
|
51
tools/vendor/github.com/alecthomas/gometalinter/aggregate.go
generated
vendored
51
tools/vendor/github.com/alecthomas/gometalinter/aggregate.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type issueKey struct {
|
||||
path string
|
||||
line, col int
|
||||
message string
|
||||
}
|
||||
|
||||
type multiIssue struct {
|
||||
*Issue
|
||||
linterNames []string
|
||||
}
|
||||
|
||||
// AggregateIssueChan reads issues from a channel, aggregates issues which have
|
||||
// the same file, line, vol, and message, and returns aggregated issues on
|
||||
// a new channel.
|
||||
func AggregateIssueChan(issues chan *Issue) chan *Issue {
|
||||
out := make(chan *Issue, 1000000)
|
||||
issueMap := make(map[issueKey]*multiIssue)
|
||||
go func() {
|
||||
for issue := range issues {
|
||||
key := issueKey{
|
||||
path: issue.Path.String(),
|
||||
line: issue.Line,
|
||||
col: issue.Col,
|
||||
message: issue.Message,
|
||||
}
|
||||
if existing, ok := issueMap[key]; ok {
|
||||
existing.linterNames = append(existing.linterNames, issue.Linter)
|
||||
} else {
|
||||
issueMap[key] = &multiIssue{
|
||||
Issue: issue,
|
||||
linterNames: []string{issue.Linter},
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, multi := range issueMap {
|
||||
issue := multi.Issue
|
||||
sort.Strings(multi.linterNames)
|
||||
issue.Linter = strings.Join(multi.linterNames, ", ")
|
||||
out <- issue
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
65
tools/vendor/github.com/alecthomas/gometalinter/checkstyle.go
generated
vendored
65
tools/vendor/github.com/alecthomas/gometalinter/checkstyle.go
generated
vendored
@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type checkstyleOutput struct {
|
||||
XMLName xml.Name `xml:"checkstyle"`
|
||||
Version string `xml:"version,attr"`
|
||||
Files []*checkstyleFile `xml:"file"`
|
||||
}
|
||||
|
||||
type checkstyleFile struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Errors []*checkstyleError `xml:"error"`
|
||||
}
|
||||
|
||||
type checkstyleError struct {
|
||||
Column int `xml:"column,attr"`
|
||||
Line int `xml:"line,attr"`
|
||||
Message string `xml:"message,attr"`
|
||||
Severity string `xml:"severity,attr"`
|
||||
Source string `xml:"source,attr"`
|
||||
}
|
||||
|
||||
func outputToCheckstyle(issues chan *Issue) int {
|
||||
var lastFile *checkstyleFile
|
||||
out := checkstyleOutput{
|
||||
Version: "5.0",
|
||||
}
|
||||
status := 0
|
||||
for issue := range issues {
|
||||
path := issue.Path.Relative()
|
||||
if lastFile != nil && lastFile.Name != path {
|
||||
out.Files = append(out.Files, lastFile)
|
||||
lastFile = nil
|
||||
}
|
||||
if lastFile == nil {
|
||||
lastFile = &checkstyleFile{Name: path}
|
||||
}
|
||||
|
||||
if config.Errors && issue.Severity != Error {
|
||||
continue
|
||||
}
|
||||
|
||||
lastFile.Errors = append(lastFile.Errors, &checkstyleError{
|
||||
Column: issue.Col,
|
||||
Line: issue.Line,
|
||||
Message: issue.Message,
|
||||
Severity: string(issue.Severity),
|
||||
Source: issue.Linter,
|
||||
})
|
||||
status = 1
|
||||
}
|
||||
if lastFile != nil {
|
||||
out.Files = append(out.Files, lastFile)
|
||||
}
|
||||
d, err := xml.Marshal(&out)
|
||||
kingpin.FatalIfError(err, "")
|
||||
fmt.Printf("%s%s\n", xml.Header, d)
|
||||
return status
|
||||
}
|
192
tools/vendor/github.com/alecthomas/gometalinter/config.go
generated
vendored
192
tools/vendor/github.com/alecthomas/gometalinter/config.go
generated
vendored
@ -1,192 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config for gometalinter. This can be loaded from a JSON file with --config.
|
||||
type Config struct { // nolint: maligned
|
||||
// A map from linter name -> <LinterConfig|string>.
|
||||
//
|
||||
// For backwards compatibility, the value stored in the JSON blob can also
|
||||
// be a string of the form "<command>:<pattern>".
|
||||
Linters map[string]StringOrLinterConfig
|
||||
|
||||
// The set of linters that should be enabled.
|
||||
Enable []string
|
||||
Disable []string
|
||||
|
||||
// A map of linter name to message that is displayed. This is useful when linters display text
|
||||
// that is useful only in isolation, such as errcheck which just reports the construct.
|
||||
MessageOverride map[string]string
|
||||
Severity map[string]string
|
||||
VendoredLinters bool
|
||||
Format string
|
||||
Fast bool
|
||||
Install bool
|
||||
Update bool
|
||||
Force bool
|
||||
DownloadOnly bool
|
||||
Debug bool
|
||||
Concurrency int
|
||||
Exclude []string
|
||||
Include []string
|
||||
Skip []string
|
||||
Vendor bool
|
||||
Cyclo int
|
||||
LineLength int
|
||||
MisspellLocale string
|
||||
MinConfidence float64
|
||||
MinOccurrences int
|
||||
MinConstLength int
|
||||
DuplThreshold int
|
||||
Sort []string
|
||||
Test bool
|
||||
Deadline jsonDuration
|
||||
Errors bool
|
||||
JSON bool
|
||||
Checkstyle bool
|
||||
EnableGC bool
|
||||
Aggregate bool
|
||||
EnableAll bool
|
||||
|
||||
// Warn if a nolint directive was never matched to a linter issue
|
||||
WarnUnmatchedDirective bool
|
||||
|
||||
formatTemplate *template.Template
|
||||
}
|
||||
|
||||
type StringOrLinterConfig LinterConfig
|
||||
|
||||
func (c *StringOrLinterConfig) UnmarshalJSON(raw []byte) error {
|
||||
var linterConfig LinterConfig
|
||||
// first try to un-marshall directly into struct
|
||||
origErr := json.Unmarshal(raw, &linterConfig)
|
||||
if origErr == nil {
|
||||
*c = StringOrLinterConfig(linterConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// i.e. bytes didn't represent the struct, treat them as a string
|
||||
var linterSpec string
|
||||
if err := json.Unmarshal(raw, &linterSpec); err != nil {
|
||||
return origErr
|
||||
}
|
||||
linter, err := parseLinterConfigSpec("", linterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = StringOrLinterConfig(linter)
|
||||
return nil
|
||||
}
|
||||
|
||||
type jsonDuration time.Duration
|
||||
|
||||
func (td *jsonDuration) UnmarshalJSON(raw []byte) error {
|
||||
var durationAsString string
|
||||
if err := json.Unmarshal(raw, &durationAsString); err != nil {
|
||||
return err
|
||||
}
|
||||
duration, err := time.ParseDuration(durationAsString)
|
||||
*td = jsonDuration(duration)
|
||||
return err
|
||||
}
|
||||
|
||||
// Duration returns the value as a time.Duration
|
||||
func (td *jsonDuration) Duration() time.Duration {
|
||||
return time.Duration(*td)
|
||||
}
|
||||
|
||||
var sortKeys = []string{"none", "path", "line", "column", "severity", "message", "linter"}
|
||||
|
||||
// Configuration defaults.
|
||||
var config = &Config{
|
||||
Format: DefaultIssueFormat,
|
||||
|
||||
Linters: map[string]StringOrLinterConfig{},
|
||||
Severity: map[string]string{
|
||||
"gotype": "error",
|
||||
"gotypex": "error",
|
||||
"test": "error",
|
||||
"testify": "error",
|
||||
"vet": "error",
|
||||
},
|
||||
MessageOverride: map[string]string{
|
||||
"errcheck": "error return value not checked ({message})",
|
||||
"gocyclo": "cyclomatic complexity {cyclo} of function {function}() is high (> {mincyclo})",
|
||||
"gofmt": "file is not gofmted with -s",
|
||||
"goimports": "file is not goimported",
|
||||
"safesql": "potentially unsafe SQL statement",
|
||||
"structcheck": "unused struct field {message}",
|
||||
"unparam": "parameter {message}",
|
||||
"varcheck": "unused variable or constant {message}",
|
||||
},
|
||||
Enable: defaultEnabled(),
|
||||
VendoredLinters: true,
|
||||
Concurrency: runtime.NumCPU(),
|
||||
Cyclo: 10,
|
||||
LineLength: 80,
|
||||
MisspellLocale: "",
|
||||
MinConfidence: 0.8,
|
||||
MinOccurrences: 3,
|
||||
MinConstLength: 3,
|
||||
DuplThreshold: 50,
|
||||
Sort: []string{"none"},
|
||||
Deadline: jsonDuration(time.Second * 30),
|
||||
}
|
||||
|
||||
func loadConfigFile(filename string) error {
|
||||
r, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close() // nolint: errcheck
|
||||
err = json.NewDecoder(r).Decode(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, disable := range config.Disable {
|
||||
for i, enable := range config.Enable {
|
||||
if enable == disable {
|
||||
config.Enable = append(config.Enable[:i], config.Enable[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func findDefaultConfigFile() (fullPath string, found bool, err error) {
|
||||
prevPath := ""
|
||||
dirPath, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
for dirPath != prevPath {
|
||||
fullPath, found, err = findConfigFileInDir(dirPath)
|
||||
if err != nil || found {
|
||||
return fullPath, found, err
|
||||
}
|
||||
prevPath, dirPath = dirPath, filepath.Dir(dirPath)
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
func findConfigFileInDir(dirPath string) (fullPath string, found bool, err error) {
|
||||
fullPath = filepath.Join(dirPath, defaultConfigPath)
|
||||
if _, err := os.Stat(fullPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", false, nil
|
||||
}
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
return fullPath, true, nil
|
||||
}
|
226
tools/vendor/github.com/alecthomas/gometalinter/directives.go
generated
vendored
226
tools/vendor/github.com/alecthomas/gometalinter/directives.go
generated
vendored
@ -1,226 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ignoredRange struct {
|
||||
col int
|
||||
start, end int
|
||||
linters []string
|
||||
matched bool
|
||||
}
|
||||
|
||||
func (i *ignoredRange) matches(issue *Issue) bool {
|
||||
if issue.Line < i.start || issue.Line > i.end {
|
||||
return false
|
||||
}
|
||||
if len(i.linters) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, l := range i.linters {
|
||||
if l == issue.Linter {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *ignoredRange) near(col, start int) bool {
|
||||
return col == i.col && i.end == start-1
|
||||
}
|
||||
|
||||
func (i *ignoredRange) String() string {
|
||||
linters := strings.Join(i.linters, ",")
|
||||
if len(i.linters) == 0 {
|
||||
linters = "all"
|
||||
}
|
||||
return fmt.Sprintf("%s:%d-%d", linters, i.start, i.end)
|
||||
}
|
||||
|
||||
type ignoredRanges []*ignoredRange
|
||||
|
||||
func (ir ignoredRanges) Len() int { return len(ir) }
|
||||
func (ir ignoredRanges) Swap(i, j int) { ir[i], ir[j] = ir[j], ir[i] }
|
||||
func (ir ignoredRanges) Less(i, j int) bool { return ir[i].end < ir[j].end }
|
||||
|
||||
type directiveParser struct {
|
||||
lock sync.Mutex
|
||||
files map[string]ignoredRanges
|
||||
fset *token.FileSet
|
||||
}
|
||||
|
||||
func newDirectiveParser() *directiveParser {
|
||||
return &directiveParser{
|
||||
files: map[string]ignoredRanges{},
|
||||
fset: token.NewFileSet(),
|
||||
}
|
||||
}
|
||||
|
||||
// IsIgnored returns true if the given linter issue is ignored by a linter directive.
|
||||
func (d *directiveParser) IsIgnored(issue *Issue) bool {
|
||||
d.lock.Lock()
|
||||
path := issue.Path.Relative()
|
||||
ranges, ok := d.files[path]
|
||||
if !ok {
|
||||
ranges = d.parseFile(path)
|
||||
sort.Sort(ranges)
|
||||
d.files[path] = ranges
|
||||
}
|
||||
d.lock.Unlock()
|
||||
for _, r := range ranges {
|
||||
if r.matches(issue) {
|
||||
debug("nolint: matched %s to issue %s", r, issue)
|
||||
r.matched = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unmatched returns all the ranges which were never used to ignore an issue
|
||||
func (d *directiveParser) Unmatched() map[string]ignoredRanges {
|
||||
unmatched := map[string]ignoredRanges{}
|
||||
for path, ranges := range d.files {
|
||||
for _, ignore := range ranges {
|
||||
if !ignore.matched {
|
||||
unmatched[path] = append(unmatched[path], ignore)
|
||||
}
|
||||
}
|
||||
}
|
||||
return unmatched
|
||||
}
|
||||
|
||||
// LoadFiles from a list of directories
|
||||
func (d *directiveParser) LoadFiles(paths []string) error {
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
filenames, err := pathsToFileGlobs(paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, filename := range filenames {
|
||||
ranges := d.parseFile(filename)
|
||||
sort.Sort(ranges)
|
||||
d.files[filename] = ranges
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Takes a set of ignoredRanges, determines if they immediately precede a statement
|
||||
// construct, and expands the range to include that construct. Why? So you can
|
||||
// precede a function or struct with //nolint
|
||||
type rangeExpander struct {
|
||||
fset *token.FileSet
|
||||
ranges ignoredRanges
|
||||
}
|
||||
|
||||
func (a *rangeExpander) Visit(node ast.Node) ast.Visitor {
|
||||
if node == nil {
|
||||
return a
|
||||
}
|
||||
startPos := a.fset.Position(node.Pos())
|
||||
start := startPos.Line
|
||||
end := a.fset.Position(node.End()).Line
|
||||
found := sort.Search(len(a.ranges), func(i int) bool {
|
||||
return a.ranges[i].end+1 >= start
|
||||
})
|
||||
if found < len(a.ranges) && a.ranges[found].near(startPos.Column, start) {
|
||||
r := a.ranges[found]
|
||||
if r.start > start {
|
||||
r.start = start
|
||||
}
|
||||
if r.end < end {
|
||||
r.end = end
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (d *directiveParser) parseFile(path string) ignoredRanges {
|
||||
start := time.Now()
|
||||
debug("nolint: parsing %s for directives", path)
|
||||
file, err := parser.ParseFile(d.fset, path, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
debug("nolint: failed to parse %q: %s", path, err)
|
||||
return nil
|
||||
}
|
||||
ranges := extractCommentGroupRange(d.fset, file.Comments...)
|
||||
visitor := &rangeExpander{fset: d.fset, ranges: ranges}
|
||||
ast.Walk(visitor, file)
|
||||
debug("nolint: parsing %s took %s", path, time.Since(start))
|
||||
return visitor.ranges
|
||||
}
|
||||
|
||||
func extractCommentGroupRange(fset *token.FileSet, comments ...*ast.CommentGroup) (ranges ignoredRanges) {
|
||||
for _, g := range comments {
|
||||
for _, c := range g.List {
|
||||
text := strings.TrimLeft(c.Text, "/ ")
|
||||
var linters []string
|
||||
if strings.HasPrefix(text, "nolint") {
|
||||
if strings.HasPrefix(text, "nolint:") {
|
||||
for _, linter := range strings.Split(text[7:], ",") {
|
||||
linters = append(linters, strings.TrimSpace(linter))
|
||||
}
|
||||
}
|
||||
pos := fset.Position(g.Pos())
|
||||
rng := &ignoredRange{
|
||||
col: pos.Column,
|
||||
start: pos.Line,
|
||||
end: fset.Position(g.End()).Line,
|
||||
linters: linters,
|
||||
}
|
||||
ranges = append(ranges, rng)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func filterIssuesViaDirectives(directives *directiveParser, issues chan *Issue) chan *Issue {
|
||||
out := make(chan *Issue, 1000000)
|
||||
go func() {
|
||||
for issue := range issues {
|
||||
if !directives.IsIgnored(issue) {
|
||||
out <- issue
|
||||
}
|
||||
}
|
||||
|
||||
if config.WarnUnmatchedDirective {
|
||||
for _, issue := range warnOnUnusedDirective(directives) {
|
||||
out <- issue
|
||||
}
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func warnOnUnusedDirective(directives *directiveParser) []*Issue {
|
||||
out := []*Issue{}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
warning("failed to get working directory %s", err)
|
||||
}
|
||||
|
||||
for path, ranges := range directives.Unmatched() {
|
||||
for _, ignore := range ranges {
|
||||
issue, _ := NewIssue("nolint", config.formatTemplate)
|
||||
issue.Path = newIssuePath(cwd, path)
|
||||
issue.Line = ignore.start
|
||||
issue.Col = ignore.col
|
||||
issue.Message = "nolint directive did not match any issue"
|
||||
out = append(out, issue)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
290
tools/vendor/github.com/alecthomas/gometalinter/execute.go
generated
vendored
290
tools/vendor/github.com/alecthomas/gometalinter/execute.go
generated
vendored
@ -1,290 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/shlex"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type Vars map[string]string
|
||||
|
||||
func (v Vars) Copy() Vars {
|
||||
out := Vars{}
|
||||
for k, v := range v {
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (v Vars) Replace(s string) string {
|
||||
for k, v := range v {
|
||||
prefix := regexp.MustCompile(fmt.Sprintf("{%s=([^}]*)}", k))
|
||||
if v != "" {
|
||||
s = prefix.ReplaceAllString(s, "$1")
|
||||
} else {
|
||||
s = prefix.ReplaceAllString(s, "")
|
||||
}
|
||||
s = strings.Replace(s, fmt.Sprintf("{%s}", k), v, -1)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type linterState struct {
|
||||
*Linter
|
||||
issues chan *Issue
|
||||
vars Vars
|
||||
exclude *regexp.Regexp
|
||||
include *regexp.Regexp
|
||||
deadline <-chan time.Time
|
||||
}
|
||||
|
||||
func (l *linterState) Partitions(paths []string) ([][]string, error) {
|
||||
cmdArgs, err := parseCommand(l.command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts, err := l.Linter.PartitionStrategy(cmdArgs, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
func (l *linterState) command() string {
|
||||
return l.vars.Replace(l.Command)
|
||||
}
|
||||
|
||||
func runLinters(linters map[string]*Linter, paths []string, concurrency int, exclude, include *regexp.Regexp) (chan *Issue, chan error) {
|
||||
errch := make(chan error, len(linters))
|
||||
concurrencych := make(chan bool, concurrency)
|
||||
incomingIssues := make(chan *Issue, 1000000)
|
||||
|
||||
directiveParser := newDirectiveParser()
|
||||
if config.WarnUnmatchedDirective {
|
||||
directiveParser.LoadFiles(paths)
|
||||
}
|
||||
|
||||
processedIssues := maybeSortIssues(filterIssuesViaDirectives(
|
||||
directiveParser, maybeAggregateIssues(incomingIssues)))
|
||||
|
||||
vars := Vars{
|
||||
"duplthreshold": fmt.Sprintf("%d", config.DuplThreshold),
|
||||
"mincyclo": fmt.Sprintf("%d", config.Cyclo),
|
||||
"maxlinelength": fmt.Sprintf("%d", config.LineLength),
|
||||
"misspelllocale": fmt.Sprintf("%s", config.MisspellLocale),
|
||||
"min_confidence": fmt.Sprintf("%f", config.MinConfidence),
|
||||
"min_occurrences": fmt.Sprintf("%d", config.MinOccurrences),
|
||||
"min_const_length": fmt.Sprintf("%d", config.MinConstLength),
|
||||
"tests": "",
|
||||
"not_tests": "true",
|
||||
}
|
||||
if config.Test {
|
||||
vars["tests"] = "true"
|
||||
vars["not_tests"] = ""
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
id := 1
|
||||
for _, linter := range linters {
|
||||
deadline := time.After(config.Deadline.Duration())
|
||||
state := &linterState{
|
||||
Linter: linter,
|
||||
issues: incomingIssues,
|
||||
vars: vars,
|
||||
exclude: exclude,
|
||||
include: include,
|
||||
deadline: deadline,
|
||||
}
|
||||
|
||||
partitions, err := state.Partitions(paths)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
continue
|
||||
}
|
||||
for _, args := range partitions {
|
||||
wg.Add(1)
|
||||
concurrencych <- true
|
||||
// Call the goroutine with a copy of the args array so that the
|
||||
// contents of the array are not modified by the next iteration of
|
||||
// the above for loop
|
||||
go func(id int, args []string) {
|
||||
err := executeLinter(id, state, args)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
}
|
||||
<-concurrencych
|
||||
wg.Done()
|
||||
}(id, args)
|
||||
id++
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(incomingIssues)
|
||||
close(errch)
|
||||
}()
|
||||
return processedIssues, errch
|
||||
}
|
||||
|
||||
func executeLinter(id int, state *linterState, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("missing linter command")
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
dbg := namespacedDebug(fmt.Sprintf("[%s.%d]: ", state.Name, id))
|
||||
dbg("executing %s", strings.Join(args, " "))
|
||||
buf := bytes.NewBuffer(nil)
|
||||
command := args[0]
|
||||
cmd := exec.Command(command, args[1:]...) // nolint: gas
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute linter %s: %s", command, err)
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
err = cmd.Wait()
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// Wait for process to complete or deadline to expire.
|
||||
select {
|
||||
case <-done:
|
||||
|
||||
case <-state.deadline:
|
||||
err = fmt.Errorf("deadline exceeded by linter %s (try increasing --deadline)",
|
||||
state.Name)
|
||||
kerr := cmd.Process.Kill()
|
||||
if kerr != nil {
|
||||
warning("failed to kill %s: %s", state.Name, kerr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
dbg("warning: %s returned %s: %s", command, err, buf.String())
|
||||
}
|
||||
|
||||
processOutput(dbg, state, buf.Bytes())
|
||||
elapsed := time.Since(start)
|
||||
dbg("%s linter took %s", state.Name, elapsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCommand(command string) ([]string, error) {
|
||||
args, err := shlex.Split(command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return nil, fmt.Errorf("invalid command %q", command)
|
||||
}
|
||||
exe, err := exec.LookPath(args[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]string{exe}, args[1:]...), nil
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func processOutput(dbg debugFunction, state *linterState, out []byte) {
|
||||
re := state.regex
|
||||
all := re.FindAllSubmatchIndex(out, -1)
|
||||
dbg("%s hits %d: %s", state.Name, len(all), state.Pattern)
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
warning("failed to get working directory %s", err)
|
||||
}
|
||||
|
||||
// Create a local copy of vars so they can be modified by the linter output
|
||||
vars := state.vars.Copy()
|
||||
|
||||
for _, indices := range all {
|
||||
group := [][]byte{}
|
||||
for i := 0; i < len(indices); i += 2 {
|
||||
var fragment []byte
|
||||
if indices[i] != -1 {
|
||||
fragment = out[indices[i]:indices[i+1]]
|
||||
}
|
||||
group = append(group, fragment)
|
||||
}
|
||||
|
||||
issue, err := NewIssue(state.Linter.Name, config.formatTemplate)
|
||||
kingpin.FatalIfError(err, "Invalid output format")
|
||||
|
||||
for i, name := range re.SubexpNames() {
|
||||
if group[i] == nil {
|
||||
continue
|
||||
}
|
||||
part := string(group[i])
|
||||
if name != "" {
|
||||
vars[name] = part
|
||||
}
|
||||
switch name {
|
||||
case "path":
|
||||
issue.Path, err = newIssuePathFromAbsPath(cwd, part)
|
||||
if err != nil {
|
||||
warning("failed to make %s a relative path: %s", part, err)
|
||||
}
|
||||
case "line":
|
||||
n, err := strconv.ParseInt(part, 10, 32)
|
||||
kingpin.FatalIfError(err, "line matched invalid integer")
|
||||
issue.Line = int(n)
|
||||
|
||||
case "col":
|
||||
n, err := strconv.ParseInt(part, 10, 32)
|
||||
kingpin.FatalIfError(err, "col matched invalid integer")
|
||||
issue.Col = int(n)
|
||||
|
||||
case "message":
|
||||
issue.Message = part
|
||||
|
||||
case "":
|
||||
}
|
||||
}
|
||||
// TODO: set messageOveride and severity on the Linter instead of reading
|
||||
// them directly from the static config
|
||||
if m, ok := config.MessageOverride[state.Name]; ok {
|
||||
issue.Message = vars.Replace(m)
|
||||
}
|
||||
if sev, ok := config.Severity[state.Name]; ok {
|
||||
issue.Severity = Severity(sev)
|
||||
}
|
||||
if state.exclude != nil && state.exclude.MatchString(issue.String()) {
|
||||
continue
|
||||
}
|
||||
if state.include != nil && !state.include.MatchString(issue.String()) {
|
||||
continue
|
||||
}
|
||||
state.issues <- issue
|
||||
}
|
||||
}
|
||||
|
||||
func maybeSortIssues(issues chan *Issue) chan *Issue {
|
||||
if reflect.DeepEqual([]string{"none"}, config.Sort) {
|
||||
return issues
|
||||
}
|
||||
return SortIssueChan(issues, config.Sort)
|
||||
}
|
||||
|
||||
func maybeAggregateIssues(issues chan *Issue) chan *Issue {
|
||||
if !config.Aggregate {
|
||||
return issues
|
||||
}
|
||||
return AggregateIssueChan(issues)
|
||||
}
|
166
tools/vendor/github.com/alecthomas/gometalinter/issue.go
generated
vendored
166
tools/vendor/github.com/alecthomas/gometalinter/issue.go
generated
vendored
@ -1,166 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// DefaultIssueFormat used to print an issue
|
||||
const DefaultIssueFormat = "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
|
||||
|
||||
// Severity of linter message
|
||||
type Severity string
|
||||
|
||||
// Linter message severity levels.
|
||||
const (
|
||||
Error Severity = "error"
|
||||
Warning Severity = "warning"
|
||||
)
|
||||
|
||||
type IssuePath struct {
|
||||
root string
|
||||
path string
|
||||
}
|
||||
|
||||
func (i IssuePath) String() string {
|
||||
return i.Relative()
|
||||
}
|
||||
|
||||
func (i IssuePath) Relative() string {
|
||||
return i.path
|
||||
}
|
||||
|
||||
func (i IssuePath) Abs() string {
|
||||
return filepath.Join(i.root, i.path)
|
||||
}
|
||||
|
||||
func (i IssuePath) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.String())
|
||||
}
|
||||
|
||||
func newIssuePath(root, path string) IssuePath {
|
||||
return IssuePath{root: root, path: path}
|
||||
}
|
||||
|
||||
// newIssuePathFromAbsPath returns a new issuePath from a path that may be
|
||||
// an absolute path. root must be an absolute path.
|
||||
func newIssuePathFromAbsPath(root, path string) (IssuePath, error) {
|
||||
resolvedRoot, err := filepath.EvalSymlinks(root)
|
||||
if err != nil {
|
||||
return newIssuePath(root, path), err
|
||||
}
|
||||
|
||||
resolvedPath, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return newIssuePath(root, path), err
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(path) {
|
||||
return newIssuePath(resolvedRoot, resolvedPath), nil
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(resolvedRoot, resolvedPath)
|
||||
return newIssuePath(resolvedRoot, relPath), err
|
||||
}
|
||||
|
||||
type Issue struct {
|
||||
Linter string `json:"linter"`
|
||||
Severity Severity `json:"severity"`
|
||||
Path IssuePath `json:"path"`
|
||||
Line int `json:"line"`
|
||||
Col int `json:"col"`
|
||||
Message string `json:"message"`
|
||||
formatTmpl *template.Template
|
||||
}
|
||||
|
||||
// NewIssue returns a new issue. Returns an error if formatTmpl is not a valid
|
||||
// template for an Issue.
|
||||
func NewIssue(linter string, formatTmpl *template.Template) (*Issue, error) {
|
||||
issue := &Issue{
|
||||
Line: 1,
|
||||
Severity: Warning,
|
||||
Linter: linter,
|
||||
formatTmpl: formatTmpl,
|
||||
}
|
||||
err := formatTmpl.Execute(ioutil.Discard, issue)
|
||||
return issue, err
|
||||
}
|
||||
|
||||
func (i *Issue) String() string {
|
||||
if i.formatTmpl == nil {
|
||||
col := ""
|
||||
if i.Col != 0 {
|
||||
col = fmt.Sprintf("%d", i.Col)
|
||||
}
|
||||
return fmt.Sprintf("%s:%d:%s:%s: %s (%s)",
|
||||
strings.TrimSpace(i.Path.Relative()),
|
||||
i.Line, col, i.Severity,
|
||||
strings.TrimSpace(i.Message),
|
||||
i.Linter)
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
_ = i.formatTmpl.Execute(buf, i)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type sortedIssues struct {
|
||||
issues []*Issue
|
||||
order []string
|
||||
}
|
||||
|
||||
func (s *sortedIssues) Len() int { return len(s.issues) }
|
||||
func (s *sortedIssues) Swap(i, j int) { s.issues[i], s.issues[j] = s.issues[j], s.issues[i] }
|
||||
|
||||
func (s *sortedIssues) Less(i, j int) bool {
|
||||
l, r := s.issues[i], s.issues[j]
|
||||
return CompareIssue(*l, *r, s.order)
|
||||
}
|
||||
|
||||
// CompareIssue two Issues and return true if left should sort before right
|
||||
// nolint: gocyclo
|
||||
func CompareIssue(l, r Issue, order []string) bool {
|
||||
for _, key := range order {
|
||||
switch {
|
||||
case key == "path" && l.Path != r.Path:
|
||||
return l.Path.String() < r.Path.String()
|
||||
case key == "line" && l.Line != r.Line:
|
||||
return l.Line < r.Line
|
||||
case key == "column" && l.Col != r.Col:
|
||||
return l.Col < r.Col
|
||||
case key == "severity" && l.Severity != r.Severity:
|
||||
return l.Severity < r.Severity
|
||||
case key == "message" && l.Message != r.Message:
|
||||
return l.Message < r.Message
|
||||
case key == "linter" && l.Linter != r.Linter:
|
||||
return l.Linter < r.Linter
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SortIssueChan reads issues from one channel, sorts them, and returns them to another
|
||||
// channel
|
||||
func SortIssueChan(issues chan *Issue, order []string) chan *Issue {
|
||||
out := make(chan *Issue, 1000000)
|
||||
sorted := &sortedIssues{
|
||||
issues: []*Issue{},
|
||||
order: order,
|
||||
}
|
||||
go func() {
|
||||
for issue := range issues {
|
||||
sorted.issues = append(sorted.issues, issue)
|
||||
}
|
||||
sort.Sort(sorted)
|
||||
for _, issue := range sorted.issues {
|
||||
out <- issue
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
413
tools/vendor/github.com/alecthomas/gometalinter/linters.go
generated
vendored
413
tools/vendor/github.com/alecthomas/gometalinter/linters.go
generated
vendored
@ -1,413 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type LinterConfig struct {
|
||||
Command string
|
||||
Pattern string
|
||||
InstallFrom string
|
||||
PartitionStrategy partitionStrategy
|
||||
IsFast bool
|
||||
defaultEnabled bool
|
||||
}
|
||||
|
||||
type Linter struct {
|
||||
LinterConfig
|
||||
Name string
|
||||
regex *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewLinter returns a new linter from a config
|
||||
func NewLinter(name string, config LinterConfig) (*Linter, error) {
|
||||
if p, ok := predefinedPatterns[config.Pattern]; ok {
|
||||
config.Pattern = p
|
||||
}
|
||||
regex, err := regexp.Compile("(?m:" + config.Pattern + ")")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.PartitionStrategy == nil {
|
||||
config.PartitionStrategy = partitionPathsAsDirectories
|
||||
}
|
||||
return &Linter{
|
||||
LinterConfig: config,
|
||||
Name: name,
|
||||
regex: regex,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *Linter) String() string {
|
||||
return l.Name
|
||||
}
|
||||
|
||||
var predefinedPatterns = map[string]string{
|
||||
"PATH:LINE:COL:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
|
||||
"PATH:LINE:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*)$`,
|
||||
}
|
||||
|
||||
func getLinterByName(name string, overrideConf LinterConfig) *Linter {
|
||||
conf := defaultLinters[name]
|
||||
if val := overrideConf.Command; val != "" {
|
||||
conf.Command = val
|
||||
}
|
||||
if val := overrideConf.Pattern; val != "" {
|
||||
conf.Pattern = val
|
||||
}
|
||||
if val := overrideConf.InstallFrom; val != "" {
|
||||
conf.InstallFrom = val
|
||||
}
|
||||
if overrideConf.IsFast {
|
||||
conf.IsFast = true
|
||||
}
|
||||
if val := overrideConf.PartitionStrategy; val != nil {
|
||||
conf.PartitionStrategy = val
|
||||
}
|
||||
|
||||
linter, _ := NewLinter(name, conf)
|
||||
return linter
|
||||
}
|
||||
|
||||
func parseLinterConfigSpec(name string, spec string) (LinterConfig, error) {
|
||||
parts := strings.SplitN(spec, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
return LinterConfig{}, fmt.Errorf("linter spec needs at least two components")
|
||||
}
|
||||
|
||||
config := defaultLinters[name]
|
||||
config.Command, config.Pattern = parts[0], parts[1]
|
||||
if predefined, ok := predefinedPatterns[config.Pattern]; ok {
|
||||
config.Pattern = predefined
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func makeInstallCommand(linters ...string) []string {
|
||||
cmd := []string{"get"}
|
||||
if config.VendoredLinters {
|
||||
cmd = []string{"install"}
|
||||
} else {
|
||||
if config.Update {
|
||||
cmd = append(cmd, "-u")
|
||||
}
|
||||
if config.Force {
|
||||
cmd = append(cmd, "-f")
|
||||
}
|
||||
if config.DownloadOnly {
|
||||
cmd = append(cmd, "-d")
|
||||
}
|
||||
}
|
||||
if config.Debug {
|
||||
cmd = append(cmd, "-v")
|
||||
}
|
||||
cmd = append(cmd, linters...)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func installLintersWithOneCommand(targets []string) error {
|
||||
cmd := makeInstallCommand(targets...)
|
||||
debug("go %s", strings.Join(cmd, " "))
|
||||
c := exec.Command("go", cmd...) // nolint: gas
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
func installLintersIndividually(targets []string) {
|
||||
failed := []string{}
|
||||
for _, target := range targets {
|
||||
cmd := makeInstallCommand(target)
|
||||
debug("go %s", strings.Join(cmd, " "))
|
||||
c := exec.Command("go", cmd...) // nolint: gas
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
if err := c.Run(); err != nil {
|
||||
warning("failed to install %s: %s", target, err)
|
||||
failed = append(failed, target)
|
||||
}
|
||||
}
|
||||
if len(failed) > 0 {
|
||||
kingpin.Fatalf("failed to install the following linters: %s", strings.Join(failed, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
func installLinters() {
|
||||
names := make([]string, 0, len(defaultLinters))
|
||||
targets := make([]string, 0, len(defaultLinters))
|
||||
for name, config := range defaultLinters {
|
||||
if config.InstallFrom == "" {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
targets = append(targets, config.InstallFrom)
|
||||
}
|
||||
sort.Strings(names)
|
||||
namesStr := strings.Join(names, "\n ")
|
||||
if config.DownloadOnly {
|
||||
fmt.Printf("Downloading:\n %s\n", namesStr)
|
||||
} else {
|
||||
fmt.Printf("Installing:\n %s\n", namesStr)
|
||||
}
|
||||
err := installLintersWithOneCommand(targets)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
warning("failed to install one or more linters: %s (installing individually)", err)
|
||||
installLintersIndividually(targets)
|
||||
}
|
||||
|
||||
func getDefaultLinters() []*Linter {
|
||||
out := []*Linter{}
|
||||
for name, config := range defaultLinters {
|
||||
linter, err := NewLinter(name, config)
|
||||
kingpin.FatalIfError(err, "invalid linter %q", name)
|
||||
out = append(out, linter)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func defaultEnabled() []string {
|
||||
enabled := []string{}
|
||||
for name, config := range defaultLinters {
|
||||
if config.defaultEnabled {
|
||||
enabled = append(enabled, name)
|
||||
}
|
||||
}
|
||||
return enabled
|
||||
}
|
||||
|
||||
func validateLinters(linters map[string]*Linter, config *Config) error {
|
||||
var unknownLinters []string
|
||||
for name := range linters {
|
||||
if _, isDefault := defaultLinters[name]; !isDefault {
|
||||
if _, isCustom := config.Linters[name]; !isCustom {
|
||||
unknownLinters = append(unknownLinters, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(unknownLinters) > 0 {
|
||||
return fmt.Errorf("unknown linters: %s", strings.Join(unknownLinters, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const vetPattern = `^(?:vet:.*?\.go:\s+(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*))|(?:(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*))$`
|
||||
|
||||
var defaultLinters = map[string]LinterConfig{
|
||||
"maligned": {
|
||||
Command: "maligned",
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
|
||||
InstallFrom: "github.com/mdempsky/maligned",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"deadcode": {
|
||||
Command: "deadcode",
|
||||
Pattern: `^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/tsenart/deadcode",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"dupl": {
|
||||
Command: `dupl -plumbing -threshold {duplthreshold}`,
|
||||
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/mibk/dupl",
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"errcheck": {
|
||||
Command: `errcheck -abspath {not_tests=-ignoretests}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/kisielk/errcheck",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"gas": {
|
||||
Command: `gas -fmt=csv`,
|
||||
Pattern: `^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
|
||||
InstallFrom: "github.com/GoASTScanner/gas",
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"goconst": {
|
||||
Command: `goconst -min-occurrences {min_occurrences} -min-length {min_const_length}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/jgautheron/goconst/cmd/goconst",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gocyclo": {
|
||||
Command: `gocyclo -over {mincyclo}`,
|
||||
Pattern: `^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>.*?\.go):(?P<line>\d+):(\d+)$`,
|
||||
InstallFrom: "github.com/alecthomas/gocyclo",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gofmt": {
|
||||
Command: `gofmt -l -s`,
|
||||
Pattern: `^(?P<path>.*?\.go)$`,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"goimports": {
|
||||
Command: `goimports -l`,
|
||||
Pattern: `^(?P<path>.*?\.go)$`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/goimports",
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"golint": {
|
||||
Command: `golint -min_confidence {min_confidence}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/golang/lint/golint",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gosimple": {
|
||||
Command: `gosimple`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/gosimple",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"gotype": {
|
||||
Command: `gotype -e {tests=-t}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/gotype",
|
||||
PartitionStrategy: partitionPathsByDirectory,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gotypex": {
|
||||
Command: `gotype -e -x`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/gotype",
|
||||
PartitionStrategy: partitionPathsByDirectory,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"ineffassign": {
|
||||
Command: `ineffassign -n`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/gordonklaus/ineffassign",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"interfacer": {
|
||||
Command: `interfacer`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "mvdan.cc/interfacer",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"lll": {
|
||||
Command: `lll -g -l {maxlinelength}`,
|
||||
Pattern: `PATH:LINE:MESSAGE`,
|
||||
InstallFrom: "github.com/walle/lll/cmd/lll",
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"megacheck": {
|
||||
Command: `megacheck`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/megacheck",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"misspell": {
|
||||
Command: `misspell -j 1 --locale "{misspelllocale}"`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/client9/misspell/cmd/misspell",
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"nakedret": {
|
||||
Command: `nakedret`,
|
||||
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/alexkohler/nakedret",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
},
|
||||
"safesql": {
|
||||
Command: `safesql`,
|
||||
Pattern: `^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
|
||||
InstallFrom: "github.com/stripe/safesql",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"staticcheck": {
|
||||
Command: `staticcheck`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/staticcheck",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"structcheck": {
|
||||
Command: `structcheck {tests=-t}`,
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
|
||||
InstallFrom: "github.com/opennota/check/cmd/structcheck",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"test": {
|
||||
Command: `go test`,
|
||||
Pattern: `^--- FAIL: .*$\s+(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.*)$`,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"testify": {
|
||||
Command: `go test`,
|
||||
Pattern: `Location:\s+(?P<path>.*?\.go):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"unconvert": {
|
||||
Command: `unconvert`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/mdempsky/unconvert",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"unparam": {
|
||||
Command: `unparam {not_tests=-tests=false}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "mvdan.cc/unparam",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"unused": {
|
||||
Command: `unused`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/unused",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"varcheck": {
|
||||
Command: `varcheck`,
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/opennota/check/cmd/varcheck",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"vet": {
|
||||
Command: `govet --no-recurse`,
|
||||
Pattern: vetPattern,
|
||||
InstallFrom: "github.com/dnephin/govet",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"vetshadow": {
|
||||
Command: `govet --no-recurse --shadow`,
|
||||
Pattern: vetPattern,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
}
|
521
tools/vendor/github.com/alecthomas/gometalinter/main.go
generated
vendored
521
tools/vendor/github.com/alecthomas/gometalinter/main.go
generated
vendored
@ -1,521 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
var (
|
||||
// Locations to look for vendored linters.
|
||||
vendoredSearchPaths = [][]string{
|
||||
{"github.com", "alecthomas", "gometalinter", "_linters"},
|
||||
{"gopkg.in", "alecthomas", "gometalinter.v2", "_linters"},
|
||||
}
|
||||
defaultConfigPath = ".gometalinter.json"
|
||||
|
||||
// Populated by goreleaser.
|
||||
version = "master"
|
||||
commit = "?"
|
||||
date = ""
|
||||
)
|
||||
|
||||
func setupFlags(app *kingpin.Application) {
|
||||
app.Flag("config", "Load JSON configuration from file.").Envar("GOMETALINTER_CONFIG").Action(loadConfig).String()
|
||||
app.Flag("no-config", "Disable automatic loading of config file.").Bool()
|
||||
app.Flag("disable", "Disable previously enabled linters.").PlaceHolder("LINTER").Short('D').Action(disableAction).Strings()
|
||||
app.Flag("enable", "Enable previously disabled linters.").PlaceHolder("LINTER").Short('E').Action(enableAction).Strings()
|
||||
app.Flag("linter", "Define a linter.").PlaceHolder("NAME:COMMAND:PATTERN").Action(cliLinterOverrides).StringMap()
|
||||
app.Flag("message-overrides", "Override message from linter. {message} will be expanded to the original message.").PlaceHolder("LINTER:MESSAGE").StringMapVar(&config.MessageOverride)
|
||||
app.Flag("severity", "Map of linter severities.").PlaceHolder("LINTER:SEVERITY").StringMapVar(&config.Severity)
|
||||
app.Flag("disable-all", "Disable all linters.").Action(disableAllAction).Bool()
|
||||
app.Flag("enable-all", "Enable all linters.").Action(enableAllAction).Bool()
|
||||
app.Flag("format", "Output format.").PlaceHolder(config.Format).StringVar(&config.Format)
|
||||
app.Flag("vendored-linters", "Use vendored linters (recommended) (DEPRECATED - use binary packages).").BoolVar(&config.VendoredLinters)
|
||||
app.Flag("fast", "Only run fast linters.").BoolVar(&config.Fast)
|
||||
app.Flag("install", "Attempt to install all known linters (DEPRECATED - use binary packages).").Short('i').BoolVar(&config.Install)
|
||||
app.Flag("update", "Pass -u to go tool when installing (DEPRECATED - use binary packages).").Short('u').BoolVar(&config.Update)
|
||||
app.Flag("force", "Pass -f to go tool when installing (DEPRECATED - use binary packages).").Short('f').BoolVar(&config.Force)
|
||||
app.Flag("download-only", "Pass -d to go tool when installing (DEPRECATED - use binary packages).").BoolVar(&config.DownloadOnly)
|
||||
app.Flag("debug", "Display messages for failed linters, etc.").Short('d').BoolVar(&config.Debug)
|
||||
app.Flag("concurrency", "Number of concurrent linters to run.").PlaceHolder(fmt.Sprintf("%d", runtime.NumCPU())).Short('j').IntVar(&config.Concurrency)
|
||||
app.Flag("exclude", "Exclude messages matching these regular expressions.").Short('e').PlaceHolder("REGEXP").StringsVar(&config.Exclude)
|
||||
app.Flag("include", "Include messages matching these regular expressions.").Short('I').PlaceHolder("REGEXP").StringsVar(&config.Include)
|
||||
app.Flag("skip", "Skip directories with this name when expanding '...'.").Short('s').PlaceHolder("DIR...").StringsVar(&config.Skip)
|
||||
app.Flag("vendor", "Enable vendoring support (skips 'vendor' directories and sets GO15VENDOREXPERIMENT=1).").BoolVar(&config.Vendor)
|
||||
app.Flag("cyclo-over", "Report functions with cyclomatic complexity over N (using gocyclo).").PlaceHolder("10").IntVar(&config.Cyclo)
|
||||
app.Flag("line-length", "Report lines longer than N (using lll).").PlaceHolder("80").IntVar(&config.LineLength)
|
||||
app.Flag("misspell-locale", "Specify locale to use (using misspell).").PlaceHolder("").StringVar(&config.MisspellLocale)
|
||||
app.Flag("min-confidence", "Minimum confidence interval to pass to golint.").PlaceHolder(".80").FloatVar(&config.MinConfidence)
|
||||
app.Flag("min-occurrences", "Minimum occurrences to pass to goconst.").PlaceHolder("3").IntVar(&config.MinOccurrences)
|
||||
app.Flag("min-const-length", "Minimum constant length.").PlaceHolder("3").IntVar(&config.MinConstLength)
|
||||
app.Flag("dupl-threshold", "Minimum token sequence as a clone for dupl.").PlaceHolder("50").IntVar(&config.DuplThreshold)
|
||||
app.Flag("sort", fmt.Sprintf("Sort output by any of %s.", strings.Join(sortKeys, ", "))).PlaceHolder("none").EnumsVar(&config.Sort, sortKeys...)
|
||||
app.Flag("tests", "Include test files for linters that support this option.").Short('t').BoolVar(&config.Test)
|
||||
app.Flag("deadline", "Cancel linters if they have not completed within this duration.").PlaceHolder("30s").DurationVar((*time.Duration)(&config.Deadline))
|
||||
app.Flag("errors", "Only show errors.").BoolVar(&config.Errors)
|
||||
app.Flag("json", "Generate structured JSON rather than standard line-based output.").BoolVar(&config.JSON)
|
||||
app.Flag("checkstyle", "Generate checkstyle XML rather than standard line-based output.").BoolVar(&config.Checkstyle)
|
||||
app.Flag("enable-gc", "Enable GC for linters (useful on large repositories).").BoolVar(&config.EnableGC)
|
||||
app.Flag("aggregate", "Aggregate issues reported by several linters.").BoolVar(&config.Aggregate)
|
||||
app.Flag("warn-unmatched-nolint", "Warn if a nolint directive is not matched with an issue.").BoolVar(&config.WarnUnmatchedDirective)
|
||||
app.GetFlag("help").Short('h')
|
||||
}
|
||||
|
||||
func cliLinterOverrides(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
// expected input structure - <name>:<command-spec>
|
||||
parts := strings.SplitN(*element.Value, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
|
||||
}
|
||||
name := parts[0]
|
||||
spec := parts[1]
|
||||
conf, err := parseLinterConfigSpec(name, spec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
|
||||
}
|
||||
config.Linters[name] = StringOrLinterConfig(conf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadDefaultConfig(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
if element != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, elem := range ctx.Elements {
|
||||
if f := elem.OneOf.Flag; f == app.GetFlag("config") || f == app.GetFlag("no-config") {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
configFile, found, err := findDefaultConfigFile()
|
||||
if err != nil || !found {
|
||||
return err
|
||||
}
|
||||
|
||||
return loadConfigFile(configFile)
|
||||
}
|
||||
|
||||
func loadConfig(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
return loadConfigFile(*element.Value)
|
||||
}
|
||||
|
||||
func disableAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
out := []string{}
|
||||
for _, linter := range config.Enable {
|
||||
if linter != *element.Value {
|
||||
out = append(out, linter)
|
||||
}
|
||||
}
|
||||
config.Enable = out
|
||||
return nil
|
||||
}
|
||||
|
||||
func enableAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
config.Enable = append(config.Enable, *element.Value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func disableAllAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
config.Enable = []string{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func enableAllAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
for linter := range defaultLinters {
|
||||
config.Enable = append(config.Enable, linter)
|
||||
}
|
||||
config.EnableAll = true
|
||||
return nil
|
||||
}
|
||||
|
||||
type debugFunction func(format string, args ...interface{})
|
||||
|
||||
func debug(format string, args ...interface{}) {
|
||||
if config.Debug {
|
||||
t := time.Now().UTC()
|
||||
fmt.Fprintf(os.Stderr, "DEBUG: [%s] ", t.Format(time.StampMilli))
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
func namespacedDebug(prefix string) debugFunction {
|
||||
return func(format string, args ...interface{}) {
|
||||
debug(prefix+format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func warning(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: "+format+"\n", args...)
|
||||
}
|
||||
|
||||
func formatLinters() string {
|
||||
w := bytes.NewBuffer(nil)
|
||||
for _, linter := range getDefaultLinters() {
|
||||
install := "(" + linter.InstallFrom + ")"
|
||||
if install == "()" {
|
||||
install = ""
|
||||
}
|
||||
fmt.Fprintf(w, " %s: %s\n\tcommand: %s\n\tregex: %s\n\tfast: %t\n\tdefault enabled: %t\n\n",
|
||||
linter.Name, install, linter.Command, linter.Pattern, linter.IsFast, linter.defaultEnabled)
|
||||
}
|
||||
return w.String()
|
||||
}
|
||||
|
||||
func formatSeverity() string {
|
||||
w := bytes.NewBuffer(nil)
|
||||
for name, severity := range config.Severity {
|
||||
fmt.Fprintf(w, " %s -> %s\n", name, severity)
|
||||
}
|
||||
return w.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
kingpin.Version(fmt.Sprintf("gometalinter version %s built from %s on %s", version, commit, date))
|
||||
pathsArg := kingpin.Arg("path", "Directories to lint. Defaults to \".\". <path>/... will recurse.").Strings()
|
||||
app := kingpin.CommandLine
|
||||
app.Action(loadDefaultConfig)
|
||||
setupFlags(app)
|
||||
app.Help = fmt.Sprintf(`Aggregate and normalise the output of a whole bunch of Go linters.
|
||||
|
||||
PlaceHolder linters:
|
||||
|
||||
%s
|
||||
|
||||
Severity override map (default is "warning"):
|
||||
|
||||
%s
|
||||
`, formatLinters(), formatSeverity())
|
||||
kingpin.Parse()
|
||||
|
||||
if config.Install {
|
||||
if config.VendoredLinters {
|
||||
configureEnvironmentForInstall()
|
||||
}
|
||||
installLinters()
|
||||
return
|
||||
}
|
||||
|
||||
configureEnvironment()
|
||||
include, exclude := processConfig(config)
|
||||
|
||||
start := time.Now()
|
||||
paths := resolvePaths(*pathsArg, config.Skip)
|
||||
|
||||
linters := lintersFromConfig(config)
|
||||
err := validateLinters(linters, config)
|
||||
kingpin.FatalIfError(err, "")
|
||||
|
||||
issues, errch := runLinters(linters, paths, config.Concurrency, exclude, include)
|
||||
status := 0
|
||||
if config.JSON {
|
||||
status |= outputToJSON(issues)
|
||||
} else if config.Checkstyle {
|
||||
status |= outputToCheckstyle(issues)
|
||||
} else {
|
||||
status |= outputToConsole(issues)
|
||||
}
|
||||
for err := range errch {
|
||||
warning("%s", err)
|
||||
status |= 2
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
debug("total elapsed time %s", elapsed)
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func processConfig(config *Config) (include *regexp.Regexp, exclude *regexp.Regexp) {
|
||||
tmpl, err := template.New("output").Parse(config.Format)
|
||||
kingpin.FatalIfError(err, "invalid format %q", config.Format)
|
||||
config.formatTemplate = tmpl
|
||||
|
||||
// Linters are by their very nature, short lived, so disable GC.
|
||||
// Reduced (user) linting time on kingpin from 0.97s to 0.64s.
|
||||
if !config.EnableGC {
|
||||
_ = os.Setenv("GOGC", "off")
|
||||
}
|
||||
// Force sorting by path if checkstyle mode is selected
|
||||
// !jsonFlag check is required to handle:
|
||||
// gometalinter --json --checkstyle --sort=severity
|
||||
if config.Checkstyle && !config.JSON {
|
||||
config.Sort = []string{"path"}
|
||||
}
|
||||
|
||||
// PlaceHolder to skipping "vendor" directory if GO15VENDOREXPERIMENT=1 is enabled.
|
||||
// TODO(alec): This will probably need to be enabled by default at a later time.
|
||||
if os.Getenv("GO15VENDOREXPERIMENT") == "1" || config.Vendor {
|
||||
if err := os.Setenv("GO15VENDOREXPERIMENT", "1"); err != nil {
|
||||
warning("setenv GO15VENDOREXPERIMENT: %s", err)
|
||||
}
|
||||
config.Skip = append(config.Skip, "vendor")
|
||||
config.Vendor = true
|
||||
}
|
||||
if len(config.Exclude) > 0 {
|
||||
exclude = regexp.MustCompile(strings.Join(config.Exclude, "|"))
|
||||
}
|
||||
|
||||
if len(config.Include) > 0 {
|
||||
include = regexp.MustCompile(strings.Join(config.Include, "|"))
|
||||
}
|
||||
|
||||
runtime.GOMAXPROCS(config.Concurrency)
|
||||
return include, exclude
|
||||
}
|
||||
|
||||
func outputToConsole(issues chan *Issue) int {
|
||||
status := 0
|
||||
for issue := range issues {
|
||||
if config.Errors && issue.Severity != Error {
|
||||
continue
|
||||
}
|
||||
fmt.Println(issue.String())
|
||||
status = 1
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func outputToJSON(issues chan *Issue) int {
|
||||
fmt.Println("[")
|
||||
status := 0
|
||||
for issue := range issues {
|
||||
if config.Errors && issue.Severity != Error {
|
||||
continue
|
||||
}
|
||||
if status != 0 {
|
||||
fmt.Printf(",\n")
|
||||
}
|
||||
d, err := json.Marshal(issue)
|
||||
kingpin.FatalIfError(err, "")
|
||||
fmt.Printf(" %s", d)
|
||||
status = 1
|
||||
}
|
||||
fmt.Printf("\n]\n")
|
||||
return status
|
||||
}
|
||||
|
||||
func resolvePaths(paths, skip []string) []string {
|
||||
if len(paths) == 0 {
|
||||
return []string{"."}
|
||||
}
|
||||
|
||||
skipPath := newPathFilter(skip)
|
||||
dirs := newStringSet()
|
||||
for _, path := range paths {
|
||||
if strings.HasSuffix(path, "/...") {
|
||||
root := filepath.Dir(path)
|
||||
_ = filepath.Walk(root, func(p string, i os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
warning("invalid path %q: %s", p, err)
|
||||
return err
|
||||
}
|
||||
|
||||
skip := skipPath(p)
|
||||
switch {
|
||||
case i.IsDir() && skip:
|
||||
return filepath.SkipDir
|
||||
case !i.IsDir() && !skip && strings.HasSuffix(p, ".go"):
|
||||
dirs.add(filepath.Clean(filepath.Dir(p)))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
dirs.add(filepath.Clean(path))
|
||||
}
|
||||
}
|
||||
out := make([]string, 0, dirs.size())
|
||||
for _, d := range dirs.asSlice() {
|
||||
out = append(out, relativePackagePath(d))
|
||||
}
|
||||
sort.Strings(out)
|
||||
for _, d := range out {
|
||||
debug("linting path %s", d)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func newPathFilter(skip []string) func(string) bool {
|
||||
filter := map[string]bool{}
|
||||
for _, name := range skip {
|
||||
filter[name] = true
|
||||
}
|
||||
|
||||
return func(path string) bool {
|
||||
base := filepath.Base(path)
|
||||
if filter[base] || filter[path] {
|
||||
return true
|
||||
}
|
||||
return base != "." && base != ".." && strings.ContainsAny(base[0:1], "_.")
|
||||
}
|
||||
}
|
||||
|
||||
func relativePackagePath(dir string) string {
|
||||
if filepath.IsAbs(dir) || strings.HasPrefix(dir, ".") {
|
||||
return dir
|
||||
}
|
||||
// package names must start with a ./
|
||||
return "./" + dir
|
||||
}
|
||||
|
||||
func lintersFromConfig(config *Config) map[string]*Linter {
|
||||
out := map[string]*Linter{}
|
||||
config.Enable = replaceWithMegacheck(config.Enable, config.EnableAll)
|
||||
for _, name := range config.Enable {
|
||||
linter := getLinterByName(name, LinterConfig(config.Linters[name]))
|
||||
if config.Fast && !linter.IsFast {
|
||||
continue
|
||||
}
|
||||
out[name] = linter
|
||||
}
|
||||
for _, linter := range config.Disable {
|
||||
delete(out, linter)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// replaceWithMegacheck checks enabled linters if they duplicate megacheck and
|
||||
// returns a either a revised list removing those and adding megacheck or an
|
||||
// unchanged slice. Emits a warning if linters were removed and swapped with
|
||||
// megacheck.
|
||||
func replaceWithMegacheck(enabled []string, enableAll bool) []string {
|
||||
var (
|
||||
staticcheck,
|
||||
gosimple,
|
||||
unused bool
|
||||
revised []string
|
||||
)
|
||||
for _, linter := range enabled {
|
||||
switch linter {
|
||||
case "staticcheck":
|
||||
staticcheck = true
|
||||
case "gosimple":
|
||||
gosimple = true
|
||||
case "unused":
|
||||
unused = true
|
||||
case "megacheck":
|
||||
// Don't add to revised slice, we'll add it later
|
||||
default:
|
||||
revised = append(revised, linter)
|
||||
}
|
||||
}
|
||||
if staticcheck && gosimple && unused {
|
||||
if !enableAll {
|
||||
warning("staticcheck, gosimple and unused are all set, using megacheck instead")
|
||||
}
|
||||
return append(revised, "megacheck")
|
||||
}
|
||||
return enabled
|
||||
}
|
||||
|
||||
func findVendoredLinters() string {
|
||||
gopaths := getGoPathList()
|
||||
for _, home := range vendoredSearchPaths {
|
||||
for _, p := range gopaths {
|
||||
joined := append([]string{p, "src"}, home...)
|
||||
vendorRoot := filepath.Join(joined...)
|
||||
if _, err := os.Stat(vendorRoot); err == nil {
|
||||
return vendorRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Go 1.8 compatible GOPATH.
|
||||
func getGoPath() string {
|
||||
path := os.Getenv("GOPATH")
|
||||
if path == "" {
|
||||
user, err := user.Current()
|
||||
kingpin.FatalIfError(err, "")
|
||||
path = filepath.Join(user.HomeDir, "go")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func getGoPathList() []string {
|
||||
return strings.Split(getGoPath(), string(os.PathListSeparator))
|
||||
}
|
||||
|
||||
// addPath appends path to paths if path does not already exist in paths. Returns
|
||||
// the new paths.
|
||||
func addPath(paths []string, path string) []string {
|
||||
for _, existingpath := range paths {
|
||||
if path == existingpath {
|
||||
return paths
|
||||
}
|
||||
}
|
||||
return append(paths, path)
|
||||
}
|
||||
|
||||
// configureEnvironment adds all `bin/` directories from $GOPATH to $PATH
|
||||
func configureEnvironment() {
|
||||
paths := addGoBinsToPath(getGoPathList())
|
||||
setEnv("PATH", strings.Join(paths, string(os.PathListSeparator)))
|
||||
debugPrintEnv()
|
||||
}
|
||||
|
||||
func addGoBinsToPath(gopaths []string) []string {
|
||||
paths := strings.Split(os.Getenv("PATH"), string(os.PathListSeparator))
|
||||
for _, p := range gopaths {
|
||||
paths = addPath(paths, filepath.Join(p, "bin"))
|
||||
}
|
||||
gobin := os.Getenv("GOBIN")
|
||||
if gobin != "" {
|
||||
paths = addPath(paths, gobin)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// configureEnvironmentForInstall sets GOPATH and GOBIN so that vendored linters
|
||||
// can be installed
|
||||
func configureEnvironmentForInstall() {
|
||||
if config.Update {
|
||||
warning(`Linters are now vendored by default, --update ignored. The original
|
||||
behaviour can be re-enabled with --no-vendored-linters.
|
||||
|
||||
To request an update for a vendored linter file an issue at:
|
||||
https://github.com/alecthomas/gometalinter/issues/new
|
||||
`)
|
||||
}
|
||||
gopaths := getGoPathList()
|
||||
vendorRoot := findVendoredLinters()
|
||||
if vendorRoot == "" {
|
||||
kingpin.Fatalf("could not find vendored linters in GOPATH=%q", getGoPath())
|
||||
}
|
||||
debug("found vendored linters at %s, updating environment", vendorRoot)
|
||||
|
||||
gobin := os.Getenv("GOBIN")
|
||||
if gobin == "" {
|
||||
gobin = filepath.Join(gopaths[0], "bin")
|
||||
}
|
||||
setEnv("GOBIN", gobin)
|
||||
|
||||
// "go install" panics when one GOPATH element is beneath another, so set
|
||||
// GOPATH to the vendor root
|
||||
setEnv("GOPATH", vendorRoot)
|
||||
debugPrintEnv()
|
||||
}
|
||||
|
||||
func setEnv(key string, value string) {
|
||||
if err := os.Setenv(key, value); err != nil {
|
||||
warning("setenv %s: %s", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrintEnv() {
|
||||
debug("PATH=%s", os.Getenv("PATH"))
|
||||
debug("GOPATH=%s", os.Getenv("GOPATH"))
|
||||
debug("GOBIN=%s", os.Getenv("GOBIN"))
|
||||
}
|
163
tools/vendor/github.com/alecthomas/gometalinter/partition.go
generated
vendored
163
tools/vendor/github.com/alecthomas/gometalinter/partition.go
generated
vendored
@ -1,163 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// MaxCommandBytes is the maximum number of bytes used when executing a command
|
||||
const MaxCommandBytes = 32000
|
||||
|
||||
type partitionStrategy func([]string, []string) ([][]string, error)
|
||||
|
||||
func (ps *partitionStrategy) UnmarshalJSON(raw []byte) error {
|
||||
var strategyName string
|
||||
if err := json.Unmarshal(raw, &strategyName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch strategyName {
|
||||
case "directories":
|
||||
*ps = partitionPathsAsDirectories
|
||||
case "files":
|
||||
*ps = partitionPathsAsFiles
|
||||
case "packages":
|
||||
*ps = partitionPathsAsPackages
|
||||
case "files-by-package":
|
||||
*ps = partitionPathsAsFilesGroupedByPackage
|
||||
case "single-directory":
|
||||
*ps = partitionPathsByDirectory
|
||||
default:
|
||||
return fmt.Errorf("unknown parition strategy %s", strategyName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pathsToFileGlobs(paths []string) ([]string, error) {
|
||||
filePaths := []string{}
|
||||
for _, dir := range paths {
|
||||
paths, err := filepath.Glob(filepath.Join(dir, "*.go"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filePaths = append(filePaths, paths...)
|
||||
}
|
||||
return filePaths, nil
|
||||
}
|
||||
|
||||
func partitionPathsAsDirectories(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
return partitionToMaxSize(cmdArgs, paths, MaxCommandBytes), nil
|
||||
}
|
||||
|
||||
func partitionToMaxSize(cmdArgs []string, paths []string, maxSize int) [][]string {
|
||||
partitions := newSizePartitioner(cmdArgs, maxSize)
|
||||
for _, path := range paths {
|
||||
partitions.add(path)
|
||||
}
|
||||
return partitions.end()
|
||||
}
|
||||
|
||||
type sizePartitioner struct {
|
||||
base []string
|
||||
parts [][]string
|
||||
current []string
|
||||
size int
|
||||
max int
|
||||
}
|
||||
|
||||
func newSizePartitioner(base []string, max int) *sizePartitioner {
|
||||
p := &sizePartitioner{base: base, max: max}
|
||||
p.new()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *sizePartitioner) add(arg string) {
|
||||
if p.size+len(arg)+1 > p.max {
|
||||
p.new()
|
||||
}
|
||||
p.current = append(p.current, arg)
|
||||
p.size += len(arg) + 1
|
||||
}
|
||||
|
||||
func (p *sizePartitioner) new() {
|
||||
p.end()
|
||||
p.size = 0
|
||||
p.current = []string{}
|
||||
for _, arg := range p.base {
|
||||
p.add(arg)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *sizePartitioner) end() [][]string {
|
||||
if len(p.current) > 0 {
|
||||
p.parts = append(p.parts, p.current)
|
||||
}
|
||||
return p.parts
|
||||
}
|
||||
|
||||
func partitionPathsAsFiles(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
filePaths, err := pathsToFileGlobs(paths)
|
||||
if err != nil || len(filePaths) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return partitionPathsAsDirectories(cmdArgs, filePaths)
|
||||
}
|
||||
|
||||
func partitionPathsAsFilesGroupedByPackage(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
parts := [][]string{}
|
||||
for _, path := range paths {
|
||||
filePaths, err := pathsToFileGlobs([]string{path})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(filePaths) == 0 {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, append(cmdArgs, filePaths...))
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
func partitionPathsAsPackages(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
packagePaths, err := pathsToPackagePaths(paths)
|
||||
if err != nil || len(packagePaths) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return partitionPathsAsDirectories(cmdArgs, packagePaths)
|
||||
}
|
||||
|
||||
func pathsToPackagePaths(paths []string) ([]string, error) {
|
||||
packages := []string{}
|
||||
|
||||
for _, path := range paths {
|
||||
pkg, err := packageNameFromPath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packages = append(packages, pkg)
|
||||
}
|
||||
return packages, nil
|
||||
}
|
||||
|
||||
func packageNameFromPath(path string) (string, error) {
|
||||
if !filepath.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
for _, gopath := range getGoPathList() {
|
||||
rel, err := filepath.Rel(filepath.Join(gopath, "src"), path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return rel, nil
|
||||
}
|
||||
return "", fmt.Errorf("%s not in GOPATH", path)
|
||||
}
|
||||
|
||||
func partitionPathsByDirectory(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
parts := [][]string{}
|
||||
for _, path := range paths {
|
||||
parts = append(parts, append(cmdArgs, path))
|
||||
}
|
||||
return parts, nil
|
||||
}
|
29
tools/vendor/github.com/alecthomas/gometalinter/stringset.go
generated
vendored
29
tools/vendor/github.com/alecthomas/gometalinter/stringset.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
package main
|
||||
|
||||
type stringSet struct {
|
||||
items map[string]struct{}
|
||||
}
|
||||
|
||||
func newStringSet(items ...string) *stringSet {
|
||||
setItems := make(map[string]struct{}, len(items))
|
||||
for _, item := range items {
|
||||
setItems[item] = struct{}{}
|
||||
}
|
||||
return &stringSet{items: setItems}
|
||||
}
|
||||
|
||||
func (s *stringSet) add(item string) {
|
||||
s.items[item] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *stringSet) asSlice() []string {
|
||||
items := []string{}
|
||||
for item := range s.items {
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (s *stringSet) size() int {
|
||||
return len(s.items)
|
||||
}
|
19
tools/vendor/github.com/alecthomas/units/COPYING
generated
vendored
19
tools/vendor/github.com/alecthomas/units/COPYING
generated
vendored
@ -1,19 +0,0 @@
|
||||
Copyright (C) 2014 Alec Thomas
|
||||
|
||||
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.
|
11
tools/vendor/github.com/alecthomas/units/README.md
generated
vendored
11
tools/vendor/github.com/alecthomas/units/README.md
generated
vendored
@ -1,11 +0,0 @@
|
||||
# Units - Helpful unit multipliers and functions for Go
|
||||
|
||||
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
|
||||
|
||||
It allows for code like this:
|
||||
|
||||
```go
|
||||
n, err := ParseBase2Bytes("1KB")
|
||||
// n == 1024
|
||||
n = units.Mebibyte * 512
|
||||
```
|
83
tools/vendor/github.com/alecthomas/units/bytes.go
generated
vendored
83
tools/vendor/github.com/alecthomas/units/bytes.go
generated
vendored
@ -1,83 +0,0 @@
|
||||
package units
|
||||
|
||||
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
|
||||
// etc.).
|
||||
type Base2Bytes int64
|
||||
|
||||
// Base-2 byte units.
|
||||
const (
|
||||
Kibibyte Base2Bytes = 1024
|
||||
KiB = Kibibyte
|
||||
Mebibyte = Kibibyte * 1024
|
||||
MiB = Mebibyte
|
||||
Gibibyte = Mebibyte * 1024
|
||||
GiB = Gibibyte
|
||||
Tebibyte = Gibibyte * 1024
|
||||
TiB = Tebibyte
|
||||
Pebibyte = Tebibyte * 1024
|
||||
PiB = Pebibyte
|
||||
Exbibyte = Pebibyte * 1024
|
||||
EiB = Exbibyte
|
||||
)
|
||||
|
||||
var (
|
||||
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
|
||||
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
|
||||
)
|
||||
|
||||
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
||||
// and KiB are both 1024.
|
||||
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, oldBytesUnitMap)
|
||||
}
|
||||
return Base2Bytes(n), err
|
||||
}
|
||||
|
||||
func (b Base2Bytes) String() string {
|
||||
return ToString(int64(b), 1024, "iB", "B")
|
||||
}
|
||||
|
||||
var (
|
||||
metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
|
||||
)
|
||||
|
||||
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
|
||||
type MetricBytes SI
|
||||
|
||||
// SI base-10 byte units.
|
||||
const (
|
||||
Kilobyte MetricBytes = 1000
|
||||
KB = Kilobyte
|
||||
Megabyte = Kilobyte * 1000
|
||||
MB = Megabyte
|
||||
Gigabyte = Megabyte * 1000
|
||||
GB = Gigabyte
|
||||
Terabyte = Gigabyte * 1000
|
||||
TB = Terabyte
|
||||
Petabyte = Terabyte * 1000
|
||||
PB = Petabyte
|
||||
Exabyte = Petabyte * 1000
|
||||
EB = Exabyte
|
||||
)
|
||||
|
||||
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
|
||||
func ParseMetricBytes(s string) (MetricBytes, error) {
|
||||
n, err := ParseUnit(s, metricBytesUnitMap)
|
||||
return MetricBytes(n), err
|
||||
}
|
||||
|
||||
func (m MetricBytes) String() string {
|
||||
return ToString(int64(m), 1000, "B", "B")
|
||||
}
|
||||
|
||||
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
||||
// respectively. That is, KiB represents 1024 and KB represents 1000.
|
||||
func ParseStrictBytes(s string) (int64, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, metricBytesUnitMap)
|
||||
}
|
||||
return int64(n), err
|
||||
}
|
13
tools/vendor/github.com/alecthomas/units/doc.go
generated
vendored
13
tools/vendor/github.com/alecthomas/units/doc.go
generated
vendored
@ -1,13 +0,0 @@
|
||||
// Package units provides helpful unit multipliers and functions for Go.
|
||||
//
|
||||
// The goal of this package is to have functionality similar to the time [1] package.
|
||||
//
|
||||
//
|
||||
// [1] http://golang.org/pkg/time/
|
||||
//
|
||||
// It allows for code like this:
|
||||
//
|
||||
// n, err := ParseBase2Bytes("1KB")
|
||||
// // n == 1024
|
||||
// n = units.Mebibyte * 512
|
||||
package units
|
26
tools/vendor/github.com/alecthomas/units/si.go
generated
vendored
26
tools/vendor/github.com/alecthomas/units/si.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
package units
|
||||
|
||||
// SI units.
|
||||
type SI int64
|
||||
|
||||
// SI unit multiples.
|
||||
const (
|
||||
Kilo SI = 1000
|
||||
Mega = Kilo * 1000
|
||||
Giga = Mega * 1000
|
||||
Tera = Giga * 1000
|
||||
Peta = Tera * 1000
|
||||
Exa = Peta * 1000
|
||||
)
|
||||
|
||||
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
||||
return map[string]float64{
|
||||
shortSuffix: 1,
|
||||
"K" + suffix: float64(scale),
|
||||
"M" + suffix: float64(scale * scale),
|
||||
"G" + suffix: float64(scale * scale * scale),
|
||||
"T" + suffix: float64(scale * scale * scale * scale),
|
||||
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
||||
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
||||
}
|
||||
}
|
138
tools/vendor/github.com/alecthomas/units/util.go
generated
vendored
138
tools/vendor/github.com/alecthomas/units/util.go
generated
vendored
@ -1,138 +0,0 @@
|
||||
package units
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
|
||||
)
|
||||
|
||||
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
|
||||
mn := len(siUnits)
|
||||
out := make([]string, mn)
|
||||
for i, m := range siUnits {
|
||||
if n%scale != 0 || i == 0 && n == 0 {
|
||||
s := suffix
|
||||
if i == 0 {
|
||||
s = baseSuffix
|
||||
}
|
||||
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
|
||||
}
|
||||
n /= scale
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings.Join(out, "")
|
||||
}
|
||||
|
||||
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
|
||||
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
|
||||
|
||||
// leadingInt consumes the leading [0-9]* from s.
|
||||
func leadingInt(s string) (x int64, rem string, err error) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
if x >= (1<<63-10)/10 {
|
||||
// overflow
|
||||
return 0, "", errLeadingInt
|
||||
}
|
||||
x = x*10 + int64(c) - '0'
|
||||
}
|
||||
return x, s[i:], nil
|
||||
}
|
||||
|
||||
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
|
||||
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
||||
orig := s
|
||||
f := float64(0)
|
||||
neg := false
|
||||
|
||||
// Consume [-+]?
|
||||
if s != "" {
|
||||
c := s[0]
|
||||
if c == '-' || c == '+' {
|
||||
neg = c == '-'
|
||||
s = s[1:]
|
||||
}
|
||||
}
|
||||
// Special case: if all that is left is "0", this is zero.
|
||||
if s == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
if s == "" {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
for s != "" {
|
||||
g := float64(0) // this element of the sequence
|
||||
|
||||
var x int64
|
||||
var err error
|
||||
|
||||
// The next character must be [0-9.]
|
||||
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
// Consume [0-9]*
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
g = float64(x)
|
||||
pre := pl != len(s) // whether we consumed anything before a period
|
||||
|
||||
// Consume (\.[0-9]*)?
|
||||
post := false
|
||||
if s != "" && s[0] == '.' {
|
||||
s = s[1:]
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
scale := 1.0
|
||||
for n := pl - len(s); n > 0; n-- {
|
||||
scale *= 10
|
||||
}
|
||||
g += float64(x) / scale
|
||||
post = pl != len(s)
|
||||
}
|
||||
if !pre && !post {
|
||||
// no digits (e.g. ".s" or "-.s")
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
|
||||
// Consume unit.
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '.' || ('0' <= c && c <= '9') {
|
||||
break
|
||||
}
|
||||
}
|
||||
u := s[:i]
|
||||
s = s[i:]
|
||||
unit, ok := unitMap[u]
|
||||
if !ok {
|
||||
return 0, errors.New("units: unknown unit " + u + " in " + orig)
|
||||
}
|
||||
|
||||
f += g * unit
|
||||
}
|
||||
|
||||
if neg {
|
||||
f = -f
|
||||
}
|
||||
if f < float64(-1<<63) || f > float64(1<<63-1) {
|
||||
return 0, errors.New("units: overflow parsing unit")
|
||||
}
|
||||
return int64(f), nil
|
||||
}
|
24
tools/vendor/github.com/alexflint/go-arg/LICENSE
generated
vendored
24
tools/vendor/github.com/alexflint/go-arg/LICENSE
generated
vendored
@ -1,24 +0,0 @@
|
||||
Copyright (c) 2015, Alex Flint
|
||||
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.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user