diff --git a/CHANGELOG.md b/CHANGELOG.md index cc112af85..8eea2baff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,89 @@ # Change Log +## [v1.2.1](https://github.com/containous/traefik/tree/v1.2.1) (2017-03-27) +[Full Changelog](https://github.com/containous/traefik/compare/v1.2.0...v1.2.1) + +**Merged pull requests:** + +- bump lego 0e2937900 [\#1347](https://github.com/containous/traefik/pull/1347) ([emilevauge](https://github.com/emilevauge)) +- k8s: Do not log service fields when GetService is failing. [\#1331](https://github.com/containous/traefik/pull/1331) ([timoreimann](https://github.com/timoreimann)) + +## [v1.2.0](https://github.com/containous/traefik/tree/v1.2.0) (2017-03-20) +[Full Changelog](https://github.com/containous/traefik/compare/v1.1.2...v1.2.0) + +**Merged pull requests:** + +- Docker: Added warning if network could not be found [\#1310](https://github.com/containous/traefik/pull/1310) ([zweizeichen](https://github.com/zweizeichen)) +- Add filter on task status in addition to desired status \(Docker Provider - swarm\) [\#1304](https://github.com/containous/traefik/pull/1304) ([Yshayy](https://github.com/Yshayy)) +- Abort Kubernetes Ingress update if Kubernetes API call fails [\#1295](https://github.com/containous/traefik/pull/1295) ([Regner](https://github.com/Regner)) +- Small fixes [\#1291](https://github.com/containous/traefik/pull/1291) ([emilevauge](https://github.com/emilevauge)) +- Rename health check URL parameter to path. [\#1285](https://github.com/containous/traefik/pull/1285) ([timoreimann](https://github.com/timoreimann)) +- Update Oxy, fix for \#1199 [\#1278](https://github.com/containous/traefik/pull/1278) ([akanto](https://github.com/akanto)) +- Fix metrics registering [\#1258](https://github.com/containous/traefik/pull/1258) ([matevzmihalic](https://github.com/matevzmihalic)) +- Update DefaultMaxIdleConnsPerHost default in docs. [\#1239](https://github.com/containous/traefik/pull/1239) ([timoreimann](https://github.com/timoreimann)) +- Update WSS/WS Proto \[Fixes \#670\] [\#1225](https://github.com/containous/traefik/pull/1225) ([dtomcej](https://github.com/dtomcej)) +- Bump go-rancher version [\#1219](https://github.com/containous/traefik/pull/1219) ([SantoDE](https://github.com/SantoDE)) +- Chunk taskArns into groups of 100 [\#1209](https://github.com/containous/traefik/pull/1209) ([owen](https://github.com/owen)) +- Prepare release v1.2.0 rc2 [\#1204](https://github.com/containous/traefik/pull/1204) ([emilevauge](https://github.com/emilevauge)) +- Revert "Ensure that we don't add balancees with no health check runs … [\#1198](https://github.com/containous/traefik/pull/1198) ([jangie](https://github.com/jangie)) +- Small fixes and improvments [\#1173](https://github.com/containous/traefik/pull/1173) ([SantoDE](https://github.com/SantoDE)) +- Fix docker issues with global and dead tasks [\#1167](https://github.com/containous/traefik/pull/1167) ([christopherobin](https://github.com/christopherobin)) +- Better ECS error checking [\#1143](https://github.com/containous/traefik/pull/1143) ([lpetre](https://github.com/lpetre)) +- Fix stats race condition [\#1141](https://github.com/containous/traefik/pull/1141) ([emilevauge](https://github.com/emilevauge)) +- ECS: Docs - info about cred. resolution and required access policies [\#1137](https://github.com/containous/traefik/pull/1137) ([rickard-von-essen](https://github.com/rickard-von-essen)) +- Healthcheck tests and doc [\#1132](https://github.com/containous/traefik/pull/1132) ([Juliens](https://github.com/Juliens)) +- Fix travis deploy [\#1128](https://github.com/containous/traefik/pull/1128) ([emilevauge](https://github.com/emilevauge)) +- Prepare release v1.2.0 rc1 [\#1126](https://github.com/containous/traefik/pull/1126) ([emilevauge](https://github.com/emilevauge)) +- Fix checkout initial before calling rmpr [\#1124](https://github.com/containous/traefik/pull/1124) ([emilevauge](https://github.com/emilevauge)) +- Feature rancher integration [\#1120](https://github.com/containous/traefik/pull/1120) ([SantoDE](https://github.com/SantoDE)) +- Fix glide go units [\#1119](https://github.com/containous/traefik/pull/1119) ([emilevauge](https://github.com/emilevauge)) +- Carry \#818 — Add systemd watchdog feature [\#1116](https://github.com/containous/traefik/pull/1116) ([vdemeester](https://github.com/vdemeester)) +- Skip file permission check on Windows [\#1115](https://github.com/containous/traefik/pull/1115) ([StefanScherer](https://github.com/StefanScherer)) +- Fix Docker API version for Windows [\#1113](https://github.com/containous/traefik/pull/1113) ([StefanScherer](https://github.com/StefanScherer)) +- Fix git rpr [\#1109](https://github.com/containous/traefik/pull/1109) ([emilevauge](https://github.com/emilevauge)) +- Fix docker version specifier [\#1108](https://github.com/containous/traefik/pull/1108) ([timoreimann](https://github.com/timoreimann)) +- Merge v1.1.2 master [\#1105](https://github.com/containous/traefik/pull/1105) ([emilevauge](https://github.com/emilevauge)) +- add sh before script in deploy... [\#1103](https://github.com/containous/traefik/pull/1103) ([emilevauge](https://github.com/emilevauge)) +- \[doc\] typo fixes for kubernetes user guide [\#1102](https://github.com/containous/traefik/pull/1102) ([bamarni](https://github.com/bamarni)) +- add skip\_cleanup in deploy [\#1101](https://github.com/containous/traefik/pull/1101) ([emilevauge](https://github.com/emilevauge)) +- Fix k8s example UI port. [\#1098](https://github.com/containous/traefik/pull/1098) ([ddunkin](https://github.com/ddunkin)) +- Fix marathon provider [\#1090](https://github.com/containous/traefik/pull/1090) ([diegooliveira](https://github.com/diegooliveira)) +- Add an ECS provider [\#1088](https://github.com/containous/traefik/pull/1088) ([lpetre](https://github.com/lpetre)) +- Update comment to reflect the code [\#1087](https://github.com/containous/traefik/pull/1087) ([np](https://github.com/np)) +- update NYTimes/gziphandler fixes \#1059 [\#1084](https://github.com/containous/traefik/pull/1084) ([JamesKyburz](https://github.com/JamesKyburz)) +- Ensure that we don't add balancees with no health check runs if there is a health check defined on it [\#1080](https://github.com/containous/traefik/pull/1080) ([jangie](https://github.com/jangie)) +- Add FreeBSD & OpenBSD to crossbinary [\#1078](https://github.com/containous/traefik/pull/1078) ([geoffgarside](https://github.com/geoffgarside)) +- Fix metrics for multiple entry points [\#1071](https://github.com/containous/traefik/pull/1071) ([matevzmihalic](https://github.com/matevzmihalic)) +- Allow setting load balancer method and sticky using service annotations [\#1068](https://github.com/containous/traefik/pull/1068) ([bakins](https://github.com/bakins)) +- Fix travis script [\#1067](https://github.com/containous/traefik/pull/1067) ([emilevauge](https://github.com/emilevauge)) +- Add missing fmt verb specifier in k8s provider. [\#1066](https://github.com/containous/traefik/pull/1066) ([timoreimann](https://github.com/timoreimann)) +- Add git rpr command [\#1063](https://github.com/containous/traefik/pull/1063) ([emilevauge](https://github.com/emilevauge)) +- Fix k8s example [\#1062](https://github.com/containous/traefik/pull/1062) ([emilevauge](https://github.com/emilevauge)) +- Replace underscores to dash in autogenerated urls \(docker provider\) [\#1061](https://github.com/containous/traefik/pull/1061) ([WTFKr0](https://github.com/WTFKr0)) +- Don't run go test on .glide cache folder [\#1057](https://github.com/containous/traefik/pull/1057) ([vdemeester](https://github.com/vdemeester)) +- Allow setting circuitbreaker expression via Kubernetes annotation [\#1056](https://github.com/containous/traefik/pull/1056) ([bakins](https://github.com/bakins)) +- Improving instrumentation. [\#1042](https://github.com/containous/traefik/pull/1042) ([enxebre](https://github.com/enxebre)) +- Update user guide for upcoming `docker stack deploy` [\#1041](https://github.com/containous/traefik/pull/1041) ([twelvelabs](https://github.com/twelvelabs)) +- Support sticky sessions under SWARM Mode. \#1024 [\#1033](https://github.com/containous/traefik/pull/1033) ([foleymic](https://github.com/foleymic)) +- Allow for wildcards in k8s ingress host, fixes \#792 [\#1029](https://github.com/containous/traefik/pull/1029) ([sheerun](https://github.com/sheerun)) +- Don't fetch ACME certificates for frontends using non-TLS entrypoints \(\#989\) [\#1023](https://github.com/containous/traefik/pull/1023) ([syfonseq](https://github.com/syfonseq)) +- Return Proper Non-ACME certificate - Fixes Issue 672 [\#1018](https://github.com/containous/traefik/pull/1018) ([dtomcej](https://github.com/dtomcej)) +- Fix docs build and add missing benchmarks page [\#1017](https://github.com/containous/traefik/pull/1017) ([csabapalfi](https://github.com/csabapalfi)) +- Set a NopCloser request body with retry middleware [\#1016](https://github.com/containous/traefik/pull/1016) ([bamarni](https://github.com/bamarni)) +- instruct to flatten dependencies with glide [\#1010](https://github.com/containous/traefik/pull/1010) ([bamarni](https://github.com/bamarni)) +- check permissions on acme.json during startup [\#1009](https://github.com/containous/traefik/pull/1009) ([bamarni](https://github.com/bamarni)) +- \[doc\] few tweaks on the basics page [\#1005](https://github.com/containous/traefik/pull/1005) ([bamarni](https://github.com/bamarni)) +- Import order as goimports does [\#1004](https://github.com/containous/traefik/pull/1004) ([vdemeester](https://github.com/vdemeester)) +- See the right go report badge [\#991](https://github.com/containous/traefik/pull/991) ([guilhem](https://github.com/guilhem)) +- Add multiple values for one rule to docs [\#978](https://github.com/containous/traefik/pull/978) ([j0hnsmith](https://github.com/j0hnsmith)) +- Add ACME/Let’s Encrypt integration tests [\#975](https://github.com/containous/traefik/pull/975) ([trecloux](https://github.com/trecloux)) +- deploy.sh: upload release source tarball [\#969](https://github.com/containous/traefik/pull/969) ([Mic92](https://github.com/Mic92)) +- toml zookeeper doc fix [\#948](https://github.com/containous/traefik/pull/948) ([brdude](https://github.com/brdude)) +- Add Rule AddPrefix [\#931](https://github.com/containous/traefik/pull/931) ([Juliens](https://github.com/Juliens)) +- Add bug command [\#921](https://github.com/containous/traefik/pull/921) ([emilevauge](https://github.com/emilevauge)) +- \(WIP\) feat: HealthCheck [\#918](https://github.com/containous/traefik/pull/918) ([Juliens](https://github.com/Juliens)) +- Add ability to set authenticated user in request header [\#889](https://github.com/containous/traefik/pull/889) ([ViViDboarder](https://github.com/ViViDboarder)) +- IP-per-task: [\#841](https://github.com/containous/traefik/pull/841) ([diegooliveira](https://github.com/diegooliveira)) ## [v1.2.0-rc2](https://github.com/containous/traefik/tree/v1.2.0-rc2) (2017-03-01) [Full Changelog](https://github.com/containous/traefik/compare/v1.2.0-rc1...v1.2.0-rc2) diff --git a/Makefile b/Makefile index dc8690e6d..b9c3dcad8 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ TRAEFIK_ENVS := \ -e VERSION \ -e CODENAME -SRCS = $(shell git ls-files '*.go' | grep -v '^external/') +SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/' | grep -v '^integration/vendor/') BIND_DIR := "dist" TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)" diff --git a/configuration.go b/configuration.go index 5286897fb..dca77f806 100644 --- a/configuration.go +++ b/configuration.go @@ -408,6 +408,9 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { defaultMesos.Endpoint = "http://127.0.0.1:5050" defaultMesos.ExposedByDefault = true defaultMesos.Constraints = types.Constraints{} + defaultMesos.RefreshSeconds = 30 + defaultMesos.ZkDetectionTimeout = 30 + defaultMesos.StateTimeoutSecond = 30 //default ECS var defaultECS provider.ECS diff --git a/docs/basics.md b/docs/basics.md index c183a2c84..7496b0d06 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -240,16 +240,22 @@ For example: sticky = true ``` -Healthcheck URL can be configured with a relative URL for `healthcheck.URL`. -Interval between healthcheck can be configured by using `healthcheck.interval` -(default: 30s) +A health check can be configured in order to remove a backend from LB rotation +as long as it keeps returning HTTP status codes other than 200 OK to HTTP GET +requests periodically carried out by Traefik. The check is defined by a path +appended to the backend URL and an interval (given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration)) specifying how +often the health check should be executed (the default being 30 seconds). Each +backend must respond to the health check within 5 seconds. + +A recovering backend returning 200 OK responses again is being returned to the +LB rotation pool. For example: ```toml [backends] [backends.backend1] [backends.backend1.healthcheck] - URL = "/health" + path = "/health" interval = "10s" ``` diff --git a/docs/toml.md b/docs/toml.md index 35af118fe..f1941143c 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -77,11 +77,13 @@ # # IdleTimeout = "360s" -# If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. -# If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value. +# Controls the maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost +# from the Go standard library net/http module is used. +# If you encounter 'too many open files' errors, you can either increase this +# value or change the `ulimit`. # # Optional -# Default: http.DefaultMaxIdleConnsPerHost +# Default: 200 # # MaxIdleConnsPerHost = 200 @@ -842,7 +844,7 @@ Labels can be used on containers to override default behaviour: - `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend. - `traefik.frontend.priority=10`: override default frontend priority - `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. -- `traefik.docker.network`: Set the docker network to use for connections to this container +- `traefik.docker.network`: Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with docker inspect ) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. If several ports need to be exposed from a container, the services labels can be used - `traefik..port=443`: create a service binding with frontend/backend using this port. Overrides `traefik.port`. @@ -1048,12 +1050,14 @@ domain = "mesos.localhost" # Zookeeper timeout (in seconds) # # Optional +# Default: 30 # # ZkDetectionTimeout = 30 # Polling interval (in seconds) # # Optional +# Default: 30 # # RefreshSeconds = 30 @@ -1066,8 +1070,9 @@ domain = "mesos.localhost" # HTTP Timeout (in seconds) # # Optional +# Default: 30 # -# StateTimeoutSecond = "host" +# StateTimeoutSecond = "30" ``` ## Kubernetes Ingress backend diff --git a/glide.lock b/glide.lock index 4b9f45666..9895a4e6a 100644 --- a/glide.lock +++ b/glide.lock @@ -1,21 +1,19 @@ -hash: b1cbcbd938a47a246b0d4d634037b76e63486c63e5867b339f92bcbd7453b75c -updated: 2017-04-07T11:34:46.101385591+01:00 +hash: 2abed980e61ff7659b181849419aadcb8d9d63594a5ac3215d09df0ea12a1700 +updated: 2017-04-11T17:02:21.540487905+02:00 imports: -- name: bitbucket.org/ww/goautoneg - version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 - name: cloud.google.com/go version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c subpackages: - compute/metadata - internal - name: github.com/abbot/go-http-auth - version: cb4372376e1e00e9f6ab9ec142e029302c9e7140 + version: d45c47bedec736d172957bd394786b76626fa8ac - name: github.com/ArthurHlt/go-eureka-client - version: ba361cd0f9f571b4e871421423d2f02f5689c3d2 + version: 9d0a49cbd39aa3634ae1977e9f519a262b10adaf subpackages: - eureka - name: github.com/ArthurHlt/gominlog - version: 068c01ce147ad68fca25ef3fa29ae5395ae273ab + version: 72eebf980f467d3ab3a8b4ddf660f664911ce519 - name: github.com/aws/aws-sdk-go version: 3f8f870ec9939e32b3372abf74d24e468bcd285d subpackages: @@ -65,27 +63,27 @@ imports: - autorest/date - autorest/to - name: github.com/beorn7/perks - version: b965b613227fddccbfffe13eae360ed3fa822f8d + version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 subpackages: - quantile - name: github.com/blang/semver version: 31b736133b98f26d5e078ec9eb591666edfd091f - name: github.com/boltdb/bolt - version: 5cc10bbbc5c141029940133bb33c9e969512a698 + version: e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd - name: github.com/BurntSushi/toml - version: 99064174e013895bbd9b025c31100bd1d9b590ca + version: b26d9c308763d68093482582cea63d69be07a0f0 - name: github.com/BurntSushi/ty version: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74 subpackages: - fun - name: github.com/cenk/backoff - version: 8edc80b07f38c27352fb186d971c628a6c32552b + version: 5d150e7eec023ce7a124856b37c68e54b4050ac7 - name: github.com/codahale/hdrhistogram version: 9208b142303c12d8899bae836fd524ac9338b4fd - name: github.com/codegangsta/cli version: bf4a526f48af7badd25d2cb02d587e1b01be3b50 - name: github.com/codegangsta/negroni - version: dc6b9d037e8dab60cbfc09c61d6932537829be8b + version: c0db5feaa33826cd5117930c8f4ee5c0f565eec6 - name: github.com/containous/flaeg version: b5d2dc5878df07c2d74413348186982e7b865871 - name: github.com/containous/mux @@ -95,11 +93,13 @@ imports: - name: github.com/coreos/etcd version: c400d05d0aa73e21e431c16145e558d624098018 subpackages: - - Godeps/_workspace/src/github.com/ugorji/go/codec - - Godeps/_workspace/src/golang.org/x/net/context + - Godeps/_workspace/src/github.com/coreos/go-systemd/journal + - Godeps/_workspace/src/github.com/coreos/pkg/capnslog - client + - pkg/fileutil - pkg/pathutil - pkg/types + - version - name: github.com/coreos/go-oidc version: 5644a2f50e2d2d5ba0b474bc5bc55fea1925936d subpackages: @@ -119,15 +119,13 @@ imports: - httputil - timeutil - name: github.com/davecgh/go-spew - version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 + version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 subpackages: - spew -- name: github.com/daviddengcn/go-colortext - version: 3b18c8575a432453d41fdafb340099fff5bba2f7 - name: github.com/decker502/dnspod-go - version: f6b1d56f1c048bd94d7e42ac36efb4d57b069b6f + version: 68650ee11e182e30773781d391c66a0c80ccf9f2 - name: github.com/dgrijalva/jwt-go - version: 9ed569b5d1ac936e6494082958d63a6aa4fff99a + version: d2709f9f1f31ebcda9651b03077758c1f3a0018c - name: github.com/dnsimple/dnsimple-go version: 5a5b427618a76f9eed5ede0f3e6306fbd9311d2e subpackages: @@ -168,9 +166,9 @@ imports: - name: github.com/docker/go-units version: 0dadbb0345b35ec7ef35e228dabb8de89a65bf52 - name: github.com/docker/leadership - version: bfc7753dd48af19513b29deec23c364bf0f274eb + version: 0a913e2d71a12fd14a028452435cb71ac8d82cb6 - name: github.com/docker/libkv - version: 35d3e2084c650109e7bcc7282655b1bc8ba924ff + version: 1d8431073ae03cdaedb198a89722f3aab6d418ef subpackages: - store - store/boltdb @@ -192,18 +190,20 @@ imports: - tokens - zones - name: github.com/elazarl/go-bindata-assetfs - version: 57eb5e1fc594ad4b0b1dbea7b286d299e0cb43c2 + version: 30f82fa23fd844bd5bb1e5f216db87fd77b5eb43 - name: github.com/emicklei/go-restful version: 892402ba11a2e2fd5e1295dd633481f27365f14d subpackages: - log - swagger +- name: github.com/fatih/color + version: 9131ab34cf20d2f6d83fdc67168a5430d1c7dc23 - name: github.com/gambol99/go-marathon version: 6b00a5b651b1beb2c6821863f7c60df490bd46c8 - name: github.com/ghodss/yaml version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee - name: github.com/go-ini/ini - version: 6f66b0e091edb3c7b380f7c4f0f884274d550b67 + version: e7fea39b01aea8d5671f6858f0532f56e8bff3a5 - name: github.com/go-kit/kit version: f66b0e13579bfc5a48b9e2a94b1209c107ea1f41 subpackages: @@ -226,15 +226,15 @@ imports: - name: github.com/golang/glog version: fca8c8854093a154ff1eb580aae10276ad6b1b5f - name: github.com/golang/protobuf - version: 5677a0e3d5e89854c9974e1256839ee23f8233ca + version: 2bba0603135d7d7f5cb73b2125beeda19c09f4ef subpackages: - proto - name: github.com/google/go-github - version: c8ebe3a4d7f0791a6315b7410353d4084c58805d + version: 6896997c7c9fe603fb9d2e8e92303bb18481e60a subpackages: - github - name: github.com/google/go-querystring - version: 9235644dd9e52eeae6fa48efd539fdc351a0af53 + version: 53e6ce116135b80d037921a7fdd5138cf32d7a8a subpackages: - query - name: github.com/google/gofuzz @@ -242,24 +242,23 @@ imports: - name: github.com/googleapis/gax-go version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b - name: github.com/gorilla/context - version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a + version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 - name: github.com/gorilla/websocket - version: 4873052237e4eeda85cf50c071ef33836fe8e139 + version: a91eba7f97777409bc2c443f5534d41dd20c5720 - name: github.com/hashicorp/consul - version: fce7d75609a04eeb9d4bf41c8dc592aac18fc97d + version: 3f92cc70e8163df866873c16c6d89889b5c95fc4 subpackages: - api - name: github.com/hashicorp/go-cleanhttp - version: 875fb671b3ddc66f8e2f0acc33829c8cb989a38d + version: 3573b8b52aa7b37b9358d966a898feb387f62437 - name: github.com/hashicorp/go-version - version: e96d3840402619007766590ecea8dd7af1292276 + version: 03c5bf6be031b6dd45afec16b1cf94fc8938bc77 - name: github.com/hashicorp/serf - version: 6c4672d66fc6312ddde18399262943e21175d831 + version: 19f2c401e122352c047a84d6584dd51e2fb8fcc4 subpackages: - coordinate - - serf - name: github.com/JamesClonk/vultr - version: 9ec0427d51411407c0402b093a1771cb75af9679 + version: 0f156dd232bc4ebf8a32ba83fec57c0e4c9db69f subpackages: - lib - name: github.com/jmespath/go-jmespath @@ -276,10 +275,16 @@ imports: - buffer - jlexer - jwriter +- name: github.com/mattn/go-colorable + version: 5411d3eea5978e6cdc258b30de592b60df6aba96 + repo: https://github.com/mattn/go-colorable +- name: github.com/mattn/go-isatty + version: 57fdcb988a5c543893cc61bce354a6e24ab70022 + repo: https://github.com/mattn/go-isatty - name: github.com/mattn/go-shellwords - version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24 + version: 02e3cf038dcea8290e44424da473dd12be796a8a - name: github.com/matttproud/golang_protobuf_extensions - version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a + version: c12348ce28de40eed0136aa2b644d0ee0650e56c subpackages: - pbutil - name: github.com/mesos/mesos-go @@ -305,79 +310,82 @@ imports: - records/state - util - name: github.com/Microsoft/go-winio - version: ce2922f643c8fd76b46cadc7f404a06282678b34 + version: fff283ad5116362ca252298cfc9b95828956d85d - name: github.com/miekg/dns version: 8060d9f51305bbe024b99679454e62f552cd0b0b - name: github.com/mitchellh/mapstructure - version: f3009df150dadf309fdee4a54ed65c124afad715 + version: 53818660ed4955e899c0bcafa97299a388bd7c8e - name: github.com/mvdan/xurls - version: fa08908f19eca8c491d68c6bd8b4b44faea6daf8 + version: db96455566f05ffe42bd6ac671f05eeb1152b45d - name: github.com/NYTimes/gziphandler - version: 6710af535839f57c687b62c4c23d649f9545d885 + version: 22d4470af89e09998fc16b35029df973932df4ae - name: github.com/ogier/pflag version: 45c278ab3607870051a2ea9040bb85fcb8557481 - name: github.com/opencontainers/runc - version: 1a81e9ab1f138c091fe5c86d0883f87716088527 + version: 50401b5b4c2e01e4f1372b73a021742deeaf4e2d subpackages: - libcontainer/user - name: github.com/ovh/go-ovh - version: a8a4c0bc40e56322142649bda7b2b4bb15145b6e + version: d2207178e10e4527e8f222fd8707982df8c3af17 subpackages: - ovh - name: github.com/pborman/uuid version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 - name: github.com/pkg/errors - version: bfd5150e4e41705ded2129ec33379de1cb90b513 + version: ff09b135c25aae272398c51a07235b90a75aa4f0 - name: github.com/pmezard/go-difflib version: d8ed2627bdf02c080bf22230dbb337003b7aba2d subpackages: - difflib - name: github.com/prometheus/client_golang - version: c5b7fccd204277076155f10851dad72b76a49317 + version: 08fd2e12372a66e68e30523c7642e0cbc3e4fbde subpackages: - prometheus - prometheus/promhttp - name: github.com/prometheus/client_model - version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6 + version: 6f3806018612930941127f2a7c6c453ba2c527d2 subpackages: - go - name: github.com/prometheus/common - version: ffe929a3f4c4faeaa10f2b9535c2b1be3ad15650 + version: 49fee292b27bfff7f354ee0f64e1bc4850462edf subpackages: - expfmt + - internal/bitbucket.org/ww/goautoneg - model - name: github.com/prometheus/procfs - version: 454a56f35412459b5e684fd5ec0f9211b94f002a + version: a1dba9ce8baed984a2495b658c82687f8157b98f + subpackages: + - xfs - name: github.com/PuerkitoBio/purell version: 8a290539e2e8629dbc4e6bad948158f790ec31f4 - name: github.com/PuerkitoBio/urlesc version: 5bd2802263f21d8788851d5305584c82a5c75d7e - name: github.com/pyr/egoscale - version: ab4b0d7ff424c462da486aef27f354cdeb29a319 + version: 987e683a7552f34ee586217d1cc8507d52e80ab9 subpackages: - src/egoscale - name: github.com/rancher/go-rancher - version: 2c43ff300f3eafcbd7d0b89b10427fc630efdc1e + version: 5b8f6cc26b355ba03d7611fce3844155b7baf05b subpackages: - client - name: github.com/ryanuber/go-glob - version: 572520ed46dbddaed19ea3d9541bdd0494163693 + version: 256dc444b735e061061cf46c809487313d5b0065 - name: github.com/samuel/go-zookeeper - version: e64db453f3512cade908163702045e0f31137843 + version: 1d7be4effb13d2d908342d349d71a284a7542693 subpackages: - zk - name: github.com/satori/go.uuid version: 879c5887cd475cd7864858769793b2ceb0d44feb - name: github.com/Sirupsen/logrus - version: a283a10442df8dc09befd873fab202bf8a253d6a + version: 10f801ebc38b33738c9d17d50860f484a0988ff5 - name: github.com/spf13/pflag version: 5ccb023bc27df288a957c5e994cd44fd19619465 - name: github.com/streamrail/concurrent-map - version: 65a174a3a4188c0b7099acbc6cfa0c53628d3287 + version: 8bf1e9bacbf65b10c81d0f4314cf2b1ebef728b5 - name: github.com/stretchr/objx version: cbeaeb16a013161a98496fad62933b1d21786672 - name: github.com/stretchr/testify - version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 + version: 4d4bfba8f1d1027c4fdbe371823030df51419987 subpackages: - assert - mock @@ -394,11 +402,11 @@ imports: subpackages: - codec - name: github.com/unrolled/render - version: 198ad4d8b8a4612176b804ca10555b222a086b40 + version: 50716a0a853771bb36bfce61a45cdefdb98c2e6e - name: github.com/vdemeester/docker-events version: be74d4929ec1ad118df54349fda4b0cba60f849b - name: github.com/vulcand/oxy - version: fcc76b52eb8568540a020b7a99e854d9d752b364 + version: f88530866c561d24a6b5aac49f76d6351b788b9f repo: https://github.com/containous/oxy.git vcs: git subpackages: @@ -523,17 +531,18 @@ imports: - tap - transport - name: gopkg.in/fsnotify.v1 - version: a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb + version: 629574ca2a5df945712d3079857300b5e4da0236 - name: gopkg.in/inf.v0 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 - name: gopkg.in/ini.v1 - version: 6f66b0e091edb3c7b380f7c4f0f884274d550b67 + version: e7fea39b01aea8d5671f6858f0532f56e8bff3a5 - name: gopkg.in/mgo.v2 - version: 29cc868a5ca65f401ff318143f9408d02f4799cc + version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 subpackages: - bson + - internal/json - name: gopkg.in/ns1/ns1-go.v2 - version: d8d10b7f448291ddbdce48d4594fb1b667014c8b + version: 2abc76c60bf88ba33b15d1d87a13f624d8dff956 subpackages: - rest - rest/model/account @@ -542,7 +551,7 @@ imports: - rest/model/filter - rest/model/monitor - name: gopkg.in/square/go-jose.v1 - version: e3f973b66b91445ec816dd7411ad1b6495a5a2fc + version: aa2e30fdd1fe9dd3394119af66451ae790d50e0d subpackages: - cipher - json diff --git a/glide.yaml b/glide.yaml index 62091d1b6..6d7d7506c 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,7 +8,7 @@ import: - package: github.com/cenk/backoff - package: github.com/containous/flaeg - package: github.com/vulcand/oxy - version: fcc76b52eb8568540a020b7a99e854d9d752b364 + version: f88530866c561d24a6b5aac49f76d6351b788b9f repo: https://github.com/containous/oxy.git vcs: git subpackages: @@ -139,7 +139,7 @@ import: subpackages: - proto - package: github.com/rancher/go-rancher - version: 2c43ff300f3eafcbd7d0b89b10427fc630efdc1e + version: 5b8f6cc26b355ba03d7611fce3844155b7baf05b - package: golang.org/x/oauth2/google version: 7fdf09982454086d5570c7db3e11f360194830ca - package: github.com/googleapis/gax-go diff --git a/healthcheck/healthcheck.go b/healthcheck/healthcheck.go index fb2f74eb4..316e75ca6 100644 --- a/healthcheck/healthcheck.go +++ b/healthcheck/healthcheck.go @@ -25,7 +25,7 @@ func GetHealthCheck() *HealthCheck { // BackendHealthCheck HealthCheck configuration for a backend type BackendHealthCheck struct { - URL string + Path string Interval time.Duration DisabledURLs []*url.URL requestTimeout time.Duration @@ -53,9 +53,9 @@ func newHealthCheck() *HealthCheck { } // NewBackendHealthCheck Instantiate a new BackendHealthCheck -func NewBackendHealthCheck(URL string, interval time.Duration, lb loadBalancer) *BackendHealthCheck { +func NewBackendHealthCheck(Path string, interval time.Duration, lb loadBalancer) *BackendHealthCheck { return &BackendHealthCheck{ - URL: URL, + Path: Path, Interval: interval, requestTimeout: 5 * time.Second, lb: lb, @@ -124,7 +124,7 @@ func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) bool { client := http.Client{ Timeout: backend.requestTimeout, } - resp, err := client.Get(serverURL.String() + backend.URL) + resp, err := client.Get(serverURL.String() + backend.Path) if err == nil { defer resp.Body.Close() } diff --git a/integration/basic_test.go b/integration/basic_test.go index 1ef8521cc..6f54659b6 100644 --- a/integration/basic_test.go +++ b/integration/basic_test.go @@ -26,7 +26,7 @@ func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) { defer cmd.Process.Kill() output := b.Bytes() - c.Assert(string(output), checker.Contains, "Near line 0 (last key parsed ''): Bare keys cannot contain '{'") + c.Assert(string(output), checker.Contains, "Near line 0 (last key parsed ''): bare keys cannot contain '{'") } func (s *SimpleSuite) TestSimpleDefaultConfig(c *check.C) { @@ -70,7 +70,7 @@ func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) { defer cmd.Process.Kill() output := b.Bytes() - c.Assert(string(output), checker.Contains, "\\\"DefaultEntryPoints\\\":[\\\"http\\\"]") + c.Assert(string(output), checker.Contains, "\"DefaultEntryPoints\":[\"http\"]") } func (s *SimpleSuite) TestPrintHelp(c *check.C) { diff --git a/middlewares/prometheus.go b/middlewares/prometheus.go index 366b96727..f41a51ffb 100644 --- a/middlewares/prometheus.go +++ b/middlewares/prometheus.go @@ -32,7 +32,8 @@ func (p *Prometheus) getLatencyHistogram() metrics.Histogram { // NewPrometheus returns a new prometheus Metrics implementation. func NewPrometheus(name string, config *types.Prometheus) *Prometheus { var m Prometheus - m.reqsCounter = prometheus.NewCounterFrom( + + cv := stdprometheus.NewCounterVec( stdprometheus.CounterOpts{ Name: reqsName, Help: "How many HTTP requests processed, partitioned by status code and method.", @@ -41,6 +42,17 @@ func NewPrometheus(name string, config *types.Prometheus) *Prometheus { []string{"code", "method"}, ) + err := stdprometheus.Register(cv) + if err != nil { + e, ok := err.(stdprometheus.AlreadyRegisteredError) + if !ok { + panic(err) + } + m.reqsCounter = prometheus.NewCounter(e.ExistingCollector.(*stdprometheus.CounterVec)) + } else { + m.reqsCounter = prometheus.NewCounter(cv) + } + var buckets []float64 if config.Buckets != nil { buckets = config.Buckets @@ -48,7 +60,7 @@ func NewPrometheus(name string, config *types.Prometheus) *Prometheus { buckets = []float64{0.1, 0.3, 1.2, 5} } - m.latencyHistogram = prometheus.NewHistogramFrom( + hv := stdprometheus.NewHistogramVec( stdprometheus.HistogramOpts{ Name: latencyName, Help: "How long it took to process the request.", @@ -57,6 +69,18 @@ func NewPrometheus(name string, config *types.Prometheus) *Prometheus { }, []string{}, ) + + err = stdprometheus.Register(hv) + if err != nil { + e, ok := err.(stdprometheus.AlreadyRegisteredError) + if !ok { + panic(err) + } + m.latencyHistogram = prometheus.NewHistogram(e.ExistingCollector.(*stdprometheus.HistogramVec)) + } else { + m.latencyHistogram = prometheus.NewHistogram(hv) + } + return &m } diff --git a/middlewares/prometheus_test.go b/middlewares/prometheus_test.go index 8315b1756..08931ac8b 100644 --- a/middlewares/prometheus_test.go +++ b/middlewares/prometheus_test.go @@ -9,10 +9,19 @@ import ( "github.com/codegangsta/negroni" "github.com/containous/traefik/types" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/assert" ) func TestPrometheus(t *testing.T) { + metricsFamily, err := prometheus.DefaultGatherer.Gather() + if err != nil { + t.Fatalf("could not gather metrics family: %s", err) + } + initialMetricsFamilyCount := len(metricsFamily) + recorder := httptest.NewRecorder() n := negroni.New() @@ -42,6 +51,80 @@ func TestPrometheus(t *testing.T) { t.Errorf("body does not contain request total entry '%s'", reqsName) } if !strings.Contains(body, latencyName) { - t.Errorf("body does not contain request duration entry '%s'", reqsName) + t.Errorf("body does not contain request duration entry '%s'", latencyName) + } + + // Register the same metrics again + metricsMiddlewareBackend = NewMetricsWrapper(NewPrometheus("test", &types.Prometheus{})) + n = negroni.New() + n.Use(metricsMiddlewareBackend) + n.UseHandler(r) + + n.ServeHTTP(recorder, req2) + + metricsFamily, err = prometheus.DefaultGatherer.Gather() + if err != nil { + t.Fatalf("could not gather metrics family: %s", err) + } + + tests := []struct { + name string + labels map[string]string + assert func(*dto.MetricFamily) + }{ + { + name: reqsName, + labels: map[string]string{ + "code": "200", + "method": "GET", + "service": "test", + }, + assert: func(family *dto.MetricFamily) { + cv := uint(family.Metric[0].Counter.GetValue()) + if cv != 3 { + t.Errorf("gathered metrics do not contain correct value for total requests, got %d", cv) + } + }, + }, + { + name: latencyName, + labels: map[string]string{ + "service": "test", + }, + assert: func(family *dto.MetricFamily) { + sc := family.Metric[0].Histogram.GetSampleCount() + if sc != 3 { + t.Errorf("gathered metrics do not contain correct sample count for request duration, got %d", sc) + } + }, + }, + } + + assert.Equal(t, len(tests), len(metricsFamily)-initialMetricsFamilyCount, "gathered traefic metrics count does not match tests count") + + for _, test := range tests { + family := findMetricFamily(test.name, metricsFamily) + if family == nil { + t.Errorf("gathered metrics do not contain '%s'", test.name) + continue + } + for _, label := range family.Metric[0].Label { + val, ok := test.labels[*label.Name] + if !ok { + t.Errorf("'%s' metric contains unexpected label '%s'", test.name, label) + } else if val != *label.Value { + t.Errorf("label '%s' in metric '%s' has wrong value '%s'", label, test.name, *label.Value) + } + } + test.assert(family) } } + +func findMetricFamily(name string, families []*dto.MetricFamily) *dto.MetricFamily { + for _, family := range families { + if family.GetName() == name { + return family + } + } + return nil +} diff --git a/provider/docker.go b/provider/docker.go index 9cc57b17d..408e21b0a 100644 --- a/provider/docker.go +++ b/provider/docker.go @@ -550,6 +550,8 @@ func (provider *Docker) getIPAddress(container dockerData) string { if network != nil { return network.Addr } + + log.Warnf("Could not find network named '%s' for container '%s'! Maybe you're missing the project's prefix in the label? Defaulting to first available network.", label, container.Name) } } @@ -826,6 +828,9 @@ func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID str var dockerDataList []dockerData for _, task := range taskList { + if task.Status.State != swarm.TaskStateRunning { + continue + } dockerData := parseTasks(task, serviceDockerData, networkMap, isGlobalSvc) dockerDataList = append(dockerDataList, dockerData) } diff --git a/provider/docker_test.go b/provider/docker_test.go index ac614ae1c..a855f4007 100644 --- a/provider/docker_test.go +++ b/provider/docker_test.go @@ -6,11 +6,16 @@ import ( "testing" "github.com/containous/traefik/types" + "github.com/davecgh/go-spew/spew" + dockerclient "github.com/docker/engine-api/client" docker "github.com/docker/engine-api/types" + dockertypes "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/network" "github.com/docker/engine-api/types/swarm" "github.com/docker/go-connections/nat" + "golang.org/x/net/context" + "strconv" ) func TestDockerGetFrontendName(t *testing.T) { @@ -99,12 +104,16 @@ func TestDockerGetFrontendName(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getFrontendName(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getFrontendName(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -176,12 +185,16 @@ func TestDockerGetFrontendRule(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getFrontendRule(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getFrontendRule(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -239,12 +252,16 @@ func TestDockerGetBackend(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getBackend(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getBackend(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -340,12 +357,16 @@ func TestDockerGetIPAddress(t *testing.T) { // TODO }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getIPAddress(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getIPAddress(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -453,12 +474,16 @@ func TestDockerGetPort(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getPort(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getPort(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -493,12 +518,16 @@ func TestDockerGetWeight(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getWeight(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getWeight(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -535,12 +564,16 @@ func TestDockerGetDomain(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getDomain(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getDomain(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -575,12 +608,16 @@ func TestDockerGetProtocol(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getProtocol(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getProtocol(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -614,12 +651,16 @@ func TestDockerGetPassHostHeader(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - actual := provider.getPassHostHeader(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + actual := provider.getPassHostHeader(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -652,18 +693,22 @@ func TestDockerGetLabel(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - label, err := getLabel(dockerData, "foo") - if e.expected != "" { - if err == nil || !strings.Contains(err.Error(), e.expected) { - t.Fatalf("expected an error with %q, got %v", e.expected, err) + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + label, err := getLabel(dockerData, "foo") + if e.expected != "" { + if err == nil || !strings.Contains(err.Error(), e.expected) { + t.Errorf("expected an error with %q, got %v", e.expected, err) + } + } else { + if label != "bar" { + t.Errorf("expected label 'bar', got %s", label) + } } - } else { - if label != "bar" { - t.Fatalf("expected label 'bar', got %s", label) - } - } + }) } } @@ -719,17 +764,21 @@ func TestDockerGetLabels(t *testing.T) { }, } - for _, e := range containers { - dockerData := parseContainer(e.container) - labels, err := getLabels(dockerData, []string{"foo", "bar"}) - if !reflect.DeepEqual(labels, e.expectedLabels) { - t.Fatalf("expect %v, got %v", e.expectedLabels, labels) - } - if e.expectedError != "" { - if err == nil || !strings.Contains(err.Error(), e.expectedError) { - t.Fatalf("expected an error with %q, got %v", e.expectedError, err) + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + dockerData := parseContainer(e.container) + labels, err := getLabels(dockerData, []string{"foo", "bar"}) + if !reflect.DeepEqual(labels, e.expectedLabels) { + t.Errorf("expect %v, got %v", e.expectedLabels, labels) } - } + if e.expectedError != "" { + if err == nil || !strings.Contains(err.Error(), e.expectedError) { + t.Errorf("expected an error with %q, got %v", e.expectedError, err) + } + } + }) } } @@ -953,13 +1002,17 @@ func TestDockerTraefikFilter(t *testing.T) { }, } - for _, e := range containers { - provider.ExposedByDefault = e.exposedByDefault - dockerData := parseContainer(e.container) - actual := provider.containerFilter(dockerData) - if actual != e.expected { - t.Fatalf("expected %v for %+v, got %+v", e.expected, e, actual) - } + for containerID, e := range containers { + e := e + t.Run(strconv.Itoa(containerID), func(t *testing.T) { + t.Parallel() + provider.ExposedByDefault = e.exposedByDefault + dockerData := parseContainer(e.container) + actual := provider.containerFilter(dockerData) + if actual != e.expected { + t.Errorf("expected %v for %+v, got %+v", e.expected, e, actual) + } + }) } } @@ -1175,21 +1228,25 @@ func TestDockerLoadDockerConfig(t *testing.T) { ExposedByDefault: true, } - for _, c := range cases { - var dockerDataList []dockerData - for _, container := range c.containers { - dockerData := parseContainer(container) - dockerDataList = append(dockerDataList, dockerData) - } + for caseID, c := range cases { + c := c + t.Run(strconv.Itoa(caseID), func(t *testing.T) { + t.Parallel() + var dockerDataList []dockerData + for _, container := range c.containers { + dockerData := parseContainer(container) + dockerDataList = append(dockerDataList, dockerData) + } - actualConfig := provider.loadDockerConfig(dockerDataList) - // Compare backends - if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) { - t.Fatalf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends) - } - if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) { - t.Fatalf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends) - } + actualConfig := provider.loadDockerConfig(dockerDataList) + // Compare backends + if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) { + t.Errorf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends) + } + if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) { + t.Errorf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends) + } + }) } } @@ -1273,12 +1330,16 @@ func TestSwarmGetFrontendName(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getFrontendName(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getFrontendName(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1345,12 +1406,16 @@ func TestSwarmGetFrontendRule(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getFrontendRule(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getFrontendRule(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1402,12 +1467,16 @@ func TestSwarmGetBackend(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getBackend(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getBackend(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1499,12 +1568,16 @@ func TestSwarmGetIPAddress(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getIPAddress(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getIPAddress(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1537,12 +1610,16 @@ func TestSwarmGetPort(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getPort(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getPort(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1589,12 +1666,16 @@ func TestSwarmGetWeight(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getWeight(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getWeight(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1642,12 +1723,16 @@ func TestSwarmGetDomain(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getDomain(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getDomain(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1694,12 +1779,16 @@ func TestSwarmGetProtocol(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getProtocol(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getProtocol(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } @@ -1746,17 +1835,20 @@ func TestSwarmGetPassHostHeader(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - actual := provider.getPassHostHeader(dockerData) - if actual != e.expected { - t.Fatalf("expected %q, got %q", e.expected, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + actual := provider.getPassHostHeader(dockerData) + if actual != e.expected { + t.Errorf("expected %q, got %q", e.expected, actual) + } + }) } } func TestSwarmGetLabel(t *testing.T) { - services := []struct { service swarm.Service expected string @@ -1795,18 +1887,22 @@ func TestSwarmGetLabel(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - label, err := getLabel(dockerData, "foo") - if e.expected != "" { - if err == nil || !strings.Contains(err.Error(), e.expected) { - t.Fatalf("expected an error with %q, got %v", e.expected, err) + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + label, err := getLabel(dockerData, "foo") + if e.expected != "" { + if err == nil || !strings.Contains(err.Error(), e.expected) { + t.Errorf("expected an error with %q, got %v", e.expected, err) + } + } else { + if label != "bar" { + t.Errorf("expected label 'bar', got %s", label) + } } - } else { - if label != "bar" { - t.Fatalf("expected label 'bar', got %s", label) - } - } + }) } } @@ -1867,17 +1963,21 @@ func TestSwarmGetLabels(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - labels, err := getLabels(dockerData, []string{"foo", "bar"}) - if !reflect.DeepEqual(labels, e.expectedLabels) { - t.Fatalf("expect %v, got %v", e.expectedLabels, labels) - } - if e.expectedError != "" { - if err == nil || !strings.Contains(err.Error(), e.expectedError) { - t.Fatalf("expected an error with %q, got %v", e.expectedError, err) + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + labels, err := getLabels(dockerData, []string{"foo", "bar"}) + if !reflect.DeepEqual(labels, e.expectedLabels) { + t.Errorf("expect %v, got %v", e.expectedLabels, labels) } - } + if e.expectedError != "" { + if err == nil || !strings.Contains(err.Error(), e.expectedError) { + t.Errorf("expected an error with %q, got %v", e.expectedError, err) + } + } + }) } } @@ -2031,13 +2131,17 @@ func TestSwarmTraefikFilter(t *testing.T) { }, } - for _, e := range services { - dockerData := parseService(e.service, e.networks) - provider.ExposedByDefault = e.exposedByDefault - actual := provider.containerFilter(dockerData) - if actual != e.expected { - t.Fatalf("expected %v for %+v, got %+v", e.expected, e, actual) - } + for serviceID, e := range services { + e := e + t.Run(strconv.Itoa(serviceID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + provider.ExposedByDefault = e.exposedByDefault + actual := provider.containerFilter(dockerData) + if actual != e.expected { + t.Errorf("expected %v for %+v, got %+v", e.expected, e, actual) + } + }) } } @@ -2208,21 +2312,25 @@ func TestSwarmLoadDockerConfig(t *testing.T) { SwarmMode: true, } - for _, c := range cases { - var dockerDataList []dockerData - for _, service := range c.services { - dockerData := parseService(service, c.networks) - dockerDataList = append(dockerDataList, dockerData) - } + for caseID, c := range cases { + c := c + t.Run(strconv.Itoa(caseID), func(t *testing.T) { + t.Parallel() + var dockerDataList []dockerData + for _, service := range c.services { + dockerData := parseService(service, c.networks) + dockerDataList = append(dockerDataList, dockerData) + } - actualConfig := provider.loadDockerConfig(dockerDataList) - // Compare backends - if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) { - t.Fatalf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends) - } - if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) { - t.Fatalf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends) - } + actualConfig := provider.loadDockerConfig(dockerDataList) + // Compare backends + if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) { + t.Errorf("expected %#v, got %#v", c.expectedBackends, actualConfig.Backends) + } + if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) { + t.Errorf("expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends) + } + }) } } @@ -2230,7 +2338,7 @@ func TestSwarmTaskParsing(t *testing.T) { cases := []struct { service swarm.Service tasks []swarm.Task - isGlobalSvc bool + isGlobalSVC bool expectedNames map[string]string networks map[string]*docker.NetworkResource }{ @@ -2256,7 +2364,7 @@ func TestSwarmTaskParsing(t *testing.T) { Slot: 3, }, }, - isGlobalSvc: false, + isGlobalSVC: false, expectedNames: map[string]string{ "id1": "container.1", "id2": "container.2", @@ -2287,7 +2395,7 @@ func TestSwarmTaskParsing(t *testing.T) { ID: "id3", }, }, - isGlobalSvc: true, + isGlobalSVC: true, expectedNames: map[string]string{ "id1": "container.id1", "id2": "container.id2", @@ -2301,15 +2409,113 @@ func TestSwarmTaskParsing(t *testing.T) { }, } - for _, e := range cases { - dockerData := parseService(e.service, e.networks) + for caseID, e := range cases { + e := e + t.Run(strconv.Itoa(caseID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) - for _, task := range e.tasks { - taskDockerData := parseTasks(task, dockerData, map[string]*docker.NetworkResource{}, e.isGlobalSvc) - if !reflect.DeepEqual(taskDockerData.Name, e.expectedNames[task.ID]) { - t.Fatalf("expect %v, got %v", e.expectedNames[task.ID], taskDockerData.Name) + for _, task := range e.tasks { + taskDockerData := parseTasks(task, dockerData, map[string]*docker.NetworkResource{}, e.isGlobalSVC) + if !reflect.DeepEqual(taskDockerData.Name, e.expectedNames[task.ID]) { + t.Errorf("expect %v, got %v", e.expectedNames[task.ID], taskDockerData.Name) + } } - } + }) + } +} + +type fakeTasksClient struct { + dockerclient.APIClient + tasks []swarm.Task + err error +} + +func (c *fakeTasksClient) TaskList(ctx context.Context, options dockertypes.TaskListOptions) ([]swarm.Task, error) { + return c.tasks, c.err +} + +func TestListTasks(t *testing.T) { + cases := []struct { + service swarm.Service + tasks []swarm.Task + isGlobalSVC bool + expectedTasks []string + networks map[string]*docker.NetworkResource + }{ + { + service: swarm.Service{ + Spec: swarm.ServiceSpec{ + Annotations: swarm.Annotations{ + Name: "container", + }, + }, + }, + tasks: []swarm.Task{ + { + ID: "id1", + Slot: 1, + Status: swarm.TaskStatus{ + State: swarm.TaskStateRunning, + }, + }, + { + ID: "id2", + Slot: 2, + Status: swarm.TaskStatus{ + State: swarm.TaskStatePending, + }, + }, + { + ID: "id3", + Slot: 3, + }, + { + ID: "id4", + Slot: 4, + Status: swarm.TaskStatus{ + State: swarm.TaskStateRunning, + }, + }, + { + ID: "id5", + Slot: 5, + Status: swarm.TaskStatus{ + State: swarm.TaskStateFailed, + }, + }, + }, + isGlobalSVC: false, + expectedTasks: []string{ + "container.1", + "container.4", + }, + networks: map[string]*docker.NetworkResource{ + "1": { + Name: "foo", + }, + }, + }, + } + + for caseID, e := range cases { + e := e + t.Run(strconv.Itoa(caseID), func(t *testing.T) { + t.Parallel() + dockerData := parseService(e.service, e.networks) + dockerClient := &fakeTasksClient{tasks: e.tasks} + taskDockerData, _ := listTasks(context.Background(), dockerClient, e.service.ID, dockerData, map[string]*docker.NetworkResource{}, e.isGlobalSVC) + + if len(e.expectedTasks) != len(taskDockerData) { + t.Errorf("expected tasks %v, got %v", spew.Sdump(e.expectedTasks), spew.Sdump(taskDockerData)) + } + + for i, taskID := range e.expectedTasks { + if taskDockerData[i].Name != taskID { + t.Errorf("expect task id %v, got %v", taskID, taskDockerData[i].Name) + } + } + }) } } diff --git a/provider/dynamodb_test.go b/provider/dynamodb_test.go index 9a2995e31..fb9742b95 100644 --- a/provider/dynamodb_test.go +++ b/provider/dynamodb_test.go @@ -19,7 +19,7 @@ type mockDynamoDBCLient struct { var backend = &types.Backend{ HealthCheck: &types.HealthCheck{ - URL: "/build", + Path: "/build", }, Servers: map[string]types.Server{ "server1": { diff --git a/provider/ecs.go b/provider/ecs.go index a85c14c30..a8426b43d 100644 --- a/provider/ecs.go +++ b/provider/ecs.go @@ -206,13 +206,28 @@ func (provider *ECS) listInstances(ctx context.Context, client *awsClient) ([]ec taskArns = append(taskArns, req.Data.(*ecs.ListTasksOutput).TaskArns...) } - req, taskResp := client.ecs.DescribeTasksRequest(&ecs.DescribeTasksInput{ - Tasks: taskArns, - Cluster: &provider.Cluster, - }) + // Early return: if we can't list tasks we have nothing to + // describe below - likely empty cluster/permissions are bad. This + // stops the AWS API from returning a 401 when you DescribeTasks + // with no input. + if len(taskArns) == 0 { + return []ecsInstance{}, nil + } + + chunkedTaskArns := provider.chunkedTaskArns(taskArns) + var tasks []*ecs.Task + + for _, arns := range chunkedTaskArns { + req, taskResp := client.ecs.DescribeTasksRequest(&ecs.DescribeTasksInput{ + Tasks: arns, + Cluster: &provider.Cluster, + }) + + if err := wrapAws(ctx, req); err != nil { + return nil, err + } + tasks = append(tasks, taskResp.Tasks...) - if err := wrapAws(ctx, req); err != nil { - return nil, err } containerInstanceArns := make([]*string, 0) @@ -221,7 +236,7 @@ func (provider *ECS) listInstances(ctx context.Context, client *awsClient) ([]ec taskDefinitionArns := make([]*string, 0) byTaskDefinition := make(map[string]int) - for _, task := range taskResp.Tasks { + for _, task := range tasks { if _, found := byContainerInstance[*task.ContainerInstanceArn]; !found { byContainerInstance[*task.ContainerInstanceArn] = len(containerInstanceArns) containerInstanceArns = append(containerInstanceArns, task.ContainerInstanceArn) @@ -243,7 +258,7 @@ func (provider *ECS) listInstances(ctx context.Context, client *awsClient) ([]ec } var instances []ecsInstance - for _, task := range taskResp.Tasks { + for _, task := range tasks { machineIdx := byContainerInstance[*task.ContainerInstanceArn] taskDefIdx := byTaskDefinition[*task.TaskDefinitionArn] @@ -398,6 +413,22 @@ func (provider *ECS) getFrontendRule(i ecsInstance) string { return "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + provider.Domain } +// ECS expects no more than 100 parameters be passed to a DescribeTask call; thus, pack +// each string into an array capped at 100 elements +func (provider *ECS) chunkedTaskArns(tasks []*string) [][]*string { + var chunkedTasks [][]*string + for i := 0; i < len(tasks); i += 100 { + sliceEnd := -1 + if i+100 < len(tasks) { + sliceEnd = i + 100 + } else { + sliceEnd = len(tasks) + } + chunkedTasks = append(chunkedTasks, tasks[i:sliceEnd]) + } + return chunkedTasks +} + func (i ecsInstance) Protocol() string { if label := i.label("traefik.protocol"); label != "" { return label diff --git a/provider/ecs_test.go b/provider/ecs_test.go index 0365819b3..c7baaca1a 100644 --- a/provider/ecs_test.go +++ b/provider/ecs_test.go @@ -308,3 +308,42 @@ func TestFilterInstance(t *testing.T) { } } } + +func TestTaskChunking(t *testing.T) { + provider := &ECS{} + + testval := "a" + cases := []struct { + count int + expectedLengths []int + }{ + {0, []int(nil)}, + {1, []int{1}}, + {99, []int{99}}, + {100, []int{100}}, + {101, []int{100, 1}}, + {199, []int{100, 99}}, + {200, []int{100, 100}}, + {201, []int{100, 100, 1}}, + {555, []int{100, 100, 100, 100, 100, 55}}, + {1001, []int{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1}}, + } + + for _, c := range cases { + var tasks []*string + for v := 0; v < c.count; v++ { + tasks = append(tasks, &testval) + } + + out := provider.chunkedTaskArns(tasks) + var outCount []int + + for _, el := range out { + outCount = append(outCount, len(el)) + } + + if !reflect.DeepEqual(outCount, c.expectedLengths) { + t.Errorf("Chunking %d elements, expected %#v, got %#v", c.count, c.expectedLengths, outCount) + } + } +} diff --git a/provider/kubernetes.go b/provider/kubernetes.go index 3300d7105..18f89d6de 100644 --- a/provider/kubernetes.go +++ b/provider/kubernetes.go @@ -198,8 +198,13 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur } service, exists, err := k8sClient.GetService(i.ObjectMeta.Namespace, pa.Backend.ServiceName) - if err != nil || !exists { - log.Warnf("Error retrieving service %s/%s: %v", i.ObjectMeta.Namespace, pa.Backend.ServiceName, err) + if err != nil { + log.Errorf("Error while retrieving service information from k8s API %s/%s: %v", i.ObjectMeta.Namespace, pa.Backend.ServiceName, err) + return nil, err + } + + if !exists { + log.Errorf("Service not found for %s/%s", i.ObjectMeta.Namespace, pa.Backend.ServiceName) delete(templateObjects.Frontends, r.Host+pa.Path) continue } @@ -233,17 +238,17 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur } else { endpoints, exists, err := k8sClient.GetEndpoints(service.ObjectMeta.Namespace, service.ObjectMeta.Name) if err != nil { - log.Errorf("Error while retrieving endpoints from k8s API %s/%s: %v", service.ObjectMeta.Namespace, service.ObjectMeta.Name, err) - continue + log.Errorf("Error retrieving endpoints %s/%s: %v", service.ObjectMeta.Namespace, service.ObjectMeta.Name, err) + return nil, err } if !exists { - log.Errorf("Service not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) + log.Errorf("Endpoints not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) continue } if len(endpoints.Subsets) == 0 { - log.Warnf("Endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name) + log.Warnf("Service endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name) templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{ URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(int(port.Port)), Weight: 1, diff --git a/provider/kubernetes_test.go b/provider/kubernetes_test.go index 086322a0a..56fe63c5d 100644 --- a/provider/kubernetes_test.go +++ b/provider/kubernetes_test.go @@ -2,6 +2,7 @@ package provider import ( "encoding/json" + "errors" "fmt" "reflect" "strings" @@ -9,6 +10,7 @@ import ( "github.com/containous/traefik/provider/k8s" "github.com/containous/traefik/types" + "github.com/davecgh/go-spew/spew" "k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/pkg/apis/extensions/v1beta1" "k8s.io/client-go/pkg/util/intstr" @@ -1814,11 +1816,286 @@ func TestGetRuleTypeFromAnnotation(t *testing.T) { } } +func TestKubeAPIErrors(t *testing.T) { + ingresses := []*v1beta1.Ingress{{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "testing", + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "foo", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/bar", + Backend: v1beta1.IngressBackend{ + ServiceName: "service1", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }} + + services := []*v1.Service{{ + ObjectMeta: v1.ObjectMeta{ + Name: "service1", + UID: "1", + Namespace: "testing", + }, + Spec: v1.ServiceSpec{ + ClusterIP: "10.0.0.1", + Ports: []v1.ServicePort{ + { + Port: 80, + }, + }, + }, + }} + + endpoints := []*v1.Endpoints{} + watchChan := make(chan interface{}) + apiErr := errors.New("failed kube api call") + + testCases := []struct { + desc string + apiServiceErr error + apiEndpointsErr error + }{ + { + desc: "failed service call", + apiServiceErr: apiErr, + }, + { + desc: "failed endpoints call", + apiEndpointsErr: apiErr, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + client := clientMock{ + ingresses: ingresses, + services: services, + endpoints: endpoints, + watchChan: watchChan, + apiServiceError: tc.apiServiceErr, + apiEndpointsError: tc.apiEndpointsErr, + } + + provider := Kubernetes{} + if _, err := provider.loadIngresses(client); err != apiErr { + t.Errorf("Got error %v, wanted error %v", err, apiErr) + } + }) + } +} + +func TestMissingResources(t *testing.T) { + ingresses := []*v1beta1.Ingress{{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "testing", + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "fully_working", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Backend: v1beta1.IngressBackend{ + ServiceName: "fully_working_service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + { + Host: "missing_service", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Backend: v1beta1.IngressBackend{ + ServiceName: "missing_service_service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + { + Host: "missing_endpoints", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Backend: v1beta1.IngressBackend{ + ServiceName: "missing_endpoints_service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }} + services := []*v1.Service{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "fully_working_service", + UID: "1", + Namespace: "testing", + }, + Spec: v1.ServiceSpec{ + ClusterIP: "10.0.0.1", + Ports: []v1.ServicePort{ + { + Port: 80, + }, + }, + }, + }, + { + ObjectMeta: v1.ObjectMeta{ + Name: "missing_endpoints_service", + UID: "3", + Namespace: "testing", + }, + Spec: v1.ServiceSpec{ + ClusterIP: "10.0.0.3", + Ports: []v1.ServicePort{ + { + Port: 80, + }, + }, + }, + }, + } + endpoints := []*v1.Endpoints{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "fully_working_service", + UID: "1", + Namespace: "testing", + }, + Subsets: []v1.EndpointSubset{ + { + Addresses: []v1.EndpointAddress{ + { + IP: "10.10.0.1", + }, + }, + Ports: []v1.EndpointPort{ + { + Port: 8080, + }, + }, + }, + }, + }, + } + + watchChan := make(chan interface{}) + client := clientMock{ + ingresses: ingresses, + services: services, + endpoints: endpoints, + watchChan: watchChan, + + // TODO: Update all tests to cope with "properExists == true" correctly and remove flag. + // See https://github.com/containous/traefik/issues/1307 + properExists: true, + } + provider := Kubernetes{} + actual, err := provider.loadIngresses(client) + if err != nil { + t.Fatalf("error %+v", err) + } + + expected := &types.Configuration{ + Backends: map[string]*types.Backend{ + "fully_working": { + Servers: map[string]types.Server{ + "http://10.10.0.1:8080": { + URL: "http://10.10.0.1:8080", + Weight: 1, + }, + }, + CircuitBreaker: nil, + LoadBalancer: &types.LoadBalancer{ + Method: "wrr", + Sticky: false, + }, + }, + "missing_service": { + Servers: map[string]types.Server{}, + LoadBalancer: &types.LoadBalancer{ + Method: "wrr", + Sticky: false, + }, + }, + "missing_endpoints": { + Servers: map[string]types.Server{}, + CircuitBreaker: nil, + LoadBalancer: &types.LoadBalancer{ + Method: "wrr", + Sticky: false, + }, + }, + }, + Frontends: map[string]*types.Frontend{ + "fully_working": { + Backend: "fully_working", + PassHostHeader: true, + Routes: map[string]types.Route{ + "fully_working": { + Rule: "Host:fully_working", + }, + }, + }, + "missing_endpoints": { + Backend: "missing_endpoints", + PassHostHeader: true, + Routes: map[string]types.Route{ + "missing_endpoints": { + Rule: "Host:missing_endpoints", + }, + }, + }, + }, + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("expected\n%v\ngot\n\n%v", spew.Sdump(expected), spew.Sdump(actual)) + } +} + type clientMock struct { ingresses []*v1beta1.Ingress services []*v1.Service endpoints []*v1.Endpoints watchChan chan interface{} + + apiServiceError error + apiEndpointsError error + + properExists bool } func (c clientMock) GetIngresses(namespaces k8s.Namespaces) []*v1beta1.Ingress { @@ -1833,20 +2110,33 @@ func (c clientMock) GetIngresses(namespaces k8s.Namespaces) []*v1beta1.Ingress { } func (c clientMock) GetService(namespace, name string) (*v1.Service, bool, error) { + if c.apiServiceError != nil { + return nil, false, c.apiServiceError + } + for _, service := range c.services { if service.Namespace == namespace && service.Name == name { return service, true, nil } } - return &v1.Service{}, true, nil + return nil, false, nil } func (c clientMock) GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error) { + if c.apiEndpointsError != nil { + return nil, false, c.apiEndpointsError + } + for _, endpoints := range c.endpoints { if endpoints.Namespace == namespace && endpoints.Name == name { return endpoints, true, nil } } + + if c.properExists { + return nil, false, nil + } + return &v1.Endpoints{}, true, nil } diff --git a/provider/provider_test.go b/provider/provider_test.go index 2e25aba9e..79c757755 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -80,7 +80,7 @@ func TestConfigurationErrors(t *testing.T) { }, nil, }, - expectedError: "Near line 1 (last key parsed 'Hello'): Expected key separator '=', but got '<' instead", + expectedError: "Near line 1 (last key parsed 'Hello'): expected key separator '=', but got '<' instead", funcMap: template.FuncMap{ "Foo": func() string { return "bar" diff --git a/server.go b/server.go index a48ad9313..058066d01 100644 --- a/server.go +++ b/server.go @@ -667,7 +667,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo interval = time.Second * 30 } } - backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rebalancer) + backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.Path, interval, rebalancer) } } case types.Wrr: @@ -701,7 +701,7 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo interval = time.Second * 30 } } - backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rr) + backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.Path, interval, rr) } } maxConns := configuration.Backends[frontend.Backend].MaxConn diff --git a/traefik.go b/traefik.go index 5399b919e..fbe0f9f8d 100644 --- a/traefik.go +++ b/traefik.go @@ -261,7 +261,6 @@ func run(traefikConfiguration *TraefikConfiguration) { } }(t) } - log.Info(t.String()) server.Wait() log.Info("Shutting down") } diff --git a/traefik.sample.toml b/traefik.sample.toml index 8b125a7f6..e5e2d073b 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -58,11 +58,13 @@ # # ProvidersThrottleDuration = "5s" -# If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. -# If you encounter 'too many open files' errors, you can either change this value, or change `ulimit` value. +# Controls the maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost +# from the Go standard library net/http module is used. +# If you encounter 'too many open files' errors, you can either increase this +# value or change the `ulimit`. # # Optional -# Default: http.DefaultMaxIdleConnsPerHost +# Default: 200 # # MaxIdleConnsPerHost = 200 @@ -652,12 +654,14 @@ # Zookeeper timeout (in seconds) # # Optional +# Default: 30 # # ZkDetectionTimeout = 30 # Polling interval (in seconds) # # Optional +# Default: 30 # # RefreshSeconds = 30 @@ -670,8 +674,9 @@ # HTTP Timeout (in seconds) # # Optional +# Default: 30 # -# StateTimeoutSecond = "host" +# StateTimeoutSecond = "30" ################################################################ # Kubernetes Ingress configuration backend diff --git a/types/types.go b/types/types.go index 815409ef7..d62d77d92 100644 --- a/types/types.go +++ b/types/types.go @@ -39,7 +39,7 @@ type CircuitBreaker struct { // HealthCheck holds HealthCheck configuration type HealthCheck struct { - URL string `json:"url,omitempty"` + Path string `json:"path,omitempty"` Interval string `json:"interval,omitempty"` } diff --git a/vendor/github.com/ArthurHlt/go-eureka-client/LICENSE b/vendor/github.com/ArthurHlt/go-eureka-client/LICENSE new file mode 100644 index 000000000..7305f8fd0 --- /dev/null +++ b/vendor/github.com/ArthurHlt/go-eureka-client/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Arthur Halet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ArthurHlt/go-eureka-client/eureka/get.go b/vendor/github.com/ArthurHlt/go-eureka-client/eureka/get.go index c4d69cd33..a27deb9e5 100644 --- a/vendor/github.com/ArthurHlt/go-eureka-client/eureka/get.go +++ b/vendor/github.com/ArthurHlt/go-eureka-client/eureka/get.go @@ -1,11 +1,12 @@ package eureka + import ( "encoding/xml" "strings" ) func (c *Client) GetApplications() (*Applications, error) { - response, err := c.Get("apps"); + response, err := c.Get("apps") if err != nil { return nil, err } @@ -17,7 +18,7 @@ func (c *Client) GetApplications() (*Applications, error) { func (c *Client) GetApplication(appId string) (*Application, error) { values := []string{"apps", appId} path := strings.Join(values, "/") - response, err := c.Get(path); + response, err := c.Get(path) if err != nil { return nil, err } @@ -25,14 +26,39 @@ func (c *Client) GetApplication(appId string) (*Application, error) { err = xml.Unmarshal(response.Body, application) return application, err } + func (c *Client) GetInstance(appId, instanceId string) (*InstanceInfo, error) { values := []string{"apps", appId, instanceId} path := strings.Join(values, "/") - response, err := c.Get(path); + response, err := c.Get(path) if err != nil { return nil, err } var instance *InstanceInfo = new(InstanceInfo) err = xml.Unmarshal(response.Body, instance) return instance, err -} \ No newline at end of file +} + +func (c *Client) GetVIP(vipId string) (*Applications, error) { + values := []string{"vips", vipId} + path := strings.Join(values, "/") + response, err := c.Get(path) + if err != nil { + return nil, err + } + var applications *Applications = new(Applications) + err = xml.Unmarshal(response.Body, applications) + return applications, err +} + +func (c *Client) GetSVIP(svipId string) (*Applications, error) { + values := []string{"svips", svipId} + path := strings.Join(values, "/") + response, err := c.Get(path) + if err != nil { + return nil, err + } + var applications *Applications = new(Applications) + err = xml.Unmarshal(response.Body, applications) + return applications, err +} diff --git a/vendor/github.com/ArthurHlt/go-eureka-client/eureka/requests.go b/vendor/github.com/ArthurHlt/go-eureka-client/eureka/requests.go index 4e913085d..467b65ff8 100644 --- a/vendor/github.com/ArthurHlt/go-eureka-client/eureka/requests.go +++ b/vendor/github.com/ArthurHlt/go-eureka-client/eureka/requests.go @@ -67,7 +67,7 @@ type InstanceInfo struct { type DataCenterInfo struct { Name string `xml:"name" json:"name"` Class string `xml:"class,attr" json:"@class"` - Metadata DataCenterMetadata `xml:"metadata,omitempty" json:"metadata,omitempty"` + Metadata *DataCenterMetadata `xml:"metadata,omitempty" json:"metadata,omitempty"` } type DataCenterMetadata struct { @@ -106,6 +106,8 @@ func NewRawRequest(method, relativePath string, body []byte, cancel <-chan bool) func NewInstanceInfo(hostName, app, ip string, port int, ttl uint, isSsl bool) *InstanceInfo { dataCenterInfo := &DataCenterInfo{ Name: "MyOwn", + Class: "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", + Metadata: nil, } leaseInfo := &LeaseInfo{ EvictionDurationInSecs: ttl, diff --git a/vendor/github.com/ArthurHlt/gominlog/gominlog.go b/vendor/github.com/ArthurHlt/gominlog/gominlog.go index f5ae2c114..b4d39067e 100644 --- a/vendor/github.com/ArthurHlt/gominlog/gominlog.go +++ b/vendor/github.com/ArthurHlt/gominlog/gominlog.go @@ -1,26 +1,26 @@ package gominlog import ( - "fmt" - "github.com/daviddengcn/go-colortext" - "io" "log" "os" - "regexp" + "fmt" "runtime" + "github.com/fatih/color" + "regexp" "strings" + "io" ) type Level int const ( - Loff = Level(^uint(0) >> 1) - Lsevere = Level(1000) - Lerror = Level(900) + Loff = Level(^uint(0) >> 1) + Lsevere = Level(1000) + Lerror = Level(900) Lwarning = Level(800) - Linfo = Level(700) - Ldebug = Level(600) - Lall = Level(-Loff - 1) + Linfo = Level(700) + Ldebug = Level(600) + Lall = Level(-Loff - 1) ) type MinLog struct { @@ -54,6 +54,14 @@ func NewMinLog(appName string, level Level, withColor bool, flag int) *MinLog { minLog.level = level return minLog } +func NewMinLogWithWriter(appName string, level Level, withColor bool, flag int, logWriter io.Writer) *MinLog { + minLog := &MinLog{} + minLog.log = log.New(logWriter, "", flag) + minLog.isColorized = withColor + minLog.packageName = appName + minLog.level = level + return minLog +} func NewMinLogWithLogger(packageName string, level Level, withColor bool, logger *log.Logger) *MinLog { minLog := &MinLog{} minLog.log = logger @@ -89,10 +97,11 @@ func (this *MinLog) IsColorized() bool { return this.isColorized } func (this *MinLog) GetLogger() *log.Logger { + return this.log } -func (this *MinLog) logMessage(typeLog string, colorFg ct.Color, colorBg ct.Color, args ...interface{}) { +func (this *MinLog) logMessage(typeLog string, colorFg color.Attribute, colorBg color.Attribute, args ...interface{}) { var text string msg := "" flags := this.log.Flags() @@ -100,7 +109,7 @@ func (this *MinLog) logMessage(typeLog string, colorFg ct.Color, colorBg ct.Colo msg += this.trace() this.log.SetFlags(flags - log.Lshortfile) } - text, ok := args[0].(string) + text, ok := args[0].(string); if !ok { panic("Firt argument should be a string") } @@ -113,51 +122,47 @@ func (this *MinLog) logMessage(typeLog string, colorFg ct.Color, colorBg ct.Colo this.writeMsgInLogger(msg, colorFg, colorBg) this.log.SetFlags(flags) } -func (this *MinLog) writeMsgInLogger(msg string, colorFg ct.Color, colorBg ct.Color) { - if this.isColorized && colorFg > 0 { - ct.Foreground(colorFg, false) - } - if this.isColorized && colorBg > 0 { - ct.ChangeColor(colorFg, false, colorBg, false) +func (this *MinLog) writeMsgInLogger(msg string, colorFg color.Attribute, colorBg color.Attribute) { + if this.isColorized && int(colorBg) == 0 { + msg = color.New(colorFg).Sprint(msg) + } else if this.isColorized { + msg = color.New(colorFg, colorBg).Sprint(msg) } this.log.Print(msg) - if this.isColorized { - ct.ResetColor() - } } func (this *MinLog) Error(args ...interface{}) { if this.level > Lerror { return } - this.logMessage("ERROR", ct.Red, 0, args...) + this.logMessage("ERROR", color.FgRed, 0, args...) } func (this *MinLog) Severe(args ...interface{}) { if this.level > Lsevere { return } - this.logMessage("SEVERE", ct.Red, ct.Yellow, args...) + this.logMessage("SEVERE", color.FgRed, color.BgYellow, args...) } func (this *MinLog) Debug(args ...interface{}) { if this.level > Ldebug { return } - this.logMessage("DEBUG", ct.Blue, 0, args...) + this.logMessage("DEBUG", color.FgBlue, 0, args...) } func (this *MinLog) Info(args ...interface{}) { if this.level > Linfo { return } - this.logMessage("INFO", ct.Cyan, 0, args...) + this.logMessage("INFO", color.FgCyan, 0, args...) } func (this *MinLog) Warning(args ...interface{}) { if this.level > Lwarning { return } - this.logMessage("WARNING", ct.Yellow, 0, args...) + this.logMessage("WARNING", color.FgYellow, 0, args...) } func (this *MinLog) trace() string { var shortFile string @@ -167,7 +172,7 @@ func (this *MinLog) trace() string { file, line := f.FileLine(pc[2]) if this.packageName == "" { execFileSplit := strings.Split(os.Args[0], "/") - this.packageName = execFileSplit[len(execFileSplit)-1] + this.packageName = execFileSplit[len(execFileSplit) - 1] } regex, err := regexp.Compile(regexp.QuoteMeta(this.packageName) + "/(.*)") if err != nil { @@ -176,10 +181,10 @@ func (this *MinLog) trace() string { subMatch := regex.FindStringSubmatch(file) if len(subMatch) < 2 { fileSplit := strings.Split(file, "/") - shortFile = fileSplit[len(fileSplit)-1] + shortFile = fileSplit[len(fileSplit) - 1] } else { shortFile = subMatch[1] } return fmt.Sprintf("/%s/%s:%d ", this.packageName, shortFile, line) -} +} \ No newline at end of file diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go index fe2680004..b371f396e 100644 --- a/vendor/github.com/BurntSushi/toml/doc.go +++ b/vendor/github.com/BurntSushi/toml/doc.go @@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with the Primitive type, and querying the set of keys in a TOML document with the MetaData type. -The specification implemented: https://github.com/mojombo/toml +The specification implemented: https://github.com/toml-lang/toml The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify whether a file is a valid TOML document. It can also be used to print the diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go index 0f2558b2e..d905c21a2 100644 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { func (enc *Encoder) eTable(key Key, rv reflect.Value) { panicIfInvalidKey(key) if len(key) == 1 { - // Output an extra new line between top-level tables. + // Output an extra newline between top-level tables. // (The newline isn't written if nothing else has been written though.) enc.newline() } diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go index 104ebda21..6dee7fc79 100644 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -30,24 +30,28 @@ const ( itemArrayTableEnd itemKeyStart itemCommentStart + itemInlineTableStart + itemInlineTableEnd ) const ( - eof = 0 - tableStart = '[' - tableEnd = ']' - arrayTableStart = '[' - arrayTableEnd = ']' - tableSep = '.' - keySep = '=' - arrayStart = '[' - arrayEnd = ']' - arrayValTerm = ',' - commentStart = '#' - stringStart = '"' - stringEnd = '"' - rawStringStart = '\'' - rawStringEnd = '\'' + eof = 0 + comma = ',' + tableStart = '[' + tableEnd = ']' + arrayTableStart = '[' + arrayTableEnd = ']' + tableSep = '.' + keySep = '=' + arrayStart = '[' + arrayEnd = ']' + commentStart = '#' + stringStart = '"' + stringEnd = '"' + rawStringStart = '\'' + rawStringEnd = '\'' + inlineTableStart = '{' + inlineTableEnd = '}' ) type stateFn func(lx *lexer) stateFn @@ -56,11 +60,18 @@ type lexer struct { input string start int pos int - width int line int state stateFn items chan item + // Allow for backing up up to three runes. + // This is necessary because TOML contains 3-rune tokens (""" and '''). + prevWidths [3]int + nprev int // how many of prevWidths are in use + // If we emit an eof, we can still back up, but it is not OK to call + // next again. + atEOF bool + // A stack of state functions used to maintain context. // The idea is to reuse parts of the state machine in various places. // For example, values can appear at the top level or within arbitrarily @@ -88,7 +99,7 @@ func (lx *lexer) nextItem() item { func lex(input string) *lexer { lx := &lexer{ - input: input + "\n", + input: input, state: lexTop, line: 1, items: make(chan item, 10), @@ -103,7 +114,7 @@ func (lx *lexer) push(state stateFn) { func (lx *lexer) pop() stateFn { if len(lx.stack) == 0 { - return lx.errorf("BUG in lexer: no states to pop.") + return lx.errorf("BUG in lexer: no states to pop") } last := lx.stack[len(lx.stack)-1] lx.stack = lx.stack[0 : len(lx.stack)-1] @@ -125,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) { } func (lx *lexer) next() (r rune) { + if lx.atEOF { + panic("next called after EOF") + } if lx.pos >= len(lx.input) { - lx.width = 0 + lx.atEOF = true return eof } if lx.input[lx.pos] == '\n' { lx.line++ } - r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:]) - lx.pos += lx.width + lx.prevWidths[2] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[0] + if lx.nprev < 3 { + lx.nprev++ + } + r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) + lx.prevWidths[0] = w + lx.pos += w return r } @@ -143,9 +163,20 @@ func (lx *lexer) ignore() { lx.start = lx.pos } -// backup steps back one rune. Can be called only once per call of next. +// backup steps back one rune. Can be called only twice between calls to next. func (lx *lexer) backup() { - lx.pos -= lx.width + if lx.atEOF { + lx.atEOF = false + return + } + if lx.nprev < 1 { + panic("backed up too far") + } + w := lx.prevWidths[0] + lx.prevWidths[0] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[2] + lx.nprev-- + lx.pos -= w if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { lx.line-- } @@ -182,7 +213,7 @@ func (lx *lexer) skip(pred func(rune) bool) { // errorf stops all lexing by emitting an error and returning `nil`. // Note that any value that is a character is escaped if it's a special -// character (new lines, tabs, etc.). +// character (newlines, tabs, etc.). func (lx *lexer) errorf(format string, values ...interface{}) stateFn { lx.items <- item{ itemError, @@ -198,7 +229,6 @@ func lexTop(lx *lexer) stateFn { if isWhitespace(r) || isNL(r) { return lexSkip(lx, lexTop) } - switch r { case commentStart: lx.push(lexTop) @@ -207,7 +237,7 @@ func lexTop(lx *lexer) stateFn { return lexTableStart case eof: if lx.pos > lx.start { - return lx.errorf("Unexpected EOF.") + return lx.errorf("unexpected EOF") } lx.emit(itemEOF) return nil @@ -222,12 +252,12 @@ func lexTop(lx *lexer) stateFn { // lexTopEnd is entered whenever a top-level item has been consumed. (A value // or a table.) It must see only whitespace, and will turn back to lexTop -// upon a new line. If it sees EOF, it will quit the lexer successfully. +// upon a newline. If it sees EOF, it will quit the lexer successfully. func lexTopEnd(lx *lexer) stateFn { r := lx.next() switch { case r == commentStart: - // a comment will read to a new line for us. + // a comment will read to a newline for us. lx.push(lexTop) return lexCommentStart case isWhitespace(r): @@ -236,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn { lx.ignore() return lexTop case r == eof: - lx.ignore() - return lexTop + lx.emit(itemEOF) + return nil } - return lx.errorf("Expected a top-level item to end with a new line, "+ - "comment or EOF, but got %q instead.", r) + return lx.errorf("expected a top-level item to end with a newline, "+ + "comment, or EOF, but got %q instead", r) } // lexTable lexes the beginning of a table. Namely, it makes sure that @@ -267,8 +297,8 @@ func lexTableEnd(lx *lexer) stateFn { func lexArrayTableEnd(lx *lexer) stateFn { if r := lx.next(); r != arrayTableEnd { - return lx.errorf("Expected end of table array name delimiter %q, "+ - "but got %q instead.", arrayTableEnd, r) + return lx.errorf("expected end of table array name delimiter %q, "+ + "but got %q instead", arrayTableEnd, r) } lx.emit(itemArrayTableEnd) return lexTopEnd @@ -278,11 +308,11 @@ func lexTableNameStart(lx *lexer) stateFn { lx.skip(isWhitespace) switch r := lx.peek(); { case r == tableEnd || r == eof: - return lx.errorf("Unexpected end of table name. (Table names cannot " + - "be empty.)") + return lx.errorf("unexpected end of table name " + + "(table names cannot be empty)") case r == tableSep: - return lx.errorf("Unexpected table separator. (Table names cannot " + - "be empty.)") + return lx.errorf("unexpected table separator " + + "(table names cannot be empty)") case r == stringStart || r == rawStringStart: lx.ignore() lx.push(lexTableNameEnd) @@ -317,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn { case r == tableEnd: return lx.pop() default: - return lx.errorf("Expected '.' or ']' to end table name, but got %q "+ - "instead.", r) + return lx.errorf("expected '.' or ']' to end table name, "+ + "but got %q instead", r) } } @@ -328,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn { r := lx.peek() switch { case r == keySep: - return lx.errorf("Unexpected key separator %q.", keySep) + return lx.errorf("unexpected key separator %q", keySep) case isWhitespace(r) || isNL(r): lx.next() return lexSkip(lx, lexKeyStart) @@ -359,7 +389,7 @@ func lexBareKey(lx *lexer) stateFn { lx.emit(itemText) return lexKeyEnd default: - return lx.errorf("Bare keys cannot contain %q.", r) + return lx.errorf("bare keys cannot contain %q", r) } } @@ -372,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexKeyEnd) default: - return lx.errorf("Expected key separator %q, but got %q instead.", + return lx.errorf("expected key separator %q, but got %q instead", keySep, r) } } @@ -381,9 +411,8 @@ func lexKeyEnd(lx *lexer) stateFn { // lexValue will ignore whitespace. // After a value is lexed, the last state on the next is popped and returned. func lexValue(lx *lexer) stateFn { - // We allow whitespace to precede a value, but NOT new lines. - // In array syntax, the array states are responsible for ignoring new - // lines. + // We allow whitespace to precede a value, but NOT newlines. + // In array syntax, the array states are responsible for ignoring newlines. r := lx.next() switch { case isWhitespace(r): @@ -397,6 +426,10 @@ func lexValue(lx *lexer) stateFn { lx.ignore() lx.emit(itemArray) return lexArrayValue + case inlineTableStart: + lx.ignore() + lx.emit(itemInlineTableStart) + return lexInlineTableValue case stringStart: if lx.accept(stringStart) { if lx.accept(stringStart) { @@ -420,7 +453,7 @@ func lexValue(lx *lexer) stateFn { case '+', '-': return lexNumberStart case '.': // special error case, be kind to users - return lx.errorf("Floats must start with a digit, not '.'.") + return lx.errorf("floats must start with a digit, not '.'") } if unicode.IsLetter(r) { // Be permissive here; lexBool will give a nice error if the @@ -430,11 +463,11 @@ func lexValue(lx *lexer) stateFn { lx.backup() return lexBool } - return lx.errorf("Expected value but found %q instead.", r) + return lx.errorf("expected value but found %q instead", r) } // lexArrayValue consumes one value in an array. It assumes that '[' or ',' -// have already been consumed. All whitespace and new lines are ignored. +// have already been consumed. All whitespace and newlines are ignored. func lexArrayValue(lx *lexer) stateFn { r := lx.next() switch { @@ -443,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn { case r == commentStart: lx.push(lexArrayValue) return lexCommentStart - case r == arrayValTerm: - return lx.errorf("Unexpected array value terminator %q.", - arrayValTerm) + case r == comma: + return lx.errorf("unexpected comma") case r == arrayEnd: + // NOTE(caleb): The spec isn't clear about whether you can have + // a trailing comma or not, so we'll allow it. return lexArrayEnd } @@ -455,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn { return lexValue } -// lexArrayValueEnd consumes the cruft between values of an array. Namely, -// it ignores whitespace and expects either a ',' or a ']'. +// lexArrayValueEnd consumes everything between the end of an array value and +// the next value (or the end of the array): it ignores whitespace and newlines +// and expects either a ',' or a ']'. func lexArrayValueEnd(lx *lexer) stateFn { r := lx.next() switch { @@ -465,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn { case r == commentStart: lx.push(lexArrayValueEnd) return lexCommentStart - case r == arrayValTerm: + case r == comma: lx.ignore() return lexArrayValue // move on to the next value case r == arrayEnd: return lexArrayEnd } - return lx.errorf("Expected an array value terminator %q or an array "+ - "terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r) + return lx.errorf( + "expected a comma or array terminator %q, but got %q instead", + arrayEnd, r, + ) } -// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has -// just been consumed. +// lexArrayEnd finishes the lexing of an array. +// It assumes that a ']' has just been consumed. func lexArrayEnd(lx *lexer) stateFn { lx.ignore() lx.emit(itemArrayEnd) return lx.pop() } +// lexInlineTableValue consumes one key/value pair in an inline table. +// It assumes that '{' or ',' have already been consumed. Whitespace is ignored. +func lexInlineTableValue(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValue) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValue) + return lexCommentStart + case r == comma: + return lx.errorf("unexpected comma") + case r == inlineTableEnd: + return lexInlineTableEnd + } + lx.backup() + lx.push(lexInlineTableValueEnd) + return lexKeyStart +} + +// lexInlineTableValueEnd consumes everything between the end of an inline table +// key/value pair and the next pair (or the end of the table): +// it ignores whitespace and expects either a ',' or a '}'. +func lexInlineTableValueEnd(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValueEnd) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValueEnd) + return lexCommentStart + case r == comma: + lx.ignore() + return lexInlineTableValue + case r == inlineTableEnd: + return lexInlineTableEnd + } + return lx.errorf("expected a comma or an inline table terminator %q, "+ + "but got %q instead", inlineTableEnd, r) +} + +// lexInlineTableEnd finishes the lexing of an inline table. +// It assumes that a '}' has just been consumed. +func lexInlineTableEnd(lx *lexer) stateFn { + lx.ignore() + lx.emit(itemInlineTableEnd) + return lx.pop() +} + // lexString consumes the inner contents of a string. It assumes that the // beginning '"' has already been consumed and ignored. func lexString(lx *lexer) stateFn { r := lx.next() switch { + case r == eof: + return lx.errorf("unexpected EOF") case isNL(r): - return lx.errorf("Strings cannot contain new lines.") + return lx.errorf("strings cannot contain newlines") case r == '\\': lx.push(lexString) return lexStringEscape @@ -506,11 +598,12 @@ func lexString(lx *lexer) stateFn { // lexMultilineString consumes the inner contents of a string. It assumes that // the beginning '"""' has already been consumed and ignored. func lexMultilineString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == '\\': + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case '\\': return lexMultilineStringEscape - case r == stringEnd: + case stringEnd: if lx.accept(stringEnd) { if lx.accept(stringEnd) { lx.backup() @@ -534,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn { func lexRawString(lx *lexer) stateFn { r := lx.next() switch { + case r == eof: + return lx.errorf("unexpected EOF") case isNL(r): - return lx.errorf("Strings cannot contain new lines.") + return lx.errorf("strings cannot contain newlines") case r == rawStringEnd: lx.backup() lx.emit(itemRawString) @@ -547,12 +642,13 @@ func lexRawString(lx *lexer) stateFn { } // lexMultilineRawString consumes a raw string. Nothing can be escaped in such -// a string. It assumes that the beginning "'" has already been consumed and +// a string. It assumes that the beginning "'''" has already been consumed and // ignored. func lexMultilineRawString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == rawStringEnd: + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case rawStringEnd: if lx.accept(rawStringEnd) { if lx.accept(rawStringEnd) { lx.backup() @@ -605,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn { case 'U': return lexLongUnicodeEscape } - return lx.errorf("Invalid escape character %q. Only the following "+ + return lx.errorf("invalid escape character %q; only the following "+ "escape characters are allowed: "+ - "\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+ - "\\uXXXX and \\UXXXXXXXX.", r) + `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r) } func lexShortUnicodeEscape(lx *lexer) stateFn { @@ -616,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn { for i := 0; i < 4; i++ { r = lx.next() if !isHexadecimal(r) { - return lx.errorf("Expected four hexadecimal digits after '\\u', "+ - "but got '%s' instead.", lx.current()) + return lx.errorf(`expected four hexadecimal digits after '\u', `+ + "but got %q instead", lx.current()) } } return lx.pop() @@ -628,8 +723,8 @@ func lexLongUnicodeEscape(lx *lexer) stateFn { for i := 0; i < 8; i++ { r = lx.next() if !isHexadecimal(r) { - return lx.errorf("Expected eight hexadecimal digits after '\\U', "+ - "but got '%s' instead.", lx.current()) + return lx.errorf(`expected eight hexadecimal digits after '\U', `+ + "but got %q instead", lx.current()) } } return lx.pop() @@ -647,9 +742,9 @@ func lexNumberOrDateStart(lx *lexer) stateFn { case 'e', 'E': return lexFloat case '.': - return lx.errorf("Floats must start with a digit, not '.'.") + return lx.errorf("floats must start with a digit, not '.'") } - return lx.errorf("Expected a digit but got %q.", r) + return lx.errorf("expected a digit but got %q", r) } // lexNumberOrDate consumes either an integer, float or datetime. @@ -697,9 +792,9 @@ func lexNumberStart(lx *lexer) stateFn { r := lx.next() if !isDigit(r) { if r == '.' { - return lx.errorf("Floats must start with a digit, not '.'.") + return lx.errorf("floats must start with a digit, not '.'") } - return lx.errorf("Expected a digit but got %q.", r) + return lx.errorf("expected a digit but got %q", r) } return lexNumber } @@ -745,7 +840,7 @@ func lexBool(lx *lexer) stateFn { var rs []rune for { r := lx.next() - if r == eof || isWhitespace(r) || isNL(r) { + if !unicode.IsLetter(r) { lx.backup() break } @@ -757,7 +852,7 @@ func lexBool(lx *lexer) stateFn { lx.emit(itemBool) return lx.pop() } - return lx.errorf("Expected value but found %q instead.", s) + return lx.errorf("expected value but found %q instead", s) } // lexCommentStart begins the lexing of a comment. It will emit @@ -769,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn { } // lexComment lexes an entire comment. It assumes that '#' has been consumed. -// It will consume *up to* the first new line character, and pass control +// It will consume *up to* the first newline character, and pass control // back to the last state on the stack. func lexComment(lx *lexer) stateFn { r := lx.peek() diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go index a5625555c..50869ef92 100644 --- a/vendor/github.com/BurntSushi/toml/parse.go +++ b/vendor/github.com/BurntSushi/toml/parse.go @@ -269,6 +269,41 @@ func (p *parser) value(it item) (interface{}, tomlType) { types = append(types, typ) } return array, p.typeOfArray(types) + case itemInlineTableStart: + var ( + hash = make(map[string]interface{}) + outerContext = p.context + outerKey = p.currentKey + ) + + p.context = append(p.context, p.currentKey) + p.currentKey = "" + for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() { + if it.typ != itemKeyStart { + p.bug("Expected key start but instead found %q, around line %d", + it.val, p.approxLine) + } + if it.typ == itemCommentStart { + p.expect(itemText) + continue + } + + // retrieve key + k := p.next() + p.approxLine = k.line + kname := p.keyString(k) + + // retrieve value + p.currentKey = kname + val, typ := p.value(p.next()) + // make sure we keep metadata up to date + p.setType(kname, typ) + p.ordered = append(p.ordered, p.context.add(p.currentKey)) + hash[kname] = val + } + p.context = outerContext + p.currentKey = outerKey + return hash, tomlHash } p.bug("Unexpected value type: %s", it.typ) panic("unreachable") diff --git a/vendor/github.com/JamesClonk/vultr/lib/applications.go b/vendor/github.com/JamesClonk/vultr/lib/applications.go new file mode 100644 index 000000000..f44d8c81e --- /dev/null +++ b/vendor/github.com/JamesClonk/vultr/lib/applications.go @@ -0,0 +1,38 @@ +package lib + +import ( + "sort" + "strings" +) + +// Application on Vultr +type Application struct { + ID string `json:"APPID"` + Name string `json:"name"` + ShortName string `json:"short_name"` + DeployName string `json:"deploy_name"` + Surcharge float64 `json:"surcharge"` +} + +type applications []Application + +func (s applications) Len() int { return len(s) } +func (s applications) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s applications) Less(i, j int) bool { + return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) +} + +// GetApplications returns a list of all available applications on Vultr +func (c *Client) GetApplications() ([]Application, error) { + var appMap map[string]Application + if err := c.get(`app/list`, &appMap); err != nil { + return nil, err + } + + var appList []Application + for _, app := range appMap { + appList = append(appList, app) + } + sort.Sort(applications(appList)) + return appList, nil +} diff --git a/vendor/github.com/JamesClonk/vultr/lib/block_storage.go b/vendor/github.com/JamesClonk/vultr/lib/block_storage.go index 58d4c37d1..e9e8e115d 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/block_storage.go +++ b/vendor/github.com/JamesClonk/vultr/lib/block_storage.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" "net/url" + "sort" "strconv" + "strings" ) // BlockStorage on Vultr account @@ -19,6 +21,25 @@ type BlockStorage struct { AttachedTo string `json:"attached_to_SUBID"` } +type blockstorages []BlockStorage + +func (b blockstorages) Len() int { return len(b) } +func (b blockstorages) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b blockstorages) Less(i, j int) bool { + // sort order: name, size, status + if strings.ToLower(b[i].Name) < strings.ToLower(b[j].Name) { + return true + } else if strings.ToLower(b[i].Name) > strings.ToLower(b[j].Name) { + return false + } + if b[i].SizeGB < b[j].SizeGB { + return true + } else if b[i].SizeGB > b[j].SizeGB { + return false + } + return b[i].Status < b[j].Status +} + // UnmarshalJSON implements json.Unmarshaller on BlockStorage. // This is needed because the Vultr API is inconsistent in it's JSON responses. // Some fields can change type, from JSON number to JSON string and vice-versa. @@ -87,6 +108,7 @@ func (c *Client) GetBlockStorages() (storages []BlockStorage, err error) { if err := c.get(`block/list`, &storages); err != nil { return nil, err } + sort.Sort(blockstorages(storages)) return storages, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/client.go b/vendor/github.com/JamesClonk/vultr/lib/client.go index 7e2364b3c..61df58e08 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/client.go +++ b/vendor/github.com/JamesClonk/vultr/lib/client.go @@ -18,7 +18,7 @@ import ( const ( // Version of this libary - Version = "1.12.0" + Version = "1.13.0" // APIVersion of Vultr APIVersion = "v1" diff --git a/vendor/github.com/JamesClonk/vultr/lib/dns.go b/vendor/github.com/JamesClonk/vultr/lib/dns.go index beb68c18a..77a86166f 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/dns.go +++ b/vendor/github.com/JamesClonk/vultr/lib/dns.go @@ -3,6 +3,8 @@ package lib import ( "fmt" "net/url" + "sort" + "strings" ) // DNSDomain represents a DNS domain on Vultr @@ -11,6 +13,14 @@ type DNSDomain struct { Created string `json:"date_created"` } +type dnsdomains []DNSDomain + +func (d dnsdomains) Len() int { return len(d) } +func (d dnsdomains) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d dnsdomains) Less(i, j int) bool { + return strings.ToLower(d[i].Domain) < strings.ToLower(d[j].Domain) +} + // DNSRecord represents a DNS record on Vultr type DNSRecord struct { RecordID int `json:"RECORDID"` @@ -21,20 +31,41 @@ type DNSRecord struct { TTL int `json:"ttl"` } +type dnsrecords []DNSRecord + +func (d dnsrecords) Len() int { return len(d) } +func (d dnsrecords) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d dnsrecords) Less(i, j int) bool { + // sort order: type, data, name + if d[i].Type < d[j].Type { + return true + } else if d[i].Type > d[j].Type { + return false + } + if d[i].Data < d[j].Data { + return true + } else if d[i].Data > d[j].Data { + return false + } + return strings.ToLower(d[i].Name) < strings.ToLower(d[j].Name) +} + // GetDNSDomains returns a list of available domains on Vultr account -func (c *Client) GetDNSDomains() (dnsdomains []DNSDomain, err error) { - if err := c.get(`dns/list`, &dnsdomains); err != nil { +func (c *Client) GetDNSDomains() (domains []DNSDomain, err error) { + if err := c.get(`dns/list`, &domains); err != nil { return nil, err } - return dnsdomains, nil + sort.Sort(dnsdomains(domains)) + return domains, nil } // GetDNSRecords returns a list of all DNS records of a particular domain -func (c *Client) GetDNSRecords(domain string) (dnsrecords []DNSRecord, err error) { - if err := c.get(`dns/records?domain=`+domain, &dnsrecords); err != nil { +func (c *Client) GetDNSRecords(domain string) (records []DNSRecord, err error) { + if err := c.get(`dns/records?domain=`+domain, &records); err != nil { return nil, err } - return dnsrecords, nil + sort.Sort(dnsrecords(records)) + return records, nil } // CreateDNSDomain creates a new DNS domain name on Vultr diff --git a/vendor/github.com/JamesClonk/vultr/lib/ip.go b/vendor/github.com/JamesClonk/vultr/lib/ip.go index 26d078785..de21b1fed 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/ip.go +++ b/vendor/github.com/JamesClonk/vultr/lib/ip.go @@ -1,6 +1,9 @@ package lib -import "net/url" +import ( + "net/url" + "sort" +) // IPv4 information of a virtual machine type IPv4 struct { @@ -11,6 +14,20 @@ type IPv4 struct { ReverseDNS string `json:"reverse"` } +type ipv4s []IPv4 + +func (s ipv4s) Len() int { return len(s) } +func (s ipv4s) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s ipv4s) Less(i, j int) bool { + // sort order: type, ip + if s[i].Type < s[j].Type { + return true + } else if s[i].Type > s[j].Type { + return false + } + return s[i].IP < s[j].IP +} + // IPv6 information of a virtual machine type IPv6 struct { IP string `json:"ip"` @@ -19,12 +36,32 @@ type IPv6 struct { Type string `json:"type"` } +type ipv6s []IPv6 + +func (s ipv6s) Len() int { return len(s) } +func (s ipv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s ipv6s) Less(i, j int) bool { + // sort order: type, ip + if s[i].Type < s[j].Type { + return true + } else if s[i].Type > s[j].Type { + return false + } + return s[i].IP < s[j].IP +} + // ReverseDNSIPv6 information of a virtual machine type ReverseDNSIPv6 struct { IP string `json:"ip"` ReverseDNS string `json:"reverse"` } +type reverseDNSIPv6s []ReverseDNSIPv6 + +func (s reverseDNSIPv6s) Len() int { return len(s) } +func (s reverseDNSIPv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s reverseDNSIPv6s) Less(i, j int) bool { return s[i].IP < s[j].IP } + // ListIPv4 lists the IPv4 information of a virtual machine func (c *Client) ListIPv4(id string) (list []IPv4, err error) { var ipMap map[string][]IPv4 @@ -37,6 +74,7 @@ func (c *Client) ListIPv4(id string) (list []IPv4, err error) { list = append(list, ip) } } + sort.Sort(ipv4s(list)) return list, nil } @@ -52,6 +90,7 @@ func (c *Client) ListIPv6(id string) (list []IPv6, err error) { list = append(list, ip) } } + sort.Sort(ipv6s(list)) return list, nil } @@ -67,6 +106,7 @@ func (c *Client) ListIPv6ReverseDNS(id string) (list []ReverseDNSIPv6, err error list = append(list, ip) } } + sort.Sort(reverseDNSIPv6s(list)) return list, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/iso.go b/vendor/github.com/JamesClonk/vultr/lib/iso.go index a975577a1..a9e1880e4 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/iso.go +++ b/vendor/github.com/JamesClonk/vultr/lib/iso.go @@ -1,5 +1,10 @@ package lib +import ( + "sort" + "strings" +) + // ISO image on Vultr type ISO struct { ID int `json:"ISOID"` @@ -9,6 +14,20 @@ type ISO struct { MD5sum string `json:"md5sum"` } +type isos []ISO + +func (s isos) Len() int { return len(s) } +func (s isos) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s isos) Less(i, j int) bool { + // sort order: filename, created + if strings.ToLower(s[i].Filename) < strings.ToLower(s[j].Filename) { + return true + } else if strings.ToLower(s[i].Filename) > strings.ToLower(s[j].Filename) { + return false + } + return s[i].Created < s[j].Created +} + // GetISO returns a list of all ISO images on Vultr account func (c *Client) GetISO() ([]ISO, error) { var isoMap map[string]ISO @@ -20,5 +39,6 @@ func (c *Client) GetISO() ([]ISO, error) { for _, iso := range isoMap { isoList = append(isoList, iso) } + sort.Sort(isos(isoList)) return isoList, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/os.go b/vendor/github.com/JamesClonk/vultr/lib/os.go index f8a93a476..647d253f8 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/os.go +++ b/vendor/github.com/JamesClonk/vultr/lib/os.go @@ -1,5 +1,10 @@ package lib +import ( + "sort" + "strings" +) + // OS image on Vultr type OS struct { ID int `json:"OSID"` @@ -10,6 +15,12 @@ type OS struct { Surcharge string `json:"surcharge"` } +type oses []OS + +func (s oses) Len() int { return len(s) } +func (s oses) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s oses) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) } + // GetOS returns a list of all available operating systems on Vultr func (c *Client) GetOS() ([]OS, error) { var osMap map[string]OS @@ -21,5 +32,6 @@ func (c *Client) GetOS() ([]OS, error) { for _, os := range osMap { osList = append(osList, os) } + sort.Sort(oses(osList)) return osList, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/plans.go b/vendor/github.com/JamesClonk/vultr/lib/plans.go index 4e6f7eb2f..b3bef4eff 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/plans.go +++ b/vendor/github.com/JamesClonk/vultr/lib/plans.go @@ -1,6 +1,11 @@ package lib -import "fmt" +import ( + "fmt" + "sort" + "strconv" + "strings" +) // Plan on Vultr type Plan struct { @@ -14,6 +19,40 @@ type Plan struct { Regions []int `json:"available_locations"` } +type plans []Plan + +func (p plans) Len() int { return len(p) } +func (p plans) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p plans) Less(i, j int) bool { + pa, _ := strconv.ParseFloat(strings.TrimSpace(p[i].Price), 64) + pb, _ := strconv.ParseFloat(strings.TrimSpace(p[j].Price), 64) + ra, _ := strconv.ParseInt(strings.TrimSpace(p[i].RAM), 10, 64) + rb, _ := strconv.ParseInt(strings.TrimSpace(p[j].RAM), 10, 64) + da, _ := strconv.ParseInt(strings.TrimSpace(p[i].Disk), 10, 64) + db, _ := strconv.ParseInt(strings.TrimSpace(p[j].Disk), 10, 64) + + // sort order: price, vcpu, ram, disk + if pa < pb { + return true + } else if pa > pb { + return false + } + + if p[i].VCpus < p[j].VCpus { + return true + } else if p[i].VCpus > p[j].VCpus { + return false + } + + if ra < rb { + return true + } else if ra > rb { + return false + } + + return da < db +} + // GetPlans returns a list of all available plans on Vultr account func (c *Client) GetPlans() ([]Plan, error) { var planMap map[string]Plan @@ -21,11 +60,13 @@ func (c *Client) GetPlans() ([]Plan, error) { return nil, err } - var planList []Plan + var p plans for _, plan := range planMap { - planList = append(planList, plan) + p = append(p, plan) } - return planList, nil + + sort.Sort(plans(p)) + return p, nil } // GetAvailablePlansForRegion returns available plans for specified region diff --git a/vendor/github.com/JamesClonk/vultr/lib/regions.go b/vendor/github.com/JamesClonk/vultr/lib/regions.go index 0e4ed8e92..70ceb2ede 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/regions.go +++ b/vendor/github.com/JamesClonk/vultr/lib/regions.go @@ -1,5 +1,7 @@ package lib +import "sort" + // Region on Vultr type Region struct { ID int `json:"DCID,string"` @@ -12,6 +14,20 @@ type Region struct { Code string `json:"regioncode"` } +type regions []Region + +func (s regions) Len() int { return len(s) } +func (s regions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s regions) Less(i, j int) bool { + // sort order: continent, name + if s[i].Continent < s[j].Continent { + return true + } else if s[i].Continent > s[j].Continent { + return false + } + return s[i].Name < s[j].Name +} + // GetRegions returns a list of all available Vultr regions func (c *Client) GetRegions() ([]Region, error) { var regionMap map[string]Region @@ -23,5 +39,6 @@ func (c *Client) GetRegions() ([]Region, error) { for _, os := range regionMap { regionList = append(regionList, os) } + sort.Sort(regions(regionList)) return regionList, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/reservedip.go b/vendor/github.com/JamesClonk/vultr/lib/reservedip.go index 7132375e3..22097cf7d 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/reservedip.go +++ b/vendor/github.com/JamesClonk/vultr/lib/reservedip.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" "net/url" + "sort" "strconv" + "strings" ) // IP on Vultr @@ -18,6 +20,25 @@ type IP struct { AttachedTo string `json:"attached_SUBID,string"` } +type ips []IP + +func (s ips) Len() int { return len(s) } +func (s ips) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s ips) Less(i, j int) bool { + // sort order: label, iptype, subnet + if strings.ToLower(s[i].Label) < strings.ToLower(s[j].Label) { + return true + } else if strings.ToLower(s[i].Label) > strings.ToLower(s[j].Label) { + return false + } + if s[i].IPType < s[j].IPType { + return true + } else if s[i].IPType > s[j].IPType { + return false + } + return s[i].Subnet < s[j].Subnet +} + // UnmarshalJSON implements json.Unmarshaller on IP. // This is needed because the Vultr API is inconsistent in it's JSON responses. // Some fields can change type, from JSON number to JSON string and vice-versa. @@ -89,11 +110,12 @@ func (c *Client) ListReservedIP() ([]IP, error) { return nil, err } - ips := make([]IP, 0) + ipList := make([]IP, 0) for _, ip := range ipMap { - ips = append(ips, ip) + ipList = append(ipList, ip) } - return ips, nil + sort.Sort(ips(ipList)) + return ipList, nil } // GetReservedIP returns reserved IP with given ID diff --git a/vendor/github.com/JamesClonk/vultr/lib/scripts.go b/vendor/github.com/JamesClonk/vultr/lib/scripts.go index 24c89fbcb..d6639cf1e 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/scripts.go +++ b/vendor/github.com/JamesClonk/vultr/lib/scripts.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" "net/url" + "sort" + "strings" ) // StartupScript on Vultr account @@ -14,6 +16,14 @@ type StartupScript struct { Content string `json:"script"` } +type startupscripts []StartupScript + +func (s startupscripts) Len() int { return len(s) } +func (s startupscripts) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s startupscripts) Less(i, j int) bool { + return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) +} + // UnmarshalJSON implements json.Unmarshaller on StartupScript. // Necessary because the SCRIPTID field has inconsistent types. func (s *StartupScript) UnmarshalJSON(data []byte) (err error) { @@ -47,6 +57,7 @@ func (c *Client) GetStartupScripts() (scripts []StartupScript, err error) { } scripts = append(scripts, script) } + sort.Sort(startupscripts(scripts)) return scripts, nil } diff --git a/vendor/github.com/JamesClonk/vultr/lib/servers.go b/vendor/github.com/JamesClonk/vultr/lib/servers.go index 9d1e5d31e..862b441a6 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/servers.go +++ b/vendor/github.com/JamesClonk/vultr/lib/servers.go @@ -5,7 +5,9 @@ import ( "encoding/json" "fmt" "net/url" + "sort" "strconv" + "strings" ) // Server (virtual machine) on Vultr account @@ -36,6 +38,8 @@ type Server struct { KVMUrl string `json:"kvm_url"` AutoBackups string `json:"auto_backups"` Tag string `json:"tag"` + OSID string `json:"OSID"` + AppID string `json:"APPID"` } // ServerOptions are optional parameters to be used during server creation @@ -52,6 +56,21 @@ type ServerOptions struct { DontNotifyOnActivate bool Hostname string Tag string + AppID string +} + +type servers []Server + +func (s servers) Len() int { return len(s) } +func (s servers) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s servers) Less(i, j int) bool { + // sort order: name, ip + if strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) { + return true + } else if strings.ToLower(s[i].Name) > strings.ToLower(s[j].Name) { + return false + } + return s[i].MainIP < s[j].MainIP } // V6Network represents a IPv6 network of a Vultr server @@ -140,6 +159,18 @@ func (s *Server) UnmarshalJSON(data []byte) (err error) { } s.AllowedBandwidth = ab + value = fmt.Sprintf("%v", fields["OSID"]) + if value == "" { + value = "" + } + s.OSID = value + + value = fmt.Sprintf("%v", fields["APPID"]) + if value == "" { + value = "" + } + s.AppID = value + s.ID = fmt.Sprintf("%v", fields["SUBID"]) s.Name = fmt.Sprintf("%v", fields["label"]) s.OS = fmt.Sprintf("%v", fields["os"]) @@ -180,29 +211,31 @@ func (s *Server) UnmarshalJSON(data []byte) (err error) { } // GetServers returns a list of current virtual machines on Vultr account -func (c *Client) GetServers() (servers []Server, err error) { +func (c *Client) GetServers() (serverList []Server, err error) { var serverMap map[string]Server if err := c.get(`server/list`, &serverMap); err != nil { return nil, err } for _, server := range serverMap { - servers = append(servers, server) + serverList = append(serverList, server) } - return servers, nil + sort.Sort(servers(serverList)) + return serverList, nil } // GetServersByTag returns a list of all virtual machines matching by tag -func (c *Client) GetServersByTag(tag string) (servers []Server, err error) { +func (c *Client) GetServersByTag(tag string) (serverList []Server, err error) { var serverMap map[string]Server if err := c.get(`server/list?tag=`+tag, &serverMap); err != nil { return nil, err } for _, server := range serverMap { - servers = append(servers, server) + serverList = append(serverList, server) } - return servers, nil + sort.Sort(servers(serverList)) + return serverList, nil } // GetServer returns the virtual machine with the given ID @@ -274,6 +307,10 @@ func (c *Client) CreateServer(name string, regionID, planID, osID int, options * if options.Tag != "" { values.Add("tag", options.Tag) } + + if options.AppID != "" { + values.Add("APPID", options.AppID) + } } var server Server @@ -371,6 +408,7 @@ func (c *Client) ListOSforServer(id string) (os []OS, err error) { for _, o := range osMap { os = append(os, o) } + sort.Sort(oses(os)) return os, nil } @@ -446,3 +484,30 @@ func (c *Client) BandwidthOfServer(id string) (bandwidth []map[string]string, er return bandwidth, nil } + +// ChangeApplicationofServer changes the virtual machine to a different application +func (c *Client) ChangeApplicationofServer(id string, appID string) error { + values := url.Values{ + "SUBID": {id}, + "APPID": {appID}, + } + + if err := c.post(`server/app_change`, values, nil); err != nil { + return err + } + return nil +} + +// ListApplicationsforServer lists all available operating systems to which an existing virtual machine can be changed +func (c *Client) ListApplicationsforServer(id string) (apps []Application, err error) { + var appMap map[string]Application + if err := c.get(`server/app_change_list?SUBID=`+id, &appMap); err != nil { + return nil, err + } + + for _, app := range appMap { + apps = append(apps, app) + } + sort.Sort(applications(apps)) + return apps, nil +} diff --git a/vendor/github.com/JamesClonk/vultr/lib/snapshots.go b/vendor/github.com/JamesClonk/vultr/lib/snapshots.go index e95cdbf58..7e9969306 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/snapshots.go +++ b/vendor/github.com/JamesClonk/vultr/lib/snapshots.go @@ -1,6 +1,10 @@ package lib -import "net/url" +import ( + "net/url" + "sort" + "strings" +) // Snapshot of a virtual machine on Vultr account type Snapshot struct { @@ -11,17 +15,32 @@ type Snapshot struct { Created string `json:"date_created"` } +type snapshots []Snapshot + +func (s snapshots) Len() int { return len(s) } +func (s snapshots) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s snapshots) Less(i, j int) bool { + // sort order: description, created + if strings.ToLower(s[i].Description) < strings.ToLower(s[j].Description) { + return true + } else if strings.ToLower(s[i].Description) > strings.ToLower(s[j].Description) { + return false + } + return s[i].Created < s[j].Created +} + // GetSnapshots retrieves a list of all snapshots on Vultr account -func (c *Client) GetSnapshots() (snapshots []Snapshot, err error) { +func (c *Client) GetSnapshots() (snapshotList []Snapshot, err error) { var snapshotMap map[string]Snapshot if err := c.get(`snapshot/list`, &snapshotMap); err != nil { return nil, err } for _, snapshot := range snapshotMap { - snapshots = append(snapshots, snapshot) + snapshotList = append(snapshotList, snapshot) } - return snapshots, nil + sort.Sort(snapshots(snapshotList)) + return snapshotList, nil } // CreateSnapshot creates a new virtual machine snapshot diff --git a/vendor/github.com/JamesClonk/vultr/lib/sshkeys.go b/vendor/github.com/JamesClonk/vultr/lib/sshkeys.go index 309c0897a..006e16f2d 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/sshkeys.go +++ b/vendor/github.com/JamesClonk/vultr/lib/sshkeys.go @@ -1,6 +1,10 @@ package lib -import "net/url" +import ( + "net/url" + "sort" + "strings" +) // SSHKey on Vultr account type SSHKey struct { @@ -10,6 +14,12 @@ type SSHKey struct { Created string `json:"date_created"` } +type sshkeys []SSHKey + +func (s sshkeys) Len() int { return len(s) } +func (s sshkeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s sshkeys) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) } + // GetSSHKeys returns a list of SSHKeys from Vultr account func (c *Client) GetSSHKeys() (keys []SSHKey, err error) { var keyMap map[string]SSHKey @@ -20,6 +30,7 @@ func (c *Client) GetSSHKeys() (keys []SSHKey, err error) { for _, key := range keyMap { keys = append(keys, key) } + sort.Sort(sshkeys(keys)) return keys, nil } diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go index 08d9ac9d5..ceedee1f4 100644 --- a/vendor/github.com/Microsoft/go-winio/backup.go +++ b/vendor/github.com/Microsoft/go-winio/backup.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go index fd16f0075..8c15e4124 100644 --- a/vendor/github.com/Microsoft/go-winio/file.go +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go index d5acb72d5..a822e4314 100644 --- a/vendor/github.com/Microsoft/go-winio/fileinfo.go +++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go index 82db28306..b85b2eef4 100644 --- a/vendor/github.com/Microsoft/go-winio/pipe.go +++ b/vendor/github.com/Microsoft/go-winio/pipe.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go index 3d59412c7..9c83d36fe 100644 --- a/vendor/github.com/Microsoft/go-winio/privilege.go +++ b/vendor/github.com/Microsoft/go-winio/privilege.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( @@ -83,7 +85,7 @@ func RunWithPrivileges(names []string, fn func() error) error { return err } defer releaseThreadToken(token) - err = adjustPrivileges(token, privileges) + err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) if err != nil { return err } @@ -110,6 +112,15 @@ func mapPrivileges(names []string) ([]uint64, error) { // EnableProcessPrivileges enables privileges globally for the process. func EnableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) +} + +// DisableProcessPrivileges disables privileges globally for the process. +func DisableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, 0) +} + +func enableDisableProcessPrivilege(names []string, action uint32) error { privileges, err := mapPrivileges(names) if err != nil { return err @@ -123,15 +134,15 @@ func EnableProcessPrivileges(names []string) error { } defer token.Close() - return adjustPrivileges(token, privileges) + return adjustPrivileges(token, privileges, action) } -func adjustPrivileges(token windows.Token, privileges []uint64) error { +func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { var b bytes.Buffer binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) for _, p := range privileges { binary.Write(&b, binary.LittleEndian, p) - binary.Write(&b, binary.LittleEndian, uint32(SE_PRIVILEGE_ENABLED)) + binary.Write(&b, binary.LittleEndian, action) } prevState := make([]byte, b.Len()) reqSize := uint32(0) diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go index 60ab56ce7..db1b370a1 100644 --- a/vendor/github.com/Microsoft/go-winio/sd.go +++ b/vendor/github.com/Microsoft/go-winio/sd.go @@ -1,3 +1,5 @@ +// +build windows + package winio import ( diff --git a/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/go-winio/syscall.go index 96fdff7b4..20d64cf41 100644 --- a/vendor/github.com/Microsoft/go-winio/syscall.go +++ b/vendor/github.com/Microsoft/go-winio/syscall.go @@ -1,3 +1,3 @@ package winio -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go similarity index 99% rename from vendor/github.com/Microsoft/go-winio/zsyscall.go rename to vendor/github.com/Microsoft/go-winio/zsyscall_windows.go index 6d047d369..c5e369bae 100644 --- a/vendor/github.com/Microsoft/go-winio/zsyscall.go +++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -12,9 +12,9 @@ import ( var _ unsafe.Pointer var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - modwinmm = syscall.NewLazyDLL("winmm.dll") - modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modwinmm = windows.NewLazySystemDLL("winmm.dll") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") diff --git a/vendor/github.com/NYTimes/gziphandler/gzip.go b/vendor/github.com/NYTimes/gziphandler/gzip.go index fbc99396d..cccf79de7 100644 --- a/vendor/github.com/NYTimes/gziphandler/gzip.go +++ b/vendor/github.com/NYTimes/gziphandler/gzip.go @@ -4,6 +4,7 @@ import ( "bufio" "compress/gzip" "fmt" + "io" "net" "net/http" "strconv" @@ -21,10 +22,16 @@ const ( type codings map[string]float64 -// The default qvalue to assign to an encoding if no explicit qvalue is set. -// This is actually kind of ambiguous in RFC 2616, so hopefully it's correct. -// The examples seem to indicate that it is. -const DEFAULT_QVALUE = 1.0 +const ( + // DefaultQValue is the default qvalue to assign to an encoding if no explicit qvalue is set. + // This is actually kind of ambiguous in RFC 2616, so hopefully it's correct. + // The examples seem to indicate that it is. + DefaultQValue = 1.0 + + // DefaultMinSize defines the minimum size to reach to enable compression. + // It's 512 bytes. + DefaultMinSize = 512 +) // gzipWriterPools stores a sync.Pool for each compression level for reuse of // gzip.Writers. Use poolIndex to covert a compression level to an index into @@ -63,35 +70,88 @@ func addLevelPool(level int) { // GzipResponseWriter provides an http.ResponseWriter interface, which gzips // bytes before writing them to the underlying response. This doesn't close the // writers, so don't forget to do that. +// It can be configured to skip response smaller than minSize. type GzipResponseWriter struct { http.ResponseWriter index int // Index for gzipWriterPools. gw *gzip.Writer + + code int // Saves the WriteHeader value. + + minSize int // Specifed the minimum response size to gzip. If the response length is bigger than this value, it is compressed. + buf []byte // Holds the first part of the write before reaching the minSize or the end of the write. } // Write appends data to the gzip writer. func (w *GzipResponseWriter) Write(b []byte) (int, error) { - // Lazily create the gzip.Writer, this allows empty bodies to be actually - // empty, for example in the case of status code 204 (no content). - if w.gw == nil { - w.init() - } - + // If content type is not set. if _, ok := w.Header()[contentType]; !ok { - // If content type is not set, infer it from the uncompressed body. + // It infer it from the uncompressed body. w.Header().Set(contentType, http.DetectContentType(b)) } - return w.gw.Write(b) + + // GZIP responseWriter is initialized. Use the GZIP responseWriter. + if w.gw != nil { + n, err := w.gw.Write(b) + return n, err + } + + // Save the write into a buffer for later use in GZIP responseWriter (if content is long enough) or at close with regular responseWriter. + w.buf = append(w.buf, b...) + + // If the global writes are bigger than the minSize, compression is enable. + if len(w.buf) >= w.minSize { + err := w.startGzip() + if err != nil { + return 0, err + } + } + + return len(b), nil } -// WriteHeader will check if the gzip writer needs to be lazily initiated and -// then pass the code along to the underlying ResponseWriter. -func (w *GzipResponseWriter) WriteHeader(code int) { - if w.gw == nil && - code != http.StatusNotModified && code != http.StatusNoContent { - w.init() +// startGzip initialize any GZIP specific informations. +func (w *GzipResponseWriter) startGzip() error { + + // Set the GZIP header. + w.Header().Set(contentEncoding, "gzip") + + // if the Content-Length is already set, then calls to Write on gzip + // will fail to set the Content-Length header since its already set + // See: https://github.com/golang/go/issues/14975. + w.Header().Del(contentLength) + + // Write the header to gzip response. + w.writeHeader() + + // Initialize the GZIP response. + w.init() + + // Flush the buffer into the gzip reponse. + n, err := w.gw.Write(w.buf) + + // This should never happen (per io.Writer docs), but if the write didn't + // accept the entire buffer but returned no specific error, we have no clue + // what's going on, so abort just to be safe. + if err == nil && n < len(w.buf) { + return io.ErrShortWrite } - w.ResponseWriter.WriteHeader(code) + + w.buf = nil + return err +} + +// WriteHeader just saves the response code until close or GZIP effective writes. +func (w *GzipResponseWriter) WriteHeader(code int) { + w.code = code +} + +// writeHeader uses the saved code to send it to the ResponseWriter. +func (w *GzipResponseWriter) writeHeader() { + if w.code == 0 { + w.code = http.StatusOK + } + w.ResponseWriter.WriteHeader(w.code) } // init graps a new gzip writer from the gzipWriterPool and writes the correct @@ -102,21 +162,29 @@ func (w *GzipResponseWriter) init() { gzw := gzipWriterPools[w.index].Get().(*gzip.Writer) gzw.Reset(w.ResponseWriter) w.gw = gzw - w.ResponseWriter.Header().Set(contentEncoding, "gzip") - // if the Content-Length is already set, then calls to Write on gzip - // will fail to set the Content-Length header since its already set - // See: https://github.com/golang/go/issues/14975 - w.ResponseWriter.Header().Del(contentLength) } // Close will close the gzip.Writer and will put it back in the gzipWriterPool. func (w *GzipResponseWriter) Close() error { + // Buffer not nil means the regular response must be returned. + if w.buf != nil { + w.writeHeader() + // Make the write into the regular response. + _, writeErr := w.ResponseWriter.Write(w.buf) + // Returns the error if any at write. + if writeErr != nil { + return fmt.Errorf("gziphandler: write to regular responseWriter at close gets error: %q", writeErr.Error()) + } + } + + // If the GZIP responseWriter is not set no needs to close it. if w.gw == nil { return nil } err := w.gw.Close() gzipWriterPools[w.index].Put(w.gw) + w.gw = nil return err } @@ -162,9 +230,18 @@ func MustNewGzipLevelHandler(level int) func(http.Handler) http.Handler { // if an invalid gzip compression level is given, so if one can ensure the level // is valid, the returned error can be safely ignored. func NewGzipLevelHandler(level int) (func(http.Handler) http.Handler, error) { + return NewGzipLevelAndMinSize(level, DefaultMinSize) +} + +// NewGzipLevelAndMinSize behave as NewGzipLevelHandler except it let the caller +// specify the minimum size before compression. +func NewGzipLevelAndMinSize(level, minSize int) (func(http.Handler) http.Handler, error) { if level != gzip.DefaultCompression && (level < gzip.BestSpeed || level > gzip.BestCompression) { return nil, fmt.Errorf("invalid compression level requested: %d", level) } + if minSize < 0 { + return nil, fmt.Errorf("minimum size must be more than zero") + } return func(h http.Handler) http.Handler { index := poolIndex(level) @@ -175,6 +252,9 @@ func NewGzipLevelHandler(level int) (func(http.Handler) http.Handler, error) { gw := &GzipResponseWriter{ ResponseWriter: w, index: index, + minSize: minSize, + + buf: []byte{}, } defer gw.Close() @@ -237,7 +317,7 @@ func parseEncodings(s string) (codings, error) { func parseCoding(s string) (coding string, qvalue float64, err error) { for n, part := range strings.Split(s, ";") { part = strings.TrimSpace(part) - qvalue = DEFAULT_QVALUE + qvalue = DefaultQValue if n == 0 { coding = strings.ToLower(part) diff --git a/vendor/github.com/NYTimes/gziphandler/gzip_go18.go b/vendor/github.com/NYTimes/gziphandler/gzip_go18.go new file mode 100644 index 000000000..fa9665b7e --- /dev/null +++ b/vendor/github.com/NYTimes/gziphandler/gzip_go18.go @@ -0,0 +1,43 @@ +// +build go1.8 + +package gziphandler + +import "net/http" + +// Push initiates an HTTP/2 server push. +// Push returns ErrNotSupported if the client has disabled push or if push +// is not supported on the underlying connection. +func (w *GzipResponseWriter) Push(target string, opts *http.PushOptions) error { + pusher, ok := w.ResponseWriter.(http.Pusher) + if ok && pusher != nil { + return pusher.Push(target, setAcceptEncodingForPushOptions(opts)) + } + return http.ErrNotSupported +} + +// setAcceptEncodingForPushOptions sets "Accept-Encoding" : "gzip" for PushOptions without overriding existing headers. +func setAcceptEncodingForPushOptions(opts *http.PushOptions) *http.PushOptions { + + if opts == nil { + opts = &http.PushOptions{ + Header: http.Header{ + acceptEncoding: []string{"gzip"}, + }, + } + return opts + } + + if opts.Header == nil { + opts.Header = http.Header{ + acceptEncoding: []string{"gzip"}, + } + return opts + } + + if encoding := opts.Header.Get(acceptEncoding); encoding == "" { + opts.Header.Add(acceptEncoding, "gzip") + return opts + } + + return opts +} diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit.go b/vendor/github.com/Sirupsen/logrus/alt_exit.go index b4c9e8475..8af90637a 100644 --- a/vendor/github.com/Sirupsen/logrus/alt_exit.go +++ b/vendor/github.com/Sirupsen/logrus/alt_exit.go @@ -1,7 +1,7 @@ package logrus // The following code was sourced and modified from the -// https://bitbucket.org/tebeka/atexit package governed by the following license: +// https://github.com/tebeka/atexit package governed by the following license: // // Copyright (c) 2012 Miki Tebeka . // diff --git a/vendor/github.com/Sirupsen/logrus/entry.go b/vendor/github.com/Sirupsen/logrus/entry.go index 54bfc57d7..4edbe7a2d 100644 --- a/vendor/github.com/Sirupsen/logrus/entry.go +++ b/vendor/github.com/Sirupsen/logrus/entry.go @@ -3,11 +3,21 @@ package logrus import ( "bytes" "fmt" - "io" "os" + "sync" "time" ) +var bufferPool *sync.Pool + +func init() { + bufferPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } +} + // Defines the key when adding errors using WithError. var ErrorKey = "error" @@ -29,6 +39,9 @@ type Entry struct { // Message passed to Debug, Info, Warn, Error, Fatal or Panic Message string + + // When formatter is called in entry.log(), an Buffer may be set to entry + Buffer *bytes.Buffer } func NewEntry(logger *Logger) *Entry { @@ -39,21 +52,15 @@ func NewEntry(logger *Logger) *Entry { } } -// Returns a reader for the entry, which is a proxy to the formatter. -func (entry *Entry) Reader() (*bytes.Buffer, error) { - serialized, err := entry.Logger.Formatter.Format(entry) - return bytes.NewBuffer(serialized), err -} - // Returns the string representation from the reader and ultimately the // formatter. func (entry *Entry) String() (string, error) { - reader, err := entry.Reader() + serialized, err := entry.Logger.Formatter.Format(entry) if err != nil { return "", err } - - return reader.String(), err + str := string(serialized) + return str, nil } // Add an error as single field (using the key defined in ErrorKey) to the Entry. @@ -81,6 +88,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry { // This function is not declared with a pointer value because otherwise // race conditions will occur when using multiple goroutines func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer entry.Time = time.Now() entry.Level = level entry.Message = msg @@ -90,20 +98,23 @@ func (entry Entry) log(level Level, msg string) { fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) entry.Logger.mu.Unlock() } - - reader, err := entry.Reader() + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + serialized, err := entry.Logger.Formatter.Format(&entry) + entry.Buffer = nil if err != nil { entry.Logger.mu.Lock() fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) entry.Logger.mu.Unlock() - } - - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - - _, err = io.Copy(entry.Logger.Out, reader) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } else { + entry.Logger.mu.Lock() + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + entry.Logger.mu.Unlock() } // To avoid Entry#log() returning a value that only would make sense for diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/Sirupsen/logrus/json_formatter.go index 2ad6dc5cf..266554e9f 100644 --- a/vendor/github.com/Sirupsen/logrus/json_formatter.go +++ b/vendor/github.com/Sirupsen/logrus/json_formatter.go @@ -5,9 +5,40 @@ import ( "fmt" ) +type fieldKey string +type FieldMap map[fieldKey]string + +const ( + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" +) + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // FieldMap allows users to customize the names of keys for various fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyLevel: "@message", + // }, + // } + FieldMap FieldMap } func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { @@ -29,9 +60,11 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat = DefaultTimestampFormat } - data["time"] = entry.Time.Format(timestampFormat) - data["msg"] = entry.Message - data["level"] = entry.Level.String() + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() serialized, err := json.Marshal(data) if err != nil { diff --git a/vendor/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/Sirupsen/logrus/logger.go index 9052a8065..b769f3d35 100644 --- a/vendor/github.com/Sirupsen/logrus/logger.go +++ b/vendor/github.com/Sirupsen/logrus/logger.go @@ -26,8 +26,31 @@ type Logger struct { // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be // logged. `logrus.Debug` is useful in Level Level - // Used to sync writing to the log. - mu sync.Mutex + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool +} + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true } // Creates a new logger. Configuration should be set by changing `Formatter`, @@ -51,162 +74,235 @@ func New() *Logger { } } +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + logger.entryPool.Put(entry) +} + // Adds a field to the log entry, note that it doesn't log until you call // Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. // If you want multiple fields, use `WithFields`. func (logger *Logger) WithField(key string, value interface{}) *Entry { - return NewEntry(logger).WithField(key, value) + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) } // Adds a struct of fields to the log entry. All it does is call `WithField` for // each `Field`. func (logger *Logger) WithFields(fields Fields) *Entry { - return NewEntry(logger).WithFields(fields) + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) } // Add an error as single field to the log entry. All it does is call // `WithError` for the given `error`. func (logger *Logger) WithError(err error) *Entry { - return NewEntry(logger).WithError(err) + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) } func (logger *Logger) Debugf(format string, args ...interface{}) { if logger.Level >= DebugLevel { - NewEntry(logger).Debugf(format, args...) + entry := logger.newEntry() + entry.Debugf(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Infof(format string, args ...interface{}) { if logger.Level >= InfoLevel { - NewEntry(logger).Infof(format, args...) + entry := logger.newEntry() + entry.Infof(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Printf(format string, args ...interface{}) { - NewEntry(logger).Printf(format, args...) + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) } func (logger *Logger) Warnf(format string, args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warnf(format, args...) + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Warningf(format string, args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warnf(format, args...) + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Errorf(format string, args ...interface{}) { if logger.Level >= ErrorLevel { - NewEntry(logger).Errorf(format, args...) + entry := logger.newEntry() + entry.Errorf(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Fatalf(format string, args ...interface{}) { if logger.Level >= FatalLevel { - NewEntry(logger).Fatalf(format, args...) + entry := logger.newEntry() + entry.Fatalf(format, args...) + logger.releaseEntry(entry) } Exit(1) } func (logger *Logger) Panicf(format string, args ...interface{}) { if logger.Level >= PanicLevel { - NewEntry(logger).Panicf(format, args...) + entry := logger.newEntry() + entry.Panicf(format, args...) + logger.releaseEntry(entry) } } func (logger *Logger) Debug(args ...interface{}) { if logger.Level >= DebugLevel { - NewEntry(logger).Debug(args...) + entry := logger.newEntry() + entry.Debug(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Info(args ...interface{}) { if logger.Level >= InfoLevel { - NewEntry(logger).Info(args...) + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Print(args ...interface{}) { - NewEntry(logger).Info(args...) + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) } func (logger *Logger) Warn(args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warn(args...) + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Warning(args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warn(args...) + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Error(args ...interface{}) { if logger.Level >= ErrorLevel { - NewEntry(logger).Error(args...) + entry := logger.newEntry() + entry.Error(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Fatal(args ...interface{}) { if logger.Level >= FatalLevel { - NewEntry(logger).Fatal(args...) + entry := logger.newEntry() + entry.Fatal(args...) + logger.releaseEntry(entry) } Exit(1) } func (logger *Logger) Panic(args ...interface{}) { if logger.Level >= PanicLevel { - NewEntry(logger).Panic(args...) + entry := logger.newEntry() + entry.Panic(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Debugln(args ...interface{}) { if logger.Level >= DebugLevel { - NewEntry(logger).Debugln(args...) + entry := logger.newEntry() + entry.Debugln(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Infoln(args ...interface{}) { if logger.Level >= InfoLevel { - NewEntry(logger).Infoln(args...) + entry := logger.newEntry() + entry.Infoln(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Println(args ...interface{}) { - NewEntry(logger).Println(args...) + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) } func (logger *Logger) Warnln(args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warnln(args...) + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Warningln(args ...interface{}) { if logger.Level >= WarnLevel { - NewEntry(logger).Warnln(args...) + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Errorln(args ...interface{}) { if logger.Level >= ErrorLevel { - NewEntry(logger).Errorln(args...) + entry := logger.newEntry() + entry.Errorln(args...) + logger.releaseEntry(entry) } } func (logger *Logger) Fatalln(args ...interface{}) { if logger.Level >= FatalLevel { - NewEntry(logger).Fatalln(args...) + entry := logger.newEntry() + entry.Fatalln(args...) + logger.releaseEntry(entry) } Exit(1) } func (logger *Logger) Panicln(args ...interface{}) { if logger.Level >= PanicLevel { - NewEntry(logger).Panicln(args...) + entry := logger.newEntry() + entry.Panicln(args...) + logger.releaseEntry(entry) } } + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_appengine.go b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go new file mode 100644 index 000000000..e011a8694 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go @@ -0,0 +1,10 @@ +// +build appengine + +package logrus + +import "io" + +// IsTerminal returns true if stderr's file descriptor is a terminal. +func IsTerminal(f io.Writer) bool { + return true +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go index 71f8d67a5..5f6be4d3c 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go +++ b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go @@ -1,4 +1,5 @@ // +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine package logrus diff --git a/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/Sirupsen/logrus/terminal_linux.go index a2c0b40db..308160ca8 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_linux.go +++ b/vendor/github.com/Sirupsen/logrus/terminal_linux.go @@ -3,6 +3,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !appengine + package logrus import "syscall" diff --git a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go index b343b3a37..190297abf 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go +++ b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go @@ -4,18 +4,25 @@ // license that can be found in the LICENSE file. // +build linux darwin freebsd openbsd netbsd dragonfly +// +build !appengine package logrus import ( + "io" + "os" "syscall" "unsafe" ) // IsTerminal returns true if stderr's file descriptor is a terminal. -func IsTerminal() bool { - fd := syscall.Stderr +func IsTerminal(f io.Writer) bool { var termios Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 + switch v := f.(type) { + case *os.File: + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 + default: + return false + } } diff --git a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go index 3e70bf7bf..3c86b1abe 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go +++ b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go @@ -1,15 +1,21 @@ -// +build solaris +// +build solaris,!appengine package logrus import ( + "io" "os" "golang.org/x/sys/unix" ) // IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal() bool { - _, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA) - return err == nil +func IsTerminal(f io.Writer) bool { + switch v := f.(type) { + case *os.File: + _, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA) + return err == nil + default: + return false + } } diff --git a/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/Sirupsen/logrus/terminal_windows.go index 0146845d1..05d2f91f1 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_windows.go +++ b/vendor/github.com/Sirupsen/logrus/terminal_windows.go @@ -3,11 +3,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build windows +// +build windows,!appengine package logrus import ( + "io" + "os" "syscall" "unsafe" ) @@ -19,9 +21,13 @@ var ( ) // IsTerminal returns true if stderr's file descriptor is a terminal. -func IsTerminal() bool { - fd := syscall.Stderr - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 +func IsTerminal(f io.Writer) bool { + switch v := f.(type) { + case *os.File: + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 + default: + return false + } } diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/Sirupsen/logrus/text_formatter.go index 6afd0e031..ba8885406 100644 --- a/vendor/github.com/Sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/Sirupsen/logrus/text_formatter.go @@ -3,9 +3,9 @@ package logrus import ( "bytes" "fmt" - "runtime" "sort" "strings" + "sync" "time" ) @@ -20,16 +20,10 @@ const ( var ( baseTimestamp time.Time - isTerminal bool ) func init() { baseTimestamp = time.Now() - isTerminal = IsTerminal() -} - -func miniTS() int { - return int(time.Since(baseTimestamp) / time.Second) } type TextFormatter struct { @@ -54,10 +48,32 @@ type TextFormatter struct { // that log extremely frequently and don't use the JSON formatter this may not // be desired. DisableSorting bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // QuoteCharacter can be set to the override the default quoting character " + // with something else. For example: ', or `. + QuoteCharacter string + + // Whether the logger's out is to a terminal + isTerminal bool + + sync.Once +} + +func (f *TextFormatter) init(entry *Entry) { + if len(f.QuoteCharacter) == 0 { + f.QuoteCharacter = "\"" + } + if entry.Logger != nil { + f.isTerminal = IsTerminal(entry.Logger.Out) + } } func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - var keys []string = make([]string, 0, len(entry.Data)) + var b *bytes.Buffer + keys := make([]string, 0, len(entry.Data)) for k := range entry.Data { keys = append(keys, k) } @@ -65,13 +81,17 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { if !f.DisableSorting { sort.Strings(keys) } - - b := &bytes.Buffer{} + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } prefixFieldClashes(entry.Data) - isColorTerminal := isTerminal && (runtime.GOOS != "windows") - isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors + f.Do(func() { f.init(entry) }) + + isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors timestampFormat := f.TimestampFormat if timestampFormat == "" { @@ -111,18 +131,24 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin levelText := strings.ToUpper(entry.Level.String())[0:4] - if !f.FullTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) + if f.DisableTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) + } else if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message) } else { fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) } for _, k := range keys { v := entry.Data[k] - fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v) + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) } } -func needsQuoting(text string) bool { +func (f *TextFormatter) needsQuoting(text string) bool { + if f.QuoteEmptyFields && len(text) == 0 { + return true + } for _, ch := range text { if !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || @@ -138,24 +164,26 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf b.WriteString(key) b.WriteByte('=') + f.appendValue(b, value) + b.WriteByte(' ') +} +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { switch value := value.(type) { case string: - if !needsQuoting(value) { + if !f.needsQuoting(value) { b.WriteString(value) } else { - fmt.Fprintf(b, "%q", value) + fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter) } case error: errmsg := value.Error() - if !needsQuoting(errmsg) { + if !f.needsQuoting(errmsg) { b.WriteString(errmsg) } else { - fmt.Fprintf(b, "%q", value) + fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter) } default: fmt.Fprint(b, value) } - - b.WriteByte(' ') } diff --git a/vendor/github.com/Sirupsen/logrus/writer.go b/vendor/github.com/Sirupsen/logrus/writer.go index f74d2aa5f..7bdebedc6 100644 --- a/vendor/github.com/Sirupsen/logrus/writer.go +++ b/vendor/github.com/Sirupsen/logrus/writer.go @@ -11,39 +11,48 @@ func (logger *Logger) Writer() *io.PipeWriter { } func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { reader, writer := io.Pipe() var printFunc func(args ...interface{}) + switch level { case DebugLevel: - printFunc = logger.Debug + printFunc = entry.Debug case InfoLevel: - printFunc = logger.Info + printFunc = entry.Info case WarnLevel: - printFunc = logger.Warn + printFunc = entry.Warn case ErrorLevel: - printFunc = logger.Error + printFunc = entry.Error case FatalLevel: - printFunc = logger.Fatal + printFunc = entry.Fatal case PanicLevel: - printFunc = logger.Panic + printFunc = entry.Panic default: - printFunc = logger.Print + printFunc = entry.Print } - go logger.writerScanner(reader, printFunc) + go entry.writerScanner(reader, printFunc) runtime.SetFinalizer(writer, writerFinalizer) return writer } -func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { scanner := bufio.NewScanner(reader) for scanner.Scan() { printFunc(scanner.Text()) } if err := scanner.Err(); err != nil { - logger.Errorf("Error while reading from Writer: %s", err) + entry.Errorf("Error while reading from Writer: %s", err) } reader.Close() } diff --git a/vendor/github.com/abbot/go-http-auth/users.go b/vendor/github.com/abbot/go-http-auth/users.go index eb4f39f97..6af06d4ac 100644 --- a/vendor/github.com/abbot/go-http-auth/users.go +++ b/vendor/github.com/abbot/go-http-auth/users.go @@ -1,7 +1,10 @@ package auth -import "encoding/csv" -import "os" +import ( + "encoding/csv" + "os" + "sync" +) /* SecretProvider is used by authenticators. Takes user name and realm @@ -20,6 +23,7 @@ type File struct { Info os.FileInfo /* must be set in inherited types during initialization */ Reload func() + mu sync.Mutex } func (f *File) ReloadIfNeeded() { @@ -27,6 +31,8 @@ func (f *File) ReloadIfNeeded() { if err != nil { panic(err) } + f.mu.Lock() + defer f.mu.Unlock() if f.Info == nil || f.Info.ModTime() != info.ModTime() { f.Info = info f.Reload() @@ -40,6 +46,7 @@ func (f *File) ReloadIfNeeded() { type HtdigestFile struct { File Users map[string]map[string]string + mu sync.RWMutex } func reload_htdigest(hf *HtdigestFile) { @@ -57,6 +64,8 @@ func reload_htdigest(hf *HtdigestFile) { panic(err) } + hf.mu.Lock() + defer hf.mu.Unlock() hf.Users = make(map[string]map[string]string) for _, record := range records { _, exists := hf.Users[record[1]] @@ -77,6 +86,8 @@ func HtdigestFileProvider(filename string) SecretProvider { hf.Reload = func() { reload_htdigest(hf) } return func(user, realm string) string { hf.ReloadIfNeeded() + hf.mu.RLock() + defer hf.mu.RUnlock() _, exists := hf.Users[realm] if !exists { return "" @@ -96,6 +107,7 @@ func HtdigestFileProvider(filename string) SecretProvider { type HtpasswdFile struct { File Users map[string]string + mu sync.RWMutex } func reload_htpasswd(h *HtpasswdFile) { @@ -113,6 +125,8 @@ func reload_htpasswd(h *HtpasswdFile) { panic(err) } + h.mu.Lock() + defer h.mu.Unlock() h.Users = make(map[string]string) for _, record := range records { h.Users[record[0]] = record[1] @@ -129,7 +143,9 @@ func HtpasswdFileProvider(filename string) SecretProvider { h.Reload = func() { reload_htpasswd(h) } return func(user, realm string) string { h.ReloadIfNeeded() + h.mu.RLock() password, exists := h.Users[user] + h.mu.RUnlock() if !exists { return "" } diff --git a/vendor/github.com/beorn7/perks/LICENSE b/vendor/github.com/beorn7/perks/LICENSE new file mode 100644 index 000000000..339177be6 --- /dev/null +++ b/vendor/github.com/beorn7/perks/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2013 Blake Mizerany + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/beorn7/perks/quantile/stream.go b/vendor/github.com/beorn7/perks/quantile/stream.go index 587b1fc5b..f4cabd669 100644 --- a/vendor/github.com/beorn7/perks/quantile/stream.go +++ b/vendor/github.com/beorn7/perks/quantile/stream.go @@ -133,7 +133,7 @@ func (s *Stream) Query(q float64) float64 { if l == 0 { return 0 } - i := int(float64(l) * q) + i := int(math.Ceil(float64(l) * q)) if i > 0 { i -= 1 } diff --git a/vendor/github.com/boltdb/bolt/bolt_386.go b/vendor/github.com/boltdb/bolt/bolt_386.go index e659bfb91..820d533c1 100644 --- a/vendor/github.com/boltdb/bolt/bolt_386.go +++ b/vendor/github.com/boltdb/bolt/bolt_386.go @@ -5,3 +5,6 @@ const maxMapSize = 0x7FFFFFFF // 2GB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0xFFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_amd64.go b/vendor/github.com/boltdb/bolt/bolt_amd64.go index cca6b7eb7..98fafdb47 100644 --- a/vendor/github.com/boltdb/bolt/bolt_amd64.go +++ b/vendor/github.com/boltdb/bolt/bolt_amd64.go @@ -5,3 +5,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_arm.go b/vendor/github.com/boltdb/bolt/bolt_arm.go index e659bfb91..7e5cb4b94 100644 --- a/vendor/github.com/boltdb/bolt/bolt_arm.go +++ b/vendor/github.com/boltdb/bolt/bolt_arm.go @@ -1,7 +1,28 @@ package bolt +import "unsafe" + // maxMapSize represents the largest mmap size supported by Bolt. const maxMapSize = 0x7FFFFFFF // 2GB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0xFFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned bool + +func init() { + // Simple check to see whether this arch handles unaligned load/stores + // correctly. + + // ARM9 and older devices require load/stores to be from/to aligned + // addresses. If not, the lower 2 bits are cleared and that address is + // read in a jumbled up order. + + // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html + + raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11} + val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2)) + + brokenUnaligned = val != 0x11222211 +} diff --git a/vendor/github.com/boltdb/bolt/bolt_arm64.go b/vendor/github.com/boltdb/bolt/bolt_arm64.go index 6d2309352..b26d84f91 100644 --- a/vendor/github.com/boltdb/bolt/bolt_arm64.go +++ b/vendor/github.com/boltdb/bolt/bolt_arm64.go @@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_ppc64.go b/vendor/github.com/boltdb/bolt/bolt_ppc64.go index 2dc6be02e..9331d9771 100644 --- a/vendor/github.com/boltdb/bolt/bolt_ppc64.go +++ b/vendor/github.com/boltdb/bolt/bolt_ppc64.go @@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_ppc64le.go b/vendor/github.com/boltdb/bolt/bolt_ppc64le.go index 8351e129f..8c143bc5d 100644 --- a/vendor/github.com/boltdb/bolt/bolt_ppc64le.go +++ b/vendor/github.com/boltdb/bolt/bolt_ppc64le.go @@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_s390x.go b/vendor/github.com/boltdb/bolt/bolt_s390x.go index f4dd26bbb..d7c39af92 100644 --- a/vendor/github.com/boltdb/bolt/bolt_s390x.go +++ b/vendor/github.com/boltdb/bolt/bolt_s390x.go @@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB // maxAllocSize is the size used when creating array pointers. const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = false diff --git a/vendor/github.com/boltdb/bolt/bolt_windows.go b/vendor/github.com/boltdb/bolt/bolt_windows.go index d538e6afd..b00fb0720 100644 --- a/vendor/github.com/boltdb/bolt/bolt_windows.go +++ b/vendor/github.com/boltdb/bolt/bolt_windows.go @@ -89,7 +89,7 @@ func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) erro func funlock(db *DB) error { err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{}) db.lockfile.Close() - os.Remove(db.path+lockExt) + os.Remove(db.path + lockExt) return err } diff --git a/vendor/github.com/boltdb/bolt/bucket.go b/vendor/github.com/boltdb/bolt/bucket.go index d2f8c524e..0c5bf2746 100644 --- a/vendor/github.com/boltdb/bolt/bucket.go +++ b/vendor/github.com/boltdb/bolt/bucket.go @@ -130,9 +130,17 @@ func (b *Bucket) Bucket(name []byte) *Bucket { func (b *Bucket) openBucket(value []byte) *Bucket { var child = newBucket(b.tx) + // If unaligned load/stores are broken on this arch and value is + // unaligned simply clone to an aligned byte array. + unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0 + + if unaligned { + value = cloneBytes(value) + } + // If this is a writable transaction then we need to copy the bucket entry. // Read-only transactions can point directly at the mmap entry. - if b.tx.writable { + if b.tx.writable && !unaligned { child.bucket = &bucket{} *child.bucket = *(*bucket)(unsafe.Pointer(&value[0])) } else { @@ -167,9 +175,8 @@ func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) { if bytes.Equal(key, k) { if (flags & bucketLeafFlag) != 0 { return nil, ErrBucketExists - } else { - return nil, ErrIncompatibleValue } + return nil, ErrIncompatibleValue } // Create empty, inline bucket. @@ -329,6 +336,28 @@ func (b *Bucket) Delete(key []byte) error { return nil } +// Sequence returns the current integer for the bucket without incrementing it. +func (b *Bucket) Sequence() uint64 { return b.bucket.sequence } + +// SetSequence updates the sequence number for the bucket. +func (b *Bucket) SetSequence(v uint64) error { + if b.tx.db == nil { + return ErrTxClosed + } else if !b.Writable() { + return ErrTxNotWritable + } + + // Materialize the root node if it hasn't been already so that the + // bucket will be saved during commit. + if b.rootNode == nil { + _ = b.node(b.root, nil) + } + + // Increment and return the sequence. + b.bucket.sequence = v + return nil +} + // NextSequence returns an autoincrementing integer for the bucket. func (b *Bucket) NextSequence() (uint64, error) { if b.tx.db == nil { diff --git a/vendor/github.com/boltdb/bolt/db.go b/vendor/github.com/boltdb/bolt/db.go index 1223493ca..f352ff14f 100644 --- a/vendor/github.com/boltdb/bolt/db.go +++ b/vendor/github.com/boltdb/bolt/db.go @@ -552,7 +552,10 @@ func (db *DB) removeTx(tx *Tx) { // Remove the transaction. for i, t := range db.txs { if t == tx { - db.txs = append(db.txs[:i], db.txs[i+1:]...) + last := len(db.txs) - 1 + db.txs[i] = db.txs[last] + db.txs[last] = nil + db.txs = db.txs[:last] break } } @@ -952,7 +955,7 @@ func (s *Stats) Sub(other *Stats) Stats { diff.PendingPageN = s.PendingPageN diff.FreeAlloc = s.FreeAlloc diff.FreelistInuse = s.FreelistInuse - diff.TxN = other.TxN - s.TxN + diff.TxN = s.TxN - other.TxN diff.TxStats = s.TxStats.Sub(&other.TxStats) return diff } diff --git a/vendor/github.com/boltdb/bolt/freelist.go b/vendor/github.com/boltdb/bolt/freelist.go index 0161948fc..aba48f58c 100644 --- a/vendor/github.com/boltdb/bolt/freelist.go +++ b/vendor/github.com/boltdb/bolt/freelist.go @@ -24,7 +24,12 @@ func newFreelist() *freelist { // size returns the size of the page after serialization. func (f *freelist) size() int { - return pageHeaderSize + (int(unsafe.Sizeof(pgid(0))) * f.count()) + n := f.count() + if n >= 0xFFFF { + // The first element will be used to store the count. See freelist.write. + n++ + } + return pageHeaderSize + (int(unsafe.Sizeof(pgid(0))) * n) } // count returns count of pages on the freelist @@ -46,16 +51,15 @@ func (f *freelist) pending_count() int { return count } -// all returns a list of all free ids and all pending ids in one sorted list. -func (f *freelist) all() []pgid { - m := make(pgids, 0) - +// copyall copies into dst a list of all free ids and all pending ids in one sorted list. +// f.count returns the minimum length required for dst. +func (f *freelist) copyall(dst []pgid) { + m := make(pgids, 0, f.pending_count()) for _, list := range f.pending { m = append(m, list...) } - sort.Sort(m) - return pgids(f.ids).merge(m) + mergepgids(dst, f.ids, m) } // allocate returns the starting page id of a contiguous list of pages of a given size. @@ -166,12 +170,16 @@ func (f *freelist) read(p *page) { } // Copy the list of page ids from the freelist. - ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count] - f.ids = make([]pgid, len(ids)) - copy(f.ids, ids) + if count == 0 { + f.ids = nil + } else { + ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count] + f.ids = make([]pgid, len(ids)) + copy(f.ids, ids) - // Make sure they're sorted. - sort.Sort(pgids(f.ids)) + // Make sure they're sorted. + sort.Sort(pgids(f.ids)) + } // Rebuild the page cache. f.reindex() @@ -182,20 +190,22 @@ func (f *freelist) read(p *page) { // become free. func (f *freelist) write(p *page) error { // Combine the old free pgids and pgids waiting on an open transaction. - ids := f.all() // Update the header flag. p.flags |= freelistPageFlag // The page.count can only hold up to 64k elements so if we overflow that // number then we handle it by putting the size in the first element. - if len(ids) < 0xFFFF { - p.count = uint16(len(ids)) - copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids) + lenids := f.count() + if lenids == 0 { + p.count = uint16(lenids) + } else if lenids < 0xFFFF { + p.count = uint16(lenids) + f.copyall(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:]) } else { p.count = 0xFFFF - ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0] = pgid(len(ids)) - copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[1:], ids) + ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0] = pgid(lenids) + f.copyall(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[1:]) } return nil @@ -230,7 +240,7 @@ func (f *freelist) reload(p *page) { // reindex rebuilds the free cache based on available and pending free lists. func (f *freelist) reindex() { - f.cache = make(map[pgid]bool) + f.cache = make(map[pgid]bool, len(f.ids)) for _, id := range f.ids { f.cache[id] = true } diff --git a/vendor/github.com/boltdb/bolt/node.go b/vendor/github.com/boltdb/bolt/node.go index e9d64af81..159318b22 100644 --- a/vendor/github.com/boltdb/bolt/node.go +++ b/vendor/github.com/boltdb/bolt/node.go @@ -201,6 +201,11 @@ func (n *node) write(p *page) { } p.count = uint16(len(n.inodes)) + // Stop here if there are no items to write. + if p.count == 0 { + return + } + // Loop over each item and write it to the page. b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):] for i, item := range n.inodes { diff --git a/vendor/github.com/boltdb/bolt/page.go b/vendor/github.com/boltdb/bolt/page.go index 4a555286a..cde403ae8 100644 --- a/vendor/github.com/boltdb/bolt/page.go +++ b/vendor/github.com/boltdb/bolt/page.go @@ -62,6 +62,9 @@ func (p *page) leafPageElement(index uint16) *leafPageElement { // leafPageElements retrieves a list of leaf nodes. func (p *page) leafPageElements() []leafPageElement { + if p.count == 0 { + return nil + } return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:] } @@ -72,6 +75,9 @@ func (p *page) branchPageElement(index uint16) *branchPageElement { // branchPageElements retrieves a list of branch nodes. func (p *page) branchPageElements() []branchPageElement { + if p.count == 0 { + return nil + } return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:] } @@ -139,12 +145,33 @@ func (a pgids) merge(b pgids) pgids { // Return the opposite slice if one is nil. if len(a) == 0 { return b - } else if len(b) == 0 { + } + if len(b) == 0 { return a } + merged := make(pgids, len(a)+len(b)) + mergepgids(merged, a, b) + return merged +} - // Create a list to hold all elements from both lists. - merged := make(pgids, 0, len(a)+len(b)) +// mergepgids copies the sorted union of a and b into dst. +// If dst is too small, it panics. +func mergepgids(dst, a, b pgids) { + if len(dst) < len(a)+len(b) { + panic(fmt.Errorf("mergepgids bad len %d < %d + %d", len(dst), len(a), len(b))) + } + // Copy in the opposite slice if one is nil. + if len(a) == 0 { + copy(dst, b) + return + } + if len(b) == 0 { + copy(dst, a) + return + } + + // Merged will hold all elements from both lists. + merged := dst[:0] // Assign lead to the slice with a lower starting value, follow to the higher value. lead, follow := a, b @@ -166,7 +193,5 @@ func (a pgids) merge(b pgids) pgids { } // Append what's left in follow. - merged = append(merged, follow...) - - return merged + _ = append(merged, follow...) } diff --git a/vendor/github.com/boltdb/bolt/tx.go b/vendor/github.com/boltdb/bolt/tx.go index 1cfb4cde8..6700308a2 100644 --- a/vendor/github.com/boltdb/bolt/tx.go +++ b/vendor/github.com/boltdb/bolt/tx.go @@ -381,7 +381,9 @@ func (tx *Tx) Check() <-chan error { func (tx *Tx) check(ch chan error) { // Check if any pages are double freed. freed := make(map[pgid]bool) - for _, id := range tx.db.freelist.all() { + all := make([]pgid, tx.db.freelist.count()) + tx.db.freelist.copyall(all) + for _, id := range all { if freed[id] { ch <- fmt.Errorf("page %d: already freed", id) } diff --git a/vendor/github.com/cenk/backoff/context.go b/vendor/github.com/cenk/backoff/context.go new file mode 100644 index 000000000..5d1570925 --- /dev/null +++ b/vendor/github.com/cenk/backoff/context.go @@ -0,0 +1,60 @@ +package backoff + +import ( + "time" + + "golang.org/x/net/context" +) + +// BackOffContext is a backoff policy that stops retrying after the context +// is canceled. +type BackOffContext interface { + BackOff + Context() context.Context +} + +type backOffContext struct { + BackOff + ctx context.Context +} + +// WithContext returns a BackOffContext with context ctx +// +// ctx must not be nil +func WithContext(b BackOff, ctx context.Context) BackOffContext { + if ctx == nil { + panic("nil context") + } + + if b, ok := b.(*backOffContext); ok { + return &backOffContext{ + BackOff: b.BackOff, + ctx: ctx, + } + } + + return &backOffContext{ + BackOff: b, + ctx: ctx, + } +} + +func ensureContext(b BackOff) BackOffContext { + if cb, ok := b.(BackOffContext); ok { + return cb + } + return WithContext(b, context.Background()) +} + +func (b *backOffContext) Context() context.Context { + return b.ctx +} + +func (b *backOffContext) NextBackOff() time.Duration { + select { + case <-b.Context().Done(): + return Stop + default: + return b.BackOff.NextBackOff() + } +} diff --git a/vendor/github.com/cenk/backoff/exponential.go b/vendor/github.com/cenk/backoff/exponential.go index ae65516dc..cc2a164f2 100644 --- a/vendor/github.com/cenk/backoff/exponential.go +++ b/vendor/github.com/cenk/backoff/exponential.go @@ -89,11 +89,6 @@ func NewExponentialBackOff() *ExponentialBackOff { MaxElapsedTime: DefaultMaxElapsedTime, Clock: SystemClock, } - if b.RandomizationFactor < 0 { - b.RandomizationFactor = 0 - } else if b.RandomizationFactor > 1 { - b.RandomizationFactor = 1 - } b.Reset() return b } diff --git a/vendor/github.com/cenk/backoff/retry.go b/vendor/github.com/cenk/backoff/retry.go index 6bc88ce75..5dbd825b5 100644 --- a/vendor/github.com/cenk/backoff/retry.go +++ b/vendor/github.com/cenk/backoff/retry.go @@ -17,6 +17,9 @@ type Notify func(error, time.Duration) // o is guaranteed to be run at least once. // It is the caller's responsibility to reset b after Retry returns. // +// If o returns a *PermanentError, the operation is not retried, and the +// wrapped error is returned. +// // Retry sleeps the goroutine for the duration returned by BackOff after a // failed operation returns. func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) } @@ -27,12 +30,18 @@ func RetryNotify(operation Operation, b BackOff, notify Notify) error { var err error var next time.Duration + cb := ensureContext(b) + b.Reset() for { if err = operation(); err == nil { return nil } + if permanent, ok := err.(*PermanentError); ok { + return permanent.Err + } + if next = b.NextBackOff(); next == Stop { return err } @@ -41,6 +50,29 @@ func RetryNotify(operation Operation, b BackOff, notify Notify) error { notify(err, next) } - time.Sleep(next) + t := time.NewTimer(next) + + select { + case <-cb.Context().Done(): + t.Stop() + return err + case <-t.C: + } + } +} + +// PermanentError signals that the operation should not be retried. +type PermanentError struct { + Err error +} + +func (e *PermanentError) Error() string { + return e.Err.Error() +} + +// Permanent wraps the given err in a *PermanentError. +func Permanent(err error) *PermanentError { + return &PermanentError{ + Err: err, } } diff --git a/vendor/github.com/cenk/backoff/ticker.go b/vendor/github.com/cenk/backoff/ticker.go index 7a5ff4ed1..49a99718d 100644 --- a/vendor/github.com/cenk/backoff/ticker.go +++ b/vendor/github.com/cenk/backoff/ticker.go @@ -13,7 +13,7 @@ import ( type Ticker struct { C <-chan time.Time c chan time.Time - b BackOff + b BackOffContext stop chan struct{} stopOnce sync.Once } @@ -26,7 +26,7 @@ func NewTicker(b BackOff) *Ticker { t := &Ticker{ C: c, c: c, - b: b, + b: ensureContext(b), stop: make(chan struct{}), } go t.run() @@ -58,6 +58,8 @@ func (t *Ticker) run() { case <-t.stop: t.c = nil // Prevent future ticks from being sent to the channel. return + case <-t.b.Context().Done(): + return } } } diff --git a/vendor/github.com/codegangsta/negroni/logger.go b/vendor/github.com/codegangsta/negroni/logger.go index e3828ef31..032909f5d 100644 --- a/vendor/github.com/codegangsta/negroni/logger.go +++ b/vendor/github.com/codegangsta/negroni/logger.go @@ -1,29 +1,80 @@ package negroni import ( + "bytes" + "log" "net/http" "os" + "text/template" "time" ) +// LoggerEntry is the structure +// passed to the template. +type LoggerEntry struct { + StartTime string + Status int + Duration time.Duration + Hostname string + Method string + Path string +} + +// LoggerDefaultFormat is the format +// logged used by the default Logger instance. +var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n" + +// LoggerDefaultDateFormat is the +// format used for date by the +// default Logger instance. +var LoggerDefaultDateFormat = time.RFC3339 + +// ALogger interface +type ALogger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + // Logger is a middleware handler that logs the request as it goes in and the response as it goes out. type Logger struct { - // Logger inherits from log.Logger used to log messages with the Logger middleware - *log.Logger + // ALogger implements just enough log.Logger interface to be compatible with other implementations + ALogger + dateFormat string + template *template.Template } // NewLogger returns a new Logger instance func NewLogger() *Logger { - return &Logger{log.New(os.Stdout, "[negroni] ", 0)} + logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat} + logger.SetFormat(LoggerDefaultFormat) + return logger +} + +func (l *Logger) SetFormat(format string) { + l.template = template.Must(template.New("negroni_parser").Parse(format)) +} + +func (l *Logger) SetDateFormat(format string) { + l.dateFormat = format } func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { start := time.Now() - l.Printf("Started %s %s", r.Method, r.URL.Path) next(rw, r) res := rw.(ResponseWriter) - l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start)) + log := LoggerEntry{ + StartTime: start.Format(l.dateFormat), + Status: res.Status(), + Duration: time.Since(start), + Hostname: r.Host, + Method: r.Method, + Path: r.URL.Path, + } + + buff := &bytes.Buffer{} + l.template.Execute(buff, log) + l.Printf(buff.String()) } diff --git a/vendor/github.com/codegangsta/negroni/negroni.go b/vendor/github.com/codegangsta/negroni/negroni.go index 9c7c187e7..7a00b38f6 100644 --- a/vendor/github.com/codegangsta/negroni/negroni.go +++ b/vendor/github.com/codegangsta/negroni/negroni.go @@ -59,6 +59,14 @@ func New(handlers ...Handler) *Negroni { } } +// With returns a new Negroni instance that is a combination of the negroni +// receiver's handlers and the provided handlers. +func (n *Negroni) With(handlers ...Handler) *Negroni { + return New( + append(n.handlers, handlers...)..., + ) +} + // Classic returns a new Negroni instance with the default middleware already // in the stack. // diff --git a/vendor/github.com/codegangsta/negroni/recovery.go b/vendor/github.com/codegangsta/negroni/recovery.go index 1fb19981d..8396cb1ed 100644 --- a/vendor/github.com/codegangsta/negroni/recovery.go +++ b/vendor/github.com/codegangsta/negroni/recovery.go @@ -11,7 +11,7 @@ import ( // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. type Recovery struct { - Logger *log.Logger + Logger ALogger PrintStack bool ErrorHandlerFunc func(interface{}) StackAll bool diff --git a/vendor/github.com/codegangsta/negroni/response_writer.go b/vendor/github.com/codegangsta/negroni/response_writer.go index f805825aa..bfb83a6ef 100644 --- a/vendor/github.com/codegangsta/negroni/response_writer.go +++ b/vendor/github.com/codegangsta/negroni/response_writer.go @@ -29,9 +29,15 @@ type beforeFunc func(ResponseWriter) // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { - return &responseWriter{ + nrw := &responseWriter{ ResponseWriter: rw, } + + if _, ok := rw.(http.CloseNotifier); ok { + return &responseWriterCloseNotifer{nrw} + } + + return nrw } type responseWriter struct { @@ -81,10 +87,6 @@ func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return hijacker.Hijack() } -func (rw *responseWriter) CloseNotify() <-chan bool { - return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - func (rw *responseWriter) callBefore() { for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { rw.beforeFuncs[i](rw) @@ -94,6 +96,18 @@ func (rw *responseWriter) callBefore() { func (rw *responseWriter) Flush() { flusher, ok := rw.ResponseWriter.(http.Flusher) if ok { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } flusher.Flush() } } + +type responseWriterCloseNotifer struct { + *responseWriter +} + +func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go b/vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go new file mode 100644 index 000000000..b9702ca8a --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go @@ -0,0 +1,63 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 fileutil implements utility functions related to files and paths. +package fileutil + +import ( + "io/ioutil" + "os" + "path" + "sort" + + "github.com/coreos/pkg/capnslog" +) + +const ( + privateFileMode = 0600 +) + +var ( + plog = capnslog.NewPackageLogger("github.com/coreos/etcd/pkg", "fileutil") +) + +// IsDirWriteable checks if dir is writable by writing and removing a file +// to dir. It returns nil if dir is writable. +func IsDirWriteable(dir string) error { + f := path.Join(dir, ".touch") + if err := ioutil.WriteFile(f, []byte(""), privateFileMode); err != nil { + return err + } + return os.Remove(f) +} + +// ReadDir returns the filenames in the given directory in sorted order. +func ReadDir(dirpath string) ([]string, error) { + dir, err := os.Open(dirpath) + if err != nil { + return nil, err + } + defer dir.Close() + names, err := dir.Readdirnames(-1) + if err != nil { + return nil, err + } + sort.Strings(names) + return names, nil +} + +func Exist(name string) bool { + _, err := os.Stat(name) + return err == nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/lock_plan9.go b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_plan9.go new file mode 100644 index 000000000..311288de0 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_plan9.go @@ -0,0 +1,90 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 fileutil + +import ( + "errors" + "os" + "syscall" + "time" +) + +var ( + ErrLocked = errors.New("file already locked") +) + +type Lock interface { + Name() string + TryLock() error + Lock() error + Unlock() error + Destroy() error +} + +type lock struct { + fname string + file *os.File +} + +func (l *lock) Name() string { + return l.fname +} + +// TryLock acquires exclusivity on the lock without blocking +func (l *lock) TryLock() error { + err := os.Chmod(l.fname, syscall.DMEXCL|0600) + if err != nil { + return err + } + + f, err := os.Open(l.fname) + if err != nil { + return ErrLocked + } + + l.file = f + return nil +} + +// Lock acquires exclusivity on the lock with blocking +func (l *lock) Lock() error { + err := os.Chmod(l.fname, syscall.DMEXCL|0600) + if err != nil { + return err + } + + for { + f, err := os.Open(l.fname) + if err == nil { + l.file = f + return nil + } + time.Sleep(10 * time.Millisecond) + } +} + +// Unlock unlocks the lock +func (l *lock) Unlock() error { + return l.file.Close() +} + +func (l *lock) Destroy() error { + return nil +} + +func NewLock(file string) (Lock, error) { + l := &lock{fname: file} + return l, nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/lock_solaris.go b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_solaris.go new file mode 100644 index 000000000..1929bd1fc --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_solaris.go @@ -0,0 +1,98 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 solaris + +package fileutil + +import ( + "errors" + "os" + "syscall" +) + +var ( + ErrLocked = errors.New("file already locked") +) + +type Lock interface { + Name() string + TryLock() error + Lock() error + Unlock() error + Destroy() error +} + +type lock struct { + fd int + file *os.File +} + +func (l *lock) Name() string { + return l.file.Name() +} + +// TryLock acquires exclusivity on the lock without blocking +func (l *lock) TryLock() error { + var lock syscall.Flock_t + lock.Start = 0 + lock.Len = 0 + lock.Pid = 0 + lock.Type = syscall.F_WRLCK + lock.Whence = 0 + lock.Pid = 0 + err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) + if err != nil && err == syscall.EAGAIN { + return ErrLocked + } + return err +} + +// Lock acquires exclusivity on the lock without blocking +func (l *lock) Lock() error { + var lock syscall.Flock_t + lock.Start = 0 + lock.Len = 0 + lock.Type = syscall.F_WRLCK + lock.Whence = 0 + lock.Pid = 0 + return syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) +} + +// Unlock unlocks the lock +func (l *lock) Unlock() error { + var lock syscall.Flock_t + lock.Start = 0 + lock.Len = 0 + lock.Type = syscall.F_UNLCK + lock.Whence = 0 + err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) + if err != nil && err == syscall.EAGAIN { + return ErrLocked + } + return err +} + +func (l *lock) Destroy() error { + return l.file.Close() +} + +func NewLock(file string) (Lock, error) { + f, err := os.OpenFile(file, os.O_WRONLY, 0600) + if err != nil { + return nil, err + } + l := &lock{int(f.Fd()), f} + return l, nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/lock_unix.go b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_unix.go new file mode 100644 index 000000000..f6e69cc34 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_unix.go @@ -0,0 +1,76 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 !windows,!plan9,!solaris + +package fileutil + +import ( + "errors" + "os" + "syscall" +) + +var ( + ErrLocked = errors.New("file already locked") +) + +type Lock interface { + Name() string + TryLock() error + Lock() error + Unlock() error + Destroy() error +} + +type lock struct { + fd int + file *os.File +} + +func (l *lock) Name() string { + return l.file.Name() +} + +// TryLock acquires exclusivity on the lock without blocking +func (l *lock) TryLock() error { + err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB) + if err != nil && err == syscall.EWOULDBLOCK { + return ErrLocked + } + return err +} + +// Lock acquires exclusivity on the lock without blocking +func (l *lock) Lock() error { + return syscall.Flock(l.fd, syscall.LOCK_EX) +} + +// Unlock unlocks the lock +func (l *lock) Unlock() error { + return syscall.Flock(l.fd, syscall.LOCK_UN) +} + +func (l *lock) Destroy() error { + return l.file.Close() +} + +func NewLock(file string) (Lock, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + l := &lock{int(f.Fd()), f} + return l, nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/lock_windows.go b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_windows.go new file mode 100644 index 000000000..a0a928b90 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/lock_windows.go @@ -0,0 +1,71 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 windows + +package fileutil + +import ( + "errors" + "os" +) + +var ( + ErrLocked = errors.New("file already locked") +) + +type Lock interface { + Name() string + TryLock() error + Lock() error + Unlock() error + Destroy() error +} + +type lock struct { + fd int + file *os.File +} + +func (l *lock) Name() string { + return l.file.Name() +} + +// TryLock acquires exclusivity on the lock without blocking +func (l *lock) TryLock() error { + return nil +} + +// Lock acquires exclusivity on the lock without blocking +func (l *lock) Lock() error { + return nil +} + +// Unlock unlocks the lock +func (l *lock) Unlock() error { + return nil +} + +func (l *lock) Destroy() error { + return l.file.Close() +} + +func NewLock(file string) (Lock, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + l := &lock{int(f.Fd()), f} + return l, nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/perallocate_unsupported.go b/vendor/github.com/coreos/etcd/pkg/fileutil/perallocate_unsupported.go new file mode 100644 index 000000000..c1a952bb7 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/perallocate_unsupported.go @@ -0,0 +1,28 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 !linux + +package fileutil + +import "os" + +// Preallocate tries to allocate the space for given +// file. This operation is only supported on linux by a +// few filesystems (btrfs, ext4, etc.). +// If the operation is unsupported, no error will be returned. +// Otherwise, the error encountered will be returned. +func Preallocate(f *os.File, sizeInBytes int) error { + return nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/preallocate.go b/vendor/github.com/coreos/etcd/pkg/fileutil/preallocate.go new file mode 100644 index 000000000..c4bd4f4c8 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/preallocate.go @@ -0,0 +1,42 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 linux + +package fileutil + +import ( + "os" + "syscall" +) + +// Preallocate tries to allocate the space for given +// file. This operation is only supported on linux by a +// few filesystems (btrfs, ext4, etc.). +// If the operation is unsupported, no error will be returned. +// Otherwise, the error encountered will be returned. +func Preallocate(f *os.File, sizeInBytes int) error { + // use mode = 1 to keep size + // see FALLOC_FL_KEEP_SIZE + err := syscall.Fallocate(int(f.Fd()), 1, 0, int64(sizeInBytes)) + if err != nil { + errno, ok := err.(syscall.Errno) + // treat not support as nil error + if ok && errno == syscall.ENOTSUP { + return nil + } + return err + } + return nil +} diff --git a/vendor/github.com/coreos/etcd/pkg/fileutil/purge.go b/vendor/github.com/coreos/etcd/pkg/fileutil/purge.go new file mode 100644 index 000000000..375aa9719 --- /dev/null +++ b/vendor/github.com/coreos/etcd/pkg/fileutil/purge.go @@ -0,0 +1,80 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 fileutil + +import ( + "os" + "path" + "sort" + "strings" + "time" +) + +func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error { + errC := make(chan error, 1) + go func() { + for { + fnames, err := ReadDir(dirname) + if err != nil { + errC <- err + return + } + newfnames := make([]string, 0) + for _, fname := range fnames { + if strings.HasSuffix(fname, suffix) { + newfnames = append(newfnames, fname) + } + } + sort.Strings(newfnames) + for len(newfnames) > int(max) { + f := path.Join(dirname, newfnames[0]) + l, err := NewLock(f) + if err != nil { + errC <- err + return + } + err = l.TryLock() + if err != nil { + break + } + err = os.Remove(f) + if err != nil { + errC <- err + return + } + err = l.Unlock() + if err != nil { + plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err) + errC <- err + return + } + err = l.Destroy() + if err != nil { + plog.Errorf("error destroying lock %s when purging file (%v)", l.Name(), err) + errC <- err + return + } + plog.Infof("purged file %s successfully", f) + newfnames = newfnames[1:] + } + select { + case <-time.After(interval): + case <-stop: + return + } + } + }() + return errC +} diff --git a/vendor/github.com/coreos/etcd/version/version.go b/vendor/github.com/coreos/etcd/version/version.go new file mode 100644 index 000000000..976917e95 --- /dev/null +++ b/vendor/github.com/coreos/etcd/version/version.go @@ -0,0 +1,91 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 version implements etcd version parsing and contains latest version +// information. +package version + +import ( + "fmt" + "os" + "path" + "strings" + + "github.com/coreos/etcd/pkg/fileutil" + "github.com/coreos/etcd/pkg/types" +) + +var ( + // MinClusterVersion is the min cluster version this etcd binary is compatible with. + MinClusterVersion = "2.2.0" + Version = "2.3.0-alpha.0+git" + + // Git SHA Value will be set during build + GitSHA = "Not provided (use ./build instead of go build)" +) + +// WalVersion is an enum for versions of etcd logs. +type DataDirVersion string + +const ( + DataDirUnknown DataDirVersion = "Unknown WAL" + DataDir2_0 DataDirVersion = "2.0.0" + DataDir2_0Proxy DataDirVersion = "2.0 proxy" + DataDir2_0_1 DataDirVersion = "2.0.1" +) + +type Versions struct { + Server string `json:"etcdserver"` + Cluster string `json:"etcdcluster"` + // TODO: raft state machine version +} + +func DetectDataDir(dirpath string) (DataDirVersion, error) { + names, err := fileutil.ReadDir(dirpath) + if err != nil { + if os.IsNotExist(err) { + err = nil + } + // Error reading the directory + return DataDirUnknown, err + } + nameSet := types.NewUnsafeSet(names...) + if nameSet.Contains("member") { + ver, err := DetectDataDir(path.Join(dirpath, "member")) + if ver == DataDir2_0 { + return DataDir2_0_1, nil + } + return ver, err + } + if nameSet.ContainsAll([]string{"snap", "wal"}) { + // .../wal cannot be empty to exist. + walnames, err := fileutil.ReadDir(path.Join(dirpath, "wal")) + if err == nil && len(walnames) > 0 { + return DataDir2_0, nil + } + } + if nameSet.ContainsAll([]string{"proxy"}) { + return DataDir2_0Proxy, nil + } + return DataDirUnknown, nil +} + +// Cluster only keeps the major.minor. +func Cluster(v string) string { + vs := strings.Split(v, ".") + if len(vs) <= 2 { + return v + } + return fmt.Sprintf("%s.%s", vs[0], vs[1]) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go index 555282723..9db83c66f 100644 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -67,6 +67,15 @@ type ConfigState struct { // Google App Engine or with the "safe" build tag specified. DisablePointerMethods bool + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + // ContinueOnMethod specifies whether or not recursion should continue once // a custom error or Stringer interface is invoked. The default, false, // means it will print the results of invoking the custom error or Stringer diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go index a0ff95e27..95f9dbfe5 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -129,7 +129,7 @@ func (d *dumpState) dumpPtr(v reflect.Value) { d.w.Write(closeParenBytes) // Display pointer information. - if len(pointerChain) > 0 { + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { d.w.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { @@ -282,13 +282,13 @@ func (d *dumpState) dump(v reflect.Value) { case reflect.Map, reflect.String: valueLen = v.Len() } - if valueLen != 0 || valueCap != 0 { + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { d.w.Write(openParenBytes) if valueLen != 0 { d.w.Write(lenEqualsBytes) printInt(d.w, int64(valueLen), 10) } - if valueCap != 0 { + if !d.cs.DisableCapacities && valueCap != 0 { if valueLen != 0 { d.w.Write(spaceBytes) } diff --git a/vendor/github.com/daviddengcn/go-colortext/LICENSE b/vendor/github.com/daviddengcn/go-colortext/LICENSE deleted file mode 100644 index 974ec4202..000000000 --- a/vendor/github.com/daviddengcn/go-colortext/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, David Deng -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 go-colortext 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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/daviddengcn/go-colortext/ct.go b/vendor/github.com/daviddengcn/go-colortext/ct.go deleted file mode 100644 index 4acfaacd5..000000000 --- a/vendor/github.com/daviddengcn/go-colortext/ct.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -ct package provides functions to change the color of console text. - -Under windows platform, the Console api is used. Under other systems, ANSI text mode is used. -*/ -package ct - -// Color is the type of color to be set. -type Color int - -const ( - // No change of color - None = Color(iota) - Black - Red - Green - Yellow - Blue - Magenta - Cyan - White -) - -/* -ResetColor resets the foreground and background to original colors -*/ -func ResetColor() { - resetColor() -} - -// ChangeColor sets the foreground and background colors. If the value of the color is None, -// the corresponding color keeps unchanged. -// If fgBright or bgBright is set true, corresponding color use bright color. bgBright may be -// ignored in some OS environment. -func ChangeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - changeColor(fg, fgBright, bg, bgBright) -} - -// Foreground changes the foreground color. -func Foreground(cl Color, bright bool) { - ChangeColor(cl, bright, None, false) -} - -// Background changes the background color. -func Background(cl Color, bright bool) { - ChangeColor(None, false, cl, bright) -} diff --git a/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go b/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go deleted file mode 100644 index 6b0c5bc6e..000000000 --- a/vendor/github.com/daviddengcn/go-colortext/ct_ansi.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build !windows - -package ct - -import ( - "fmt" -) - -func resetColor() { - fmt.Print("\x1b[0m") -} - -func changeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - if fg == None && bg == None { - return - } // if - - s := "" - if fg != None { - s = fmt.Sprintf("%s%d", s, 30+(int)(fg-Black)) - if fgBright { - s += ";1" - } // if - } // if - - if bg != None { - if s != "" { - s += ";" - } // if - s = fmt.Sprintf("%s%d", s, 40+(int)(bg-Black)) - } // if - - s = "\x1b[0;" + s + "m" - fmt.Print(s) -} diff --git a/vendor/github.com/daviddengcn/go-colortext/ct_win.go b/vendor/github.com/daviddengcn/go-colortext/ct_win.go deleted file mode 100644 index 6b4164415..000000000 --- a/vendor/github.com/daviddengcn/go-colortext/ct_win.go +++ /dev/null @@ -1,139 +0,0 @@ -// +build windows - -package ct - -import ( - "syscall" - "unsafe" -) - -var fg_colors = []uint16{ - 0, - 0, - foreground_red, - foreground_green, - foreground_red | foreground_green, - foreground_blue, - foreground_red | foreground_blue, - foreground_green | foreground_blue, - foreground_red | foreground_green | foreground_blue} - -var bg_colors = []uint16{ - 0, - 0, - background_red, - background_green, - background_red | background_green, - background_blue, - background_red | background_blue, - background_green | background_blue, - background_red | background_green | background_blue} - -const ( - foreground_blue = uint16(0x0001) - foreground_green = uint16(0x0002) - foreground_red = uint16(0x0004) - foreground_intensity = uint16(0x0008) - background_blue = uint16(0x0010) - background_green = uint16(0x0020) - background_red = uint16(0x0040) - background_intensity = uint16(0x0080) - - foreground_mask = foreground_blue | foreground_green | foreground_red | foreground_intensity - background_mask = background_blue | background_green | background_red | background_intensity -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - - procGetStdHandle = kernel32.NewProc("GetStdHandle") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - - hStdout uintptr - initScreenInfo *console_screen_buffer_info -) - -func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { - ret, _, _ := procSetConsoleTextAttribute.Call( - hConsoleOutput, - uintptr(wAttributes)) - return ret != 0 -} - -type coord struct { - X, Y int16 -} - -type small_rect struct { - Left, Top, Right, Bottom int16 -} - -type console_screen_buffer_info struct { - DwSize coord - DwCursorPosition coord - WAttributes uint16 - SrWindow small_rect - DwMaximumWindowSize coord -} - -func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *console_screen_buffer_info { - var csbi console_screen_buffer_info - ret, _, _ := procGetConsoleScreenBufferInfo.Call( - hConsoleOutput, - uintptr(unsafe.Pointer(&csbi))) - if ret == 0 { - return nil - } - return &csbi -} - -const ( - std_output_handle = uint32(-11 & 0xFFFFFFFF) -) - -func init() { - kernel32 := syscall.NewLazyDLL("kernel32.dll") - - procGetStdHandle = kernel32.NewProc("GetStdHandle") - - hStdout, _, _ = procGetStdHandle.Call(uintptr(std_output_handle)) - - initScreenInfo = getConsoleScreenBufferInfo(hStdout) - - syscall.LoadDLL("") -} - -func resetColor() { - if initScreenInfo == nil { // No console info - Ex: stdout redirection - return - } - setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes) -} - -func changeColor(fg Color, fgBright bool, bg Color, bgBright bool) { - attr := uint16(0) - if fg == None || bg == None { - cbufinfo := getConsoleScreenBufferInfo(hStdout) - if cbufinfo == nil { // No console info - Ex: stdout redirection - return - } - attr = getConsoleScreenBufferInfo(hStdout).WAttributes - } // if - - if fg != None { - attr = attr & ^foreground_mask | fg_colors[fg] - if fgBright { - attr |= foreground_intensity - } // if - } // if - - if bg != None { - attr = attr & ^background_mask | bg_colors[bg] - if bgBright { - attr |= background_intensity - } // if - } // if - - setConsoleTextAttribute(hStdout, attr) -} diff --git a/vendor/github.com/decker502/dnspod-go/LICENSE b/vendor/github.com/decker502/dnspod-go/LICENSE new file mode 100644 index 000000000..c5c9a4e37 --- /dev/null +++ b/vendor/github.com/decker502/dnspod-go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 decker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/dgrijalva/jwt-go/errors.go b/vendor/github.com/dgrijalva/jwt-go/errors.go index 1c93024aa..662df19d4 100644 --- a/vendor/github.com/dgrijalva/jwt-go/errors.go +++ b/vendor/github.com/dgrijalva/jwt-go/errors.go @@ -51,9 +51,13 @@ func (e ValidationError) Error() string { } else { return "token is invalid" } + return e.Inner.Error() } // No errors func (e *ValidationError) valid() bool { - return e.Errors == 0 + if e.Errors > 0 { + return false + } + return true } diff --git a/vendor/github.com/dgrijalva/jwt-go/parser.go b/vendor/github.com/dgrijalva/jwt-go/parser.go index 7bf1c4ea0..7020c52a1 100644 --- a/vendor/github.com/dgrijalva/jwt-go/parser.go +++ b/vendor/github.com/dgrijalva/jwt-go/parser.go @@ -8,9 +8,8 @@ import ( ) type Parser struct { - ValidMethods []string // If populated, only these methods will be considered valid - UseJSONNumber bool // Use JSON Number format in JSON decoder - SkipClaimsValidation bool // Skip claims validation during token parsing + ValidMethods []string // If populated, only these methods will be considered valid + UseJSONNumber bool // Use JSON Number format in JSON decoder } // Parse, validate, and return a token. @@ -102,16 +101,14 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf vErr := &ValidationError{} // Validate Claims - if !p.SkipClaimsValidation { - if err := token.Claims.Valid(); err != nil { + if err := token.Claims.Valid(); err != nil { - // If the Claims Valid returned an error, check if it is a validation error, - // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set - if e, ok := err.(*ValidationError); !ok { - vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} - } else { - vErr = e - } + // If the Claims Valid returned an error, check if it is a validation error, + // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set + if e, ok := err.(*ValidationError); !ok { + vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} + } else { + vErr = e } } diff --git a/vendor/github.com/docker/libkv/store/boltdb/boltdb.go b/vendor/github.com/docker/libkv/store/boltdb/boltdb.go index 4026e0a20..cdfd74f87 100644 --- a/vendor/github.com/docker/libkv/store/boltdb/boltdb.go +++ b/vendor/github.com/docker/libkv/store/boltdb/boltdb.go @@ -59,6 +59,7 @@ func New(endpoints []string, options *store.Config) (store.Store, error) { db *bolt.DB err error boltOptions *bolt.Options + timeout = transientTimeout ) if len(endpoints) > 1 { @@ -82,11 +83,15 @@ func New(endpoints []string, options *store.Config) (store.Store, error) { } } + if options.ConnectionTimeout != 0 { + timeout = options.ConnectionTimeout + } + b := &BoltDB{ client: db, path: endpoints[0], boltBucket: []byte(options.Bucket), - timeout: transientTimeout, + timeout: timeout, PersistConnection: options.PersistConnection, } diff --git a/vendor/github.com/docker/libkv/store/zookeeper/zookeeper.go b/vendor/github.com/docker/libkv/store/zookeeper/zookeeper.go index 8a44ad318..ff8d4ebe0 100644 --- a/vendor/github.com/docker/libkv/store/zookeeper/zookeeper.go +++ b/vendor/github.com/docker/libkv/store/zookeeper/zookeeper.go @@ -252,7 +252,7 @@ func (s *Zookeeper) List(directory string) ([]*store.KVPair, error) { pair, err := s.Get(strings.TrimSuffix(directory, "/") + s.normalize(key)) if err != nil { // If node is not found: List is out of date, retry - if err == zk.ErrNoNode { + if err == store.ErrKeyNotFound { return s.List(directory) } return nil, err diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go index 9397e58d5..04f6d7a39 100644 --- a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go +++ b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go @@ -9,6 +9,7 @@ import ( "os" "path" "path/filepath" + "strings" "time" ) @@ -145,14 +146,22 @@ func (fs *AssetFS) Open(name string) (http.File, error) { } if b, err := fs.Asset(name); err == nil { timestamp := defaultFileTimestamp - if info, err := fs.AssetInfo(name); err == nil { - timestamp = info.ModTime() + if fs.AssetInfo != nil { + if info, err := fs.AssetInfo(name); err == nil { + timestamp = info.ModTime() + } } return NewAssetFile(name, b, timestamp), nil } if children, err := fs.AssetDir(name); err == nil { return NewAssetDirectory(name, children, fs), nil } else { + // If the error is not found, return an error that will + // result in a 404 error. Otherwise the server returns + // a 500 error for files not found. + if strings.Contains(err.Error(), "not found") { + return nil, os.ErrNotExist + } return nil, err } } diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md new file mode 100644 index 000000000..25fdaf639 --- /dev/null +++ b/vendor/github.com/fatih/color/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go new file mode 100644 index 000000000..f76c73ae1 --- /dev/null +++ b/vendor/github.com/fatih/color/color.go @@ -0,0 +1,526 @@ +package color + +import ( + "fmt" + "io" + "os" + "strconv" + "strings" + "sync" + + "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" +) + +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = os.Getenv("TERM") == "dumb" || + (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) + +// Color defines a custom color object which is defined by SGR parameters. +type Color struct { + params []Attribute + noColor *bool +} + +// Attribute defines a single SGR Code +type Attribute int + +const escape = "\x1b" + +// Base attributes +const ( + Reset Attribute = iota + Bold + Faint + Italic + Underline + BlinkSlow + BlinkRapid + ReverseVideo + Concealed + CrossedOut +) + +// Foreground text colors +const ( + FgBlack Attribute = iota + 30 + FgRed + FgGreen + FgYellow + FgBlue + FgMagenta + FgCyan + FgWhite +) + +// Foreground Hi-Intensity text colors +const ( + FgHiBlack Attribute = iota + 90 + FgHiRed + FgHiGreen + FgHiYellow + FgHiBlue + FgHiMagenta + FgHiCyan + FgHiWhite +) + +// Background text colors +const ( + BgBlack Attribute = iota + 40 + BgRed + BgGreen + BgYellow + BgBlue + BgMagenta + BgCyan + BgWhite +) + +// Background Hi-Intensity text colors +const ( + BgHiBlack Attribute = iota + 100 + BgHiRed + BgHiGreen + BgHiYellow + BgHiBlue + BgHiMagenta + BgHiCyan + BgHiWhite +) + +// New returns a newly created color object. +func New(value ...Attribute) *Color { + c := &Color{params: make([]Attribute, 0)} + c.Add(value...) + return c +} + +// Set sets the given parameters immediately. It will change the color of +// output with the given SGR parameters until color.Unset() is called. +func Set(p ...Attribute) *Color { + c := New(p...) + c.Set() + return c +} + +// Unset resets all escape attributes and clears the output. Usually should +// be called after Set(). +func Unset() { + if NoColor { + return + } + + fmt.Fprintf(Output, "%s[%dm", escape, Reset) +} + +// Set sets the SGR sequence. +func (c *Color) Set() *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(Output, c.format()) + return c +} + +func (c *Color) unset() { + if c.isNoColorSet() { + return + } + + Unset() +} + +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + +// Add is used to chain SGR parameters. Use as many as parameters to combine +// and create custom color objects. Example: Add(color.FgRed, color.Underline). +func (c *Color) Add(value ...Attribute) *Color { + c.params = append(c.params, value...) + return c +} + +func (c *Color) prepend(value Attribute) { + c.params = append(c.params, 0) + copy(c.params[1:], c.params[0:]) + c.params[0] = value +} + +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} + +// Print formats using the default formats for its operands and writes to +// standard output. Spaces are added between operands when neither is a +// string. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Print(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprint(Output, a...) +} + +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + +// Printf formats according to a format specifier and writes to standard output. +// It returns the number of bytes written and any write error encountered. +// This is the standard fmt.Printf() method wrapped with the given color. +func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintf(Output, format, a...) +} + +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + +// Println formats using the default formats for its operands and writes to +// standard output. Spaces are always added between operands and a newline is +// appended. It returns the number of bytes written and any write error +// encountered. This is the standard fmt.Print() method wrapped with the given +// color. +func (c *Color) Println(a ...interface{}) (n int, err error) { + c.Set() + defer c.unset() + + return fmt.Fprintln(Output, a...) +} + +// Sprint is just like Print, but returns a string instead of printing it. +func (c *Color) Sprint(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) +} + +// Sprintln is just like Println, but returns a string instead of printing it. +func (c *Color) Sprintln(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) +} + +// Sprintf is just like Printf, but returns a string instead of printing it. +func (c *Color) Sprintf(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) +} + +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + +// PrintFunc returns a new function that prints the passed arguments as +// colorized with color.Print(). +func (c *Color) PrintFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } +} + +// PrintfFunc returns a new function that prints the passed arguments as +// colorized with color.Printf(). +func (c *Color) PrintfFunc() func(format string, a ...interface{}) { + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } +} + +// PrintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Println(). +func (c *Color) PrintlnFunc() func(a ...interface{}) { + return func(a ...interface{}) { + c.Println(a...) + } +} + +// SprintFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprint(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output, example: +// +// put := New(FgYellow).SprintFunc() +// fmt.Fprintf(color.Output, "This is a %s", put("warning")) +func (c *Color) SprintFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) + } +} + +// SprintfFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintf(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { + return func(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) + } +} + +// SprintlnFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintln(). Useful to put into or mix into other +// string. Windows users should use this in conjunction with color.Output. +func (c *Color) SprintlnFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) + } +} + +// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m" +// an example output might be: "1;36" -> bold cyan +func (c *Color) sequence() string { + format := make([]string, len(c.params)) + for i, v := range c.params { + format[i] = strconv.Itoa(int(v)) + } + + return strings.Join(format, ";") +} + +// wrap wraps the s string with the colors attributes. The string is ready to +// be printed. +func (c *Color) wrap(s string) string { + if c.isNoColorSet() { + return s + } + + return c.format() + s + c.unformat() +} + +func (c *Color) format() string { + return fmt.Sprintf("%s[%sm", escape, c.sequence()) +} + +func (c *Color) unformat() string { + return fmt.Sprintf("%s[%dm", escape, Reset) +} + +// DisableColor disables the color output. Useful to not change any existing +// code and still being able to output. Can be used for flags like +// "--no-color". To enable back use EnableColor() method. +func (c *Color) DisableColor() { + c.noColor = boolPtr(true) +} + +// EnableColor enables the color output. Use it in conjunction with +// DisableColor(). Otherwise this method has no side effects. +func (c *Color) EnableColor() { + c.noColor = boolPtr(false) +} + +func (c *Color) isNoColorSet() bool { + // check first if we have user setted action + if c.noColor != nil { + return *c.noColor + } + + // if not return the global option, which is disabled by default + return NoColor +} + +// Equals returns a boolean value indicating whether two colors are equal. +func (c *Color) Equals(c2 *Color) bool { + if len(c.params) != len(c2.params) { + return false + } + + for _, attr := range c.params { + if !c2.attrExists(attr) { + return false + } + } + + return true +} + +func (c *Color) attrExists(a Attribute) bool { + for _, attr := range c.params { + if attr == a { + return true + } + } + + return false +} + +func boolPtr(v bool) *bool { + return &v +} + +func getCachedColor(p Attribute) *Color { + colorsCacheMu.Lock() + defer colorsCacheMu.Unlock() + + c, ok := colorsCache[p] + if !ok { + c = New(p) + colorsCache[p] = c + } + + return c +} + +func colorPrint(format string, p Attribute, a ...interface{}) { + c := getCachedColor(p) + + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + if len(a) == 0 { + c.Print(format) + } else { + c.Printf(format, a...) + } +} + +func colorString(format string, p Attribute, a ...interface{}) string { + c := getCachedColor(p) + + if len(a) == 0 { + return c.SprintFunc()(format) + } + + return c.SprintfFunc()(format, a...) +} + +// Black is an convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } + +// Red is an convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } + +// Green is an convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } + +// Yellow is an convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } + +// Blue is an convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } + +// Magenta is an convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } + +// Cyan is an convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } + +// White is an convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } + +// BlackString is an convenient helper function to return a string with black +// foreground. +func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } + +// RedString is an convenient helper function to return a string with red +// foreground. +func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } + +// GreenString is an convenient helper function to return a string with green +// foreground. +func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } + +// YellowString is an convenient helper function to return a string with yellow +// foreground. +func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } + +// BlueString is an convenient helper function to return a string with blue +// foreground. +func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } + +// MagentaString is an convenient helper function to return a string with magenta +// foreground. +func MagentaString(format string, a ...interface{}) string { + return colorString(format, FgMagenta, a...) +} + +// CyanString is an convenient helper function to return a string with cyan +// foreground. +func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } + +// WhiteString is an convenient helper function to return a string with white +// foreground. +func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go new file mode 100644 index 000000000..1e57812d7 --- /dev/null +++ b/vendor/github.com/fatih/color/doc.go @@ -0,0 +1,128 @@ +/* +Package color is an ANSI color package to output colorized or SGR defined +output to the standard output. The API can be used in several way, pick one +that suits you. + +Use simple and default helper functions with predefined foreground colors: + + color.Cyan("Prints text in cyan.") + + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") + + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") + +However there are times where custom color mixes are required. Below are some +examples to create custom color objects and use the print functions of each +separate color object. + + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") + + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") + + + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) + + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") + + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") + + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") + +You can create PrintXxx functions to simplify even more: + + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) + + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") + +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + + +Or create SprintXxx functions to mix strings with other non-colorized strings: + + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() + + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) + +Windows support is enabled by default. All Print functions works as intended. +However only for color.SprintXXX functions, user should use fmt.FprintXXX and +set the output to color.Output: + + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + +Using with existing code is possible. Just use the Set() method to set the +standard output to the given parameters. That way a rewrite of an existing +code is not required. + + // Use handy standard colors. + color.Set(color.FgYellow) + + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") + + color.Unset() // don't forget to unset + + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function + + fmt.Println("All text will be now bold magenta.") + +There might be a case where you want to disable color output (for example to +pipe the standard output of your app to somewhere else). `Color` has support to +disable colors both globally and for single color definition. For example +suppose you have a CLI app and a `--no-color` bool flag. You can easily disable +the color output with: + + var flagNoColor = flag.Bool("no-color", false, "Disable color output") + + if *flagNoColor { + color.NoColor = true // disables colorized output + } + +It also has support for single color definitions (local). You can +disable/enable color output on the fly: + + c := color.New(color.FgCyan) + c.Println("Prints cyan text") + + c.DisableColor() + c.Println("This is printed without any color") + + c.EnableColor() + c.Println("This prints again cyan...") +*/ +package color diff --git a/vendor/github.com/go-ini/ini/ini.go b/vendor/github.com/go-ini/ini/ini.go index 50abd815f..5211d5abc 100644 --- a/vendor/github.com/go-ini/ini/ini.go +++ b/vendor/github.com/go-ini/ini/ini.go @@ -37,7 +37,7 @@ const ( // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 - _VERSION = "1.23.0" + _VERSION = "1.27.0" ) // Version returns current package version literal. @@ -173,9 +173,13 @@ type LoadOptions struct { Insensitive bool // IgnoreContinuation indicates whether to ignore continuation lines while parsing. IgnoreContinuation bool + // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. + IgnoreInlineComment bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool + // AllowShadows indicates whether to keep track of keys with same name under same section. + AllowShadows bool // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise // conform to key/value pairs. Specify the names of those blocks here. UnparseableSections []string @@ -219,6 +223,12 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } +// InsensitiveLoad has exactly same functionality as Load function +// except it allows have shadow keys. +func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{AllowShadows: true}, source, others...) +} + // Empty returns an empty file object. func Empty() *File { // Ignore error here, we sure our data is good. @@ -311,6 +321,11 @@ func (f *File) Sections() []*Section { return sections } +// ChildSections returns a list of child sections of given section name. +func (f *File) ChildSections(name string) []*Section { + return f.Section(name).ChildSections() +} + // SectionStrings returns list of section names. func (f *File) SectionStrings() []string { list := make([]string, len(f.sectionList)) @@ -441,6 +456,7 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { } alignSpaces := bytes.Repeat([]byte(" "), alignLength) + KEY_LIST: for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { @@ -467,28 +483,33 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` } - if _, err = buf.WriteString(kname); err != nil { - return 0, err - } - if key.isBooleanType { - continue - } + for _, val := range key.ValueWithShadows() { + if _, err = buf.WriteString(kname); err != nil { + return 0, err + } - // Write out alignment spaces before "=" sign - if PrettyFormat { - buf.Write(alignSpaces[:alignLength-len(kname)]) - } + if key.isBooleanType { + if kname != sec.keyList[len(sec.keyList)-1] { + buf.WriteString(LineBreak) + } + continue KEY_LIST + } - val := key.value - // In case key value contains "\n", "`", "\"", "#" or ";" - if strings.ContainsAny(val, "\n`") { - val = `"""` + val + `"""` - } else if strings.ContainsAny(val, "#;") { - val = "`" + val + "`" - } - if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { - return 0, err + // Write out alignment spaces before "=" sign + if PrettyFormat { + buf.Write(alignSpaces[:alignLength-len(kname)]) + } + + // In case key value contains "\n", "`", "\"", "#" or ";" + if strings.ContainsAny(val, "\n`") { + val = `"""` + val + `"""` + } else if strings.ContainsAny(val, "#;") { + val = "`" + val + "`" + } + if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { + return 0, err + } } } diff --git a/vendor/github.com/go-ini/ini/key.go b/vendor/github.com/go-ini/ini/key.go index 9738c55a2..838356af0 100644 --- a/vendor/github.com/go-ini/ini/key.go +++ b/vendor/github.com/go-ini/ini/key.go @@ -15,6 +15,7 @@ package ini import ( + "errors" "fmt" "strconv" "strings" @@ -29,9 +30,42 @@ type Key struct { isAutoIncrement bool isBooleanType bool + isShadow bool + shadows []*Key + Comment string } +// newKey simply return a key object with given values. +func newKey(s *Section, name, val string) *Key { + return &Key{ + s: s, + name: name, + value: val, + } +} + +func (k *Key) addShadow(val string) error { + if k.isShadow { + return errors.New("cannot add shadow to another shadow key") + } else if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add shadow to auto-increment or boolean key") + } + + shadow := newKey(k.s, k.name, val) + shadow.isShadow = true + k.shadows = append(k.shadows, shadow) + return nil +} + +// AddShadow adds a new shadow key to itself. +func (k *Key) AddShadow(val string) error { + if !k.s.f.options.AllowShadows { + return errors.New("shadow key is not allowed") + } + return k.addShadow(val) +} + // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv type ValueMapper func(string) string @@ -45,16 +79,29 @@ func (k *Key) Value() string { return k.value } -// String returns string representation of value. -func (k *Key) String() string { - val := k.value +// ValueWithShadows returns raw values of key and its shadows if any. +func (k *Key) ValueWithShadows() []string { + if len(k.shadows) == 0 { + return []string{k.value} + } + vals := make([]string, len(k.shadows)+1) + vals[0] = k.value + for i := range k.shadows { + vals[i+1] = k.shadows[i].value + } + return vals +} + +// transformValue takes a raw value and transforms to its final string. +func (k *Key) transformValue(val string) string { if k.s.f.ValueMapper != nil { val = k.s.f.ValueMapper(val) } - if strings.Index(val, "%") == -1 { + + // Fail-fast if no indicate char found for recursive value + if !strings.Contains(val, "%") { return val } - for i := 0; i < _DEPTH_VALUES; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { @@ -78,6 +125,11 @@ func (k *Key) String() string { return val } +// String returns string representation of value. +func (k *Key) String() string { + return k.transformValue(k.value) +} + // Validate accepts a validate function which can // return modifed result as key value. func (k *Key) Validate(fn func(string) string) string { @@ -394,45 +446,65 @@ func (k *Key) Strings(delim string) []string { vals := strings.Split(str, delim) for i := range vals { + // vals[i] = k.transformValue(strings.TrimSpace(vals[i])) vals[i] = strings.TrimSpace(vals[i]) } return vals } +// StringsWithShadows returns list of string divided by given delimiter. +// Shadows will also be appended if any. +func (k *Key) StringsWithShadows(delim string) []string { + vals := k.ValueWithShadows() + results := make([]string, 0, len(vals)*2) + for i := range vals { + if len(vals) == 0 { + continue + } + + results = append(results, strings.Split(vals[i], delim)...) + } + + for i := range results { + results[i] = k.transformValue(strings.TrimSpace(results[i])) + } + return results +} + // Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Float64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, true, false) + vals, _ := k.parseFloat64s(k.Strings(delim), true, false) return vals } // Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Ints(delim string) []int { - vals, _ := k.getInts(delim, true, false) + vals, _ := k.parseInts(k.Strings(delim), true, false) return vals } // Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Int64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, true, false) + vals, _ := k.parseInt64s(k.Strings(delim), true, false) return vals } // Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uints(delim string) []uint { - vals, _ := k.getUints(delim, true, false) + vals, _ := k.parseUints(k.Strings(delim), true, false) return vals } // Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, true, false) + vals, _ := k.parseUint64s(k.Strings(delim), true, false) return vals } // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, true, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) return vals } @@ -445,41 +517,41 @@ func (k *Key) Times(delim string) []time.Time { // ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then // it will not be included to result list. func (k *Key) ValidFloat64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, false, false) + vals, _ := k.parseFloat64s(k.Strings(delim), false, false) return vals } // ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will // not be included to result list. func (k *Key) ValidInts(delim string) []int { - vals, _ := k.getInts(delim, false, false) + vals, _ := k.parseInts(k.Strings(delim), false, false) return vals } // ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, // then it will not be included to result list. func (k *Key) ValidInt64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, false, false) + vals, _ := k.parseInt64s(k.Strings(delim), false, false) return vals } // ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, // then it will not be included to result list. func (k *Key) ValidUints(delim string) []uint { - vals, _ := k.getUints(delim, false, false) + vals, _ := k.parseUints(k.Strings(delim), false, false) return vals } // ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned // integer, then it will not be included to result list. func (k *Key) ValidUint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, false, false) + vals, _ := k.parseUint64s(k.Strings(delim), false, false) return vals } // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, false, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) return vals } @@ -490,33 +562,33 @@ func (k *Key) ValidTimes(delim string) []time.Time { // StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. func (k *Key) StrictFloat64s(delim string) ([]float64, error) { - return k.getFloat64s(delim, false, true) + return k.parseFloat64s(k.Strings(delim), false, true) } // StrictInts returns list of int divided by given delimiter or error on first invalid input. func (k *Key) StrictInts(delim string) ([]int, error) { - return k.getInts(delim, false, true) + return k.parseInts(k.Strings(delim), false, true) } // StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. func (k *Key) StrictInt64s(delim string) ([]int64, error) { - return k.getInt64s(delim, false, true) + return k.parseInt64s(k.Strings(delim), false, true) } // StrictUints returns list of uint divided by given delimiter or error on first invalid input. func (k *Key) StrictUints(delim string) ([]uint, error) { - return k.getUints(delim, false, true) + return k.parseUints(k.Strings(delim), false, true) } // StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. func (k *Key) StrictUint64s(delim string) ([]uint64, error) { - return k.getUint64s(delim, false, true) + return k.parseUint64s(k.Strings(delim), false, true) } // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { - return k.getTimesFormat(format, delim, false, true) + return k.parseTimesFormat(format, k.Strings(delim), false, true) } // StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter @@ -525,9 +597,8 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } -// getFloat64s returns list of float64 divided by given delimiter. -func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]float64, error) { - strs := k.Strings(delim) +// parseFloat64s transforms strings to float64s. +func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseFloat(str, 64) @@ -541,9 +612,8 @@ func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]flo return vals, nil } -// getInts returns list of int divided by given delimiter. -func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, error) { - strs := k.Strings(delim) +// parseInts transforms strings to ints. +func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) for _, str := range strs { val, err := strconv.Atoi(str) @@ -557,9 +627,8 @@ func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, er return vals, nil } -// getInt64s returns list of int64 divided by given delimiter. -func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64, error) { - strs := k.Strings(delim) +// parseInt64s transforms strings to int64s. +func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseInt(str, 10, 64) @@ -573,9 +642,8 @@ func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64 return vals, nil } -// getUints returns list of uint divided by given delimiter. -func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, error) { - strs := k.Strings(delim) +// parseUints transforms strings to uints. +func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 0) @@ -589,9 +657,8 @@ func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, return vals, nil } -// getUint64s returns list of uint64 divided by given delimiter. -func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint64, error) { - strs := k.Strings(delim) +// parseUint64s transforms strings to uint64s. +func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 64) @@ -605,9 +672,8 @@ func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint return vals, nil } -// getTimesFormat parses with given format and returns list of time.Time divided by given delimiter. -func (k *Key) getTimesFormat(format, delim string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { - strs := k.Strings(delim) +// parseTimesFormat transforms strings to times in given format. +func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { vals := make([]time.Time, 0, len(strs)) for _, str := range strs { val, err := time.Parse(format, str) diff --git a/vendor/github.com/go-ini/ini/parser.go b/vendor/github.com/go-ini/ini/parser.go index b0aabe33b..6c0b10745 100644 --- a/vendor/github.com/go-ini/ini/parser.go +++ b/vendor/github.com/go-ini/ini/parser.go @@ -193,7 +193,7 @@ func hasSurroundedQuote(in string, quote byte) bool { strings.IndexByte(in[1:], quote) == len(in)-2 } -func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { +func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { return "", nil @@ -217,18 +217,21 @@ func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { return line[startIdx : pos+startIdx], nil } - // Won't be able to reach here if value only contains whitespace. + // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) - // Check continuation lines when desired. + // Check continuation lines when desired if !ignoreContinuation && line[len(line)-1] == '\\' { return p.readContinuationLines(line[:len(line)-1]) } - i := strings.IndexAny(line, "#;") - if i > -1 { - p.comment.WriteString(line[i:]) - line = strings.TrimSpace(line[:i]) + // Check if ignore inline comment + if !ignoreInlineComment { + i := strings.IndexAny(line, "#;") + if i > -1 { + p.comment.WriteString(line[i:]) + line = strings.TrimSpace(line[:i]) + } } // Trim single quotes @@ -318,11 +321,14 @@ func (f *File) parse(reader io.Reader) (err error) { if err != nil { // Treat as boolean key when desired, and whole line is key name. if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { - key, err := section.NewKey(string(line), "true") + kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) if err != nil { return err } - key.isBooleanType = true key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() continue @@ -338,17 +344,16 @@ func (f *File) parse(reader io.Reader) (err error) { p.count++ } - key, err := section.NewKey(kname, "") + value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment) + if err != nil { + return err + } + + key, err := section.NewKey(kname, value) if err != nil { return err } key.isAutoIncrement = isAutoIncr - - value, err := p.readValue(line[offset:], f.options.IgnoreContinuation) - if err != nil { - return err - } - key.SetValue(value) key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() } diff --git a/vendor/github.com/go-ini/ini/section.go b/vendor/github.com/go-ini/ini/section.go index 45d2f3bfd..94f7375ed 100644 --- a/vendor/github.com/go-ini/ini/section.go +++ b/vendor/github.com/go-ini/ini/section.go @@ -68,20 +68,33 @@ func (s *Section) NewKey(name, val string) (*Key, error) { } if inSlice(name, s.keyList) { - s.keys[name].value = val + if s.f.options.AllowShadows { + if err := s.keys[name].addShadow(val); err != nil { + return nil, err + } + } else { + s.keys[name].value = val + } return s.keys[name], nil } s.keyList = append(s.keyList, name) - s.keys[name] = &Key{ - s: s, - name: name, - value: val, - } + s.keys[name] = newKey(s, name, val) s.keysHash[name] = val return s.keys[name], nil } +// NewBooleanKey creates a new boolean type key to given section. +func (s *Section) NewBooleanKey(name string) (*Key, error) { + key, err := s.NewKey(name, "true") + if err != nil { + return nil, err + } + + key.isBooleanType = true + return key, nil +} + // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { // FIXME: change to section level lock? @@ -219,3 +232,17 @@ func (s *Section) DeleteKey(name string) { } } } + +// ChildSections returns a list of child sections of current section. +// For example, "[parent.child1]" and "[parent.child12]" are child sections +// of section "[parent]". +func (s *Section) ChildSections() []*Section { + prefix := s.name + "." + children := make([]*Section, 0, 3) + for _, name := range s.f.sectionList { + if strings.HasPrefix(name, prefix) { + children = append(children, s.f.sections[name]) + } + } + return children +} diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go index d00fb4b83..031c78b8e 100644 --- a/vendor/github.com/go-ini/ini/struct.go +++ b/vendor/github.com/go-ini/ini/struct.go @@ -78,8 +78,14 @@ func parseDelim(actual string) string { var reflectTime = reflect.TypeOf(time.Now()).Kind() // setSliceWithProperType sets proper values to slice based on its type. -func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { - strs := key.Strings(delim) +func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { + var strs []string + if allowShadow { + strs = key.StringsWithShadows(delim) + } else { + strs = key.Strings(delim) + } + numVals := len(strs) if numVals == 0 { return nil @@ -92,17 +98,17 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { case reflect.String: vals = strs case reflect.Int: - vals = key.Ints(delim) + vals, _ = key.parseInts(strs, true, false) case reflect.Int64: - vals = key.Int64s(delim) + vals, _ = key.parseInt64s(strs, true, false) case reflect.Uint: - vals = key.Uints(delim) + vals, _ = key.parseUints(strs, true, false) case reflect.Uint64: - vals = key.Uint64s(delim) + vals, _ = key.parseUint64s(strs, true, false) case reflect.Float64: - vals = key.Float64s(delim) + vals, _ = key.parseFloat64s(strs, true, false) case reflectTime: - vals = key.Times(delim) + vals, _ = key.parseTimesFormat(time.RFC3339, strs, true, false) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } @@ -133,7 +139,7 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, // because we want to use default value that is already assigned to strcut. -func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { +func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { switch t.Kind() { case reflect.String: if len(key.String()) == 0 { @@ -174,7 +180,7 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri } field.SetUint(uintVal) - case reflect.Float64: + case reflect.Float32, reflect.Float64: floatVal, err := key.Float64() if err != nil { return nil @@ -187,13 +193,25 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri } field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: - return setSliceWithProperType(key, field, delim) + return setSliceWithProperType(key, field, delim, allowShadow) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } +func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { + opts := strings.SplitN(tag, ",", 3) + rawName = opts[0] + if len(opts) > 1 { + omitEmpty = opts[1] == "omitempty" + } + if len(opts) > 2 { + allowShadow = opts[2] == "allowshadow" + } + return rawName, omitEmpty, allowShadow +} + func (s *Section) mapTo(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() @@ -209,8 +227,8 @@ func (s *Section) mapTo(val reflect.Value) error { continue } - opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty - fieldName := s.parseFieldName(tpField.Name, opts[0]) + rawName, _, allowShadow := parseTagOptions(tag) + fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } @@ -231,7 +249,8 @@ func (s *Section) mapTo(val reflect.Value) error { } if key, err := s.GetKey(fieldName); err == nil { - if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { + delim := parseDelim(tpField.Tag.Get("delim")) + if err = setWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } } diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go index 6c6a7d95f..e392575b3 100644 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -30,7 +30,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Protocol buffer deep copy and merge. -// TODO: MessageSet and RawMessage. +// TODO: RawMessage. package proto @@ -75,17 +75,24 @@ func Merge(dst, src Message) { } func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) for i := 0; i < in.NumField(); i++ { f := in.Type().Field(i) if strings.HasPrefix(f.Name, "XXX_") { continue } - mergeAny(out.Field(i), in.Field(i)) + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } - if emIn, ok := in.Addr().Interface().(extendableProto); ok { - emOut := out.Addr().Interface().(extendableProto) - mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap()) + if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } } uf := in.FieldByName("XXX_unrecognized") @@ -98,7 +105,10 @@ func mergeStruct(out, in reflect.Value) { } } -func mergeAny(out, in reflect.Value) { +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { if in.Type() == protoMessageType { if !in.IsNil() { if out.IsNil() { @@ -112,7 +122,21 @@ func mergeAny(out, in reflect.Value) { switch in.Kind() { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) case reflect.Map: if in.Len() == 0 { return @@ -127,7 +151,7 @@ func mergeAny(out, in reflect.Value) { switch elemKind { case reflect.Ptr: val = reflect.New(in.Type().Elem().Elem()) - mergeAny(val, in.MapIndex(key)) + mergeAny(val, in.MapIndex(key), false, nil) case reflect.Slice: val = in.MapIndex(key) val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) @@ -143,13 +167,21 @@ func mergeAny(out, in reflect.Value) { if out.IsNil() { out.Set(reflect.New(in.Elem().Type())) } - mergeAny(out.Elem(), in.Elem()) + mergeAny(out.Elem(), in.Elem(), true, nil) case reflect.Slice: if in.IsNil() { return } if in.Type().Elem().Kind() == reflect.Uint8 { // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + // Make a deep copy. // Append to []byte{} instead of []byte(nil) so that we never end up // with a nil result. @@ -167,7 +199,7 @@ func mergeAny(out, in reflect.Value) { default: for i := 0; i < n; i++ { x := reflect.Indirect(reflect.New(in.Type().Elem())) - mergeAny(x, in.Index(i)) + mergeAny(x, in.Index(i), false, nil) out.Set(reflect.Append(out, x)) } } @@ -184,7 +216,7 @@ func mergeExtension(out, in map[int32]Extension) { eOut := Extension{desc: eIn.desc} if eIn.value != nil { v := reflect.New(reflect.TypeOf(eIn.value)).Elem() - mergeAny(v, reflect.ValueOf(eIn.value)) + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) eOut.value = v.Interface() } if eIn.enc != nil { diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go index 129792ed1..aa207298f 100644 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -46,6 +46,10 @@ import ( // errOverflow is returned when an integer is too large to be represented. var errOverflow = errors.New("proto: integer overflow") +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + // The fundamental decoders that interpret bytes on the wire. // Those that take integer types all return uint64 and are // therefore of type valueDecoder. @@ -57,7 +61,6 @@ var errOverflow = errors.New("proto: integer overflow") // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func DecodeVarint(buf []byte) (x uint64, n int) { - // x, n already 0 for shift := uint(0); shift < 64; shift += 7 { if n >= len(buf) { return 0, 0 @@ -74,13 +77,7 @@ func DecodeVarint(buf []byte) (x uint64, n int) { return 0, 0 } -// DecodeVarint reads a varint-encoded integer from the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) DecodeVarint() (x uint64, err error) { - // x, err already 0 - +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { i := p.index l := len(p.buf) @@ -103,6 +100,107 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) { return } +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + // DecodeFixed64 reads a 64-bit integer from the Buffer. // This is the format for the // fixed64, sfixed64, and double protocol buffer types. @@ -314,10 +412,30 @@ func UnmarshalMerge(buf []byte, pb Message) error { return NewBuffer(buf).Unmarshal(pb) } +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +func (p *Buffer) DecodeGroup(pb Message) error { + typ, base, err := getbase(pb) + if err != nil { + return err + } + return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) +} + // Unmarshal parses the protocol buffer representation in the // Buffer and places the decoded result in pb. If the struct // underlying pb does not match the data in the buffer, the results can be // unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. func (p *Buffer) Unmarshal(pb Message) error { // If the object can unmarshal itself, let it. if u, ok := pb.(Unmarshaler); ok { @@ -356,6 +474,11 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group wire := int(u & 0x7) if wire == WireEndGroup { if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } return nil // input is satisfied } return fmt.Errorf("proto: %s: wiretype end group for non-group", st) @@ -368,15 +491,30 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group if !ok { // Maybe it's an extension? if prop.extendable { - if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) { + if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { if err = o.skip(st, tag, wire); err == nil { - ext := e.ExtensionMap()[int32(tag)] // may be missing + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing ext.enc = append(ext.enc, o.buf[oi:o.index]...) - e.ExtensionMap()[int32(tag)] = ext + extmap[int32(tag)] = ext } continue } } + // Maybe it's a oneof? + if prop.oneofUnmarshaler != nil { + m := structPointer_Interface(base, st).(Message) + // First return value indicates whether tag is a oneof field. + ok, err = prop.oneofUnmarshaler(m, tag, wire, o) + if err == ErrInternalBadWireType { + // Map the error to something more descriptive. + // Do the formatting here to save generated code space. + err = fmt.Errorf("bad wiretype for oneof field in %T", m) + } + if ok { + continue + } + } err = o.skipAndSave(st, tag, wire, base, prop.unrecField) continue } @@ -561,9 +699,13 @@ func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error return err } nb := int(nn) // number of bytes of encoded bools + fin := o.index + nb + if fin < o.index { + return errOverflow + } y := *v - for i := 0; i < nb; i++ { + for o.index < fin { u, err := p.valDec(o) if err != nil { return err @@ -675,7 +817,7 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { oi := o.index // index at the end of this map entry o.index -= len(raw) // move buffer back to start of map entry - mptr := structPointer_Map(base, p.field, p.mtype) // *map[K]V + mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V if mptr.Elem().IsNil() { mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) } @@ -727,8 +869,15 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { return fmt.Errorf("proto: bad map data tag %d", raw[0]) } } + keyelem, valelem := keyptr.Elem(), valptr.Elem() + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) + } - v.SetMapIndex(keyptr.Elem(), valptr.Elem()) + v.SetMapIndex(keyelem, valelem) return nil } diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go index 1512d605b..2b30f8462 100644 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -60,12 +60,20 @@ func (e *RequiredNotSetError) Error() string { } var ( - // ErrRepeatedHasNil is the error returned if Marshal is called with + // errRepeatedHasNil is the error returned if Marshal is called with // a struct with a repeated field containing a nil element. - ErrRepeatedHasNil = errors.New("proto: repeated field has nil element") + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") // ErrNil is the error returned if Marshal is called with nil. ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") ) // The fundamental encoders that put bytes on the wire. @@ -74,6 +82,10 @@ var ( const maxVarintBytes = 10 // maximum length of a varint +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum @@ -105,6 +117,11 @@ func (p *Buffer) EncodeVarint(x uint64) error { return nil } +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + return sizeVarint(x) +} + func sizeVarint(x uint64) (n int) { for { n++ @@ -217,10 +234,6 @@ func Marshal(pb Message) ([]byte, error) { } p := NewBuffer(nil) err := p.Marshal(pb) - var state errorState - if err != nil && !state.shouldContinue(err, nil) { - return nil, err - } if p.buf == nil && err == nil { // Return a non-nil slice on success. return []byte{}, nil @@ -228,6 +241,20 @@ func Marshal(pb Message) ([]byte, error) { return p.buf, err } +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + var state errorState + err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) + } + return err +} + // Marshal takes the protocol buffer // and encodes it into the wire format, writing the result to the // Buffer. @@ -235,11 +262,8 @@ func (p *Buffer) Marshal(pb Message) error { // Can the object marshal itself? if m, ok := pb.(Marshaler); ok { data, err := m.Marshal() - if err != nil { - return err - } p.buf = append(p.buf, data...) - return nil + return err } t, base, err := getbase(pb) @@ -251,9 +275,12 @@ func (p *Buffer) Marshal(pb Message) error { } if collectStats { - stats.Encode++ + (stats).Encode++ // Parens are to work around a goimports bug. } + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } return err } @@ -275,7 +302,7 @@ func Size(pb Message) (n int) { } if collectStats { - stats.Size++ + (stats).Size++ // Parens are to work around a goimports bug. } return @@ -318,7 +345,7 @@ func size_bool(p *Properties, base structPointer) int { func size_proto3_bool(p *Properties, base structPointer) int { v := *structPointer_BoolVal(base, p.field) - if !v { + if !v && !p.oneof { return 0 } return len(p.tagcode) + 1 // each bool takes exactly one byte @@ -361,7 +388,7 @@ func size_int32(p *Properties, base structPointer) (n int) { func size_proto3_int32(p *Properties, base structPointer) (n int) { v := structPointer_Word32Val(base, p.field) x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { + if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) @@ -407,7 +434,7 @@ func size_uint32(p *Properties, base structPointer) (n int) { func size_proto3_uint32(p *Properties, base structPointer) (n int) { v := structPointer_Word32Val(base, p.field) x := word32Val_Get(v) - if x == 0 { + if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) @@ -452,7 +479,7 @@ func size_int64(p *Properties, base structPointer) (n int) { func size_proto3_int64(p *Properties, base structPointer) (n int) { v := structPointer_Word64Val(base, p.field) x := word64Val_Get(v) - if x == 0 { + if x == 0 && !p.oneof { return 0 } n += len(p.tagcode) @@ -495,7 +522,7 @@ func size_string(p *Properties, base structPointer) (n int) { func size_proto3_string(p *Properties, base structPointer) (n int) { v := *structPointer_StringVal(base, p.field) - if v == "" { + if v == "" && !p.oneof { return 0 } n += len(p.tagcode) @@ -529,7 +556,7 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { } o.buf = append(o.buf, p.tagcode...) o.EncodeRawBytes(data) - return nil + return state.err } o.buf = append(o.buf, p.tagcode...) @@ -667,7 +694,7 @@ func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error func size_slice_byte(p *Properties, base structPointer) (n int) { s := *structPointer_Bytes(base, p.field) - if s == nil { + if s == nil && !p.oneof { return 0 } n += len(p.tagcode) @@ -677,7 +704,7 @@ func size_slice_byte(p *Properties, base structPointer) (n int) { func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { + if len(s) == 0 && !p.oneof { return 0 } n += len(p.tagcode) @@ -939,7 +966,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err for i := 0; i < l; i++ { structp := s.Index(i) if structPointer_IsNil(structp) { - return ErrRepeatedHasNil + return errRepeatedHasNil } // Can the object marshal itself? @@ -958,7 +985,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err err := o.enc_len_struct(p.sprop, structp, &state) if err != nil && !state.shouldContinue(err, nil) { if err == ErrNil { - return ErrRepeatedHasNil + return errRepeatedHasNil } return err } @@ -980,7 +1007,6 @@ func size_slice_struct_message(p *Properties, base structPointer) (n int) { if p.isMarshaler { m := structPointer_Interface(structp, p.stype).(Marshaler) data, _ := m.Marshal() - n += len(p.tagcode) n += sizeRawBytes(data) continue } @@ -1001,7 +1027,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error for i := 0; i < l; i++ { b := s.Index(i) if structPointer_IsNil(b) { - return ErrRepeatedHasNil + return errRepeatedHasNil } o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) @@ -1010,7 +1036,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error if err != nil && !state.shouldContinue(err, nil) { if err == ErrNil { - return ErrRepeatedHasNil + return errRepeatedHasNil } return err } @@ -1039,10 +1065,32 @@ func size_slice_struct_group(p *Properties, base structPointer) (n int) { // Encode an extension map. func (o *Buffer) enc_map(p *Properties, base structPointer) error { - v := *structPointer_ExtMap(base, p.field) - if err := encodeExtensionMap(v); err != nil { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { return err } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + + v, mu := exts.extensionsRead() + if v == nil { + return nil + } + + mu.Lock() + defer mu.Unlock() + if err := encodeExtensionsMap(v); err != nil { + return err + } + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { // Fast-path for common cases: zero or one extensions. if len(v) <= 1 { for _, e := range v { @@ -1065,8 +1113,13 @@ func (o *Buffer) enc_map(p *Properties, base structPointer) error { } func size_map(p *Properties, base structPointer) int { - v := *structPointer_ExtMap(base, p.field) - return sizeExtensionMap(v) + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) } // Encode a map field. @@ -1084,7 +1137,7 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { repeated MapFieldEntry map_field = N; */ - v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V if v.Len() == 0 { return nil } @@ -1095,15 +1148,14 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { return err } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil { + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { return err } return nil } - keys := v.MapKeys() - sort.Sort(mapKeys(keys)) - for _, key := range keys { + // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. + for _, key := range v.MapKeys() { val := v.MapIndex(key) keycopy.Set(key) @@ -1118,7 +1170,7 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { } func size_new_map(p *Properties, base structPointer) int { - v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) @@ -1128,10 +1180,12 @@ func size_new_map(p *Properties, base structPointer) int { keycopy.Set(key) valcopy.Set(val) - // Tag codes are two bytes per map entry. - n += 2 - n += p.mkeyprop.size(p.mkeyprop, keybase) - n += p.mvalprop.size(p.mvalprop, valbase) + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry } return n } @@ -1184,16 +1238,35 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { if p.Required && state.err == nil { state.err = &RequiredNotSetError{p.Name} } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") } else if !state.shouldContinue(err, p) { return err } } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } + } + } + + // Do oneof fields. + if prop.oneofMarshaler != nil { + m := structPointer_Interface(base, prop.stype).(Message) + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { + return err } } // Add unrecognized fields at the end. if prop.unrecField.IsValid() { v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } if len(v) > 0 { o.buf = append(o.buf, v...) } @@ -1216,6 +1289,12 @@ func size_struct(prop *StructProperties, base structPointer) (n int) { n += len(v) } + // Factor in any oneof fields. + if prop.oneofSizer != nil { + m := structPointer_Interface(base, prop.stype).(Message) + n += prop.oneofSizer(m) + } + return } diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go index d8673a3e9..2ed1cf596 100644 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -30,7 +30,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Protocol buffer comparison. -// TODO: MessageSet. package proto @@ -51,15 +50,21 @@ Equality is defined in this way: are equal, and extensions sets are equal. - Two set scalar fields are equal iff their values are equal. If the fields are of a floating-point type, remember that - NaN != x for all x, including NaN. + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). - Two repeated fields are equal iff their lengths are the same, - and their corresponding elements are equal (a "bytes" field, - although represented by []byte, is not a repeated field) + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. - Two unset fields are equal. - Two unknown field sets are equal if their current encoded state is equal. - Two extension sets are equal iff they have corresponding elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. - Every other combination of things are not equal. The return value is undefined if a and b are not protocol buffers. @@ -89,6 +94,7 @@ func Equal(a, b Message) bool { // v1 and v2 are known to have the same type. func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) for i := 0; i < v1.NumField(); i++ { f := v1.Type().Field(i) if strings.HasPrefix(f.Name, "XXX_") { @@ -114,14 +120,21 @@ func equalStruct(v1, v2 reflect.Value) bool { } f1, f2 = f1.Elem(), f2.Elem() } - if !equalAny(f1, f2) { + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { return false } } if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { em2 := v2.FieldByName("XXX_extensions") - if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { return false } } @@ -141,7 +154,8 @@ func equalStruct(v1, v2 reflect.Value) bool { } // v1 and v2 are known to have the same type. -func equalAny(v1, v2 reflect.Value) bool { +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { if v1.Type() == protoMessageType { m1, _ := v1.Interface().(Message) m2, _ := v2.Interface().(Message) @@ -154,6 +168,17 @@ func equalAny(v1, v2 reflect.Value) bool { return v1.Float() == v2.Float() case reflect.Int32, reflect.Int64: return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) case reflect.Map: if v1.Len() != v2.Len() { return false @@ -164,16 +189,29 @@ func equalAny(v1, v2 reflect.Value) bool { // This key was not found in the second map. return false } - if !equalAny(v1.MapIndex(key), val2) { + if !equalAny(v1.MapIndex(key), val2, nil) { return false } } return true case reflect.Ptr: - return equalAny(v1.Elem(), v2.Elem()) + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) case reflect.Slice: if v1.Type().Elem().Kind() == reflect.Uint8 { // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } if v1.IsNil() != v2.IsNil() { return false } @@ -184,7 +222,7 @@ func equalAny(v1, v2 reflect.Value) bool { return false } for i := 0; i < v1.Len(); i++ { - if !equalAny(v1.Index(i), v2.Index(i)) { + if !equalAny(v1.Index(i), v2.Index(i), prop) { return false } } @@ -203,8 +241,14 @@ func equalAny(v1, v2 reflect.Value) bool { } // base is the struct type that the extensions are based on. -// em1 and em2 are extension maps. -func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { if len(em1) != len(em2) { return false } @@ -219,7 +263,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { if m1 != nil && m2 != nil { // Both are unencoded. - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { return false } continue @@ -247,7 +291,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) return false } - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { return false } } diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go index f7667fab4..eaad21831 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -37,6 +37,7 @@ package proto import ( "errors" + "fmt" "reflect" "strconv" "sync" @@ -51,14 +52,99 @@ type ExtensionRange struct { Start, End int32 // both inclusive } -// extendableProto is an interface implemented by any protocol buffer that may be extended. +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { Message ExtensionRangeArray() []ExtensionRange ExtensionMap() map[int32]Extension } +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. @@ -68,6 +154,7 @@ type ExtensionDesc struct { Field int32 // field number Name string // fully-qualified name of extension, for text formatting Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined } func (ed *ExtensionDesc) repeated() bool { @@ -91,8 +178,13 @@ type Extension struct { } // SetRawExtension is for testing only. -func SetRawExtension(base extendableProto, id int32, b []byte) { - base.ExtensionMap()[id] = Extension{enc: b} +func SetRawExtension(base Message, id int32, b []byte) { + epb, ok := extendable(base) + if !ok { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} } // isExtensionField returns true iff the given field number is in an extension range. @@ -107,8 +199,12 @@ func isExtensionField(pb extendableProto, field int32) bool { // checkExtensionTypes checks that the given extension is valid for pb. func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb // Check the extended type. - if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) } // Check the range. @@ -154,8 +250,19 @@ func extensionProperties(ed *ExtensionDesc) *Properties { return prop } -// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. -func encodeExtensionMap(m map[int32]Extension) error { +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { for k, e := range m { if e.value == nil || e.desc == nil { // Extension is only in its encoded form. @@ -183,7 +290,17 @@ func encodeExtensionMap(m map[int32]Extension) error { return nil } -func sizeExtensionMap(m map[int32]Extension) (n int) { +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) +} + +func extensionsMapSize(m map[int32]Extension) (n int) { for _, e := range m { if e.value == nil || e.desc == nil { // Extension is only in its encoded form. @@ -208,30 +325,58 @@ func sizeExtensionMap(m map[int32]Extension) (n int) { } // HasExtension returns whether the given extension is present in pb. -func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { +func HasExtension(pb Message, extension *ExtensionDesc) bool { // TODO: Check types, field numbers, etc.? - _, ok := pb.ExtensionMap()[extension.Field] + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() return ok } // ClearExtension removes the given extension from pb. -func ClearExtension(pb extendableProto, extension *ExtensionDesc) { +func ClearExtension(pb Message, extension *ExtensionDesc) { + epb, ok := extendable(pb) + if !ok { + return + } // TODO: Check types, field numbers, etc.? - delete(pb.ExtensionMap(), extension.Field) + extmap := epb.extensionsWrite() + delete(extmap, extension.Field) } // GetExtension parses and returns the given extension of pb. -// If the extension is not present it returns ErrMissingExtension. -func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) { - if err := checkExtensionTypes(pb, extension); err != nil { +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + + if err := checkExtensionTypes(epb, extension); err != nil { return nil, err } - emap := pb.ExtensionMap() + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() e, ok := emap[extension.Field] if !ok { - return nil, ErrMissingExtension + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) } + if e.value != nil { // Already decoded. Check the descriptor, though. if e.desc != extension { @@ -257,12 +402,46 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er return e.value, nil } +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + // decodeExtension decodes an extension encoded in b. func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { o := NewBuffer(b) t := reflect.TypeOf(extension.ExtensionType) - rep := extension.repeated() props := extensionProperties(extension) @@ -284,7 +463,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { return nil, err } - if !rep || o.index >= len(o.buf) { + if o.index >= len(o.buf) { break } } @@ -294,10 +473,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := pb.(extendableProto) + epb, ok := extendable(pb) if !ok { - err = errors.New("proto: not an extendable proto") - return + return nil, errors.New("proto: not an extendable proto") } extensions = make([]interface{}, len(es)) for i, e := range es { @@ -312,20 +490,76 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e return } +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + // SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { - if err := checkExtensionTypes(pb, extension); err != nil { +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { return errors.New("proto: bad extension value type") } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } - pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} return nil } +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + // A global registry of extensions. // The generated code will register the generated descriptors by calling RegisterExtension. diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go index f81052f2a..ac4ddbc07 100644 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -30,179 +30,237 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* - Package proto converts data structures to and from the wire format of - protocol buffers. It works in concert with the Go source code generated - for .proto files by the protocol compiler. +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. - A summary of the properties of the protocol buffer interface - for a protocol buffer variable v: +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. - - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Marshal and Unmarshal are functions to encode and decode the wire format. + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. - The simplest way to describe this is to see an example. - Given file test.proto, containing +When the .proto file specifies `syntax="proto3"`, there are some differences: - package example; + - Non-repeated fields of non-message type are values instead of pointers. + - Getters are only generated for message and oneof fields. + - Enum types do not get an Enum method. - enum FOO { X = 17; } +The simplest way to describe this is to see an example. +Given file test.proto, containing - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/golang/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err } + *x = FOO(value) + return nil + } - The resulting file, test.pb.go, is: + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} - package example + type isTest_Union interface { + isTest_Union() + } - import proto "github.com/golang/protobuf/proto" - import math "math" + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } - type FOO int32 - const ( - FOO_X FOO = 17 - ) - var FOO_name = map[int32]string{ - 17: "X", + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union } - var FOO_value = map[string]int32{ - "X": 17, + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label } + return "" + } - func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type } - func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup } - func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data) - if err != nil { - return err - } - *x = FOO(value) - return nil + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField } + return "" + } - type Test struct { - Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` - Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` - Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` - Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` - XXX_unrecognized []byte `json:"-"` + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number } - func (m *Test) Reset() { *m = Test{} } - func (m *Test) String() string { return proto.CompactTextString(m) } - func (*Test) ProtoMessage() {} - const Default_Test_Type int32 = 77 + return 0 + } - func (m *Test) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name } + return "" + } - func (m *Test) GetType() int32 { - if m != nil && m.Type != nil { - return *m.Type - } - return Default_Test_Type + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, } - - func (m *Test) GetOptionalgroup() *Test_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) } - - type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) } - func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } - func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - - func (m *Test_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) } - - func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) - } - - To create and play with a Test object: - - package main - - import ( - "log" - - "github.com/golang/protobuf/proto" - pb "./example.pb" - ) - - func main() { - test := &pb.Test{ - Label: proto.String("hello"), - Type: proto.Int32(17), - Optionalgroup: &pb.Test_OptionalGroup{ - RequiredField: proto.String("good bye"), - }, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &pb.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // etc. + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. } + // etc. + } */ package proto @@ -211,6 +269,7 @@ import ( "fmt" "log" "reflect" + "sort" "strconv" "sync" ) @@ -249,7 +308,7 @@ func GetStats() Stats { return stats } // temporary Buffer and are fine for most applications. type Buffer struct { buf []byte // encode/decode byte stream - index int // write point + index int // read point // pools of basic types to amortize allocation. bools []bool @@ -385,13 +444,13 @@ func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, // DebugPrint dumps the encoded data in b in a debugging format with a header // including the string s. Used in testing but made available for general debugging. -func (o *Buffer) DebugPrint(s string, b []byte) { +func (p *Buffer) DebugPrint(s string, b []byte) { var u uint64 - obuf := o.buf - index := o.index - o.buf = b - o.index = 0 + obuf := p.buf + index := p.index + p.buf = b + p.index = 0 depth := 0 fmt.Printf("\n--- %s ---\n", s) @@ -402,12 +461,12 @@ out: fmt.Print(" ") } - index := o.index - if index == len(o.buf) { + index := p.index + if index == len(p.buf) { break } - op, err := o.DecodeVarint() + op, err := p.DecodeVarint() if err != nil { fmt.Printf("%3d: fetching op err %v\n", index, err) break out @@ -424,7 +483,7 @@ out: case WireBytes: var r []byte - r, err = o.DecodeRawBytes(false) + r, err = p.DecodeRawBytes(false) if err != nil { break out } @@ -445,7 +504,7 @@ out: fmt.Printf("\n") case WireFixed32: - u, err = o.DecodeFixed32() + u, err = p.DecodeFixed32() if err != nil { fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) break out @@ -453,16 +512,15 @@ out: fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) case WireFixed64: - u, err = o.DecodeFixed64() + u, err = p.DecodeFixed64() if err != nil { fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) - break case WireVarint: - u, err = o.DecodeVarint() + u, err = p.DecodeVarint() if err != nil { fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) break out @@ -470,30 +528,22 @@ out: fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) case WireStartGroup: - if err != nil { - fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err) - break out - } fmt.Printf("%3d: t=%3d start\n", index, tag) depth++ case WireEndGroup: depth-- - if err != nil { - fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err) - break out - } fmt.Printf("%3d: t=%3d end\n", index, tag) } } if depth != 0 { - fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth) + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) } fmt.Printf("\n") - o.buf = obuf - o.index = index + p.buf = obuf + p.index = index } // SetDefaults sets unset protocol buffer fields to their default values. @@ -607,13 +657,15 @@ func setDefaults(v reflect.Value, recur, zeros bool) { for _, ni := range dm.nested { f := v.Field(ni) - if f.IsNil() { - continue - } - // f is *T or []*T - if f.Kind() == reflect.Ptr { + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } setDefaults(f, recur, zeros) - } else { + + case reflect.Slice: for i := 0; i < f.Len(); i++ { e := f.Index(i) if e.IsNil() { @@ -621,6 +673,15 @@ func setDefaults(v reflect.Value, recur, zeros bool) { } setDefaults(e, recur, zeros) } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } } } } @@ -646,10 +707,6 @@ type scalarField struct { value interface{} // the proto-declared default value, or nil } -func ptrToStruct(t reflect.Type) bool { - return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct -} - // t is a struct type. func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { sprop := GetProperties(t) @@ -661,99 +718,181 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { } ft := t.Field(fi).Type - // nested messages - if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) { + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: dm.nested = append(dm.nested, fi) - continue + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) } - - sf := scalarField{ - index: fi, - kind: ft.Elem().Kind(), - } - - // scalar fields without defaults - if !prop.HasDefault { - dm.scalars = append(dm.scalars, sf) - continue - } - - // a scalar field: either *T or []byte - switch ft.Elem().Kind() { - case reflect.Bool: - x, err := strconv.ParseBool(prop.Default) - if err != nil { - log.Printf("proto: bad default bool %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.Float32: - x, err := strconv.ParseFloat(prop.Default, 32) - if err != nil { - log.Printf("proto: bad default float32 %q: %v", prop.Default, err) - continue - } - sf.value = float32(x) - case reflect.Float64: - x, err := strconv.ParseFloat(prop.Default, 64) - if err != nil { - log.Printf("proto: bad default float64 %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.Int32: - x, err := strconv.ParseInt(prop.Default, 10, 32) - if err != nil { - log.Printf("proto: bad default int32 %q: %v", prop.Default, err) - continue - } - sf.value = int32(x) - case reflect.Int64: - x, err := strconv.ParseInt(prop.Default, 10, 64) - if err != nil { - log.Printf("proto: bad default int64 %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.String: - sf.value = prop.Default - case reflect.Uint8: - // []byte (not *uint8) - sf.value = []byte(prop.Default) - case reflect.Uint32: - x, err := strconv.ParseUint(prop.Default, 10, 32) - if err != nil { - log.Printf("proto: bad default uint32 %q: %v", prop.Default, err) - continue - } - sf.value = uint32(x) - case reflect.Uint64: - x, err := strconv.ParseUint(prop.Default, 10, 64) - if err != nil { - log.Printf("proto: bad default uint64 %q: %v", prop.Default, err) - continue - } - sf.value = x - default: - log.Printf("proto: unhandled def kind %v", ft.Elem().Kind()) - continue - } - - dm.scalars = append(dm.scalars, sf) } return dm } +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + // Map fields may have key types of non-float scalars, strings and enums. // The easiest way to sort them in some deterministic order is to use fmt. // If this turns out to be inefficient we can always consider other options, // such as doing a Schwartzian transform. -type mapKeys []reflect.Value +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{ + vs: vs, + // default Less function: textual comparison + less: func(a, b reflect.Value) bool { + return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) + }, + } -func (s mapKeys) Len() int { return len(s) } -func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s mapKeys) Less(i, j int) bool { - return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface()) + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; + // numeric keys are sorted numerically. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + } + + return s } + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion1 = true diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go index 9d912bce1..fd982decd 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -44,11 +44,11 @@ import ( "sort" ) -// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID. +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. // A message type ID is required for storing a protocol buffer in a message set. -var ErrNoMessageTypeId = errors.New("proto does not have a message type ID") +var errNoMessageTypeID = errors.New("proto does not have a message type ID") -// The first two types (_MessageSet_Item and MessageSet) +// The first two types (_MessageSet_Item and messageSet) // model what the protocol compiler produces for the following protocol message: // message MessageSet { // repeated group Item = 1 { @@ -58,27 +58,20 @@ var ErrNoMessageTypeId = errors.New("proto does not have a message type ID") // } // That is the MessageSet wire format. We can't use a proto to generate these // because that would introduce a circular dependency between it and this package. -// -// When a proto1 proto has a field that looks like: -// optional message info = 3; -// the protocol compiler produces a field in the generated struct that looks like: -// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"` -// The package is automatically inserted so there is no need for that proto file to -// import this package. type _MessageSet_Item struct { TypeId *int32 `protobuf:"varint,2,req,name=type_id"` Message []byte `protobuf:"bytes,3,req,name=message"` } -type MessageSet struct { +type messageSet struct { Item []*_MessageSet_Item `protobuf:"group,1,rep"` XXX_unrecognized []byte // TODO: caching? } -// Make sure MessageSet is a Message. -var _ Message = (*MessageSet)(nil) +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) // messageTypeIder is an interface satisfied by a protocol buffer type // that may be stored in a MessageSet. @@ -86,7 +79,7 @@ type messageTypeIder interface { MessageTypeId() int32 } -func (ms *MessageSet) find(pb Message) *_MessageSet_Item { +func (ms *messageSet) find(pb Message) *_MessageSet_Item { mti, ok := pb.(messageTypeIder) if !ok { return nil @@ -100,24 +93,24 @@ func (ms *MessageSet) find(pb Message) *_MessageSet_Item { return nil } -func (ms *MessageSet) Has(pb Message) bool { +func (ms *messageSet) Has(pb Message) bool { if ms.find(pb) != nil { return true } return false } -func (ms *MessageSet) Unmarshal(pb Message) error { +func (ms *messageSet) Unmarshal(pb Message) error { if item := ms.find(pb); item != nil { return Unmarshal(item.Message, pb) } if _, ok := pb.(messageTypeIder); !ok { - return ErrNoMessageTypeId + return errNoMessageTypeID } return nil // TODO: return error instead? } -func (ms *MessageSet) Marshal(pb Message) error { +func (ms *messageSet) Marshal(pb Message) error { msg, err := Marshal(pb) if err != nil { return err @@ -130,7 +123,7 @@ func (ms *MessageSet) Marshal(pb Message) error { mti, ok := pb.(messageTypeIder) if !ok { - return ErrNoMessageTypeId + return errNoMessageTypeID } mtid := mti.MessageTypeId() @@ -141,9 +134,9 @@ func (ms *MessageSet) Marshal(pb Message) error { return nil } -func (ms *MessageSet) Reset() { *ms = MessageSet{} } -func (ms *MessageSet) String() string { return CompactTextString(ms) } -func (*MessageSet) ProtoMessage() {} +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} // Support for the message_set_wire_format message option. @@ -156,9 +149,21 @@ func skipVarint(buf []byte) []byte { // MarshalMessageSet encodes the extension map represented by m in the message set wire format. // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { - if err := encodeExtensionMap(m); err != nil { - return nil, err +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") } // Sort extension IDs to provide a deterministic encoding. @@ -169,7 +174,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { } sort.Ints(ids) - ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} for _, id := range ids { e := m[int32(id)] // Remove the wire type and field number varint, as well as the length varint. @@ -185,8 +190,18 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { - ms := new(MessageSet) +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) if err := Unmarshal(buf, ms); err != nil { return err } @@ -216,7 +231,16 @@ func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { // MarshalMessageSetJSON encodes the extension map represented by m in JSON format. // It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } var b bytes.Buffer b.WriteByte('{') @@ -259,7 +283,7 @@ func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { // UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. // It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error { +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { // Common-case fast path. if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { return nil diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go index c68b12525..fb512e2e1 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build appengine +// +build appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can @@ -139,13 +139,18 @@ func structPointer_StringSlice(p structPointer, f field) *[]string { return structPointer_ifield(p, f).(*[]string) } +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + // ExtMap returns the address of an extension map field in the struct. func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return structPointer_ifield(p, f).(*map[int32]Extension) } -// Map returns the reflect.Value for the address of a map field in the struct. -func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { return structPointer_field(p, f).Addr() } diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go index 48bc0fa48..6b5567d47 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build !appengine +// +build !appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. @@ -126,12 +126,16 @@ func structPointer_StringSlice(p structPointer, f field) *[]string { } // ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) } -// Map returns the reflect.Value for the address of a map field in the struct. -func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) } diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go index 730a59579..ec2289c00 100644 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -37,6 +37,7 @@ package proto import ( "fmt" + "log" "os" "reflect" "sort" @@ -84,6 +85,15 @@ type decoder func(p *Buffer, prop *Properties, base structPointer) error // A valueDecoder decodes a single integer in a particular encoding. type valueDecoder func(o *Buffer) (x uint64, err error) +// A oneofMarshaler does the marshaling for all oneof fields in a message. +type oneofMarshaler func(Message, *Buffer) error + +// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. +type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) + +// A oneofSizer does the sizing for all oneof fields in a message. +type oneofSizer func(Message) int + // tagMap is an optimization over map[int]int for typical protocol buffer // use-cases. Encoded protocol buffers are often in tag order with small tag // numbers. @@ -132,6 +142,22 @@ type StructProperties struct { order []int // list of struct field numbers in tag order unrecField field // field id of the XXX_unrecognized []byte field extendable bool // is this an extendable proto + + oneofMarshaler oneofMarshaler + oneofUnmarshaler oneofUnmarshaler + oneofSizer oneofSizer + stype reflect.Type + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties } // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. @@ -147,6 +173,7 @@ func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order type Properties struct { Name string // name of the field, for error messages OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc Wire string WireType int Tag int @@ -156,6 +183,7 @@ type Properties struct { Packed bool // relevant for repeated primitives only Enum string // set for enum types only proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field Default string // default value HasDefault bool // whether an explicit default was provided @@ -202,12 +230,16 @@ func (p *Properties) String() string { if p.Packed { s += ",packed" } - if p.OrigName != p.Name { - s += ",name=" + p.OrigName + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName } if p.proto3 { s += ",proto3" } + if p.oneof { + s += ",oneof" + } if len(p.Enum) > 0 { s += ",enum=" + p.Enum } @@ -280,10 +312,14 @@ func (p *Properties) Parse(s string) { p.Packed = true case strings.HasPrefix(f, "name="): p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] case strings.HasPrefix(f, "enum="): p.Enum = f[5:] case f == "proto3": p.proto3 = true + case f == "oneof": + p.oneof = true case strings.HasPrefix(f, "def="): p.HasDefault = true p.Default = f[4:] // rest of string @@ -437,12 +473,13 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock p.dec = (*Buffer).dec_slice_int64 p.packedDec = (*Buffer).dec_slice_packed_int64 case reflect.Uint8: - p.enc = (*Buffer).enc_slice_byte p.dec = (*Buffer).dec_slice_byte - p.size = size_slice_byte if p.proto3 { p.enc = (*Buffer).enc_proto3_slice_byte p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte } case reflect.Float32, reflect.Float64: switch t2.Bits() { @@ -595,7 +632,7 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF } var ( - mutex sync.Mutex + propertiesMu sync.RWMutex propertiesMap = make(map[reflect.Type]*StructProperties) ) @@ -605,13 +642,26 @@ func GetProperties(t reflect.Type) *StructProperties { if t.Kind() != reflect.Struct { panic("proto: type must have kind struct") } - mutex.Lock() - sprop := getPropertiesLocked(t) - mutex.Unlock() + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() return sprop } -// getPropertiesLocked requires that mutex is held. +// getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { if collectStats { @@ -628,7 +678,8 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { propertiesMap[t] = prop // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) @@ -639,14 +690,22 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - if f.Name == "XXX_extensions" { // special case + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case p.enc = (*Buffer).enc_map p.dec = nil // not needed p.size = size_map - } - if f.Name == "XXX_unrecognized" { // special case + } else if f.Name == "XXX_unrecognized" { // special case prop.unrecField = toField(&f) } + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } prop.Prop[i] = p prop.order[i] = i if debug { @@ -656,7 +715,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } print("\n") } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") { + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") } } @@ -664,6 +723,41 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { // Re-order prop.order. sort.Sort(prop) + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + var oots []interface{} + prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() + prop.stype = t + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + // build required counts // build tags reqCount := 0 @@ -722,3 +816,57 @@ func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[ } enumValueMaps[typeName] = valueMap } + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypes = make(map[string]reflect.Type) + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypes[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go index 720eac470..965876bf0 100644 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -37,11 +37,11 @@ import ( "bufio" "bytes" "encoding" + "errors" "fmt" "io" "log" "math" - "os" "reflect" "sort" "strings" @@ -154,7 +154,7 @@ func (w *textWriter) indent() { w.ind++ } func (w *textWriter) unindent() { if w.ind == 0 { - log.Printf("proto: textWriter unindented too far") + log.Print("proto: textWriter unindented too far") return } w.ind-- @@ -170,20 +170,98 @@ func writeName(w *textWriter, props *Properties) error { return nil } -var ( - messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem() -) - // raw is the interface satisfied by RawMessage. type raw interface { Bytes() []byte } -func writeStruct(w *textWriter, sv reflect.Value) error { - if sv.Type() == messageSetType { - return writeMessageSet(w, sv.Addr().Interface().(*MessageSet)) +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") } + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } st := sv.Type() sprops := GetProperties(st) for i := 0; i < sv.NumField(); i++ { @@ -235,7 +313,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } continue } - if err := writeAny(w, v, props); err != nil { + if err := tm.writeAny(w, v, props); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -246,7 +324,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } if fv.Kind() == reflect.Map { // Map fields are rendered as a repeated struct with key/value fields. - keys := fv.MapKeys() // TODO: should we sort these for deterministic output? + keys := fv.MapKeys() sort.Sort(mapKeys(keys)) for _, key := range keys { val := fv.MapIndex(key) @@ -277,26 +355,29 @@ func writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if err := writeAny(w, key, props.mkeyprop); err != nil { + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } - // value - if _, err := w.WriteString("value:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { return err } - } - if err := writeAny(w, val, props.mvalprop); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err } // close struct w.unindent() @@ -315,26 +396,34 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { // proto3 non-repeated scalar field; skip if zero value - switch fv.Kind() { - case reflect.Bool: - if !fv.Bool() { + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { continue } - case reflect.Int32, reflect.Int64: - if fv.Int() == 0 { - continue - } - case reflect.Uint32, reflect.Uint64: - if fv.Uint() == 0 { - continue - } - case reflect.Float32, reflect.Float64: - if fv.Float() == 0 { - continue - } - case reflect.String: - if fv.String() == "" { - continue + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() } } } @@ -355,7 +444,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error { } // Enums have a String method, so writeAny will work fine. - if err := writeAny(w, fv, props); err != nil { + if err := tm.writeAny(w, fv, props); err != nil { return err } @@ -366,8 +455,8 @@ func writeStruct(w *textWriter, sv reflect.Value) error { // Extensions (the XXX_extensions field). pv := sv.Addr() - if pv.Type().Implements(extendableProtoType) { - if err := writeExtensions(w, pv); err != nil { + if _, ok := extendable(pv.Interface()); ok { + if err := tm.writeExtensions(w, pv); err != nil { return err } } @@ -397,7 +486,7 @@ func writeRaw(w *textWriter, b []byte) error { } // writeAny writes an arbitrary field. -func writeAny(w *textWriter, v reflect.Value, props *Properties) error { +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { v = reflect.Indirect(v) // Floats have special cases. @@ -424,7 +513,7 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error { switch v.Kind() { case reflect.Slice: // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Interface().([]byte))); err != nil { + if err := writeString(w, string(v.Bytes())); err != nil { return err } case reflect.String: @@ -446,15 +535,15 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error { } } w.indent() - if tm, ok := v.Interface().(encoding.TextMarshaler); ok { - text, err := tm.MarshalText() + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() if err != nil { return err } if _, err = w.Write(text); err != nil { return err } - } else if err := writeStruct(w, v); err != nil { + } else if err := tm.writeStruct(w, v); err != nil { return err } w.unindent() @@ -514,44 +603,6 @@ func writeString(w *textWriter, s string) error { return w.WriteByte('"') } -func writeMessageSet(w *textWriter, ms *MessageSet) error { - for _, item := range ms.Item { - id := *item.TypeId - if msd, ok := messageSetMap[id]; ok { - // Known message set type. - if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil { - return err - } - w.indent() - - pb := reflect.New(msd.t.Elem()) - if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil { - if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil { - return err - } - } else { - if err := writeStruct(w, pb.Elem()); err != nil { - return err - } - } - } else { - // Unknown type. - if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil { - return err - } - w.indent() - if err := writeUnknownStruct(w, item.Message); err != nil { - return err - } - } - w.unindent() - if _, err := w.Write(gtNewline); err != nil { - return err - } - } - return nil -} - func writeUnknownStruct(w *textWriter, data []byte) (err error) { if !w.compact { if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { @@ -636,19 +687,24 @@ func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // writeExtensions writes all the extensions in pv. // pv is assumed to be a pointer to a protocol message struct that is extendable. -func writeExtensions(w *textWriter, pv reflect.Value) error { +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { emap := extensionMaps[pv.Type().Elem()] - ep := pv.Interface().(extendableProto) + ep, _ := extendable(pv.Interface()) // Order the extensions by ID. // This isn't strictly necessary, but it will give us // canonical output, which will also make testing easier. - m := ep.ExtensionMap() + m, mu := ep.extensionsRead() + if m == nil { + return nil + } + mu.Lock() ids := make([]int32, 0, len(m)) for id := range m { ids = append(ids, id) } sort.Sort(int32Slice(ids)) + mu.Unlock() for _, extNum := range ids { ext := m[extNum] @@ -666,21 +722,18 @@ func writeExtensions(w *textWriter, pv reflect.Value) error { pb, err := GetExtension(ep, desc) if err != nil { - if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil { - return err - } - continue + return fmt.Errorf("failed getting extension: %v", err) } // Repeated extensions will appear as a slice. if !desc.repeated() { - if err := writeExtension(w, desc.Name, pb); err != nil { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { return err } } else { v := reflect.ValueOf(pb) for i := 0; i < v.Len(); i++ { - if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { return err } } @@ -689,7 +742,7 @@ func writeExtensions(w *textWriter, pv reflect.Value) error { return nil } -func writeExtension(w *textWriter, name string, pb interface{}) error { +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { return err } @@ -698,7 +751,7 @@ func writeExtension(w *textWriter, name string, pb interface{}) error { return err } } - if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil { + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -723,7 +776,15 @@ func (w *textWriter) writeIndent() { w.complete = false } -func marshalText(w io.Writer, pb Message, compact bool) error { +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { val := reflect.ValueOf(pb) if pb == nil || val.IsNil() { w.Write([]byte("")) @@ -738,11 +799,11 @@ func marshalText(w io.Writer, pb Message, compact bool) error { aw := &textWriter{ w: ww, complete: true, - compact: compact, + compact: tm.Compact, } - if tm, ok := pb.(encoding.TextMarshaler); ok { - text, err := tm.MarshalText() + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() if err != nil { return err } @@ -756,7 +817,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error { } // Dereference the received pointer so we don't have outer < and >. v := reflect.Indirect(val) - if err := writeStruct(aw, v); err != nil { + if err := tm.writeStruct(aw, v); err != nil { return err } if bw != nil { @@ -765,25 +826,29 @@ func marshalText(w io.Writer, pb Message, compact bool) error { return nil } +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + // MarshalText writes a given protocol buffer in text format. // The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { - return marshalText(w, pb, false) -} +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } // MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, false) - return buf.String() -} +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } // CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) } +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } // CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, true) - return buf.String() -} +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go index d1caeff5d..61f83c1e1 100644 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -44,6 +44,9 @@ import ( "unicode/utf8" ) +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + type ParseError struct { Message string Line int // 1-based line number @@ -119,6 +122,14 @@ func isWhitespace(c byte) bool { return false } +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + func (p *textParser) skipWhitespace() { i := 0 for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { @@ -155,7 +166,7 @@ func (p *textParser) advance() { p.cur.offset, p.cur.line = p.offset, p.line p.cur.unquoted = "" switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',': + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': // Single symbol p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] case '"', '\'': @@ -174,7 +185,7 @@ func (p *textParser) advance() { } unq, err := unquoteC(p.s[1:i], rune(p.s[0])) if err != nil { - p.errorf("invalid quoted string %v", p.s[0:i+1]) + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) return } p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] @@ -333,13 +344,13 @@ func (p *textParser) next() *token { p.advance() if p.done { p.cur.value = "" - } else if len(p.cur.value) > 0 && p.cur.value[0] == '"' { + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { // Look for multiple quoted strings separated by whitespace, // and concatenate them. cat := p.cur for { p.skipWhitespace() - if p.done || p.s[0] != '"' { + if p.done || !isQuote(p.s[0]) { break } p.advance() @@ -385,8 +396,7 @@ func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSet } // Returns the index in the struct for the named field, as well as the parsed tag properties. -func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) { - sprops := GetProperties(st) +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { i, ok := sprops.decoderOrigNames[name] if ok { return i, sprops.Prop[i], true @@ -438,12 +448,16 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr func (p *textParser) readStruct(sv reflect.Value, terminator string) error { st := sv.Type() - reqCount := GetProperties(st).reqCount + sprops := GetProperties(st) + reqCount := sprops.reqCount var reqFieldErr error fieldSet := make(map[string]bool) // A struct is a sequence of "name: value", terminated by one of // '>' or '}', or the end of the input. A name may also be - // "[extension]". + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > for { tok := p.next() if tok.err != nil { @@ -453,33 +467,74 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { break } if tok.value == "[" { - // Looks like an extension. + // Looks like an extension or an Any. // // TODO: Check whether we need to handle // namespace rooted names (e.g. ".something.Foo"). - tok = p.next() - if tok.err != nil { - return tok.err + extName, err := p.consumeExtName() + if err != nil { + return err } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + var desc *ExtensionDesc // This could be faster, but it's functional. // TODO: Do something smarter than a linear scan. for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { - if d.Name == tok.value { + if d.Name == extName { desc = d break } } if desc == nil { - return p.errorf("unrecognized extension %q", tok.value) - } - // Check the extension terminator. - tok = p.next() - if tok.err != nil { - return tok.err - } - if tok.value != "]" { - return p.errorf("unrecognized extension terminator %q", tok.value) + return p.errorf("unrecognized extension %q", extName) } props := &Properties{} @@ -506,7 +561,7 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { } reqFieldErr = err } - ep := sv.Addr().Interface().(extendableProto) + ep := sv.Addr().Interface().(Message) if !rep { SetExtension(ep, desc, ext.Interface()) } else { @@ -520,99 +575,126 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { sl = reflect.Append(sl, ext) SetExtension(ep, desc, sl.Interface()) } - } else { - // This is a normal, non-extension field. - name := tok.value - fi, props, ok := structFieldByName(st, name) - if !ok { - return p.errorf("unknown field name %q in %v", name, st) + if err := p.consumeOptionalSeparator(); err != nil { + return err } + continue + } - dst := sv.Field(fi) - - if dst.Kind() == reflect.Map { - // Consume any colon. - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Construct the map if it doesn't already exist. - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - key := reflect.New(dst.Type().Key()).Elem() - val := reflect.New(dst.Type().Elem()).Elem() - - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // Technically the "key" and "value" could come in any order, - // but in practice they won't. - - tok := p.next() - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - if err := p.consumeToken("key"); err != nil { - return err - } - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.mkeyprop); err != nil { - return err - } - if err := p.consumeToken("value"); err != nil { - return err - } - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.mvalprop); err != nil { - return err - } - if err := p.consumeToken(terminator); err != nil { - return err - } - - dst.SetMapIndex(key, val) - continue + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } - // Check that it's not already set if it's not a repeated field. - if !props.Repeated && fieldSet[name] { - return p.errorf("non-repeated field %q was repeated", name) - } - - if err := p.checkForColon(props, st.Field(fi).Type); err != nil { + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { return err } - // Parse into the field. - fieldSet[name] = true - if err := p.readAny(dst, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } else if props.Required { - reqCount-- + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue } - // For backward compatibility, permit a semicolon or comma after a field. - tok = p.next() - if tok.err != nil { - return tok.err + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) } - if tok.value != ";" && tok.value != "," { - p.back() + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + } if reqCount > 0 { @@ -621,6 +703,48 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { return reqFieldErr } +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + func (p *textParser) readAny(v reflect.Value, props *Properties) error { tok := p.next() if tok.err != nil { @@ -645,25 +769,39 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { fv.Set(reflect.ValueOf(bytes)) return nil } - // Repeated field. May already exist. - flen := fv.Len() - if flen == fv.Cap() { - nav := reflect.MakeSlice(at, flen, 2*flen+1) - reflect.Copy(nav, fv) - fv.Set(nav) + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "]" { + break + } + if tok.value != "," { + return p.errorf("Expected ']' or ',' found %q", tok.value) + } + } + return nil } - fv.SetLen(flen + 1) - - // Read one. + // One value of the repeated field. p.back() - return p.readAny(fv.Index(flen), props) + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) case reflect.Bool: - // Either "true", "false", 1 or 0. + // true/1/t/True or false/f/0/False. switch tok.value { - case "true", "1": + case "true", "1", "t", "True": fv.SetBool(true) return nil - case "false", "0": + case "false", "0", "f", "False": fv.SetBool(false) return nil } diff --git a/vendor/github.com/google/go-github/LICENSE b/vendor/github.com/google/go-github/LICENSE index 5582e4af8..53d5374a7 100644 --- a/vendor/github.com/google/go-github/LICENSE +++ b/vendor/github.com/google/go-github/LICENSE @@ -29,8 +29,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------- Some documentation is taken from the GitHub Developer site -, which is available under the following Creative -Commons Attribution 3.0 License. This applies only to the go-github source +, which is available under the following Creative +Commons Attribution 3.0 License. This applies only to the go-github source code and would not apply to any compiled binaries. THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE diff --git a/vendor/github.com/google/go-github/github/activity.go b/vendor/github.com/google/go-github/github/activity.go index d719ebb83..d6c992c7f 100644 --- a/vendor/github.com/google/go-github/github/activity.go +++ b/vendor/github.com/google/go-github/github/activity.go @@ -5,10 +5,12 @@ package github +import "context" + // ActivityService handles communication with the activity related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/activity/ +// GitHub API docs: https://developer.github.com/v3/activity/ type ActivityService service // FeedLink represents a link to a related resource. @@ -51,14 +53,14 @@ type Feeds struct { // // Note: Private feeds are only returned when authenticating via Basic Auth // since current feed URIs use the older, non revocable auth tokens. -func (s *ActivityService) ListFeeds() (*Feeds, *Response, error) { +func (s *ActivityService) ListFeeds(ctx context.Context) (*Feeds, *Response, error) { req, err := s.client.NewRequest("GET", "feeds", nil) if err != nil { return nil, nil, err } f := &Feeds{} - resp, err := s.client.Do(req, f) + resp, err := s.client.Do(ctx, req, f) if err != nil { return nil, resp, err } diff --git a/vendor/github.com/google/go-github/github/activity_events.go b/vendor/github.com/google/go-github/github/activity_events.go index 557001e1d..78219f8ab 100644 --- a/vendor/github.com/google/go-github/github/activity_events.go +++ b/vendor/github.com/google/go-github/github/activity_events.go @@ -6,6 +6,7 @@ package github import ( + "context" "encoding/json" "fmt" "time" @@ -27,9 +28,9 @@ func (e Event) String() string { return Stringify(e) } -// Payload returns the parsed event payload. For recognized event types, +// ParsePayload parses the event payload. For recognized event types, // a value of the corresponding struct type will be returned. -func (e *Event) Payload() (payload interface{}) { +func (e *Event) ParsePayload() (payload interface{}, err error) { switch *e.Type { case "CommitCommentEvent": payload = &CommitCommentEvent{} @@ -49,8 +50,6 @@ func (e *Event) Payload() (payload interface{}) { payload = &IntegrationInstallationEvent{} case "IntegrationInstallationRepositoriesEvent": payload = &IntegrationInstallationRepositoriesEvent{} - case "IssueActivityEvent": - payload = &IssueActivityEvent{} case "IssueCommentEvent": payload = &IssueCommentEvent{} case "IssuesEvent": @@ -63,10 +62,18 @@ func (e *Event) Payload() (payload interface{}) { payload = &MembershipEvent{} case "MilestoneEvent": payload = &MilestoneEvent{} + case "OrganizationEvent": + payload = &OrganizationEvent{} case "PageBuildEvent": payload = &PageBuildEvent{} case "PingEvent": payload = &PingEvent{} + case "ProjectEvent": + payload = &ProjectEvent{} + case "ProjectCardEvent": + payload = &ProjectCardEvent{} + case "ProjectColumnEvent": + payload = &ProjectColumnEvent{} case "PublicEvent": payload = &PublicEvent{} case "PullRequestEvent": @@ -88,16 +95,28 @@ func (e *Event) Payload() (payload interface{}) { case "WatchEvent": payload = &WatchEvent{} } - if err := json.Unmarshal(*e.RawPayload, &payload); err != nil { - panic(err.Error()) + err = json.Unmarshal(*e.RawPayload, &payload) + return payload, err +} + +// Payload returns the parsed event payload. For recognized event types, +// a value of the corresponding struct type will be returned. +// +// Deprecated: Use ParsePayload instead, which returns an error +// rather than panics if JSON unmarshaling raw payload fails. +func (e *Event) Payload() (payload interface{}) { + var err error + payload, err = e.ParsePayload() + if err != nil { + panic(err) } return payload } // ListEvents drinks from the firehose of all public events across GitHub. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events -func (s *ActivityService) ListEvents(opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events +func (s *ActivityService) ListEvents(ctx context.Context, opt *ListOptions) ([]*Event, *Response, error) { u, err := addOptions("events", opt) if err != nil { return nil, nil, err @@ -108,19 +127,19 @@ func (s *ActivityService) ListEvents(opt *ListOptions) ([]*Event, *Response, err return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListRepositoryEvents lists events for a repository. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-repository-events -func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-repository-events +func (s *ActivityService) ListRepositoryEvents(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("repos/%v/%v/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -132,19 +151,19 @@ func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOpti return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListIssueEventsForRepository lists issue events for a repository. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository -func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository +func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -156,19 +175,19 @@ func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt * return nil, nil, err } - events := new([]*IssueEvent) - resp, err := s.client.Do(req, events) + var events []*IssueEvent + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListEventsForRepoNetwork lists public events for a network of repositories. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories -func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories +func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("networks/%v/%v/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -180,19 +199,19 @@ func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *List return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListEventsForOrganization lists public events for an organization. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-an-organization -func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-an-organization +func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("orgs/%v/events", org) u, err := addOptions(u, opt) if err != nil { @@ -204,20 +223,20 @@ func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListEventsPerformedByUser lists the events performed by a user. If publicOnly is // true, only public events will be returned. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-performed-by-a-user -func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-performed-by-a-user +func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { var u string if publicOnly { u = fmt.Sprintf("users/%v/events/public", user) @@ -234,20 +253,20 @@ func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListEventsReceivedByUser lists the events received by a user. If publicOnly is // true, only public events will be returned. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received -func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received +func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { var u string if publicOnly { u = fmt.Sprintf("users/%v/received_events/public", user) @@ -264,20 +283,20 @@ func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } // ListUserEventsForOrganization provides the user’s organization dashboard. You // must be authenticated as the user to view this. // -// GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-for-an-organization -func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *ListOptions) ([]*Event, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-for-an-organization +func (s *ActivityService) ListUserEventsForOrganization(ctx context.Context, org, user string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("users/%v/events/orgs/%v", user, org) u, err := addOptions(u, opt) if err != nil { @@ -289,11 +308,11 @@ func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *L return nil, nil, err } - events := new([]*Event) - resp, err := s.client.Do(req, events) + var events []*Event + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return *events, resp, err + return events, resp, nil } diff --git a/vendor/github.com/google/go-github/github/activity_notifications.go b/vendor/github.com/google/go-github/github/activity_notifications.go index b538a7b4d..45c8b2aec 100644 --- a/vendor/github.com/google/go-github/github/activity_notifications.go +++ b/vendor/github.com/google/go-github/github/activity_notifications.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -18,7 +19,7 @@ type Notification struct { // Reason identifies the event that triggered the notification. // - // GitHub API Docs: https://developer.github.com/v3/activity/notifications/#notification-reasons + // GitHub API docs: https://developer.github.com/v3/activity/notifications/#notification-reasons Reason *string `json:"reason,omitempty"` Unread *bool `json:"unread,omitempty"` @@ -48,8 +49,8 @@ type NotificationListOptions struct { // ListNotifications lists all notifications for the authenticated user. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications -func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]*Notification, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications +func (s *ActivityService) ListNotifications(ctx context.Context, opt *NotificationListOptions) ([]*Notification, *Response, error) { u := fmt.Sprintf("notifications") u, err := addOptions(u, opt) if err != nil { @@ -62,19 +63,19 @@ func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]*No } var notifications []*Notification - resp, err := s.client.Do(req, ¬ifications) + resp, err := s.client.Do(ctx, req, ¬ifications) if err != nil { return nil, resp, err } - return notifications, resp, err + return notifications, resp, nil } // ListRepositoryNotifications lists all notifications in a given repository // for the authenticated user. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository -func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *NotificationListOptions) ([]*Notification, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository +func (s *ActivityService) ListRepositoryNotifications(ctx context.Context, owner, repo string, opt *NotificationListOptions) ([]*Notification, *Response, error) { u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -87,12 +88,12 @@ func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *N } var notifications []*Notification - resp, err := s.client.Do(req, ¬ifications) + resp, err := s.client.Do(ctx, req, ¬ifications) if err != nil { return nil, resp, err } - return notifications, resp, err + return notifications, resp, nil } type markReadOptions struct { @@ -101,8 +102,8 @@ type markReadOptions struct { // MarkNotificationsRead marks all notifications up to lastRead as read. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-as-read -func (s *ActivityService) MarkNotificationsRead(lastRead time.Time) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-as-read +func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead time.Time) (*Response, error) { opts := &markReadOptions{ LastReadAt: lastRead, } @@ -111,14 +112,14 @@ func (s *ActivityService) MarkNotificationsRead(lastRead time.Time) (*Response, return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // MarkRepositoryNotificationsRead marks all notifications up to lastRead in // the specified repository as read. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository -func (s *ActivityService) MarkRepositoryNotificationsRead(owner, repo string, lastRead time.Time) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository +func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) { opts := &markReadOptions{ LastReadAt: lastRead, } @@ -128,13 +129,13 @@ func (s *ActivityService) MarkRepositoryNotificationsRead(owner, repo string, la return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // GetThread gets the specified notification thread. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#view-a-single-thread -func (s *ActivityService) GetThread(id string) (*Notification, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#view-a-single-thread +func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notification, *Response, error) { u := fmt.Sprintf("notifications/threads/%v", id) req, err := s.client.NewRequest("GET", u, nil) @@ -143,18 +144,18 @@ func (s *ActivityService) GetThread(id string) (*Notification, *Response, error) } notification := new(Notification) - resp, err := s.client.Do(req, notification) + resp, err := s.client.Do(ctx, req, notification) if err != nil { return nil, resp, err } - return notification, resp, err + return notification, resp, nil } // MarkThreadRead marks the specified thread as read. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read -func (s *ActivityService) MarkThreadRead(id string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read +func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Response, error) { u := fmt.Sprintf("notifications/threads/%v", id) req, err := s.client.NewRequest("PATCH", u, nil) @@ -162,14 +163,14 @@ func (s *ActivityService) MarkThreadRead(id string) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // GetThreadSubscription checks to see if the authenticated user is subscribed // to a thread. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription -func (s *ActivityService) GetThreadSubscription(id string) (*Subscription, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription +func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string) (*Subscription, *Response, error) { u := fmt.Sprintf("notifications/threads/%v/subscription", id) req, err := s.client.NewRequest("GET", u, nil) @@ -178,19 +179,19 @@ func (s *ActivityService) GetThreadSubscription(id string) (*Subscription, *Resp } sub := new(Subscription) - resp, err := s.client.Do(req, sub) + resp, err := s.client.Do(ctx, req, sub) if err != nil { return nil, resp, err } - return sub, resp, err + return sub, resp, nil } // SetThreadSubscription sets the subscription for the specified thread for the // authenticated user. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription -func (s *ActivityService) SetThreadSubscription(id string, subscription *Subscription) (*Subscription, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription +func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string, subscription *Subscription) (*Subscription, *Response, error) { u := fmt.Sprintf("notifications/threads/%v/subscription", id) req, err := s.client.NewRequest("PUT", u, subscription) @@ -199,24 +200,24 @@ func (s *ActivityService) SetThreadSubscription(id string, subscription *Subscri } sub := new(Subscription) - resp, err := s.client.Do(req, sub) + resp, err := s.client.Do(ctx, req, sub) if err != nil { return nil, resp, err } - return sub, resp, err + return sub, resp, nil } // DeleteThreadSubscription deletes the subscription for the specified thread // for the authenticated user. // -// GitHub API Docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription -func (s *ActivityService) DeleteThreadSubscription(id string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription +func (s *ActivityService) DeleteThreadSubscription(ctx context.Context, id string) (*Response, error) { u := fmt.Sprintf("notifications/threads/%v/subscription", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/activity_star.go b/vendor/github.com/google/go-github/github/activity_star.go index 5df6814a4..d5b067127 100644 --- a/vendor/github.com/google/go-github/github/activity_star.go +++ b/vendor/github.com/google/go-github/github/activity_star.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // StarredRepository is returned by ListStarred. type StarredRepository struct { @@ -21,8 +24,8 @@ type Stargazer struct { // ListStargazers lists people who have starred the specified repo. // -// GitHub API Docs: https://developer.github.com/v3/activity/starring/#list-stargazers -func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ([]*Stargazer, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-stargazers +func (s *ActivityService) ListStargazers(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Stargazer, *Response, error) { u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -37,34 +40,34 @@ func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ( // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeStarringPreview) - stargazers := new([]*Stargazer) - resp, err := s.client.Do(req, stargazers) + var stargazers []*Stargazer + resp, err := s.client.Do(ctx, req, &stargazers) if err != nil { return nil, resp, err } - return *stargazers, resp, err + return stargazers, resp, nil } // ActivityListStarredOptions specifies the optional parameters to the // ActivityService.ListStarred method. type ActivityListStarredOptions struct { - // How to sort the repository list. Possible values are: created, updated, - // pushed, full_name. Default is "full_name". + // How to sort the repository list. Possible values are: created, updated, + // pushed, full_name. Default is "full_name". Sort string `url:"sort,omitempty"` - // Direction in which to sort repositories. Possible values are: asc, desc. + // Direction in which to sort repositories. Possible values are: asc, desc. // Default is "asc" when sort is "full_name", otherwise default is "desc". Direction string `url:"direction,omitempty"` ListOptions } -// ListStarred lists all the repos starred by a user. Passing the empty string +// ListStarred lists all the repos starred by a user. Passing the empty string // will list the starred repositories for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/activity/starring/#list-repositories-being-starred -func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-repositories-being-starred +func (s *ActivityService) ListStarred(ctx context.Context, user string, opt *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/starred", user) @@ -84,25 +87,25 @@ func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptio // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeStarringPreview) - repos := new([]*StarredRepository) - resp, err := s.client.Do(req, repos) + var repos []*StarredRepository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } // IsStarred checks if a repository is starred by authenticated user. // // GitHub API docs: https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository -func (s *ActivityService) IsStarred(owner, repo string) (bool, *Response, error) { +func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bool, *Response, error) { u := fmt.Sprintf("user/starred/%v/%v", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) starred, err := parseBoolResponse(err) return starred, resp, err } @@ -110,23 +113,23 @@ func (s *ActivityService) IsStarred(owner, repo string) (bool, *Response, error) // Star a repository as the authenticated user. // // GitHub API docs: https://developer.github.com/v3/activity/starring/#star-a-repository -func (s *ActivityService) Star(owner, repo string) (*Response, error) { +func (s *ActivityService) Star(ctx context.Context, owner, repo string) (*Response, error) { u := fmt.Sprintf("user/starred/%v/%v", owner, repo) req, err := s.client.NewRequest("PUT", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Unstar a repository as the authenticated user. // // GitHub API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository -func (s *ActivityService) Unstar(owner, repo string) (*Response, error) { +func (s *ActivityService) Unstar(ctx context.Context, owner, repo string) (*Response, error) { u := fmt.Sprintf("user/starred/%v/%v", owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/activity_watching.go b/vendor/github.com/google/go-github/github/activity_watching.go index 9a275419c..c749ca86e 100644 --- a/vendor/github.com/google/go-github/github/activity_watching.go +++ b/vendor/github.com/google/go-github/github/activity_watching.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Subscription identifies a repository or thread subscription. type Subscription struct { @@ -24,8 +27,8 @@ type Subscription struct { // ListWatchers lists watchers of a particular repo. // -// GitHub API Docs: http://developer.github.com/v3/activity/watching/#list-watchers -func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-watchers +func (s *ActivityService) ListWatchers(ctx context.Context, owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -37,20 +40,20 @@ func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([] return nil, nil, err } - watchers := new([]*User) - resp, err := s.client.Do(req, watchers) + var watchers []*User + resp, err := s.client.Do(ctx, req, &watchers) if err != nil { return nil, resp, err } - return *watchers, resp, err + return watchers, resp, nil } -// ListWatched lists the repositories the specified user is watching. Passing +// ListWatched lists the repositories the specified user is watching. Passing // the empty string will fetch watched repos for the authenticated user. // -// GitHub API Docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched -func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched +func (s *ActivityService) ListWatched(ctx context.Context, user string, opt *ListOptions) ([]*Repository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/subscriptions", user) @@ -67,21 +70,21 @@ func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]*Reposit return nil, nil, err } - watched := new([]*Repository) - resp, err := s.client.Do(req, watched) + var watched []*Repository + resp, err := s.client.Do(ctx, req, &watched) if err != nil { return nil, resp, err } - return *watched, resp, err + return watched, resp, nil } // GetRepositorySubscription returns the subscription for the specified -// repository for the authenticated user. If the authenticated user is not +// repository for the authenticated user. If the authenticated user is not // watching the repository, a nil Subscription is returned. // -// GitHub API Docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription -func (s *ActivityService) GetRepositorySubscription(owner, repo string) (*Subscription, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription +func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner, repo string) (*Subscription, *Response, error) { u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) req, err := s.client.NewRequest("GET", u, nil) @@ -90,14 +93,14 @@ func (s *ActivityService) GetRepositorySubscription(owner, repo string) (*Subscr } sub := new(Subscription) - resp, err := s.client.Do(req, sub) + resp, err := s.client.Do(ctx, req, sub) if err != nil { // if it's just a 404, don't return that as an error _, err = parseBoolResponse(err) return nil, resp, err } - return sub, resp, err + return sub, resp, nil } // SetRepositorySubscription sets the subscription for the specified repository @@ -107,8 +110,8 @@ func (s *ActivityService) GetRepositorySubscription(owner, repo string) (*Subscr // To ignore notifications made within a repository, set subscription.Ignored to true. // To stop watching a repository, use DeleteRepositorySubscription. // -// GitHub API Docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription -func (s *ActivityService) SetRepositorySubscription(owner, repo string, subscription *Subscription) (*Subscription, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription +func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner, repo string, subscription *Subscription) (*Subscription, *Response, error) { u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) req, err := s.client.NewRequest("PUT", u, subscription) @@ -117,12 +120,12 @@ func (s *ActivityService) SetRepositorySubscription(owner, repo string, subscrip } sub := new(Subscription) - resp, err := s.client.Do(req, sub) + resp, err := s.client.Do(ctx, req, sub) if err != nil { return nil, resp, err } - return sub, resp, err + return sub, resp, nil } // DeleteRepositorySubscription deletes the subscription for the specified @@ -131,13 +134,13 @@ func (s *ActivityService) SetRepositorySubscription(owner, repo string, subscrip // This is used to stop watching a repository. To control whether or not to // receive notifications from a repository, use SetRepositorySubscription. // -// GitHub API Docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription -func (s *ActivityService) DeleteRepositorySubscription(owner, repo string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription +func (s *ActivityService) DeleteRepositorySubscription(ctx context.Context, owner, repo string) (*Response, error) { u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/admin.go b/vendor/github.com/google/go-github/github/admin.go index 44d7a9fb6..d0f055bcf 100644 --- a/vendor/github.com/google/go-github/github/admin.go +++ b/vendor/github.com/google/go-github/github/admin.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // AdminService handles communication with the admin related methods of the // GitHub API. These API routes are normally only accessible for GitHub @@ -62,7 +65,7 @@ func (m UserLDAPMapping) String() string { // UpdateUserLDAPMapping updates the mapping between a GitHub user and an LDAP user. // // GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-user -func (s *AdminService) UpdateUserLDAPMapping(user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) { +func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) { u := fmt.Sprintf("admin/ldap/users/%v/mapping", user) req, err := s.client.NewRequest("PATCH", u, mapping) if err != nil { @@ -70,18 +73,18 @@ func (s *AdminService) UpdateUserLDAPMapping(user string, mapping *UserLDAPMappi } m := new(UserLDAPMapping) - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } - return m, resp, err + return m, resp, nil } // UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group. // // GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-team -func (s *AdminService) UpdateTeamLDAPMapping(team int, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) { +func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) { u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team) req, err := s.client.NewRequest("PATCH", u, mapping) if err != nil { @@ -89,10 +92,10 @@ func (s *AdminService) UpdateTeamLDAPMapping(team int, mapping *TeamLDAPMapping) } m := new(TeamLDAPMapping) - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } - return m, resp, err + return m, resp, nil } diff --git a/vendor/github.com/google/go-github/github/authorizations.go b/vendor/github.com/google/go-github/github/authorizations.go index d5a5e631d..181e83dfe 100644 --- a/vendor/github.com/google/go-github/github/authorizations.go +++ b/vendor/github.com/google/go-github/github/authorizations.go @@ -5,11 +5,14 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Scope models a GitHub authorization scope. // -// GitHub API docs:https://developer.github.com/v3/oauth/#scopes +// GitHub API docs: https://developer.github.com/v3/oauth/#scopes type Scope string // This is the set of scopes for GitHub API V3 @@ -114,7 +117,7 @@ func (a AuthorizationRequest) String() string { // AuthorizationUpdateRequest represents a request to update an authorization. // // Note that for any one update, you must only provide one of the "scopes" -// fields. That is, you may provide only one of "Scopes", or "AddScopes", or +// fields. That is, you may provide only one of "Scopes", or "AddScopes", or // "RemoveScopes". // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization @@ -134,7 +137,7 @@ func (a AuthorizationUpdateRequest) String() string { // List the authorizations for the authenticated user. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations -func (s *AuthorizationsService) List(opt *ListOptions) ([]*Authorization, *Response, error) { +func (s *AuthorizationsService) List(ctx context.Context, opt *ListOptions) ([]*Authorization, *Response, error) { u := "authorizations" u, err := addOptions(u, opt) if err != nil { @@ -146,18 +149,18 @@ func (s *AuthorizationsService) List(opt *ListOptions) ([]*Authorization, *Respo return nil, nil, err } - auths := new([]*Authorization) - resp, err := s.client.Do(req, auths) + var auths []*Authorization + resp, err := s.client.Do(ctx, req, &auths) if err != nil { return nil, resp, err } - return *auths, resp, err + return auths, resp, nil } // Get a single authorization. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization -func (s *AuthorizationsService) Get(id int) (*Authorization, *Response, error) { +func (s *AuthorizationsService) Get(ctx context.Context, id int) (*Authorization, *Response, error) { u := fmt.Sprintf("authorizations/%d", id) req, err := s.client.NewRequest("GET", u, nil) @@ -166,17 +169,17 @@ func (s *AuthorizationsService) Get(id int) (*Authorization, *Response, error) { } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // Create a new authorization for the specified OAuth application. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization -func (s *AuthorizationsService) Create(auth *AuthorizationRequest) (*Authorization, *Response, error) { +func (s *AuthorizationsService) Create(ctx context.Context, auth *AuthorizationRequest) (*Authorization, *Response, error) { u := "authorizations" req, err := s.client.NewRequest("POST", u, auth) @@ -185,11 +188,11 @@ func (s *AuthorizationsService) Create(auth *AuthorizationRequest) (*Authorizati } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // GetOrCreateForApp creates a new authorization for the specified OAuth @@ -204,9 +207,9 @@ func (s *AuthorizationsService) Create(auth *AuthorizationRequest) (*Authorizati // clientID is the OAuth Client ID with which to create the token. // // GitHub API docs: -// - https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app -// - https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app-and-fingerprint -func (s *AuthorizationsService) GetOrCreateForApp(clientID string, auth *AuthorizationRequest) (*Authorization, *Response, error) { +// https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app +// https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app-and-fingerprint +func (s *AuthorizationsService) GetOrCreateForApp(ctx context.Context, clientID string, auth *AuthorizationRequest) (*Authorization, *Response, error) { var u string if auth.Fingerprint == nil || *auth.Fingerprint == "" { u = fmt.Sprintf("authorizations/clients/%v", clientID) @@ -220,18 +223,18 @@ func (s *AuthorizationsService) GetOrCreateForApp(clientID string, auth *Authori } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // Edit a single authorization. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization -func (s *AuthorizationsService) Edit(id int, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) { +func (s *AuthorizationsService) Edit(ctx context.Context, id int, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) { u := fmt.Sprintf("authorizations/%d", id) req, err := s.client.NewRequest("PATCH", u, auth) @@ -240,18 +243,18 @@ func (s *AuthorizationsService) Edit(id int, auth *AuthorizationUpdateRequest) ( } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // Delete a single authorization. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization -func (s *AuthorizationsService) Delete(id int) (*Response, error) { +func (s *AuthorizationsService) Delete(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("authorizations/%d", id) req, err := s.client.NewRequest("DELETE", u, nil) @@ -259,7 +262,7 @@ func (s *AuthorizationsService) Delete(id int) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Check if an OAuth token is valid for a specific app. @@ -271,7 +274,7 @@ func (s *AuthorizationsService) Delete(id int) (*Response, error) { // The returned Authorization.User field will be populated. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#check-an-authorization -func (s *AuthorizationsService) Check(clientID string, token string) (*Authorization, *Response, error) { +func (s *AuthorizationsService) Check(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) { u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) req, err := s.client.NewRequest("GET", u, nil) @@ -280,12 +283,12 @@ func (s *AuthorizationsService) Check(clientID string, token string) (*Authoriza } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // Reset is used to reset a valid OAuth token without end user involvement. @@ -299,7 +302,7 @@ func (s *AuthorizationsService) Check(clientID string, token string) (*Authoriza // The returned Authorization.User field will be populated. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization -func (s *AuthorizationsService) Reset(clientID string, token string) (*Authorization, *Response, error) { +func (s *AuthorizationsService) Reset(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) { u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) req, err := s.client.NewRequest("POST", u, nil) @@ -308,12 +311,12 @@ func (s *AuthorizationsService) Reset(clientID string, token string) (*Authoriza } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // Revoke an authorization for an application. @@ -323,7 +326,7 @@ func (s *AuthorizationsService) Reset(clientID string, token string) (*Authoriza // clientSecret. Invalid tokens will return a 404 Not Found. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application -func (s *AuthorizationsService) Revoke(clientID string, token string) (*Response, error) { +func (s *AuthorizationsService) Revoke(ctx context.Context, clientID string, token string) (*Response, error) { u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) req, err := s.client.NewRequest("DELETE", u, nil) @@ -331,7 +334,7 @@ func (s *AuthorizationsService) Revoke(clientID string, token string) (*Response return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListGrants lists the set of OAuth applications that have been granted @@ -340,25 +343,25 @@ func (s *AuthorizationsService) Revoke(clientID string, token string) (*Response // tokens an application has generated for the user. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-grants -func (s *AuthorizationsService) ListGrants() ([]*Grant, *Response, error) { +func (s *AuthorizationsService) ListGrants(ctx context.Context) ([]*Grant, *Response, error) { req, err := s.client.NewRequest("GET", "applications/grants", nil) if err != nil { return nil, nil, err } grants := []*Grant{} - resp, err := s.client.Do(req, &grants) + resp, err := s.client.Do(ctx, req, &grants) if err != nil { return nil, resp, err } - return grants, resp, err + return grants, resp, nil } // GetGrant gets a single OAuth application grant. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant -func (s *AuthorizationsService) GetGrant(id int) (*Grant, *Response, error) { +func (s *AuthorizationsService) GetGrant(ctx context.Context, id int) (*Grant, *Response, error) { u := fmt.Sprintf("applications/grants/%d", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -366,12 +369,12 @@ func (s *AuthorizationsService) GetGrant(id int) (*Grant, *Response, error) { } grant := new(Grant) - resp, err := s.client.Do(req, grant) + resp, err := s.client.Do(ctx, req, grant) if err != nil { return nil, resp, err } - return grant, resp, err + return grant, resp, nil } // DeleteGrant deletes an OAuth application grant. Deleting an application's @@ -379,14 +382,14 @@ func (s *AuthorizationsService) GetGrant(id int) (*Grant, *Response, error) { // the user. // // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant -func (s *AuthorizationsService) DeleteGrant(id int) (*Response, error) { +func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("applications/grants/%d", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // CreateImpersonation creates an impersonation OAuth token. @@ -396,7 +399,7 @@ func (s *AuthorizationsService) DeleteGrant(id int) (*Response, error) { // new token automatically revokes an existing one. // // GitHub API docs: https://developer.github.com/enterprise/2.5/v3/users/administration/#create-an-impersonation-oauth-token -func (s *AuthorizationsService) CreateImpersonation(username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) { +func (s *AuthorizationsService) CreateImpersonation(ctx context.Context, username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) { u := fmt.Sprintf("admin/users/%v/authorizations", username) req, err := s.client.NewRequest("POST", u, authReq) if err != nil { @@ -404,11 +407,11 @@ func (s *AuthorizationsService) CreateImpersonation(username string, authReq *Au } a := new(Authorization) - resp, err := s.client.Do(req, a) + resp, err := s.client.Do(ctx, req, a) if err != nil { return nil, resp, err } - return a, resp, err + return a, resp, nil } // DeleteImpersonation deletes an impersonation OAuth token. @@ -416,12 +419,12 @@ func (s *AuthorizationsService) CreateImpersonation(username string, authReq *Au // NOTE: there can be only one at a time. // // GitHub API docs: https://developer.github.com/enterprise/2.5/v3/users/administration/#delete-an-impersonation-oauth-token -func (s *AuthorizationsService) DeleteImpersonation(username string) (*Response, error) { +func (s *AuthorizationsService) DeleteImpersonation(ctx context.Context, username string) (*Response, error) { u := fmt.Sprintf("admin/users/%v/authorizations", username) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/doc.go b/vendor/github.com/google/go-github/github/doc.go index 659dd8248..0acf3281f 100644 --- a/vendor/github.com/google/go-github/github/doc.go +++ b/vendor/github.com/google/go-github/github/doc.go @@ -16,7 +16,7 @@ access different parts of the GitHub API. For example: client := github.NewClient(nil) // list all organizations for user "willnorris" - orgs, _, err := client.Organizations.List("willnorris", nil) + orgs, _, err := client.Organizations.List(ctx, "willnorris", nil) Some API methods have optional parameters that can be passed. For example: @@ -24,11 +24,11 @@ Some API methods have optional parameters that can be passed. For example: // list public repositories for org "github" opt := &github.RepositoryListByOrgOptions{Type: "public"} - repos, _, err := client.Repositories.ListByOrg("github", opt) + repos, _, err := client.Repositories.ListByOrg(ctx, "github", opt) The services of a client divide the API into logical chunks and correspond to the structure of the GitHub API documentation at -http://developer.github.com/v3/. +https://developer.github.com/v3/. Authentication @@ -42,15 +42,16 @@ use it with the oauth2 library using: import "golang.org/x/oauth2" func main() { + ctx := context.Background() ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: "... your access token ..."}, ) - tc := oauth2.NewClient(oauth2.NoContext, ts) + tc := oauth2.NewClient(ctx, ts) client := github.NewClient(tc) // list all repositories for the authenticated user - repos, _, err := client.Repositories.List("", nil) + repos, _, err := client.Repositories.List(ctx, "", nil) } Note that when using an authenticated Client, all calls made by the client will @@ -78,13 +79,13 @@ up-to-date rate limit data for the client. To detect an API rate limit error, you can check if its type is *github.RateLimitError: - repos, _, err := client.Repositories.List("", nil) + repos, _, err := client.Repositories.List(ctx, "", nil) if _, ok := err.(*github.RateLimitError); ok { log.Println("hit rate limit") } Learn more about GitHub rate limiting at -http://developer.github.com/v3/#rate-limiting. +https://developer.github.com/v3/#rate-limiting. Accepted Status @@ -96,7 +97,7 @@ this behavior. To detect this condition of error, you can check if its type is *github.AcceptedError: - stats, _, err := client.Repositories.ListContributorsStats(org, repo) + stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo) if _, ok := err.(*github.AcceptedError); ok { log.Println("scheduled on GitHub side") } @@ -124,7 +125,7 @@ bool, and int values. For example: Name: github.String("foo"), Private: github.Bool(true), } - client.Repositories.Create("", repo) + client.Repositories.Create(ctx, "", repo) Users who have worked with protocol buffers should find this pattern familiar. @@ -145,7 +146,7 @@ github.Response struct. // get all pages of results var allRepos []*github.Repository for { - repos, resp, err := client.Repositories.ListByOrg("github", opt) + repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt) if err != nil { return err } @@ -156,5 +157,16 @@ github.Response struct. opt.ListOptions.Page = resp.NextPage } +Google App Engine + +Go on App Engine Classic (which as of this writing uses Go 1.6) can not use +the "context" import and still relies on "golang.org/x/net/context". +As a result, if you wish to continue to use "go-github" on App Engine Classic, +you will need to rewrite all the "context" imports using the following command: + + gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go + +See "with_appengine.go" for more details. + */ package github diff --git a/vendor/github.com/google/go-github/github/event_types.go b/vendor/github.com/google/go-github/github/event_types.go index a1ffa699b..acf139b1e 100644 --- a/vendor/github.com/google/go-github/github/event_types.go +++ b/vendor/github.com/google/go-github/github/event_types.go @@ -10,14 +10,15 @@ package github // CommitCommentEvent is triggered when a commit comment is created. // The Webhook event name is "commit_comment". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#commitcommentevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#commitcommentevent type CommitCommentEvent struct { Comment *RepositoryComment `json:"comment,omitempty"` // The following fields are only populated by Webhook events. - Action *string `json:"action,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Action *string `json:"action,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // CreateEvent represents a created repository, branch, or tag. @@ -27,7 +28,7 @@ type CommitCommentEvent struct { // Additionally, webhooks will not receive this event for tags if more // than three tags are pushed at once. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#createevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#createevent type CreateEvent struct { Ref *string `json:"ref,omitempty"` // RefType is the object that was created. Possible values are: "repository", "branch", "tag". @@ -36,9 +37,10 @@ type CreateEvent struct { Description *string `json:"description,omitempty"` // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + PusherType *string `json:"pusher_type,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // DeleteEvent represents a deleted branch or tag. @@ -47,16 +49,17 @@ type CreateEvent struct { // Note: webhooks will not receive this event for tags if more than three tags // are deleted at once. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#deleteevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deleteevent type DeleteEvent struct { Ref *string `json:"ref,omitempty"` // RefType is the object that was deleted. Possible values are: "branch", "tag". RefType *string `json:"ref_type,omitempty"` // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + PusherType *string `json:"pusher_type,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // DeploymentEvent represents a deployment. @@ -64,13 +67,14 @@ type DeleteEvent struct { // // Events of this type are not visible in timelines, they are only used to trigger hooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#deploymentevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentevent type DeploymentEvent struct { Deployment *Deployment `json:"deployment,omitempty"` Repo *Repository `json:"repository,omitempty"` // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // DeploymentStatusEvent represents a deployment status. @@ -78,27 +82,29 @@ type DeploymentEvent struct { // // Events of this type are not visible in timelines, they are only used to trigger hooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#deploymentstatusevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentstatusevent type DeploymentStatusEvent struct { Deployment *Deployment `json:"deployment,omitempty"` DeploymentStatus *DeploymentStatus `json:"deployment_status,omitempty"` Repo *Repository `json:"repository,omitempty"` // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // ForkEvent is triggered when a user forks a repository. // The Webhook event name is "fork". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#forkevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#forkevent type ForkEvent struct { // Forkee is the created repository. Forkee *Repository `json:"forkee,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // Page represents a single Wiki page. @@ -114,25 +120,14 @@ type Page struct { // GollumEvent is triggered when a Wiki page is created or updated. // The Webhook event name is "gollum". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#gollumevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#gollumevent type GollumEvent struct { Pages []*Page `json:"pages,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -// IssueActivityEvent represents the payload delivered by Issue webhook. -// -// Deprecated: Use IssuesEvent instead. -type IssueActivityEvent struct { - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // EditChange represents the changes when an issue, pull request, or comment has @@ -146,37 +141,61 @@ type EditChange struct { } `json:"body,omitempty"` } +// ProjectChange represents the changes when a project has been edited. +type ProjectChange struct { + Name *struct { + From *string `json:"from,omitempty"` + } `json:"name,omitempty"` + Body *struct { + From *string `json:"from,omitempty"` + } `json:"body,omitempty"` +} + +// ProjectCardChange represents the changes when a project card has been edited. +type ProjectCardChange struct { + Note *struct { + From *string `json:"from,omitempty"` + } `json:"note,omitempty"` +} + +// ProjectColumnChange represents the changes when a project column has been edited. +type ProjectColumnChange struct { + Name *struct { + From *string `json:"from,omitempty"` + } `json:"name,omitempty"` +} + // IntegrationInstallationEvent is triggered when an integration is created or deleted. // The Webhook event name is "integration_installation". // -// GitHub docs: https://developer.github.com/early-access/integrations/webhooks/#integrationinstallationevent +// GitHub API docs: https://developer.github.com/early-access/integrations/webhooks/#integrationinstallationevent type IntegrationInstallationEvent struct { // The action that was performed. Possible values for an "integration_installation" // event are: "created", "deleted". Action *string `json:"action,omitempty"` - Installation *Installation `json:"installation,omitempty"` Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // IntegrationInstallationRepositoriesEvent is triggered when an integration repository // is added or removed. The Webhook event name is "integration_installation_repositories". // -// GitHub docs: https://developer.github.com/early-access/integrations/webhooks/#integrationinstallationrepositoriesevent +// GitHub API docs: https://developer.github.com/early-access/integrations/webhooks/#integrationinstallationrepositoriesevent type IntegrationInstallationRepositoriesEvent struct { // The action that was performed. Possible values for an "integration_installation_repositories" // event are: "added", "removed". Action *string `json:"action,omitempty"` - Installation *Installation `json:"installation,omitempty"` RepositoriesAdded []*Repository `json:"repositories_added,omitempty"` RepositoriesRemoved []*Repository `json:"repositories_removed,omitempty"` Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // IssueCommentEvent is triggered when an issue comment is created on an issue // or pull request. // The Webhook event name is "issue_comment". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#issuecommentevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuecommentevent type IssueCommentEvent struct { // Action is the action that was performed on the comment. // Possible values are: "created", "edited", "deleted". @@ -185,16 +204,17 @@ type IssueCommentEvent struct { Comment *IssueComment `json:"comment,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // IssuesEvent is triggered when an issue is assigned, unassigned, labeled, // unlabeled, opened, closed, or reopened. // The Webhook event name is "issues". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#issuesevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuesevent type IssuesEvent struct { // Action is the action that was performed. Possible values are: "assigned", // "unassigned", "labeled", "unlabeled", "opened", "closed", "reopened", "edited". @@ -204,15 +224,16 @@ type IssuesEvent struct { Label *Label `json:"label,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // LabelEvent is triggered when a repository's label is created, edited, or deleted. // The Webhook event name is "label" // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#labelevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#labelevent type LabelEvent struct { // Action is the action that was performed. Possible values are: // "created", "edited", "deleted" @@ -220,23 +241,25 @@ type LabelEvent struct { Label *Label `json:"label,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Org *Organization `json:"organization,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // MemberEvent is triggered when a user is added as a collaborator to a repository. // The Webhook event name is "member". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#memberevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#memberevent type MemberEvent struct { // Action is the action that was performed. Possible value is: "added". Action *string `json:"action,omitempty"` Member *User `json:"member,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // MembershipEvent is triggered when a user is added or removed from a team. @@ -245,7 +268,7 @@ type MemberEvent struct { // Events of this type are not visible in timelines, they are only used to // trigger organization webhooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#membershipevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#membershipevent type MembershipEvent struct { // Action is the action that was performed. Possible values are: "added", "removed". Action *string `json:"action,omitempty"` @@ -255,14 +278,15 @@ type MembershipEvent struct { Team *Team `json:"team,omitempty"` // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // MilestoneEvent is triggered when a milestone is created, closed, opened, edited, or deleted. // The Webhook event name is "milestone". // -// Github docs: https://developer.github.com/v3/activity/events/types/#milestoneevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#milestoneevent type MilestoneEvent struct { // Action is the action that was performed. Possible values are: // "created", "closed", "opened", "edited", "deleted" @@ -270,10 +294,33 @@ type MilestoneEvent struct { Milestone *Milestone `json:"milestone,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Org *Organization `json:"organization,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Org *Organization `json:"organization,omitempty"` + Installation *Installation `json:"installation,omitempty"` +} + +// OrganizationEvent is triggered when a user is added, removed, or invited to an organization. +// Events of this type are not visible in timelines. These events are only used to trigger organization hooks. +// Webhook event name is "organization". +// +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#organizationevent +type OrganizationEvent struct { + // Action is the action that was performed. + // Can be one of "member_added", "member_removed", or "member_invited". + Action *string `json:"action,omitempty"` + + // Invitaion is the invitation for the user or email if the action is "member_invited". + Invitation *Invitation `json:"invitation,omitempty"` + + // Membership is the membership between the user and the organization. + // Not present when the action is "member_invited". + Membership *Membership `json:"membership,omitempty"` + + Organization *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PageBuildEvent represents an attempted build of a GitHub Pages site, whether @@ -285,44 +332,97 @@ type MilestoneEvent struct { // // Events of this type are not visible in timelines, they are only used to trigger hooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#pagebuildevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pagebuildevent type PageBuildEvent struct { Build *PagesBuild `json:"build,omitempty"` // The following fields are only populated by Webhook events. - ID *int `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + ID *int `json:"id,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PingEvent is triggered when a Webhook is added to GitHub. // -// GitHub docs: https://developer.github.com/webhooks/#ping-event +// GitHub API docs: https://developer.github.com/webhooks/#ping-event type PingEvent struct { // Random string of GitHub zen. Zen *string `json:"zen,omitempty"` // The ID of the webhook that triggered the ping. HookID *int `json:"hook_id,omitempty"` // The webhook configuration. - Hook *Hook `json:"hook,omitempty"` + Hook *Hook `json:"hook,omitempty"` + Installation *Installation `json:"installation,omitempty"` +} + +// ProjectEvent is triggered when project is created, modified or deleted. +// The webhook event name is "project". +// +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectevent +type ProjectEvent struct { + Action *string `json:"action,omitempty"` + Changes *ProjectChange `json:"changes,omitempty"` + Project *Project `json:"project,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` +} + +// ProjectCardEvent is triggered when a project card is created, updated, moved, converted to an issue, or deleted. +// The webhook event name is "project_card". +// +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcardevent +type ProjectCardEvent struct { + Action *string `json:"action,omitempty"` + Changes *ProjectCardChange `json:"changes,omitempty"` + AfterID *int `json:"after_id,omitempty"` + ProjectCard *ProjectCard `json:"project_card,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` +} + +// ProjectColumnEvent is triggered when a project column is created, updated, moved, or deleted. +// The webhook event name is "project_column". +// +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcolumnevent +type ProjectColumnEvent struct { + Action *string `json:"action,omitempty"` + Changes *ProjectColumnChange `json:"changes,omitempty"` + AfterID *int `json:"after_id,omitempty"` + ProjectColumn *ProjectColumn `json:"project_column,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PublicEvent is triggered when a private repository is open sourced. // According to GitHub: "Without a doubt: the best GitHub event." // The Webhook event name is "public". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#publicevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#publicevent type PublicEvent struct { // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PullRequestEvent is triggered when a pull request is assigned, unassigned, // labeled, unlabeled, opened, closed, reopened, or synchronized. // The Webhook event name is "pull_request". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent type PullRequestEvent struct { // Action is the action that was performed. Possible values are: "assigned", // "unassigned", "labeled", "unlabeled", "opened", "closed", or "reopened", @@ -334,16 +434,17 @@ type PullRequestEvent struct { PullRequest *PullRequest `json:"pull_request,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PullRequestReviewEvent is triggered when a review is submitted on a pull // request. // The Webhook event name is "pull_request_review". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent type PullRequestReviewEvent struct { // Action is always "submitted". Action *string `json:"action,omitempty"` @@ -351,8 +452,9 @@ type PullRequestReviewEvent struct { PullRequest *PullRequest `json:"pull_request,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` // The following field is only present when the webhook is triggered on // a repository belonging to an organization. @@ -363,7 +465,7 @@ type PullRequestReviewEvent struct { // portion of the unified diff of a pull request. // The Webhook event name is "pull_request_review_comment". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent type PullRequestReviewCommentEvent struct { // Action is the action that was performed on the comment. // Possible values are: "created", "edited", "deleted". @@ -372,34 +474,36 @@ type PullRequestReviewCommentEvent struct { Comment *PullRequestComment `json:"comment,omitempty"` // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Changes *EditChange `json:"changes,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // PushEvent represents a git push to a GitHub repository. // -// GitHub API docs: http://developer.github.com/v3/activity/events/types/#pushevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pushevent type PushEvent struct { - PushID *int `json:"push_id,omitempty"` - Head *string `json:"head,omitempty"` - Ref *string `json:"ref,omitempty"` - Size *int `json:"size,omitempty"` - Commits []PushEventCommit `json:"commits,omitempty"` - Repo *PushEventRepository `json:"repository,omitempty"` - Before *string `json:"before,omitempty"` - DistinctSize *int `json:"distinct_size,omitempty"` + PushID *int `json:"push_id,omitempty"` + Head *string `json:"head,omitempty"` + Ref *string `json:"ref,omitempty"` + Size *int `json:"size,omitempty"` + Commits []PushEventCommit `json:"commits,omitempty"` + Before *string `json:"before,omitempty"` + DistinctSize *int `json:"distinct_size,omitempty"` // The following fields are only populated by Webhook events. - After *string `json:"after,omitempty"` - Created *bool `json:"created,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - Forced *bool `json:"forced,omitempty"` - BaseRef *string `json:"base_ref,omitempty"` - Compare *string `json:"compare,omitempty"` - HeadCommit *PushEventCommit `json:"head_commit,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Sender *User `json:"sender,omitempty"` + After *string `json:"after,omitempty"` + Created *bool `json:"created,omitempty"` + Deleted *bool `json:"deleted,omitempty"` + Forced *bool `json:"forced,omitempty"` + BaseRef *string `json:"base_ref,omitempty"` + Compare *string `json:"compare,omitempty"` + Repo *PushEventRepository `json:"repository,omitempty"` + HeadCommit *PushEventCommit `json:"head_commit,omitempty"` + Pusher *User `json:"pusher,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } func (p PushEvent) String() string { @@ -430,7 +534,7 @@ func (p PushEventCommit) String() string { return Stringify(p) } -// PushEventRepository represents the repo object in a PushEvent payload +// PushEventRepository represents the repo object in a PushEvent payload. type PushEventRepository struct { ID *int `json:"id,omitempty"` Name *string `json:"name,omitempty"` @@ -456,13 +560,17 @@ type PushEventRepository struct { DefaultBranch *string `json:"default_branch,omitempty"` MasterBranch *string `json:"master_branch,omitempty"` Organization *string `json:"organization,omitempty"` - - // The following fields are only populated by Webhook events. - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` + URL *string `json:"url,omitempty"` + ArchiveURL *string `json:"archive_url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + StatusesURL *string `json:"statuses_url,omitempty"` + GitURL *string `json:"git_url,omitempty"` + SSHURL *string `json:"ssh_url,omitempty"` + CloneURL *string `json:"clone_url,omitempty"` + SVNURL *string `json:"svn_url,omitempty"` } -// PushEventRepoOwner is a basic reporesntation of user/org in a PushEvent payload +// PushEventRepoOwner is a basic representation of user/org in a PushEvent payload. type PushEventRepoOwner struct { Name *string `json:"name,omitempty"` Email *string `json:"email,omitempty"` @@ -471,15 +579,16 @@ type PushEventRepoOwner struct { // ReleaseEvent is triggered when a release is published. // The Webhook event name is "release". // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#releaseevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#releaseevent type ReleaseEvent struct { // Action is the action that was performed. Possible value is: "published". Action *string `json:"action,omitempty"` Release *RepositoryRelease `json:"release,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // RepositoryEvent is triggered when a repository is created. @@ -488,7 +597,7 @@ type ReleaseEvent struct { // Events of this type are not visible in timelines, they are only used to // trigger organization webhooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#repositoryevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryevent type RepositoryEvent struct { // Action is the action that was performed. Possible values are: "created", "deleted", // "publicized", "privatized". @@ -496,8 +605,9 @@ type RepositoryEvent struct { Repo *Repository `json:"repository,omitempty"` // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // StatusEvent is triggered when the status of a Git commit changes. @@ -506,7 +616,7 @@ type RepositoryEvent struct { // Events of this type are not visible in timelines, they are only used to // trigger hooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#statusevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#statusevent type StatusEvent struct { SHA *string `json:"sha,omitempty"` // State is the new state. Possible values are: "pending", "success", "failure", "error". @@ -516,14 +626,15 @@ type StatusEvent struct { Branches []*Branch `json:"branches,omitempty"` // The following fields are only populated by Webhook events. - ID *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Context *string `json:"context,omitempty"` - Commit *RepositoryCommit `json:"commit,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + ID *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Context *string `json:"context,omitempty"` + Commit *RepositoryCommit `json:"commit,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // TeamAddEvent is triggered when a repository is added to a team. @@ -532,14 +643,15 @@ type StatusEvent struct { // Events of this type are not visible in timelines. These events are only used // to trigger hooks. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#teamaddevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamaddevent type TeamAddEvent struct { Team *Team `json:"team,omitempty"` Repo *Repository `json:"repository,omitempty"` // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } // WatchEvent is related to starring a repository, not watching. See this API @@ -548,12 +660,13 @@ type TeamAddEvent struct { // The event’s actor is the user who starred a repository, and the event’s // repository is the repository that was starred. // -// GitHub docs: https://developer.github.com/v3/activity/events/types/#watchevent +// GitHub API docs: https://developer.github.com/v3/activity/events/types/#watchevent type WatchEvent struct { // Action is the action that was performed. Possible value is: "started". Action *string `json:"action,omitempty"` // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` + Installation *Installation `json:"installation,omitempty"` } diff --git a/vendor/github.com/google/go-github/github/gen-accessors.go b/vendor/github.com/google/go-github/github/gen-accessors.go new file mode 100644 index 000000000..131c56cbf --- /dev/null +++ b/vendor/github.com/google/go-github/github/gen-accessors.go @@ -0,0 +1,299 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// gen-accessors generates accessor methods for structs with pointer fields. +// +// It is meant to be used by the go-github authors in conjunction with the +// go generate tool before sending a commit to GitHub. +package main + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "io/ioutil" + "log" + "os" + "sort" + "strings" + "text/template" + "time" +) + +const ( + fileSuffix = "-accessors.go" +) + +var ( + verbose = flag.Bool("v", false, "Print verbose log messages") + + sourceTmpl = template.Must(template.New("source").Parse(source)) + + // blacklist lists which "struct.method" combos to not generate. + blacklist = map[string]bool{ + "RepositoryContent.GetContent": true, + "Client.GetBaseURL": true, + "Client.GetUploadURL": true, + "ErrorResponse.GetResponse": true, + "RateLimitError.GetResponse": true, + "AbuseRateLimitError.GetResponse": true, + } +) + +func logf(fmt string, args ...interface{}) { + if *verbose { + log.Printf(fmt, args...) + } +} + +func main() { + flag.Parse() + fset := token.NewFileSet() + + pkgs, err := parser.ParseDir(fset, ".", sourceFilter, 0) + if err != nil { + log.Fatal(err) + return + } + + for pkgName, pkg := range pkgs { + t := &templateData{ + filename: pkgName + fileSuffix, + Year: time.Now().Year(), + Package: pkgName, + Imports: map[string]string{}, + } + for filename, f := range pkg.Files { + logf("Processing %v...", filename) + if err := t.processAST(f); err != nil { + log.Fatal(err) + } + } + if err := t.dump(); err != nil { + log.Fatal(err) + } + } + logf("Done.") +} + +func (t *templateData) processAST(f *ast.File) error { + for _, decl := range f.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + for _, spec := range gd.Specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + st, ok := ts.Type.(*ast.StructType) + if !ok { + continue + } + for _, field := range st.Fields.List { + se, ok := field.Type.(*ast.StarExpr) + if len(field.Names) == 0 || !ok { + continue + } + + fieldName := field.Names[0] + if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklist[key] { + logf("Method %v blacklisted; skipping.", key) + continue + } + + switch x := se.X.(type) { + case *ast.ArrayType: + t.addArrayType(x, ts.Name.String(), fieldName.String()) + case *ast.Ident: + t.addIdent(x, ts.Name.String(), fieldName.String()) + case *ast.MapType: + t.addMapType(x, ts.Name.String(), fieldName.String()) + case *ast.SelectorExpr: + t.addSelectorExpr(x, ts.Name.String(), fieldName.String()) + default: + logf("processAST: type %q, field %q, unknown %T: %+v", ts.Name, fieldName, x, x) + } + } + } + } + return nil +} + +func sourceFilter(fi os.FileInfo) bool { + return !strings.HasSuffix(fi.Name(), "_test.go") && !strings.HasSuffix(fi.Name(), fileSuffix) +} + +func (t *templateData) dump() error { + if len(t.Getters) == 0 { + logf("No getters for %v; skipping.", t.filename) + return nil + } + + // Sort getters by ReceiverType.FieldName + sort.Sort(byName(t.Getters)) + + var buf bytes.Buffer + if err := sourceTmpl.Execute(&buf, t); err != nil { + return err + } + clean, err := format.Source(buf.Bytes()) + if err != nil { + return err + } + + logf("Writing %v...", t.filename) + return ioutil.WriteFile(t.filename, clean, 0644) +} + +func newGetter(receiverType, fieldName, fieldType, zeroValue string) *getter { + return &getter{ + sortVal: strings.ToLower(receiverType) + "." + strings.ToLower(fieldName), + ReceiverVar: strings.ToLower(receiverType[:1]), + ReceiverType: receiverType, + FieldName: fieldName, + FieldType: fieldType, + ZeroValue: zeroValue, + } +} + +func (t *templateData) addArrayType(x *ast.ArrayType, receiverType, fieldName string) { + var eltType string + switch elt := x.Elt.(type) { + case *ast.Ident: + eltType = elt.String() + default: + logf("addArrayType: type %q, field %q: unknown elt type: %T %+v; skipping.", receiverType, fieldName, elt, elt) + return + } + + t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil")) +} + +func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) { + var zeroValue string + switch x.String() { + case "int": + zeroValue = "0" + case "string": + zeroValue = `""` + case "bool": + zeroValue = "false" + case "Timestamp": + zeroValue = "Timestamp{}" + default: // other structs handled by their receivers directly. + return + } + + t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue)) +} + +func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string) { + var keyType string + switch key := x.Key.(type) { + case *ast.Ident: + keyType = key.String() + default: + logf("addMapType: type %q, field %q: unknown key type: %T %+v; skipping.", receiverType, fieldName, key, key) + return + } + + var valueType string + switch value := x.Value.(type) { + case *ast.Ident: + valueType = value.String() + default: + logf("addMapType: type %q, field %q: unknown value type: %T %+v; skipping.", receiverType, fieldName, value, value) + return + } + + fieldType := fmt.Sprintf("map[%v]%v", keyType, valueType) + zeroValue := fmt.Sprintf("map[%v]%v{}", keyType, valueType) + t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue)) +} + +func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldName string) { + if strings.ToLower(fieldName[:1]) == fieldName[:1] { // non-exported field + return + } + + var xX string + if xx, ok := x.X.(*ast.Ident); ok { + xX = xx.String() + } + + switch xX { + case "time", "json": + if xX == "json" { + t.Imports["encoding/json"] = "encoding/json" + } else { + t.Imports[xX] = xX + } + fieldType := fmt.Sprintf("%v.%v", xX, x.Sel.Name) + zeroValue := fmt.Sprintf("%v.%v{}", xX, x.Sel.Name) + if xX == "time" && x.Sel.Name == "Duration" { + zeroValue = "0" + } + t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue)) + default: + logf("addSelectorExpr: xX %q, type %q, field %q: unknown x=%+v; skipping.", xX, receiverType, fieldName, x) + } +} + +type templateData struct { + filename string + Year int + Package string + Imports map[string]string + Getters []*getter +} + +type getter struct { + sortVal string // lower-case version of "ReceiverType.FieldName" + ReceiverVar string // the one-letter variable name to match the ReceiverType + ReceiverType string + FieldName string + FieldType string + ZeroValue string +} + +type byName []*getter + +func (b byName) Len() int { return len(b) } +func (b byName) Less(i, j int) bool { return b[i].sortVal < b[j].sortVal } +func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +const source = `// Copyright {{.Year}} The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by gen-accessors; DO NOT EDIT. + +package {{.Package}} +{{with .Imports}} +import ( + {{- range . -}} + "{{.}}" + {{end -}} +) +{{end}} +{{range .Getters}} +// Get{{.FieldName}} returns the {{.FieldName}} field if it's non-nil, zero value otherwise. +func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} { + if {{.ReceiverVar}} == nil || {{.ReceiverVar}}.{{.FieldName}} == nil { + return {{.ZeroValue}} + } + return *{{.ReceiverVar}}.{{.FieldName}} +} +{{end}} +` diff --git a/vendor/github.com/google/go-github/github/gists.go b/vendor/github.com/google/go-github/github/gists.go index a3327f840..e7d6586c6 100644 --- a/vendor/github.com/google/go-github/github/gists.go +++ b/vendor/github.com/google/go-github/github/gists.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -13,7 +14,7 @@ import ( // GistsService handles communication with the Gist related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/gists/ +// GitHub API docs: https://developer.github.com/v3/gists/ type GistsService service // Gist represents a GitHub's gist. @@ -42,6 +43,7 @@ type GistFilename string type GistFile struct { Size *int `json:"size,omitempty"` Filename *string `json:"filename,omitempty"` + Language *string `json:"language,omitempty"` Type *string `json:"type,omitempty"` RawURL *string `json:"raw_url,omitempty"` Content *string `json:"content,omitempty"` @@ -57,7 +59,7 @@ type GistCommit struct { Version *string `json:"version,omitempty"` User *User `json:"user,omitempty"` ChangeStatus *CommitStats `json:"change_status,omitempty"` - CommitedAt *Timestamp `json:"commited_at,omitempty"` + CommittedAt *Timestamp `json:"committed_at,omitempty"` } func (gc GistCommit) String() string { @@ -91,8 +93,8 @@ type GistListOptions struct { // is authenticated, it will returns all gists for the authenticated // user. // -// GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) List(user string, opt *GistListOptions) ([]*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#list-gists +func (s *GistsService) List(ctx context.Context, user string, opt *GistListOptions) ([]*Gist, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/gists", user) @@ -109,19 +111,19 @@ func (s *GistsService) List(user string, opt *GistListOptions) ([]*Gist, *Respon return nil, nil, err } - gists := new([]*Gist) - resp, err := s.client.Do(req, gists) + var gists []*Gist + resp, err := s.client.Do(ctx, req, &gists) if err != nil { return nil, resp, err } - return *gists, resp, err + return gists, resp, nil } // ListAll lists all public gists. // -// GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListAll(opt *GistListOptions) ([]*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#list-gists +func (s *GistsService) ListAll(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { u, err := addOptions("gists/public", opt) if err != nil { return nil, nil, err @@ -132,19 +134,19 @@ func (s *GistsService) ListAll(opt *GistListOptions) ([]*Gist, *Response, error) return nil, nil, err } - gists := new([]*Gist) - resp, err := s.client.Do(req, gists) + var gists []*Gist + resp, err := s.client.Do(ctx, req, &gists) if err != nil { return nil, resp, err } - return *gists, resp, err + return gists, resp, nil } // ListStarred lists starred gists of authenticated user. // -// GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListStarred(opt *GistListOptions) ([]*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#list-gists +func (s *GistsService) ListStarred(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { u, err := addOptions("gists/starred", opt) if err != nil { return nil, nil, err @@ -155,160 +157,160 @@ func (s *GistsService) ListStarred(opt *GistListOptions) ([]*Gist, *Response, er return nil, nil, err } - gists := new([]*Gist) - resp, err := s.client.Do(req, gists) + var gists []*Gist + resp, err := s.client.Do(ctx, req, &gists) if err != nil { return nil, resp, err } - return *gists, resp, err + return gists, resp, nil } // Get a single gist. // -// GitHub API docs: http://developer.github.com/v3/gists/#get-a-single-gist -func (s *GistsService) Get(id string) (*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#get-a-single-gist +func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) { u := fmt.Sprintf("gists/%v", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } gist := new(Gist) - resp, err := s.client.Do(req, gist) + resp, err := s.client.Do(ctx, req, gist) if err != nil { return nil, resp, err } - return gist, resp, err + return gist, resp, nil } // GetRevision gets a specific revision of a gist. // // GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist -func (s *GistsService) GetRevision(id, sha string) (*Gist, *Response, error) { +func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) { u := fmt.Sprintf("gists/%v/%v", id, sha) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } gist := new(Gist) - resp, err := s.client.Do(req, gist) + resp, err := s.client.Do(ctx, req, gist) if err != nil { return nil, resp, err } - return gist, resp, err + return gist, resp, nil } // Create a gist for authenticated user. // -// GitHub API docs: http://developer.github.com/v3/gists/#create-a-gist -func (s *GistsService) Create(gist *Gist) (*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist +func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) { u := "gists" req, err := s.client.NewRequest("POST", u, gist) if err != nil { return nil, nil, err } g := new(Gist) - resp, err := s.client.Do(req, g) + resp, err := s.client.Do(ctx, req, g) if err != nil { return nil, resp, err } - return g, resp, err + return g, resp, nil } // Edit a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/#edit-a-gist -func (s *GistsService) Edit(id string, gist *Gist) (*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#edit-a-gist +func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) { u := fmt.Sprintf("gists/%v", id) req, err := s.client.NewRequest("PATCH", u, gist) if err != nil { return nil, nil, err } g := new(Gist) - resp, err := s.client.Do(req, g) + resp, err := s.client.Do(ctx, req, g) if err != nil { return nil, resp, err } - return g, resp, err + return g, resp, nil } // ListCommits lists commits of a gist. // -// Github API docs: https://developer.github.com/v3/gists/#list-gist-commits -func (s *GistsService) ListCommits(id string) ([]*GistCommit, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits +func (s *GistsService) ListCommits(ctx context.Context, id string) ([]*GistCommit, *Response, error) { u := fmt.Sprintf("gists/%v/commits", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - gistCommits := new([]*GistCommit) - resp, err := s.client.Do(req, gistCommits) + var gistCommits []*GistCommit + resp, err := s.client.Do(ctx, req, &gistCommits) if err != nil { return nil, resp, err } - return *gistCommits, resp, err + return gistCommits, resp, nil } // Delete a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/#delete-a-gist -func (s *GistsService) Delete(id string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist +func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) { u := fmt.Sprintf("gists/%v", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Star a gist on behalf of authenticated user. // -// GitHub API docs: http://developer.github.com/v3/gists/#star-a-gist -func (s *GistsService) Star(id string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist +func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) { u := fmt.Sprintf("gists/%v/star", id) req, err := s.client.NewRequest("PUT", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Unstar a gist on a behalf of authenticated user. // -// Github API docs: http://developer.github.com/v3/gists/#unstar-a-gist -func (s *GistsService) Unstar(id string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist +func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) { u := fmt.Sprintf("gists/%v/star", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // IsStarred checks if a gist is starred by authenticated user. // -// GitHub API docs: http://developer.github.com/v3/gists/#check-if-a-gist-is-starred -func (s *GistsService) IsStarred(id string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred +func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) { u := fmt.Sprintf("gists/%v/star", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) starred, err := parseBoolResponse(err) return starred, resp, err } // Fork a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/#fork-a-gist -func (s *GistsService) Fork(id string) (*Gist, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist +func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) { u := fmt.Sprintf("gists/%v/forks", id) req, err := s.client.NewRequest("POST", u, nil) if err != nil { @@ -316,29 +318,29 @@ func (s *GistsService) Fork(id string) (*Gist, *Response, error) { } g := new(Gist) - resp, err := s.client.Do(req, g) + resp, err := s.client.Do(ctx, req, g) if err != nil { return nil, resp, err } - return g, resp, err + return g, resp, nil } // ListForks lists forks of a gist. // -// Github API docs: https://developer.github.com/v3/gists/#list-gist-forks -func (s *GistsService) ListForks(id string) ([]*GistFork, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks +func (s *GistsService) ListForks(ctx context.Context, id string) ([]*GistFork, *Response, error) { u := fmt.Sprintf("gists/%v/forks", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - gistForks := new([]*GistFork) - resp, err := s.client.Do(req, gistForks) + var gistForks []*GistFork + resp, err := s.client.Do(ctx, req, &gistForks) if err != nil { return nil, resp, err } - return *gistForks, resp, err + return gistForks, resp, nil } diff --git a/vendor/github.com/google/go-github/github/gists_comments.go b/vendor/github.com/google/go-github/github/gists_comments.go index 95a7fc76c..2d0722375 100644 --- a/vendor/github.com/google/go-github/github/gists_comments.go +++ b/vendor/github.com/google/go-github/github/gists_comments.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -25,8 +26,8 @@ func (g GistComment) String() string { // ListComments lists all comments for a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/comments/#list-comments-on-a-gist -func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]*GistComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/comments/#list-comments-on-a-gist +func (s *GistsService) ListComments(ctx context.Context, gistID string, opt *ListOptions) ([]*GistComment, *Response, error) { u := fmt.Sprintf("gists/%v/comments", gistID) u, err := addOptions(u, opt) if err != nil { @@ -38,19 +39,19 @@ func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]*GistCom return nil, nil, err } - comments := new([]*GistComment) - resp, err := s.client.Do(req, comments) + var comments []*GistComment + resp, err := s.client.Do(ctx, req, &comments) if err != nil { return nil, resp, err } - return *comments, resp, err + return comments, resp, nil } // GetComment retrieves a single comment from a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/comments/#get-a-single-comment -func (s *GistsService) GetComment(gistID string, commentID int) (*GistComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/comments/#get-a-single-comment +func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int) (*GistComment, *Response, error) { u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -58,18 +59,18 @@ func (s *GistsService) GetComment(gistID string, commentID int) (*GistComment, * } c := new(GistComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // CreateComment creates a comment for a gist. // -// GitHub API docs: http://developer.github.com/v3/gists/comments/#create-a-comment -func (s *GistsService) CreateComment(gistID string, comment *GistComment) (*GistComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/comments/#create-a-comment +func (s *GistsService) CreateComment(ctx context.Context, gistID string, comment *GistComment) (*GistComment, *Response, error) { u := fmt.Sprintf("gists/%v/comments", gistID) req, err := s.client.NewRequest("POST", u, comment) if err != nil { @@ -77,18 +78,18 @@ func (s *GistsService) CreateComment(gistID string, comment *GistComment) (*Gist } c := new(GistComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // EditComment edits an existing gist comment. // -// GitHub API docs: http://developer.github.com/v3/gists/comments/#edit-a-comment -func (s *GistsService) EditComment(gistID string, commentID int, comment *GistComment) (*GistComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/comments/#edit-a-comment +func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int, comment *GistComment) (*GistComment, *Response, error) { u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { @@ -96,23 +97,23 @@ func (s *GistsService) EditComment(gistID string, commentID int, comment *GistCo } c := new(GistComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // DeleteComment deletes a gist comment. // -// GitHub API docs: http://developer.github.com/v3/gists/comments/#delete-a-comment -func (s *GistsService) DeleteComment(gistID string, commentID int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/gists/comments/#delete-a-comment +func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int) (*Response, error) { u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/git.go b/vendor/github.com/google/go-github/github/git.go index c934751a9..1ce47437b 100644 --- a/vendor/github.com/google/go-github/github/git.go +++ b/vendor/github.com/google/go-github/github/git.go @@ -8,5 +8,5 @@ package github // GitService handles communication with the git data related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/git/ +// GitHub API docs: https://developer.github.com/v3/git/ type GitService service diff --git a/vendor/github.com/google/go-github/github/git_blobs.go b/vendor/github.com/google/go-github/github/git_blobs.go index 55148fdb4..67ea74a19 100644 --- a/vendor/github.com/google/go-github/github/git_blobs.go +++ b/vendor/github.com/google/go-github/github/git_blobs.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Blob represents a blob object. type Blob struct { @@ -18,8 +21,8 @@ type Blob struct { // GetBlob fetchs a blob from a repo given a SHA. // -// GitHub API docs: http://developer.github.com/v3/git/blobs/#get-a-blob -func (s *GitService) GetBlob(owner string, repo string, sha string) (*Blob, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob +func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -27,14 +30,14 @@ func (s *GitService) GetBlob(owner string, repo string, sha string) (*Blob, *Res } blob := new(Blob) - resp, err := s.client.Do(req, blob) + resp, err := s.client.Do(ctx, req, blob) return blob, resp, err } // CreateBlob creates a blob object. // // GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob -func (s *GitService) CreateBlob(owner string, repo string, blob *Blob) (*Blob, *Response, error) { +func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string, blob *Blob) (*Blob, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo) req, err := s.client.NewRequest("POST", u, blob) if err != nil { @@ -42,6 +45,6 @@ func (s *GitService) CreateBlob(owner string, repo string, blob *Blob) (*Blob, * } t := new(Blob) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) return t, resp, err } diff --git a/vendor/github.com/google/go-github/github/git_commits.go b/vendor/github.com/google/go-github/github/git_commits.go index 0bcad41d9..3c49a8a29 100644 --- a/vendor/github.com/google/go-github/github/git_commits.go +++ b/vendor/github.com/google/go-github/github/git_commits.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -27,10 +28,11 @@ type Commit struct { Tree *Tree `json:"tree,omitempty"` Parents []Commit `json:"parents,omitempty"` Stats *CommitStats `json:"stats,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` URL *string `json:"url,omitempty"` Verification *SignatureVerification `json:"verification,omitempty"` - // CommentCount is the number of GitHub comments on the commit. This + // CommentCount is the number of GitHub comments on the commit. This // is only populated for requests that fetch GitHub data like // Pulls.ListCommits, Repositories.ListCommits, etc. CommentCount *int `json:"comment_count,omitempty"` @@ -40,7 +42,7 @@ func (c Commit) String() string { return Stringify(c) } -// CommitAuthor represents the author or committer of a commit. The commit +// CommitAuthor represents the author or committer of a commit. The commit // author may not correspond to a GitHub User. type CommitAuthor struct { Date *time.Time `json:"date,omitempty"` @@ -57,8 +59,8 @@ func (c CommitAuthor) String() string { // GetCommit fetchs the Commit object for a given SHA. // -// GitHub API docs: http://developer.github.com/v3/git/commits/#get-a-commit -func (s *GitService) GetCommit(owner string, repo string, sha string) (*Commit, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit +func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/commits/%v", owner, repo, sha) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -69,12 +71,12 @@ func (s *GitService) GetCommit(owner string, repo string, sha string) (*Commit, req.Header.Set("Accept", mediaTypeGitSigningPreview) c := new(Commit) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // createCommit represents the body of a CreateCommit request. @@ -87,29 +89,33 @@ type createCommit struct { } // CreateCommit creates a new commit in a repository. +// commit must not be nil. // // The commit.Committer is optional and will be filled with the commit.Author // data if omitted. If the commit.Author is omitted, it will be filled in with // the authenticated user’s information and the current date. // -// GitHub API docs: http://developer.github.com/v3/git/commits/#create-a-commit -func (s *GitService) CreateCommit(owner string, repo string, commit *Commit) (*Commit, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/commits/#create-a-commit +func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string, commit *Commit) (*Commit, *Response, error) { + if commit == nil { + return nil, nil, fmt.Errorf("commit must be provided") + } + u := fmt.Sprintf("repos/%v/%v/git/commits", owner, repo) - body := &createCommit{} - if commit != nil { - parents := make([]string, len(commit.Parents)) - for i, parent := range commit.Parents { - parents[i] = *parent.SHA - } + parents := make([]string, len(commit.Parents)) + for i, parent := range commit.Parents { + parents[i] = *parent.SHA + } - body = &createCommit{ - Author: commit.Author, - Committer: commit.Committer, - Message: commit.Message, - Tree: commit.Tree.SHA, - Parents: parents, - } + body := &createCommit{ + Author: commit.Author, + Committer: commit.Committer, + Message: commit.Message, + Parents: parents, + } + if commit.Tree != nil { + body.Tree = commit.Tree.SHA } req, err := s.client.NewRequest("POST", u, body) @@ -118,10 +124,10 @@ func (s *GitService) CreateCommit(owner string, repo string, commit *Commit) (*C } c := new(Commit) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } diff --git a/vendor/github.com/google/go-github/github/git_refs.go b/vendor/github.com/google/go-github/github/git_refs.go index 16cbd6b3d..bd5df3f72 100644 --- a/vendor/github.com/google/go-github/github/git_refs.go +++ b/vendor/github.com/google/go-github/github/git_refs.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "strings" ) @@ -46,8 +47,8 @@ type updateRefRequest struct { // GetRef fetches the Reference object for a given Git ref. // -// GitHub API docs: http://developer.github.com/v3/git/refs/#get-a-reference -func (s *GitService) GetRef(owner string, repo string, ref string) (*Reference, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference +func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) { ref = strings.TrimPrefix(ref, "refs/") u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref) req, err := s.client.NewRequest("GET", u, nil) @@ -56,12 +57,12 @@ func (s *GitService) GetRef(owner string, repo string, ref string) (*Reference, } r := new(Reference) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // ReferenceListOptions specifies optional parameters to the @@ -74,8 +75,8 @@ type ReferenceListOptions struct { // ListRefs lists all refs in a repository. // -// GitHub API docs: http://developer.github.com/v3/git/refs/#get-all-references -func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references +func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) { var u string if opt != nil && opt.Type != "" { u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type) @@ -93,18 +94,18 @@ func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([] } var rs []*Reference - resp, err := s.client.Do(req, &rs) + resp, err := s.client.Do(ctx, req, &rs) if err != nil { return nil, resp, err } - return rs, resp, err + return rs, resp, nil } // CreateRef creates a new ref in a repository. // -// GitHub API docs: http://developer.github.com/v3/git/refs/#create-a-reference -func (s *GitService) CreateRef(owner string, repo string, ref *Reference) (*Reference, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference +func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) req, err := s.client.NewRequest("POST", u, &createRefRequest{ // back-compat with previous behavior that didn't require 'refs/' prefix @@ -116,18 +117,18 @@ func (s *GitService) CreateRef(owner string, repo string, ref *Reference) (*Refe } r := new(Reference) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // UpdateRef updates an existing ref in a repository. // -// GitHub API docs: http://developer.github.com/v3/git/refs/#update-a-reference -func (s *GitService) UpdateRef(owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference +func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) { refPath := strings.TrimPrefix(*ref.Ref, "refs/") u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath) req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{ @@ -139,18 +140,18 @@ func (s *GitService) UpdateRef(owner string, repo string, ref *Reference, force } r := new(Reference) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // DeleteRef deletes a ref from a repository. // -// GitHub API docs: http://developer.github.com/v3/git/refs/#delete-a-reference -func (s *GitService) DeleteRef(owner string, repo string, ref string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference +func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) { ref = strings.TrimPrefix(ref, "refs/") u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref) req, err := s.client.NewRequest("DELETE", u, nil) @@ -158,5 +159,5 @@ func (s *GitService) DeleteRef(owner string, repo string, ref string) (*Response return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/git_tags.go b/vendor/github.com/google/go-github/github/git_tags.go index 01b9cb2af..08df3d3d1 100644 --- a/vendor/github.com/google/go-github/github/git_tags.go +++ b/vendor/github.com/google/go-github/github/git_tags.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" ) @@ -20,7 +21,7 @@ type Tag struct { Verification *SignatureVerification `json:"verification,omitempty"` } -// createTagRequest represents the body of a CreateTag request. This is mostly +// createTagRequest represents the body of a CreateTag request. This is mostly // identical to Tag with the exception that the object SHA and Type are // top-level fields, rather than being nested inside a JSON object. type createTagRequest struct { @@ -33,8 +34,8 @@ type createTagRequest struct { // GetTag fetchs a tag from a repo given a SHA. // -// GitHub API docs: http://developer.github.com/v3/git/tags/#get-a-tag -func (s *GitService) GetTag(owner string, repo string, sha string) (*Tag, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag +func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -45,14 +46,14 @@ func (s *GitService) GetTag(owner string, repo string, sha string) (*Tag, *Respo req.Header.Set("Accept", mediaTypeGitSigningPreview) tag := new(Tag) - resp, err := s.client.Do(req, tag) + resp, err := s.client.Do(ctx, req, tag) return tag, resp, err } // CreateTag creates a tag object. // -// GitHub API docs: http://developer.github.com/v3/git/tags/#create-a-tag-object -func (s *GitService) CreateTag(owner string, repo string, tag *Tag) (*Tag, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/tags/#create-a-tag-object +func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, tag *Tag) (*Tag, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo) // convert Tag into a createTagRequest @@ -72,6 +73,6 @@ func (s *GitService) CreateTag(owner string, repo string, tag *Tag) (*Tag, *Resp } t := new(Tag) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) return t, resp, err } diff --git a/vendor/github.com/google/go-github/github/git_trees.go b/vendor/github.com/google/go-github/github/git_trees.go index 9efa4b380..bdd481f1e 100644 --- a/vendor/github.com/google/go-github/github/git_trees.go +++ b/vendor/github.com/google/go-github/github/git_trees.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Tree represents a GitHub tree. type Tree struct { @@ -17,7 +20,7 @@ func (t Tree) String() string { return Stringify(t) } -// TreeEntry represents the contents of a tree structure. TreeEntry can +// TreeEntry represents the contents of a tree structure. TreeEntry can // represent either a blob, a commit (in the case of a submodule), or another // tree. type TreeEntry struct { @@ -35,8 +38,8 @@ func (t TreeEntry) String() string { // GetTree fetches the Tree object for a given sha hash from a repository. // -// GitHub API docs: http://developer.github.com/v3/git/trees/#get-a-tree -func (s *GitService) GetTree(owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/trees/#get-a-tree +func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) if recursive { u += "?recursive=1" @@ -48,12 +51,12 @@ func (s *GitService) GetTree(owner string, repo string, sha string, recursive bo } t := new(Tree) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // createTree represents the body of a CreateTree request. @@ -62,12 +65,12 @@ type createTree struct { Entries []TreeEntry `json:"tree"` } -// CreateTree creates a new tree in a repository. If both a tree and a nested +// CreateTree creates a new tree in a repository. If both a tree and a nested // path modifying that tree are specified, it will overwrite the contents of // that tree with the new path contents and write a new tree out. // -// GitHub API docs: http://developer.github.com/v3/git/trees/#create-a-tree -func (s *GitService) CreateTree(owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/git/trees/#create-a-tree +func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) { u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) body := &createTree{ @@ -80,10 +83,10 @@ func (s *GitService) CreateTree(owner string, repo string, baseTree string, entr } t := new(Tree) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } diff --git a/vendor/github.com/google/go-github/github/github-accessors.go b/vendor/github.com/google/go-github/github/github-accessors.go new file mode 100644 index 000000000..c74c02548 --- /dev/null +++ b/vendor/github.com/google/go-github/github/github-accessors.go @@ -0,0 +1,7277 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by gen-accessors; DO NOT EDIT. + +package github + +import ( + "encoding/json" + "time" +) + +// GetRetryAfter returns the RetryAfter field if it's non-nil, zero value otherwise. +func (a *AbuseRateLimitError) GetRetryAfter() time.Duration { + if a == nil || a.RetryAfter == nil { + return 0 + } + return *a.RetryAfter +} + +// GetVerifiablePasswordAuthentication returns the VerifiablePasswordAuthentication field if it's non-nil, zero value otherwise. +func (a *APIMeta) GetVerifiablePasswordAuthentication() bool { + if a == nil || a.VerifiablePasswordAuthentication == nil { + return false + } + return *a.VerifiablePasswordAuthentication +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (a *Authorization) GetCreatedAt() Timestamp { + if a == nil || a.CreatedAt == nil { + return Timestamp{} + } + return *a.CreatedAt +} + +// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. +func (a *Authorization) GetFingerprint() string { + if a == nil || a.Fingerprint == nil { + return "" + } + return *a.Fingerprint +} + +// GetHashedToken returns the HashedToken field if it's non-nil, zero value otherwise. +func (a *Authorization) GetHashedToken() string { + if a == nil || a.HashedToken == nil { + return "" + } + return *a.HashedToken +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (a *Authorization) GetID() int { + if a == nil || a.ID == nil { + return 0 + } + return *a.ID +} + +// GetNote returns the Note field if it's non-nil, zero value otherwise. +func (a *Authorization) GetNote() string { + if a == nil || a.Note == nil { + return "" + } + return *a.Note +} + +// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. +func (a *Authorization) GetNoteURL() string { + if a == nil || a.NoteURL == nil { + return "" + } + return *a.NoteURL +} + +// GetToken returns the Token field if it's non-nil, zero value otherwise. +func (a *Authorization) GetToken() string { + if a == nil || a.Token == nil { + return "" + } + return *a.Token +} + +// GetTokenLastEight returns the TokenLastEight field if it's non-nil, zero value otherwise. +func (a *Authorization) GetTokenLastEight() string { + if a == nil || a.TokenLastEight == nil { + return "" + } + return *a.TokenLastEight +} + +// GetUpdateAt returns the UpdateAt field if it's non-nil, zero value otherwise. +func (a *Authorization) GetUpdateAt() Timestamp { + if a == nil || a.UpdateAt == nil { + return Timestamp{} + } + return *a.UpdateAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (a *Authorization) GetURL() string { + if a == nil || a.URL == nil { + return "" + } + return *a.URL +} + +// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. +func (a *AuthorizationApp) GetClientID() string { + if a == nil || a.ClientID == nil { + return "" + } + return *a.ClientID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (a *AuthorizationApp) GetName() string { + if a == nil || a.Name == nil { + return "" + } + return *a.Name +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (a *AuthorizationApp) GetURL() string { + if a == nil || a.URL == nil { + return "" + } + return *a.URL +} + +// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. +func (a *AuthorizationRequest) GetClientID() string { + if a == nil || a.ClientID == nil { + return "" + } + return *a.ClientID +} + +// GetClientSecret returns the ClientSecret field if it's non-nil, zero value otherwise. +func (a *AuthorizationRequest) GetClientSecret() string { + if a == nil || a.ClientSecret == nil { + return "" + } + return *a.ClientSecret +} + +// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. +func (a *AuthorizationRequest) GetFingerprint() string { + if a == nil || a.Fingerprint == nil { + return "" + } + return *a.Fingerprint +} + +// GetNote returns the Note field if it's non-nil, zero value otherwise. +func (a *AuthorizationRequest) GetNote() string { + if a == nil || a.Note == nil { + return "" + } + return *a.Note +} + +// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. +func (a *AuthorizationRequest) GetNoteURL() string { + if a == nil || a.NoteURL == nil { + return "" + } + return *a.NoteURL +} + +// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. +func (a *AuthorizationUpdateRequest) GetFingerprint() string { + if a == nil || a.Fingerprint == nil { + return "" + } + return *a.Fingerprint +} + +// GetNote returns the Note field if it's non-nil, zero value otherwise. +func (a *AuthorizationUpdateRequest) GetNote() string { + if a == nil || a.Note == nil { + return "" + } + return *a.Note +} + +// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. +func (a *AuthorizationUpdateRequest) GetNoteURL() string { + if a == nil || a.NoteURL == nil { + return "" + } + return *a.NoteURL +} + +// GetContent returns the Content field if it's non-nil, zero value otherwise. +func (b *Blob) GetContent() string { + if b == nil || b.Content == nil { + return "" + } + return *b.Content +} + +// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. +func (b *Blob) GetEncoding() string { + if b == nil || b.Encoding == nil { + return "" + } + return *b.Encoding +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (b *Blob) GetSHA() string { + if b == nil || b.SHA == nil { + return "" + } + return *b.SHA +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (b *Blob) GetSize() int { + if b == nil || b.Size == nil { + return 0 + } + return *b.Size +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (b *Blob) GetURL() string { + if b == nil || b.URL == nil { + return "" + } + return *b.URL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (b *Branch) GetName() string { + if b == nil || b.Name == nil { + return "" + } + return *b.Name +} + +// GetProtected returns the Protected field if it's non-nil, zero value otherwise. +func (b *Branch) GetProtected() bool { + if b == nil || b.Protected == nil { + return false + } + return *b.Protected +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (c *CodeResult) GetHTMLURL() string { + if c == nil || c.HTMLURL == nil { + return "" + } + return *c.HTMLURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (c *CodeResult) GetName() string { + if c == nil || c.Name == nil { + return "" + } + return *c.Name +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (c *CodeResult) GetPath() string { + if c == nil || c.Path == nil { + return "" + } + return *c.Path +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *CodeResult) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. +func (c *CodeSearchResult) GetIncompleteResults() bool { + if c == nil || c.IncompleteResults == nil { + return false + } + return *c.IncompleteResults +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (c *CodeSearchResult) GetTotal() int { + if c == nil || c.Total == nil { + return 0 + } + return *c.Total +} + +// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetCommitURL() string { + if c == nil || c.CommitURL == nil { + return "" + } + return *c.CommitURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetName() string { + if c == nil || c.Name == nil { + return "" + } + return *c.Name +} + +// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetRepositoryURL() string { + if c == nil || c.RepositoryURL == nil { + return "" + } + return *c.RepositoryURL +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetState() string { + if c == nil || c.State == nil { + return "" + } + return *c.State +} + +// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. +func (c *CombinedStatus) GetTotalCount() int { + if c == nil || c.TotalCount == nil { + return 0 + } + return *c.TotalCount +} + +// GetCommentCount returns the CommentCount field if it's non-nil, zero value otherwise. +func (c *Commit) GetCommentCount() int { + if c == nil || c.CommentCount == nil { + return 0 + } + return *c.CommentCount +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (c *Commit) GetHTMLURL() string { + if c == nil || c.HTMLURL == nil { + return "" + } + return *c.HTMLURL +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (c *Commit) GetMessage() string { + if c == nil || c.Message == nil { + return "" + } + return *c.Message +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *Commit) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (c *Commit) GetURL() string { + if c == nil || c.URL == nil { + return "" + } + return *c.URL +} + +// GetDate returns the Date field if it's non-nil, zero value otherwise. +func (c *CommitAuthor) GetDate() time.Time { + if c == nil || c.Date == nil { + return time.Time{} + } + return *c.Date +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (c *CommitAuthor) GetEmail() string { + if c == nil || c.Email == nil { + return "" + } + return *c.Email +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (c *CommitAuthor) GetLogin() string { + if c == nil || c.Login == nil { + return "" + } + return *c.Login +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (c *CommitAuthor) GetName() string { + if c == nil || c.Name == nil { + return "" + } + return *c.Name +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (c *CommitCommentEvent) GetAction() string { + if c == nil || c.Action == nil { + return "" + } + return *c.Action +} + +// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetAdditions() int { + if c == nil || c.Additions == nil { + return 0 + } + return *c.Additions +} + +// GetBlobURL returns the BlobURL field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetBlobURL() string { + if c == nil || c.BlobURL == nil { + return "" + } + return *c.BlobURL +} + +// GetChanges returns the Changes field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetChanges() int { + if c == nil || c.Changes == nil { + return 0 + } + return *c.Changes +} + +// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetContentsURL() string { + if c == nil || c.ContentsURL == nil { + return "" + } + return *c.ContentsURL +} + +// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetDeletions() int { + if c == nil || c.Deletions == nil { + return 0 + } + return *c.Deletions +} + +// GetFilename returns the Filename field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetFilename() string { + if c == nil || c.Filename == nil { + return "" + } + return *c.Filename +} + +// GetPatch returns the Patch field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetPatch() string { + if c == nil || c.Patch == nil { + return "" + } + return *c.Patch +} + +// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetRawURL() string { + if c == nil || c.RawURL == nil { + return "" + } + return *c.RawURL +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (c *CommitFile) GetStatus() string { + if c == nil || c.Status == nil { + return "" + } + return *c.Status +} + +// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. +func (c *CommitResult) GetCommentsURL() string { + if c == nil || c.CommentsURL == nil { + return "" + } + return *c.CommentsURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (c *CommitResult) GetHTMLURL() string { + if c == nil || c.HTMLURL == nil { + return "" + } + return *c.HTMLURL +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *CommitResult) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (c *CommitResult) GetURL() string { + if c == nil || c.URL == nil { + return "" + } + return *c.URL +} + +// GetAheadBy returns the AheadBy field if it's non-nil, zero value otherwise. +func (c *CommitsComparison) GetAheadBy() int { + if c == nil || c.AheadBy == nil { + return 0 + } + return *c.AheadBy +} + +// GetBehindBy returns the BehindBy field if it's non-nil, zero value otherwise. +func (c *CommitsComparison) GetBehindBy() int { + if c == nil || c.BehindBy == nil { + return 0 + } + return *c.BehindBy +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (c *CommitsComparison) GetStatus() string { + if c == nil || c.Status == nil { + return "" + } + return *c.Status +} + +// GetTotalCommits returns the TotalCommits field if it's non-nil, zero value otherwise. +func (c *CommitsComparison) GetTotalCommits() int { + if c == nil || c.TotalCommits == nil { + return 0 + } + return *c.TotalCommits +} + +// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. +func (c *CommitsSearchResult) GetIncompleteResults() bool { + if c == nil || c.IncompleteResults == nil { + return false + } + return *c.IncompleteResults +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (c *CommitsSearchResult) GetTotal() int { + if c == nil || c.Total == nil { + return 0 + } + return *c.Total +} + +// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. +func (c *CommitStats) GetAdditions() int { + if c == nil || c.Additions == nil { + return 0 + } + return *c.Additions +} + +// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. +func (c *CommitStats) GetDeletions() int { + if c == nil || c.Deletions == nil { + return 0 + } + return *c.Deletions +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (c *CommitStats) GetTotal() int { + if c == nil || c.Total == nil { + return 0 + } + return *c.Total +} + +// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetAvatarURL() string { + if c == nil || c.AvatarURL == nil { + return "" + } + return *c.AvatarURL +} + +// GetContributions returns the Contributions field if it's non-nil, zero value otherwise. +func (c *Contributor) GetContributions() int { + if c == nil || c.Contributions == nil { + return 0 + } + return *c.Contributions +} + +// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetEventsURL() string { + if c == nil || c.EventsURL == nil { + return "" + } + return *c.EventsURL +} + +// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetFollowersURL() string { + if c == nil || c.FollowersURL == nil { + return "" + } + return *c.FollowersURL +} + +// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetFollowingURL() string { + if c == nil || c.FollowingURL == nil { + return "" + } + return *c.FollowingURL +} + +// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetGistsURL() string { + if c == nil || c.GistsURL == nil { + return "" + } + return *c.GistsURL +} + +// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. +func (c *Contributor) GetGravatarID() string { + if c == nil || c.GravatarID == nil { + return "" + } + return *c.GravatarID +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetHTMLURL() string { + if c == nil || c.HTMLURL == nil { + return "" + } + return *c.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (c *Contributor) GetID() int { + if c == nil || c.ID == nil { + return 0 + } + return *c.ID +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (c *Contributor) GetLogin() string { + if c == nil || c.Login == nil { + return "" + } + return *c.Login +} + +// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetOrganizationsURL() string { + if c == nil || c.OrganizationsURL == nil { + return "" + } + return *c.OrganizationsURL +} + +// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetReceivedEventsURL() string { + if c == nil || c.ReceivedEventsURL == nil { + return "" + } + return *c.ReceivedEventsURL +} + +// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetReposURL() string { + if c == nil || c.ReposURL == nil { + return "" + } + return *c.ReposURL +} + +// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. +func (c *Contributor) GetSiteAdmin() bool { + if c == nil || c.SiteAdmin == nil { + return false + } + return *c.SiteAdmin +} + +// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetStarredURL() string { + if c == nil || c.StarredURL == nil { + return "" + } + return *c.StarredURL +} + +// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetSubscriptionsURL() string { + if c == nil || c.SubscriptionsURL == nil { + return "" + } + return *c.SubscriptionsURL +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (c *Contributor) GetType() string { + if c == nil || c.Type == nil { + return "" + } + return *c.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (c *Contributor) GetURL() string { + if c == nil || c.URL == nil { + return "" + } + return *c.URL +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (c *ContributorStats) GetTotal() int { + if c == nil || c.Total == nil { + return 0 + } + return *c.Total +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (c *createCommit) GetMessage() string { + if c == nil || c.Message == nil { + return "" + } + return *c.Message +} + +// GetTree returns the Tree field if it's non-nil, zero value otherwise. +func (c *createCommit) GetTree() string { + if c == nil || c.Tree == nil { + return "" + } + return *c.Tree +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (c *CreateEvent) GetDescription() string { + if c == nil || c.Description == nil { + return "" + } + return *c.Description +} + +// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. +func (c *CreateEvent) GetMasterBranch() string { + if c == nil || c.MasterBranch == nil { + return "" + } + return *c.MasterBranch +} + +// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. +func (c *CreateEvent) GetPusherType() string { + if c == nil || c.PusherType == nil { + return "" + } + return *c.PusherType +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (c *CreateEvent) GetRef() string { + if c == nil || c.Ref == nil { + return "" + } + return *c.Ref +} + +// GetRefType returns the RefType field if it's non-nil, zero value otherwise. +func (c *CreateEvent) GetRefType() string { + if c == nil || c.RefType == nil { + return "" + } + return *c.RefType +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (c *createRefRequest) GetRef() string { + if c == nil || c.Ref == nil { + return "" + } + return *c.Ref +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (c *createRefRequest) GetSHA() string { + if c == nil || c.SHA == nil { + return "" + } + return *c.SHA +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (c *createTagRequest) GetMessage() string { + if c == nil || c.Message == nil { + return "" + } + return *c.Message +} + +// GetObject returns the Object field if it's non-nil, zero value otherwise. +func (c *createTagRequest) GetObject() string { + if c == nil || c.Object == nil { + return "" + } + return *c.Object +} + +// GetTag returns the Tag field if it's non-nil, zero value otherwise. +func (c *createTagRequest) GetTag() string { + if c == nil || c.Tag == nil { + return "" + } + return *c.Tag +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (c *createTagRequest) GetType() string { + if c == nil || c.Type == nil { + return "" + } + return *c.Type +} + +// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. +func (d *DeleteEvent) GetPusherType() string { + if d == nil || d.PusherType == nil { + return "" + } + return *d.PusherType +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (d *DeleteEvent) GetRef() string { + if d == nil || d.Ref == nil { + return "" + } + return *d.Ref +} + +// GetRefType returns the RefType field if it's non-nil, zero value otherwise. +func (d *DeleteEvent) GetRefType() string { + if d == nil || d.RefType == nil { + return "" + } + return *d.RefType +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (d *Deployment) GetCreatedAt() Timestamp { + if d == nil || d.CreatedAt == nil { + return Timestamp{} + } + return *d.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (d *Deployment) GetDescription() string { + if d == nil || d.Description == nil { + return "" + } + return *d.Description +} + +// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. +func (d *Deployment) GetEnvironment() string { + if d == nil || d.Environment == nil { + return "" + } + return *d.Environment +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (d *Deployment) GetID() int { + if d == nil || d.ID == nil { + return 0 + } + return *d.ID +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (d *Deployment) GetRef() string { + if d == nil || d.Ref == nil { + return "" + } + return *d.Ref +} + +// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. +func (d *Deployment) GetRepositoryURL() string { + if d == nil || d.RepositoryURL == nil { + return "" + } + return *d.RepositoryURL +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (d *Deployment) GetSHA() string { + if d == nil || d.SHA == nil { + return "" + } + return *d.SHA +} + +// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. +func (d *Deployment) GetStatusesURL() string { + if d == nil || d.StatusesURL == nil { + return "" + } + return *d.StatusesURL +} + +// GetTask returns the Task field if it's non-nil, zero value otherwise. +func (d *Deployment) GetTask() string { + if d == nil || d.Task == nil { + return "" + } + return *d.Task +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (d *Deployment) GetUpdatedAt() Timestamp { + if d == nil || d.UpdatedAt == nil { + return Timestamp{} + } + return *d.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (d *Deployment) GetURL() string { + if d == nil || d.URL == nil { + return "" + } + return *d.URL +} + +// GetAutoMerge returns the AutoMerge field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetAutoMerge() bool { + if d == nil || d.AutoMerge == nil { + return false + } + return *d.AutoMerge +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetDescription() string { + if d == nil || d.Description == nil { + return "" + } + return *d.Description +} + +// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetEnvironment() string { + if d == nil || d.Environment == nil { + return "" + } + return *d.Environment +} + +// GetPayload returns the Payload field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetPayload() string { + if d == nil || d.Payload == nil { + return "" + } + return *d.Payload +} + +// GetProductionEnvironment returns the ProductionEnvironment field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetProductionEnvironment() bool { + if d == nil || d.ProductionEnvironment == nil { + return false + } + return *d.ProductionEnvironment +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetRef() string { + if d == nil || d.Ref == nil { + return "" + } + return *d.Ref +} + +// GetRequiredContexts returns the RequiredContexts field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetRequiredContexts() []string { + if d == nil || d.RequiredContexts == nil { + return nil + } + return *d.RequiredContexts +} + +// GetTask returns the Task field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetTask() string { + if d == nil || d.Task == nil { + return "" + } + return *d.Task +} + +// GetTransientEnvironment returns the TransientEnvironment field if it's non-nil, zero value otherwise. +func (d *DeploymentRequest) GetTransientEnvironment() bool { + if d == nil || d.TransientEnvironment == nil { + return false + } + return *d.TransientEnvironment +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetCreatedAt() Timestamp { + if d == nil || d.CreatedAt == nil { + return Timestamp{} + } + return *d.CreatedAt +} + +// GetDeploymentURL returns the DeploymentURL field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetDeploymentURL() string { + if d == nil || d.DeploymentURL == nil { + return "" + } + return *d.DeploymentURL +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetDescription() string { + if d == nil || d.Description == nil { + return "" + } + return *d.Description +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetID() int { + if d == nil || d.ID == nil { + return 0 + } + return *d.ID +} + +// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetRepositoryURL() string { + if d == nil || d.RepositoryURL == nil { + return "" + } + return *d.RepositoryURL +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetState() string { + if d == nil || d.State == nil { + return "" + } + return *d.State +} + +// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetTargetURL() string { + if d == nil || d.TargetURL == nil { + return "" + } + return *d.TargetURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (d *DeploymentStatus) GetUpdatedAt() Timestamp { + if d == nil || d.UpdatedAt == nil { + return Timestamp{} + } + return *d.UpdatedAt +} + +// GetAutoInactive returns the AutoInactive field if it's non-nil, zero value otherwise. +func (d *DeploymentStatusRequest) GetAutoInactive() bool { + if d == nil || d.AutoInactive == nil { + return false + } + return *d.AutoInactive +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (d *DeploymentStatusRequest) GetDescription() string { + if d == nil || d.Description == nil { + return "" + } + return *d.Description +} + +// GetEnvironmentURL returns the EnvironmentURL field if it's non-nil, zero value otherwise. +func (d *DeploymentStatusRequest) GetEnvironmentURL() string { + if d == nil || d.EnvironmentURL == nil { + return "" + } + return *d.EnvironmentURL +} + +// GetLogURL returns the LogURL field if it's non-nil, zero value otherwise. +func (d *DeploymentStatusRequest) GetLogURL() string { + if d == nil || d.LogURL == nil { + return "" + } + return *d.LogURL +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (d *DeploymentStatusRequest) GetState() string { + if d == nil || d.State == nil { + return "" + } + return *d.State +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (d *DraftReviewComment) GetBody() string { + if d == nil || d.Body == nil { + return "" + } + return *d.Body +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (d *DraftReviewComment) GetPath() string { + if d == nil || d.Path == nil { + return "" + } + return *d.Path +} + +// GetPosition returns the Position field if it's non-nil, zero value otherwise. +func (d *DraftReviewComment) GetPosition() int { + if d == nil || d.Position == nil { + return 0 + } + return *d.Position +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (e *Event) GetCreatedAt() time.Time { + if e == nil || e.CreatedAt == nil { + return time.Time{} + } + return *e.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (e *Event) GetID() string { + if e == nil || e.ID == nil { + return "" + } + return *e.ID +} + +// GetPublic returns the Public field if it's non-nil, zero value otherwise. +func (e *Event) GetPublic() bool { + if e == nil || e.Public == nil { + return false + } + return *e.Public +} + +// GetRawPayload returns the RawPayload field if it's non-nil, zero value otherwise. +func (e *Event) GetRawPayload() json.RawMessage { + if e == nil || e.RawPayload == nil { + return json.RawMessage{} + } + return *e.RawPayload +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (e *Event) GetType() string { + if e == nil || e.Type == nil { + return "" + } + return *e.Type +} + +// GetHRef returns the HRef field if it's non-nil, zero value otherwise. +func (f *FeedLink) GetHRef() string { + if f == nil || f.HRef == nil { + return "" + } + return *f.HRef +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (f *FeedLink) GetType() string { + if f == nil || f.Type == nil { + return "" + } + return *f.Type +} + +// GetCurrentUserActorURL returns the CurrentUserActorURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetCurrentUserActorURL() string { + if f == nil || f.CurrentUserActorURL == nil { + return "" + } + return *f.CurrentUserActorURL +} + +// GetCurrentUserOrganizationURL returns the CurrentUserOrganizationURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetCurrentUserOrganizationURL() string { + if f == nil || f.CurrentUserOrganizationURL == nil { + return "" + } + return *f.CurrentUserOrganizationURL +} + +// GetCurrentUserPublicURL returns the CurrentUserPublicURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetCurrentUserPublicURL() string { + if f == nil || f.CurrentUserPublicURL == nil { + return "" + } + return *f.CurrentUserPublicURL +} + +// GetCurrentUserURL returns the CurrentUserURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetCurrentUserURL() string { + if f == nil || f.CurrentUserURL == nil { + return "" + } + return *f.CurrentUserURL +} + +// GetTimelineURL returns the TimelineURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetTimelineURL() string { + if f == nil || f.TimelineURL == nil { + return "" + } + return *f.TimelineURL +} + +// GetUserURL returns the UserURL field if it's non-nil, zero value otherwise. +func (f *Feeds) GetUserURL() string { + if f == nil || f.UserURL == nil { + return "" + } + return *f.UserURL +} + +// GetComments returns the Comments field if it's non-nil, zero value otherwise. +func (g *Gist) GetComments() int { + if g == nil || g.Comments == nil { + return 0 + } + return *g.Comments +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (g *Gist) GetCreatedAt() time.Time { + if g == nil || g.CreatedAt == nil { + return time.Time{} + } + return *g.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (g *Gist) GetDescription() string { + if g == nil || g.Description == nil { + return "" + } + return *g.Description +} + +// GetGitPullURL returns the GitPullURL field if it's non-nil, zero value otherwise. +func (g *Gist) GetGitPullURL() string { + if g == nil || g.GitPullURL == nil { + return "" + } + return *g.GitPullURL +} + +// GetGitPushURL returns the GitPushURL field if it's non-nil, zero value otherwise. +func (g *Gist) GetGitPushURL() string { + if g == nil || g.GitPushURL == nil { + return "" + } + return *g.GitPushURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (g *Gist) GetHTMLURL() string { + if g == nil || g.HTMLURL == nil { + return "" + } + return *g.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (g *Gist) GetID() string { + if g == nil || g.ID == nil { + return "" + } + return *g.ID +} + +// GetPublic returns the Public field if it's non-nil, zero value otherwise. +func (g *Gist) GetPublic() bool { + if g == nil || g.Public == nil { + return false + } + return *g.Public +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (g *Gist) GetUpdatedAt() time.Time { + if g == nil || g.UpdatedAt == nil { + return time.Time{} + } + return *g.UpdatedAt +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (g *GistComment) GetBody() string { + if g == nil || g.Body == nil { + return "" + } + return *g.Body +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (g *GistComment) GetCreatedAt() time.Time { + if g == nil || g.CreatedAt == nil { + return time.Time{} + } + return *g.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (g *GistComment) GetID() int { + if g == nil || g.ID == nil { + return 0 + } + return *g.ID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (g *GistComment) GetURL() string { + if g == nil || g.URL == nil { + return "" + } + return *g.URL +} + +// GetCommittedAt returns the CommittedAt field if it's non-nil, zero value otherwise. +func (g *GistCommit) GetCommittedAt() Timestamp { + if g == nil || g.CommittedAt == nil { + return Timestamp{} + } + return *g.CommittedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (g *GistCommit) GetURL() string { + if g == nil || g.URL == nil { + return "" + } + return *g.URL +} + +// GetVersion returns the Version field if it's non-nil, zero value otherwise. +func (g *GistCommit) GetVersion() string { + if g == nil || g.Version == nil { + return "" + } + return *g.Version +} + +// GetContent returns the Content field if it's non-nil, zero value otherwise. +func (g *GistFile) GetContent() string { + if g == nil || g.Content == nil { + return "" + } + return *g.Content +} + +// GetFilename returns the Filename field if it's non-nil, zero value otherwise. +func (g *GistFile) GetFilename() string { + if g == nil || g.Filename == nil { + return "" + } + return *g.Filename +} + +// GetLanguage returns the Language field if it's non-nil, zero value otherwise. +func (g *GistFile) GetLanguage() string { + if g == nil || g.Language == nil { + return "" + } + return *g.Language +} + +// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. +func (g *GistFile) GetRawURL() string { + if g == nil || g.RawURL == nil { + return "" + } + return *g.RawURL +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (g *GistFile) GetSize() int { + if g == nil || g.Size == nil { + return 0 + } + return *g.Size +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (g *GistFile) GetType() string { + if g == nil || g.Type == nil { + return "" + } + return *g.Type +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (g *GistFork) GetCreatedAt() Timestamp { + if g == nil || g.CreatedAt == nil { + return Timestamp{} + } + return *g.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (g *GistFork) GetID() string { + if g == nil || g.ID == nil { + return "" + } + return *g.ID +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (g *GistFork) GetUpdatedAt() Timestamp { + if g == nil || g.UpdatedAt == nil { + return Timestamp{} + } + return *g.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (g *GistFork) GetURL() string { + if g == nil || g.URL == nil { + return "" + } + return *g.URL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (g *Gitignore) GetName() string { + if g == nil || g.Name == nil { + return "" + } + return *g.Name +} + +// GetSource returns the Source field if it's non-nil, zero value otherwise. +func (g *Gitignore) GetSource() string { + if g == nil || g.Source == nil { + return "" + } + return *g.Source +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (g *GitObject) GetSHA() string { + if g == nil || g.SHA == nil { + return "" + } + return *g.SHA +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (g *GitObject) GetType() string { + if g == nil || g.Type == nil { + return "" + } + return *g.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (g *GitObject) GetURL() string { + if g == nil || g.URL == nil { + return "" + } + return *g.URL +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (g *GPGEmail) GetEmail() string { + if g == nil || g.Email == nil { + return "" + } + return *g.Email +} + +// GetVerified returns the Verified field if it's non-nil, zero value otherwise. +func (g *GPGEmail) GetVerified() bool { + if g == nil || g.Verified == nil { + return false + } + return *g.Verified +} + +// GetCanCertify returns the CanCertify field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetCanCertify() bool { + if g == nil || g.CanCertify == nil { + return false + } + return *g.CanCertify +} + +// GetCanEncryptComms returns the CanEncryptComms field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetCanEncryptComms() bool { + if g == nil || g.CanEncryptComms == nil { + return false + } + return *g.CanEncryptComms +} + +// GetCanEncryptStorage returns the CanEncryptStorage field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetCanEncryptStorage() bool { + if g == nil || g.CanEncryptStorage == nil { + return false + } + return *g.CanEncryptStorage +} + +// GetCanSign returns the CanSign field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetCanSign() bool { + if g == nil || g.CanSign == nil { + return false + } + return *g.CanSign +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetCreatedAt() time.Time { + if g == nil || g.CreatedAt == nil { + return time.Time{} + } + return *g.CreatedAt +} + +// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetExpiresAt() time.Time { + if g == nil || g.ExpiresAt == nil { + return time.Time{} + } + return *g.ExpiresAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetID() int { + if g == nil || g.ID == nil { + return 0 + } + return *g.ID +} + +// GetKeyID returns the KeyID field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetKeyID() string { + if g == nil || g.KeyID == nil { + return "" + } + return *g.KeyID +} + +// GetPrimaryKeyID returns the PrimaryKeyID field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetPrimaryKeyID() int { + if g == nil || g.PrimaryKeyID == nil { + return 0 + } + return *g.PrimaryKeyID +} + +// GetPublicKey returns the PublicKey field if it's non-nil, zero value otherwise. +func (g *GPGKey) GetPublicKey() string { + if g == nil || g.PublicKey == nil { + return "" + } + return *g.PublicKey +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (g *Grant) GetCreatedAt() Timestamp { + if g == nil || g.CreatedAt == nil { + return Timestamp{} + } + return *g.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (g *Grant) GetID() int { + if g == nil || g.ID == nil { + return 0 + } + return *g.ID +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (g *Grant) GetUpdatedAt() Timestamp { + if g == nil || g.UpdatedAt == nil { + return Timestamp{} + } + return *g.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (g *Grant) GetURL() string { + if g == nil || g.URL == nil { + return "" + } + return *g.URL +} + +// GetActive returns the Active field if it's non-nil, zero value otherwise. +func (h *Hook) GetActive() bool { + if h == nil || h.Active == nil { + return false + } + return *h.Active +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (h *Hook) GetCreatedAt() time.Time { + if h == nil || h.CreatedAt == nil { + return time.Time{} + } + return *h.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (h *Hook) GetID() int { + if h == nil || h.ID == nil { + return 0 + } + return *h.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (h *Hook) GetName() string { + if h == nil || h.Name == nil { + return "" + } + return *h.Name +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (h *Hook) GetUpdatedAt() time.Time { + if h == nil || h.UpdatedAt == nil { + return time.Time{} + } + return *h.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (h *Hook) GetURL() string { + if h == nil || h.URL == nil { + return "" + } + return *h.URL +} + +// GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise. +func (i *Import) GetAuthorsCount() int { + if i == nil || i.AuthorsCount == nil { + return 0 + } + return *i.AuthorsCount +} + +// GetAuthorsURL returns the AuthorsURL field if it's non-nil, zero value otherwise. +func (i *Import) GetAuthorsURL() string { + if i == nil || i.AuthorsURL == nil { + return "" + } + return *i.AuthorsURL +} + +// GetCommitCount returns the CommitCount field if it's non-nil, zero value otherwise. +func (i *Import) GetCommitCount() int { + if i == nil || i.CommitCount == nil { + return 0 + } + return *i.CommitCount +} + +// GetFailedStep returns the FailedStep field if it's non-nil, zero value otherwise. +func (i *Import) GetFailedStep() string { + if i == nil || i.FailedStep == nil { + return "" + } + return *i.FailedStep +} + +// GetHasLargeFiles returns the HasLargeFiles field if it's non-nil, zero value otherwise. +func (i *Import) GetHasLargeFiles() bool { + if i == nil || i.HasLargeFiles == nil { + return false + } + return *i.HasLargeFiles +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (i *Import) GetHTMLURL() string { + if i == nil || i.HTMLURL == nil { + return "" + } + return *i.HTMLURL +} + +// GetHumanName returns the HumanName field if it's non-nil, zero value otherwise. +func (i *Import) GetHumanName() string { + if i == nil || i.HumanName == nil { + return "" + } + return *i.HumanName +} + +// GetLargeFilesCount returns the LargeFilesCount field if it's non-nil, zero value otherwise. +func (i *Import) GetLargeFilesCount() int { + if i == nil || i.LargeFilesCount == nil { + return 0 + } + return *i.LargeFilesCount +} + +// GetLargeFilesSize returns the LargeFilesSize field if it's non-nil, zero value otherwise. +func (i *Import) GetLargeFilesSize() int { + if i == nil || i.LargeFilesSize == nil { + return 0 + } + return *i.LargeFilesSize +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (i *Import) GetMessage() string { + if i == nil || i.Message == nil { + return "" + } + return *i.Message +} + +// GetPercent returns the Percent field if it's non-nil, zero value otherwise. +func (i *Import) GetPercent() int { + if i == nil || i.Percent == nil { + return 0 + } + return *i.Percent +} + +// GetPushPercent returns the PushPercent field if it's non-nil, zero value otherwise. +func (i *Import) GetPushPercent() int { + if i == nil || i.PushPercent == nil { + return 0 + } + return *i.PushPercent +} + +// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. +func (i *Import) GetRepositoryURL() string { + if i == nil || i.RepositoryURL == nil { + return "" + } + return *i.RepositoryURL +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (i *Import) GetStatus() string { + if i == nil || i.Status == nil { + return "" + } + return *i.Status +} + +// GetStatusText returns the StatusText field if it's non-nil, zero value otherwise. +func (i *Import) GetStatusText() string { + if i == nil || i.StatusText == nil { + return "" + } + return *i.StatusText +} + +// GetTFVCProject returns the TFVCProject field if it's non-nil, zero value otherwise. +func (i *Import) GetTFVCProject() string { + if i == nil || i.TFVCProject == nil { + return "" + } + return *i.TFVCProject +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (i *Import) GetURL() string { + if i == nil || i.URL == nil { + return "" + } + return *i.URL +} + +// GetUseLFS returns the UseLFS field if it's non-nil, zero value otherwise. +func (i *Import) GetUseLFS() string { + if i == nil || i.UseLFS == nil { + return "" + } + return *i.UseLFS +} + +// GetVCS returns the VCS field if it's non-nil, zero value otherwise. +func (i *Import) GetVCS() string { + if i == nil || i.VCS == nil { + return "" + } + return *i.VCS +} + +// GetVCSPassword returns the VCSPassword field if it's non-nil, zero value otherwise. +func (i *Import) GetVCSPassword() string { + if i == nil || i.VCSPassword == nil { + return "" + } + return *i.VCSPassword +} + +// GetVCSURL returns the VCSURL field if it's non-nil, zero value otherwise. +func (i *Import) GetVCSURL() string { + if i == nil || i.VCSURL == nil { + return "" + } + return *i.VCSURL +} + +// GetVCSUsername returns the VCSUsername field if it's non-nil, zero value otherwise. +func (i *Import) GetVCSUsername() string { + if i == nil || i.VCSUsername == nil { + return "" + } + return *i.VCSUsername +} + +// GetAccessTokensURL returns the AccessTokensURL field if it's non-nil, zero value otherwise. +func (i *Installation) GetAccessTokensURL() string { + if i == nil || i.AccessTokensURL == nil { + return "" + } + return *i.AccessTokensURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (i *Installation) GetHTMLURL() string { + if i == nil || i.HTMLURL == nil { + return "" + } + return *i.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (i *Installation) GetID() int { + if i == nil || i.ID == nil { + return 0 + } + return *i.ID +} + +// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. +func (i *Installation) GetRepositoriesURL() string { + if i == nil || i.RepositoriesURL == nil { + return "" + } + return *i.RepositoriesURL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (i *IntegrationInstallationEvent) GetAction() string { + if i == nil || i.Action == nil { + return "" + } + return *i.Action +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (i *IntegrationInstallationRepositoriesEvent) GetAction() string { + if i == nil || i.Action == nil { + return "" + } + return *i.Action +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (i *Invitation) GetCreatedAt() time.Time { + if i == nil || i.CreatedAt == nil { + return time.Time{} + } + return *i.CreatedAt +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (i *Invitation) GetEmail() string { + if i == nil || i.Email == nil { + return "" + } + return *i.Email +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (i *Invitation) GetID() int { + if i == nil || i.ID == nil { + return 0 + } + return *i.ID +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (i *Invitation) GetLogin() string { + if i == nil || i.Login == nil { + return "" + } + return *i.Login +} + +// GetRole returns the Role field if it's non-nil, zero value otherwise. +func (i *Invitation) GetRole() string { + if i == nil || i.Role == nil { + return "" + } + return *i.Role +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (i *Issue) GetBody() string { + if i == nil || i.Body == nil { + return "" + } + return *i.Body +} + +// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. +func (i *Issue) GetClosedAt() time.Time { + if i == nil || i.ClosedAt == nil { + return time.Time{} + } + return *i.ClosedAt +} + +// GetComments returns the Comments field if it's non-nil, zero value otherwise. +func (i *Issue) GetComments() int { + if i == nil || i.Comments == nil { + return 0 + } + return *i.Comments +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (i *Issue) GetCreatedAt() time.Time { + if i == nil || i.CreatedAt == nil { + return time.Time{} + } + return *i.CreatedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (i *Issue) GetHTMLURL() string { + if i == nil || i.HTMLURL == nil { + return "" + } + return *i.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (i *Issue) GetID() int { + if i == nil || i.ID == nil { + return 0 + } + return *i.ID +} + +// GetLocked returns the Locked field if it's non-nil, zero value otherwise. +func (i *Issue) GetLocked() bool { + if i == nil || i.Locked == nil { + return false + } + return *i.Locked +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (i *Issue) GetNumber() int { + if i == nil || i.Number == nil { + return 0 + } + return *i.Number +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (i *Issue) GetState() string { + if i == nil || i.State == nil { + return "" + } + return *i.State +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (i *Issue) GetTitle() string { + if i == nil || i.Title == nil { + return "" + } + return *i.Title +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (i *Issue) GetUpdatedAt() time.Time { + if i == nil || i.UpdatedAt == nil { + return time.Time{} + } + return *i.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (i *Issue) GetURL() string { + if i == nil || i.URL == nil { + return "" + } + return *i.URL +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetBody() string { + if i == nil || i.Body == nil { + return "" + } + return *i.Body +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetCreatedAt() time.Time { + if i == nil || i.CreatedAt == nil { + return time.Time{} + } + return *i.CreatedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetHTMLURL() string { + if i == nil || i.HTMLURL == nil { + return "" + } + return *i.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetID() int { + if i == nil || i.ID == nil { + return 0 + } + return *i.ID +} + +// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetIssueURL() string { + if i == nil || i.IssueURL == nil { + return "" + } + return *i.IssueURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetUpdatedAt() time.Time { + if i == nil || i.UpdatedAt == nil { + return time.Time{} + } + return *i.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (i *IssueComment) GetURL() string { + if i == nil || i.URL == nil { + return "" + } + return *i.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (i *IssueCommentEvent) GetAction() string { + if i == nil || i.Action == nil { + return "" + } + return *i.Action +} + +// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. +func (i *IssueEvent) GetCommitID() string { + if i == nil || i.CommitID == nil { + return "" + } + return *i.CommitID +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (i *IssueEvent) GetCreatedAt() time.Time { + if i == nil || i.CreatedAt == nil { + return time.Time{} + } + return *i.CreatedAt +} + +// GetEvent returns the Event field if it's non-nil, zero value otherwise. +func (i *IssueEvent) GetEvent() string { + if i == nil || i.Event == nil { + return "" + } + return *i.Event +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (i *IssueEvent) GetID() int { + if i == nil || i.ID == nil { + return 0 + } + return *i.ID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (i *IssueEvent) GetURL() string { + if i == nil || i.URL == nil { + return "" + } + return *i.URL +} + +// GetAssignee returns the Assignee field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetAssignee() string { + if i == nil || i.Assignee == nil { + return "" + } + return *i.Assignee +} + +// GetAssignees returns the Assignees field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetAssignees() []string { + if i == nil || i.Assignees == nil { + return nil + } + return *i.Assignees +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetBody() string { + if i == nil || i.Body == nil { + return "" + } + return *i.Body +} + +// GetLabels returns the Labels field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetLabels() []string { + if i == nil || i.Labels == nil { + return nil + } + return *i.Labels +} + +// GetMilestone returns the Milestone field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetMilestone() int { + if i == nil || i.Milestone == nil { + return 0 + } + return *i.Milestone +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetState() string { + if i == nil || i.State == nil { + return "" + } + return *i.State +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (i *IssueRequest) GetTitle() string { + if i == nil || i.Title == nil { + return "" + } + return *i.Title +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (i *IssuesEvent) GetAction() string { + if i == nil || i.Action == nil { + return "" + } + return *i.Action +} + +// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. +func (i *IssuesSearchResult) GetIncompleteResults() bool { + if i == nil || i.IncompleteResults == nil { + return false + } + return *i.IncompleteResults +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (i *IssuesSearchResult) GetTotal() int { + if i == nil || i.Total == nil { + return 0 + } + return *i.Total +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (k *Key) GetID() int { + if k == nil || k.ID == nil { + return 0 + } + return *k.ID +} + +// GetKey returns the Key field if it's non-nil, zero value otherwise. +func (k *Key) GetKey() string { + if k == nil || k.Key == nil { + return "" + } + return *k.Key +} + +// GetReadOnly returns the ReadOnly field if it's non-nil, zero value otherwise. +func (k *Key) GetReadOnly() bool { + if k == nil || k.ReadOnly == nil { + return false + } + return *k.ReadOnly +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (k *Key) GetTitle() string { + if k == nil || k.Title == nil { + return "" + } + return *k.Title +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (k *Key) GetURL() string { + if k == nil || k.URL == nil { + return "" + } + return *k.URL +} + +// GetColor returns the Color field if it's non-nil, zero value otherwise. +func (l *Label) GetColor() string { + if l == nil || l.Color == nil { + return "" + } + return *l.Color +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (l *Label) GetID() int { + if l == nil || l.ID == nil { + return 0 + } + return *l.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (l *Label) GetName() string { + if l == nil || l.Name == nil { + return "" + } + return *l.Name +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (l *Label) GetURL() string { + if l == nil || l.URL == nil { + return "" + } + return *l.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (l *LabelEvent) GetAction() string { + if l == nil || l.Action == nil { + return "" + } + return *l.Action +} + +// GetOID returns the OID field if it's non-nil, zero value otherwise. +func (l *LargeFile) GetOID() string { + if l == nil || l.OID == nil { + return "" + } + return *l.OID +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (l *LargeFile) GetPath() string { + if l == nil || l.Path == nil { + return "" + } + return *l.Path +} + +// GetRefName returns the RefName field if it's non-nil, zero value otherwise. +func (l *LargeFile) GetRefName() string { + if l == nil || l.RefName == nil { + return "" + } + return *l.RefName +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (l *LargeFile) GetSize() int { + if l == nil || l.Size == nil { + return 0 + } + return *l.Size +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (l *License) GetBody() string { + if l == nil || l.Body == nil { + return "" + } + return *l.Body +} + +// GetConditions returns the Conditions field if it's non-nil, zero value otherwise. +func (l *License) GetConditions() []string { + if l == nil || l.Conditions == nil { + return nil + } + return *l.Conditions +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (l *License) GetDescription() string { + if l == nil || l.Description == nil { + return "" + } + return *l.Description +} + +// GetFeatured returns the Featured field if it's non-nil, zero value otherwise. +func (l *License) GetFeatured() bool { + if l == nil || l.Featured == nil { + return false + } + return *l.Featured +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (l *License) GetHTMLURL() string { + if l == nil || l.HTMLURL == nil { + return "" + } + return *l.HTMLURL +} + +// GetImplementation returns the Implementation field if it's non-nil, zero value otherwise. +func (l *License) GetImplementation() string { + if l == nil || l.Implementation == nil { + return "" + } + return *l.Implementation +} + +// GetKey returns the Key field if it's non-nil, zero value otherwise. +func (l *License) GetKey() string { + if l == nil || l.Key == nil { + return "" + } + return *l.Key +} + +// GetLimitations returns the Limitations field if it's non-nil, zero value otherwise. +func (l *License) GetLimitations() []string { + if l == nil || l.Limitations == nil { + return nil + } + return *l.Limitations +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (l *License) GetName() string { + if l == nil || l.Name == nil { + return "" + } + return *l.Name +} + +// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +func (l *License) GetPermissions() []string { + if l == nil || l.Permissions == nil { + return nil + } + return *l.Permissions +} + +// GetSPDXID returns the SPDXID field if it's non-nil, zero value otherwise. +func (l *License) GetSPDXID() string { + if l == nil || l.SPDXID == nil { + return "" + } + return *l.SPDXID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (l *License) GetURL() string { + if l == nil || l.URL == nil { + return "" + } + return *l.URL +} + +// GetContext returns the Context field if it's non-nil, zero value otherwise. +func (m *markdownRequest) GetContext() string { + if m == nil || m.Context == nil { + return "" + } + return *m.Context +} + +// GetMode returns the Mode field if it's non-nil, zero value otherwise. +func (m *markdownRequest) GetMode() string { + if m == nil || m.Mode == nil { + return "" + } + return *m.Mode +} + +// GetText returns the Text field if it's non-nil, zero value otherwise. +func (m *markdownRequest) GetText() string { + if m == nil || m.Text == nil { + return "" + } + return *m.Text +} + +// GetText returns the Text field if it's non-nil, zero value otherwise. +func (m *Match) GetText() string { + if m == nil || m.Text == nil { + return "" + } + return *m.Text +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (m *MemberEvent) GetAction() string { + if m == nil || m.Action == nil { + return "" + } + return *m.Action +} + +// GetOrganizationURL returns the OrganizationURL field if it's non-nil, zero value otherwise. +func (m *Membership) GetOrganizationURL() string { + if m == nil || m.OrganizationURL == nil { + return "" + } + return *m.OrganizationURL +} + +// GetRole returns the Role field if it's non-nil, zero value otherwise. +func (m *Membership) GetRole() string { + if m == nil || m.Role == nil { + return "" + } + return *m.Role +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (m *Membership) GetState() string { + if m == nil || m.State == nil { + return "" + } + return *m.State +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (m *Membership) GetURL() string { + if m == nil || m.URL == nil { + return "" + } + return *m.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (m *MembershipEvent) GetAction() string { + if m == nil || m.Action == nil { + return "" + } + return *m.Action +} + +// GetScope returns the Scope field if it's non-nil, zero value otherwise. +func (m *MembershipEvent) GetScope() string { + if m == nil || m.Scope == nil { + return "" + } + return *m.Scope +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (m *Migration) GetCreatedAt() string { + if m == nil || m.CreatedAt == nil { + return "" + } + return *m.CreatedAt +} + +// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. +func (m *Migration) GetExcludeAttachments() bool { + if m == nil || m.ExcludeAttachments == nil { + return false + } + return *m.ExcludeAttachments +} + +// GetGUID returns the GUID field if it's non-nil, zero value otherwise. +func (m *Migration) GetGUID() string { + if m == nil || m.GUID == nil { + return "" + } + return *m.GUID +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (m *Migration) GetID() int { + if m == nil || m.ID == nil { + return 0 + } + return *m.ID +} + +// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. +func (m *Migration) GetLockRepositories() bool { + if m == nil || m.LockRepositories == nil { + return false + } + return *m.LockRepositories +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (m *Migration) GetState() string { + if m == nil || m.State == nil { + return "" + } + return *m.State +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (m *Migration) GetUpdatedAt() string { + if m == nil || m.UpdatedAt == nil { + return "" + } + return *m.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (m *Migration) GetURL() string { + if m == nil || m.URL == nil { + return "" + } + return *m.URL +} + +// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. +func (m *Milestone) GetClosedAt() time.Time { + if m == nil || m.ClosedAt == nil { + return time.Time{} + } + return *m.ClosedAt +} + +// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise. +func (m *Milestone) GetClosedIssues() int { + if m == nil || m.ClosedIssues == nil { + return 0 + } + return *m.ClosedIssues +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (m *Milestone) GetCreatedAt() time.Time { + if m == nil || m.CreatedAt == nil { + return time.Time{} + } + return *m.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (m *Milestone) GetDescription() string { + if m == nil || m.Description == nil { + return "" + } + return *m.Description +} + +// GetDueOn returns the DueOn field if it's non-nil, zero value otherwise. +func (m *Milestone) GetDueOn() time.Time { + if m == nil || m.DueOn == nil { + return time.Time{} + } + return *m.DueOn +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (m *Milestone) GetHTMLURL() string { + if m == nil || m.HTMLURL == nil { + return "" + } + return *m.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (m *Milestone) GetID() int { + if m == nil || m.ID == nil { + return 0 + } + return *m.ID +} + +// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. +func (m *Milestone) GetLabelsURL() string { + if m == nil || m.LabelsURL == nil { + return "" + } + return *m.LabelsURL +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (m *Milestone) GetNumber() int { + if m == nil || m.Number == nil { + return 0 + } + return *m.Number +} + +// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise. +func (m *Milestone) GetOpenIssues() int { + if m == nil || m.OpenIssues == nil { + return 0 + } + return *m.OpenIssues +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (m *Milestone) GetState() string { + if m == nil || m.State == nil { + return "" + } + return *m.State +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (m *Milestone) GetTitle() string { + if m == nil || m.Title == nil { + return "" + } + return *m.Title +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (m *Milestone) GetUpdatedAt() time.Time { + if m == nil || m.UpdatedAt == nil { + return time.Time{} + } + return *m.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (m *Milestone) GetURL() string { + if m == nil || m.URL == nil { + return "" + } + return *m.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (m *MilestoneEvent) GetAction() string { + if m == nil || m.Action == nil { + return "" + } + return *m.Action +} + +// GetBase returns the Base field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetBase() string { + if n == nil || n.Base == nil { + return "" + } + return *n.Base +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetBody() string { + if n == nil || n.Body == nil { + return "" + } + return *n.Body +} + +// GetHead returns the Head field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetHead() string { + if n == nil || n.Head == nil { + return "" + } + return *n.Head +} + +// GetIssue returns the Issue field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetIssue() int { + if n == nil || n.Issue == nil { + return 0 + } + return *n.Issue +} + +// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetMaintainerCanModify() bool { + if n == nil || n.MaintainerCanModify == nil { + return false + } + return *n.MaintainerCanModify +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (n *NewPullRequest) GetTitle() string { + if n == nil || n.Title == nil { + return "" + } + return *n.Title +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (n *Notification) GetID() string { + if n == nil || n.ID == nil { + return "" + } + return *n.ID +} + +// GetLastReadAt returns the LastReadAt field if it's non-nil, zero value otherwise. +func (n *Notification) GetLastReadAt() time.Time { + if n == nil || n.LastReadAt == nil { + return time.Time{} + } + return *n.LastReadAt +} + +// GetReason returns the Reason field if it's non-nil, zero value otherwise. +func (n *Notification) GetReason() string { + if n == nil || n.Reason == nil { + return "" + } + return *n.Reason +} + +// GetUnread returns the Unread field if it's non-nil, zero value otherwise. +func (n *Notification) GetUnread() bool { + if n == nil || n.Unread == nil { + return false + } + return *n.Unread +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (n *Notification) GetUpdatedAt() time.Time { + if n == nil || n.UpdatedAt == nil { + return time.Time{} + } + return *n.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (n *Notification) GetURL() string { + if n == nil || n.URL == nil { + return "" + } + return *n.URL +} + +// GetLatestCommentURL returns the LatestCommentURL field if it's non-nil, zero value otherwise. +func (n *NotificationSubject) GetLatestCommentURL() string { + if n == nil || n.LatestCommentURL == nil { + return "" + } + return *n.LatestCommentURL +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (n *NotificationSubject) GetTitle() string { + if n == nil || n.Title == nil { + return "" + } + return *n.Title +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (n *NotificationSubject) GetType() string { + if n == nil || n.Type == nil { + return "" + } + return *n.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (n *NotificationSubject) GetURL() string { + if n == nil || n.URL == nil { + return "" + } + return *n.URL +} + +// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetAvatarURL() string { + if o == nil || o.AvatarURL == nil { + return "" + } + return *o.AvatarURL +} + +// GetBillingEmail returns the BillingEmail field if it's non-nil, zero value otherwise. +func (o *Organization) GetBillingEmail() string { + if o == nil || o.BillingEmail == nil { + return "" + } + return *o.BillingEmail +} + +// GetBlog returns the Blog field if it's non-nil, zero value otherwise. +func (o *Organization) GetBlog() string { + if o == nil || o.Blog == nil { + return "" + } + return *o.Blog +} + +// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. +func (o *Organization) GetCollaborators() int { + if o == nil || o.Collaborators == nil { + return 0 + } + return *o.Collaborators +} + +// GetCompany returns the Company field if it's non-nil, zero value otherwise. +func (o *Organization) GetCompany() string { + if o == nil || o.Company == nil { + return "" + } + return *o.Company +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (o *Organization) GetCreatedAt() time.Time { + if o == nil || o.CreatedAt == nil { + return time.Time{} + } + return *o.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (o *Organization) GetDescription() string { + if o == nil || o.Description == nil { + return "" + } + return *o.Description +} + +// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. +func (o *Organization) GetDiskUsage() int { + if o == nil || o.DiskUsage == nil { + return 0 + } + return *o.DiskUsage +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (o *Organization) GetEmail() string { + if o == nil || o.Email == nil { + return "" + } + return *o.Email +} + +// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetEventsURL() string { + if o == nil || o.EventsURL == nil { + return "" + } + return *o.EventsURL +} + +// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. +func (o *Organization) GetFollowers() int { + if o == nil || o.Followers == nil { + return 0 + } + return *o.Followers +} + +// GetFollowing returns the Following field if it's non-nil, zero value otherwise. +func (o *Organization) GetFollowing() int { + if o == nil || o.Following == nil { + return 0 + } + return *o.Following +} + +// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetHooksURL() string { + if o == nil || o.HooksURL == nil { + return "" + } + return *o.HooksURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetHTMLURL() string { + if o == nil || o.HTMLURL == nil { + return "" + } + return *o.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (o *Organization) GetID() int { + if o == nil || o.ID == nil { + return 0 + } + return *o.ID +} + +// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetIssuesURL() string { + if o == nil || o.IssuesURL == nil { + return "" + } + return *o.IssuesURL +} + +// GetLocation returns the Location field if it's non-nil, zero value otherwise. +func (o *Organization) GetLocation() string { + if o == nil || o.Location == nil { + return "" + } + return *o.Location +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (o *Organization) GetLogin() string { + if o == nil || o.Login == nil { + return "" + } + return *o.Login +} + +// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetMembersURL() string { + if o == nil || o.MembersURL == nil { + return "" + } + return *o.MembersURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (o *Organization) GetName() string { + if o == nil || o.Name == nil { + return "" + } + return *o.Name +} + +// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. +func (o *Organization) GetOwnedPrivateRepos() int { + if o == nil || o.OwnedPrivateRepos == nil { + return 0 + } + return *o.OwnedPrivateRepos +} + +// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. +func (o *Organization) GetPrivateGists() int { + if o == nil || o.PrivateGists == nil { + return 0 + } + return *o.PrivateGists +} + +// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. +func (o *Organization) GetPublicGists() int { + if o == nil || o.PublicGists == nil { + return 0 + } + return *o.PublicGists +} + +// GetPublicMembersURL returns the PublicMembersURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetPublicMembersURL() string { + if o == nil || o.PublicMembersURL == nil { + return "" + } + return *o.PublicMembersURL +} + +// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. +func (o *Organization) GetPublicRepos() int { + if o == nil || o.PublicRepos == nil { + return 0 + } + return *o.PublicRepos +} + +// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. +func (o *Organization) GetReposURL() string { + if o == nil || o.ReposURL == nil { + return "" + } + return *o.ReposURL +} + +// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. +func (o *Organization) GetTotalPrivateRepos() int { + if o == nil || o.TotalPrivateRepos == nil { + return 0 + } + return *o.TotalPrivateRepos +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (o *Organization) GetType() string { + if o == nil || o.Type == nil { + return "" + } + return *o.Type +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (o *Organization) GetUpdatedAt() time.Time { + if o == nil || o.UpdatedAt == nil { + return time.Time{} + } + return *o.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (o *Organization) GetURL() string { + if o == nil || o.URL == nil { + return "" + } + return *o.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (o *OrganizationEvent) GetAction() string { + if o == nil || o.Action == nil { + return "" + } + return *o.Action +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *Page) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *Page) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetPageName returns the PageName field if it's non-nil, zero value otherwise. +func (p *Page) GetPageName() string { + if p == nil || p.PageName == nil { + return "" + } + return *p.PageName +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (p *Page) GetSHA() string { + if p == nil || p.SHA == nil { + return "" + } + return *p.SHA +} + +// GetSummary returns the Summary field if it's non-nil, zero value otherwise. +func (p *Page) GetSummary() string { + if p == nil || p.Summary == nil { + return "" + } + return *p.Summary +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (p *Page) GetTitle() string { + if p == nil || p.Title == nil { + return "" + } + return *p.Title +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PageBuildEvent) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetCNAME returns the CNAME field if it's non-nil, zero value otherwise. +func (p *Pages) GetCNAME() string { + if p == nil || p.CNAME == nil { + return "" + } + return *p.CNAME +} + +// GetCustom404 returns the Custom404 field if it's non-nil, zero value otherwise. +func (p *Pages) GetCustom404() bool { + if p == nil || p.Custom404 == nil { + return false + } + return *p.Custom404 +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *Pages) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (p *Pages) GetStatus() string { + if p == nil || p.Status == nil { + return "" + } + return *p.Status +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *Pages) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetCommit returns the Commit field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetCommit() string { + if p == nil || p.Commit == nil { + return "" + } + return *p.Commit +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetCreatedAt() Timestamp { + if p == nil || p.CreatedAt == nil { + return Timestamp{} + } + return *p.CreatedAt +} + +// GetDuration returns the Duration field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetDuration() int { + if p == nil || p.Duration == nil { + return 0 + } + return *p.Duration +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetStatus() string { + if p == nil || p.Status == nil { + return "" + } + return *p.Status +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetUpdatedAt() Timestamp { + if p == nil || p.UpdatedAt == nil { + return Timestamp{} + } + return *p.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PagesBuild) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (p *PagesError) GetMessage() string { + if p == nil || p.Message == nil { + return "" + } + return *p.Message +} + +// GetHookID returns the HookID field if it's non-nil, zero value otherwise. +func (p *PingEvent) GetHookID() int { + if p == nil || p.HookID == nil { + return 0 + } + return *p.HookID +} + +// GetZen returns the Zen field if it's non-nil, zero value otherwise. +func (p *PingEvent) GetZen() string { + if p == nil || p.Zen == nil { + return "" + } + return *p.Zen +} + +// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. +func (p *Plan) GetCollaborators() int { + if p == nil || p.Collaborators == nil { + return 0 + } + return *p.Collaborators +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *Plan) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetPrivateRepos returns the PrivateRepos field if it's non-nil, zero value otherwise. +func (p *Plan) GetPrivateRepos() int { + if p == nil || p.PrivateRepos == nil { + return 0 + } + return *p.PrivateRepos +} + +// GetSpace returns the Space field if it's non-nil, zero value otherwise. +func (p *Plan) GetSpace() int { + if p == nil || p.Space == nil { + return 0 + } + return *p.Space +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *Project) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *Project) GetCreatedAt() Timestamp { + if p == nil || p.CreatedAt == nil { + return Timestamp{} + } + return *p.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *Project) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *Project) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (p *Project) GetNumber() int { + if p == nil || p.Number == nil { + return 0 + } + return *p.Number +} + +// GetOwnerURL returns the OwnerURL field if it's non-nil, zero value otherwise. +func (p *Project) GetOwnerURL() string { + if p == nil || p.OwnerURL == nil { + return "" + } + return *p.OwnerURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *Project) GetUpdatedAt() Timestamp { + if p == nil || p.UpdatedAt == nil { + return Timestamp{} + } + return *p.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *Project) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetColumnURL returns the ColumnURL field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetColumnURL() string { + if p == nil || p.ColumnURL == nil { + return "" + } + return *p.ColumnURL +} + +// GetContentURL returns the ContentURL field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetContentURL() string { + if p == nil || p.ContentURL == nil { + return "" + } + return *p.ContentURL +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetCreatedAt() Timestamp { + if p == nil || p.CreatedAt == nil { + return Timestamp{} + } + return *p.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetNote returns the Note field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetNote() string { + if p == nil || p.Note == nil { + return "" + } + return *p.Note +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *ProjectCard) GetUpdatedAt() Timestamp { + if p == nil || p.UpdatedAt == nil { + return Timestamp{} + } + return *p.UpdatedAt +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *ProjectCardEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. +func (p *ProjectCardEvent) GetAfterID() int { + if p == nil || p.AfterID == nil { + return 0 + } + return *p.AfterID +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *ProjectColumn) GetCreatedAt() Timestamp { + if p == nil || p.CreatedAt == nil { + return Timestamp{} + } + return *p.CreatedAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *ProjectColumn) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *ProjectColumn) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetProjectURL returns the ProjectURL field if it's non-nil, zero value otherwise. +func (p *ProjectColumn) GetProjectURL() string { + if p == nil || p.ProjectURL == nil { + return "" + } + return *p.ProjectURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *ProjectColumn) GetUpdatedAt() Timestamp { + if p == nil || p.UpdatedAt == nil { + return Timestamp{} + } + return *p.UpdatedAt +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *ProjectColumnEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. +func (p *ProjectColumnEvent) GetAfterID() int { + if p == nil || p.AfterID == nil { + return 0 + } + return *p.AfterID +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *ProjectEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetAdditions() int { + if p == nil || p.Additions == nil { + return 0 + } + return *p.Additions +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetChangedFiles returns the ChangedFiles field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetChangedFiles() int { + if p == nil || p.ChangedFiles == nil { + return 0 + } + return *p.ChangedFiles +} + +// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetClosedAt() time.Time { + if p == nil || p.ClosedAt == nil { + return time.Time{} + } + return *p.ClosedAt +} + +// GetComments returns the Comments field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetComments() int { + if p == nil || p.Comments == nil { + return 0 + } + return *p.Comments +} + +// GetCommits returns the Commits field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetCommits() int { + if p == nil || p.Commits == nil { + return 0 + } + return *p.Commits +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetCreatedAt() time.Time { + if p == nil || p.CreatedAt == nil { + return time.Time{} + } + return *p.CreatedAt +} + +// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetDeletions() int { + if p == nil || p.Deletions == nil { + return 0 + } + return *p.Deletions +} + +// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetDiffURL() string { + if p == nil || p.DiffURL == nil { + return "" + } + return *p.DiffURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetIssueURL() string { + if p == nil || p.IssueURL == nil { + return "" + } + return *p.IssueURL +} + +// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetMaintainerCanModify() bool { + if p == nil || p.MaintainerCanModify == nil { + return false + } + return *p.MaintainerCanModify +} + +// GetMergeable returns the Mergeable field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetMergeable() bool { + if p == nil || p.Mergeable == nil { + return false + } + return *p.Mergeable +} + +// GetMerged returns the Merged field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetMerged() bool { + if p == nil || p.Merged == nil { + return false + } + return *p.Merged +} + +// GetMergedAt returns the MergedAt field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetMergedAt() time.Time { + if p == nil || p.MergedAt == nil { + return time.Time{} + } + return *p.MergedAt +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetNumber() int { + if p == nil || p.Number == nil { + return 0 + } + return *p.Number +} + +// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetPatchURL() string { + if p == nil || p.PatchURL == nil { + return "" + } + return *p.PatchURL +} + +// GetReviewCommentsURL returns the ReviewCommentsURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetReviewCommentsURL() string { + if p == nil || p.ReviewCommentsURL == nil { + return "" + } + return *p.ReviewCommentsURL +} + +// GetReviewCommentURL returns the ReviewCommentURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetReviewCommentURL() string { + if p == nil || p.ReviewCommentURL == nil { + return "" + } + return *p.ReviewCommentURL +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetState() string { + if p == nil || p.State == nil { + return "" + } + return *p.State +} + +// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetStatusesURL() string { + if p == nil || p.StatusesURL == nil { + return "" + } + return *p.StatusesURL +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetTitle() string { + if p == nil || p.Title == nil { + return "" + } + return *p.Title +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetUpdatedAt() time.Time { + if p == nil || p.UpdatedAt == nil { + return time.Time{} + } + return *p.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PullRequest) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetLabel returns the Label field if it's non-nil, zero value otherwise. +func (p *PullRequestBranch) GetLabel() string { + if p == nil || p.Label == nil { + return "" + } + return *p.Label +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (p *PullRequestBranch) GetRef() string { + if p == nil || p.Ref == nil { + return "" + } + return *p.Ref +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (p *PullRequestBranch) GetSHA() string { + if p == nil || p.SHA == nil { + return "" + } + return *p.SHA +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetCommitID() string { + if p == nil || p.CommitID == nil { + return "" + } + return *p.CommitID +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetCreatedAt() time.Time { + if p == nil || p.CreatedAt == nil { + return time.Time{} + } + return *p.CreatedAt +} + +// GetDiffHunk returns the DiffHunk field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetDiffHunk() string { + if p == nil || p.DiffHunk == nil { + return "" + } + return *p.DiffHunk +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetInReplyTo returns the InReplyTo field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetInReplyTo() int { + if p == nil || p.InReplyTo == nil { + return 0 + } + return *p.InReplyTo +} + +// GetOriginalCommitID returns the OriginalCommitID field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetOriginalCommitID() string { + if p == nil || p.OriginalCommitID == nil { + return "" + } + return *p.OriginalCommitID +} + +// GetOriginalPosition returns the OriginalPosition field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetOriginalPosition() int { + if p == nil || p.OriginalPosition == nil { + return 0 + } + return *p.OriginalPosition +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetPath() string { + if p == nil || p.Path == nil { + return "" + } + return *p.Path +} + +// GetPosition returns the Position field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetPosition() int { + if p == nil || p.Position == nil { + return 0 + } + return *p.Position +} + +// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetPullRequestURL() string { + if p == nil || p.PullRequestURL == nil { + return "" + } + return *p.PullRequestURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetUpdatedAt() time.Time { + if p == nil || p.UpdatedAt == nil { + return time.Time{} + } + return *p.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PullRequestComment) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *PullRequestEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetNumber returns the Number field if it's non-nil, zero value otherwise. +func (p *PullRequestEvent) GetNumber() int { + if p == nil || p.Number == nil { + return 0 + } + return *p.Number +} + +// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. +func (p *PullRequestLinks) GetDiffURL() string { + if p == nil || p.DiffURL == nil { + return "" + } + return *p.DiffURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PullRequestLinks) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. +func (p *PullRequestLinks) GetPatchURL() string { + if p == nil || p.PatchURL == nil { + return "" + } + return *p.PatchURL +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PullRequestLinks) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetMerged returns the Merged field if it's non-nil, zero value otherwise. +func (p *PullRequestMergeResult) GetMerged() bool { + if p == nil || p.Merged == nil { + return false + } + return *p.Merged +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (p *PullRequestMergeResult) GetMessage() string { + if p == nil || p.Message == nil { + return "" + } + return *p.Message +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (p *PullRequestMergeResult) GetSHA() string { + if p == nil || p.SHA == nil { + return "" + } + return *p.SHA +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetCommitID() string { + if p == nil || p.CommitID == nil { + return "" + } + return *p.CommitID +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetPullRequestURL() string { + if p == nil || p.PullRequestURL == nil { + return "" + } + return *p.PullRequestURL +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetState() string { + if p == nil || p.State == nil { + return "" + } + return *p.State +} + +// GetSubmittedAt returns the SubmittedAt field if it's non-nil, zero value otherwise. +func (p *PullRequestReview) GetSubmittedAt() time.Time { + if p == nil || p.SubmittedAt == nil { + return time.Time{} + } + return *p.SubmittedAt +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *PullRequestReviewCommentEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (p *PullRequestReviewDismissalRequest) GetMessage() string { + if p == nil || p.Message == nil { + return "" + } + return *p.Message +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (p *PullRequestReviewEvent) GetAction() string { + if p == nil || p.Action == nil { + return "" + } + return *p.Action +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *PullRequestReviewRequest) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetEvent returns the Event field if it's non-nil, zero value otherwise. +func (p *PullRequestReviewRequest) GetEvent() string { + if p == nil || p.Event == nil { + return "" + } + return *p.Event +} + +// GetBase returns the Base field if it's non-nil, zero value otherwise. +func (p *pullRequestUpdate) GetBase() string { + if p == nil || p.Base == nil { + return "" + } + return *p.Base +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (p *pullRequestUpdate) GetBody() string { + if p == nil || p.Body == nil { + return "" + } + return *p.Body +} + +// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. +func (p *pullRequestUpdate) GetMaintainerCanModify() bool { + if p == nil || p.MaintainerCanModify == nil { + return false + } + return *p.MaintainerCanModify +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (p *pullRequestUpdate) GetState() string { + if p == nil || p.State == nil { + return "" + } + return *p.State +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (p *pullRequestUpdate) GetTitle() string { + if p == nil || p.Title == nil { + return "" + } + return *p.Title +} + +// GetCommits returns the Commits field if it's non-nil, zero value otherwise. +func (p *PunchCard) GetCommits() int { + if p == nil || p.Commits == nil { + return 0 + } + return *p.Commits +} + +// GetDay returns the Day field if it's non-nil, zero value otherwise. +func (p *PunchCard) GetDay() int { + if p == nil || p.Day == nil { + return 0 + } + return *p.Day +} + +// GetHour returns the Hour field if it's non-nil, zero value otherwise. +func (p *PunchCard) GetHour() int { + if p == nil || p.Hour == nil { + return 0 + } + return *p.Hour +} + +// GetAfter returns the After field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetAfter() string { + if p == nil || p.After == nil { + return "" + } + return *p.After +} + +// GetBaseRef returns the BaseRef field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetBaseRef() string { + if p == nil || p.BaseRef == nil { + return "" + } + return *p.BaseRef +} + +// GetBefore returns the Before field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetBefore() string { + if p == nil || p.Before == nil { + return "" + } + return *p.Before +} + +// GetCompare returns the Compare field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetCompare() string { + if p == nil || p.Compare == nil { + return "" + } + return *p.Compare +} + +// GetCreated returns the Created field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetCreated() bool { + if p == nil || p.Created == nil { + return false + } + return *p.Created +} + +// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetDeleted() bool { + if p == nil || p.Deleted == nil { + return false + } + return *p.Deleted +} + +// GetDistinctSize returns the DistinctSize field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetDistinctSize() int { + if p == nil || p.DistinctSize == nil { + return 0 + } + return *p.DistinctSize +} + +// GetForced returns the Forced field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetForced() bool { + if p == nil || p.Forced == nil { + return false + } + return *p.Forced +} + +// GetHead returns the Head field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetHead() string { + if p == nil || p.Head == nil { + return "" + } + return *p.Head +} + +// GetPushID returns the PushID field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetPushID() int { + if p == nil || p.PushID == nil { + return 0 + } + return *p.PushID +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetRef() string { + if p == nil || p.Ref == nil { + return "" + } + return *p.Ref +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (p *PushEvent) GetSize() int { + if p == nil || p.Size == nil { + return 0 + } + return *p.Size +} + +// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetDistinct() bool { + if p == nil || p.Distinct == nil { + return false + } + return *p.Distinct +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetID() string { + if p == nil || p.ID == nil { + return "" + } + return *p.ID +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetMessage() string { + if p == nil || p.Message == nil { + return "" + } + return *p.Message +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetSHA() string { + if p == nil || p.SHA == nil { + return "" + } + return *p.SHA +} + +// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetTimestamp() Timestamp { + if p == nil || p.Timestamp == nil { + return Timestamp{} + } + return *p.Timestamp +} + +// GetTreeID returns the TreeID field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetTreeID() string { + if p == nil || p.TreeID == nil { + return "" + } + return *p.TreeID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PushEventCommit) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (p *PushEventRepoOwner) GetEmail() string { + if p == nil || p.Email == nil { + return "" + } + return *p.Email +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *PushEventRepoOwner) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetArchiveURL() string { + if p == nil || p.ArchiveURL == nil { + return "" + } + return *p.ArchiveURL +} + +// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetCloneURL() string { + if p == nil || p.CloneURL == nil { + return "" + } + return *p.CloneURL +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetCreatedAt() Timestamp { + if p == nil || p.CreatedAt == nil { + return Timestamp{} + } + return *p.CreatedAt +} + +// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetDefaultBranch() string { + if p == nil || p.DefaultBranch == nil { + return "" + } + return *p.DefaultBranch +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetDescription() string { + if p == nil || p.Description == nil { + return "" + } + return *p.Description +} + +// GetFork returns the Fork field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetFork() bool { + if p == nil || p.Fork == nil { + return false + } + return *p.Fork +} + +// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetForksCount() int { + if p == nil || p.ForksCount == nil { + return 0 + } + return *p.ForksCount +} + +// GetFullName returns the FullName field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetFullName() string { + if p == nil || p.FullName == nil { + return "" + } + return *p.FullName +} + +// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetGitURL() string { + if p == nil || p.GitURL == nil { + return "" + } + return *p.GitURL +} + +// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHasDownloads() bool { + if p == nil || p.HasDownloads == nil { + return false + } + return *p.HasDownloads +} + +// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHasIssues() bool { + if p == nil || p.HasIssues == nil { + return false + } + return *p.HasIssues +} + +// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHasPages() bool { + if p == nil || p.HasPages == nil { + return false + } + return *p.HasPages +} + +// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHasWiki() bool { + if p == nil || p.HasWiki == nil { + return false + } + return *p.HasWiki +} + +// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHomepage() string { + if p == nil || p.Homepage == nil { + return "" + } + return *p.Homepage +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetID() int { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetLanguage returns the Language field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetLanguage() string { + if p == nil || p.Language == nil { + return "" + } + return *p.Language +} + +// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetMasterBranch() string { + if p == nil || p.MasterBranch == nil { + return "" + } + return *p.MasterBranch +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetOpenIssuesCount() int { + if p == nil || p.OpenIssuesCount == nil { + return 0 + } + return *p.OpenIssuesCount +} + +// GetOrganization returns the Organization field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetOrganization() string { + if p == nil || p.Organization == nil { + return "" + } + return *p.Organization +} + +// GetPrivate returns the Private field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetPrivate() bool { + if p == nil || p.Private == nil { + return false + } + return *p.Private +} + +// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetPushedAt() Timestamp { + if p == nil || p.PushedAt == nil { + return Timestamp{} + } + return *p.PushedAt +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetSize() int { + if p == nil || p.Size == nil { + return 0 + } + return *p.Size +} + +// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetSSHURL() string { + if p == nil || p.SSHURL == nil { + return "" + } + return *p.SSHURL +} + +// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetStargazersCount() int { + if p == nil || p.StargazersCount == nil { + return 0 + } + return *p.StargazersCount +} + +// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetStatusesURL() string { + if p == nil || p.StatusesURL == nil { + return "" + } + return *p.StatusesURL +} + +// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetSVNURL() string { + if p == nil || p.SVNURL == nil { + return "" + } + return *p.SVNURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetUpdatedAt() Timestamp { + if p == nil || p.UpdatedAt == nil { + return Timestamp{} + } + return *p.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + +// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. +func (p *PushEventRepository) GetWatchersCount() int { + if p == nil || p.WatchersCount == nil { + return 0 + } + return *p.WatchersCount +} + +// GetContent returns the Content field if it's non-nil, zero value otherwise. +func (r *Reaction) GetContent() string { + if r == nil || r.Content == nil { + return "" + } + return *r.Content +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *Reaction) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetConfused returns the Confused field if it's non-nil, zero value otherwise. +func (r *Reactions) GetConfused() int { + if r == nil || r.Confused == nil { + return 0 + } + return *r.Confused +} + +// GetHeart returns the Heart field if it's non-nil, zero value otherwise. +func (r *Reactions) GetHeart() int { + if r == nil || r.Heart == nil { + return 0 + } + return *r.Heart +} + +// GetHooray returns the Hooray field if it's non-nil, zero value otherwise. +func (r *Reactions) GetHooray() int { + if r == nil || r.Hooray == nil { + return 0 + } + return *r.Hooray +} + +// GetLaugh returns the Laugh field if it's non-nil, zero value otherwise. +func (r *Reactions) GetLaugh() int { + if r == nil || r.Laugh == nil { + return 0 + } + return *r.Laugh +} + +// GetMinusOne returns the MinusOne field if it's non-nil, zero value otherwise. +func (r *Reactions) GetMinusOne() int { + if r == nil || r.MinusOne == nil { + return 0 + } + return *r.MinusOne +} + +// GetPlusOne returns the PlusOne field if it's non-nil, zero value otherwise. +func (r *Reactions) GetPlusOne() int { + if r == nil || r.PlusOne == nil { + return 0 + } + return *r.PlusOne +} + +// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. +func (r *Reactions) GetTotalCount() int { + if r == nil || r.TotalCount == nil { + return 0 + } + return *r.TotalCount +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *Reactions) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (r *Reference) GetRef() string { + if r == nil || r.Ref == nil { + return "" + } + return *r.Ref +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *Reference) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetBrowserDownloadURL returns the BrowserDownloadURL field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetBrowserDownloadURL() string { + if r == nil || r.BrowserDownloadURL == nil { + return "" + } + return *r.BrowserDownloadURL +} + +// GetContentType returns the ContentType field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetContentType() string { + if r == nil || r.ContentType == nil { + return "" + } + return *r.ContentType +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetCreatedAt() Timestamp { + if r == nil || r.CreatedAt == nil { + return Timestamp{} + } + return *r.CreatedAt +} + +// GetDownloadCount returns the DownloadCount field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetDownloadCount() int { + if r == nil || r.DownloadCount == nil { + return 0 + } + return *r.DownloadCount +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetLabel returns the Label field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetLabel() string { + if r == nil || r.Label == nil { + return "" + } + return *r.Label +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetSize() int { + if r == nil || r.Size == nil { + return 0 + } + return *r.Size +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetState() string { + if r == nil || r.State == nil { + return "" + } + return *r.State +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetUpdatedAt() Timestamp { + if r == nil || r.UpdatedAt == nil { + return Timestamp{} + } + return *r.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *ReleaseAsset) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (r *ReleaseEvent) GetAction() string { + if r == nil || r.Action == nil { + return "" + } + return *r.Action +} + +// GetFrom returns the From field if it's non-nil, zero value otherwise. +func (r *Rename) GetFrom() string { + if r == nil || r.From == nil { + return "" + } + return *r.From +} + +// GetTo returns the To field if it's non-nil, zero value otherwise. +func (r *Rename) GetTo() string { + if r == nil || r.To == nil { + return "" + } + return *r.To +} + +// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. +func (r *RepositoriesSearchResult) GetIncompleteResults() bool { + if r == nil || r.IncompleteResults == nil { + return false + } + return *r.IncompleteResults +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (r *RepositoriesSearchResult) GetTotal() int { + if r == nil || r.Total == nil { + return 0 + } + return *r.Total +} + +// GetAllowMergeCommit returns the AllowMergeCommit field if it's non-nil, zero value otherwise. +func (r *Repository) GetAllowMergeCommit() bool { + if r == nil || r.AllowMergeCommit == nil { + return false + } + return *r.AllowMergeCommit +} + +// GetAllowRebaseMerge returns the AllowRebaseMerge field if it's non-nil, zero value otherwise. +func (r *Repository) GetAllowRebaseMerge() bool { + if r == nil || r.AllowRebaseMerge == nil { + return false + } + return *r.AllowRebaseMerge +} + +// GetAllowSquashMerge returns the AllowSquashMerge field if it's non-nil, zero value otherwise. +func (r *Repository) GetAllowSquashMerge() bool { + if r == nil || r.AllowSquashMerge == nil { + return false + } + return *r.AllowSquashMerge +} + +// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetArchiveURL() string { + if r == nil || r.ArchiveURL == nil { + return "" + } + return *r.ArchiveURL +} + +// GetAssigneesURL returns the AssigneesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetAssigneesURL() string { + if r == nil || r.AssigneesURL == nil { + return "" + } + return *r.AssigneesURL +} + +// GetAutoInit returns the AutoInit field if it's non-nil, zero value otherwise. +func (r *Repository) GetAutoInit() bool { + if r == nil || r.AutoInit == nil { + return false + } + return *r.AutoInit +} + +// GetBlobsURL returns the BlobsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetBlobsURL() string { + if r == nil || r.BlobsURL == nil { + return "" + } + return *r.BlobsURL +} + +// GetBranchesURL returns the BranchesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetBranchesURL() string { + if r == nil || r.BranchesURL == nil { + return "" + } + return *r.BranchesURL +} + +// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetCloneURL() string { + if r == nil || r.CloneURL == nil { + return "" + } + return *r.CloneURL +} + +// GetCollaboratorsURL returns the CollaboratorsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetCollaboratorsURL() string { + if r == nil || r.CollaboratorsURL == nil { + return "" + } + return *r.CollaboratorsURL +} + +// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetCommentsURL() string { + if r == nil || r.CommentsURL == nil { + return "" + } + return *r.CommentsURL +} + +// GetCommitsURL returns the CommitsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetCommitsURL() string { + if r == nil || r.CommitsURL == nil { + return "" + } + return *r.CommitsURL +} + +// GetCompareURL returns the CompareURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetCompareURL() string { + if r == nil || r.CompareURL == nil { + return "" + } + return *r.CompareURL +} + +// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetContentsURL() string { + if r == nil || r.ContentsURL == nil { + return "" + } + return *r.ContentsURL +} + +// GetContributorsURL returns the ContributorsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetContributorsURL() string { + if r == nil || r.ContributorsURL == nil { + return "" + } + return *r.ContributorsURL +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *Repository) GetCreatedAt() Timestamp { + if r == nil || r.CreatedAt == nil { + return Timestamp{} + } + return *r.CreatedAt +} + +// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. +func (r *Repository) GetDefaultBranch() string { + if r == nil || r.DefaultBranch == nil { + return "" + } + return *r.DefaultBranch +} + +// GetDeploymentsURL returns the DeploymentsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetDeploymentsURL() string { + if r == nil || r.DeploymentsURL == nil { + return "" + } + return *r.DeploymentsURL +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (r *Repository) GetDescription() string { + if r == nil || r.Description == nil { + return "" + } + return *r.Description +} + +// GetDownloadsURL returns the DownloadsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetDownloadsURL() string { + if r == nil || r.DownloadsURL == nil { + return "" + } + return *r.DownloadsURL +} + +// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetEventsURL() string { + if r == nil || r.EventsURL == nil { + return "" + } + return *r.EventsURL +} + +// GetFork returns the Fork field if it's non-nil, zero value otherwise. +func (r *Repository) GetFork() bool { + if r == nil || r.Fork == nil { + return false + } + return *r.Fork +} + +// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetForksCount() int { + if r == nil || r.ForksCount == nil { + return 0 + } + return *r.ForksCount +} + +// GetForksURL returns the ForksURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetForksURL() string { + if r == nil || r.ForksURL == nil { + return "" + } + return *r.ForksURL +} + +// GetFullName returns the FullName field if it's non-nil, zero value otherwise. +func (r *Repository) GetFullName() string { + if r == nil || r.FullName == nil { + return "" + } + return *r.FullName +} + +// GetGitCommitsURL returns the GitCommitsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetGitCommitsURL() string { + if r == nil || r.GitCommitsURL == nil { + return "" + } + return *r.GitCommitsURL +} + +// GetGitignoreTemplate returns the GitignoreTemplate field if it's non-nil, zero value otherwise. +func (r *Repository) GetGitignoreTemplate() string { + if r == nil || r.GitignoreTemplate == nil { + return "" + } + return *r.GitignoreTemplate +} + +// GetGitRefsURL returns the GitRefsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetGitRefsURL() string { + if r == nil || r.GitRefsURL == nil { + return "" + } + return *r.GitRefsURL +} + +// GetGitTagsURL returns the GitTagsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetGitTagsURL() string { + if r == nil || r.GitTagsURL == nil { + return "" + } + return *r.GitTagsURL +} + +// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetGitURL() string { + if r == nil || r.GitURL == nil { + return "" + } + return *r.GitURL +} + +// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. +func (r *Repository) GetHasDownloads() bool { + if r == nil || r.HasDownloads == nil { + return false + } + return *r.HasDownloads +} + +// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. +func (r *Repository) GetHasIssues() bool { + if r == nil || r.HasIssues == nil { + return false + } + return *r.HasIssues +} + +// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. +func (r *Repository) GetHasPages() bool { + if r == nil || r.HasPages == nil { + return false + } + return *r.HasPages +} + +// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. +func (r *Repository) GetHasWiki() bool { + if r == nil || r.HasWiki == nil { + return false + } + return *r.HasWiki +} + +// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. +func (r *Repository) GetHomepage() string { + if r == nil || r.Homepage == nil { + return "" + } + return *r.Homepage +} + +// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetHooksURL() string { + if r == nil || r.HooksURL == nil { + return "" + } + return *r.HooksURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *Repository) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetIssueCommentURL returns the IssueCommentURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetIssueCommentURL() string { + if r == nil || r.IssueCommentURL == nil { + return "" + } + return *r.IssueCommentURL +} + +// GetIssueEventsURL returns the IssueEventsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetIssueEventsURL() string { + if r == nil || r.IssueEventsURL == nil { + return "" + } + return *r.IssueEventsURL +} + +// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetIssuesURL() string { + if r == nil || r.IssuesURL == nil { + return "" + } + return *r.IssuesURL +} + +// GetKeysURL returns the KeysURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetKeysURL() string { + if r == nil || r.KeysURL == nil { + return "" + } + return *r.KeysURL +} + +// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetLabelsURL() string { + if r == nil || r.LabelsURL == nil { + return "" + } + return *r.LabelsURL +} + +// GetLanguage returns the Language field if it's non-nil, zero value otherwise. +func (r *Repository) GetLanguage() string { + if r == nil || r.Language == nil { + return "" + } + return *r.Language +} + +// GetLanguagesURL returns the LanguagesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetLanguagesURL() string { + if r == nil || r.LanguagesURL == nil { + return "" + } + return *r.LanguagesURL +} + +// GetLicenseTemplate returns the LicenseTemplate field if it's non-nil, zero value otherwise. +func (r *Repository) GetLicenseTemplate() string { + if r == nil || r.LicenseTemplate == nil { + return "" + } + return *r.LicenseTemplate +} + +// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. +func (r *Repository) GetMasterBranch() string { + if r == nil || r.MasterBranch == nil { + return "" + } + return *r.MasterBranch +} + +// GetMergesURL returns the MergesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetMergesURL() string { + if r == nil || r.MergesURL == nil { + return "" + } + return *r.MergesURL +} + +// GetMilestonesURL returns the MilestonesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetMilestonesURL() string { + if r == nil || r.MilestonesURL == nil { + return "" + } + return *r.MilestonesURL +} + +// GetMirrorURL returns the MirrorURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetMirrorURL() string { + if r == nil || r.MirrorURL == nil { + return "" + } + return *r.MirrorURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *Repository) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetNetworkCount returns the NetworkCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetNetworkCount() int { + if r == nil || r.NetworkCount == nil { + return 0 + } + return *r.NetworkCount +} + +// GetNotificationsURL returns the NotificationsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetNotificationsURL() string { + if r == nil || r.NotificationsURL == nil { + return "" + } + return *r.NotificationsURL +} + +// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetOpenIssuesCount() int { + if r == nil || r.OpenIssuesCount == nil { + return 0 + } + return *r.OpenIssuesCount +} + +// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +func (r *Repository) GetPermissions() map[string]bool { + if r == nil || r.Permissions == nil { + return map[string]bool{} + } + return *r.Permissions +} + +// GetPrivate returns the Private field if it's non-nil, zero value otherwise. +func (r *Repository) GetPrivate() bool { + if r == nil || r.Private == nil { + return false + } + return *r.Private +} + +// GetPullsURL returns the PullsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetPullsURL() string { + if r == nil || r.PullsURL == nil { + return "" + } + return *r.PullsURL +} + +// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. +func (r *Repository) GetPushedAt() Timestamp { + if r == nil || r.PushedAt == nil { + return Timestamp{} + } + return *r.PushedAt +} + +// GetReleasesURL returns the ReleasesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetReleasesURL() string { + if r == nil || r.ReleasesURL == nil { + return "" + } + return *r.ReleasesURL +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (r *Repository) GetSize() int { + if r == nil || r.Size == nil { + return 0 + } + return *r.Size +} + +// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetSSHURL() string { + if r == nil || r.SSHURL == nil { + return "" + } + return *r.SSHURL +} + +// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetStargazersCount() int { + if r == nil || r.StargazersCount == nil { + return 0 + } + return *r.StargazersCount +} + +// GetStargazersURL returns the StargazersURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetStargazersURL() string { + if r == nil || r.StargazersURL == nil { + return "" + } + return *r.StargazersURL +} + +// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetStatusesURL() string { + if r == nil || r.StatusesURL == nil { + return "" + } + return *r.StatusesURL +} + +// GetSubscribersCount returns the SubscribersCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetSubscribersCount() int { + if r == nil || r.SubscribersCount == nil { + return 0 + } + return *r.SubscribersCount +} + +// GetSubscribersURL returns the SubscribersURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetSubscribersURL() string { + if r == nil || r.SubscribersURL == nil { + return "" + } + return *r.SubscribersURL +} + +// GetSubscriptionURL returns the SubscriptionURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetSubscriptionURL() string { + if r == nil || r.SubscriptionURL == nil { + return "" + } + return *r.SubscriptionURL +} + +// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetSVNURL() string { + if r == nil || r.SVNURL == nil { + return "" + } + return *r.SVNURL +} + +// GetTagsURL returns the TagsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetTagsURL() string { + if r == nil || r.TagsURL == nil { + return "" + } + return *r.TagsURL +} + +// GetTeamID returns the TeamID field if it's non-nil, zero value otherwise. +func (r *Repository) GetTeamID() int { + if r == nil || r.TeamID == nil { + return 0 + } + return *r.TeamID +} + +// GetTeamsURL returns the TeamsURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetTeamsURL() string { + if r == nil || r.TeamsURL == nil { + return "" + } + return *r.TeamsURL +} + +// GetTreesURL returns the TreesURL field if it's non-nil, zero value otherwise. +func (r *Repository) GetTreesURL() string { + if r == nil || r.TreesURL == nil { + return "" + } + return *r.TreesURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (r *Repository) GetUpdatedAt() Timestamp { + if r == nil || r.UpdatedAt == nil { + return Timestamp{} + } + return *r.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *Repository) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. +func (r *Repository) GetWatchersCount() int { + if r == nil || r.WatchersCount == nil { + return 0 + } + return *r.WatchersCount +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetBody() string { + if r == nil || r.Body == nil { + return "" + } + return *r.Body +} + +// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetCommitID() string { + if r == nil || r.CommitID == nil { + return "" + } + return *r.CommitID +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetCreatedAt() time.Time { + if r == nil || r.CreatedAt == nil { + return time.Time{} + } + return *r.CreatedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetPath() string { + if r == nil || r.Path == nil { + return "" + } + return *r.Path +} + +// GetPosition returns the Position field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetPosition() int { + if r == nil || r.Position == nil { + return 0 + } + return *r.Position +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetUpdatedAt() time.Time { + if r == nil || r.UpdatedAt == nil { + return time.Time{} + } + return *r.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryComment) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. +func (r *RepositoryCommit) GetCommentsURL() string { + if r == nil || r.CommentsURL == nil { + return "" + } + return *r.CommentsURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryCommit) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (r *RepositoryCommit) GetSHA() string { + if r == nil || r.SHA == nil { + return "" + } + return *r.SHA +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryCommit) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetDownloadURL() string { + if r == nil || r.DownloadURL == nil { + return "" + } + return *r.DownloadURL +} + +// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetEncoding() string { + if r == nil || r.Encoding == nil { + return "" + } + return *r.Encoding +} + +// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetGitURL() string { + if r == nil || r.GitURL == nil { + return "" + } + return *r.GitURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetPath() string { + if r == nil || r.Path == nil { + return "" + } + return *r.Path +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetSHA() string { + if r == nil || r.SHA == nil { + return "" + } + return *r.SHA +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetSize() int { + if r == nil || r.Size == nil { + return 0 + } + return *r.Size +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetType() string { + if r == nil || r.Type == nil { + return "" + } + return *r.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryContent) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetBranch returns the Branch field if it's non-nil, zero value otherwise. +func (r *RepositoryContentFileOptions) GetBranch() string { + if r == nil || r.Branch == nil { + return "" + } + return *r.Branch +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (r *RepositoryContentFileOptions) GetMessage() string { + if r == nil || r.Message == nil { + return "" + } + return *r.Message +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (r *RepositoryContentFileOptions) GetSHA() string { + if r == nil || r.SHA == nil { + return "" + } + return *r.SHA +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (r *RepositoryEvent) GetAction() string { + if r == nil || r.Action == nil { + return "" + } + return *r.Action +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *RepositoryInvitation) GetCreatedAt() Timestamp { + if r == nil || r.CreatedAt == nil { + return Timestamp{} + } + return *r.CreatedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryInvitation) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *RepositoryInvitation) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +func (r *RepositoryInvitation) GetPermissions() string { + if r == nil || r.Permissions == nil { + return "" + } + return *r.Permissions +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryInvitation) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetContent returns the Content field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetContent() string { + if r == nil || r.Content == nil { + return "" + } + return *r.Content +} + +// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetDownloadURL() string { + if r == nil || r.DownloadURL == nil { + return "" + } + return *r.DownloadURL +} + +// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetEncoding() string { + if r == nil || r.Encoding == nil { + return "" + } + return *r.Encoding +} + +// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetGitURL() string { + if r == nil || r.GitURL == nil { + return "" + } + return *r.GitURL +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetPath() string { + if r == nil || r.Path == nil { + return "" + } + return *r.Path +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetSHA() string { + if r == nil || r.SHA == nil { + return "" + } + return *r.SHA +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetSize() int { + if r == nil || r.Size == nil { + return 0 + } + return *r.Size +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetType() string { + if r == nil || r.Type == nil { + return "" + } + return *r.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryLicense) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetBase returns the Base field if it's non-nil, zero value otherwise. +func (r *RepositoryMergeRequest) GetBase() string { + if r == nil || r.Base == nil { + return "" + } + return *r.Base +} + +// GetCommitMessage returns the CommitMessage field if it's non-nil, zero value otherwise. +func (r *RepositoryMergeRequest) GetCommitMessage() string { + if r == nil || r.CommitMessage == nil { + return "" + } + return *r.CommitMessage +} + +// GetHead returns the Head field if it's non-nil, zero value otherwise. +func (r *RepositoryMergeRequest) GetHead() string { + if r == nil || r.Head == nil { + return "" + } + return *r.Head +} + +// GetPermission returns the Permission field if it's non-nil, zero value otherwise. +func (r *RepositoryPermissionLevel) GetPermission() string { + if r == nil || r.Permission == nil { + return "" + } + return *r.Permission +} + +// GetAssetsURL returns the AssetsURL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetAssetsURL() string { + if r == nil || r.AssetsURL == nil { + return "" + } + return *r.AssetsURL +} + +// GetBody returns the Body field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetBody() string { + if r == nil || r.Body == nil { + return "" + } + return *r.Body +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetCreatedAt() Timestamp { + if r == nil || r.CreatedAt == nil { + return Timestamp{} + } + return *r.CreatedAt +} + +// GetDraft returns the Draft field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetDraft() bool { + if r == nil || r.Draft == nil { + return false + } + return *r.Draft +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetHTMLURL() string { + if r == nil || r.HTMLURL == nil { + return "" + } + return *r.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetPrerelease returns the Prerelease field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetPrerelease() bool { + if r == nil || r.Prerelease == nil { + return false + } + return *r.Prerelease +} + +// GetPublishedAt returns the PublishedAt field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetPublishedAt() Timestamp { + if r == nil || r.PublishedAt == nil { + return Timestamp{} + } + return *r.PublishedAt +} + +// GetTagName returns the TagName field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetTagName() string { + if r == nil || r.TagName == nil { + return "" + } + return *r.TagName +} + +// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetTarballURL() string { + if r == nil || r.TarballURL == nil { + return "" + } + return *r.TarballURL +} + +// GetTargetCommitish returns the TargetCommitish field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetTargetCommitish() string { + if r == nil || r.TargetCommitish == nil { + return "" + } + return *r.TargetCommitish +} + +// GetUploadURL returns the UploadURL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetUploadURL() string { + if r == nil || r.UploadURL == nil { + return "" + } + return *r.UploadURL +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. +func (r *RepositoryRelease) GetZipballURL() string { + if r == nil || r.ZipballURL == nil { + return "" + } + return *r.ZipballURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (r *RepositoryTag) GetName() string { + if r == nil || r.Name == nil { + return "" + } + return *r.Name +} + +// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. +func (r *RepositoryTag) GetTarballURL() string { + if r == nil || r.TarballURL == nil { + return "" + } + return *r.TarballURL +} + +// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. +func (r *RepositoryTag) GetZipballURL() string { + if r == nil || r.ZipballURL == nil { + return "" + } + return *r.ZipballURL +} + +// GetContext returns the Context field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetContext() string { + if r == nil || r.Context == nil { + return "" + } + return *r.Context +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetCreatedAt() time.Time { + if r == nil || r.CreatedAt == nil { + return time.Time{} + } + return *r.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetDescription() string { + if r == nil || r.Description == nil { + return "" + } + return *r.Description +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetID() int { + if r == nil || r.ID == nil { + return 0 + } + return *r.ID +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetState() string { + if r == nil || r.State == nil { + return "" + } + return *r.State +} + +// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetTargetURL() string { + if r == nil || r.TargetURL == nil { + return "" + } + return *r.TargetURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetUpdatedAt() time.Time { + if r == nil || r.UpdatedAt == nil { + return time.Time{} + } + return *r.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (r *RepoStatus) GetURL() string { + if r == nil || r.URL == nil { + return "" + } + return *r.URL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (s *ServiceHook) GetName() string { + if s == nil || s.Name == nil { + return "" + } + return *s.Name +} + +// GetPayload returns the Payload field if it's non-nil, zero value otherwise. +func (s *SignatureVerification) GetPayload() string { + if s == nil || s.Payload == nil { + return "" + } + return *s.Payload +} + +// GetReason returns the Reason field if it's non-nil, zero value otherwise. +func (s *SignatureVerification) GetReason() string { + if s == nil || s.Reason == nil { + return "" + } + return *s.Reason +} + +// GetSignature returns the Signature field if it's non-nil, zero value otherwise. +func (s *SignatureVerification) GetSignature() string { + if s == nil || s.Signature == nil { + return "" + } + return *s.Signature +} + +// GetVerified returns the Verified field if it's non-nil, zero value otherwise. +func (s *SignatureVerification) GetVerified() bool { + if s == nil || s.Verified == nil { + return false + } + return *s.Verified +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *Source) GetID() int { + if s == nil || s.ID == nil { + return 0 + } + return *s.ID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (s *Source) GetURL() string { + if s == nil || s.URL == nil { + return "" + } + return *s.URL +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetEmail() string { + if s == nil || s.Email == nil { + return "" + } + return *s.Email +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetID() int { + if s == nil || s.ID == nil { + return 0 + } + return *s.ID +} + +// GetImportURL returns the ImportURL field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetImportURL() string { + if s == nil || s.ImportURL == nil { + return "" + } + return *s.ImportURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetName() string { + if s == nil || s.Name == nil { + return "" + } + return *s.Name +} + +// GetRemoteID returns the RemoteID field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetRemoteID() string { + if s == nil || s.RemoteID == nil { + return "" + } + return *s.RemoteID +} + +// GetRemoteName returns the RemoteName field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetRemoteName() string { + if s == nil || s.RemoteName == nil { + return "" + } + return *s.RemoteName +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (s *SourceImportAuthor) GetURL() string { + if s == nil || s.URL == nil { + return "" + } + return *s.URL +} + +// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. +func (s *Stargazer) GetStarredAt() Timestamp { + if s == nil || s.StarredAt == nil { + return Timestamp{} + } + return *s.StarredAt +} + +// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. +func (s *StarredRepository) GetStarredAt() Timestamp { + if s == nil || s.StarredAt == nil { + return Timestamp{} + } + return *s.StarredAt +} + +// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. +func (s *startMigration) GetExcludeAttachments() bool { + if s == nil || s.ExcludeAttachments == nil { + return false + } + return *s.ExcludeAttachments +} + +// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. +func (s *startMigration) GetLockRepositories() bool { + if s == nil || s.LockRepositories == nil { + return false + } + return *s.LockRepositories +} + +// GetContext returns the Context field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetContext() string { + if s == nil || s.Context == nil { + return "" + } + return *s.Context +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetCreatedAt() Timestamp { + if s == nil || s.CreatedAt == nil { + return Timestamp{} + } + return *s.CreatedAt +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetDescription() string { + if s == nil || s.Description == nil { + return "" + } + return *s.Description +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetID() int { + if s == nil || s.ID == nil { + return 0 + } + return *s.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetName() string { + if s == nil || s.Name == nil { + return "" + } + return *s.Name +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetSHA() string { + if s == nil || s.SHA == nil { + return "" + } + return *s.SHA +} + +// GetState returns the State field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetState() string { + if s == nil || s.State == nil { + return "" + } + return *s.State +} + +// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetTargetURL() string { + if s == nil || s.TargetURL == nil { + return "" + } + return *s.TargetURL +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (s *StatusEvent) GetUpdatedAt() Timestamp { + if s == nil || s.UpdatedAt == nil { + return Timestamp{} + } + return *s.UpdatedAt +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (s *Subscription) GetCreatedAt() Timestamp { + if s == nil || s.CreatedAt == nil { + return Timestamp{} + } + return *s.CreatedAt +} + +// GetIgnored returns the Ignored field if it's non-nil, zero value otherwise. +func (s *Subscription) GetIgnored() bool { + if s == nil || s.Ignored == nil { + return false + } + return *s.Ignored +} + +// GetReason returns the Reason field if it's non-nil, zero value otherwise. +func (s *Subscription) GetReason() string { + if s == nil || s.Reason == nil { + return "" + } + return *s.Reason +} + +// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. +func (s *Subscription) GetRepositoryURL() string { + if s == nil || s.RepositoryURL == nil { + return "" + } + return *s.RepositoryURL +} + +// GetSubscribed returns the Subscribed field if it's non-nil, zero value otherwise. +func (s *Subscription) GetSubscribed() bool { + if s == nil || s.Subscribed == nil { + return false + } + return *s.Subscribed +} + +// GetThreadURL returns the ThreadURL field if it's non-nil, zero value otherwise. +func (s *Subscription) GetThreadURL() string { + if s == nil || s.ThreadURL == nil { + return "" + } + return *s.ThreadURL +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (s *Subscription) GetURL() string { + if s == nil || s.URL == nil { + return "" + } + return *s.URL +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (t *Tag) GetMessage() string { + if t == nil || t.Message == nil { + return "" + } + return *t.Message +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (t *Tag) GetSHA() string { + if t == nil || t.SHA == nil { + return "" + } + return *t.SHA +} + +// GetTag returns the Tag field if it's non-nil, zero value otherwise. +func (t *Tag) GetTag() string { + if t == nil || t.Tag == nil { + return "" + } + return *t.Tag +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (t *Tag) GetURL() string { + if t == nil || t.URL == nil { + return "" + } + return *t.URL +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (t *Team) GetDescription() string { + if t == nil || t.Description == nil { + return "" + } + return *t.Description +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (t *Team) GetID() int { + if t == nil || t.ID == nil { + return 0 + } + return *t.ID +} + +// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. +func (t *Team) GetLDAPDN() string { + if t == nil || t.LDAPDN == nil { + return "" + } + return *t.LDAPDN +} + +// GetMembersCount returns the MembersCount field if it's non-nil, zero value otherwise. +func (t *Team) GetMembersCount() int { + if t == nil || t.MembersCount == nil { + return 0 + } + return *t.MembersCount +} + +// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. +func (t *Team) GetMembersURL() string { + if t == nil || t.MembersURL == nil { + return "" + } + return *t.MembersURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (t *Team) GetName() string { + if t == nil || t.Name == nil { + return "" + } + return *t.Name +} + +// GetPermission returns the Permission field if it's non-nil, zero value otherwise. +func (t *Team) GetPermission() string { + if t == nil || t.Permission == nil { + return "" + } + return *t.Permission +} + +// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. +func (t *Team) GetPrivacy() string { + if t == nil || t.Privacy == nil { + return "" + } + return *t.Privacy +} + +// GetReposCount returns the ReposCount field if it's non-nil, zero value otherwise. +func (t *Team) GetReposCount() int { + if t == nil || t.ReposCount == nil { + return 0 + } + return *t.ReposCount +} + +// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. +func (t *Team) GetRepositoriesURL() string { + if t == nil || t.RepositoriesURL == nil { + return "" + } + return *t.RepositoriesURL +} + +// GetSlug returns the Slug field if it's non-nil, zero value otherwise. +func (t *Team) GetSlug() string { + if t == nil || t.Slug == nil { + return "" + } + return *t.Slug +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (t *Team) GetURL() string { + if t == nil || t.URL == nil { + return "" + } + return *t.URL +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetDescription() string { + if t == nil || t.Description == nil { + return "" + } + return *t.Description +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetID() int { + if t == nil || t.ID == nil { + return 0 + } + return *t.ID +} + +// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetLDAPDN() string { + if t == nil || t.LDAPDN == nil { + return "" + } + return *t.LDAPDN +} + +// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetMembersURL() string { + if t == nil || t.MembersURL == nil { + return "" + } + return *t.MembersURL +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetName() string { + if t == nil || t.Name == nil { + return "" + } + return *t.Name +} + +// GetPermission returns the Permission field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetPermission() string { + if t == nil || t.Permission == nil { + return "" + } + return *t.Permission +} + +// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetPrivacy() string { + if t == nil || t.Privacy == nil { + return "" + } + return *t.Privacy +} + +// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetRepositoriesURL() string { + if t == nil || t.RepositoriesURL == nil { + return "" + } + return *t.RepositoriesURL +} + +// GetSlug returns the Slug field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetSlug() string { + if t == nil || t.Slug == nil { + return "" + } + return *t.Slug +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (t *TeamLDAPMapping) GetURL() string { + if t == nil || t.URL == nil { + return "" + } + return *t.URL +} + +// GetFragment returns the Fragment field if it's non-nil, zero value otherwise. +func (t *TextMatch) GetFragment() string { + if t == nil || t.Fragment == nil { + return "" + } + return *t.Fragment +} + +// GetObjectType returns the ObjectType field if it's non-nil, zero value otherwise. +func (t *TextMatch) GetObjectType() string { + if t == nil || t.ObjectType == nil { + return "" + } + return *t.ObjectType +} + +// GetObjectURL returns the ObjectURL field if it's non-nil, zero value otherwise. +func (t *TextMatch) GetObjectURL() string { + if t == nil || t.ObjectURL == nil { + return "" + } + return *t.ObjectURL +} + +// GetProperty returns the Property field if it's non-nil, zero value otherwise. +func (t *TextMatch) GetProperty() string { + if t == nil || t.Property == nil { + return "" + } + return *t.Property +} + +// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. +func (t *Timeline) GetCommitID() string { + if t == nil || t.CommitID == nil { + return "" + } + return *t.CommitID +} + +// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. +func (t *Timeline) GetCommitURL() string { + if t == nil || t.CommitURL == nil { + return "" + } + return *t.CommitURL +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (t *Timeline) GetCreatedAt() time.Time { + if t == nil || t.CreatedAt == nil { + return time.Time{} + } + return *t.CreatedAt +} + +// GetEvent returns the Event field if it's non-nil, zero value otherwise. +func (t *Timeline) GetEvent() string { + if t == nil || t.Event == nil { + return "" + } + return *t.Event +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (t *Timeline) GetID() int { + if t == nil || t.ID == nil { + return 0 + } + return *t.ID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (t *Timeline) GetURL() string { + if t == nil || t.URL == nil { + return "" + } + return *t.URL +} + +// GetCount returns the Count field if it's non-nil, zero value otherwise. +func (t *TrafficClones) GetCount() int { + if t == nil || t.Count == nil { + return 0 + } + return *t.Count +} + +// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. +func (t *TrafficClones) GetUniques() int { + if t == nil || t.Uniques == nil { + return 0 + } + return *t.Uniques +} + +// GetCount returns the Count field if it's non-nil, zero value otherwise. +func (t *TrafficData) GetCount() int { + if t == nil || t.Count == nil { + return 0 + } + return *t.Count +} + +// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. +func (t *TrafficData) GetTimestamp() Timestamp { + if t == nil || t.Timestamp == nil { + return Timestamp{} + } + return *t.Timestamp +} + +// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. +func (t *TrafficData) GetUniques() int { + if t == nil || t.Uniques == nil { + return 0 + } + return *t.Uniques +} + +// GetCount returns the Count field if it's non-nil, zero value otherwise. +func (t *TrafficPath) GetCount() int { + if t == nil || t.Count == nil { + return 0 + } + return *t.Count +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (t *TrafficPath) GetPath() string { + if t == nil || t.Path == nil { + return "" + } + return *t.Path +} + +// GetTitle returns the Title field if it's non-nil, zero value otherwise. +func (t *TrafficPath) GetTitle() string { + if t == nil || t.Title == nil { + return "" + } + return *t.Title +} + +// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. +func (t *TrafficPath) GetUniques() int { + if t == nil || t.Uniques == nil { + return 0 + } + return *t.Uniques +} + +// GetCount returns the Count field if it's non-nil, zero value otherwise. +func (t *TrafficReferrer) GetCount() int { + if t == nil || t.Count == nil { + return 0 + } + return *t.Count +} + +// GetReferrer returns the Referrer field if it's non-nil, zero value otherwise. +func (t *TrafficReferrer) GetReferrer() string { + if t == nil || t.Referrer == nil { + return "" + } + return *t.Referrer +} + +// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. +func (t *TrafficReferrer) GetUniques() int { + if t == nil || t.Uniques == nil { + return 0 + } + return *t.Uniques +} + +// GetCount returns the Count field if it's non-nil, zero value otherwise. +func (t *TrafficViews) GetCount() int { + if t == nil || t.Count == nil { + return 0 + } + return *t.Count +} + +// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. +func (t *TrafficViews) GetUniques() int { + if t == nil || t.Uniques == nil { + return 0 + } + return *t.Uniques +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (t *Tree) GetSHA() string { + if t == nil || t.SHA == nil { + return "" + } + return *t.SHA +} + +// GetContent returns the Content field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetContent() string { + if t == nil || t.Content == nil { + return "" + } + return *t.Content +} + +// GetMode returns the Mode field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetMode() string { + if t == nil || t.Mode == nil { + return "" + } + return *t.Mode +} + +// GetPath returns the Path field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetPath() string { + if t == nil || t.Path == nil { + return "" + } + return *t.Path +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetSHA() string { + if t == nil || t.SHA == nil { + return "" + } + return *t.SHA +} + +// GetSize returns the Size field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetSize() int { + if t == nil || t.Size == nil { + return 0 + } + return *t.Size +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (t *TreeEntry) GetType() string { + if t == nil || t.Type == nil { + return "" + } + return *t.Type +} + +// GetForce returns the Force field if it's non-nil, zero value otherwise. +func (u *updateRefRequest) GetForce() bool { + if u == nil || u.Force == nil { + return false + } + return *u.Force +} + +// GetSHA returns the SHA field if it's non-nil, zero value otherwise. +func (u *updateRefRequest) GetSHA() string { + if u == nil || u.SHA == nil { + return "" + } + return *u.SHA +} + +// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. +func (u *User) GetAvatarURL() string { + if u == nil || u.AvatarURL == nil { + return "" + } + return *u.AvatarURL +} + +// GetBio returns the Bio field if it's non-nil, zero value otherwise. +func (u *User) GetBio() string { + if u == nil || u.Bio == nil { + return "" + } + return *u.Bio +} + +// GetBlog returns the Blog field if it's non-nil, zero value otherwise. +func (u *User) GetBlog() string { + if u == nil || u.Blog == nil { + return "" + } + return *u.Blog +} + +// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. +func (u *User) GetCollaborators() int { + if u == nil || u.Collaborators == nil { + return 0 + } + return *u.Collaborators +} + +// GetCompany returns the Company field if it's non-nil, zero value otherwise. +func (u *User) GetCompany() string { + if u == nil || u.Company == nil { + return "" + } + return *u.Company +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (u *User) GetCreatedAt() Timestamp { + if u == nil || u.CreatedAt == nil { + return Timestamp{} + } + return *u.CreatedAt +} + +// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. +func (u *User) GetDiskUsage() int { + if u == nil || u.DiskUsage == nil { + return 0 + } + return *u.DiskUsage +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (u *User) GetEmail() string { + if u == nil || u.Email == nil { + return "" + } + return *u.Email +} + +// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. +func (u *User) GetEventsURL() string { + if u == nil || u.EventsURL == nil { + return "" + } + return *u.EventsURL +} + +// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. +func (u *User) GetFollowers() int { + if u == nil || u.Followers == nil { + return 0 + } + return *u.Followers +} + +// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. +func (u *User) GetFollowersURL() string { + if u == nil || u.FollowersURL == nil { + return "" + } + return *u.FollowersURL +} + +// GetFollowing returns the Following field if it's non-nil, zero value otherwise. +func (u *User) GetFollowing() int { + if u == nil || u.Following == nil { + return 0 + } + return *u.Following +} + +// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. +func (u *User) GetFollowingURL() string { + if u == nil || u.FollowingURL == nil { + return "" + } + return *u.FollowingURL +} + +// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. +func (u *User) GetGistsURL() string { + if u == nil || u.GistsURL == nil { + return "" + } + return *u.GistsURL +} + +// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. +func (u *User) GetGravatarID() string { + if u == nil || u.GravatarID == nil { + return "" + } + return *u.GravatarID +} + +// GetHireable returns the Hireable field if it's non-nil, zero value otherwise. +func (u *User) GetHireable() bool { + if u == nil || u.Hireable == nil { + return false + } + return *u.Hireable +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (u *User) GetHTMLURL() string { + if u == nil || u.HTMLURL == nil { + return "" + } + return *u.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (u *User) GetID() int { + if u == nil || u.ID == nil { + return 0 + } + return *u.ID +} + +// GetLocation returns the Location field if it's non-nil, zero value otherwise. +func (u *User) GetLocation() string { + if u == nil || u.Location == nil { + return "" + } + return *u.Location +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (u *User) GetLogin() string { + if u == nil || u.Login == nil { + return "" + } + return *u.Login +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (u *User) GetName() string { + if u == nil || u.Name == nil { + return "" + } + return *u.Name +} + +// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. +func (u *User) GetOrganizationsURL() string { + if u == nil || u.OrganizationsURL == nil { + return "" + } + return *u.OrganizationsURL +} + +// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. +func (u *User) GetOwnedPrivateRepos() int { + if u == nil || u.OwnedPrivateRepos == nil { + return 0 + } + return *u.OwnedPrivateRepos +} + +// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. +func (u *User) GetPermissions() map[string]bool { + if u == nil || u.Permissions == nil { + return map[string]bool{} + } + return *u.Permissions +} + +// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. +func (u *User) GetPrivateGists() int { + if u == nil || u.PrivateGists == nil { + return 0 + } + return *u.PrivateGists +} + +// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. +func (u *User) GetPublicGists() int { + if u == nil || u.PublicGists == nil { + return 0 + } + return *u.PublicGists +} + +// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. +func (u *User) GetPublicRepos() int { + if u == nil || u.PublicRepos == nil { + return 0 + } + return *u.PublicRepos +} + +// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. +func (u *User) GetReceivedEventsURL() string { + if u == nil || u.ReceivedEventsURL == nil { + return "" + } + return *u.ReceivedEventsURL +} + +// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. +func (u *User) GetReposURL() string { + if u == nil || u.ReposURL == nil { + return "" + } + return *u.ReposURL +} + +// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. +func (u *User) GetSiteAdmin() bool { + if u == nil || u.SiteAdmin == nil { + return false + } + return *u.SiteAdmin +} + +// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. +func (u *User) GetStarredURL() string { + if u == nil || u.StarredURL == nil { + return "" + } + return *u.StarredURL +} + +// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. +func (u *User) GetSubscriptionsURL() string { + if u == nil || u.SubscriptionsURL == nil { + return "" + } + return *u.SubscriptionsURL +} + +// GetSuspendedAt returns the SuspendedAt field if it's non-nil, zero value otherwise. +func (u *User) GetSuspendedAt() Timestamp { + if u == nil || u.SuspendedAt == nil { + return Timestamp{} + } + return *u.SuspendedAt +} + +// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. +func (u *User) GetTotalPrivateRepos() int { + if u == nil || u.TotalPrivateRepos == nil { + return 0 + } + return *u.TotalPrivateRepos +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (u *User) GetType() string { + if u == nil || u.Type == nil { + return "" + } + return *u.Type +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (u *User) GetUpdatedAt() Timestamp { + if u == nil || u.UpdatedAt == nil { + return Timestamp{} + } + return *u.UpdatedAt +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (u *User) GetURL() string { + if u == nil || u.URL == nil { + return "" + } + return *u.URL +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (u *UserEmail) GetEmail() string { + if u == nil || u.Email == nil { + return "" + } + return *u.Email +} + +// GetPrimary returns the Primary field if it's non-nil, zero value otherwise. +func (u *UserEmail) GetPrimary() bool { + if u == nil || u.Primary == nil { + return false + } + return *u.Primary +} + +// GetVerified returns the Verified field if it's non-nil, zero value otherwise. +func (u *UserEmail) GetVerified() bool { + if u == nil || u.Verified == nil { + return false + } + return *u.Verified +} + +// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetAvatarURL() string { + if u == nil || u.AvatarURL == nil { + return "" + } + return *u.AvatarURL +} + +// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetEventsURL() string { + if u == nil || u.EventsURL == nil { + return "" + } + return *u.EventsURL +} + +// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetFollowersURL() string { + if u == nil || u.FollowersURL == nil { + return "" + } + return *u.FollowersURL +} + +// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetFollowingURL() string { + if u == nil || u.FollowingURL == nil { + return "" + } + return *u.FollowingURL +} + +// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetGistsURL() string { + if u == nil || u.GistsURL == nil { + return "" + } + return *u.GistsURL +} + +// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetGravatarID() string { + if u == nil || u.GravatarID == nil { + return "" + } + return *u.GravatarID +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetID() int { + if u == nil || u.ID == nil { + return 0 + } + return *u.ID +} + +// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetLDAPDN() string { + if u == nil || u.LDAPDN == nil { + return "" + } + return *u.LDAPDN +} + +// GetLogin returns the Login field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetLogin() string { + if u == nil || u.Login == nil { + return "" + } + return *u.Login +} + +// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetOrganizationsURL() string { + if u == nil || u.OrganizationsURL == nil { + return "" + } + return *u.OrganizationsURL +} + +// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetReceivedEventsURL() string { + if u == nil || u.ReceivedEventsURL == nil { + return "" + } + return *u.ReceivedEventsURL +} + +// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetReposURL() string { + if u == nil || u.ReposURL == nil { + return "" + } + return *u.ReposURL +} + +// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetSiteAdmin() bool { + if u == nil || u.SiteAdmin == nil { + return false + } + return *u.SiteAdmin +} + +// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetStarredURL() string { + if u == nil || u.StarredURL == nil { + return "" + } + return *u.StarredURL +} + +// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetSubscriptionsURL() string { + if u == nil || u.SubscriptionsURL == nil { + return "" + } + return *u.SubscriptionsURL +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetType() string { + if u == nil || u.Type == nil { + return "" + } + return *u.Type +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (u *UserLDAPMapping) GetURL() string { + if u == nil || u.URL == nil { + return "" + } + return *u.URL +} + +// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. +func (u *UsersSearchResult) GetIncompleteResults() bool { + if u == nil || u.IncompleteResults == nil { + return false + } + return *u.IncompleteResults +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (u *UsersSearchResult) GetTotal() int { + if u == nil || u.Total == nil { + return 0 + } + return *u.Total +} + +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (w *WatchEvent) GetAction() string { + if w == nil || w.Action == nil { + return "" + } + return *w.Action +} + +// GetEmail returns the Email field if it's non-nil, zero value otherwise. +func (w *WebHookAuthor) GetEmail() string { + if w == nil || w.Email == nil { + return "" + } + return *w.Email +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (w *WebHookAuthor) GetName() string { + if w == nil || w.Name == nil { + return "" + } + return *w.Name +} + +// GetUsername returns the Username field if it's non-nil, zero value otherwise. +func (w *WebHookAuthor) GetUsername() string { + if w == nil || w.Username == nil { + return "" + } + return *w.Username +} + +// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. +func (w *WebHookCommit) GetDistinct() bool { + if w == nil || w.Distinct == nil { + return false + } + return *w.Distinct +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (w *WebHookCommit) GetID() string { + if w == nil || w.ID == nil { + return "" + } + return *w.ID +} + +// GetMessage returns the Message field if it's non-nil, zero value otherwise. +func (w *WebHookCommit) GetMessage() string { + if w == nil || w.Message == nil { + return "" + } + return *w.Message +} + +// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. +func (w *WebHookCommit) GetTimestamp() time.Time { + if w == nil || w.Timestamp == nil { + return time.Time{} + } + return *w.Timestamp +} + +// GetAfter returns the After field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetAfter() string { + if w == nil || w.After == nil { + return "" + } + return *w.After +} + +// GetBefore returns the Before field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetBefore() string { + if w == nil || w.Before == nil { + return "" + } + return *w.Before +} + +// GetCompare returns the Compare field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetCompare() string { + if w == nil || w.Compare == nil { + return "" + } + return *w.Compare +} + +// GetCreated returns the Created field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetCreated() bool { + if w == nil || w.Created == nil { + return false + } + return *w.Created +} + +// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetDeleted() bool { + if w == nil || w.Deleted == nil { + return false + } + return *w.Deleted +} + +// GetForced returns the Forced field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetForced() bool { + if w == nil || w.Forced == nil { + return false + } + return *w.Forced +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (w *WebHookPayload) GetRef() string { + if w == nil || w.Ref == nil { + return "" + } + return *w.Ref +} + +// GetTotal returns the Total field if it's non-nil, zero value otherwise. +func (w *WeeklyCommitActivity) GetTotal() int { + if w == nil || w.Total == nil { + return 0 + } + return *w.Total +} + +// GetWeek returns the Week field if it's non-nil, zero value otherwise. +func (w *WeeklyCommitActivity) GetWeek() Timestamp { + if w == nil || w.Week == nil { + return Timestamp{} + } + return *w.Week +} + +// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. +func (w *WeeklyStats) GetAdditions() int { + if w == nil || w.Additions == nil { + return 0 + } + return *w.Additions +} + +// GetCommits returns the Commits field if it's non-nil, zero value otherwise. +func (w *WeeklyStats) GetCommits() int { + if w == nil || w.Commits == nil { + return 0 + } + return *w.Commits +} + +// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. +func (w *WeeklyStats) GetDeletions() int { + if w == nil || w.Deletions == nil { + return 0 + } + return *w.Deletions +} + +// GetWeek returns the Week field if it's non-nil, zero value otherwise. +func (w *WeeklyStats) GetWeek() Timestamp { + if w == nil || w.Week == nil { + return Timestamp{} + } + return *w.Week +} diff --git a/vendor/github.com/google/go-github/github/github.go b/vendor/github.com/google/go-github/github/github.go index 3d7421fdc..decdaaae6 100644 --- a/vendor/github.com/google/go-github/github/github.go +++ b/vendor/github.com/google/go-github/github/github.go @@ -3,10 +3,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run gen-accessors.go + package github import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -24,12 +27,7 @@ import ( ) const ( - // StatusUnprocessableEntity is the status code returned when sending a request with invalid fields. - StatusUnprocessableEntity = 422 -) - -const ( - libraryVersion = "2" + libraryVersion = "6" defaultBaseURL = "https://api.github.com/" uploadBaseURL = "https://uploads.github.com/" userAgent = "go-github/" + libraryVersion @@ -85,14 +83,20 @@ const ( // https://developer.github.com/changes/2016-07-06-github-pages-preiew-api/ mediaTypePagesPreview = "application/vnd.github.mister-fantastic-preview+json" - // https://developer.github.com/v3/repos/traffic/ - mediaTypeTrafficPreview = "application/vnd.github.spiderman-preview+json" - // https://developer.github.com/changes/2016-09-14-projects-api/ mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json" // https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/ mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json" + + // https://developer.github.com/changes/2017-01-05-commit-search-api/ + mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json" + + // https://developer.github.com/changes/2016-12-14-reviews-api/ + mediaTypePullRequestReviewsPreview = "application/vnd.github.black-cat-preview+json" + + // https://developer.github.com/changes/2017-02-28-user-blocking-apis-and-webhook/ + mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json" ) // A Client manages communication with the GitHub API. @@ -100,8 +104,8 @@ type Client struct { clientMu sync.Mutex // clientMu protects the client during calls that modify the CheckRedirect func. client *http.Client // HTTP client used to communicate with the API. - // Base URL for API requests. Defaults to the public GitHub API, but can be - // set to a domain endpoint to use with GitHub Enterprise. BaseURL should + // Base URL for API requests. Defaults to the public GitHub API, but can be + // set to a domain endpoint to use with GitHub Enterprise. BaseURL should // always be specified with a trailing slash. BaseURL *url.URL @@ -113,7 +117,6 @@ type Client struct { rateMu sync.Mutex rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls. - mostRecent rateLimitCategory common service // Reuse a single struct instead of allocating one for each service on the heap. @@ -172,7 +175,7 @@ type RawOptions struct { Type RawType } -// addOptions adds the parameters in opt as URL query parameters to s. opt +// addOptions adds the parameters in opt as URL query parameters to s. opt // must be a struct whose fields may contain "url" tags. func addOptions(s string, opt interface{}) (string, error) { v := reflect.ValueOf(opt) @@ -194,8 +197,8 @@ func addOptions(s string, opt interface{}) (string, error) { return u.String(), nil } -// NewClient returns a new GitHub API client. If a nil httpClient is -// provided, http.DefaultClient will be used. To use API methods which require +// NewClient returns a new GitHub API client. If a nil httpClient is +// provided, http.DefaultClient will be used. To use API methods which require // authentication, provide an http.Client that will perform the authentication // for you (such as that provided by the golang.org/x/oauth2 library). func NewClient(httpClient *http.Client) *Client { @@ -229,7 +232,7 @@ func NewClient(httpClient *http.Client) *Client { // NewRequest creates an API request. A relative URL can be provided in urlStr, // in which case it is resolved relative to the BaseURL of the Client. -// Relative URLs should always be specified without a preceding slash. If +// Relative URLs should always be specified without a preceding slash. If // specified, the value pointed to by body is JSON encoded and included as the // request body. func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { @@ -289,14 +292,14 @@ func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, m return req, nil } -// Response is a GitHub API response. This wraps the standard http.Response +// Response is a GitHub API response. This wraps the standard http.Response // returned from GitHub and provides convenient access to things like // pagination links. type Response struct { *http.Response // These fields provide the page values for paginating through a set of - // results. Any or all of these may be set to the zero value for + // results. Any or all of these may be set to the zero value for // responses that are not part of a paginated set, or for which there // are no additional pages. @@ -377,26 +380,18 @@ func parseRate(r *http.Response) Rate { return rate } -// Rate specifies the current rate limit for the client as determined by the -// most recent API call. If the client is used in a multi-user application, -// this rate may not always be up-to-date. -// -// Deprecated: Use the Response.Rate returned from most recent API call instead. -// Call RateLimits() to check the current rate. -func (c *Client) Rate() Rate { - c.rateMu.Lock() - rate := c.rateLimits[c.mostRecent] - c.rateMu.Unlock() - return rate -} - -// Do sends an API request and returns the API response. The API response is +// Do sends an API request and returns the API response. The API response is // JSON decoded and stored in the value pointed to by v, or returned as an -// error if an API error has occurred. If v implements the io.Writer +// error if an API error has occurred. If v implements the io.Writer // interface, the raw response body will be written to v, without attempting to -// first decode it. If rate limit is exceeded and reset time is in the future, +// first decode it. If rate limit is exceeded and reset time is in the future, // Do returns *RateLimitError immediately without making a network API call. -func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { +// +// The provided ctx must be non-nil. If it is canceled or times out, +// ctx.Err() will be returned. +func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) { + ctx, req = withContext(ctx, req) + rateLimitCategory := category(req.URL.Path) // If we've hit rate limit, don't make further requests before Reset time. @@ -406,6 +401,22 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { resp, err := c.client.Do(req) if err != nil { + // If we got an error, and the context has been canceled, + // the context's error is probably more useful. + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + // If the error type is *url.Error, sanitize its URL before returning. + if e, ok := err.(*url.Error); ok { + if url, err := url.Parse(e.URL); err == nil { + e.URL = sanitizeURL(url).String() + return nil, e + } + } + return nil, err } @@ -419,7 +430,6 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { c.rateMu.Lock() c.rateLimits[rateLimitCategory] = response.Rate - c.mostRecent = rateLimitCategory c.rateMu.Unlock() err = CheckResponse(resp) @@ -473,7 +483,7 @@ func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rat /* An ErrorResponse reports one or more errors caused by an API request. -GitHub API docs: http://developer.github.com/v3/#client-errors +GitHub API docs: https://developer.github.com/v3/#client-errors */ type ErrorResponse struct { Response *http.Response // HTTP response that caused this error @@ -499,7 +509,7 @@ func (r *ErrorResponse) Error() string { } // TwoFactorAuthError occurs when using HTTP Basic Authentication for a user -// that has two-factor authentication enabled. The request can be reattempted +// that has two-factor authentication enabled. The request can be reattempted // by providing a one-time password in the request. type TwoFactorAuthError ErrorResponse @@ -550,7 +560,7 @@ func (r *AbuseRateLimitError) Error() string { } // sanitizeURL redacts the client_secret parameter from the URL which may be -// exposed to the user, specifically in the ErrorResponse error message. +// exposed to the user. func sanitizeURL(uri *url.URL) *url.URL { if uri == nil { return nil @@ -579,7 +589,7 @@ These are the possible validation error codes: some resources return this (e.g. github.User.CreateKey()), additional information is set in the Message field of the Error -GitHub API docs: http://developer.github.com/v3/#client-errors +GitHub API docs: https://developer.github.com/v3/#client-errors */ type Error struct { Resource string `json:"resource"` // resource on which the error occurred @@ -597,7 +607,7 @@ func (e *Error) Error() string { // present. A response is considered an error if it has a status code outside // the 200 range or equal to 202 Accepted. // API error responses are expected to have either no response -// body, or a JSON response body that maps to ErrorResponse. Any other +// body, or a JSON response body that maps to ErrorResponse. Any other // response body will be silently ignored. // // The error type will be *RateLimitError for rate limit exceeded errors, @@ -646,15 +656,15 @@ func CheckResponse(r *http.Response) error { // parseBoolResponse determines the boolean result from a GitHub API response. // Several GitHub API methods return boolean responses indicated by the HTTP // status code in the response (true indicated by a 204, false indicated by a -// 404). This helper function will determine that result and hide the 404 -// error if present. Any other error will be returned through as-is. +// 404). This helper function will determine that result and hide the 404 +// error if present. Any other error will be returned through as-is. func parseBoolResponse(err error) (bool, error) { if err == nil { return true, nil } if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound { - // Simply false. In this one case, we do not pass the error through. + // Simply false. In this one case, we do not pass the error through. return false, nil } @@ -680,15 +690,15 @@ func (r Rate) String() string { // RateLimits represents the rate limits for the current client. type RateLimits struct { - // The rate limit for non-search API requests. Unauthenticated - // requests are limited to 60 per hour. Authenticated requests are + // The rate limit for non-search API requests. Unauthenticated + // requests are limited to 60 per hour. Authenticated requests are // limited to 5,000 per hour. // // GitHub API docs: https://developer.github.com/v3/#rate-limiting Core *Rate `json:"core"` - // The rate limit for search API requests. Unauthenticated requests - // are limited to 10 requests per minutes. Authenticated requests are + // The rate limit for search API requests. Unauthenticated requests + // are limited to 10 requests per minutes. Authenticated requests are // limited to 30 per minute. // // GitHub API docs: https://developer.github.com/v3/search/#rate-limit @@ -718,20 +728,8 @@ func category(path string) rateLimitCategory { } } -// RateLimit returns the core rate limit for the current client. -// -// Deprecated: RateLimit is deprecated, use RateLimits instead. -func (c *Client) RateLimit() (*Rate, *Response, error) { - limits, resp, err := c.RateLimits() - if limits == nil { - return nil, nil, err - } - - return limits.Core, resp, err -} - // RateLimits returns the rate limits for the current client. -func (c *Client) RateLimits() (*RateLimits, *Response, error) { +func (c *Client) RateLimits(ctx context.Context) (*RateLimits, *Response, error) { req, err := c.NewRequest("GET", "rate_limit", nil) if err != nil { return nil, nil, err @@ -740,7 +738,7 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) { response := new(struct { Resources *RateLimits `json:"resources"` }) - resp, err := c.Do(req, response) + resp, err := c.Do(ctx, req, response) if err != nil { return nil, nil, err } @@ -756,7 +754,7 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) { c.rateMu.Unlock() } - return response.Resources, resp, err + return response.Resources, resp, nil } /* @@ -772,7 +770,7 @@ that need to use a higher rate limit associated with your OAuth application. This will append the querystring params client_id=xxx&client_secret=yyy to all requests. -See http://developer.github.com/v3/#unauthenticated-rate-limited-requests for +See https://developer.github.com/v3/#unauthenticated-rate-limited-requests for more information. */ type UnauthenticatedRateLimitedTransport struct { @@ -826,7 +824,7 @@ func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper { } // BasicAuthTransport is an http.RoundTripper that authenticates all requests -// using HTTP Basic Authentication with the provided username and password. It +// using HTTP Basic Authentication with the provided username and password. It // additionally supports users who have two-factor authentication enabled on // their GitHub account. type BasicAuthTransport struct { diff --git a/vendor/github.com/google/go-github/github/gitignore.go b/vendor/github.com/google/go-github/github/gitignore.go index faaceb5a5..2f691bc32 100644 --- a/vendor/github.com/google/go-github/github/gitignore.go +++ b/vendor/github.com/google/go-github/github/gitignore.go @@ -5,12 +5,15 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // GitignoresService provides access to the gitignore related functions in the // GitHub API. // -// GitHub API docs: http://developer.github.com/v3/gitignore/ +// GitHub API docs: https://developer.github.com/v3/gitignore/ type GitignoresService service // Gitignore represents a .gitignore file as returned by the GitHub API. @@ -25,26 +28,26 @@ func (g Gitignore) String() string { // List all available Gitignore templates. // -// http://developer.github.com/v3/gitignore/#listing-available-templates -func (s GitignoresService) List() ([]string, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gitignore/#listing-available-templates +func (s GitignoresService) List(ctx context.Context) ([]string, *Response, error) { req, err := s.client.NewRequest("GET", "gitignore/templates", nil) if err != nil { return nil, nil, err } - availableTemplates := new([]string) - resp, err := s.client.Do(req, availableTemplates) + var availableTemplates []string + resp, err := s.client.Do(ctx, req, &availableTemplates) if err != nil { return nil, resp, err } - return *availableTemplates, resp, err + return availableTemplates, resp, nil } // Get a Gitignore by name. // -// http://developer.github.com/v3/gitignore/#get-a-single-template -func (s GitignoresService) Get(name string) (*Gitignore, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/gitignore/#get-a-single-template +func (s GitignoresService) Get(ctx context.Context, name string) (*Gitignore, *Response, error) { u := fmt.Sprintf("gitignore/templates/%v", name) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -52,10 +55,10 @@ func (s GitignoresService) Get(name string) (*Gitignore, *Response, error) { } gitignore := new(Gitignore) - resp, err := s.client.Do(req, gitignore) + resp, err := s.client.Do(ctx, req, gitignore) if err != nil { return nil, resp, err } - return gitignore, resp, err + return gitignore, resp, nil } diff --git a/vendor/github.com/google/go-github/github/integration.go b/vendor/github.com/google/go-github/github/integration.go index b8d77ca4f..6d74e44f0 100644 --- a/vendor/github.com/google/go-github/github/integration.go +++ b/vendor/github.com/google/go-github/github/integration.go @@ -5,6 +5,8 @@ package github +import "context" + // IntegrationsService provides access to the installation related functions // in the GitHub API. // @@ -14,7 +16,7 @@ type IntegrationsService service // ListInstallations lists the installations that the current integration has. // // GitHub API docs: https://developer.github.com/v3/integrations/#find-installations -func (s *IntegrationsService) ListInstallations(opt *ListOptions) ([]*Installation, *Response, error) { +func (s *IntegrationsService) ListInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { u, err := addOptions("integration/installations", opt) if err != nil { return nil, nil, err @@ -28,11 +30,11 @@ func (s *IntegrationsService) ListInstallations(opt *ListOptions) ([]*Installati // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeIntegrationPreview) - i := new([]*Installation) - resp, err := s.client.Do(req, &i) + var i []*Installation + resp, err := s.client.Do(ctx, req, &i) if err != nil { return nil, resp, err } - return *i, resp, err + return i, resp, nil } diff --git a/vendor/github.com/google/go-github/github/integration_installation.go b/vendor/github.com/google/go-github/github/integration_installation.go index aa59bfe4b..0836d86d1 100644 --- a/vendor/github.com/google/go-github/github/integration_installation.go +++ b/vendor/github.com/google/go-github/github/integration_installation.go @@ -5,12 +5,15 @@ package github +import "context" + // Installation represents a GitHub integration installation. type Installation struct { ID *int `json:"id,omitempty"` Account *User `json:"account,omitempty"` AccessTokensURL *string `json:"access_tokens_url,omitempty"` RepositoriesURL *string `json:"repositories_url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` } func (i Installation) String() string { @@ -20,7 +23,7 @@ func (i Installation) String() string { // ListRepos lists the repositories that the current installation has access to. // // GitHub API docs: https://developer.github.com/v3/integrations/installations/#list-repositories -func (s *IntegrationsService) ListRepos(opt *ListOptions) ([]*Repository, *Response, error) { +func (s *IntegrationsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repository, *Response, error) { u, err := addOptions("installation/repositories", opt) if err != nil { return nil, nil, err @@ -37,10 +40,10 @@ func (s *IntegrationsService) ListRepos(opt *ListOptions) ([]*Repository, *Respo var r struct { Repositories []*Repository `json:"repositories"` } - resp, err := s.client.Do(req, &r) + resp, err := s.client.Do(ctx, req, &r) if err != nil { return nil, resp, err } - return r.Repositories, resp, err + return r.Repositories, resp, nil } diff --git a/vendor/github.com/google/go-github/github/issues.go b/vendor/github.com/google/go-github/github/issues.go index d8e7d41c4..b437d5063 100644 --- a/vendor/github.com/google/go-github/github/issues.go +++ b/vendor/github.com/google/go-github/github/issues.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -13,7 +14,7 @@ import ( // IssuesService handles communication with the issue related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/issues/ +// GitHub API docs: https://developer.github.com/v3/issues/ type IssuesService service // Issue represents a GitHub issue on a repository. @@ -26,6 +27,7 @@ type Issue struct { ID *int `json:"id,omitempty"` Number *int `json:"number,omitempty"` State *string `json:"state,omitempty"` + Locked *bool `json:"locked,omitempty"` Title *string `json:"title,omitempty"` Body *string `json:"body,omitempty"` User *User `json:"user,omitempty"` @@ -35,6 +37,7 @@ type Issue struct { ClosedAt *time.Time `json:"closed_at,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` + ClosedBy *User `json:"closed_by,omitempty"` URL *string `json:"url,omitempty"` HTMLURL *string `json:"html_url,omitempty"` Milestone *Milestone `json:"milestone,omitempty"` @@ -68,22 +71,22 @@ type IssueRequest struct { // IssueListOptions specifies the optional parameters to the IssuesService.List // and IssuesService.ListByOrg methods. type IssueListOptions struct { - // Filter specifies which issues to list. Possible values are: assigned, - // created, mentioned, subscribed, all. Default is "assigned". + // Filter specifies which issues to list. Possible values are: assigned, + // created, mentioned, subscribed, all. Default is "assigned". Filter string `url:"filter,omitempty"` - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". + // State filters issues based on their state. Possible values are: open, + // closed, all. Default is "open". State string `url:"state,omitempty"` // Labels filters issues based on their label. Labels []string `url:"labels,comma,omitempty"` - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". + // Sort specifies how to sort issues. Possible values are: created, updated, + // and comments. Default value is "created". Sort string `url:"sort,omitempty"` - // Direction in which to sort issues. Possible values are: asc, desc. + // Direction in which to sort issues. Possible values are: asc, desc. // Default is "desc". Direction string `url:"direction,omitempty"` @@ -102,32 +105,32 @@ type PullRequestLinks struct { PatchURL *string `json:"patch_url,omitempty"` } -// List the issues for the authenticated user. If all is true, list issues +// List the issues for the authenticated user. If all is true, list issues // across all the user's visible repositories including owned, member, and // organization repositories; if false, list only owned and member // repositories. // -// GitHub API docs: http://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#list-issues +func (s *IssuesService) List(ctx context.Context, all bool, opt *IssueListOptions) ([]*Issue, *Response, error) { var u string if all { u = "issues" } else { u = "user/issues" } - return s.listIssues(u, opt) + return s.listIssues(ctx, u, opt) } // ListByOrg fetches the issues in the specified organization for the // authenticated user. // -// GitHub API docs: http://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) ListByOrg(org string, opt *IssueListOptions) ([]*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#list-issues +func (s *IssuesService) ListByOrg(ctx context.Context, org string, opt *IssueListOptions) ([]*Issue, *Response, error) { u := fmt.Sprintf("orgs/%v/issues", org) - return s.listIssues(u, opt) + return s.listIssues(ctx, u, opt) } -func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]*Issue, *Response, error) { +func (s *IssuesService) listIssues(ctx context.Context, u string, opt *IssueListOptions) ([]*Issue, *Response, error) { u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -141,28 +144,28 @@ func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]*Issue, * // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - issues := new([]*Issue) - resp, err := s.client.Do(req, issues) + var issues []*Issue + resp, err := s.client.Do(ctx, req, &issues) if err != nil { return nil, resp, err } - return *issues, resp, err + return issues, resp, nil } // IssueListByRepoOptions specifies the optional parameters to the // IssuesService.ListByRepo method. type IssueListByRepoOptions struct { - // Milestone limits issues for the specified milestone. Possible values are + // Milestone limits issues for the specified milestone. Possible values are // a milestone number, "none" for issues with no milestone, "*" for issues // with any milestone. Milestone string `url:"milestone,omitempty"` - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". + // State filters issues based on their state. Possible values are: open, + // closed, all. Default is "open". State string `url:"state,omitempty"` - // Assignee filters issues based on their assignee. Possible values are a + // Assignee filters issues based on their assignee. Possible values are a // user name, "none" for issues that are not assigned, "*" for issues with // any assigned user. Assignee string `url:"assignee,omitempty"` @@ -176,11 +179,11 @@ type IssueListByRepoOptions struct { // Labels filters issues based on their label. Labels []string `url:"labels,omitempty,comma"` - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". + // Sort specifies how to sort issues. Possible values are: created, updated, + // and comments. Default value is "created". Sort string `url:"sort,omitempty"` - // Direction in which to sort issues. Possible values are: asc, desc. + // Direction in which to sort issues. Possible values are: asc, desc. // Default is "desc". Direction string `url:"direction,omitempty"` @@ -192,8 +195,8 @@ type IssueListByRepoOptions struct { // ListByRepo lists the issues for the specified repository. // -// GitHub API docs: http://developer.github.com/v3/issues/#list-issues-for-a-repository -func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRepoOptions) ([]*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#list-issues-for-a-repository +func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo string, opt *IssueListByRepoOptions) ([]*Issue, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -208,19 +211,19 @@ func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRe // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - issues := new([]*Issue) - resp, err := s.client.Do(req, issues) + var issues []*Issue + resp, err := s.client.Do(ctx, req, &issues) if err != nil { return nil, resp, err } - return *issues, resp, err + return issues, resp, nil } // Get a single issue. // -// GitHub API docs: http://developer.github.com/v3/issues/#get-a-single-issue -func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#get-a-single-issue +func (s *IssuesService) Get(ctx context.Context, owner string, repo string, number int) (*Issue, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -231,18 +234,18 @@ func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, *Res req.Header.Set("Accept", mediaTypeReactionsPreview) issue := new(Issue) - resp, err := s.client.Do(req, issue) + resp, err := s.client.Do(ctx, req, issue) if err != nil { return nil, resp, err } - return issue, resp, err + return issue, resp, nil } // Create a new issue on the specified repository. // -// GitHub API docs: http://developer.github.com/v3/issues/#create-an-issue -func (s *IssuesService) Create(owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#create-an-issue +func (s *IssuesService) Create(ctx context.Context, owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) req, err := s.client.NewRequest("POST", u, issue) if err != nil { @@ -250,18 +253,18 @@ func (s *IssuesService) Create(owner string, repo string, issue *IssueRequest) ( } i := new(Issue) - resp, err := s.client.Do(req, i) + resp, err := s.client.Do(ctx, req, i) if err != nil { return nil, resp, err } - return i, resp, err + return i, resp, nil } // Edit an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/#edit-an-issue -func (s *IssuesService) Edit(owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/#edit-an-issue +func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) req, err := s.client.NewRequest("PATCH", u, issue) if err != nil { @@ -269,36 +272,36 @@ func (s *IssuesService) Edit(owner string, repo string, number int, issue *Issue } i := new(Issue) - resp, err := s.client.Do(req, i) + resp, err := s.client.Do(ctx, req, i) if err != nil { return nil, resp, err } - return i, resp, err + return i, resp, nil } // Lock an issue's conversation. // // GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue -func (s *IssuesService) Lock(owner string, repo string, number int) (*Response, error) { +func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) req, err := s.client.NewRequest("PUT", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Unlock an issue's conversation. // // GitHub API docs: https://developer.github.com/v3/issues/#unlock-an-issue -func (s *IssuesService) Unlock(owner string, repo string, number int) (*Response, error) { +func (s *IssuesService) Unlock(ctx context.Context, owner string, repo string, number int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/issues_assignees.go b/vendor/github.com/google/go-github/github/issues_assignees.go index 2503be1de..9cb366f50 100644 --- a/vendor/github.com/google/go-github/github/issues_assignees.go +++ b/vendor/github.com/google/go-github/github/issues_assignees.go @@ -5,13 +5,16 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // ListAssignees fetches all available assignees (owners and collaborators) to // which issues may be assigned. // -// GitHub API docs: http://developer.github.com/v3/issues/assignees/#list-assignees -func (s *IssuesService) ListAssignees(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/assignees/#list-assignees +func (s *IssuesService) ListAssignees(ctx context.Context, owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -22,25 +25,25 @@ func (s *IssuesService) ListAssignees(owner, repo string, opt *ListOptions) ([]* if err != nil { return nil, nil, err } - assignees := new([]*User) - resp, err := s.client.Do(req, assignees) + var assignees []*User + resp, err := s.client.Do(ctx, req, &assignees) if err != nil { return nil, resp, err } - return *assignees, resp, err + return assignees, resp, nil } // IsAssignee checks if a user is an assignee for the specified repository. // -// GitHub API docs: http://developer.github.com/v3/issues/assignees/#check-assignee -func (s *IssuesService) IsAssignee(owner, repo, user string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/assignees/#check-assignee +func (s *IssuesService) IsAssignee(ctx context.Context, owner, repo, user string) (bool, *Response, error) { u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) assignee, err := parseBoolResponse(err) return assignee, resp, err } @@ -48,7 +51,7 @@ func (s *IssuesService) IsAssignee(owner, repo, user string) (bool, *Response, e // AddAssignees adds the provided GitHub users as assignees to the issue. // // GitHub API docs: https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue -func (s *IssuesService) AddAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) { +func (s *IssuesService) AddAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { users := &struct { Assignees []string `json:"assignees,omitempty"` }{Assignees: assignees} @@ -59,14 +62,14 @@ func (s *IssuesService) AddAssignees(owner, repo string, number int, assignees [ } issue := &Issue{} - resp, err := s.client.Do(req, issue) + resp, err := s.client.Do(ctx, req, issue) return issue, resp, err } // RemoveAssignees removes the provided GitHub users as assignees from the issue. // // GitHub API docs: https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue -func (s *IssuesService) RemoveAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) { +func (s *IssuesService) RemoveAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { users := &struct { Assignees []string `json:"assignees,omitempty"` }{Assignees: assignees} @@ -77,6 +80,6 @@ func (s *IssuesService) RemoveAssignees(owner, repo string, number int, assignee } issue := &Issue{} - resp, err := s.client.Do(req, issue) + resp, err := s.client.Do(ctx, req, issue) return issue, resp, err } diff --git a/vendor/github.com/google/go-github/github/issues_comments.go b/vendor/github.com/google/go-github/github/issues_comments.go index b24c5aed8..fd72657cd 100644 --- a/vendor/github.com/google/go-github/github/issues_comments.go +++ b/vendor/github.com/google/go-github/github/issues_comments.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -30,10 +31,10 @@ func (i IssueComment) String() string { // IssueListCommentsOptions specifies the optional parameters to the // IssuesService.ListComments method. type IssueListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. + // Sort specifies how to sort comments. Possible values are: created, updated. Sort string `url:"sort,omitempty"` - // Direction in which to sort comments. Possible values are: asc, desc. + // Direction in which to sort comments. Possible values are: asc, desc. Direction string `url:"direction,omitempty"` // Since filters comments by time. @@ -42,11 +43,11 @@ type IssueListCommentsOptions struct { ListOptions } -// ListComments lists all comments on the specified issue. Specifying an issue +// ListComments lists all comments on the specified issue. Specifying an issue // number of 0 will return all comments on all issues for the repository. // -// GitHub API docs: http://developer.github.com/v3/issues/comments/#list-comments-on-an-issue -func (s *IssuesService) ListComments(owner string, repo string, number int, opt *IssueListCommentsOptions) ([]*IssueComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue +func (s *IssuesService) ListComments(ctx context.Context, owner string, repo string, number int, opt *IssueListCommentsOptions) ([]*IssueComment, *Response, error) { var u string if number == 0 { u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo) @@ -66,19 +67,19 @@ func (s *IssuesService) ListComments(owner string, repo string, number int, opt // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - comments := new([]*IssueComment) - resp, err := s.client.Do(req, comments) + var comments []*IssueComment + resp, err := s.client.Do(ctx, req, &comments) if err != nil { return nil, resp, err } - return *comments, resp, err + return comments, resp, nil } // GetComment fetches the specified issue comment. // -// GitHub API docs: http://developer.github.com/v3/issues/comments/#get-a-single-comment -func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment +func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, id int) (*IssueComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) @@ -90,58 +91,58 @@ func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueCom req.Header.Set("Accept", mediaTypeReactionsPreview) comment := new(IssueComment) - resp, err := s.client.Do(req, comment) + resp, err := s.client.Do(ctx, req, comment) if err != nil { return nil, resp, err } - return comment, resp, err + return comment, resp, nil } // CreateComment creates a new comment on the specified issue. // -// GitHub API docs: http://developer.github.com/v3/issues/comments/#create-a-comment -func (s *IssuesService) CreateComment(owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/comments/#create-a-comment +func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) req, err := s.client.NewRequest("POST", u, comment) if err != nil { return nil, nil, err } c := new(IssueComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // EditComment updates an issue comment. // -// GitHub API docs: http://developer.github.com/v3/issues/comments/#edit-a-comment -func (s *IssuesService) EditComment(owner string, repo string, id int, comment *IssueComment) (*IssueComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment +func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, id int, comment *IssueComment) (*IssueComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { return nil, nil, err } c := new(IssueComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // DeleteComment deletes an issue comment. // -// GitHub API docs: http://developer.github.com/v3/issues/comments/#delete-a-comment -func (s *IssuesService) DeleteComment(owner string, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment +func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/issues_events.go b/vendor/github.com/google/go-github/github/issues_events.go index 71cf61adb..2d5e19a1c 100644 --- a/vendor/github.com/google/go-github/github/issues_events.go +++ b/vendor/github.com/google/go-github/github/issues_events.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -18,7 +19,7 @@ type IssueEvent struct { // The User that generated this event. Actor *User `json:"actor,omitempty"` - // Event identifies the actual type of Event that occurred. Possible + // Event identifies the actual type of Event that occurred. Possible // values are: // // closed @@ -64,6 +65,7 @@ type IssueEvent struct { // Only present on certain events; see above. Assignee *User `json:"assignee,omitempty"` + Assigner *User `json:"assigner,omitempty"` CommitID *string `json:"commit_id,omitempty"` Milestone *Milestone `json:"milestone,omitempty"` Label *Label `json:"label,omitempty"` @@ -73,7 +75,7 @@ type IssueEvent struct { // ListIssueEvents lists events for the specified issue. // // GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-an-issue -func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *ListOptions) ([]*IssueEvent, *Response, error) { +func (s *IssuesService) ListIssueEvents(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%v/events", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -86,18 +88,18 @@ func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *Lis } var events []*IssueEvent - resp, err := s.client.Do(req, &events) + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return events, resp, err + return events, resp, nil } // ListRepositoryEvents lists events for the specified repository. // // GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository -func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { +func (s *IssuesService) ListRepositoryEvents(ctx context.Context, owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -110,18 +112,18 @@ func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOption } var events []*IssueEvent - resp, err := s.client.Do(req, &events) + resp, err := s.client.Do(ctx, req, &events) if err != nil { return nil, resp, err } - return events, resp, err + return events, resp, nil } // GetEvent returns the specified issue event. // // GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event -func (s *IssuesService) GetEvent(owner, repo string, id int) (*IssueEvent, *Response, error) { +func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int) (*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) @@ -130,12 +132,12 @@ func (s *IssuesService) GetEvent(owner, repo string, id int) (*IssueEvent, *Resp } event := new(IssueEvent) - resp, err := s.client.Do(req, event) + resp, err := s.client.Do(ctx, req, event) if err != nil { return nil, resp, err } - return event, resp, err + return event, resp, nil } // Rename contains details for 'renamed' events. diff --git a/vendor/github.com/google/go-github/github/issues_labels.go b/vendor/github.com/google/go-github/github/issues_labels.go index c65454783..a39001d66 100644 --- a/vendor/github.com/google/go-github/github/issues_labels.go +++ b/vendor/github.com/google/go-github/github/issues_labels.go @@ -5,10 +5,14 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Label represents a GitHub label on an Issue type Label struct { + ID *int `json:"id,omitempty"` URL *string `json:"url,omitempty"` Name *string `json:"name,omitempty"` Color *string `json:"color,omitempty"` @@ -20,8 +24,8 @@ func (l Label) String() string { // ListLabels lists all labels for a repository. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) ([]*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository +func (s *IssuesService) ListLabels(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -33,19 +37,19 @@ func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) return nil, nil, err } - labels := new([]*Label) - resp, err := s.client.Do(req, labels) + var labels []*Label + resp, err := s.client.Do(ctx, req, &labels) if err != nil { return nil, resp, err } - return *labels, resp, err + return labels, resp, nil } // GetLabel gets a single label. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#get-a-single-label -func (s *IssuesService) GetLabel(owner string, repo string, name string) (*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-a-single-label +func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string, name string) (*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -53,18 +57,18 @@ func (s *IssuesService) GetLabel(owner string, repo string, name string) (*Label } label := new(Label) - resp, err := s.client.Do(req, label) + resp, err := s.client.Do(ctx, req, label) if err != nil { return nil, resp, err } - return label, resp, err + return label, resp, nil } // CreateLabel creates a new label on the specified repository. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#create-a-label -func (s *IssuesService) CreateLabel(owner string, repo string, label *Label) (*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#create-a-label +func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo string, label *Label) (*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) req, err := s.client.NewRequest("POST", u, label) if err != nil { @@ -72,18 +76,18 @@ func (s *IssuesService) CreateLabel(owner string, repo string, label *Label) (*L } l := new(Label) - resp, err := s.client.Do(req, l) + resp, err := s.client.Do(ctx, req, l) if err != nil { return nil, resp, err } - return l, resp, err + return l, resp, nil } // EditLabel edits a label. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#update-a-label -func (s *IssuesService) EditLabel(owner string, repo string, name string, label *Label) (*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#update-a-label +func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string, name string, label *Label) (*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) req, err := s.client.NewRequest("PATCH", u, label) if err != nil { @@ -91,30 +95,30 @@ func (s *IssuesService) EditLabel(owner string, repo string, name string, label } l := new(Label) - resp, err := s.client.Do(req, l) + resp, err := s.client.Do(ctx, req, l) if err != nil { return nil, resp, err } - return l, resp, err + return l, resp, nil } // DeleteLabel deletes a label. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#delete-a-label -func (s *IssuesService) DeleteLabel(owner string, repo string, name string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#delete-a-label +func (s *IssuesService) DeleteLabel(ctx context.Context, owner string, repo string, name string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListLabelsByIssue lists all labels for an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue +func (s *IssuesService) ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -126,81 +130,81 @@ func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, return nil, nil, err } - labels := new([]*Label) - resp, err := s.client.Do(req, labels) + var labels []*Label + resp, err := s.client.Do(ctx, req, &labels) if err != nil { return nil, resp, err } - return *labels, resp, err + return labels, resp, nil } // AddLabelsToIssue adds labels to an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) AddLabelsToIssue(owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue +func (s *IssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) req, err := s.client.NewRequest("POST", u, labels) if err != nil { return nil, nil, err } - l := new([]*Label) - resp, err := s.client.Do(req, l) + var l []*Label + resp, err := s.client.Do(ctx, req, &l) if err != nil { return nil, resp, err } - return *l, resp, err + return l, resp, nil } // RemoveLabelForIssue removes a label for an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue -func (s *IssuesService) RemoveLabelForIssue(owner string, repo string, number int, label string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue +func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels/%v", owner, repo, number, label) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ReplaceLabelsForIssue replaces all labels for an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue -func (s *IssuesService) ReplaceLabelsForIssue(owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue +func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) req, err := s.client.NewRequest("PUT", u, labels) if err != nil { return nil, nil, err } - l := new([]*Label) - resp, err := s.client.Do(req, l) + var l []*Label + resp, err := s.client.Do(ctx, req, &l) if err != nil { return nil, resp, err } - return *l, resp, err + return l, resp, nil } // RemoveLabelsForIssue removes all labels for an issue. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue -func (s *IssuesService) RemoveLabelsForIssue(owner string, repo string, number int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue +func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string, repo string, number int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListLabelsForMilestone lists labels for every issue in a milestone. // -// GitHub API docs: http://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone -func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone +func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones/%d/labels", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -212,11 +216,11 @@ func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number return nil, nil, err } - labels := new([]*Label) - resp, err := s.client.Do(req, labels) + var labels []*Label + resp, err := s.client.Do(ctx, req, &labels) if err != nil { return nil, resp, err } - return *labels, resp, err + return labels, resp, nil } diff --git a/vendor/github.com/google/go-github/github/issues_milestones.go b/vendor/github.com/google/go-github/github/issues_milestones.go index b7621acf2..e6e882d14 100644 --- a/vendor/github.com/google/go-github/github/issues_milestones.go +++ b/vendor/github.com/google/go-github/github/issues_milestones.go @@ -6,11 +6,12 @@ package github import ( + "context" "fmt" "time" ) -// Milestone represents a Github repository milestone. +// Milestone represents a GitHub repository milestone. type Milestone struct { URL *string `json:"url,omitempty"` HTMLURL *string `json:"html_url,omitempty"` @@ -37,11 +38,11 @@ func (m Milestone) String() string { // IssuesService.ListMilestones method. type MilestoneListOptions struct { // State filters milestones based on their state. Possible values are: - // open, closed. Default is "open". + // open, closed, all. Default is "open". State string `url:"state,omitempty"` - // Sort specifies how to sort milestones. Possible values are: due_date, completeness. - // Default value is "due_date". + // Sort specifies how to sort milestones. Possible values are: due_on, completeness. + // Default value is "due_on". Sort string `url:"sort,omitempty"` // Direction in which to sort milestones. Possible values are: asc, desc. @@ -54,7 +55,7 @@ type MilestoneListOptions struct { // ListMilestones lists all milestones for a repository. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository -func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]*Milestone, *Response, error) { +func (s *IssuesService) ListMilestones(ctx context.Context, owner string, repo string, opt *MilestoneListOptions) ([]*Milestone, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -66,19 +67,19 @@ func (s *IssuesService) ListMilestones(owner string, repo string, opt *Milestone return nil, nil, err } - milestones := new([]*Milestone) - resp, err := s.client.Do(req, milestones) + var milestones []*Milestone + resp, err := s.client.Do(ctx, req, &milestones) if err != nil { return nil, resp, err } - return *milestones, resp, err + return milestones, resp, nil } // GetMilestone gets a single milestone. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone -func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Milestone, *Response, error) { +func (s *IssuesService) GetMilestone(ctx context.Context, owner string, repo string, number int) (*Milestone, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -86,18 +87,18 @@ func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Mi } milestone := new(Milestone) - resp, err := s.client.Do(req, milestone) + resp, err := s.client.Do(ctx, req, milestone) if err != nil { return nil, resp, err } - return milestone, resp, err + return milestone, resp, nil } // CreateMilestone creates a new milestone on the specified repository. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone -func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { +func (s *IssuesService) CreateMilestone(ctx context.Context, owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) req, err := s.client.NewRequest("POST", u, milestone) if err != nil { @@ -105,18 +106,18 @@ func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Mi } m := new(Milestone) - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } - return m, resp, err + return m, resp, nil } // EditMilestone edits a milestone. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone -func (s *IssuesService) EditMilestone(owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { +func (s *IssuesService) EditMilestone(ctx context.Context, owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) req, err := s.client.NewRequest("PATCH", u, milestone) if err != nil { @@ -124,23 +125,23 @@ func (s *IssuesService) EditMilestone(owner string, repo string, number int, mil } m := new(Milestone) - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } - return m, resp, err + return m, resp, nil } // DeleteMilestone deletes a milestone. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone -func (s *IssuesService) DeleteMilestone(owner string, repo string, number int) (*Response, error) { +func (s *IssuesService) DeleteMilestone(ctx context.Context, owner string, repo string, number int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/issues_timeline.go b/vendor/github.com/google/go-github/github/issues_timeline.go index d20eef8f0..bc0b10899 100644 --- a/vendor/github.com/google/go-github/github/issues_timeline.go +++ b/vendor/github.com/google/go-github/github/issues_timeline.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -127,7 +128,7 @@ type Source struct { // ListIssueTimeline lists events for the specified issue. // // GitHub API docs: https://developer.github.com/v3/issues/timeline/#list-events-for-an-issue -func (s *IssuesService) ListIssueTimeline(owner, repo string, number int, opt *ListOptions) ([]*Timeline, *Response, error) { +func (s *IssuesService) ListIssueTimeline(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Timeline, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%v/timeline", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -143,6 +144,6 @@ func (s *IssuesService) ListIssueTimeline(owner, repo string, number int, opt *L req.Header.Set("Accept", mediaTypeTimelinePreview) var events []*Timeline - resp, err := s.client.Do(req, &events) + resp, err := s.client.Do(ctx, req, &events) return events, resp, err } diff --git a/vendor/github.com/google/go-github/github/licenses.go b/vendor/github.com/google/go-github/github/licenses.go index 0b5e8b382..e9cd1777a 100644 --- a/vendor/github.com/google/go-github/github/licenses.go +++ b/vendor/github.com/google/go-github/github/licenses.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // LicensesService handles communication with the license related // methods of the GitHub API. @@ -58,7 +61,7 @@ func (l License) String() string { // List popular open source licenses. // // GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses -func (s *LicensesService) List() ([]*License, *Response, error) { +func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, error) { req, err := s.client.NewRequest("GET", "licenses", nil) if err != nil { return nil, nil, err @@ -67,19 +70,19 @@ func (s *LicensesService) List() ([]*License, *Response, error) { // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - licenses := new([]*License) - resp, err := s.client.Do(req, licenses) + var licenses []*License + resp, err := s.client.Do(ctx, req, &licenses) if err != nil { return nil, resp, err } - return *licenses, resp, err + return licenses, resp, nil } // Get extended metadata for one license. // // GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license -func (s *LicensesService) Get(licenseName string) (*License, *Response, error) { +func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License, *Response, error) { u := fmt.Sprintf("licenses/%s", licenseName) req, err := s.client.NewRequest("GET", u, nil) @@ -91,10 +94,10 @@ func (s *LicensesService) Get(licenseName string) (*License, *Response, error) { req.Header.Set("Accept", mediaTypeLicensesPreview) license := new(License) - resp, err := s.client.Do(req, license) + resp, err := s.client.Do(ctx, req, license) if err != nil { return nil, resp, err } - return license, resp, err + return license, resp, nil } diff --git a/vendor/github.com/google/go-github/github/messages.go b/vendor/github.com/google/go-github/github/messages.go index 5e167eed3..a7ec65fba 100644 --- a/vendor/github.com/google/go-github/github/messages.go +++ b/vendor/github.com/google/go-github/github/messages.go @@ -4,7 +4,7 @@ // license that can be found in the LICENSE file. // This file provides functions for validating payloads from GitHub Webhooks. -// GitHub docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github +// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github package github @@ -31,7 +31,7 @@ const ( sha512Prefix = "sha512" // signatureHeader is the GitHub header key used to pass the HMAC hexdigest. signatureHeader = "X-Hub-Signature" - // eventTypeHeader is the Github header key used to pass the event type. + // eventTypeHeader is the GitHub header key used to pass the event type. eventTypeHeader = "X-Github-Event" ) @@ -53,8 +53,12 @@ var ( "member": "MemberEvent", "membership": "MembershipEvent", "milestone": "MilestoneEvent", + "organization": "OrganizationEvent", "page_build": "PageBuildEvent", "ping": "PingEvent", + "project": "ProjectEvent", + "project_card": "ProjectCardEvent", + "project_column": "ProjectColumnEvent", "public": "PublicEvent", "pull_request_review": "PullRequestReviewEvent", "pull_request_review_comment": "PullRequestReviewCommentEvent", @@ -142,7 +146,7 @@ func ValidatePayload(r *http.Request, secretKey []byte) (payload []byte, err err // payload is the JSON payload sent by GitHub Webhooks. // secretKey is the GitHub Webhook secret message. // -// GitHub docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github +// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github func validateSignature(signature string, payload, secretKey []byte) error { messageMAC, hashFunc, err := messageMAC(signature) if err != nil { @@ -161,7 +165,7 @@ func WebHookType(r *http.Request) string { // ParseWebHook parses the event payload. For recognized event types, a // value of the corresponding struct type will be returned (as returned -// by Event.Payload()). An error will be returned for unrecognized event +// by Event.ParsePayload()). An error will be returned for unrecognized event // types. // // Example usage: @@ -190,5 +194,5 @@ func ParseWebHook(messageType string, payload []byte) (interface{}, error) { Type: &eventType, RawPayload: (*json.RawMessage)(&payload), } - return event.Payload(), nil + return event.ParsePayload() } diff --git a/vendor/github.com/google/go-github/github/migrations.go b/vendor/github.com/google/go-github/github/migrations.go index a7890b0a3..6793269cd 100644 --- a/vendor/github.com/google/go-github/github/migrations.go +++ b/vendor/github.com/google/go-github/github/migrations.go @@ -6,6 +6,7 @@ package github import ( + "context" "errors" "fmt" "net/http" @@ -74,7 +75,7 @@ type startMigration struct { // repos is a slice of repository names to migrate. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#start-a-migration -func (s *MigrationService) StartMigration(org string, repos []string, opt *MigrationOptions) (*Migration, *Response, error) { +func (s *MigrationService) StartMigration(ctx context.Context, org string, repos []string, opt *MigrationOptions) (*Migration, *Response, error) { u := fmt.Sprintf("orgs/%v/migrations", org) body := &startMigration{Repositories: repos} @@ -92,7 +93,7 @@ func (s *MigrationService) StartMigration(org string, repos []string, opt *Migra req.Header.Set("Accept", mediaTypeMigrationsPreview) m := &Migration{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -103,7 +104,7 @@ func (s *MigrationService) StartMigration(org string, repos []string, opt *Migra // ListMigrations lists the most recent migrations. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations -func (s *MigrationService) ListMigrations(org string) ([]*Migration, *Response, error) { +func (s *MigrationService) ListMigrations(ctx context.Context, org string) ([]*Migration, *Response, error) { u := fmt.Sprintf("orgs/%v/migrations", org) req, err := s.client.NewRequest("GET", u, nil) @@ -115,7 +116,7 @@ func (s *MigrationService) ListMigrations(org string) ([]*Migration, *Response, req.Header.Set("Accept", mediaTypeMigrationsPreview) var m []*Migration - resp, err := s.client.Do(req, &m) + resp, err := s.client.Do(ctx, req, &m) if err != nil { return nil, resp, err } @@ -127,7 +128,7 @@ func (s *MigrationService) ListMigrations(org string) ([]*Migration, *Response, // id is the migration ID. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration -func (s *MigrationService) MigrationStatus(org string, id int) (*Migration, *Response, error) { +func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id int) (*Migration, *Response, error) { u := fmt.Sprintf("orgs/%v/migrations/%v", org, id) req, err := s.client.NewRequest("GET", u, nil) @@ -139,7 +140,7 @@ func (s *MigrationService) MigrationStatus(org string, id int) (*Migration, *Res req.Header.Set("Accept", mediaTypeMigrationsPreview) m := &Migration{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -151,7 +152,7 @@ func (s *MigrationService) MigrationStatus(org string, id int) (*Migration, *Res // id is the migration ID. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#download-a-migration-archive -func (s *MigrationService) MigrationArchiveURL(org string, id int) (url string, err error) { +func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string, id int) (url string, err error) { u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) req, err := s.client.NewRequest("GET", u, nil) @@ -174,7 +175,7 @@ func (s *MigrationService) MigrationArchiveURL(org string, id int) (url string, } defer func() { s.client.client.CheckRedirect = saveRedirect }() - _, err = s.client.Do(req, nil) // expect error from disable redirect + _, err = s.client.Do(ctx, req, nil) // expect error from disable redirect if err == nil { return "", errors.New("expected redirect, none provided") } @@ -188,7 +189,7 @@ func (s *MigrationService) MigrationArchiveURL(org string, id int) (url string, // id is the migration ID. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive -func (s *MigrationService) DeleteMigration(org string, id int) (*Response, error) { +func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id int) (*Response, error) { u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) req, err := s.client.NewRequest("DELETE", u, nil) @@ -199,7 +200,7 @@ func (s *MigrationService) DeleteMigration(org string, id int) (*Response, error // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeMigrationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // UnlockRepo unlocks a repository that was locked for migration. @@ -208,7 +209,7 @@ func (s *MigrationService) DeleteMigration(org string, id int) (*Response, error // is complete and you no longer need the source data. // // GitHub API docs: https://developer.github.com/v3/migration/migrations/#unlock-a-repository -func (s *MigrationService) UnlockRepo(org string, id int, repo string) (*Response, error) { +func (s *MigrationService) UnlockRepo(ctx context.Context, org string, id int, repo string) (*Response, error) { u := fmt.Sprintf("orgs/%v/migrations/%v/repos/%v/lock", org, id, repo) req, err := s.client.NewRequest("DELETE", u, nil) @@ -219,5 +220,5 @@ func (s *MigrationService) UnlockRepo(org string, id int, repo string) (*Respons // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeMigrationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/migrations_source_import.go b/vendor/github.com/google/go-github/github/migrations_source_import.go index 44505fa91..aa45a5a36 100644 --- a/vendor/github.com/google/go-github/github/migrations_source_import.go +++ b/vendor/github.com/google/go-github/github/migrations_source_import.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Import represents a repository import request. type Import struct { @@ -39,7 +42,7 @@ type Import struct { // repository. To see a list of these files, call LargeFiles. LargeFilesCount *int `json:"large_files_count,omitempty"` - // Identifies the current status of an import. An import that does not + // Identifies the current status of an import. An import that does not // have errors will progress through these steps: // // detecting - the "detection" step of the import is in progress @@ -101,7 +104,7 @@ type Import struct { HumanName *string `json:"human_name,omitempty"` // When the importer finds several projects or repositories at the - // provided URLs, this will identify the available choices. Call + // provided URLs, this will identify the available choices. Call // UpdateImport with the selected Import value. ProjectChoices []Import `json:"project_choices,omitempty"` } @@ -144,7 +147,7 @@ func (f LargeFile) String() string { // StartImport initiates a repository import. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#start-an-import -func (s *MigrationService) StartImport(owner, repo string, in *Import) (*Import, *Response, error) { +func (s *MigrationService) StartImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import", owner, repo) req, err := s.client.NewRequest("PUT", u, in) if err != nil { @@ -155,18 +158,18 @@ func (s *MigrationService) StartImport(owner, repo string, in *Import) (*Import, req.Header.Set("Accept", mediaTypeImportPreview) out := new(Import) - resp, err := s.client.Do(req, out) + resp, err := s.client.Do(ctx, req, out) if err != nil { return nil, resp, err } - return out, resp, err + return out, resp, nil } // ImportProgress queries for the status and progress of an ongoing repository import. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-import-progress -func (s *MigrationService) ImportProgress(owner, repo string) (*Import, *Response, error) { +func (s *MigrationService) ImportProgress(ctx context.Context, owner, repo string) (*Import, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -177,18 +180,18 @@ func (s *MigrationService) ImportProgress(owner, repo string) (*Import, *Respons req.Header.Set("Accept", mediaTypeImportPreview) out := new(Import) - resp, err := s.client.Do(req, out) + resp, err := s.client.Do(ctx, req, out) if err != nil { return nil, resp, err } - return out, resp, err + return out, resp, nil } // UpdateImport initiates a repository import. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#update-existing-import -func (s *MigrationService) UpdateImport(owner, repo string, in *Import) (*Import, *Response, error) { +func (s *MigrationService) UpdateImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import", owner, repo) req, err := s.client.NewRequest("PATCH", u, in) if err != nil { @@ -199,12 +202,12 @@ func (s *MigrationService) UpdateImport(owner, repo string, in *Import) (*Import req.Header.Set("Accept", mediaTypeImportPreview) out := new(Import) - resp, err := s.client.Do(req, out) + resp, err := s.client.Do(ctx, req, out) if err != nil { return nil, resp, err } - return out, resp, err + return out, resp, nil } // CommitAuthors gets the authors mapped from the original repository. @@ -220,7 +223,7 @@ func (s *MigrationService) UpdateImport(owner, repo string, in *Import) (*Import // information. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors -func (s *MigrationService) CommitAuthors(owner, repo string) ([]*SourceImportAuthor, *Response, error) { +func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string) ([]*SourceImportAuthor, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -230,13 +233,13 @@ func (s *MigrationService) CommitAuthors(owner, repo string) ([]*SourceImportAut // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeImportPreview) - authors := new([]*SourceImportAuthor) - resp, err := s.client.Do(req, authors) + var authors []*SourceImportAuthor + resp, err := s.client.Do(ctx, req, &authors) if err != nil { return nil, resp, err } - return *authors, resp, err + return authors, resp, nil } // MapCommitAuthor updates an author's identity for the import. Your @@ -244,7 +247,7 @@ func (s *MigrationService) CommitAuthors(owner, repo string) ([]*SourceImportAut // commits to the repository. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#map-a-commit-author -func (s *MigrationService) MapCommitAuthor(owner, repo string, id int, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) { +func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, author) if err != nil { @@ -255,20 +258,20 @@ func (s *MigrationService) MapCommitAuthor(owner, repo string, id int, author *S req.Header.Set("Accept", mediaTypeImportPreview) out := new(SourceImportAuthor) - resp, err := s.client.Do(req, out) + resp, err := s.client.Do(ctx, req, out) if err != nil { return nil, resp, err } - return out, resp, err + return out, resp, nil } // SetLFSPreference sets whether imported repositories should use Git LFS for -// files larger than 100MB. Only the UseLFS field on the provided Import is +// files larger than 100MB. Only the UseLFS field on the provided Import is // used. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#set-git-lfs-preference -func (s *MigrationService) SetLFSPreference(owner, repo string, in *Import) (*Import, *Response, error) { +func (s *MigrationService) SetLFSPreference(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo) req, err := s.client.NewRequest("PATCH", u, in) if err != nil { @@ -279,18 +282,18 @@ func (s *MigrationService) SetLFSPreference(owner, repo string, in *Import) (*Im req.Header.Set("Accept", mediaTypeImportPreview) out := new(Import) - resp, err := s.client.Do(req, out) + resp, err := s.client.Do(ctx, req, out) if err != nil { return nil, resp, err } - return out, resp, err + return out, resp, nil } // LargeFiles lists files larger than 100MB found during the import. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files -func (s *MigrationService) LargeFiles(owner, repo string) ([]*LargeFile, *Response, error) { +func (s *MigrationService) LargeFiles(ctx context.Context, owner, repo string) ([]*LargeFile, *Response, error) { u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -300,19 +303,19 @@ func (s *MigrationService) LargeFiles(owner, repo string) ([]*LargeFile, *Respon // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeImportPreview) - files := new([]*LargeFile) - resp, err := s.client.Do(req, files) + var files []*LargeFile + resp, err := s.client.Do(ctx, req, &files) if err != nil { return nil, resp, err } - return *files, resp, err + return files, resp, nil } // CancelImport stops an import for a repository. // // GitHub API docs: https://developer.github.com/v3/migration/source_imports/#cancel-an-import -func (s *MigrationService) CancelImport(owner, repo string) (*Response, error) { +func (s *MigrationService) CancelImport(ctx context.Context, owner, repo string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/import", owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -322,5 +325,5 @@ func (s *MigrationService) CancelImport(owner, repo string) (*Response, error) { // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeImportPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/misc.go b/vendor/github.com/google/go-github/github/misc.go index 8576a4cda..42d0d3033 100644 --- a/vendor/github.com/google/go-github/github/misc.go +++ b/vendor/github.com/google/go-github/github/misc.go @@ -7,13 +7,14 @@ package github import ( "bytes" + "context" "fmt" "net/url" ) // MarkdownOptions specifies optional parameters to the Markdown method. type MarkdownOptions struct { - // Mode identifies the rendering mode. Possible values are: + // Mode identifies the rendering mode. Possible values are: // markdown - render a document as plain Markdown, just like // README files are rendered. // @@ -25,7 +26,7 @@ type MarkdownOptions struct { // Default is "markdown". Mode string - // Context identifies the repository context. Only taken into account + // Context identifies the repository context. Only taken into account // when rendering as "gfm". Context string } @@ -39,7 +40,7 @@ type markdownRequest struct { // Markdown renders an arbitrary Markdown document. // // GitHub API docs: https://developer.github.com/v3/markdown/ -func (c *Client) Markdown(text string, opt *MarkdownOptions) (string, *Response, error) { +func (c *Client) Markdown(ctx context.Context, text string, opt *MarkdownOptions) (string, *Response, error) { request := &markdownRequest{Text: String(text)} if opt != nil { if opt.Mode != "" { @@ -56,7 +57,7 @@ func (c *Client) Markdown(text string, opt *MarkdownOptions) (string, *Response, } buf := new(bytes.Buffer) - resp, err := c.Do(req, buf) + resp, err := c.Do(ctx, req, buf) if err != nil { return "", resp, err } @@ -67,14 +68,14 @@ func (c *Client) Markdown(text string, opt *MarkdownOptions) (string, *Response, // ListEmojis returns the emojis available to use on GitHub. // // GitHub API docs: https://developer.github.com/v3/emojis/ -func (c *Client) ListEmojis() (map[string]string, *Response, error) { +func (c *Client) ListEmojis(ctx context.Context) (map[string]string, *Response, error) { req, err := c.NewRequest("GET", "emojis", nil) if err != nil { return nil, nil, err } var emoji map[string]string - resp, err := c.Do(req, &emoji) + resp, err := c.Do(ctx, req, &emoji) if err != nil { return nil, resp, err } @@ -109,14 +110,14 @@ type APIMeta struct { // endpoint provides information about that installation. // // GitHub API docs: https://developer.github.com/v3/meta/ -func (c *Client) APIMeta() (*APIMeta, *Response, error) { +func (c *Client) APIMeta(ctx context.Context) (*APIMeta, *Response, error) { req, err := c.NewRequest("GET", "meta", nil) if err != nil { return nil, nil, err } meta := new(APIMeta) - resp, err := c.Do(req, meta) + resp, err := c.Do(ctx, req, meta) if err != nil { return nil, resp, err } @@ -125,8 +126,8 @@ func (c *Client) APIMeta() (*APIMeta, *Response, error) { } // Octocat returns an ASCII art octocat with the specified message in a speech -// bubble. If message is empty, a random zen phrase is used. -func (c *Client) Octocat(message string) (string, *Response, error) { +// bubble. If message is empty, a random zen phrase is used. +func (c *Client) Octocat(ctx context.Context, message string) (string, *Response, error) { u := "octocat" if message != "" { u = fmt.Sprintf("%s?s=%s", u, url.QueryEscape(message)) @@ -138,7 +139,7 @@ func (c *Client) Octocat(message string) (string, *Response, error) { } buf := new(bytes.Buffer) - resp, err := c.Do(req, buf) + resp, err := c.Do(ctx, req, buf) if err != nil { return "", resp, err } @@ -149,14 +150,14 @@ func (c *Client) Octocat(message string) (string, *Response, error) { // Zen returns a random line from The Zen of GitHub. // // see also: http://warpspire.com/posts/taste/ -func (c *Client) Zen() (string, *Response, error) { +func (c *Client) Zen(ctx context.Context) (string, *Response, error) { req, err := c.NewRequest("GET", "zen", nil) if err != nil { return "", nil, err } buf := new(bytes.Buffer) - resp, err := c.Do(req, buf) + resp, err := c.Do(ctx, req, buf) if err != nil { return "", resp, err } @@ -180,18 +181,18 @@ func (s *ServiceHook) String() string { // ListServiceHooks lists all of the available service hooks. // // GitHub API docs: https://developer.github.com/webhooks/#services -func (c *Client) ListServiceHooks() ([]*ServiceHook, *Response, error) { +func (c *Client) ListServiceHooks(ctx context.Context) ([]*ServiceHook, *Response, error) { u := "hooks" req, err := c.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - hooks := new([]*ServiceHook) - resp, err := c.Do(req, hooks) + var hooks []*ServiceHook + resp, err := c.Do(ctx, req, &hooks) if err != nil { return nil, resp, err } - return *hooks, resp, err + return hooks, resp, nil } diff --git a/vendor/github.com/google/go-github/github/orgs.go b/vendor/github.com/google/go-github/github/orgs.go index d137e3e82..8b126f00f 100644 --- a/vendor/github.com/google/go-github/github/orgs.go +++ b/vendor/github.com/google/go-github/github/orgs.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -13,7 +14,7 @@ import ( // OrganizationsService provides access to the organization related functions // in the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/orgs/ +// GitHub API docs: https://developer.github.com/v3/orgs/ type OrganizationsService service // Organization represents a GitHub organization account. @@ -57,7 +58,7 @@ func (o Organization) String() string { return Stringify(o) } -// Plan represents the payment plan for an account. See plans at https://github.com/plans. +// Plan represents the payment plan for an account. See plans at https://github.com/plans. type Plan struct { Name *string `json:"name,omitempty"` Space *int `json:"space,omitempty"` @@ -85,7 +86,7 @@ type OrganizationsListOptions struct { // as the opts.Since parameter for the next call. // // GitHub API docs: https://developer.github.com/v3/orgs/#list-all-organizations -func (s *OrganizationsService) ListAll(opt *OrganizationsListOptions) ([]*Organization, *Response, error) { +func (s *OrganizationsService) ListAll(ctx context.Context, opt *OrganizationsListOptions) ([]*Organization, *Response, error) { u, err := addOptions("organizations", opt) if err != nil { return nil, nil, err @@ -97,18 +98,18 @@ func (s *OrganizationsService) ListAll(opt *OrganizationsListOptions) ([]*Organi } orgs := []*Organization{} - resp, err := s.client.Do(req, &orgs) + resp, err := s.client.Do(ctx, req, &orgs) if err != nil { return nil, resp, err } - return orgs, resp, err + return orgs, resp, nil } -// List the organizations for a user. Passing the empty string will list +// List the organizations for a user. Passing the empty string will list // organizations for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/orgs/#list-user-organizations -func (s *OrganizationsService) List(user string, opt *ListOptions) ([]*Organization, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/#list-user-organizations +func (s *OrganizationsService) List(ctx context.Context, user string, opt *ListOptions) ([]*Organization, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/orgs", user) @@ -125,19 +126,19 @@ func (s *OrganizationsService) List(user string, opt *ListOptions) ([]*Organizat return nil, nil, err } - orgs := new([]*Organization) - resp, err := s.client.Do(req, orgs) + var orgs []*Organization + resp, err := s.client.Do(ctx, req, &orgs) if err != nil { return nil, resp, err } - return *orgs, resp, err + return orgs, resp, nil } // Get fetches an organization by name. // -// GitHub API docs: http://developer.github.com/v3/orgs/#get-an-organization -func (s *OrganizationsService) Get(org string) (*Organization, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/#get-an-organization +func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organization, *Response, error) { u := fmt.Sprintf("orgs/%v", org) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -145,18 +146,18 @@ func (s *OrganizationsService) Get(org string) (*Organization, *Response, error) } organization := new(Organization) - resp, err := s.client.Do(req, organization) + resp, err := s.client.Do(ctx, req, organization) if err != nil { return nil, resp, err } - return organization, resp, err + return organization, resp, nil } // Edit an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/#edit-an-organization -func (s *OrganizationsService) Edit(name string, org *Organization) (*Organization, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/#edit-an-organization +func (s *OrganizationsService) Edit(ctx context.Context, name string, org *Organization) (*Organization, *Response, error) { u := fmt.Sprintf("orgs/%v", name) req, err := s.client.NewRequest("PATCH", u, org) if err != nil { @@ -164,10 +165,10 @@ func (s *OrganizationsService) Edit(name string, org *Organization) (*Organizati } o := new(Organization) - resp, err := s.client.Do(req, o) + resp, err := s.client.Do(ctx, req, o) if err != nil { return nil, resp, err } - return o, resp, err + return o, resp, nil } diff --git a/vendor/github.com/google/go-github/github/orgs_hooks.go b/vendor/github.com/google/go-github/github/orgs_hooks.go index 95b832290..4fc692e0f 100644 --- a/vendor/github.com/google/go-github/github/orgs_hooks.go +++ b/vendor/github.com/google/go-github/github/orgs_hooks.go @@ -5,12 +5,15 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // ListHooks lists all Hooks for the specified organization. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#list-hooks -func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]*Hook, *Response, error) { +func (s *OrganizationsService) ListHooks(ctx context.Context, org string, opt *ListOptions) ([]*Hook, *Response, error) { u := fmt.Sprintf("orgs/%v/hooks", org) u, err := addOptions(u, opt) if err != nil { @@ -22,26 +25,26 @@ func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]*Hook, return nil, nil, err } - hooks := new([]*Hook) - resp, err := s.client.Do(req, hooks) + var hooks []*Hook + resp, err := s.client.Do(ctx, req, &hooks) if err != nil { return nil, resp, err } - return *hooks, resp, err + return hooks, resp, nil } // GetHook returns a single specified Hook. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook -func (s *OrganizationsService) GetHook(org string, id int) (*Hook, *Response, error) { +func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int) (*Hook, *Response, error) { u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } hook := new(Hook) - resp, err := s.client.Do(req, hook) + resp, err := s.client.Do(ctx, req, hook) return hook, resp, err } @@ -49,7 +52,7 @@ func (s *OrganizationsService) GetHook(org string, id int) (*Hook, *Response, er // Name and Config are required fields. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook -func (s *OrganizationsService) CreateHook(org string, hook *Hook) (*Hook, *Response, error) { +func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) { u := fmt.Sprintf("orgs/%v/hooks", org) req, err := s.client.NewRequest("POST", u, hook) if err != nil { @@ -57,48 +60,48 @@ func (s *OrganizationsService) CreateHook(org string, hook *Hook) (*Hook, *Respo } h := new(Hook) - resp, err := s.client.Do(req, h) + resp, err := s.client.Do(ctx, req, h) if err != nil { return nil, resp, err } - return h, resp, err + return h, resp, nil } // EditHook updates a specified Hook. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook -func (s *OrganizationsService) EditHook(org string, id int, hook *Hook) (*Hook, *Response, error) { +func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int, hook *Hook) (*Hook, *Response, error) { u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) req, err := s.client.NewRequest("PATCH", u, hook) if err != nil { return nil, nil, err } h := new(Hook) - resp, err := s.client.Do(req, h) + resp, err := s.client.Do(ctx, req, h) return h, resp, err } // PingHook triggers a 'ping' event to be sent to the Hook. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook -func (s *OrganizationsService) PingHook(org string, id int) (*Response, error) { +func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int) (*Response, error) { u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id) req, err := s.client.NewRequest("POST", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // DeleteHook deletes a specified Hook. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook -func (s *OrganizationsService) DeleteHook(org string, id int) (*Response, error) { +func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int) (*Response, error) { u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/orgs_members.go b/vendor/github.com/google/go-github/github/orgs_members.go index 80454ada0..f1209c7c4 100644 --- a/vendor/github.com/google/go-github/github/orgs_members.go +++ b/vendor/github.com/google/go-github/github/orgs_members.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Membership represents the status of a user's membership in an organization or team. type Membership struct { @@ -48,8 +51,8 @@ type ListMembersOptions struct { // organization), list only publicly visible members. PublicOnly bool `url:"-"` - // Filter members returned in the list. Possible values are: - // 2fa_disabled, all. Default is "all". + // Filter members returned in the list. Possible values are: + // 2fa_disabled, all. Default is "all". Filter string `url:"filter,omitempty"` // Role filters members returned by their role in the organization. @@ -64,12 +67,12 @@ type ListMembersOptions struct { ListOptions } -// ListMembers lists the members for an organization. If the authenticated +// ListMembers lists the members for an organization. If the authenticated // user is an owner of the organization, this will return both concealed and // public members, otherwise it will only return public members. // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#members-list -func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#members-list +func (s *OrganizationsService) ListMembers(ctx context.Context, org string, opt *ListMembersOptions) ([]*User, *Response, error) { var u string if opt != nil && opt.PublicOnly { u = fmt.Sprintf("orgs/%v/public_members", org) @@ -86,83 +89,83 @@ func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) return nil, nil, err } - members := new([]*User) - resp, err := s.client.Do(req, members) + var members []*User + resp, err := s.client.Do(ctx, req, &members) if err != nil { return nil, resp, err } - return *members, resp, err + return members, resp, nil } // IsMember checks if a user is a member of an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#check-membership -func (s *OrganizationsService) IsMember(org, user string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-membership +func (s *OrganizationsService) IsMember(ctx context.Context, org, user string) (bool, *Response, error) { u := fmt.Sprintf("orgs/%v/members/%v", org, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) member, err := parseBoolResponse(err) return member, resp, err } // IsPublicMember checks if a user is a public member of an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#check-public-membership -func (s *OrganizationsService) IsPublicMember(org, user string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-public-membership +func (s *OrganizationsService) IsPublicMember(ctx context.Context, org, user string) (bool, *Response, error) { u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) member, err := parseBoolResponse(err) return member, resp, err } // RemoveMember removes a user from all teams of an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#remove-a-member -func (s *OrganizationsService) RemoveMember(org, user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-a-member +func (s *OrganizationsService) RemoveMember(ctx context.Context, org, user string) (*Response, error) { u := fmt.Sprintf("orgs/%v/members/%v", org, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // PublicizeMembership publicizes a user's membership in an organization. (A // user cannot publicize the membership for another user.) // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#publicize-a-users-membership -func (s *OrganizationsService) PublicizeMembership(org, user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#publicize-a-users-membership +func (s *OrganizationsService) PublicizeMembership(ctx context.Context, org, user string) (*Response, error) { u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) req, err := s.client.NewRequest("PUT", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ConcealMembership conceals a user's membership in an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/members/#conceal-a-users-membership -func (s *OrganizationsService) ConcealMembership(org, user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/members/#conceal-a-users-membership +func (s *OrganizationsService) ConcealMembership(ctx context.Context, org, user string) (*Response, error) { u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListOrgMembershipsOptions specifies optional parameters to the @@ -178,7 +181,7 @@ type ListOrgMembershipsOptions struct { // ListOrgMemberships lists the organization memberships for the authenticated user. // // GitHub API docs: https://developer.github.com/v3/orgs/members/#list-your-organization-memberships -func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { +func (s *OrganizationsService) ListOrgMemberships(ctx context.Context, opt *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { u := "user/memberships/orgs" u, err := addOptions(u, opt) if err != nil { @@ -191,21 +194,22 @@ func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions } var memberships []*Membership - resp, err := s.client.Do(req, &memberships) + resp, err := s.client.Do(ctx, req, &memberships) if err != nil { return nil, resp, err } - return memberships, resp, err + return memberships, resp, nil } // GetOrgMembership gets the membership for a user in a specified organization. // Passing an empty string for user will get the membership for the // authenticated user. // -// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-organization-membership -// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-your-organization-membership -func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership, *Response, error) { +// GitHub API docs: +// https://developer.github.com/v3/orgs/members/#get-organization-membership +// https://developer.github.com/v3/orgs/members/#get-your-organization-membership +func (s *OrganizationsService) GetOrgMembership(ctx context.Context, user, org string) (*Membership, *Response, error) { var u string if user != "" { u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) @@ -219,12 +223,12 @@ func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership, } membership := new(Membership) - resp, err := s.client.Do(req, membership) + resp, err := s.client.Do(ctx, req, membership) if err != nil { return nil, resp, err } - return membership, resp, err + return membership, resp, nil } // EditOrgMembership edits the membership for user in specified organization. @@ -233,7 +237,7 @@ func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership, // // GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership // GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership -func (s *OrganizationsService) EditOrgMembership(user, org string, membership *Membership) (*Membership, *Response, error) { +func (s *OrganizationsService) EditOrgMembership(ctx context.Context, user, org string, membership *Membership) (*Membership, *Response, error) { var u, method string if user != "" { u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) @@ -249,24 +253,47 @@ func (s *OrganizationsService) EditOrgMembership(user, org string, membership *M } m := new(Membership) - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } - return m, resp, err + return m, resp, nil } -// RemoveOrgMembership removes user from the specified organization. If the +// RemoveOrgMembership removes user from the specified organization. If the // user has been invited to the organization, this will cancel their invitation. // // GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership -func (s *OrganizationsService) RemoveOrgMembership(user, org string) (*Response, error) { +func (s *OrganizationsService) RemoveOrgMembership(ctx context.Context, user, org string) (*Response, error) { u := fmt.Sprintf("orgs/%v/memberships/%v", org, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) +} + +// ListPendingOrgInvitations returns a list of pending invitations. +// +// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations +func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org int, opt *ListOptions) ([]*Invitation, *Response, error) { + u := fmt.Sprintf("orgs/%v/invitations", org) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var pendingInvitations []*Invitation + resp, err := s.client.Do(ctx, req, &pendingInvitations) + if err != nil { + return nil, resp, err + } + return pendingInvitations, resp, nil } diff --git a/vendor/github.com/google/go-github/github/orgs_outside_collaborators.go b/vendor/github.com/google/go-github/github/orgs_outside_collaborators.go new file mode 100644 index 000000000..e34f8653b --- /dev/null +++ b/vendor/github.com/google/go-github/github/orgs_outside_collaborators.go @@ -0,0 +1,50 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ListOutsideCollaboratorsOptions specifies optional parameters to the +// OrganizationsService.ListOutsideCollaborators method. +type ListOutsideCollaboratorsOptions struct { + // Filter outside collaborators returned in the list. Possible values are: + // 2fa_disabled, all. Default is "all". + Filter string `url:"filter,omitempty"` + + ListOptions +} + +// ListOutsideCollaborators lists outside collaborators of organization's repositories. +// This will only work if the authenticated +// user is an owner of the organization. +// +// Warning: The API may change without advance notice during the preview period. +// Preview features are not supported for production use. +// +// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#list-outside-collaborators +func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org string, opt *ListOutsideCollaboratorsOptions) ([]*User, *Response, error) { + u := fmt.Sprintf("orgs/%v/outside_collaborators", org) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var members []*User + resp, err := s.client.Do(ctx, req, &members) + if err != nil { + return nil, resp, err + } + + return members, resp, nil +} diff --git a/vendor/github.com/google/go-github/github/orgs_projects.go b/vendor/github.com/google/go-github/github/orgs_projects.go new file mode 100644 index 000000000..e57cba978 --- /dev/null +++ b/vendor/github.com/google/go-github/github/orgs_projects.go @@ -0,0 +1,60 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ListProjects lists the projects for an organization. +// +// GitHub API docs: https://developer.github.com/v3/projects/#list-organization-projects +func (s *OrganizationsService) ListProjects(ctx context.Context, org string, opt *ProjectListOptions) ([]*Project, *Response, error) { + u := fmt.Sprintf("orgs/%v/projects", org) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeProjectsPreview) + + var projects []*Project + resp, err := s.client.Do(ctx, req, &projects) + if err != nil { + return nil, resp, err + } + + return projects, resp, nil +} + +// CreateProject creates a GitHub Project for the specified organization. +// +// GitHub API docs: https://developer.github.com/v3/projects/#create-an-organization-project +func (s *OrganizationsService) CreateProject(ctx context.Context, org string, opt *ProjectOptions) (*Project, *Response, error) { + u := fmt.Sprintf("orgs/%v/projects", org) + req, err := s.client.NewRequest("POST", u, opt) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeProjectsPreview) + + project := &Project{} + resp, err := s.client.Do(ctx, req, project) + if err != nil { + return nil, resp, err + } + + return project, resp, nil +} diff --git a/vendor/github.com/google/go-github/github/orgs_teams.go b/vendor/github.com/google/go-github/github/orgs_teams.go index 8e8550ce3..70b090d0d 100644 --- a/vendor/github.com/google/go-github/github/orgs_teams.go +++ b/vendor/github.com/google/go-github/github/orgs_teams.go @@ -5,9 +5,13 @@ package github -import "fmt" +import ( + "context" + "fmt" + "time" +) -// Team represents a team within a GitHub organization. Teams are used to +// Team represents a team within a GitHub organization. Teams are used to // manage access to an organization's repositories. type Team struct { ID *int `json:"id,omitempty"` @@ -17,9 +21,9 @@ type Team struct { Slug *string `json:"slug,omitempty"` // Permission is deprecated when creating or editing a team in an org - // using the new GitHub permission model. It no longer identifies the + // using the new GitHub permission model. It no longer identifies the // permission a team has on its repos, but only specifies the default - // permission a repo is initially added with. Avoid confusion by + // permission a repo is initially added with. Avoid confusion by // specifying a permission value when calling AddTeamRepo. Permission *string `json:"permission,omitempty"` @@ -35,16 +39,35 @@ type Team struct { Organization *Organization `json:"organization,omitempty"` MembersURL *string `json:"members_url,omitempty"` RepositoriesURL *string `json:"repositories_url,omitempty"` + + // LDAPDN is only available in GitHub Enterprise and when the team + // membership is synchronized with LDAP. + LDAPDN *string `json:"ldap_dn,omitempty"` } func (t Team) String() string { return Stringify(t) } +// Invitation represents a team member's invitation status. +type Invitation struct { + ID *int `json:"id,omitempty"` + Login *string `json:"login,omitempty"` + Email *string `json:"email,omitempty"` + // Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'. + Role *string `json:"role,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + Inviter *User `json:"inviter,omitempty"` +} + +func (i Invitation) String() string { + return Stringify(i) +} + // ListTeams lists all of the teams for an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-teams -func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]*Team, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-teams +func (s *OrganizationsService) ListTeams(ctx context.Context, org string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams", org) u, err := addOptions(u, opt) if err != nil { @@ -56,19 +79,19 @@ func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]*Team, return nil, nil, err } - teams := new([]*Team) - resp, err := s.client.Do(req, teams) + var teams []*Team + resp, err := s.client.Do(ctx, req, &teams) if err != nil { return nil, resp, err } - return *teams, resp, err + return teams, resp, nil } // GetTeam fetches a team by ID. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team -func (s *OrganizationsService) GetTeam(team int) (*Team, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team +func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *Response, error) { u := fmt.Sprintf("teams/%v", team) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -76,18 +99,18 @@ func (s *OrganizationsService) GetTeam(team int) (*Team, *Response, error) { } t := new(Team) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // CreateTeam creates a new team within an organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#create-team -func (s *OrganizationsService) CreateTeam(org string, team *Team) (*Team, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#create-team +func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *Team) (*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams", org) req, err := s.client.NewRequest("POST", u, team) if err != nil { @@ -95,18 +118,18 @@ func (s *OrganizationsService) CreateTeam(org string, team *Team) (*Team, *Respo } t := new(Team) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // EditTeam edits a team. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#edit-team -func (s *OrganizationsService) EditTeam(id int, team *Team) (*Team, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#edit-team +func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *Team) (*Team, *Response, error) { u := fmt.Sprintf("teams/%v", id) req, err := s.client.NewRequest("PATCH", u, team) if err != nil { @@ -114,32 +137,32 @@ func (s *OrganizationsService) EditTeam(id int, team *Team) (*Team, *Response, e } t := new(Team) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // DeleteTeam deletes a team. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#delete-team -func (s *OrganizationsService) DeleteTeam(team int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#delete-team +func (s *OrganizationsService) DeleteTeam(ctx context.Context, team int) (*Response, error) { u := fmt.Sprintf("teams/%v", team) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // OrganizationListTeamMembersOptions specifies the optional parameters to the // OrganizationsService.ListTeamMembers method. type OrganizationListTeamMembersOptions struct { - // Role filters members returned by their role in the team. Possible - // values are "all", "member", "maintainer". Default is "all". + // Role filters members returned by their role in the team. Possible + // values are "all", "member", "maintainer". Default is "all". Role string `url:"role,omitempty"` ListOptions @@ -148,8 +171,8 @@ type OrganizationListTeamMembersOptions struct { // ListTeamMembers lists all of the users who are members of the specified // team. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-members -func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTeamMembersOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-team-members +func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int, opt *OrganizationListTeamMembersOptions) ([]*User, *Response, error) { u := fmt.Sprintf("teams/%v/members", team) u, err := addOptions(u, opt) if err != nil { @@ -161,34 +184,34 @@ func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTe return nil, nil, err } - members := new([]*User) - resp, err := s.client.Do(req, members) + var members []*User + resp, err := s.client.Do(ctx, req, &members) if err != nil { return nil, resp, err } - return *members, resp, err + return members, resp, nil } // IsTeamMember checks if a user is a member of the specified team. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team-member -func (s *OrganizationsService) IsTeamMember(team int, user string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-member +func (s *OrganizationsService) IsTeamMember(ctx context.Context, team int, user string) (bool, *Response, error) { u := fmt.Sprintf("teams/%v/members/%v", team, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) member, err := parseBoolResponse(err) return member, resp, err } // ListTeamRepos lists the repositories that the specified team has access to. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-repos -func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-team-repos +func (s *OrganizationsService) ListTeamRepos(ctx context.Context, team int, opt *ListOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("teams/%v/repos", team) u, err := addOptions(u, opt) if err != nil { @@ -200,21 +223,21 @@ func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]*Rep return nil, nil, err } - repos := new([]*Repository) - resp, err := s.client.Do(req, repos) + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } -// IsTeamRepo checks if a team manages the specified repository. If the +// IsTeamRepo checks if a team manages the specified repository. If the // repository is managed by team, a Repository is returned which includes the // permissions team has for that repo. // // GitHub API docs: https://developer.github.com/v3/orgs/teams/#check-if-a-team-manages-a-repository -func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (*Repository, *Response, error) { +func (s *OrganizationsService) IsTeamRepo(ctx context.Context, team int, owner string, repo string) (*Repository, *Response, error) { u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -224,12 +247,12 @@ func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) ( req.Header.Set("Accept", mediaTypeOrgPermissionRepo) repository := new(Repository) - resp, err := s.client.Do(req, repository) + resp, err := s.client.Do(ctx, req, repository) if err != nil { return nil, resp, err } - return repository, resp, err + return repository, resp, nil } // OrganizationAddTeamRepoOptions specifies the optional parameters to the @@ -245,39 +268,39 @@ type OrganizationAddTeamRepoOptions struct { Permission string `json:"permission,omitempty"` } -// AddTeamRepo adds a repository to be managed by the specified team. The +// AddTeamRepo adds a repository to be managed by the specified team. The // specified repository must be owned by the organization to which the team // belongs, or a direct fork of a repository owned by the organization. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#add-team-repo -func (s *OrganizationsService) AddTeamRepo(team int, owner string, repo string, opt *OrganizationAddTeamRepoOptions) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-repo +func (s *OrganizationsService) AddTeamRepo(ctx context.Context, team int, owner string, repo string, opt *OrganizationAddTeamRepoOptions) (*Response, error) { u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // RemoveTeamRepo removes a repository from being managed by the specified -// team. Note that this does not delete the repository, it just removes it +// team. Note that this does not delete the repository, it just removes it // from the team. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#remove-team-repo -func (s *OrganizationsService) RemoveTeamRepo(team int, owner string, repo string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-repo +func (s *OrganizationsService) RemoveTeamRepo(ctx context.Context, team int, owner string, repo string) (*Response, error) { u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListUserTeams lists a user's teams // GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams -func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]*Team, *Response, error) { +func (s *OrganizationsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]*Team, *Response, error) { u := "user/teams" u, err := addOptions(u, opt) if err != nil { @@ -289,19 +312,19 @@ func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]*Team, *Respon return nil, nil, err } - teams := new([]*Team) - resp, err := s.client.Do(req, teams) + var teams []*Team + resp, err := s.client.Do(ctx, req, &teams) if err != nil { return nil, resp, err } - return *teams, resp, err + return teams, resp, nil } // GetTeamMembership returns the membership status for a user in a team. // // GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership -func (s *OrganizationsService) GetTeamMembership(team int, user string) (*Membership, *Response, error) { +func (s *OrganizationsService) GetTeamMembership(ctx context.Context, team int, user string) (*Membership, *Response, error) { u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -309,18 +332,18 @@ func (s *OrganizationsService) GetTeamMembership(team int, user string) (*Member } t := new(Membership) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // OrganizationAddTeamMembershipOptions does stuff specifies the optional // parameters to the OrganizationsService.AddTeamMembership method. type OrganizationAddTeamMembershipOptions struct { - // Role specifies the role the user should have in the team. Possible + // Role specifies the role the user should have in the team. Possible // values are: // member - a normal member of the team // maintainer - a team maintainer. Able to add/remove other team @@ -349,7 +372,7 @@ type OrganizationAddTeamMembershipOptions struct { // added as a member of the team. // // GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership -func (s *OrganizationsService) AddTeamMembership(team int, user string, opt *OrganizationAddTeamMembershipOptions) (*Membership, *Response, error) { +func (s *OrganizationsService) AddTeamMembership(ctx context.Context, team int, user string, opt *OrganizationAddTeamMembershipOptions) (*Membership, *Response, error) { u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -357,23 +380,49 @@ func (s *OrganizationsService) AddTeamMembership(team int, user string, opt *Org } t := new(Membership) - resp, err := s.client.Do(req, t) + resp, err := s.client.Do(ctx, req, t) if err != nil { return nil, resp, err } - return t, resp, err + return t, resp, nil } // RemoveTeamMembership removes a user from a team. // // GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-membership -func (s *OrganizationsService) RemoveTeamMembership(team int, user string) (*Response, error) { +func (s *OrganizationsService) RemoveTeamMembership(ctx context.Context, team int, user string) (*Response, error) { u := fmt.Sprintf("teams/%v/memberships/%v", team, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) +} + +// ListPendingTeamInvitations get pending invitaion list in team. +// Warning: The API may change without advance notice during the preview period. +// Preview features are not supported for production use. +// +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-pending-team-invitations +func (s *OrganizationsService) ListPendingTeamInvitations(ctx context.Context, team int, opt *ListOptions) ([]*Invitation, *Response, error) { + u := fmt.Sprintf("teams/%v/invitations", team) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var pendingInvitations []*Invitation + resp, err := s.client.Do(ctx, req, &pendingInvitations) + if err != nil { + return nil, resp, err + } + + return pendingInvitations, resp, nil } diff --git a/vendor/github.com/google/go-github/github/projects.go b/vendor/github.com/google/go-github/github/projects.go index 233005668..58b638eb8 100644 --- a/vendor/github.com/google/go-github/github/projects.go +++ b/vendor/github.com/google/go-github/github/projects.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // ProjectsService provides access to the projects functions in the // GitHub API. @@ -35,7 +38,7 @@ func (p Project) String() string { // GetProject gets a GitHub Project for a repo. // // GitHub API docs: https://developer.github.com/v3/projects/#get-a-project -func (s *ProjectsService) GetProject(id int) (*Project, *Response, error) { +func (s *ProjectsService) GetProject(ctx context.Context, id int) (*Project, *Response, error) { u := fmt.Sprintf("projects/%v", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -46,12 +49,12 @@ func (s *ProjectsService) GetProject(id int) (*Project, *Response, error) { req.Header.Set("Accept", mediaTypeProjectsPreview) project := &Project{} - resp, err := s.client.Do(req, project) + resp, err := s.client.Do(ctx, req, project) if err != nil { return nil, resp, err } - return project, resp, err + return project, resp, nil } // ProjectOptions specifies the parameters to the @@ -67,7 +70,7 @@ type ProjectOptions struct { // UpdateProject updates a repository project. // // GitHub API docs: https://developer.github.com/v3/projects/#update-a-project -func (s *ProjectsService) UpdateProject(id int, opt *ProjectOptions) (*Project, *Response, error) { +func (s *ProjectsService) UpdateProject(ctx context.Context, id int, opt *ProjectOptions) (*Project, *Response, error) { u := fmt.Sprintf("projects/%v", id) req, err := s.client.NewRequest("PATCH", u, opt) if err != nil { @@ -78,18 +81,18 @@ func (s *ProjectsService) UpdateProject(id int, opt *ProjectOptions) (*Project, req.Header.Set("Accept", mediaTypeProjectsPreview) project := &Project{} - resp, err := s.client.Do(req, project) + resp, err := s.client.Do(ctx, req, project) if err != nil { return nil, resp, err } - return project, resp, err + return project, resp, nil } // DeleteProject deletes a GitHub Project from a repository. // // GitHub API docs: https://developer.github.com/v3/projects/#delete-a-project -func (s *ProjectsService) DeleteProject(id int) (*Response, error) { +func (s *ProjectsService) DeleteProject(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("projects/%v", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -99,7 +102,7 @@ func (s *ProjectsService) DeleteProject(id int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ProjectColumn represents a column of a GitHub Project. @@ -116,7 +119,7 @@ type ProjectColumn struct { // ListProjectColumns lists the columns of a GitHub Project for a repo. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns -func (s *ProjectsService) ListProjectColumns(projectID int, opt *ListOptions) ([]*ProjectColumn, *Response, error) { +func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int, opt *ListOptions) ([]*ProjectColumn, *Response, error) { u := fmt.Sprintf("projects/%v/columns", projectID) u, err := addOptions(u, opt) if err != nil { @@ -132,18 +135,18 @@ func (s *ProjectsService) ListProjectColumns(projectID int, opt *ListOptions) ([ req.Header.Set("Accept", mediaTypeProjectsPreview) columns := []*ProjectColumn{} - resp, err := s.client.Do(req, &columns) + resp, err := s.client.Do(ctx, req, &columns) if err != nil { return nil, resp, err } - return columns, resp, err + return columns, resp, nil } // GetProjectColumn gets a column of a GitHub Project for a repo. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#get-a-project-column -func (s *ProjectsService) GetProjectColumn(id int) (*ProjectColumn, *Response, error) { +func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int) (*ProjectColumn, *Response, error) { u := fmt.Sprintf("projects/columns/%v", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -154,12 +157,12 @@ func (s *ProjectsService) GetProjectColumn(id int) (*ProjectColumn, *Response, e req.Header.Set("Accept", mediaTypeProjectsPreview) column := &ProjectColumn{} - resp, err := s.client.Do(req, column) + resp, err := s.client.Do(ctx, req, column) if err != nil { return nil, resp, err } - return column, resp, err + return column, resp, nil } // ProjectColumnOptions specifies the parameters to the @@ -173,7 +176,7 @@ type ProjectColumnOptions struct { // CreateProjectColumn creates a column for the specified (by number) project. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#create-a-project-column -func (s *ProjectsService) CreateProjectColumn(projectID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { +func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { u := fmt.Sprintf("projects/%v/columns", projectID) req, err := s.client.NewRequest("POST", u, opt) if err != nil { @@ -184,18 +187,18 @@ func (s *ProjectsService) CreateProjectColumn(projectID int, opt *ProjectColumnO req.Header.Set("Accept", mediaTypeProjectsPreview) column := &ProjectColumn{} - resp, err := s.client.Do(req, column) + resp, err := s.client.Do(ctx, req, column) if err != nil { return nil, resp, err } - return column, resp, err + return column, resp, nil } // UpdateProjectColumn updates a column of a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#update-a-project-column -func (s *ProjectsService) UpdateProjectColumn(columnID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { +func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { u := fmt.Sprintf("projects/columns/%v", columnID) req, err := s.client.NewRequest("PATCH", u, opt) if err != nil { @@ -206,18 +209,18 @@ func (s *ProjectsService) UpdateProjectColumn(columnID int, opt *ProjectColumnOp req.Header.Set("Accept", mediaTypeProjectsPreview) column := &ProjectColumn{} - resp, err := s.client.Do(req, column) + resp, err := s.client.Do(ctx, req, column) if err != nil { return nil, resp, err } - return column, resp, err + return column, resp, nil } // DeleteProjectColumn deletes a column from a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#delete-a-project-column -func (s *ProjectsService) DeleteProjectColumn(columnID int) (*Response, error) { +func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int) (*Response, error) { u := fmt.Sprintf("projects/columns/%v", columnID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -227,7 +230,7 @@ func (s *ProjectsService) DeleteProjectColumn(columnID int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ProjectColumnMoveOptions specifies the parameters to the @@ -241,7 +244,7 @@ type ProjectColumnMoveOptions struct { // MoveProjectColumn moves a column within a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/columns/#move-a-project-column -func (s *ProjectsService) MoveProjectColumn(columnID int, opt *ProjectColumnMoveOptions) (*Response, error) { +func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int, opt *ProjectColumnMoveOptions) (*Response, error) { u := fmt.Sprintf("projects/columns/%v/moves", columnID) req, err := s.client.NewRequest("POST", u, opt) if err != nil { @@ -251,7 +254,7 @@ func (s *ProjectsService) MoveProjectColumn(columnID int, opt *ProjectColumnMove // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ProjectCard represents a card in a column of a GitHub Project. @@ -269,7 +272,7 @@ type ProjectCard struct { // ListProjectCards lists the cards in a column of a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards -func (s *ProjectsService) ListProjectCards(columnID int, opt *ListOptions) ([]*ProjectCard, *Response, error) { +func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int, opt *ListOptions) ([]*ProjectCard, *Response, error) { u := fmt.Sprintf("projects/columns/%v/cards", columnID) u, err := addOptions(u, opt) if err != nil { @@ -285,18 +288,18 @@ func (s *ProjectsService) ListProjectCards(columnID int, opt *ListOptions) ([]*P req.Header.Set("Accept", mediaTypeProjectsPreview) cards := []*ProjectCard{} - resp, err := s.client.Do(req, &cards) + resp, err := s.client.Do(ctx, req, &cards) if err != nil { return nil, resp, err } - return cards, resp, err + return cards, resp, nil } // GetProjectCard gets a card in a column of a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card -func (s *ProjectsService) GetProjectCard(columnID int) (*ProjectCard, *Response, error) { +func (s *ProjectsService) GetProjectCard(ctx context.Context, columnID int) (*ProjectCard, *Response, error) { u := fmt.Sprintf("projects/columns/cards/%v", columnID) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -307,12 +310,12 @@ func (s *ProjectsService) GetProjectCard(columnID int) (*ProjectCard, *Response, req.Header.Set("Accept", mediaTypeProjectsPreview) card := &ProjectCard{} - resp, err := s.client.Do(req, card) + resp, err := s.client.Do(ctx, req, card) if err != nil { return nil, resp, err } - return card, resp, err + return card, resp, nil } // ProjectCardOptions specifies the parameters to the @@ -331,7 +334,7 @@ type ProjectCardOptions struct { // CreateProjectCard creates a card in the specified column of a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card -func (s *ProjectsService) CreateProjectCard(columnID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { +func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { u := fmt.Sprintf("projects/columns/%v/cards", columnID) req, err := s.client.NewRequest("POST", u, opt) if err != nil { @@ -342,18 +345,18 @@ func (s *ProjectsService) CreateProjectCard(columnID int, opt *ProjectCardOption req.Header.Set("Accept", mediaTypeProjectsPreview) card := &ProjectCard{} - resp, err := s.client.Do(req, card) + resp, err := s.client.Do(ctx, req, card) if err != nil { return nil, resp, err } - return card, resp, err + return card, resp, nil } // UpdateProjectCard updates a card of a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#update-a-project-card -func (s *ProjectsService) UpdateProjectCard(cardID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { +func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { u := fmt.Sprintf("projects/columns/cards/%v", cardID) req, err := s.client.NewRequest("PATCH", u, opt) if err != nil { @@ -364,18 +367,18 @@ func (s *ProjectsService) UpdateProjectCard(cardID int, opt *ProjectCardOptions) req.Header.Set("Accept", mediaTypeProjectsPreview) card := &ProjectCard{} - resp, err := s.client.Do(req, card) + resp, err := s.client.Do(ctx, req, card) if err != nil { return nil, resp, err } - return card, resp, err + return card, resp, nil } // DeleteProjectCard deletes a card from a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#delete-a-project-card -func (s *ProjectsService) DeleteProjectCard(cardID int) (*Response, error) { +func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int) (*Response, error) { u := fmt.Sprintf("projects/columns/cards/%v", cardID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -385,7 +388,7 @@ func (s *ProjectsService) DeleteProjectCard(cardID int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ProjectCardMoveOptions specifies the parameters to the @@ -403,7 +406,7 @@ type ProjectCardMoveOptions struct { // MoveProjectCard moves a card within a GitHub Project. // // GitHub API docs: https://developer.github.com/v3/projects/cards/#move-a-project-card -func (s *ProjectsService) MoveProjectCard(cardID int, opt *ProjectCardMoveOptions) (*Response, error) { +func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int, opt *ProjectCardMoveOptions) (*Response, error) { u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID) req, err := s.client.NewRequest("POST", u, opt) if err != nil { @@ -413,5 +416,5 @@ func (s *ProjectsService) MoveProjectCard(cardID int, opt *ProjectCardMoveOption // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/pulls.go b/vendor/github.com/google/go-github/github/pulls.go index 51c6ccb57..0fdb4cd21 100644 --- a/vendor/github.com/google/go-github/github/pulls.go +++ b/vendor/github.com/google/go-github/github/pulls.go @@ -7,6 +7,7 @@ package github import ( "bytes" + "context" "fmt" "time" ) @@ -14,40 +15,41 @@ import ( // PullRequestsService handles communication with the pull request related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/pulls/ +// GitHub API docs: https://developer.github.com/v3/pulls/ type PullRequestsService service // PullRequest represents a GitHub pull request on a repository. type PullRequest struct { - ID *int `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - MergedAt *time.Time `json:"merged_at,omitempty"` - User *User `json:"user,omitempty"` - Merged *bool `json:"merged,omitempty"` - Mergeable *bool `json:"mergeable,omitempty"` - MergedBy *User `json:"merged_by,omitempty"` - Comments *int `json:"comments,omitempty"` - Commits *int `json:"commits,omitempty"` - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - ChangedFiles *int `json:"changed_files,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - IssueURL *string `json:"issue_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` - ReviewCommentsURL *string `json:"review_comments_url,omitempty"` - ReviewCommentURL *string `json:"review_comment_url,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Assignees []*User `json:"assignees,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` + ID *int `json:"id,omitempty"` + Number *int `json:"number,omitempty"` + State *string `json:"state,omitempty"` + Title *string `json:"title,omitempty"` + Body *string `json:"body,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + ClosedAt *time.Time `json:"closed_at,omitempty"` + MergedAt *time.Time `json:"merged_at,omitempty"` + User *User `json:"user,omitempty"` + Merged *bool `json:"merged,omitempty"` + Mergeable *bool `json:"mergeable,omitempty"` + MergedBy *User `json:"merged_by,omitempty"` + Comments *int `json:"comments,omitempty"` + Commits *int `json:"commits,omitempty"` + Additions *int `json:"additions,omitempty"` + Deletions *int `json:"deletions,omitempty"` + ChangedFiles *int `json:"changed_files,omitempty"` + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + IssueURL *string `json:"issue_url,omitempty"` + StatusesURL *string `json:"statuses_url,omitempty"` + DiffURL *string `json:"diff_url,omitempty"` + PatchURL *string `json:"patch_url,omitempty"` + ReviewCommentsURL *string `json:"review_comments_url,omitempty"` + ReviewCommentURL *string `json:"review_comment_url,omitempty"` + Assignee *User `json:"assignee,omitempty"` + Assignees []*User `json:"assignees,omitempty"` + Milestone *Milestone `json:"milestone,omitempty"` + MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` Head *PullRequestBranch `json:"head,omitempty"` Base *PullRequestBranch `json:"base,omitempty"` @@ -69,8 +71,8 @@ type PullRequestBranch struct { // PullRequestListOptions specifies the optional parameters to the // PullRequestsService.List method. type PullRequestListOptions struct { - // State filters pull requests based on their state. Possible values are: - // open, closed. Default is "open". + // State filters pull requests based on their state. Possible values are: + // open, closed. Default is "open". State string `url:"state,omitempty"` // Head filters pull requests by head user and branch name in the format of: @@ -94,8 +96,8 @@ type PullRequestListOptions struct { // List the pull requests for the specified repository. // -// GitHub API docs: http://developer.github.com/v3/pulls/#list-pull-requests -func (s *PullRequestsService) List(owner string, repo string, opt *PullRequestListOptions) ([]*PullRequest, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests +func (s *PullRequestsService) List(ctx context.Context, owner string, repo string, opt *PullRequestListOptions) ([]*PullRequest, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -107,19 +109,19 @@ func (s *PullRequestsService) List(owner string, repo string, opt *PullRequestLi return nil, nil, err } - pulls := new([]*PullRequest) - resp, err := s.client.Do(req, pulls) + var pulls []*PullRequest + resp, err := s.client.Do(ctx, req, &pulls) if err != nil { return nil, resp, err } - return *pulls, resp, err + return pulls, resp, nil } // Get a single pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#get-a-single-pull-request -func (s *PullRequestsService) Get(owner string, repo string, number int) (*PullRequest, *Response, error) { +func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string, number int) (*PullRequest, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -127,16 +129,16 @@ func (s *PullRequestsService) Get(owner string, repo string, number int) (*PullR } pull := new(PullRequest) - resp, err := s.client.Do(req, pull) + resp, err := s.client.Do(ctx, req, pull) if err != nil { return nil, resp, err } - return pull, resp, err + return pull, resp, nil } // GetRaw gets raw (diff or patch) format of a pull request. -func (s *PullRequestsService) GetRaw(owner string, repo string, number int, opt RawOptions) (string, *Response, error) { +func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -153,27 +155,28 @@ func (s *PullRequestsService) GetRaw(owner string, repo string, number int, opt } ret := new(bytes.Buffer) - resp, err := s.client.Do(req, ret) + resp, err := s.client.Do(ctx, req, ret) if err != nil { return "", resp, err } - return ret.String(), resp, err + return ret.String(), resp, nil } // NewPullRequest represents a new pull request to be created. type NewPullRequest struct { - Title *string `json:"title,omitempty"` - Head *string `json:"head,omitempty"` - Base *string `json:"base,omitempty"` - Body *string `json:"body,omitempty"` - Issue *int `json:"issue,omitempty"` + Title *string `json:"title,omitempty"` + Head *string `json:"head,omitempty"` + Base *string `json:"base,omitempty"` + Body *string `json:"body,omitempty"` + Issue *int `json:"issue,omitempty"` + MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` } // Create a new pull request on the specified repository. // // GitHub API docs: https://developer.github.com/v3/pulls/#create-a-pull-request -func (s *PullRequestsService) Create(owner string, repo string, pull *NewPullRequest) (*PullRequest, *Response, error) { +func (s *PullRequestsService) Create(ctx context.Context, owner string, repo string, pull *NewPullRequest) (*PullRequest, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) req, err := s.client.NewRequest("POST", u, pull) if err != nil { @@ -181,37 +184,64 @@ func (s *PullRequestsService) Create(owner string, repo string, pull *NewPullReq } p := new(PullRequest) - resp, err := s.client.Do(req, p) + resp, err := s.client.Do(ctx, req, p) if err != nil { return nil, resp, err } - return p, resp, err + return p, resp, nil +} + +type pullRequestUpdate struct { + Title *string `json:"title,omitempty"` + Body *string `json:"body,omitempty"` + State *string `json:"state,omitempty"` + Base *string `json:"base,omitempty"` + MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` } // Edit a pull request. +// pull must not be nil. +// +// The following fields are editable: Title, Body, State, Base.Ref and MaintainerCanModify. +// Base.Ref updates the base branch of the pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request -func (s *PullRequestsService) Edit(owner string, repo string, number int, pull *PullRequest) (*PullRequest, *Response, error) { +func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo string, number int, pull *PullRequest) (*PullRequest, *Response, error) { + if pull == nil { + return nil, nil, fmt.Errorf("pull must be provided") + } + u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - req, err := s.client.NewRequest("PATCH", u, pull) + + update := &pullRequestUpdate{ + Title: pull.Title, + Body: pull.Body, + State: pull.State, + MaintainerCanModify: pull.MaintainerCanModify, + } + if pull.Base != nil { + update.Base = pull.Base.Ref + } + + req, err := s.client.NewRequest("PATCH", u, update) if err != nil { return nil, nil, err } p := new(PullRequest) - resp, err := s.client.Do(req, p) + resp, err := s.client.Do(ctx, req, p) if err != nil { return nil, resp, err } - return p, resp, err + return p, resp, nil } // ListCommits lists the commits in a pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request -func (s *PullRequestsService) ListCommits(owner string, repo string, number int, opt *ListOptions) ([]*RepositoryCommit, *Response, error) { +func (s *PullRequestsService) ListCommits(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/commits", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -223,19 +253,19 @@ func (s *PullRequestsService) ListCommits(owner string, repo string, number int, return nil, nil, err } - commits := new([]*RepositoryCommit) - resp, err := s.client.Do(req, commits) + var commits []*RepositoryCommit + resp, err := s.client.Do(ctx, req, &commits) if err != nil { return nil, resp, err } - return *commits, resp, err + return commits, resp, nil } // ListFiles lists the files in a pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests-files -func (s *PullRequestsService) ListFiles(owner string, repo string, number int, opt *ListOptions) ([]*CommitFile, *Response, error) { +func (s *PullRequestsService) ListFiles(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*CommitFile, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/files", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -247,26 +277,26 @@ func (s *PullRequestsService) ListFiles(owner string, repo string, number int, o return nil, nil, err } - commitFiles := new([]*CommitFile) - resp, err := s.client.Do(req, commitFiles) + var commitFiles []*CommitFile + resp, err := s.client.Do(ctx, req, &commitFiles) if err != nil { return nil, resp, err } - return *commitFiles, resp, err + return commitFiles, resp, nil } // IsMerged checks if a pull request has been merged. // // GitHub API docs: https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged -func (s *PullRequestsService) IsMerged(owner string, repo string, number int) (bool, *Response, error) { +func (s *PullRequestsService) IsMerged(ctx context.Context, owner string, repo string, number int) (bool, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) merged, err := parseBoolResponse(err) return merged, resp, err } @@ -298,7 +328,7 @@ type pullRequestMergeRequest struct { // commitMessage is the title for the automatic commit message. // // GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-buttontrade -func (s *PullRequestsService) Merge(owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) { +func (s *PullRequestsService) Merge(ctx context.Context, owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) pullRequestBody := &pullRequestMergeRequest{CommitMessage: commitMessage} @@ -316,10 +346,10 @@ func (s *PullRequestsService) Merge(owner string, repo string, number int, commi req.Header.Set("Accept", mediaTypeSquashPreview) mergeResult := new(PullRequestMergeResult) - resp, err := s.client.Do(req, mergeResult) + resp, err := s.client.Do(ctx, req, mergeResult) if err != nil { return nil, resp, err } - return mergeResult, resp, err + return mergeResult, resp, nil } diff --git a/vendor/github.com/google/go-github/github/pulls_comments.go b/vendor/github.com/google/go-github/github/pulls_comments.go index c7af85a8e..bc0bc2d4a 100644 --- a/vendor/github.com/google/go-github/github/pulls_comments.go +++ b/vendor/github.com/google/go-github/github/pulls_comments.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -37,10 +38,10 @@ func (p PullRequestComment) String() string { // PullRequestListCommentsOptions specifies the optional parameters to the // PullRequestsService.ListComments method. type PullRequestListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. + // Sort specifies how to sort comments. Possible values are: created, updated. Sort string `url:"sort,omitempty"` - // Direction in which to sort comments. Possible values are: asc, desc. + // Direction in which to sort comments. Possible values are: asc, desc. Direction string `url:"direction,omitempty"` // Since filters comments by time. @@ -49,12 +50,12 @@ type PullRequestListCommentsOptions struct { ListOptions } -// ListComments lists all comments on the specified pull request. Specifying a +// ListComments lists all comments on the specified pull request. Specifying a // pull request number of 0 will return all comments on all pull requests for // the repository. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request -func (s *PullRequestsService) ListComments(owner string, repo string, number int, opt *PullRequestListCommentsOptions) ([]*PullRequestComment, *Response, error) { +func (s *PullRequestsService) ListComments(ctx context.Context, owner string, repo string, number int, opt *PullRequestListCommentsOptions) ([]*PullRequestComment, *Response, error) { var u string if number == 0 { u = fmt.Sprintf("repos/%v/%v/pulls/comments", owner, repo) @@ -74,19 +75,19 @@ func (s *PullRequestsService) ListComments(owner string, repo string, number int // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - comments := new([]*PullRequestComment) - resp, err := s.client.Do(req, comments) + var comments []*PullRequestComment + resp, err := s.client.Do(ctx, req, &comments) if err != nil { return nil, resp, err } - return *comments, resp, err + return comments, resp, nil } // GetComment fetches the specified pull request comment. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment -func (s *PullRequestsService) GetComment(owner string, repo string, number int) (*PullRequestComment, *Response, error) { +func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, number int) (*PullRequestComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -97,18 +98,18 @@ func (s *PullRequestsService) GetComment(owner string, repo string, number int) req.Header.Set("Accept", mediaTypeReactionsPreview) comment := new(PullRequestComment) - resp, err := s.client.Do(req, comment) + resp, err := s.client.Do(ctx, req, comment) if err != nil { return nil, resp, err } - return comment, resp, err + return comment, resp, nil } // CreateComment creates a new comment on the specified pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment -func (s *PullRequestsService) CreateComment(owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { +func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) req, err := s.client.NewRequest("POST", u, comment) if err != nil { @@ -116,18 +117,18 @@ func (s *PullRequestsService) CreateComment(owner string, repo string, number in } c := new(PullRequestComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // EditComment updates a pull request comment. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment -func (s *PullRequestsService) EditComment(owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { +func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { @@ -135,22 +136,22 @@ func (s *PullRequestsService) EditComment(owner string, repo string, number int, } c := new(PullRequestComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // DeleteComment deletes a pull request comment. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment -func (s *PullRequestsService) DeleteComment(owner string, repo string, number int) (*Response, error) { +func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, number int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/pulls_reviewers.go b/vendor/github.com/google/go-github/github/pulls_reviewers.go new file mode 100644 index 000000000..efa388896 --- /dev/null +++ b/vendor/github.com/google/go-github/github/pulls_reviewers.go @@ -0,0 +1,84 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// RequestReviewers creates a review request for the provided GitHub users for the specified pull request. +// +// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request +func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo string, number int, logins []string) (*PullRequest, *Response, error) { + u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) + + reviewers := struct { + Reviewers []string `json:"reviewers,omitempty"` + }{ + Reviewers: logins, + } + req, err := s.client.NewRequest("POST", u, &reviewers) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + r := new(PullRequest) + resp, err := s.client.Do(ctx, req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} + +// ListReviewers lists users whose reviews have been requested on the specified pull request. +// +// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests +func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo string, number int) ([]*User, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/requested_reviewers", owner, repo, number) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + var users []*User + resp, err := s.client.Do(ctx, req, &users) + if err != nil { + return nil, resp, err + } + + return users, resp, nil +} + +// RemoveReviewers removes the review request for the provided GitHub users for the specified pull request. +// +// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request +func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo string, number int, logins []string) (*Response, error) { + u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) + + reviewers := struct { + Reviewers []string `json:"reviewers,omitempty"` + }{ + Reviewers: logins, + } + req, err := s.client.NewRequest("DELETE", u, &reviewers) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + return s.client.Do(ctx, req, reviewers) +} diff --git a/vendor/github.com/google/go-github/github/pulls_reviews.go b/vendor/github.com/google/go-github/github/pulls_reviews.go index ae3cdd4af..c27b6a8c4 100644 --- a/vendor/github.com/google/go-github/github/pulls_reviews.go +++ b/vendor/github.com/google/go-github/github/pulls_reviews.go @@ -5,15 +5,244 @@ package github -import "time" +import ( + "context" + "fmt" + "time" +) // PullRequestReview represents a review of a pull request. type PullRequestReview struct { - ID *int `json:"id,omitempty"` - User *User `json:"user,omitempty"` - Body *string `json:"body,omitempty"` - SubmittedAt *time.Time `json:"submitted_at,omitempty"` - - // State can be "approved", "rejected", or "commented". - State *string `json:"state,omitempty"` + ID *int `json:"id,omitempty"` + User *User `json:"user,omitempty"` + Body *string `json:"body,omitempty"` + SubmittedAt *time.Time `json:"submitted_at,omitempty"` + CommitID *string `json:"commit_id,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + PullRequestURL *string `json:"pull_request_url,omitempty"` + State *string `json:"state,omitempty"` +} + +func (p PullRequestReview) String() string { + return Stringify(p) +} + +// DraftReviewComment represents a comment part of the review. +type DraftReviewComment struct { + Path *string `json:"path,omitempty"` + Position *int `json:"position,omitempty"` + Body *string `json:"body,omitempty"` +} + +func (c DraftReviewComment) String() string { + return Stringify(c) +} + +// PullRequestReviewRequest represents a request to create a review. +type PullRequestReviewRequest struct { + Body *string `json:"body,omitempty"` + Event *string `json:"event,omitempty"` + Comments []*DraftReviewComment `json:"comments,omitempty"` +} + +func (r PullRequestReviewRequest) String() string { + return Stringify(r) +} + +// PullRequestReviewDismissalRequest represents a request to dismiss a review. +type PullRequestReviewDismissalRequest struct { + Message *string `json:"message,omitempty"` +} + +func (r PullRequestReviewDismissalRequest) String() string { + return Stringify(r) +} + +// ListReviews lists all reviews on the specified pull request. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#list-reviews-on-a-pull-request +func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo string, number int) ([]*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + var reviews []*PullRequestReview + resp, err := s.client.Do(ctx, req, &reviews) + if err != nil { + return nil, resp, err + } + + return reviews, resp, nil +} + +// GetReview fetches the specified pull request review. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review +func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number, reviewID int) (*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + review := new(PullRequestReview) + resp, err := s.client.Do(ctx, req, review) + if err != nil { + return nil, resp, err + } + + return review, resp, nil +} + +// DeletePendingReview deletes the specified pull request pending review. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review +func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number, reviewID int) (*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + review := new(PullRequestReview) + resp, err := s.client.Do(ctx, req, review) + if err != nil { + return nil, resp, err + } + + return review, resp, nil +} + +// ListReviewComments lists all the comments for the specified review. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-reviews-comments +func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number, reviewID int) ([]*PullRequestComment, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + var comments []*PullRequestComment + resp, err := s.client.Do(ctx, req, &comments) + if err != nil { + return nil, resp, err + } + + return comments, resp, nil +} + +// CreateReview creates a new review on the specified pull request. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review +func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo string, number int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) + + req, err := s.client.NewRequest("POST", u, review) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + r := new(PullRequestReview) + resp, err := s.client.Do(ctx, req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} + +// SubmitReview submits a specified review on the specified pull request. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review +func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number, reviewID int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID) + + req, err := s.client.NewRequest("POST", u, review) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + r := new(PullRequestReview) + resp, err := s.client.Do(ctx, req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} + +// DismissReview dismisses a specified review on the specified pull request. +// +// TODO: Follow up with GitHub support about an issue with this method's +// returned error format and remove this comment once it's fixed. +// Read more about it here - https://github.com/google/go-github/issues/540 +// +// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review +func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number, reviewID int, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID) + + req, err := s.client.NewRequest("PUT", u, review) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypePullRequestReviewsPreview) + + r := new(PullRequestReview) + resp, err := s.client.Do(ctx, req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil } diff --git a/vendor/github.com/google/go-github/github/reactions.go b/vendor/github.com/google/go-github/github/reactions.go index 03b131be9..739413d71 100644 --- a/vendor/github.com/google/go-github/github/reactions.go +++ b/vendor/github.com/google/go-github/github/reactions.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // ReactionsService provides access to the reactions-related functions in the // GitHub API. @@ -43,7 +46,7 @@ func (r Reaction) String() string { // ListCommentReactions lists the reactions for a commit comment. // // GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment -func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { +func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -59,7 +62,7 @@ func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt req.Header.Set("Accept", mediaTypeReactionsPreview) var m []*Reaction - resp, err := s.client.Do(req, &m) + resp, err := s.client.Do(ctx, req, &m) if err != nil { return nil, resp, err } @@ -72,7 +75,7 @@ func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt // previously created reaction will be returned with Status: 200 OK. // // GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment -func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { +func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) body := &Reaction{Content: String(content)} @@ -85,7 +88,7 @@ func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, cont req.Header.Set("Accept", mediaTypeReactionsPreview) m := &Reaction{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -96,7 +99,7 @@ func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, cont // ListIssueReactions lists the reactions for an issue. // // GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue -func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) { +func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -112,7 +115,7 @@ func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, op req.Header.Set("Accept", mediaTypeReactionsPreview) var m []*Reaction - resp, err := s.client.Do(req, &m) + resp, err := s.client.Do(ctx, req, &m) if err != nil { return nil, resp, err } @@ -125,7 +128,7 @@ func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, op // previously created reaction will be returned with Status: 200 OK. // // GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue -func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, content string) (*Reaction, *Response, error) { +func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) body := &Reaction{Content: String(content)} @@ -138,7 +141,7 @@ func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, co req.Header.Set("Accept", mediaTypeReactionsPreview) m := &Reaction{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -149,7 +152,7 @@ func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, co // ListIssueCommentReactions lists the reactions for an issue comment. // // GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment -func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { +func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -165,7 +168,7 @@ func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, req.Header.Set("Accept", mediaTypeReactionsPreview) var m []*Reaction - resp, err := s.client.Do(req, &m) + resp, err := s.client.Do(ctx, req, &m) if err != nil { return nil, resp, err } @@ -178,7 +181,7 @@ func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, // previously created reaction will be returned with Status: 200 OK. // // GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment -func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { +func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) body := &Reaction{Content: String(content)} @@ -191,7 +194,7 @@ func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, req.Header.Set("Accept", mediaTypeReactionsPreview) m := &Reaction{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -202,7 +205,7 @@ func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, // ListPullRequestCommentReactions lists the reactions for a pull request review comment. // // GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment -func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { +func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -218,7 +221,7 @@ func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, i req.Header.Set("Accept", mediaTypeReactionsPreview) var m []*Reaction - resp, err := s.client.Do(req, &m) + resp, err := s.client.Do(ctx, req, &m) if err != nil { return nil, resp, err } @@ -231,7 +234,7 @@ func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, i // previously created reaction will be returned with Status: 200 OK. // // GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment -func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { +func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) body := &Reaction{Content: String(content)} @@ -244,7 +247,7 @@ func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, i req.Header.Set("Accept", mediaTypeReactionsPreview) m := &Reaction{} - resp, err := s.client.Do(req, m) + resp, err := s.client.Do(ctx, req, m) if err != nil { return nil, resp, err } @@ -255,7 +258,7 @@ func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, i // DeleteReaction deletes a reaction. // // GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive -func (s *ReactionsService) DeleteReaction(id int) (*Response, error) { +func (s *ReactionsService) DeleteReaction(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("reactions/%v", id) req, err := s.client.NewRequest("DELETE", u, nil) @@ -266,5 +269,5 @@ func (s *ReactionsService) DeleteReaction(id int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/repos.go b/vendor/github.com/google/go-github/github/repos.go index 040cd31e0..058f149dd 100644 --- a/vendor/github.com/google/go-github/github/repos.go +++ b/vendor/github.com/google/go-github/github/repos.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "strings" ) @@ -13,7 +14,7 @@ import ( // RepositoriesService handles communication with the repository related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/repos/ +// GitHub API docs: https://developer.github.com/v3/repos/ type RepositoriesService service // Repository represents a GitHub repository. @@ -151,11 +152,11 @@ type RepositoryListOptions struct { ListOptions } -// List the repositories for a user. Passing the empty string will list +// List the repositories for a user. Passing the empty string will list // repositories for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/repos/#list-user-repositories -func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-user-repositories +func (s *RepositoriesService) List(ctx context.Context, user string, opt *RepositoryListOptions) ([]*Repository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/repos", user) @@ -175,20 +176,20 @@ func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]* // TODO: remove custom Accept header when license support fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - repos := new([]*Repository) - resp, err := s.client.Do(req, repos) + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } // RepositoryListByOrgOptions specifies the optional parameters to the // RepositoriesService.ListByOrg method. type RepositoryListByOrgOptions struct { - // Type of repositories to list. Possible values are: all, public, private, - // forks, sources, member. Default is "all". + // Type of repositories to list. Possible values are: all, public, private, + // forks, sources, member. Default is "all". Type string `url:"type,omitempty"` ListOptions @@ -196,8 +197,8 @@ type RepositoryListByOrgOptions struct { // ListByOrg lists the repositories for an organization. // -// GitHub API docs: http://developer.github.com/v3/repos/#list-organization-repositories -func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-organization-repositories +func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *RepositoryListByOrgOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/repos", org) u, err := addOptions(u, opt) if err != nil { @@ -212,13 +213,13 @@ func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOpti // TODO: remove custom Accept header when license support fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - repos := new([]*Repository) - resp, err := s.client.Do(req, repos) + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } // RepositoryListAllOptions specifies the optional parameters to the @@ -232,8 +233,8 @@ type RepositoryListAllOptions struct { // ListAll lists all GitHub repositories in the order that they were created. // -// GitHub API docs: http://developer.github.com/v3/repos/#list-all-public-repositories -func (s *RepositoriesService) ListAll(opt *RepositoryListAllOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-all-public-repositories +func (s *RepositoriesService) ListAll(ctx context.Context, opt *RepositoryListAllOptions) ([]*Repository, *Response, error) { u, err := addOptions("repositories", opt) if err != nil { return nil, nil, err @@ -244,21 +245,21 @@ func (s *RepositoriesService) ListAll(opt *RepositoryListAllOptions) ([]*Reposit return nil, nil, err } - repos := new([]*Repository) - resp, err := s.client.Do(req, repos) + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } -// Create a new repository. If an organization is specified, the new -// repository will be created under that org. If the empty string is +// Create a new repository. If an organization is specified, the new +// repository will be created under that org. If the empty string is // specified, it will be created for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/repos/#create -func (s *RepositoriesService) Create(org string, repo *Repository) (*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#create +func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) { var u string if org != "" { u = fmt.Sprintf("orgs/%v/repos", org) @@ -272,18 +273,18 @@ func (s *RepositoriesService) Create(org string, repo *Repository) (*Repository, } r := new(Repository) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // Get fetches a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/#get -func (s *RepositoriesService) Get(owner, repo string) (*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#get +func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -296,18 +297,18 @@ func (s *RepositoriesService) Get(owner, repo string) (*Repository, *Response, e req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) repository := new(Repository) - resp, err := s.client.Do(req, repository) + resp, err := s.client.Do(ctx, req, repository) if err != nil { return nil, resp, err } - return repository, resp, err + return repository, resp, nil } // GetByID fetches a repository. // // Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id. -func (s *RepositoriesService) GetByID(id int) (*Repository, *Response, error) { +func (s *RepositoriesService) GetByID(ctx context.Context, id int) (*Repository, *Response, error) { u := fmt.Sprintf("repositories/%d", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -319,18 +320,18 @@ func (s *RepositoriesService) GetByID(id int) (*Repository, *Response, error) { req.Header.Set("Accept", mediaTypeLicensesPreview) repository := new(Repository) - resp, err := s.client.Do(req, repository) + resp, err := s.client.Do(ctx, req, repository) if err != nil { return nil, resp, err } - return repository, resp, err + return repository, resp, nil } // Edit updates a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/#edit -func (s *RepositoriesService) Edit(owner, repo string, repository *Repository) (*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#edit +func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repository *Repository) (*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v", owner, repo) req, err := s.client.NewRequest("PATCH", u, repository) if err != nil { @@ -338,28 +339,28 @@ func (s *RepositoriesService) Edit(owner, repo string, repository *Repository) ( } // TODO: Remove this preview header after API is fully vetted. - req.Header.Add("Accept", mediaTypeSquashPreview) + req.Header.Set("Accept", mediaTypeSquashPreview) r := new(Repository) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // Delete a repository. // // GitHub API docs: https://developer.github.com/v3/repos/#delete-a-repository -func (s *RepositoriesService) Delete(owner, repo string) (*Response, error) { +func (s *RepositoriesService) Delete(ctx context.Context, owner, repo string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v", owner, repo) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Contributor represents a repository contributor @@ -395,8 +396,8 @@ type ListContributorsOptions struct { // ListContributors lists contributors for a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/#list-contributors -func (s *RepositoriesService) ListContributors(owner string, repository string, opt *ListContributorsOptions) ([]*Contributor, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-contributors +func (s *RepositoriesService) ListContributors(ctx context.Context, owner string, repository string, opt *ListContributorsOptions) ([]*Contributor, *Response, error) { u := fmt.Sprintf("repos/%v/%v/contributors", owner, repository) u, err := addOptions(u, opt) if err != nil { @@ -408,13 +409,13 @@ func (s *RepositoriesService) ListContributors(owner string, repository string, return nil, nil, err } - contributor := new([]*Contributor) - resp, err := s.client.Do(req, contributor) + var contributor []*Contributor + resp, err := s.client.Do(ctx, req, &contributor) if err != nil { return nil, nil, err } - return *contributor, resp, err + return contributor, resp, nil } // ListLanguages lists languages for the specified repository. The returned map @@ -426,8 +427,8 @@ func (s *RepositoriesService) ListContributors(owner string, repository string, // "Python": 7769 // } // -// GitHub API Docs: http://developer.github.com/v3/repos/#list-languages -func (s *RepositoriesService) ListLanguages(owner string, repo string) (map[string]int, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-languages +func (s *RepositoriesService) ListLanguages(ctx context.Context, owner string, repo string) (map[string]int, *Response, error) { u := fmt.Sprintf("repos/%v/%v/languages", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -435,18 +436,18 @@ func (s *RepositoriesService) ListLanguages(owner string, repo string) (map[stri } languages := make(map[string]int) - resp, err := s.client.Do(req, &languages) + resp, err := s.client.Do(ctx, req, &languages) if err != nil { return nil, resp, err } - return languages, resp, err + return languages, resp, nil } // ListTeams lists the teams for the specified repository. // // GitHub API docs: https://developer.github.com/v3/repos/#list-teams -func (s *RepositoriesService) ListTeams(owner string, repo string, opt *ListOptions) ([]*Team, *Response, error) { +func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("repos/%v/%v/teams", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -458,13 +459,13 @@ func (s *RepositoriesService) ListTeams(owner string, repo string, opt *ListOpti return nil, nil, err } - teams := new([]*Team) - resp, err := s.client.Do(req, teams) + var teams []*Team + resp, err := s.client.Do(ctx, req, &teams) if err != nil { return nil, resp, err } - return *teams, resp, err + return teams, resp, nil } // RepositoryTag represents a repository tag. @@ -478,7 +479,7 @@ type RepositoryTag struct { // ListTags lists tags for the specified repository. // // GitHub API docs: https://developer.github.com/v3/repos/#list-tags -func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptions) ([]*RepositoryTag, *Response, error) { +func (s *RepositoriesService) ListTags(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*RepositoryTag, *Response, error) { u := fmt.Sprintf("repos/%v/%v/tags", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -490,13 +491,13 @@ func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptio return nil, nil, err } - tags := new([]*RepositoryTag) - resp, err := s.client.Do(req, tags) + var tags []*RepositoryTag + resp, err := s.client.Do(ctx, req, &tags) if err != nil { return nil, resp, err } - return *tags, resp, err + return tags, resp, nil } // Branch represents a repository branch @@ -508,34 +509,42 @@ type Branch struct { // Protection represents a repository branch's protection. type Protection struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - Restrictions *BranchRestrictions `json:"restrictions"` + RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` + RequiredPullRequestReviews *RequiredPullRequestReviews `json:"required_pull_request_reviews"` + Restrictions *BranchRestrictions `json:"restrictions"` } // ProtectionRequest represents a request to create/edit a branch's protection. type ProtectionRequest struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - Restrictions *BranchRestrictionsRequest `json:"restrictions"` + RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` + RequiredPullRequestReviews *RequiredPullRequestReviews `json:"required_pull_request_reviews"` + Restrictions *BranchRestrictionsRequest `json:"restrictions"` } // RequiredStatusChecks represents the protection status of a individual branch. type RequiredStatusChecks struct { - // Enforce required status checks for repository administrators. - IncludeAdmins *bool `json:"include_admins,omitempty"` - // Require branches to be up to date before merging. - Strict *bool `json:"strict,omitempty"` + // Enforce required status checks for repository administrators. (Required.) + IncludeAdmins bool `json:"include_admins"` + // Require branches to be up to date before merging. (Required.) + Strict bool `json:"strict"` // The list of status checks to require in order to merge into this - // branch. - Contexts *[]string `json:"contexts,omitempty"` + // branch. (Required; use []string{} instead of nil for empty list.) + Contexts []string `json:"contexts"` +} + +// RequiredPullRequestReviews represents the protection configuration for pull requests. +type RequiredPullRequestReviews struct { + // Enforce pull request reviews for repository administrators. (Required.) + IncludeAdmins bool `json:"include_admins"` } // BranchRestrictions represents the restriction that only certain users or // teams may push to a branch. type BranchRestrictions struct { // The list of user logins with push access. - Users []*User `json:"users,omitempty"` + Users []*User `json:"users"` // The list of team slugs with push access. - Teams []*Team `json:"teams,omitempty"` + Teams []*Team `json:"teams"` } // BranchRestrictionsRequest represents the request to create/edit the @@ -543,16 +552,16 @@ type BranchRestrictions struct { // separate from BranchRestrictions above because the request structure is // different from the response structure. type BranchRestrictionsRequest struct { - // The list of user logins with push access. - Users *[]string `json:"users,omitempty"` - // The list of team slugs with push access. - Teams *[]string `json:"teams,omitempty"` + // The list of user logins with push access. (Required; use []string{} instead of nil for empty list.) + Users []string `json:"users"` + // The list of team slugs with push access. (Required; use []string{} instead of nil for empty list.) + Teams []string `json:"teams"` } // ListBranches lists branches for the specified repository. // -// GitHub API docs: http://developer.github.com/v3/repos/#list-branches -func (s *RepositoriesService) ListBranches(owner string, repo string, opt *ListOptions) ([]*Branch, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/#list-branches +func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Branch, *Response, error) { u := fmt.Sprintf("repos/%v/%v/branches", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -567,19 +576,19 @@ func (s *RepositoriesService) ListBranches(owner string, repo string, opt *ListO // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) - branches := new([]*Branch) - resp, err := s.client.Do(req, branches) + var branches []*Branch + resp, err := s.client.Do(ctx, req, &branches) if err != nil { return nil, resp, err } - return *branches, resp, err + return branches, resp, nil } // GetBranch gets the specified branch for a repository. // // GitHub API docs: https://developer.github.com/v3/repos/#get-branch -func (s *RepositoriesService) GetBranch(owner, repo, branch string) (*Branch, *Response, error) { +func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch string) (*Branch, *Response, error) { u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branch) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -590,18 +599,18 @@ func (s *RepositoriesService) GetBranch(owner, repo, branch string) (*Branch, *R req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) b := new(Branch) - resp, err := s.client.Do(req, b) + resp, err := s.client.Do(ctx, req, b) if err != nil { return nil, resp, err } - return b, resp, err + return b, resp, nil } // GetBranchProtection gets the protection of a given branch. // // GitHub API docs: https://developer.github.com/v3/repos/branches/#get-branch-protection -func (s *RepositoriesService) GetBranchProtection(owner, repo, branch string) (*Protection, *Response, error) { +func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, repo, branch string) (*Protection, *Response, error) { u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -612,18 +621,61 @@ func (s *RepositoriesService) GetBranchProtection(owner, repo, branch string) (* req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) p := new(Protection) - resp, err := s.client.Do(req, p) + resp, err := s.client.Do(ctx, req, p) if err != nil { return nil, resp, err } - return p, resp, err + return p, resp, nil +} + +// GetRequiredStatusChecks gets the required status checks for a given protected branch. +// +// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-status-checks-of-protected-branch +func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*RequiredStatusChecks, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) + + p := new(RequiredStatusChecks) + resp, err := s.client.Do(ctx, req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, nil +} + +// ListRequiredStatusChecksContexts lists the required status checks contexts for a given protected branch. +// +// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-required-status-checks-contexts-of-protected-branch +func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Context, owner, repo, branch string) (contexts []string, resp *Response, err error) { + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, branch) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) + + resp, err = s.client.Do(ctx, req, &contexts) + if err != nil { + return nil, resp, err + } + + return contexts, resp, nil } // UpdateBranchProtection updates the protection of a given branch. // // GitHub API docs: https://developer.github.com/v3/repos/branches/#update-branch-protection -func (s *RepositoriesService) UpdateBranchProtection(owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) { +func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) { u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) req, err := s.client.NewRequest("PUT", u, preq) if err != nil { @@ -634,18 +686,18 @@ func (s *RepositoriesService) UpdateBranchProtection(owner, repo, branch string, req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) p := new(Protection) - resp, err := s.client.Do(req, p) + resp, err := s.client.Do(ctx, req, p) if err != nil { return nil, resp, err } - return p, resp, err + return p, resp, nil } // RemoveBranchProtection removes the protection of a given branch. // // GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-branch-protection -func (s *RepositoriesService) RemoveBranchProtection(owner, repo, branch string) (*Response, error) { +func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, repo, branch string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -655,13 +707,13 @@ func (s *RepositoriesService) RemoveBranchProtection(owner, repo, branch string) // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // License gets the contents of a repository's license if one is detected. // // GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license -func (s *RepositoriesService) License(owner, repo string) (*RepositoryLicense, *Response, error) { +func (s *RepositoriesService) License(ctx context.Context, owner, repo string) (*RepositoryLicense, *Response, error) { u := fmt.Sprintf("repos/%v/%v/license", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -669,10 +721,10 @@ func (s *RepositoriesService) License(owner, repo string) (*RepositoryLicense, * } r := &RepositoryLicense{} - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_collaborators.go b/vendor/github.com/google/go-github/github/repos_collaborators.go index 68a9f466c..76e8a1f0a 100644 --- a/vendor/github.com/google/go-github/github/repos_collaborators.go +++ b/vendor/github.com/google/go-github/github/repos_collaborators.go @@ -5,12 +5,15 @@ package github -import "fmt" +import ( + "context" + "fmt" +) -// ListCollaborators lists the Github users that have access to the repository. +// ListCollaborators lists the GitHub users that have access to the repository. // -// GitHub API docs: http://developer.github.com/v3/repos/collaborators/#list -func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#list +func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -22,33 +25,59 @@ func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOpt return nil, nil, err } - users := new([]*User) - resp, err := s.client.Do(req, users) + var users []*User + resp, err := s.client.Do(ctx, req, &users) if err != nil { return nil, resp, err } - return *users, resp, err + return users, resp, nil } -// IsCollaborator checks whether the specified Github user has collaborator +// IsCollaborator checks whether the specified GitHub user has collaborator // access to the given repo. // Note: This will return false if the user is not a collaborator OR the user // is not a GitHub user. // -// GitHub API docs: http://developer.github.com/v3/repos/collaborators/#get -func (s *RepositoriesService) IsCollaborator(owner, repo, user string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#get +func (s *RepositoriesService) IsCollaborator(ctx context.Context, owner, repo, user string) (bool, *Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) isCollab, err := parseBoolResponse(err) return isCollab, resp, err } +// RepositoryPermissionLevel represents the permission level an organization +// member has for a given repository. +type RepositoryPermissionLevel struct { + // Possible values: "admin", "write", "read", "none" + Permission *string `json:"permission,omitempty"` + + User *User `json:"user,omitempty"` +} + +// GetPermissionLevel retrieves the specific permission level a collaborator has for a given repository. +// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level +func (s *RepositoriesService) GetPermissionLevel(ctx context.Context, owner, repo, user string) (*RepositoryPermissionLevel, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/collaborators/%v/permission", owner, repo, user) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + rpl := new(RepositoryPermissionLevel) + resp, err := s.client.Do(ctx, req, rpl) + if err != nil { + return nil, resp, err + } + return rpl, resp, nil +} + // RepositoryAddCollaboratorOptions specifies the optional parameters to the // RepositoriesService.AddCollaborator method. type RepositoryAddCollaboratorOptions struct { @@ -58,14 +87,14 @@ type RepositoryAddCollaboratorOptions struct { // push - team members can pull and push, but not administer this repository // admin - team members can pull, push and administer this repository // - // Default value is "push". This option is only valid for organization-owned repositories. + // Default value is "push". This option is only valid for organization-owned repositories. Permission string `json:"permission,omitempty"` } -// AddCollaborator adds the specified Github user as collaborator to the given repo. +// AddCollaborator adds the specified GitHub user as collaborator to the given repo. // // GitHub API docs: https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator -func (s *RepositoriesService) AddCollaborator(owner, repo, user string, opt *RepositoryAddCollaboratorOptions) (*Response, error) { +func (s *RepositoriesService) AddCollaborator(ctx context.Context, owner, repo, user string, opt *RepositoryAddCollaboratorOptions) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { @@ -75,18 +104,18 @@ func (s *RepositoriesService) AddCollaborator(owner, repo, user string, opt *Rep // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } -// RemoveCollaborator removes the specified Github user as collaborator from the given repo. +// RemoveCollaborator removes the specified GitHub user as collaborator from the given repo. // Note: Does not return error if a valid user that is not a collaborator is removed. // -// GitHub API docs: http://developer.github.com/v3/repos/collaborators/#remove-collaborator -func (s *RepositoriesService) RemoveCollaborator(owner, repo, user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#remove-collaborator +func (s *RepositoriesService) RemoveCollaborator(ctx context.Context, owner, repo, user string) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/repos_comments.go b/vendor/github.com/google/go-github/github/repos_comments.go index 34a8d0208..4830ee220 100644 --- a/vendor/github.com/google/go-github/github/repos_comments.go +++ b/vendor/github.com/google/go-github/github/repos_comments.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -34,8 +35,8 @@ func (r RepositoryComment) String() string { // ListComments lists all the comments for the repository. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository -func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository +func (s *RepositoriesService) ListComments(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -50,19 +51,19 @@ func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - comments := new([]*RepositoryComment) - resp, err := s.client.Do(req, comments) + var comments []*RepositoryComment + resp, err := s.client.Do(ctx, req, &comments) if err != nil { return nil, resp, err } - return *comments, resp, err + return comments, resp, nil } // ListCommitComments lists all the comments for a given commit SHA. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit -func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit +func (s *RepositoriesService) ListCommitComments(ctx context.Context, owner, repo, sha string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) u, err := addOptions(u, opt) if err != nil { @@ -77,20 +78,20 @@ func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *L // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeReactionsPreview) - comments := new([]*RepositoryComment) - resp, err := s.client.Do(req, comments) + var comments []*RepositoryComment + resp, err := s.client.Do(ctx, req, &comments) if err != nil { return nil, resp, err } - return *comments, resp, err + return comments, resp, nil } // CreateComment creates a comment for the given commit. // Note: GitHub allows for comments to be created for non-existing files and positions. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#create-a-commit-comment -func (s *RepositoriesService) CreateComment(owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#create-a-commit-comment +func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) req, err := s.client.NewRequest("POST", u, comment) if err != nil { @@ -98,18 +99,18 @@ func (s *RepositoriesService) CreateComment(owner, repo, sha string, comment *Re } c := new(RepositoryComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // GetComment gets a single comment from a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment -func (s *RepositoriesService) GetComment(owner, repo string, id int) (*RepositoryComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment +func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int) (*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -120,18 +121,18 @@ func (s *RepositoriesService) GetComment(owner, repo string, id int) (*Repositor req.Header.Set("Accept", mediaTypeReactionsPreview) c := new(RepositoryComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // UpdateComment updates the body of a single comment. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#update-a-commit-comment -func (s *RepositoriesService) UpdateComment(owner, repo string, id int, comment *RepositoryComment) (*RepositoryComment, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment +func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int, comment *RepositoryComment) (*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, comment) if err != nil { @@ -139,22 +140,22 @@ func (s *RepositoriesService) UpdateComment(owner, repo string, id int, comment } c := new(RepositoryComment) - resp, err := s.client.Do(req, c) + resp, err := s.client.Do(ctx, req, c) if err != nil { return nil, resp, err } - return c, resp, err + return c, resp, nil } // DeleteComment deletes a single comment from a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/comments/#delete-a-commit-comment -func (s *RepositoriesService) DeleteComment(owner, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment +func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/repos_commits.go b/vendor/github.com/google/go-github/github/repos_commits.go index 22e8fca87..e516f1afd 100644 --- a/vendor/github.com/google/go-github/github/repos_commits.go +++ b/vendor/github.com/google/go-github/github/repos_commits.go @@ -7,6 +7,7 @@ package github import ( "bytes" + "context" "fmt" "time" ) @@ -107,8 +108,8 @@ type CommitsListOptions struct { // ListCommits lists the commits of a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/commits/#list -func (s *RepositoriesService) ListCommits(owner, repo string, opt *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/commits/#list +func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo string, opt *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -120,21 +121,21 @@ func (s *RepositoriesService) ListCommits(owner, repo string, opt *CommitsListOp return nil, nil, err } - commits := new([]*RepositoryCommit) - resp, err := s.client.Do(req, commits) + var commits []*RepositoryCommit + resp, err := s.client.Do(ctx, req, &commits) if err != nil { return nil, resp, err } - return *commits, resp, err + return commits, resp, nil } // GetCommit fetches the specified commit, including all details about it. // todo: support media formats - https://github.com/google/go-github/issues/6 // -// GitHub API docs: http://developer.github.com/v3/repos/commits/#get-a-single-commit -// See also: http://developer.github.com//v3/git/commits/#get-a-single-commit provides the same functionality -func (s *RepositoriesService) GetCommit(owner, repo, sha string) (*RepositoryCommit, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit +// See also: https://developer.github.com//v3/git/commits/#get-a-single-commit provides the same functionality +func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) req, err := s.client.NewRequest("GET", u, nil) @@ -146,19 +147,19 @@ func (s *RepositoriesService) GetCommit(owner, repo, sha string) (*RepositoryCom req.Header.Set("Accept", mediaTypeGitSigningPreview) commit := new(RepositoryCommit) - resp, err := s.client.Do(req, commit) + resp, err := s.client.Do(ctx, req, commit) if err != nil { return nil, resp, err } - return commit, resp, err + return commit, resp, nil } -// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is +// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is // supplied and no new commits have occurred, a 304 Unmodified response is returned. // // GitHub API docs: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference -func (s *RepositoriesService) GetCommitSHA1(owner, repo, ref, lastSHA string) (string, *Response, error) { +func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, ref) req, err := s.client.NewRequest("GET", u, nil) @@ -172,19 +173,19 @@ func (s *RepositoriesService) GetCommitSHA1(owner, repo, ref, lastSHA string) (s req.Header.Set("Accept", mediaTypeV3SHA) var buf bytes.Buffer - resp, err := s.client.Do(req, &buf) + resp, err := s.client.Do(ctx, req, &buf) if err != nil { return "", resp, err } - return buf.String(), resp, err + return buf.String(), resp, nil } // CompareCommits compares a range of commits with each other. // todo: support media formats - https://github.com/google/go-github/issues/6 // -// GitHub API docs: http://developer.github.com/v3/repos/commits/index.html#compare-two-commits -func (s *RepositoriesService) CompareCommits(owner, repo string, base, head string) (*CommitsComparison, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/commits/index.html#compare-two-commits +func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) req, err := s.client.NewRequest("GET", u, nil) @@ -193,10 +194,10 @@ func (s *RepositoriesService) CompareCommits(owner, repo string, base, head stri } comp := new(CommitsComparison) - resp, err := s.client.Do(req, comp) + resp, err := s.client.Do(ctx, req, comp) if err != nil { return nil, resp, err } - return comp, resp, err + return comp, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_contents.go b/vendor/github.com/google/go-github/github/repos_contents.go index 7b08cf04a..dfcbe33d2 100644 --- a/vendor/github.com/google/go-github/github/repos_contents.go +++ b/vendor/github.com/google/go-github/github/repos_contents.go @@ -4,14 +4,14 @@ // license that can be found in the LICENSE file. // Repository contents API methods. -// http://developer.github.com/v3/repos/contents/ +// GitHub API docs: https://developer.github.com/v3/repos/contents/ package github import ( + "context" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -64,20 +64,6 @@ func (r RepositoryContent) String() string { return Stringify(r) } -// Decode decodes the file content if it is base64 encoded. -// -// Deprecated: Use GetContent instead. -func (r *RepositoryContent) Decode() ([]byte, error) { - if *r.Encoding != "base64" { - return nil, errors.New("cannot decode non-base64") - } - o, err := base64.StdEncoding.DecodeString(*r.Content) - if err != nil { - return nil, err - } - return o, nil -} - // GetContent returns the content of r, decoding it if necessary. func (r *RepositoryContent) GetContent() (string, error) { var encoding string @@ -101,8 +87,8 @@ func (r *RepositoryContent) GetContent() (string, error) { // GetReadme gets the Readme file for the repository. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#get-the-readme -func (s *RepositoriesService) GetReadme(owner, repo string, opt *RepositoryContentGetOptions) (*RepositoryContent, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-the-readme +func (s *RepositoriesService) GetReadme(ctx context.Context, owner, repo string, opt *RepositoryContentGetOptions) (*RepositoryContent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/readme", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -113,21 +99,21 @@ func (s *RepositoriesService) GetReadme(owner, repo string, opt *RepositoryConte return nil, nil, err } readme := new(RepositoryContent) - resp, err := s.client.Do(req, readme) + resp, err := s.client.Do(ctx, req, readme) if err != nil { return nil, resp, err } - return readme, resp, err + return readme, resp, nil } // DownloadContents returns an io.ReadCloser that reads the contents of the // specified file. This function will work with files of any size, as opposed // to GetContents which is limited to 1 Mb files. It is the caller's // responsibility to close the ReadCloser. -func (s *RepositoriesService) DownloadContents(owner, repo, filepath string, opt *RepositoryContentGetOptions) (io.ReadCloser, error) { +func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, filepath string, opt *RepositoryContentGetOptions) (io.ReadCloser, error) { dir := path.Dir(filepath) filename := path.Base(filepath) - _, dirContents, _, err := s.GetContents(owner, repo, dir, opt) + _, dirContents, _, err := s.GetContents(ctx, owner, repo, dir, opt) if err != nil { return nil, err } @@ -153,8 +139,8 @@ func (s *RepositoriesService) DownloadContents(owner, repo, filepath string, opt // as possible, both result types will be returned but only one will contain a // value and the other will be nil. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#get-contents -func (s *RepositoriesService) GetContents(owner, repo, path string, opt *RepositoryContentGetOptions) (fileContent *RepositoryContent, directoryContent []*RepositoryContent, resp *Response, err error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-contents +func (s *RepositoriesService) GetContents(ctx context.Context, owner, repo, path string, opt *RepositoryContentGetOptions) (fileContent *RepositoryContent, directoryContent []*RepositoryContent, resp *Response, err error) { escapedPath := (&url.URL{Path: path}).String() u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, escapedPath) u, err = addOptions(u, opt) @@ -166,17 +152,17 @@ func (s *RepositoriesService) GetContents(owner, repo, path string, opt *Reposit return nil, nil, nil, err } var rawJSON json.RawMessage - resp, err = s.client.Do(req, &rawJSON) + resp, err = s.client.Do(ctx, req, &rawJSON) if err != nil { return nil, nil, resp, err } fileUnmarshalError := json.Unmarshal(rawJSON, &fileContent) if fileUnmarshalError == nil { - return fileContent, nil, resp, fileUnmarshalError + return fileContent, nil, resp, nil } directoryUnmarshalError := json.Unmarshal(rawJSON, &directoryContent) if directoryUnmarshalError == nil { - return nil, directoryContent, resp, directoryUnmarshalError + return nil, directoryContent, resp, nil } return nil, nil, resp, fmt.Errorf("unmarshalling failed for both file and directory content: %s and %s ", fileUnmarshalError, directoryUnmarshalError) } @@ -184,55 +170,55 @@ func (s *RepositoriesService) GetContents(owner, repo, path string, opt *Reposit // CreateFile creates a new file in a repository at the given path and returns // the commit and file metadata. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#create-a-file -func (s *RepositoriesService) CreateFile(owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#create-a-file +func (s *RepositoriesService) CreateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, nil, err } createResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(req, createResponse) + resp, err := s.client.Do(ctx, req, createResponse) if err != nil { return nil, resp, err } - return createResponse, resp, err + return createResponse, resp, nil } // UpdateFile updates a file in a repository at the given path and returns the // commit and file metadata. Requires the blob SHA of the file being updated. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#update-a-file -func (s *RepositoriesService) UpdateFile(owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#update-a-file +func (s *RepositoriesService) UpdateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) req, err := s.client.NewRequest("PUT", u, opt) if err != nil { return nil, nil, err } updateResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(req, updateResponse) + resp, err := s.client.Do(ctx, req, updateResponse) if err != nil { return nil, resp, err } - return updateResponse, resp, err + return updateResponse, resp, nil } // DeleteFile deletes a file from a repository and returns the commit. // Requires the blob SHA of the file to be deleted. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#delete-a-file -func (s *RepositoriesService) DeleteFile(owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#delete-a-file +func (s *RepositoriesService) DeleteFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) req, err := s.client.NewRequest("DELETE", u, opt) if err != nil { return nil, nil, err } deleteResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(req, deleteResponse) + resp, err := s.client.Do(ctx, req, deleteResponse) if err != nil { return nil, resp, err } - return deleteResponse, resp, err + return deleteResponse, resp, nil } // archiveFormat is used to define the archive type when calling GetArchiveLink. @@ -250,8 +236,8 @@ const ( // repository. The archiveFormat can be specified by either the github.Tarball // or github.Zipball constant. // -// GitHub API docs: http://developer.github.com/v3/repos/contents/#get-archive-link -func (s *RepositoriesService) GetArchiveLink(owner, repo string, archiveformat archiveFormat, opt *RepositoryContentGetOptions) (*url.URL, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-archive-link +func (s *RepositoriesService) GetArchiveLink(ctx context.Context, owner, repo string, archiveformat archiveFormat, opt *RepositoryContentGetOptions) (*url.URL, *Response, error) { u := fmt.Sprintf("repos/%s/%s/%s", owner, repo, archiveformat) if opt != nil && opt.Ref != "" { u += fmt.Sprintf("/%s", opt.Ref) @@ -262,6 +248,7 @@ func (s *RepositoriesService) GetArchiveLink(owner, repo string, archiveformat a } var resp *http.Response // Use http.DefaultTransport if no custom Transport is configured + ctx, req = withContext(ctx, req) if s.client.client.Transport == nil { resp, err = http.DefaultTransport.RoundTrip(req) } else { diff --git a/vendor/github.com/google/go-github/github/repos_deployments.go b/vendor/github.com/google/go-github/github/repos_deployments.go index cf245207f..9054ca947 100644 --- a/vendor/github.com/google/go-github/github/repos_deployments.go +++ b/vendor/github.com/google/go-github/github/repos_deployments.go @@ -6,6 +6,7 @@ package github import ( + "context" "encoding/json" "fmt" ) @@ -61,7 +62,7 @@ type DeploymentsListOptions struct { // ListDeployments lists the deployments of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployments -func (s *RepositoriesService) ListDeployments(owner, repo string, opt *DeploymentsListOptions) ([]*Deployment, *Response, error) { +func (s *RepositoriesService) ListDeployments(ctx context.Context, owner, repo string, opt *DeploymentsListOptions) ([]*Deployment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -73,19 +74,19 @@ func (s *RepositoriesService) ListDeployments(owner, repo string, opt *Deploymen return nil, nil, err } - deployments := new([]*Deployment) - resp, err := s.client.Do(req, deployments) + var deployments []*Deployment + resp, err := s.client.Do(ctx, req, &deployments) if err != nil { return nil, resp, err } - return *deployments, resp, err + return deployments, resp, nil } // GetDeployment returns a single deployment of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment -func (s *RepositoriesService) GetDeployment(owner, repo string, deploymentID int) (*Deployment, *Response, error) { +func (s *RepositoriesService) GetDeployment(ctx context.Context, owner, repo string, deploymentID int) (*Deployment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments/%v", owner, repo, deploymentID) req, err := s.client.NewRequest("GET", u, nil) @@ -94,18 +95,18 @@ func (s *RepositoriesService) GetDeployment(owner, repo string, deploymentID int } deployment := new(Deployment) - resp, err := s.client.Do(req, deployment) + resp, err := s.client.Do(ctx, req, deployment) if err != nil { return nil, resp, err } - return deployment, resp, err + return deployment, resp, nil } // CreateDeployment creates a new deployment for a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment -func (s *RepositoriesService) CreateDeployment(owner, repo string, request *DeploymentRequest) (*Deployment, *Response, error) { +func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo string, request *DeploymentRequest) (*Deployment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) req, err := s.client.NewRequest("POST", u, request) @@ -117,12 +118,12 @@ func (s *RepositoriesService) CreateDeployment(owner, repo string, request *Depl req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) d := new(Deployment) - resp, err := s.client.Do(req, d) + resp, err := s.client.Do(ctx, req, d) if err != nil { return nil, resp, err } - return d, resp, err + return d, resp, nil } // DeploymentStatus represents the status of a @@ -144,7 +145,6 @@ type DeploymentStatus struct { // DeploymentStatusRequest represents a deployment request type DeploymentStatusRequest struct { State *string `json:"state,omitempty"` - TargetURL *string `json:"target_url,omitempty"` // Deprecated. Use LogURL instead. LogURL *string `json:"log_url,omitempty"` Description *string `json:"description,omitempty"` EnvironmentURL *string `json:"environment_url,omitempty"` @@ -154,7 +154,7 @@ type DeploymentStatusRequest struct { // ListDeploymentStatuses lists the statuses of a given deployment of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployment-statuses -func (s *RepositoriesService) ListDeploymentStatuses(owner, repo string, deployment int, opt *ListOptions) ([]*DeploymentStatus, *Response, error) { +func (s *RepositoriesService) ListDeploymentStatuses(ctx context.Context, owner, repo string, deployment int, opt *ListOptions) ([]*DeploymentStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) u, err := addOptions(u, opt) if err != nil { @@ -166,19 +166,19 @@ func (s *RepositoriesService) ListDeploymentStatuses(owner, repo string, deploym return nil, nil, err } - statuses := new([]*DeploymentStatus) - resp, err := s.client.Do(req, statuses) + var statuses []*DeploymentStatus + resp, err := s.client.Do(ctx, req, &statuses) if err != nil { return nil, resp, err } - return *statuses, resp, err + return statuses, resp, nil } // GetDeploymentStatus returns a single deployment status of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment-status -func (s *RepositoriesService) GetDeploymentStatus(owner, repo string, deploymentID, deploymentStatusID int) (*DeploymentStatus, *Response, error) { +func (s *RepositoriesService) GetDeploymentStatus(ctx context.Context, owner, repo string, deploymentID, deploymentStatusID int) (*DeploymentStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses/%v", owner, repo, deploymentID, deploymentStatusID) req, err := s.client.NewRequest("GET", u, nil) @@ -190,18 +190,18 @@ func (s *RepositoriesService) GetDeploymentStatus(owner, repo string, deployment req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) d := new(DeploymentStatus) - resp, err := s.client.Do(req, d) + resp, err := s.client.Do(ctx, req, d) if err != nil { return nil, resp, err } - return d, resp, err + return d, resp, nil } // CreateDeploymentStatus creates a new status for a deployment. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment-status -func (s *RepositoriesService) CreateDeploymentStatus(owner, repo string, deployment int, request *DeploymentStatusRequest) (*DeploymentStatus, *Response, error) { +func (s *RepositoriesService) CreateDeploymentStatus(ctx context.Context, owner, repo string, deployment int, request *DeploymentStatusRequest) (*DeploymentStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) req, err := s.client.NewRequest("POST", u, request) @@ -213,10 +213,10 @@ func (s *RepositoriesService) CreateDeploymentStatus(owner, repo string, deploym req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) d := new(DeploymentStatus) - resp, err := s.client.Do(req, d) + resp, err := s.client.Do(ctx, req, d) if err != nil { return nil, resp, err } - return d, resp, err + return d, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_forks.go b/vendor/github.com/google/go-github/github/repos_forks.go index c88f3d3f0..6b5e4eabb 100644 --- a/vendor/github.com/google/go-github/github/repos_forks.go +++ b/vendor/github.com/google/go-github/github/repos_forks.go @@ -5,13 +5,16 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // RepositoryListForksOptions specifies the optional parameters to the // RepositoriesService.ListForks method. type RepositoryListForksOptions struct { - // How to sort the forks list. Possible values are: newest, oldest, - // watchers. Default is "newest". + // How to sort the forks list. Possible values are: newest, oldest, + // watchers. Default is "newest". Sort string `url:"sort,omitempty"` ListOptions @@ -19,8 +22,8 @@ type RepositoryListForksOptions struct { // ListForks lists the forks of the specified repository. // -// GitHub API docs: http://developer.github.com/v3/repos/forks/#list-forks -func (s *RepositoriesService) ListForks(owner, repo string, opt *RepositoryListForksOptions) ([]*Repository, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/forks/#list-forks +func (s *RepositoriesService) ListForks(ctx context.Context, owner, repo string, opt *RepositoryListForksOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -32,13 +35,13 @@ func (s *RepositoriesService) ListForks(owner, repo string, opt *RepositoryListF return nil, nil, err } - repos := new([]*Repository) - resp, err := s.client.Do(req, repos) + var repos []*Repository + resp, err := s.client.Do(ctx, req, &repos) if err != nil { return nil, resp, err } - return *repos, resp, err + return repos, resp, nil } // RepositoryCreateForkOptions specifies the optional parameters to the @@ -57,7 +60,7 @@ type RepositoryCreateForkOptions struct { // in a successful request. // // GitHub API docs: https://developer.github.com/v3/repos/forks/#create-a-fork -func (s *RepositoriesService) CreateFork(owner, repo string, opt *RepositoryCreateForkOptions) (*Repository, *Response, error) { +func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string, opt *RepositoryCreateForkOptions) (*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -70,10 +73,10 @@ func (s *RepositoriesService) CreateFork(owner, repo string, opt *RepositoryCrea } fork := new(Repository) - resp, err := s.client.Do(req, fork) + resp, err := s.client.Do(ctx, req, fork) if err != nil { return nil, resp, err } - return fork, resp, err + return fork, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_hooks.go b/vendor/github.com/google/go-github/github/repos_hooks.go index fe725b454..67ce96ac3 100644 --- a/vendor/github.com/google/go-github/github/repos_hooks.go +++ b/vendor/github.com/google/go-github/github/repos_hooks.go @@ -6,14 +6,15 @@ package github import ( + "context" "fmt" "time" ) // WebHookPayload represents the data that is received from GitHub when a push -// event hook is triggered. The format of these payloads pre-date most of the +// event hook is triggered. The format of these payloads pre-date most of the // GitHub v3 API, so there are lots of minor incompatibilities with the types -// defined in the rest of the API. Therefore, several types are duplicated +// defined in the rest of the API. Therefore, several types are duplicated // here to account for these differences. // // GitHub API docs: https://help.github.com/articles/post-receive-hooks @@ -55,7 +56,7 @@ func (w WebHookCommit) String() string { } // WebHookAuthor represents the author or committer of a commit, as specified -// in a WebHookCommit. The commit author may not correspond to a GitHub User. +// in a WebHookCommit. The commit author may not correspond to a GitHub User. type WebHookAuthor struct { Email *string `json:"email,omitempty"` Name *string `json:"name,omitempty"` @@ -85,8 +86,8 @@ func (h Hook) String() string { // CreateHook creates a Hook for the specified repository. // Name and Config are required fields. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#create-a-hook -func (s *RepositoriesService) CreateHook(owner, repo string, hook *Hook) (*Hook, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook +func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) req, err := s.client.NewRequest("POST", u, hook) if err != nil { @@ -94,18 +95,18 @@ func (s *RepositoriesService) CreateHook(owner, repo string, hook *Hook) (*Hook, } h := new(Hook) - resp, err := s.client.Do(req, h) + resp, err := s.client.Do(ctx, req, h) if err != nil { return nil, resp, err } - return h, resp, err + return h, resp, nil } // ListHooks lists all Hooks for the specified repository. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#list -func (s *RepositoriesService) ListHooks(owner, repo string, opt *ListOptions) ([]*Hook, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#list +func (s *RepositoriesService) ListHooks(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Hook, *Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -117,80 +118,75 @@ func (s *RepositoriesService) ListHooks(owner, repo string, opt *ListOptions) ([ return nil, nil, err } - hooks := new([]*Hook) - resp, err := s.client.Do(req, hooks) + var hooks []*Hook + resp, err := s.client.Do(ctx, req, &hooks) if err != nil { return nil, resp, err } - return *hooks, resp, err + return hooks, resp, nil } // GetHook returns a single specified Hook. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#get-single-hook -func (s *RepositoriesService) GetHook(owner, repo string, id int) (*Hook, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#get-single-hook +func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int) (*Hook, *Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } hook := new(Hook) - resp, err := s.client.Do(req, hook) + resp, err := s.client.Do(ctx, req, hook) return hook, resp, err } // EditHook updates a specified Hook. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#edit-a-hook -func (s *RepositoriesService) EditHook(owner, repo string, id int, hook *Hook) (*Hook, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#edit-a-hook +func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int, hook *Hook) (*Hook, *Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, hook) if err != nil { return nil, nil, err } h := new(Hook) - resp, err := s.client.Do(req, h) + resp, err := s.client.Do(ctx, req, h) return h, resp, err } // DeleteHook deletes a specified Hook. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#delete-a-hook -func (s *RepositoriesService) DeleteHook(owner, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#delete-a-hook +func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // PingHook triggers a 'ping' event to be sent to the Hook. // // GitHub API docs: https://developer.github.com/v3/repos/hooks/#ping-a-hook -func (s *RepositoriesService) PingHook(owner, repo string, id int) (*Response, error) { +func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", owner, repo, id) req, err := s.client.NewRequest("POST", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // TestHook triggers a test Hook by github. // -// GitHub API docs: http://developer.github.com/v3/repos/hooks/#test-a-push-hook -func (s *RepositoriesService) TestHook(owner, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/hooks/#test-a-push-hook +func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) req, err := s.client.NewRequest("POST", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) -} - -// ListServiceHooks is deprecated. Use Client.ListServiceHooks instead. -func (s *RepositoriesService) ListServiceHooks() ([]*ServiceHook, *Response, error) { - return s.client.ListServiceHooks() + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/repos_invitations.go b/vendor/github.com/google/go-github/github/repos_invitations.go index f2806d11c..a803a12da 100644 --- a/vendor/github.com/google/go-github/github/repos_invitations.go +++ b/vendor/github.com/google/go-github/github/repos_invitations.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // RepositoryInvitation represents an invitation to collaborate on a repo. type RepositoryInvitation struct { @@ -25,8 +28,8 @@ type RepositoryInvitation struct { // ListInvitations lists all currently-open repository invitations. // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-invitations-for-a-repository -func (s *RepositoriesService) ListInvitations(repoID int, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { - u := fmt.Sprintf("repositories/%v/invitations", repoID) +func (s *RepositoriesService) ListInvitations(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/invitations", owner, repo) u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -41,19 +44,19 @@ func (s *RepositoriesService) ListInvitations(repoID int, opt *ListOptions) ([]* req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) invites := []*RepositoryInvitation{} - resp, err := s.client.Do(req, &invites) + resp, err := s.client.Do(ctx, req, &invites) if err != nil { return nil, resp, err } - return invites, resp, err + return invites, resp, nil } // DeleteInvitation deletes a repository invitation. // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation -func (s *RepositoriesService) DeleteInvitation(repoID, invitationID int) (*Response, error) { - u := fmt.Sprintf("repositories/%v/invitations/%v", repoID, invitationID) +func (s *RepositoriesService) DeleteInvitation(ctx context.Context, owner, repo string, invitationID int) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -62,7 +65,7 @@ func (s *RepositoriesService) DeleteInvitation(repoID, invitationID int) (*Respo // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // UpdateInvitation updates the permissions associated with a repository @@ -72,11 +75,11 @@ func (s *RepositoriesService) DeleteInvitation(repoID, invitationID int) (*Respo // on the repository. Possible values are: "read", "write", "admin". // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#update-a-repository-invitation -func (s *RepositoriesService) UpdateInvitation(repoID, invitationID int, permissions string) (*RepositoryInvitation, *Response, error) { +func (s *RepositoriesService) UpdateInvitation(ctx context.Context, owner, repo string, invitationID int, permissions string) (*RepositoryInvitation, *Response, error) { opts := &struct { Permissions string `json:"permissions"` }{Permissions: permissions} - u := fmt.Sprintf("repositories/%v/invitations/%v", repoID, invitationID) + u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) req, err := s.client.NewRequest("PATCH", u, opts) if err != nil { return nil, nil, err @@ -86,6 +89,6 @@ func (s *RepositoriesService) UpdateInvitation(repoID, invitationID int, permiss req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) invite := &RepositoryInvitation{} - resp, err := s.client.Do(req, invite) + resp, err := s.client.Do(ctx, req, invite) return invite, resp, err } diff --git a/vendor/github.com/google/go-github/github/repos_keys.go b/vendor/github.com/google/go-github/github/repos_keys.go index 0bb404a3a..f5a865813 100644 --- a/vendor/github.com/google/go-github/github/repos_keys.go +++ b/vendor/github.com/google/go-github/github/repos_keys.go @@ -5,14 +5,17 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // The Key type is defined in users_keys.go // ListKeys lists the deploy keys for a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/keys/#list -func (s *RepositoriesService) ListKeys(owner string, repo string, opt *ListOptions) ([]*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/keys/#list +func (s *RepositoriesService) ListKeys(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Key, *Response, error) { u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -24,19 +27,19 @@ func (s *RepositoriesService) ListKeys(owner string, repo string, opt *ListOptio return nil, nil, err } - keys := new([]*Key) - resp, err := s.client.Do(req, keys) + var keys []*Key + resp, err := s.client.Do(ctx, req, &keys) if err != nil { return nil, resp, err } - return *keys, resp, err + return keys, resp, nil } // GetKey fetches a single deploy key. // -// GitHub API docs: http://developer.github.com/v3/repos/keys/#get -func (s *RepositoriesService) GetKey(owner string, repo string, id int) (*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/keys/#get +func (s *RepositoriesService) GetKey(ctx context.Context, owner string, repo string, id int) (*Key, *Response, error) { u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) @@ -45,18 +48,18 @@ func (s *RepositoriesService) GetKey(owner string, repo string, id int) (*Key, * } key := new(Key) - resp, err := s.client.Do(req, key) + resp, err := s.client.Do(ctx, req, key) if err != nil { return nil, resp, err } - return key, resp, err + return key, resp, nil } // CreateKey adds a deploy key for a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/keys/#create -func (s *RepositoriesService) CreateKey(owner string, repo string, key *Key) (*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/keys/#create +func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo string, key *Key) (*Key, *Response, error) { u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) req, err := s.client.NewRequest("POST", u, key) @@ -65,18 +68,18 @@ func (s *RepositoriesService) CreateKey(owner string, repo string, key *Key) (*K } k := new(Key) - resp, err := s.client.Do(req, k) + resp, err := s.client.Do(ctx, req, k) if err != nil { return nil, resp, err } - return k, resp, err + return k, resp, nil } // EditKey edits a deploy key. // -// GitHub API docs: http://developer.github.com/v3/repos/keys/#edit -func (s *RepositoriesService) EditKey(owner string, repo string, id int, key *Key) (*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/keys/#edit +func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo string, id int, key *Key) (*Key, *Response, error) { u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, key) @@ -85,18 +88,18 @@ func (s *RepositoriesService) EditKey(owner string, repo string, id int, key *Ke } k := new(Key) - resp, err := s.client.Do(req, k) + resp, err := s.client.Do(ctx, req, k) if err != nil { return nil, resp, err } - return k, resp, err + return k, resp, nil } // DeleteKey deletes a deploy key. // -// GitHub API docs: http://developer.github.com/v3/repos/keys/#delete -func (s *RepositoriesService) DeleteKey(owner string, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/keys/#delete +func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) @@ -104,5 +107,5 @@ func (s *RepositoriesService) DeleteKey(owner string, repo string, id int) (*Res return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/repos_merging.go b/vendor/github.com/google/go-github/github/repos_merging.go index 31f8313ea..04383c1ae 100644 --- a/vendor/github.com/google/go-github/github/repos_merging.go +++ b/vendor/github.com/google/go-github/github/repos_merging.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" ) @@ -20,7 +21,7 @@ type RepositoryMergeRequest struct { // Merge a branch in the specified repository. // // GitHub API docs: https://developer.github.com/v3/repos/merging/#perform-a-merge -func (s *RepositoriesService) Merge(owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { +func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/merges", owner, repo) req, err := s.client.NewRequest("POST", u, request) if err != nil { @@ -28,10 +29,10 @@ func (s *RepositoriesService) Merge(owner, repo string, request *RepositoryMerge } commit := new(RepositoryCommit) - resp, err := s.client.Do(req, commit) + resp, err := s.client.Do(ctx, req, commit) if err != nil { return nil, resp, err } - return commit, resp, err + return commit, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_pages.go b/vendor/github.com/google/go-github/github/repos_pages.go index ddd830155..3d19b43db 100644 --- a/vendor/github.com/google/go-github/github/repos_pages.go +++ b/vendor/github.com/google/go-github/github/repos_pages.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Pages represents a GitHub Pages site configuration. type Pages struct { @@ -36,7 +39,7 @@ type PagesBuild struct { // GetPagesInfo fetches information about a GitHub Pages site. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#get-information-about-a-pages-site -func (s *RepositoriesService) GetPagesInfo(owner, repo string) (*Pages, *Response, error) { +func (s *RepositoriesService) GetPagesInfo(ctx context.Context, owner, repo string) (*Pages, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -47,18 +50,18 @@ func (s *RepositoriesService) GetPagesInfo(owner, repo string) (*Pages, *Respons req.Header.Set("Accept", mediaTypePagesPreview) site := new(Pages) - resp, err := s.client.Do(req, site) + resp, err := s.client.Do(ctx, req, site) if err != nil { return nil, resp, err } - return site, resp, err + return site, resp, nil } // ListPagesBuilds lists the builds for a GitHub Pages site. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#list-pages-builds -func (s *RepositoriesService) ListPagesBuilds(owner, repo string) ([]*PagesBuild, *Response, error) { +func (s *RepositoriesService) ListPagesBuilds(ctx context.Context, owner, repo string) ([]*PagesBuild, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -66,18 +69,18 @@ func (s *RepositoriesService) ListPagesBuilds(owner, repo string) ([]*PagesBuild } var pages []*PagesBuild - resp, err := s.client.Do(req, &pages) + resp, err := s.client.Do(ctx, req, &pages) if err != nil { return nil, resp, err } - return pages, resp, err + return pages, resp, nil } // GetLatestPagesBuild fetches the latest build information for a GitHub pages site. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#list-latest-pages-build -func (s *RepositoriesService) GetLatestPagesBuild(owner, repo string) (*PagesBuild, *Response, error) { +func (s *RepositoriesService) GetLatestPagesBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages/builds/latest", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -85,18 +88,18 @@ func (s *RepositoriesService) GetLatestPagesBuild(owner, repo string) (*PagesBui } build := new(PagesBuild) - resp, err := s.client.Do(req, build) + resp, err := s.client.Do(ctx, req, build) if err != nil { return nil, resp, err } - return build, resp, err + return build, resp, nil } // GetPageBuild fetches the specific build information for a GitHub pages site. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#list-a-specific-pages-build -func (s *RepositoriesService) GetPageBuild(owner, repo string, id int) (*PagesBuild, *Response, error) { +func (s *RepositoriesService) GetPageBuild(ctx context.Context, owner, repo string, id int) (*PagesBuild, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages/builds/%v", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -104,18 +107,18 @@ func (s *RepositoriesService) GetPageBuild(owner, repo string, id int) (*PagesBu } build := new(PagesBuild) - resp, err := s.client.Do(req, build) + resp, err := s.client.Do(ctx, req, build) if err != nil { return nil, resp, err } - return build, resp, err + return build, resp, nil } // RequestPageBuild requests a build of a GitHub Pages site without needing to push new commit. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#request-a-page-build -func (s *RepositoriesService) RequestPageBuild(owner, repo string) (*PagesBuild, *Response, error) { +func (s *RepositoriesService) RequestPageBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) req, err := s.client.NewRequest("POST", u, nil) if err != nil { @@ -126,10 +129,10 @@ func (s *RepositoriesService) RequestPageBuild(owner, repo string) (*PagesBuild, req.Header.Set("Accept", mediaTypePagesPreview) build := new(PagesBuild) - resp, err := s.client.Do(req, build) + resp, err := s.client.Do(ctx, req, build) if err != nil { return nil, resp, err } - return build, resp, err + return build, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_projects.go b/vendor/github.com/google/go-github/github/repos_projects.go index 137f89d14..770ffc76f 100644 --- a/vendor/github.com/google/go-github/github/repos_projects.go +++ b/vendor/github.com/google/go-github/github/repos_projects.go @@ -1,16 +1,28 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. +// Copyright 2017 The go-github AUTHORS. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package github -import "fmt" +import ( + "context" + "fmt" +) + +// ProjectListOptions specifies the optional parameters to the +// OrganizationsService.ListProjects and RepositoriesService.ListProjects methods. +type ProjectListOptions struct { + // Indicates the state of the projects to return. Can be either open, closed, or all. Default: open + State string `url:"state,omitempty"` + + ListOptions +} // ListProjects lists the projects for a repo. // // GitHub API docs: https://developer.github.com/v3/projects/#list-repository-projects -func (s *RepositoriesService) ListProjects(owner, repo string, opt *ListOptions) ([]*Project, *Response, error) { +func (s *RepositoriesService) ListProjects(ctx context.Context, owner, repo string, opt *ProjectListOptions) ([]*Project, *Response, error) { u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -25,19 +37,19 @@ func (s *RepositoriesService) ListProjects(owner, repo string, opt *ListOptions) // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeProjectsPreview) - projects := []*Project{} - resp, err := s.client.Do(req, &projects) + var projects []*Project + resp, err := s.client.Do(ctx, req, &projects) if err != nil { return nil, resp, err } - return projects, resp, err + return projects, resp, nil } // CreateProject creates a GitHub Project for the specified repository. // // GitHub API docs: https://developer.github.com/v3/projects/#create-a-repository-project -func (s *RepositoriesService) CreateProject(owner, repo string, opt *ProjectOptions) (*Project, *Response, error) { +func (s *RepositoriesService) CreateProject(ctx context.Context, owner, repo string, opt *ProjectOptions) (*Project, *Response, error) { u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) req, err := s.client.NewRequest("POST", u, opt) if err != nil { @@ -48,10 +60,10 @@ func (s *RepositoriesService) CreateProject(owner, repo string, opt *ProjectOpti req.Header.Set("Accept", mediaTypeProjectsPreview) project := &Project{} - resp, err := s.client.Do(req, project) + resp, err := s.client.Do(ctx, req, project) if err != nil { return nil, resp, err } - return project, resp, err + return project, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_releases.go b/vendor/github.com/google/go-github/github/repos_releases.go index 331a4b7c0..5c2756551 100644 --- a/vendor/github.com/google/go-github/github/repos_releases.go +++ b/vendor/github.com/google/go-github/github/repos_releases.go @@ -6,6 +6,7 @@ package github import ( + "context" "errors" "fmt" "io" @@ -41,7 +42,7 @@ func (r RepositoryRelease) String() string { return Stringify(r) } -// ReleaseAsset represents a Github release asset in a repository. +// ReleaseAsset represents a GitHub release asset in a repository. type ReleaseAsset struct { ID *int `json:"id,omitempty"` URL *string `json:"url,omitempty"` @@ -63,8 +64,8 @@ func (r ReleaseAsset) String() string { // ListReleases lists the releases for a repository. // -// GitHub API docs: http://developer.github.com/v3/repos/releases/#list-releases-for-a-repository -func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions) ([]*RepositoryRelease, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository +func (s *RepositoriesService) ListReleases(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -76,56 +77,56 @@ func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions) return nil, nil, err } - releases := new([]*RepositoryRelease) - resp, err := s.client.Do(req, releases) + var releases []*RepositoryRelease + resp, err := s.client.Do(ctx, req, &releases) if err != nil { return nil, resp, err } - return *releases, resp, err + return releases, resp, nil } // GetRelease fetches a single release. // -// GitHub API docs: http://developer.github.com/v3/repos/releases/#get-a-single-release -func (s *RepositoriesService) GetRelease(owner, repo string, id int) (*RepositoryRelease, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release +func (s *RepositoriesService) GetRelease(ctx context.Context, owner, repo string, id int) (*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - return s.getSingleRelease(u) + return s.getSingleRelease(ctx, u) } // GetLatestRelease fetches the latest published release for the repository. // // GitHub API docs: https://developer.github.com/v3/repos/releases/#get-the-latest-release -func (s *RepositoriesService) GetLatestRelease(owner, repo string) (*RepositoryRelease, *Response, error) { +func (s *RepositoriesService) GetLatestRelease(ctx context.Context, owner, repo string) (*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo) - return s.getSingleRelease(u) + return s.getSingleRelease(ctx, u) } // GetReleaseByTag fetches a release with the specified tag. // // GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name -func (s *RepositoriesService) GetReleaseByTag(owner, repo, tag string) (*RepositoryRelease, *Response, error) { +func (s *RepositoriesService) GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag) - return s.getSingleRelease(u) + return s.getSingleRelease(ctx, u) } -func (s *RepositoriesService) getSingleRelease(url string) (*RepositoryRelease, *Response, error) { +func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string) (*RepositoryRelease, *Response, error) { req, err := s.client.NewRequest("GET", url, nil) if err != nil { return nil, nil, err } release := new(RepositoryRelease) - resp, err := s.client.Do(req, release) + resp, err := s.client.Do(ctx, req, release) if err != nil { return nil, resp, err } - return release, resp, err + return release, resp, nil } // CreateRelease adds a new release for a repository. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#create-a-release -func (s *RepositoriesService) CreateRelease(owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release +func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) req, err := s.client.NewRequest("POST", u, release) @@ -134,17 +135,17 @@ func (s *RepositoriesService) CreateRelease(owner, repo string, release *Reposit } r := new(RepositoryRelease) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // EditRelease edits a repository release. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#edit-a-release -func (s *RepositoriesService) EditRelease(owner, repo string, id int, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release +func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, release) @@ -153,30 +154,30 @@ func (s *RepositoriesService) EditRelease(owner, repo string, id int, release *R } r := new(RepositoryRelease) - resp, err := s.client.Do(req, r) + resp, err := s.client.Do(ctx, req, r) if err != nil { return nil, resp, err } - return r, resp, err + return r, resp, nil } // DeleteRelease delete a single release from a repository. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#delete-a-release -func (s *RepositoriesService) DeleteRelease(owner, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release +func (s *RepositoriesService) DeleteRelease(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // ListReleaseAssets lists the release's assets. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#list-assets-for-a-release -func (s *RepositoriesService) ListReleaseAssets(owner, repo string, id int, opt *ListOptions) ([]*ReleaseAsset, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release +func (s *RepositoriesService) ListReleaseAssets(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*ReleaseAsset, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -188,18 +189,18 @@ func (s *RepositoriesService) ListReleaseAssets(owner, repo string, id int, opt return nil, nil, err } - assets := new([]*ReleaseAsset) - resp, err := s.client.Do(req, assets) + var assets []*ReleaseAsset + resp, err := s.client.Do(ctx, req, &assets) if err != nil { - return nil, resp, nil + return nil, resp, err } - return *assets, resp, err + return assets, resp, nil } // GetReleaseAsset fetches a single release asset. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*ReleaseAsset, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset +func (s *RepositoriesService) GetReleaseAsset(ctx context.Context, owner, repo string, id int) (*ReleaseAsset, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) @@ -208,11 +209,11 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele } asset := new(ReleaseAsset) - resp, err := s.client.Do(req, asset) + resp, err := s.client.Do(ctx, req, asset) if err != nil { - return nil, resp, nil + return nil, resp, err } - return asset, resp, err + return asset, resp, nil } // DownloadReleaseAsset downloads a release asset or returns a redirect URL. @@ -222,8 +223,8 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele // If a redirect is returned, the redirect URL will be returned as a string instead // of the io.ReadCloser. Exactly one of rc and redirectURL will be zero. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (rc io.ReadCloser, redirectURL string, err error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset +func (s *RepositoriesService) DownloadReleaseAsset(ctx context.Context, owner, repo string, id int) (rc io.ReadCloser, redirectURL string, err error) { u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) @@ -243,12 +244,13 @@ func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) ( } defer func() { s.client.client.CheckRedirect = saveRedirect }() + ctx, req = withContext(ctx, req) resp, err := s.client.client.Do(req) if err != nil { if !strings.Contains(err.Error(), "disable redirect") { return nil, "", err } - return nil, loc, nil + return nil, loc, nil // Intentionally return no error with valid redirect URL. } if err := CheckResponse(resp); err != nil { @@ -261,8 +263,8 @@ func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) ( // EditReleaseAsset edits a repository release asset. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#edit-a-release-asset -func (s *RepositoriesService) EditReleaseAsset(owner, repo string, id int, release *ReleaseAsset) (*ReleaseAsset, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release-asset +func (s *RepositoriesService) EditReleaseAsset(ctx context.Context, owner, repo string, id int, release *ReleaseAsset) (*ReleaseAsset, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) req, err := s.client.NewRequest("PATCH", u, release) @@ -271,31 +273,31 @@ func (s *RepositoriesService) EditReleaseAsset(owner, repo string, id int, relea } asset := new(ReleaseAsset) - resp, err := s.client.Do(req, asset) + resp, err := s.client.Do(ctx, req, asset) if err != nil { return nil, resp, err } - return asset, resp, err + return asset, resp, nil } // DeleteReleaseAsset delete a single release asset from a repository. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#delete-a-release-asset -func (s *RepositoriesService) DeleteReleaseAsset(owner, repo string, id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release-asset +func (s *RepositoriesService) DeleteReleaseAsset(ctx context.Context, owner, repo string, id int) (*Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // UploadReleaseAsset creates an asset by uploading a file into a release repository. // To upload assets that cannot be represented by an os.File, call NewUploadRequest directly. // -// GitHub API docs : http://developer.github.com/v3/repos/releases/#upload-a-release-asset -func (s *RepositoriesService) UploadReleaseAsset(owner, repo string, id int, opt *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/releases/#upload-a-release-asset +func (s *RepositoriesService) UploadReleaseAsset(ctx context.Context, owner, repo string, id int, opt *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -317,9 +319,9 @@ func (s *RepositoriesService) UploadReleaseAsset(owner, repo string, id int, opt } asset := new(ReleaseAsset) - resp, err := s.client.Do(req, asset) + resp, err := s.client.Do(ctx, req, asset) if err != nil { return nil, resp, err } - return asset, resp, err + return asset, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_stats.go b/vendor/github.com/google/go-github/github/repos_stats.go index 8657bd797..30fc7bd34 100644 --- a/vendor/github.com/google/go-github/github/repos_stats.go +++ b/vendor/github.com/google/go-github/github/repos_stats.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -44,8 +45,8 @@ func (w WeeklyStats) String() string { // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // -// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#contributors -func (s *RepositoriesService) ListContributorsStats(owner, repo string) ([]*ContributorStats, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statistics/#contributors +func (s *RepositoriesService) ListContributorsStats(ctx context.Context, owner, repo string) ([]*ContributorStats, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/contributors", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -53,12 +54,12 @@ func (s *RepositoriesService) ListContributorsStats(owner, repo string) ([]*Cont } var contributorStats []*ContributorStats - resp, err := s.client.Do(req, &contributorStats) + resp, err := s.client.Do(ctx, req, &contributorStats) if err != nil { return nil, resp, err } - return contributorStats, resp, err + return contributorStats, resp, nil } // WeeklyCommitActivity represents the weekly commit activity for a repository. @@ -83,8 +84,8 @@ func (w WeeklyCommitActivity) String() string { // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // -// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#commit-activity -func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statistics/#commit-activity +func (s *RepositoriesService) ListCommitActivity(ctx context.Context, owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/commit_activity", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -92,16 +93,16 @@ func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]*WeeklyC } var weeklyCommitActivity []*WeeklyCommitActivity - resp, err := s.client.Do(req, &weeklyCommitActivity) + resp, err := s.client.Do(ctx, req, &weeklyCommitActivity) if err != nil { return nil, resp, err } - return weeklyCommitActivity, resp, err + return weeklyCommitActivity, resp, nil } // ListCodeFrequency returns a weekly aggregate of the number of additions and -// deletions pushed to a repository. Returned WeeklyStats will contain +// deletions pushed to a repository. Returned WeeklyStats will contain // additions and deletions, but not total commits. // // If this is the first time these statistics are requested for the given @@ -110,8 +111,8 @@ func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]*WeeklyC // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // -// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#code-frequency -func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]*WeeklyStats, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statistics/#code-frequency +func (s *RepositoriesService) ListCodeFrequency(ctx context.Context, owner, repo string) ([]*WeeklyStats, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -119,7 +120,7 @@ func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]*WeeklySt } var weeks [][]int - resp, err := s.client.Do(req, &weeks) + resp, err := s.client.Do(ctx, req, &weeks) // convert int slices into WeeklyStats var stats []*WeeklyStats @@ -163,8 +164,8 @@ func (r RepositoryParticipation) String() string { // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // -// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#participation -func (s *RepositoriesService) ListParticipation(owner, repo string) (*RepositoryParticipation, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statistics/#participation +func (s *RepositoriesService) ListParticipation(ctx context.Context, owner, repo string) (*RepositoryParticipation, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/participation", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -172,12 +173,12 @@ func (s *RepositoriesService) ListParticipation(owner, repo string) (*Repository } participation := new(RepositoryParticipation) - resp, err := s.client.Do(req, participation) + resp, err := s.client.Do(ctx, req, participation) if err != nil { return nil, resp, err } - return participation, resp, err + return participation, resp, nil } // PunchCard represents the number of commits made during a given hour of a @@ -196,8 +197,8 @@ type PunchCard struct { // it is now computing the requested statistics. A follow up request, after a // delay of a second or so, should result in a successful request. // -// GitHub API Docs: https://developer.github.com/v3/repos/statistics/#punch-card -func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]*PunchCard, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statistics/#punch-card +func (s *RepositoriesService) ListPunchCard(ctx context.Context, owner, repo string) ([]*PunchCard, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -205,7 +206,7 @@ func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]*PunchCard, * } var results [][]int - resp, err := s.client.Do(req, &results) + resp, err := s.client.Do(ctx, req, &results) // convert int slices into Punchcards var cards []*PunchCard diff --git a/vendor/github.com/google/go-github/github/repos_statuses.go b/vendor/github.com/google/go-github/github/repos_statuses.go index 6478ee2a8..6db501076 100644 --- a/vendor/github.com/google/go-github/github/repos_statuses.go +++ b/vendor/github.com/google/go-github/github/repos_statuses.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -15,11 +16,11 @@ type RepoStatus struct { ID *int `json:"id,omitempty"` URL *string `json:"url,omitempty"` - // State is the current state of the repository. Possible values are: + // State is the current state of the repository. Possible values are: // pending, success, error, or failure. State *string `json:"state,omitempty"` - // TargetURL is the URL of the page representing this status. It will be + // TargetURL is the URL of the page representing this status. It will be // linked from the GitHub UI to allow users to see the source of the status. TargetURL *string `json:"target_url,omitempty"` @@ -39,10 +40,10 @@ func (r RepoStatus) String() string { } // ListStatuses lists the statuses of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. +// reference. ref can be a SHA, a branch name, or a tag name. // -// GitHub API docs: http://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref -func (s *RepositoriesService) ListStatuses(owner, repo, ref string, opt *ListOptions) ([]*RepoStatus, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref +func (s *RepositoriesService) ListStatuses(ctx context.Context, owner, repo, ref string, opt *ListOptions) ([]*RepoStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/statuses", owner, repo, ref) u, err := addOptions(u, opt) if err != nil { @@ -54,20 +55,20 @@ func (s *RepositoriesService) ListStatuses(owner, repo, ref string, opt *ListOpt return nil, nil, err } - statuses := new([]*RepoStatus) - resp, err := s.client.Do(req, statuses) + var statuses []*RepoStatus + resp, err := s.client.Do(ctx, req, &statuses) if err != nil { return nil, resp, err } - return *statuses, resp, err + return statuses, resp, nil } // CreateStatus creates a new status for a repository at the specified -// reference. Ref can be a SHA, a branch name, or a tag name. +// reference. Ref can be a SHA, a branch name, or a tag name. // -// GitHub API docs: http://developer.github.com/v3/repos/statuses/#create-a-status -func (s *RepositoriesService) CreateStatus(owner, repo, ref string, status *RepoStatus) (*RepoStatus, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/repos/statuses/#create-a-status +func (s *RepositoriesService) CreateStatus(ctx context.Context, owner, repo, ref string, status *RepoStatus) (*RepoStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/statuses/%v", owner, repo, ref) req, err := s.client.NewRequest("POST", u, status) if err != nil { @@ -75,17 +76,17 @@ func (s *RepositoriesService) CreateStatus(owner, repo, ref string, status *Repo } repoStatus := new(RepoStatus) - resp, err := s.client.Do(req, repoStatus) + resp, err := s.client.Do(ctx, req, repoStatus) if err != nil { return nil, resp, err } - return repoStatus, resp, err + return repoStatus, resp, nil } // CombinedStatus represents the combined status of a repository at a particular reference. type CombinedStatus struct { - // State is the combined state of the repository. Possible values are: + // State is the combined state of the repository. Possible values are: // failure, pending, or success. State *string `json:"state,omitempty"` @@ -103,10 +104,10 @@ func (s CombinedStatus) String() string { } // GetCombinedStatus returns the combined status of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. +// reference. ref can be a SHA, a branch name, or a tag name. // // GitHub API docs: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref -func (s *RepositoriesService) GetCombinedStatus(owner, repo, ref string, opt *ListOptions) (*CombinedStatus, *Response, error) { +func (s *RepositoriesService) GetCombinedStatus(ctx context.Context, owner, repo, ref string, opt *ListOptions) (*CombinedStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/status", owner, repo, ref) u, err := addOptions(u, opt) if err != nil { @@ -119,10 +120,10 @@ func (s *RepositoriesService) GetCombinedStatus(owner, repo, ref string, opt *Li } status := new(CombinedStatus) - resp, err := s.client.Do(req, status) + resp, err := s.client.Do(ctx, req, status) if err != nil { return nil, resp, err } - return status, resp, err + return status, resp, nil } diff --git a/vendor/github.com/google/go-github/github/repos_traffic.go b/vendor/github.com/google/go-github/github/repos_traffic.go index 9688b58be..fb1c97648 100644 --- a/vendor/github.com/google/go-github/github/repos_traffic.go +++ b/vendor/github.com/google/go-github/github/repos_traffic.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // TrafficReferrer represent information about traffic from a referrer . type TrafficReferrer struct { @@ -52,7 +55,7 @@ type TrafficBreakdownOptions struct { // ListTrafficReferrers list the top 10 referrers over the last 14 days. // // GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-referrers -func (s *RepositoriesService) ListTrafficReferrers(owner, repo string) ([]*TrafficReferrer, *Response, error) { +func (s *RepositoriesService) ListTrafficReferrers(ctx context.Context, owner, repo string) ([]*TrafficReferrer, *Response, error) { u := fmt.Sprintf("repos/%v/%v/traffic/popular/referrers", owner, repo) req, err := s.client.NewRequest("GET", u, nil) @@ -60,22 +63,19 @@ func (s *RepositoriesService) ListTrafficReferrers(owner, repo string) ([]*Traff return nil, nil, err } - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTrafficPreview) - - trafficReferrers := new([]*TrafficReferrer) - resp, err := s.client.Do(req, &trafficReferrers) + var trafficReferrers []*TrafficReferrer + resp, err := s.client.Do(ctx, req, &trafficReferrers) if err != nil { return nil, resp, err } - return *trafficReferrers, resp, err + return trafficReferrers, resp, nil } // ListTrafficPaths list the top 10 popular content over the last 14 days. // // GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-paths -func (s *RepositoriesService) ListTrafficPaths(owner, repo string) ([]*TrafficPath, *Response, error) { +func (s *RepositoriesService) ListTrafficPaths(ctx context.Context, owner, repo string) ([]*TrafficPath, *Response, error) { u := fmt.Sprintf("repos/%v/%v/traffic/popular/paths", owner, repo) req, err := s.client.NewRequest("GET", u, nil) @@ -83,22 +83,19 @@ func (s *RepositoriesService) ListTrafficPaths(owner, repo string) ([]*TrafficPa return nil, nil, err } - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTrafficPreview) - - var paths = new([]*TrafficPath) - resp, err := s.client.Do(req, &paths) + var paths []*TrafficPath + resp, err := s.client.Do(ctx, req, &paths) if err != nil { return nil, resp, err } - return *paths, resp, err + return paths, resp, nil } // ListTrafficViews get total number of views for the last 14 days and breaks it down either per day or week. // // GitHub API docs: https://developer.github.com/v3/repos/traffic/#views -func (s *RepositoriesService) ListTrafficViews(owner, repo string, opt *TrafficBreakdownOptions) (*TrafficViews, *Response, error) { +func (s *RepositoriesService) ListTrafficViews(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficViews, *Response, error) { u := fmt.Sprintf("repos/%v/%v/traffic/views", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -110,22 +107,19 @@ func (s *RepositoriesService) ListTrafficViews(owner, repo string, opt *TrafficB return nil, nil, err } - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTrafficPreview) - trafficViews := new(TrafficViews) - resp, err := s.client.Do(req, &trafficViews) + resp, err := s.client.Do(ctx, req, &trafficViews) if err != nil { return nil, resp, err } - return trafficViews, resp, err + return trafficViews, resp, nil } // ListTrafficClones get total number of clones for the last 14 days and breaks it down either per day or week for the last 14 days. // // GitHub API docs: https://developer.github.com/v3/repos/traffic/#views -func (s *RepositoriesService) ListTrafficClones(owner, repo string, opt *TrafficBreakdownOptions) (*TrafficClones, *Response, error) { +func (s *RepositoriesService) ListTrafficClones(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficClones, *Response, error) { u := fmt.Sprintf("repos/%v/%v/traffic/clones", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -137,14 +131,11 @@ func (s *RepositoriesService) ListTrafficClones(owner, repo string, opt *Traffic return nil, nil, err } - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTrafficPreview) - trafficClones := new(TrafficClones) - resp, err := s.client.Do(req, &trafficClones) + resp, err := s.client.Do(ctx, req, &trafficClones) if err != nil { return nil, resp, err } - return trafficClones, resp, err + return trafficClones, resp, nil } diff --git a/vendor/github.com/google/go-github/github/search.go b/vendor/github.com/google/go-github/github/search.go index 579a57d7f..7668b8b62 100644 --- a/vendor/github.com/google/go-github/github/search.go +++ b/vendor/github.com/google/go-github/github/search.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" qs "github.com/google/go-querystring/query" @@ -14,13 +15,14 @@ import ( // SearchService provides access to the search related functions // in the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/search/ +// GitHub API docs: https://developer.github.com/v3/search/ type SearchService service // SearchOptions specifies optional parameters to the SearchService methods. type SearchOptions struct { - // How to sort the search results. Possible values are: + // How to sort the search results. Possible values are: // - for repositories: stars, fork, updated + // - for commits: author-date, committer-date // - for code: indexed // - for issues: comments, created, updated // - for users: followers, repositories, joined @@ -47,10 +49,41 @@ type RepositoriesSearchResult struct { // Repositories searches repositories via various criteria. // -// GitHub API docs: http://developer.github.com/v3/search/#search-repositories -func (s *SearchService) Repositories(query string, opt *SearchOptions) (*RepositoriesSearchResult, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/search/#search-repositories +func (s *SearchService) Repositories(ctx context.Context, query string, opt *SearchOptions) (*RepositoriesSearchResult, *Response, error) { result := new(RepositoriesSearchResult) - resp, err := s.search("repositories", query, opt, result) + resp, err := s.search(ctx, "repositories", query, opt, result) + return result, resp, err +} + +// CommitsSearchResult represents the result of a commits search. +type CommitsSearchResult struct { + Total *int `json:"total_count,omitempty"` + IncompleteResults *bool `json:"incomplete_results,omitempty"` + Commits []*CommitResult `json:"items,omitempty"` +} + +// CommitResult represents a commit object as returned in commit search endpoint response. +type CommitResult struct { + SHA *string `json:"sha,omitempty"` + Commit *Commit `json:"commit,omitempty"` + Author *User `json:"author,omitempty"` + Committer *User `json:"committer,omitempty"` + Parents []*Commit `json:"parents,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + URL *string `json:"url,omitempty"` + CommentsURL *string `json:"comments_url,omitempty"` + + Repository *Repository `json:"repository,omitempty"` + Score *float64 `json:"score,omitempty"` +} + +// Commits searches commits via various criteria. +// +// GitHub API docs: https://developer.github.com/v3/search/#search-commits +func (s *SearchService) Commits(ctx context.Context, query string, opt *SearchOptions) (*CommitsSearchResult, *Response, error) { + result := new(CommitsSearchResult) + resp, err := s.search(ctx, "commits", query, opt, result) return result, resp, err } @@ -63,10 +96,10 @@ type IssuesSearchResult struct { // Issues searches issues via various criteria. // -// GitHub API docs: http://developer.github.com/v3/search/#search-issues -func (s *SearchService) Issues(query string, opt *SearchOptions) (*IssuesSearchResult, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/search/#search-issues +func (s *SearchService) Issues(ctx context.Context, query string, opt *SearchOptions) (*IssuesSearchResult, *Response, error) { result := new(IssuesSearchResult) - resp, err := s.search("issues", query, opt, result) + resp, err := s.search(ctx, "issues", query, opt, result) return result, resp, err } @@ -79,10 +112,10 @@ type UsersSearchResult struct { // Users searches users via various criteria. // -// GitHub API docs: http://developer.github.com/v3/search/#search-users -func (s *SearchService) Users(query string, opt *SearchOptions) (*UsersSearchResult, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/search/#search-users +func (s *SearchService) Users(ctx context.Context, query string, opt *SearchOptions) (*UsersSearchResult, *Response, error) { result := new(UsersSearchResult) - resp, err := s.search("users", query, opt, result) + resp, err := s.search(ctx, "users", query, opt, result) return result, resp, err } @@ -128,21 +161,21 @@ func (c CodeResult) String() string { // Code searches code via various criteria. // -// GitHub API docs: http://developer.github.com/v3/search/#search-code -func (s *SearchService) Code(query string, opt *SearchOptions) (*CodeSearchResult, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/search/#search-code +func (s *SearchService) Code(ctx context.Context, query string, opt *SearchOptions) (*CodeSearchResult, *Response, error) { result := new(CodeSearchResult) - resp, err := s.search("code", query, opt, result) + resp, err := s.search(ctx, "code", query, opt, result) return result, resp, err } // Helper function that executes search queries against different -// GitHub search types (repositories, code, issues, users) -func (s *SearchService) search(searchType string, query string, opt *SearchOptions, result interface{}) (*Response, error) { +// GitHub search types (repositories, commits, code, issues, users) +func (s *SearchService) search(ctx context.Context, searchType string, query string, opt *SearchOptions, result interface{}) (*Response, error) { params, err := qs.Values(opt) if err != nil { return nil, err } - params.Add("q", query) + params.Set("q", query) u := fmt.Sprintf("search/%s?%s", searchType, params.Encode()) req, err := s.client.NewRequest("GET", u, nil) @@ -150,11 +183,16 @@ func (s *SearchService) search(searchType string, query string, opt *SearchOptio return nil, err } - if opt != nil && opt.TextMatch { + switch { + case searchType == "commits": + // Accept header for search commits preview endpoint + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeCommitSearchPreview) + case opt != nil && opt.TextMatch: // Accept header defaults to "application/vnd.github.v3+json" // We change it here to fetch back text-match metadata req.Header.Set("Accept", "application/vnd.github.v3.text-match+json") } - return s.client.Do(req, result) + return s.client.Do(ctx, req, result) } diff --git a/vendor/github.com/google/go-github/github/strings.go b/vendor/github.com/google/go-github/github/strings.go index 38577236c..431e1cc6c 100644 --- a/vendor/github.com/google/go-github/github/strings.go +++ b/vendor/github.com/google/go-github/github/strings.go @@ -16,7 +16,7 @@ import ( var timestampType = reflect.TypeOf(Timestamp{}) // Stringify attempts to create a reasonable string representation of types in -// the GitHub library. It does things like resolve pointers to their values +// the GitHub library. It does things like resolve pointers to their values // and omits struct fields with nil values. func Stringify(message interface{}) string { var buf bytes.Buffer diff --git a/vendor/github.com/google/go-github/github/users.go b/vendor/github.com/google/go-github/github/users.go index 8f637466a..d74439c7b 100644 --- a/vendor/github.com/google/go-github/github/users.go +++ b/vendor/github.com/google/go-github/github/users.go @@ -5,12 +5,15 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // UsersService handles communication with the user related // methods of the GitHub API. // -// GitHub API docs: http://developer.github.com/v3/users/ +// GitHub API docs: https://developer.github.com/v3/users/ type UsersService service // User represents a GitHub user. @@ -68,11 +71,11 @@ func (u User) String() string { return Stringify(u) } -// Get fetches a user. Passing the empty string will fetch the authenticated +// Get fetches a user. Passing the empty string will fetch the authenticated // user. // -// GitHub API docs: http://developer.github.com/v3/users/#get-a-single-user -func (s *UsersService) Get(user string) (*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user +func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v", user) @@ -85,18 +88,18 @@ func (s *UsersService) Get(user string) (*User, *Response, error) { } uResp := new(User) - resp, err := s.client.Do(req, uResp) + resp, err := s.client.Do(ctx, req, uResp) if err != nil { return nil, resp, err } - return uResp, resp, err + return uResp, resp, nil } // GetByID fetches a user. // // Note: GetByID uses the undocumented GitHub API endpoint /user/:id. -func (s *UsersService) GetByID(id int) (*User, *Response, error) { +func (s *UsersService) GetByID(ctx context.Context, id int) (*User, *Response, error) { u := fmt.Sprintf("user/%d", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -104,18 +107,18 @@ func (s *UsersService) GetByID(id int) (*User, *Response, error) { } user := new(User) - resp, err := s.client.Do(req, user) + resp, err := s.client.Do(ctx, req, user) if err != nil { return nil, resp, err } - return user, resp, err + return user, resp, nil } // Edit the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/#update-the-authenticated-user -func (s *UsersService) Edit(user *User) (*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/#update-the-authenticated-user +func (s *UsersService) Edit(ctx context.Context, user *User) (*User, *Response, error) { u := "user" req, err := s.client.NewRequest("PATCH", u, user) if err != nil { @@ -123,12 +126,12 @@ func (s *UsersService) Edit(user *User) (*User, *Response, error) { } uResp := new(User) - resp, err := s.client.Do(req, uResp) + resp, err := s.client.Do(ctx, req, uResp) if err != nil { return nil, resp, err } - return uResp, resp, err + return uResp, resp, nil } // UserListOptions specifies optional parameters to the UsersService.ListAll @@ -144,8 +147,8 @@ type UserListOptions struct { // // To paginate through all users, populate 'Since' with the ID of the last user. // -// GitHub API docs: http://developer.github.com/v3/users/#get-all-users -func (s *UsersService) ListAll(opt *UserListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/#get-all-users +func (s *UsersService) ListAll(ctx context.Context, opt *UserListOptions) ([]*User, *Response, error) { u, err := addOptions("users", opt) if err != nil { return nil, nil, err @@ -156,20 +159,20 @@ func (s *UsersService) ListAll(opt *UserListOptions) ([]*User, *Response, error) return nil, nil, err } - users := new([]*User) - resp, err := s.client.Do(req, users) + var users []*User + resp, err := s.client.Do(ctx, req, &users) if err != nil { return nil, resp, err } - return *users, resp, err + return users, resp, nil } // ListInvitations lists all currently-open repository invitations for the // authenticated user. // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-a-users-repository-invitations -func (s *UsersService) ListInvitations() ([]*RepositoryInvitation, *Response, error) { +func (s *UsersService) ListInvitations(ctx context.Context) ([]*RepositoryInvitation, *Response, error) { req, err := s.client.NewRequest("GET", "user/repository_invitations", nil) if err != nil { return nil, nil, err @@ -179,19 +182,19 @@ func (s *UsersService) ListInvitations() ([]*RepositoryInvitation, *Response, er req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) invites := []*RepositoryInvitation{} - resp, err := s.client.Do(req, &invites) + resp, err := s.client.Do(ctx, req, &invites) if err != nil { return nil, resp, err } - return invites, resp, err + return invites, resp, nil } // AcceptInvitation accepts the currently-open repository invitation for the // authenticated user. // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#accept-a-repository-invitation -func (s *UsersService) AcceptInvitation(invitationID int) (*Response, error) { +func (s *UsersService) AcceptInvitation(ctx context.Context, invitationID int) (*Response, error) { u := fmt.Sprintf("user/repository_invitations/%v", invitationID) req, err := s.client.NewRequest("PATCH", u, nil) if err != nil { @@ -201,14 +204,14 @@ func (s *UsersService) AcceptInvitation(invitationID int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // DeclineInvitation declines the currently-open repository invitation for the // authenticated user. // // GitHub API docs: https://developer.github.com/v3/repos/invitations/#decline-a-repository-invitation -func (s *UsersService) DeclineInvitation(invitationID int) (*Response, error) { +func (s *UsersService) DeclineInvitation(ctx context.Context, invitationID int) (*Response, error) { u := fmt.Sprintf("user/repository_invitations/%v", invitationID) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -218,5 +221,5 @@ func (s *UsersService) DeclineInvitation(invitationID int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/users_administration.go b/vendor/github.com/google/go-github/github/users_administration.go index dc1dcb894..e042398d8 100644 --- a/vendor/github.com/google/go-github/github/users_administration.go +++ b/vendor/github.com/google/go-github/github/users_administration.go @@ -5,12 +5,15 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // PromoteSiteAdmin promotes a user to a site administrator of a GitHub Enterprise instance. // // GitHub API docs: https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator -func (s *UsersService) PromoteSiteAdmin(user string) (*Response, error) { +func (s *UsersService) PromoteSiteAdmin(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("users/%v/site_admin", user) req, err := s.client.NewRequest("PUT", u, nil) @@ -18,13 +21,13 @@ func (s *UsersService) PromoteSiteAdmin(user string) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // DemoteSiteAdmin demotes a user from site administrator of a GitHub Enterprise instance. // // GitHub API docs: https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user -func (s *UsersService) DemoteSiteAdmin(user string) (*Response, error) { +func (s *UsersService) DemoteSiteAdmin(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("users/%v/site_admin", user) req, err := s.client.NewRequest("DELETE", u, nil) @@ -32,13 +35,13 @@ func (s *UsersService) DemoteSiteAdmin(user string) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Suspend a user on a GitHub Enterprise instance. // // GitHub API docs: https://developer.github.com/v3/users/administration/#suspend-a-user -func (s *UsersService) Suspend(user string) (*Response, error) { +func (s *UsersService) Suspend(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("users/%v/suspended", user) req, err := s.client.NewRequest("PUT", u, nil) @@ -46,13 +49,13 @@ func (s *UsersService) Suspend(user string) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Unsuspend a user on a GitHub Enterprise instance. // // GitHub API docs: https://developer.github.com/v3/users/administration/#unsuspend-a-user -func (s *UsersService) Unsuspend(user string) (*Response, error) { +func (s *UsersService) Unsuspend(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("users/%v/suspended", user) req, err := s.client.NewRequest("DELETE", u, nil) @@ -60,5 +63,5 @@ func (s *UsersService) Unsuspend(user string) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/users_blocking.go b/vendor/github.com/google/go-github/github/users_blocking.go new file mode 100644 index 000000000..39e45601c --- /dev/null +++ b/vendor/github.com/google/go-github/github/users_blocking.go @@ -0,0 +1,91 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ListBlockedUsers lists all the blocked users by the authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/users/blocking/#list-blocked-users +func (s *UsersService) ListBlockedUsers(ctx context.Context, opt *ListOptions) ([]*User, *Response, error) { + u := "user/blocks" + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeBlockUsersPreview) + + var blockedUsers []*User + resp, err := s.client.Do(ctx, req, &blockedUsers) + if err != nil { + return nil, resp, err + } + + return blockedUsers, resp, nil +} + +// IsBlocked reports whether specified user is blocked by the authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/users/blocking/#check-whether-youve-blocked-a-user +func (s *UsersService) IsBlocked(ctx context.Context, user string) (bool, *Response, error) { + u := fmt.Sprintf("user/blocks/%v", user) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return false, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeBlockUsersPreview) + + resp, err := s.client.Do(ctx, req, nil) + isBlocked, err := parseBoolResponse(err) + return isBlocked, resp, err +} + +// BlockUser blocks specified user for the authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/users/blocking/#block-a-user +func (s *UsersService) BlockUser(ctx context.Context, user string) (*Response, error) { + u := fmt.Sprintf("user/blocks/%v", user) + + req, err := s.client.NewRequest("PUT", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeBlockUsersPreview) + + return s.client.Do(ctx, req, nil) +} + +// UnblockUser unblocks specified user for the authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/users/blocking/#unblock-a-user +func (s *UsersService) UnblockUser(ctx context.Context, user string) (*Response, error) { + u := fmt.Sprintf("user/blocks/%v", user) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeBlockUsersPreview) + + return s.client.Do(ctx, req, nil) +} diff --git a/vendor/github.com/google/go-github/github/users_emails.go b/vendor/github.com/google/go-github/github/users_emails.go index e4a58983f..0bbd4627e 100644 --- a/vendor/github.com/google/go-github/github/users_emails.go +++ b/vendor/github.com/google/go-github/github/users_emails.go @@ -5,6 +5,8 @@ package github +import "context" + // UserEmail represents user's email address type UserEmail struct { Email *string `json:"email,omitempty"` @@ -14,8 +16,8 @@ type UserEmail struct { // ListEmails lists all email addresses for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user -func (s *UsersService) ListEmails(opt *ListOptions) ([]*UserEmail, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user +func (s *UsersService) ListEmails(ctx context.Context, opt *ListOptions) ([]*UserEmail, *Response, error) { u := "user/emails" u, err := addOptions(u, opt) if err != nil { @@ -27,43 +29,43 @@ func (s *UsersService) ListEmails(opt *ListOptions) ([]*UserEmail, *Response, er return nil, nil, err } - emails := new([]*UserEmail) - resp, err := s.client.Do(req, emails) + var emails []*UserEmail + resp, err := s.client.Do(ctx, req, &emails) if err != nil { return nil, resp, err } - return *emails, resp, err + return emails, resp, nil } // AddEmails adds email addresses of the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/emails/#add-email-addresses -func (s *UsersService) AddEmails(emails []string) ([]*UserEmail, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/emails/#add-email-addresses +func (s *UsersService) AddEmails(ctx context.Context, emails []string) ([]*UserEmail, *Response, error) { u := "user/emails" req, err := s.client.NewRequest("POST", u, emails) if err != nil { return nil, nil, err } - e := new([]*UserEmail) - resp, err := s.client.Do(req, e) + var e []*UserEmail + resp, err := s.client.Do(ctx, req, &e) if err != nil { return nil, resp, err } - return *e, resp, err + return e, resp, nil } // DeleteEmails deletes email addresses from authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/emails/#delete-email-addresses -func (s *UsersService) DeleteEmails(emails []string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/emails/#delete-email-addresses +func (s *UsersService) DeleteEmails(ctx context.Context, emails []string) (*Response, error) { u := "user/emails" req, err := s.client.NewRequest("DELETE", u, emails) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/users_followers.go b/vendor/github.com/google/go-github/github/users_followers.go index 38a16621e..c2224096a 100644 --- a/vendor/github.com/google/go-github/github/users_followers.go +++ b/vendor/github.com/google/go-github/github/users_followers.go @@ -5,13 +5,16 @@ package github -import "fmt" +import ( + "context" + "fmt" +) -// ListFollowers lists the followers for a user. Passing the empty string will +// ListFollowers lists the followers for a user. Passing the empty string will // fetch followers for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/followers/#list-followers-of-a-user -func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/followers/#list-followers-of-a-user +func (s *UsersService) ListFollowers(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/followers", user) @@ -28,20 +31,20 @@ func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]*User, *R return nil, nil, err } - users := new([]*User) - resp, err := s.client.Do(req, users) + var users []*User + resp, err := s.client.Do(ctx, req, &users) if err != nil { return nil, resp, err } - return *users, resp, err + return users, resp, nil } -// ListFollowing lists the people that a user is following. Passing the empty +// ListFollowing lists the people that a user is following. Passing the empty // string will list people the authenticated user is following. // -// GitHub API docs: http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user -func (s *UsersService) ListFollowing(user string, opt *ListOptions) ([]*User, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user +func (s *UsersService) ListFollowing(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/following", user) @@ -58,20 +61,20 @@ func (s *UsersService) ListFollowing(user string, opt *ListOptions) ([]*User, *R return nil, nil, err } - users := new([]*User) - resp, err := s.client.Do(req, users) + var users []*User + resp, err := s.client.Do(ctx, req, &users) if err != nil { return nil, resp, err } - return *users, resp, err + return users, resp, nil } -// IsFollowing checks if "user" is following "target". Passing the empty +// IsFollowing checks if "user" is following "target". Passing the empty // string for "user" will check if the authenticated user is following "target". // -// GitHub API docs: http://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user -func (s *UsersService) IsFollowing(user, target string) (bool, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user +func (s *UsersService) IsFollowing(ctx context.Context, user, target string) (bool, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/following/%v", user, target) @@ -84,33 +87,33 @@ func (s *UsersService) IsFollowing(user, target string) (bool, *Response, error) return false, nil, err } - resp, err := s.client.Do(req, nil) + resp, err := s.client.Do(ctx, req, nil) following, err := parseBoolResponse(err) return following, resp, err } // Follow will cause the authenticated user to follow the specified user. // -// GitHub API docs: http://developer.github.com/v3/users/followers/#follow-a-user -func (s *UsersService) Follow(user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/followers/#follow-a-user +func (s *UsersService) Follow(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("user/following/%v", user) req, err := s.client.NewRequest("PUT", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } // Unfollow will cause the authenticated user to unfollow the specified user. // -// GitHub API docs: http://developer.github.com/v3/users/followers/#unfollow-a-user -func (s *UsersService) Unfollow(user string) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/followers/#unfollow-a-user +func (s *UsersService) Unfollow(ctx context.Context, user string) (*Response, error) { u := fmt.Sprintf("user/following/%v", user) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/users_gpg_keys.go b/vendor/github.com/google/go-github/github/users_gpg_keys.go index 08cfbed57..be88c042a 100644 --- a/vendor/github.com/google/go-github/github/users_gpg_keys.go +++ b/vendor/github.com/google/go-github/github/users_gpg_keys.go @@ -6,6 +6,7 @@ package github import ( + "context" "fmt" "time" ) @@ -39,12 +40,24 @@ type GPGEmail struct { Verified *bool `json:"verified,omitempty"` } -// ListGPGKeys lists the current user's GPG keys. It requires authentication +// ListGPGKeys lists the public GPG keys for a user. Passing the empty +// string will fetch keys for the authenticated user. It requires authentication // via Basic Auth or via OAuth with at least read:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-your-gpg-keys -func (s *UsersService) ListGPGKeys() ([]*GPGKey, *Response, error) { - req, err := s.client.NewRequest("GET", "user/gpg_keys", nil) + +// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-gpg-keys-for-a-user +func (s *UsersService) ListGPGKeys(ctx context.Context, user string, opt *ListOptions) ([]*GPGKey, *Response, error) { + var u string + if user != "" { + u = fmt.Sprintf("users/%v/gpg_keys", user) + } else { + u = "user/gpg_keys" + } + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } @@ -53,19 +66,19 @@ func (s *UsersService) ListGPGKeys() ([]*GPGKey, *Response, error) { req.Header.Set("Accept", mediaTypeGitSigningPreview) var keys []*GPGKey - resp, err := s.client.Do(req, &keys) + resp, err := s.client.Do(ctx, req, &keys) if err != nil { return nil, resp, err } - return keys, resp, err + return keys, resp, nil } // GetGPGKey gets extended details for a single GPG key. It requires authentication // via Basic Auth or via OAuth with at least read:gpg_key scope. // // GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key -func (s *UsersService) GetGPGKey(id int) (*GPGKey, *Response, error) { +func (s *UsersService) GetGPGKey(ctx context.Context, id int) (*GPGKey, *Response, error) { u := fmt.Sprintf("user/gpg_keys/%v", id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -76,19 +89,19 @@ func (s *UsersService) GetGPGKey(id int) (*GPGKey, *Response, error) { req.Header.Set("Accept", mediaTypeGitSigningPreview) key := &GPGKey{} - resp, err := s.client.Do(req, key) + resp, err := s.client.Do(ctx, req, key) if err != nil { return nil, resp, err } - return key, resp, err + return key, resp, nil } // CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth // or OAuth with at least write:gpg_key scope. // // GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key -func (s *UsersService) CreateGPGKey(armoredPublicKey string) (*GPGKey, *Response, error) { +func (s *UsersService) CreateGPGKey(ctx context.Context, armoredPublicKey string) (*GPGKey, *Response, error) { gpgKey := &struct { ArmoredPublicKey string `json:"armored_public_key"` }{ArmoredPublicKey: armoredPublicKey} @@ -101,19 +114,19 @@ func (s *UsersService) CreateGPGKey(armoredPublicKey string) (*GPGKey, *Response req.Header.Set("Accept", mediaTypeGitSigningPreview) key := &GPGKey{} - resp, err := s.client.Do(req, key) + resp, err := s.client.Do(ctx, req, key) if err != nil { return nil, resp, err } - return key, resp, err + return key, resp, nil } // DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or // via OAuth with at least admin:gpg_key scope. // // GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key -func (s *UsersService) DeleteGPGKey(id int) (*Response, error) { +func (s *UsersService) DeleteGPGKey(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("user/gpg_keys/%v", id) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { @@ -123,5 +136,5 @@ func (s *UsersService) DeleteGPGKey(id int) (*Response, error) { // TODO: remove custom Accept header when this API fully launches. req.Header.Set("Accept", mediaTypeGitSigningPreview) - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/users_keys.go b/vendor/github.com/google/go-github/github/users_keys.go index e4c255f9c..97ed4b861 100644 --- a/vendor/github.com/google/go-github/github/users_keys.go +++ b/vendor/github.com/google/go-github/github/users_keys.go @@ -5,7 +5,10 @@ package github -import "fmt" +import ( + "context" + "fmt" +) // Key represents a public SSH key used to authenticate a user or deploy script. type Key struct { @@ -20,11 +23,11 @@ func (k Key) String() string { return Stringify(k) } -// ListKeys lists the verified public keys for a user. Passing the empty +// ListKeys lists the verified public keys for a user. Passing the empty // string will fetch keys for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/keys/#list-public-keys-for-a-user -func (s *UsersService) ListKeys(user string, opt *ListOptions) ([]*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user +func (s *UsersService) ListKeys(ctx context.Context, user string, opt *ListOptions) ([]*Key, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/keys", user) @@ -41,19 +44,19 @@ func (s *UsersService) ListKeys(user string, opt *ListOptions) ([]*Key, *Respons return nil, nil, err } - keys := new([]*Key) - resp, err := s.client.Do(req, keys) + var keys []*Key + resp, err := s.client.Do(ctx, req, &keys) if err != nil { return nil, resp, err } - return *keys, resp, err + return keys, resp, nil } // GetKey fetches a single public key. // -// GitHub API docs: http://developer.github.com/v3/users/keys/#get-a-single-public-key -func (s *UsersService) GetKey(id int) (*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/keys/#get-a-single-public-key +func (s *UsersService) GetKey(ctx context.Context, id int) (*Key, *Response, error) { u := fmt.Sprintf("user/keys/%v", id) req, err := s.client.NewRequest("GET", u, nil) @@ -62,18 +65,18 @@ func (s *UsersService) GetKey(id int) (*Key, *Response, error) { } key := new(Key) - resp, err := s.client.Do(req, key) + resp, err := s.client.Do(ctx, req, key) if err != nil { return nil, resp, err } - return key, resp, err + return key, resp, nil } // CreateKey adds a public key for the authenticated user. // -// GitHub API docs: http://developer.github.com/v3/users/keys/#create-a-public-key -func (s *UsersService) CreateKey(key *Key) (*Key, *Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/keys/#create-a-public-key +func (s *UsersService) CreateKey(ctx context.Context, key *Key) (*Key, *Response, error) { u := "user/keys" req, err := s.client.NewRequest("POST", u, key) @@ -82,18 +85,18 @@ func (s *UsersService) CreateKey(key *Key) (*Key, *Response, error) { } k := new(Key) - resp, err := s.client.Do(req, k) + resp, err := s.client.Do(ctx, req, k) if err != nil { return nil, resp, err } - return k, resp, err + return k, resp, nil } // DeleteKey deletes a public key. // -// GitHub API docs: http://developer.github.com/v3/users/keys/#delete-a-public-key -func (s *UsersService) DeleteKey(id int) (*Response, error) { +// GitHub API docs: https://developer.github.com/v3/users/keys/#delete-a-public-key +func (s *UsersService) DeleteKey(ctx context.Context, id int) (*Response, error) { u := fmt.Sprintf("user/keys/%v", id) req, err := s.client.NewRequest("DELETE", u, nil) @@ -101,5 +104,5 @@ func (s *UsersService) DeleteKey(id int) (*Response, error) { return nil, err } - return s.client.Do(req, nil) + return s.client.Do(ctx, req, nil) } diff --git a/vendor/github.com/google/go-github/github/with_appengine.go b/vendor/github.com/google/go-github/github/with_appengine.go new file mode 100644 index 000000000..957c4d307 --- /dev/null +++ b/vendor/github.com/google/go-github/github/with_appengine.go @@ -0,0 +1,26 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +// This file provides glue for making github work on App Engine. +// In order to get the entire github package to compile with +// Go 1.6, you will need to rewrite all the import "context" lines. +// Fortunately, this is easy with "gofmt": +// +// gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go + +package github + +import ( + "context" + "net/http" + + "google.golang.org/appengine" +) + +func withContext(ctx context.Context, req *http.Request) (context.Context, *http.Request) { + return appengine.WithContext(ctx, req), req +} diff --git a/vendor/github.com/google/go-github/github/without_appengine.go b/vendor/github.com/google/go-github/github/without_appengine.go new file mode 100644 index 000000000..b0edc04db --- /dev/null +++ b/vendor/github.com/google/go-github/github/without_appengine.go @@ -0,0 +1,19 @@ +// Copyright 2017 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// This file provides glue for making github work without App Engine. + +package github + +import ( + "context" + "net/http" +) + +func withContext(ctx context.Context, req *http.Request) (context.Context, *http.Request) { + return ctx, req.WithContext(ctx) +} diff --git a/vendor/github.com/google/go-querystring/query/encode.go b/vendor/github.com/google/go-querystring/query/encode.go index 19437b34f..37080b19b 100644 --- a/vendor/github.com/google/go-querystring/query/encode.go +++ b/vendor/github.com/google/go-querystring/query/encode.go @@ -217,11 +217,6 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error { continue } - if sv.Type() == timeType { - values.Add(name, valueString(sv, opts)) - continue - } - for sv.Kind() == reflect.Ptr { if sv.IsNil() { break @@ -229,6 +224,11 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error { sv = sv.Elem() } + if sv.Type() == timeType { + values.Add(name, valueString(sv, opts)) + continue + } + if sv.Kind() == reflect.Struct { reflectValue(values, sv, name) continue diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go index 73c740031..448d1bfca 100644 --- a/vendor/github.com/gorilla/context/doc.go +++ b/vendor/github.com/gorilla/context/doc.go @@ -5,6 +5,12 @@ /* Package context stores values shared during a request lifetime. +Note: gorilla/context, having been born well before `context.Context` existed, +does not play well > with the shallow copying of the request that +[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) +(added to net/http Go 1.7 onwards) performs. You should either use *just* +gorilla/context, or moving forward, the new `http.Request.Context()`. + For example, a router can set variables extracted from the URL and later application handlers can access those values, or it can be used to store sessions values to be saved at the end of a request. There are several diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 1b0e69ab2..43a87c753 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -66,8 +66,9 @@ type Dialer struct { // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration - // Input and output buffer sizes. If the buffer size is zero, then a - // default value of 4096 is used. + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then a useful default size is used. The I/O buffer sizes + // do not limit the size of the messages that can be sent or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the client's requested subprotocols. @@ -368,7 +369,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re return nil, resp, ErrBadHandshake } - for _, ext := range parseExtensions(req.Header) { + for _, ext := range parseExtensions(resp.Header) { if ext[""] != "permessage-deflate" { continue } diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index 7acc58a7d..97e1dbacb 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -268,33 +268,58 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil) } +type writeHook struct { + p []byte +} + +func (wh *writeHook) Write(p []byte) (int, error) { + wh.p = p + return len(p), nil +} + func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn { mu := make(chan bool, 1) mu <- true - if readBufferSize == 0 { - readBufferSize = defaultReadBufferSize - } - if readBufferSize < maxControlFramePayloadSize { - readBufferSize = maxControlFramePayloadSize - } - - // Reuse the supplied brw.Reader if brw.Reader's buf is the requested size. var br *bufio.Reader - if brw != nil && brw.Reader != nil { - // This code assumes that peek on a reset reader returns + if readBufferSize == 0 && brw != nil && brw.Reader != nil { + // Reuse the supplied bufio.Reader if the buffer has a useful size. + // This code assumes that peek on a reader returns // bufio.Reader.buf[:0]. brw.Reader.Reset(conn) - if p, err := brw.Reader.Peek(0); err == nil && cap(p) == readBufferSize { + if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 { br = brw.Reader } } if br == nil { + if readBufferSize == 0 { + readBufferSize = defaultReadBufferSize + } + if readBufferSize < maxControlFramePayloadSize { + readBufferSize = maxControlFramePayloadSize + } br = bufio.NewReaderSize(conn, readBufferSize) } - if writeBufferSize == 0 { - writeBufferSize = defaultWriteBufferSize + var writeBuf []byte + if writeBufferSize == 0 && brw != nil && brw.Writer != nil { + // Use the bufio.Writer's buffer if the buffer has a useful size. This + // code assumes that bufio.Writer.buf[:1] is passed to the + // bufio.Writer's underlying writer. + var wh writeHook + brw.Writer.Reset(&wh) + brw.Writer.WriteByte(0) + brw.Flush() + if cap(wh.p) >= maxFrameHeaderSize+256 { + writeBuf = wh.p[:cap(wh.p)] + } + } + + if writeBuf == nil { + if writeBufferSize == 0 { + writeBufferSize = defaultWriteBufferSize + } + writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize) } c := &Conn{ @@ -303,7 +328,7 @@ func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize in conn: conn, mu: mu, readFinal: true, - writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize), + writeBuf: writeBuf, enableWriteCompression: true, compressionLevel: defaultCompressionLevel, } diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go index 95c16566c..3495e0f1a 100644 --- a/vendor/github.com/gorilla/websocket/server.go +++ b/vendor/github.com/gorilla/websocket/server.go @@ -28,8 +28,9 @@ type Upgrader struct { HandshakeTimeout time.Duration // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer - // size is zero, then a default value of 4096 is used. The I/O buffer sizes - // do not limit the size of the messages that can be sent or received. + // size is zero, then buffers allocated by the HTTP server are used. The + // I/O buffer sizes do not limit the size of the messages that can be sent + // or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the server's supported protocols in order of diff --git a/vendor/github.com/hashicorp/consul/api/agent.go b/vendor/github.com/hashicorp/consul/api/agent.go index 3df013cc5..1893d1cf3 100644 --- a/vendor/github.com/hashicorp/consul/api/agent.go +++ b/vendor/github.com/hashicorp/consul/api/agent.go @@ -1,6 +1,7 @@ package api import ( + "bufio" "fmt" ) @@ -62,8 +63,7 @@ type AgentCheckRegistration struct { AgentServiceCheck } -// AgentServiceCheck is used to create an associated -// check for a service +// AgentServiceCheck is used to define a node or service level check type AgentServiceCheck struct { Script string `json:",omitempty"` DockerContainerID string `json:",omitempty"` @@ -74,6 +74,16 @@ type AgentServiceCheck struct { HTTP string `json:",omitempty"` TCP string `json:",omitempty"` Status string `json:",omitempty"` + Notes string `json:",omitempty"` + TLSSkipVerify bool `json:",omitempty"` + + // In Consul 0.7 and later, checks that are associated with a service + // may also contain this optional DeregisterCriticalServiceAfter field, + // which is a timeout in the same Go time format as Interval and TTL. If + // a check is in the critical state for more than this configured value, + // then its associated service (and all of its associated checks) will + // automatically be deregistered. + DeregisterCriticalServiceAfter string `json:",omitempty"` } type AgentServiceChecks []*AgentServiceCheck @@ -107,6 +117,17 @@ func (a *Agent) Self() (map[string]map[string]interface{}, error) { return out, nil } +// Reload triggers a configuration reload for the agent we are connected to. +func (a *Agent) Reload() error { + r := a.c.newRequest("PUT", "/v1/agent/reload") + _, resp, err := requireOK(a.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + // NodeName is used to get the node name of the agent func (a *Agent) NodeName() (string, error) { if a.nodeName != "" { @@ -338,6 +359,17 @@ func (a *Agent) Join(addr string, wan bool) error { return nil } +// Leave is used to have the agent gracefully leave the cluster and shutdown +func (a *Agent) Leave() error { + r := a.c.newRequest("PUT", "/v1/agent/leave") + _, resp, err := requireOK(a.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + // ForceLeave is used to have the agent eject a failed node func (a *Agent) ForceLeave(node string) error { r := a.c.newRequest("PUT", "/v1/agent/force-leave/"+node) @@ -402,3 +434,38 @@ func (a *Agent) DisableNodeMaintenance() error { resp.Body.Close() return nil } + +// Monitor returns a channel which will receive streaming logs from the agent +// Providing a non-nil stopCh can be used to close the connection and stop the +// log stream +func (a *Agent) Monitor(loglevel string, stopCh chan struct{}, q *QueryOptions) (chan string, error) { + r := a.c.newRequest("GET", "/v1/agent/monitor") + r.setQueryOptions(q) + if loglevel != "" { + r.params.Add("loglevel", loglevel) + } + _, resp, err := requireOK(a.c.doRequest(r)) + if err != nil { + return nil, err + } + + logCh := make(chan string, 64) + go func() { + defer resp.Body.Close() + + scanner := bufio.NewScanner(resp.Body) + for { + select { + case <-stopCh: + close(logCh) + return + default: + } + if scanner.Scan() { + logCh <- scanner.Text() + } + } + }() + + return logCh, nil +} diff --git a/vendor/github.com/hashicorp/consul/api/api.go b/vendor/github.com/hashicorp/consul/api/api.go index 590b858e1..f6fe5a1bd 100644 --- a/vendor/github.com/hashicorp/consul/api/api.go +++ b/vendor/github.com/hashicorp/consul/api/api.go @@ -2,6 +2,7 @@ package api import ( "bytes" + "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -20,6 +21,28 @@ import ( "github.com/hashicorp/go-cleanhttp" ) +const ( + // HTTPAddrEnvName defines an environment variable name which sets + // the HTTP address if there is no -http-addr specified. + HTTPAddrEnvName = "CONSUL_HTTP_ADDR" + + // HTTPTokenEnvName defines an environment variable name which sets + // the HTTP token. + HTTPTokenEnvName = "CONSUL_HTTP_TOKEN" + + // HTTPAuthEnvName defines an environment variable name which sets + // the HTTP authentication header. + HTTPAuthEnvName = "CONSUL_HTTP_AUTH" + + // HTTPSSLEnvName defines an environment variable name which sets + // whether or not to use HTTPS. + HTTPSSLEnvName = "CONSUL_HTTP_SSL" + + // HTTPSSLVerifyEnvName defines an environment variable name which sets + // whether or not to disable certificate checking. + HTTPSSLVerifyEnvName = "CONSUL_HTTP_SSL_VERIFY" +) + // QueryOptions are used to parameterize a query type QueryOptions struct { // Providing a datacenter overwrites the DC provided @@ -52,6 +75,16 @@ type QueryOptions struct { // that node. Setting this to "_agent" will use the agent's node // for the sort. Near string + + // NodeMeta is used to filter results by nodes with the given + // metadata key/value pairs. Currently, only one key/value pair can + // be provided for filtering. + NodeMeta map[string]string + + // RelayFactor is used in keyring operations to cause reponses to be + // relayed back to the sender through N other random nodes. Must be + // a value from 0 to 5 (inclusive). + RelayFactor uint8 } // WriteOptions are used to parameterize a write @@ -63,6 +96,11 @@ type WriteOptions struct { // Token is used to provide a per-request ACL token // which overrides the agent's default token. Token string + + // RelayFactor is used in keyring operations to cause reponses to be + // relayed back to the sender through N other random nodes. Must be + // a value from 0 to 5 (inclusive). + RelayFactor uint8 } // QueryMeta is used to return meta data about a query @@ -80,6 +118,9 @@ type QueryMeta struct { // How long did the request take RequestTime time.Duration + + // Is address translation enabled for HTTP responses on this agent + AddressTranslationEnabled bool } // WriteMeta is used to return meta data about a write @@ -178,15 +219,15 @@ func defaultConfig(transportFn func() *http.Transport) *Config { }, } - if addr := os.Getenv("CONSUL_HTTP_ADDR"); addr != "" { + if addr := os.Getenv(HTTPAddrEnvName); addr != "" { config.Address = addr } - if token := os.Getenv("CONSUL_HTTP_TOKEN"); token != "" { + if token := os.Getenv(HTTPTokenEnvName); token != "" { config.Token = token } - if auth := os.Getenv("CONSUL_HTTP_AUTH"); auth != "" { + if auth := os.Getenv(HTTPAuthEnvName); auth != "" { var username, password string if strings.Contains(auth, ":") { split := strings.SplitN(auth, ":", 2) @@ -202,10 +243,10 @@ func defaultConfig(transportFn func() *http.Transport) *Config { } } - if ssl := os.Getenv("CONSUL_HTTP_SSL"); ssl != "" { + if ssl := os.Getenv(HTTPSSLEnvName); ssl != "" { enabled, err := strconv.ParseBool(ssl) if err != nil { - log.Printf("[WARN] client: could not parse CONSUL_HTTP_SSL: %s", err) + log.Printf("[WARN] client: could not parse %s: %s", HTTPSSLEnvName, err) } if enabled { @@ -213,10 +254,10 @@ func defaultConfig(transportFn func() *http.Transport) *Config { } } - if verify := os.Getenv("CONSUL_HTTP_SSL_VERIFY"); verify != "" { + if verify := os.Getenv(HTTPSSLVerifyEnvName); verify != "" { doVerify, err := strconv.ParseBool(verify) if err != nil { - log.Printf("[WARN] client: could not parse CONSUL_HTTP_SSL_VERIFY: %s", err) + log.Printf("[WARN] client: could not parse %s: %s", HTTPSSLVerifyEnvName, err) } if !doVerify { @@ -306,13 +347,22 @@ func NewClient(config *Config) (*Client, error) { config.HttpClient = defConfig.HttpClient } - if parts := strings.SplitN(config.Address, "unix://", 2); len(parts) == 2 { - trans := cleanhttp.DefaultTransport() - trans.Dial = func(_, _ string) (net.Conn, error) { - return net.Dial("unix", parts[1]) - } - config.HttpClient = &http.Client{ - Transport: trans, + parts := strings.SplitN(config.Address, "://", 2) + if len(parts) == 2 { + switch parts[0] { + case "http": + case "https": + config.Scheme = "https" + case "unix": + trans := cleanhttp.DefaultTransport() + trans.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", parts[1]) + } + config.HttpClient = &http.Client{ + Transport: trans, + } + default: + return nil, fmt.Errorf("Unknown protocol scheme: %s", parts[0]) } config.Address = parts[1] } @@ -330,6 +380,7 @@ type request struct { url *url.URL params url.Values body io.Reader + header http.Header obj interface{} } @@ -355,11 +406,19 @@ func (r *request) setQueryOptions(q *QueryOptions) { r.params.Set("wait", durToMsec(q.WaitTime)) } if q.Token != "" { - r.params.Set("token", q.Token) + r.header.Set("X-Consul-Token", q.Token) } if q.Near != "" { r.params.Set("near", q.Near) } + if len(q.NodeMeta) > 0 { + for key, value := range q.NodeMeta { + r.params.Add("node-meta", key+":"+value) + } + } + if q.RelayFactor != 0 { + r.params.Set("relay-factor", strconv.Itoa(int(q.RelayFactor))) + } } // durToMsec converts a duration to a millisecond specified string. If the @@ -399,7 +458,10 @@ func (r *request) setWriteOptions(q *WriteOptions) { r.params.Set("dc", q.Datacenter) } if q.Token != "" { - r.params.Set("token", q.Token) + r.header.Set("X-Consul-Token", q.Token) + } + if q.RelayFactor != 0 { + r.params.Set("relay-factor", strconv.Itoa(int(q.RelayFactor))) } } @@ -426,6 +488,7 @@ func (r *request) toHTTP() (*http.Request, error) { req.URL.Host = r.url.Host req.URL.Scheme = r.url.Scheme req.Host = r.url.Host + req.Header = r.header // Setup auth if r.config.HttpAuth != nil { @@ -446,6 +509,7 @@ func (c *Client) newRequest(method, path string) *request { Path: path, }, params: make(map[string][]string), + header: make(http.Header), } if c.config.Datacenter != "" { r.params.Set("dc", c.config.Datacenter) @@ -454,7 +518,7 @@ func (c *Client) newRequest(method, path string) *request { r.params.Set("wait", durToMsec(r.config.WaitTime)) } if c.config.Token != "" { - r.params.Set("token", r.config.Token) + r.header.Set("X-Consul-Token", r.config.Token) } return r } @@ -539,6 +603,15 @@ func parseQueryMeta(resp *http.Response, q *QueryMeta) error { default: q.KnownLeader = false } + + // Parse X-Consul-Translate-Addresses + switch header.Get("X-Consul-Translate-Addresses") { + case "true": + q.AddressTranslationEnabled = true + default: + q.AddressTranslationEnabled = false + } + return nil } diff --git a/vendor/github.com/hashicorp/consul/api/catalog.go b/vendor/github.com/hashicorp/consul/api/catalog.go index 52a00b304..96226f11f 100644 --- a/vendor/github.com/hashicorp/consul/api/catalog.go +++ b/vendor/github.com/hashicorp/consul/api/catalog.go @@ -1,19 +1,27 @@ package api type Node struct { - Node string - Address string + ID string + Node string + Address string + TaggedAddresses map[string]string + Meta map[string]string } type CatalogService struct { + ID string Node string Address string + TaggedAddresses map[string]string + NodeMeta map[string]string ServiceID string ServiceName string ServiceAddress string ServiceTags []string ServicePort int ServiceEnableTagOverride bool + CreateIndex uint64 + ModifyIndex uint64 } type CatalogNode struct { @@ -22,16 +30,19 @@ type CatalogNode struct { } type CatalogRegistration struct { - Node string - Address string - Datacenter string - Service *AgentService - Check *AgentCheck + ID string + Node string + Address string + TaggedAddresses map[string]string + NodeMeta map[string]string + Datacenter string + Service *AgentService + Check *AgentCheck } type CatalogDeregistration struct { Node string - Address string + Address string // Obsolete. Datacenter string ServiceID string CheckID string diff --git a/vendor/github.com/hashicorp/consul/api/coordinate.go b/vendor/github.com/hashicorp/consul/api/coordinate.go index fdff2075c..ae8d16ee6 100644 --- a/vendor/github.com/hashicorp/consul/api/coordinate.go +++ b/vendor/github.com/hashicorp/consul/api/coordinate.go @@ -10,10 +10,11 @@ type CoordinateEntry struct { Coord *coordinate.Coordinate } -// CoordinateDatacenterMap represents a datacenter and its associated WAN -// nodes and their associates coordinates. +// CoordinateDatacenterMap has the coordinates for servers in a given datacenter +// and area. Network coordinates are only compatible within the same area. type CoordinateDatacenterMap struct { Datacenter string + AreaID string Coordinates []CoordinateEntry } diff --git a/vendor/github.com/hashicorp/consul/api/health.go b/vendor/github.com/hashicorp/consul/api/health.go index 5bb403f55..8abe2393a 100644 --- a/vendor/github.com/hashicorp/consul/api/health.go +++ b/vendor/github.com/hashicorp/consul/api/health.go @@ -2,16 +2,25 @@ package api import ( "fmt" + "strings" ) const ( // HealthAny is special, and is used as a wild card, // not as a specific state. HealthAny = "any" - HealthUnknown = "unknown" HealthPassing = "passing" HealthWarning = "warning" HealthCritical = "critical" + HealthMaint = "maintenance" +) + +const ( + // NodeMaint is the special key set by a node in maintenance mode. + NodeMaint = "_node_maintenance" + + // ServiceMaintPrefix is the prefix for a service in maintenance mode. + ServiceMaintPrefix = "_service_maintenance:" ) // HealthCheck is used to represent a single check @@ -26,11 +35,56 @@ type HealthCheck struct { ServiceName string } +// HealthChecks is a collection of HealthCheck structs. +type HealthChecks []*HealthCheck + +// AggregatedStatus returns the "best" status for the list of health checks. +// Because a given entry may have many service and node-level health checks +// attached, this function determines the best representative of the status as +// as single string using the following heuristic: +// +// maintenance > critical > warning > passing +// +func (c HealthChecks) AggregatedStatus() string { + var passing, warning, critical, maintenance bool + for _, check := range c { + id := string(check.CheckID) + if id == NodeMaint || strings.HasPrefix(id, ServiceMaintPrefix) { + maintenance = true + continue + } + + switch check.Status { + case HealthPassing: + passing = true + case HealthWarning: + warning = true + case HealthCritical: + critical = true + default: + return "" + } + } + + switch { + case maintenance: + return HealthMaint + case critical: + return HealthCritical + case warning: + return HealthWarning + case passing: + return HealthPassing + default: + return HealthPassing + } +} + // ServiceEntry is used for the health service endpoint type ServiceEntry struct { Node *Node Service *AgentService - Checks []*HealthCheck + Checks HealthChecks } // Health can be used to query the Health endpoints @@ -44,7 +98,7 @@ func (c *Client) Health() *Health { } // Node is used to query for checks belonging to a given node -func (h *Health) Node(node string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { +func (h *Health) Node(node string, q *QueryOptions) (HealthChecks, *QueryMeta, error) { r := h.c.newRequest("GET", "/v1/health/node/"+node) r.setQueryOptions(q) rtt, resp, err := requireOK(h.c.doRequest(r)) @@ -57,7 +111,7 @@ func (h *Health) Node(node string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, parseQueryMeta(resp, qm) qm.RequestTime = rtt - var out []*HealthCheck + var out HealthChecks if err := decodeBody(resp, &out); err != nil { return nil, nil, err } @@ -65,7 +119,7 @@ func (h *Health) Node(node string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, } // Checks is used to return the checks associated with a service -func (h *Health) Checks(service string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { +func (h *Health) Checks(service string, q *QueryOptions) (HealthChecks, *QueryMeta, error) { r := h.c.newRequest("GET", "/v1/health/checks/"+service) r.setQueryOptions(q) rtt, resp, err := requireOK(h.c.doRequest(r)) @@ -78,7 +132,7 @@ func (h *Health) Checks(service string, q *QueryOptions) ([]*HealthCheck, *Query parseQueryMeta(resp, qm) qm.RequestTime = rtt - var out []*HealthCheck + var out HealthChecks if err := decodeBody(resp, &out); err != nil { return nil, nil, err } @@ -116,13 +170,12 @@ func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) // State is used to retrieve all the checks in a given state. // The wildcard "any" state can also be used for all checks. -func (h *Health) State(state string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { +func (h *Health) State(state string, q *QueryOptions) (HealthChecks, *QueryMeta, error) { switch state { case HealthAny: case HealthWarning: case HealthCritical: case HealthPassing: - case HealthUnknown: default: return nil, nil, fmt.Errorf("Unsupported state: %v", state) } @@ -138,7 +191,7 @@ func (h *Health) State(state string, q *QueryOptions) ([]*HealthCheck, *QueryMet parseQueryMeta(resp, qm) qm.RequestTime = rtt - var out []*HealthCheck + var out HealthChecks if err := decodeBody(resp, &out); err != nil { return nil, nil, err } diff --git a/vendor/github.com/hashicorp/consul/api/kv.go b/vendor/github.com/hashicorp/consul/api/kv.go index 3dac2583c..44e06bbb4 100644 --- a/vendor/github.com/hashicorp/consul/api/kv.go +++ b/vendor/github.com/hashicorp/consul/api/kv.go @@ -11,13 +11,35 @@ import ( // KVPair is used to represent a single K/V entry type KVPair struct { - Key string + // Key is the name of the key. It is also part of the URL path when accessed + // via the API. + Key string + + // CreateIndex holds the index corresponding the creation of this KVPair. This + // is a read-only field. CreateIndex uint64 + + // ModifyIndex is used for the Check-And-Set operations and can also be fed + // back into the WaitIndex of the QueryOptions in order to perform blocking + // queries. ModifyIndex uint64 - LockIndex uint64 - Flags uint64 - Value []byte - Session string + + // LockIndex holds the index corresponding to a lock on this key, if any. This + // is a read-only field. + LockIndex uint64 + + // Flags are any user-defined flags on the key. It is up to the implementer + // to check these values, since Consul does not treat them specially. + Flags uint64 + + // Value is the value for the key. This can be any value, but it will be + // base64 encoded upon transport. + Value []byte + + // Session is a string representing the ID of the session. Any other + // interactions with this key over the same session must specify the same + // session ID. + Session string } // KVPairs is a list of KVPair objects @@ -28,21 +50,21 @@ type KVOp string const ( KVSet KVOp = "set" - KVDelete = "delete" - KVDeleteCAS = "delete-cas" - KVDeleteTree = "delete-tree" - KVCAS = "cas" - KVLock = "lock" - KVUnlock = "unlock" - KVGet = "get" - KVGetTree = "get-tree" - KVCheckSession = "check-session" - KVCheckIndex = "check-index" + KVDelete KVOp = "delete" + KVDeleteCAS KVOp = "delete-cas" + KVDeleteTree KVOp = "delete-tree" + KVCAS KVOp = "cas" + KVLock KVOp = "lock" + KVUnlock KVOp = "unlock" + KVGet KVOp = "get" + KVGetTree KVOp = "get-tree" + KVCheckSession KVOp = "check-session" + KVCheckIndex KVOp = "check-index" ) // KVTxnOp defines a single operation inside a transaction. type KVTxnOp struct { - Verb string + Verb KVOp Key string Value []byte Flags uint64 @@ -70,7 +92,8 @@ func (c *Client) KV() *KV { return &KV{c} } -// Get is used to lookup a single key +// Get is used to lookup a single key. The returned pointer +// to the KVPair will be nil if the key does not exist. func (k *KV) Get(key string, q *QueryOptions) (*KVPair, *QueryMeta, error) { resp, qm, err := k.getInternal(key, nil, q) if err != nil { @@ -133,7 +156,7 @@ func (k *KV) Keys(prefix, separator string, q *QueryOptions) ([]string, *QueryMe } func (k *KV) getInternal(key string, params map[string]string, q *QueryOptions) (*http.Response, *QueryMeta, error) { - r := k.c.newRequest("GET", "/v1/kv/"+key) + r := k.c.newRequest("GET", "/v1/kv/"+strings.TrimPrefix(key, "/")) r.setQueryOptions(q) for param, val := range params { r.params.Set(param, val) @@ -254,7 +277,7 @@ func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) { } func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOptions) (bool, *WriteMeta, error) { - r := k.c.newRequest("DELETE", "/v1/kv/"+key) + r := k.c.newRequest("DELETE", "/v1/kv/"+strings.TrimPrefix(key, "/")) r.setWriteOptions(q) for param, val := range params { r.params.Set(param, val) diff --git a/vendor/github.com/hashicorp/consul/api/lock.go b/vendor/github.com/hashicorp/consul/api/lock.go index 08e8e7931..9f9845a43 100644 --- a/vendor/github.com/hashicorp/consul/api/lock.go +++ b/vendor/github.com/hashicorp/consul/api/lock.go @@ -72,8 +72,9 @@ type LockOptions struct { Key string // Must be set and have write permissions Value []byte // Optional, value to associate with the lock Session string // Optional, created if not specified - SessionName string // Optional, defaults to DefaultLockSessionName - SessionTTL string // Optional, defaults to DefaultLockSessionTTL + SessionOpts *SessionEntry // Optional, options to use when creating a session + SessionName string // Optional, defaults to DefaultLockSessionName (ignored if SessionOpts is given) + SessionTTL string // Optional, defaults to DefaultLockSessionTTL (ignored if SessionOpts is given) MonitorRetries int // Optional, defaults to 0 which means no retries MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime LockWaitTime time.Duration // Optional, defaults to DefaultLockWaitTime @@ -329,9 +330,12 @@ func (l *Lock) Destroy() error { // createSession is used to create a new managed session func (l *Lock) createSession() (string, error) { session := l.c.Session() - se := &SessionEntry{ - Name: l.opts.SessionName, - TTL: l.opts.SessionTTL, + se := l.opts.SessionOpts + if se == nil { + se = &SessionEntry{ + Name: l.opts.SessionName, + TTL: l.opts.SessionTTL, + } } id, _, err := session.Create(se, nil) if err != nil { diff --git a/vendor/github.com/hashicorp/consul/api/operator.go b/vendor/github.com/hashicorp/consul/api/operator.go new file mode 100644 index 000000000..079e22486 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/operator.go @@ -0,0 +1,11 @@ +package api + +// Operator can be used to perform low-level operator tasks for Consul. +type Operator struct { + c *Client +} + +// Operator returns a handle to the operator endpoints. +func (c *Client) Operator() *Operator { + return &Operator{c} +} diff --git a/vendor/github.com/hashicorp/consul/api/operator_area.go b/vendor/github.com/hashicorp/consul/api/operator_area.go new file mode 100644 index 000000000..7b0e461e9 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/operator_area.go @@ -0,0 +1,168 @@ +// The /v1/operator/area endpoints are available only in Consul Enterprise and +// interact with its network area subsystem. Network areas are used to link +// together Consul servers in different Consul datacenters. With network areas, +// Consul datacenters can be linked together in ways other than a fully-connected +// mesh, as is required for Consul's WAN. +package api + +import ( + "net" + "time" +) + +// Area defines a network area. +type Area struct { + // ID is this identifier for an area (a UUID). This must be left empty + // when creating a new area. + ID string + + // PeerDatacenter is the peer Consul datacenter that will make up the + // other side of this network area. Network areas always involve a pair + // of datacenters: the datacenter where the area was created, and the + // peer datacenter. This is required. + PeerDatacenter string + + // RetryJoin specifies the address of Consul servers to join to, such as + // an IPs or hostnames with an optional port number. This is optional. + RetryJoin []string +} + +// AreaJoinResponse is returned when a join occurs and gives the result for each +// address. +type AreaJoinResponse struct { + // The address that was joined. + Address string + + // Whether or not the join was a success. + Joined bool + + // If we couldn't join, this is the message with information. + Error string +} + +// SerfMember is a generic structure for reporting information about members in +// a Serf cluster. This is only used by the area endpoints right now, but this +// could be expanded to other endpoints in the future. +type SerfMember struct { + // ID is the node identifier (a UUID). + ID string + + // Name is the node name. + Name string + + // Addr has the IP address. + Addr net.IP + + // Port is the RPC port. + Port uint16 + + // Datacenter is the DC name. + Datacenter string + + // Role is "client", "server", or "unknown". + Role string + + // Build has the version of the Consul agent. + Build string + + // Protocol is the protocol of the Consul agent. + Protocol int + + // Status is the Serf health status "none", "alive", "leaving", "left", + // or "failed". + Status string + + // RTT is the estimated round trip time from the server handling the + // request to the this member. This will be negative if no RTT estimate + // is available. + RTT time.Duration +} + +// AreaCreate will create a new network area. The ID in the given structure must +// be empty and a generated ID will be returned on success. +func (op *Operator) AreaCreate(area *Area, q *WriteOptions) (string, *WriteMeta, error) { + r := op.c.newRequest("POST", "/v1/operator/area") + r.setWriteOptions(q) + r.obj = area + rtt, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return "", nil, err + } + defer resp.Body.Close() + + wm := &WriteMeta{} + wm.RequestTime = rtt + + var out struct{ ID string } + if err := decodeBody(resp, &out); err != nil { + return "", nil, err + } + return out.ID, wm, nil +} + +// AreaGet returns a single network area. +func (op *Operator) AreaGet(areaID string, q *QueryOptions) ([]*Area, *QueryMeta, error) { + var out []*Area + qm, err := op.c.query("/v1/operator/area/"+areaID, &out, q) + if err != nil { + return nil, nil, err + } + return out, qm, nil +} + +// AreaList returns all the available network areas. +func (op *Operator) AreaList(q *QueryOptions) ([]*Area, *QueryMeta, error) { + var out []*Area + qm, err := op.c.query("/v1/operator/area", &out, q) + if err != nil { + return nil, nil, err + } + return out, qm, nil +} + +// AreaDelete deletes the given network area. +func (op *Operator) AreaDelete(areaID string, q *WriteOptions) (*WriteMeta, error) { + r := op.c.newRequest("DELETE", "/v1/operator/area/"+areaID) + r.setWriteOptions(q) + rtt, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + wm := &WriteMeta{} + wm.RequestTime = rtt + return wm, nil +} + +// AreaJoin attempts to join the given set of join addresses to the given +// network area. See the Area structure for details about join addresses. +func (op *Operator) AreaJoin(areaID string, addresses []string, q *WriteOptions) ([]*AreaJoinResponse, *WriteMeta, error) { + r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID+"/join") + r.setWriteOptions(q) + r.obj = addresses + rtt, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + + wm := &WriteMeta{} + wm.RequestTime = rtt + + var out []*AreaJoinResponse + if err := decodeBody(resp, &out); err != nil { + return nil, nil, err + } + return out, wm, nil +} + +// AreaMembers lists the Serf information about the members in the given area. +func (op *Operator) AreaMembers(areaID string, q *QueryOptions) ([]*SerfMember, *QueryMeta, error) { + var out []*SerfMember + qm, err := op.c.query("/v1/operator/area/"+areaID+"/members", &out, q) + if err != nil { + return nil, nil, err + } + return out, qm, nil +} diff --git a/vendor/github.com/hashicorp/consul/api/operator_autopilot.go b/vendor/github.com/hashicorp/consul/api/operator_autopilot.go new file mode 100644 index 000000000..59471ecf9 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/operator_autopilot.go @@ -0,0 +1,215 @@ +package api + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" + "time" +) + +// AutopilotConfiguration is used for querying/setting the Autopilot configuration. +// Autopilot helps manage operator tasks related to Consul servers like removing +// failed servers from the Raft quorum. +type AutopilotConfiguration struct { + // CleanupDeadServers controls whether to remove dead servers from the Raft + // peer list when a new server joins + CleanupDeadServers bool + + // LastContactThreshold is the limit on the amount of time a server can go + // without leader contact before being considered unhealthy. + LastContactThreshold *ReadableDuration + + // MaxTrailingLogs is the amount of entries in the Raft Log that a server can + // be behind before being considered unhealthy. + MaxTrailingLogs uint64 + + // ServerStabilizationTime is the minimum amount of time a server must be + // in a stable, healthy state before it can be added to the cluster. Only + // applicable with Raft protocol version 3 or higher. + ServerStabilizationTime *ReadableDuration + + // (Enterprise-only) RedundancyZoneTag is the node tag to use for separating + // servers into zones for redundancy. If left blank, this feature will be disabled. + RedundancyZoneTag string + + // (Enterprise-only) DisableUpgradeMigration will disable Autopilot's upgrade migration + // strategy of waiting until enough newer-versioned servers have been added to the + // cluster before promoting them to voters. + DisableUpgradeMigration bool + + // CreateIndex holds the index corresponding the creation of this configuration. + // This is a read-only field. + CreateIndex uint64 + + // ModifyIndex will be set to the index of the last update when retrieving the + // Autopilot configuration. Resubmitting a configuration with + // AutopilotCASConfiguration will perform a check-and-set operation which ensures + // there hasn't been a subsequent update since the configuration was retrieved. + ModifyIndex uint64 +} + +// ServerHealth is the health (from the leader's point of view) of a server. +type ServerHealth struct { + // ID is the raft ID of the server. + ID string + + // Name is the node name of the server. + Name string + + // Address is the address of the server. + Address string + + // The status of the SerfHealth check for the server. + SerfStatus string + + // Version is the Consul version of the server. + Version string + + // Leader is whether this server is currently the leader. + Leader bool + + // LastContact is the time since this node's last contact with the leader. + LastContact *ReadableDuration + + // LastTerm is the highest leader term this server has a record of in its Raft log. + LastTerm uint64 + + // LastIndex is the last log index this server has a record of in its Raft log. + LastIndex uint64 + + // Healthy is whether or not the server is healthy according to the current + // Autopilot config. + Healthy bool + + // Voter is whether this is a voting server. + Voter bool + + // StableSince is the last time this server's Healthy value changed. + StableSince time.Time +} + +// OperatorHealthReply is a representation of the overall health of the cluster +type OperatorHealthReply struct { + // Healthy is true if all the servers in the cluster are healthy. + Healthy bool + + // FailureTolerance is the number of healthy servers that could be lost without + // an outage occurring. + FailureTolerance int + + // Servers holds the health of each server. + Servers []ServerHealth +} + +// ReadableDuration is a duration type that is serialized to JSON in human readable format. +type ReadableDuration time.Duration + +func NewReadableDuration(dur time.Duration) *ReadableDuration { + d := ReadableDuration(dur) + return &d +} + +func (d *ReadableDuration) String() string { + return d.Duration().String() +} + +func (d *ReadableDuration) Duration() time.Duration { + if d == nil { + return time.Duration(0) + } + return time.Duration(*d) +} + +func (d *ReadableDuration) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, d.Duration().String())), nil +} + +func (d *ReadableDuration) UnmarshalJSON(raw []byte) error { + if d == nil { + return fmt.Errorf("cannot unmarshal to nil pointer") + } + + str := string(raw) + if len(str) < 2 || str[0] != '"' || str[len(str)-1] != '"' { + return fmt.Errorf("must be enclosed with quotes: %s", str) + } + dur, err := time.ParseDuration(str[1 : len(str)-1]) + if err != nil { + return err + } + *d = ReadableDuration(dur) + return nil +} + +// AutopilotGetConfiguration is used to query the current Autopilot configuration. +func (op *Operator) AutopilotGetConfiguration(q *QueryOptions) (*AutopilotConfiguration, error) { + r := op.c.newRequest("GET", "/v1/operator/autopilot/configuration") + r.setQueryOptions(q) + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var out AutopilotConfiguration + if err := decodeBody(resp, &out); err != nil { + return nil, err + } + + return &out, nil +} + +// AutopilotSetConfiguration is used to set the current Autopilot configuration. +func (op *Operator) AutopilotSetConfiguration(conf *AutopilotConfiguration, q *WriteOptions) error { + r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration") + r.setWriteOptions(q) + r.obj = conf + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// AutopilotCASConfiguration is used to perform a Check-And-Set update on the +// Autopilot configuration. The ModifyIndex value will be respected. Returns +// true on success or false on failures. +func (op *Operator) AutopilotCASConfiguration(conf *AutopilotConfiguration, q *WriteOptions) (bool, error) { + r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration") + r.setWriteOptions(q) + r.params.Set("cas", strconv.FormatUint(conf.ModifyIndex, 10)) + r.obj = conf + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return false, err + } + defer resp.Body.Close() + + var buf bytes.Buffer + if _, err := io.Copy(&buf, resp.Body); err != nil { + return false, fmt.Errorf("Failed to read response: %v", err) + } + res := strings.Contains(string(buf.Bytes()), "true") + + return res, nil +} + +// AutopilotServerHealth +func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply, error) { + r := op.c.newRequest("GET", "/v1/operator/autopilot/health") + r.setQueryOptions(q) + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var out OperatorHealthReply + if err := decodeBody(resp, &out); err != nil { + return nil, err + } + return &out, nil +} diff --git a/vendor/github.com/hashicorp/consul/api/operator_keyring.go b/vendor/github.com/hashicorp/consul/api/operator_keyring.go new file mode 100644 index 000000000..4f91c3543 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/operator_keyring.go @@ -0,0 +1,83 @@ +package api + +// keyringRequest is used for performing Keyring operations +type keyringRequest struct { + Key string +} + +// KeyringResponse is returned when listing the gossip encryption keys +type KeyringResponse struct { + // Whether this response is for a WAN ring + WAN bool + + // The datacenter name this request corresponds to + Datacenter string + + // A map of the encryption keys to the number of nodes they're installed on + Keys map[string]int + + // The total number of nodes in this ring + NumNodes int +} + +// KeyringInstall is used to install a new gossip encryption key into the cluster +func (op *Operator) KeyringInstall(key string, q *WriteOptions) error { + r := op.c.newRequest("POST", "/v1/operator/keyring") + r.setWriteOptions(q) + r.obj = keyringRequest{ + Key: key, + } + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// KeyringList is used to list the gossip keys installed in the cluster +func (op *Operator) KeyringList(q *QueryOptions) ([]*KeyringResponse, error) { + r := op.c.newRequest("GET", "/v1/operator/keyring") + r.setQueryOptions(q) + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var out []*KeyringResponse + if err := decodeBody(resp, &out); err != nil { + return nil, err + } + return out, nil +} + +// KeyringRemove is used to remove a gossip encryption key from the cluster +func (op *Operator) KeyringRemove(key string, q *WriteOptions) error { + r := op.c.newRequest("DELETE", "/v1/operator/keyring") + r.setWriteOptions(q) + r.obj = keyringRequest{ + Key: key, + } + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// KeyringUse is used to change the active gossip encryption key +func (op *Operator) KeyringUse(key string, q *WriteOptions) error { + r := op.c.newRequest("PUT", "/v1/operator/keyring") + r.setWriteOptions(q) + r.obj = keyringRequest{ + Key: key, + } + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + resp.Body.Close() + return nil +} diff --git a/vendor/github.com/hashicorp/consul/api/operator_raft.go b/vendor/github.com/hashicorp/consul/api/operator_raft.go new file mode 100644 index 000000000..5f3c25b13 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/operator_raft.go @@ -0,0 +1,86 @@ +package api + +// RaftServer has information about a server in the Raft configuration. +type RaftServer struct { + // ID is the unique ID for the server. These are currently the same + // as the address, but they will be changed to a real GUID in a future + // release of Consul. + ID string + + // Node is the node name of the server, as known by Consul, or this + // will be set to "(unknown)" otherwise. + Node string + + // Address is the IP:port of the server, used for Raft communications. + Address string + + // Leader is true if this server is the current cluster leader. + Leader bool + + // Voter is true if this server has a vote in the cluster. This might + // be false if the server is staging and still coming online, or if + // it's a non-voting server, which will be added in a future release of + // Consul. + Voter bool +} + +// RaftConfigration is returned when querying for the current Raft configuration. +type RaftConfiguration struct { + // Servers has the list of servers in the Raft configuration. + Servers []*RaftServer + + // Index has the Raft index of this configuration. + Index uint64 +} + +// RaftGetConfiguration is used to query the current Raft peer set. +func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) { + r := op.c.newRequest("GET", "/v1/operator/raft/configuration") + r.setQueryOptions(q) + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var out RaftConfiguration + if err := decodeBody(resp, &out); err != nil { + return nil, err + } + return &out, nil +} + +// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft +// quorum but no longer known to Serf or the catalog) by address in the form of +// "IP:port". +func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error { + r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") + r.setWriteOptions(q) + + r.params.Set("address", string(address)) + + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + + resp.Body.Close() + return nil +} + +// RaftRemovePeerByID is used to kick a stale peer (one that it in the Raft +// quorum but no longer known to Serf or the catalog) by ID. +func (op *Operator) RaftRemovePeerByID(id string, q *WriteOptions) error { + r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") + r.setWriteOptions(q) + + r.params.Set("id", string(id)) + + _, resp, err := requireOK(op.c.doRequest(r)) + if err != nil { + return err + } + + resp.Body.Close() + return nil +} diff --git a/vendor/github.com/hashicorp/consul/api/prepared_query.go b/vendor/github.com/hashicorp/consul/api/prepared_query.go index 63e741e05..ff210de3f 100644 --- a/vendor/github.com/hashicorp/consul/api/prepared_query.go +++ b/vendor/github.com/hashicorp/consul/api/prepared_query.go @@ -43,6 +43,11 @@ type ServiceQuery struct { // this list it must be present. If the tag is preceded with "!" then // it is disallowed. Tags []string + + // NodeMeta is a map of required node metadata fields. If a key/value + // pair is in this map it must be present on the node in order for the + // service entry to be returned. + NodeMeta map[string]string } // QueryTemplate carries the arguments for creating a templated query. @@ -167,19 +172,18 @@ func (c *PreparedQuery) Get(queryID string, q *QueryOptions) ([]*PreparedQueryDe } // Delete is used to delete a specific prepared query. -func (c *PreparedQuery) Delete(queryID string, q *QueryOptions) (*QueryMeta, error) { +func (c *PreparedQuery) Delete(queryID string, q *WriteOptions) (*WriteMeta, error) { r := c.c.newRequest("DELETE", "/v1/query/"+queryID) - r.setQueryOptions(q) + r.setWriteOptions(q) rtt, resp, err := requireOK(c.c.doRequest(r)) if err != nil { return nil, err } defer resp.Body.Close() - qm := &QueryMeta{} - parseQueryMeta(resp, qm) - qm.RequestTime = rtt - return qm, nil + wm := &WriteMeta{} + wm.RequestTime = rtt + return wm, nil } // Execute is used to execute a specific prepared query. You can execute using diff --git a/vendor/github.com/hashicorp/consul/api/snapshot.go b/vendor/github.com/hashicorp/consul/api/snapshot.go new file mode 100644 index 000000000..e902377dd --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/snapshot.go @@ -0,0 +1,47 @@ +package api + +import ( + "io" +) + +// Snapshot can be used to query the /v1/snapshot endpoint to take snapshots of +// Consul's internal state and restore snapshots for disaster recovery. +type Snapshot struct { + c *Client +} + +// Snapshot returns a handle that exposes the snapshot endpoints. +func (c *Client) Snapshot() *Snapshot { + return &Snapshot{c} +} + +// Save requests a new snapshot and provides an io.ReadCloser with the snapshot +// data to save. If this doesn't return an error, then it's the responsibility +// of the caller to close it. Only a subset of the QueryOptions are supported: +// Datacenter, AllowStale, and Token. +func (s *Snapshot) Save(q *QueryOptions) (io.ReadCloser, *QueryMeta, error) { + r := s.c.newRequest("GET", "/v1/snapshot") + r.setQueryOptions(q) + + rtt, resp, err := requireOK(s.c.doRequest(r)) + if err != nil { + return nil, nil, err + } + + qm := &QueryMeta{} + parseQueryMeta(resp, qm) + qm.RequestTime = rtt + return resp.Body, qm, nil +} + +// Restore streams in an existing snapshot and attempts to restore it. +func (s *Snapshot) Restore(q *WriteOptions, in io.Reader) error { + r := s.c.newRequest("PUT", "/v1/snapshot") + r.body = in + r.setWriteOptions(q) + _, _, err := requireOK(s.c.doRequest(r)) + if err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/hashicorp/consul/commands.go b/vendor/github.com/hashicorp/consul/commands.go index 84f0c07fe..99406274a 100644 --- a/vendor/github.com/hashicorp/consul/commands.go +++ b/vendor/github.com/hashicorp/consul/commands.go @@ -7,6 +7,8 @@ import ( "github.com/hashicorp/consul/command" "github.com/hashicorp/consul/command/agent" + "github.com/hashicorp/consul/command/base" + "github.com/hashicorp/consul/version" "github.com/mitchellh/cli" ) @@ -14,116 +16,323 @@ import ( var Commands map[string]cli.CommandFactory func init() { - ui := &cli.BasicUi{Writer: os.Stdout} + ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr} Commands = map[string]cli.CommandFactory{ "agent": func() (cli.Command, error) { return &agent.Command{ - Revision: GitCommit, - Version: Version, - VersionPrerelease: VersionPrerelease, - HumanVersion: GetHumanVersion(), - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + Revision: version.GitCommit, + Version: version.Version, + VersionPrerelease: version.VersionPrerelease, + HumanVersion: version.GetHumanVersion(), ShutdownCh: make(chan struct{}), }, nil }, "configtest": func() (cli.Command, error) { return &command.ConfigTestCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, }, nil }, "event": func() (cli.Command, error) { return &command.EventCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, }, nil }, "exec": func() (cli.Command, error) { return &command.ExecCommand{ ShutdownCh: makeShutdownCh(), - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, }, nil }, "force-leave": func() (cli.Command, error) { return &command.ForceLeaveCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, + }, nil + }, + + "info": func() (cli.Command, error) { + return &command.InfoCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetClientHTTP, + }, }, nil }, "join": func() (cli.Command, error) { return &command.JoinCommand{ - Ui: ui, + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetClientHTTP, + }, }, nil }, "keygen": func() (cli.Command, error) { return &command.KeygenCommand{ - Ui: ui, + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetNone, + }, }, nil }, "keyring": func() (cli.Command, error) { return &command.KeyringCommand{ - Ui: ui, + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetClientHTTP, + }, + }, nil + }, + + "kv": func() (cli.Command, error) { + return &command.KVCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetNone, + }, + }, nil + }, + + "kv delete": func() (cli.Command, error) { + return &command.KVDeleteCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + }, nil + }, + + "kv get": func() (cli.Command, error) { + return &command.KVGetCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + }, nil + }, + + "kv put": func() (cli.Command, error) { + return &command.KVPutCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + }, nil + }, + + "kv export": func() (cli.Command, error) { + return &command.KVExportCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, + }, nil + }, + + "kv import": func() (cli.Command, error) { + return &command.KVImportCommand{ + Command: base.Command{ + Ui: ui, + Flags: base.FlagSetHTTP, + }, }, nil }, "leave": func() (cli.Command, error) { return &command.LeaveCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, }, nil }, "lock": func() (cli.Command, error) { return &command.LockCommand{ ShutdownCh: makeShutdownCh(), - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, }, nil }, "maint": func() (cli.Command, error) { return &command.MaintCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, }, nil }, "members": func() (cli.Command, error) { return &command.MembersCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, }, nil }, "monitor": func() (cli.Command, error) { return &command.MonitorCommand{ ShutdownCh: makeShutdownCh(), - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, }, nil }, - "info": func() (cli.Command, error) { - return &command.InfoCommand{ - Ui: ui, + "operator": func() (cli.Command, error) { + return &command.OperatorCommand{ + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + }, nil + }, + + "operator autopilot": func() (cli.Command, error) { + return &command.OperatorAutopilotCommand{ + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + }, nil + }, + + "operator autopilot get-config": func() (cli.Command, error) { + return &command.OperatorAutopilotGetCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator autopilot set-config": func() (cli.Command, error) { + return &command.OperatorAutopilotSetCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator raft": func() (cli.Command, error) { + return &command.OperatorRaftCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator raft list-peers": func() (cli.Command, error) { + return &command.OperatorRaftListCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "operator raft remove-peer": func() (cli.Command, error) { + return &command.OperatorRaftRemoveCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, }, nil }, "reload": func() (cli.Command, error) { return &command.ReloadCommand{ - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, }, nil }, "rtt": func() (cli.Command, error) { return &command.RTTCommand{ + Command: base.Command{ + Flags: base.FlagSetClientHTTP, + Ui: ui, + }, + }, nil + }, + + "snapshot": func() (cli.Command, error) { + return &command.SnapshotCommand{ Ui: ui, }, nil }, + "snapshot restore": func() (cli.Command, error) { + return &command.SnapshotRestoreCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "snapshot save": func() (cli.Command, error) { + return &command.SnapshotSaveCommand{ + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, + }, nil + }, + + "snapshot inspect": func() (cli.Command, error) { + return &command.SnapshotInspectCommand{ + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + }, nil + }, + + "validate": func() (cli.Command, error) { + return &command.ValidateCommand{ + Command: base.Command{ + Flags: base.FlagSetNone, + Ui: ui, + }, + }, nil + }, + "version": func() (cli.Command, error) { return &command.VersionCommand{ - HumanVersion: GetHumanVersion(), + HumanVersion: version.GetHumanVersion(), Ui: ui, }, nil }, @@ -131,7 +340,10 @@ func init() { "watch": func() (cli.Command, error) { return &command.WatchCommand{ ShutdownCh: makeShutdownCh(), - Ui: ui, + Command: base.Command{ + Flags: base.FlagSetHTTP, + Ui: ui, + }, }, nil }, } diff --git a/vendor/github.com/hashicorp/consul/main.go b/vendor/github.com/hashicorp/consul/main.go index 249e6e253..1867a73f4 100644 --- a/vendor/github.com/hashicorp/consul/main.go +++ b/vendor/github.com/hashicorp/consul/main.go @@ -37,10 +37,18 @@ func realMain() int { } } + // Filter out the configtest command from the help display + var included []string + for command := range Commands { + if command != "configtest" { + included = append(included, command) + } + } + cli := &cli.CLI{ Args: args, Commands: Commands, - HelpFunc: cli.BasicHelpFunc("consul"), + HelpFunc: cli.FilteredHelpFunc(included, cli.BasicHelpFunc("consul")), } exitCode, err := cli.Run() diff --git a/vendor/github.com/hashicorp/consul/version.go b/vendor/github.com/hashicorp/consul/version.go deleted file mode 100644 index e158f79dc..000000000 --- a/vendor/github.com/hashicorp/consul/version.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "fmt" - "strings" -) - -// The git commit that was compiled. This will be filled in by the compiler. -var ( - GitCommit string - GitDescribe string -) - -// The main version number that is being run at the moment. -const Version = "0.7.0" - -// A pre-release marker for the version. If this is "" (empty string) -// then it means that it is a final release. Otherwise, this is a pre-release -// such as "dev" (in development), "beta", "rc1", etc. -const VersionPrerelease = "dev" - -// GetHumanVersion composes the parts of the version in a way that's suitable -// for displaying to humans. -func GetHumanVersion() string { - version := Version - if GitDescribe != "" { - version = GitDescribe - } - - release := VersionPrerelease - if GitDescribe == "" && release == "" { - release = "dev" - } - if release != "" { - version += fmt.Sprintf("-%s", release) - if GitCommit != "" { - version += fmt.Sprintf(" (%s)", GitCommit) - } - } - - // Strip off any single quotes added by the git information. - return strings.Replace(version, "'", "", -1) -} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go index 84b22c944..7d8a57c28 100644 --- a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go +++ b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go @@ -3,11 +3,12 @@ package cleanhttp import ( "net" "net/http" + "runtime" "time" ) -// DefaultTransport returns a new http.Transport with the same default values -// as http.DefaultTransport, but with idle connections and keepalives disabled. +// DefaultTransport returns a new http.Transport with similar default values to +// http.DefaultTransport, but with idle connections and keepalives disabled. func DefaultTransport() *http.Transport { transport := DefaultPooledTransport() transport.DisableKeepAlives = true @@ -22,13 +23,15 @@ func DefaultTransport() *http.Transport { func DefaultPooledTransport() *http.Transport { transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ + DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - DisableKeepAlives: false, - MaxIdleConnsPerHost: 1, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, } return transport } @@ -42,10 +45,10 @@ func DefaultClient() *http.Client { } } -// DefaultPooledClient returns a new http.Client with the same default values -// as http.Client, but with a non-shared Transport. Do not use this function -// for transient clients as it can leak file descriptors over time. Only use -// this for clients that will be re-used for the same host(s). +// DefaultPooledClient returns a new http.Client with similar default values to +// http.Client, but with a shared Transport. Do not use this function for +// transient clients as it can leak file descriptors over time. Only use this +// for clients that will be re-used for the same host(s). func DefaultPooledClient() *http.Client { return &http.Client{ Transport: DefaultPooledTransport(), diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go index ae2f6b63a..dfe509caa 100644 --- a/vendor/github.com/hashicorp/go-version/version.go +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -166,24 +166,38 @@ func comparePart(preSelf string, preOther string) int { return 0 } + selfNumeric := true + _, err := strconv.ParseInt(preSelf, 10, 64) + if err != nil { + selfNumeric = false + } + + otherNumeric := true + _, err = strconv.ParseInt(preOther, 10, 64) + if err != nil { + otherNumeric = false + } + // if a part is empty, we use the other to decide if preSelf == "" { - _, notIsNumeric := strconv.ParseInt(preOther, 10, 64) - if notIsNumeric == nil { + if otherNumeric { return -1 } return 1 } if preOther == "" { - _, notIsNumeric := strconv.ParseInt(preSelf, 10, 64) - if notIsNumeric == nil { + if selfNumeric { return 1 } return -1 } - if preSelf > preOther { + if selfNumeric && !otherNumeric { + return -1 + } else if !selfNumeric && otherNumeric { + return 1 + } else if preSelf > preOther { return 1 } diff --git a/vendor/github.com/hashicorp/serf/commands.go b/vendor/github.com/hashicorp/serf/commands.go deleted file mode 100644 index 1759546af..000000000 --- a/vendor/github.com/hashicorp/serf/commands.go +++ /dev/null @@ -1,133 +0,0 @@ -package main - -import ( - "github.com/hashicorp/serf/command" - "github.com/hashicorp/serf/command/agent" - "github.com/mitchellh/cli" - "os" - "os/signal" -) - -// Commands is the mapping of all the available Serf commands. -var Commands map[string]cli.CommandFactory - -func init() { - ui := &cli.BasicUi{Writer: os.Stdout} - - Commands = map[string]cli.CommandFactory{ - "agent": func() (cli.Command, error) { - return &agent.Command{ - Ui: ui, - ShutdownCh: make(chan struct{}), - }, nil - }, - - "event": func() (cli.Command, error) { - return &command.EventCommand{ - Ui: ui, - }, nil - }, - - "query": func() (cli.Command, error) { - return &command.QueryCommand{ - ShutdownCh: makeShutdownCh(), - Ui: ui, - }, nil - }, - - "force-leave": func() (cli.Command, error) { - return &command.ForceLeaveCommand{ - Ui: ui, - }, nil - }, - - "join": func() (cli.Command, error) { - return &command.JoinCommand{ - Ui: ui, - }, nil - }, - - "keygen": func() (cli.Command, error) { - return &command.KeygenCommand{ - Ui: ui, - }, nil - }, - - "keys": func() (cli.Command, error) { - return &command.KeysCommand{ - Ui: ui, - }, nil - }, - - "leave": func() (cli.Command, error) { - return &command.LeaveCommand{ - Ui: ui, - }, nil - }, - - "members": func() (cli.Command, error) { - return &command.MembersCommand{ - Ui: ui, - }, nil - }, - - "monitor": func() (cli.Command, error) { - return &command.MonitorCommand{ - ShutdownCh: makeShutdownCh(), - Ui: ui, - }, nil - }, - - "tags": func() (cli.Command, error) { - return &command.TagsCommand{ - Ui: ui, - }, nil - }, - - "reachability": func() (cli.Command, error) { - return &command.ReachabilityCommand{ - ShutdownCh: makeShutdownCh(), - Ui: ui, - }, nil - }, - - "rtt": func() (cli.Command, error) { - return &command.RTTCommand{ - Ui: ui, - }, nil - }, - - "info": func() (cli.Command, error) { - return &command.InfoCommand{ - Ui: ui, - }, nil - }, - - "version": func() (cli.Command, error) { - return &command.VersionCommand{ - Revision: GitCommit, - Version: Version, - VersionPrerelease: VersionPrerelease, - Ui: ui, - }, nil - }, - } -} - -// makeShutdownCh returns a channel that can be used for shutdown -// notifications for commands. This channel will send a message for every -// interrupt received. -func makeShutdownCh() <-chan struct{} { - resultCh := make(chan struct{}) - - signalCh := make(chan os.Signal, 4) - signal.Notify(signalCh, os.Interrupt) - go func() { - for { - <-signalCh - resultCh <- struct{}{} - } - }() - - return resultCh -} diff --git a/vendor/github.com/hashicorp/serf/main.go b/vendor/github.com/hashicorp/serf/main.go deleted file mode 100644 index 4876a0ca5..000000000 --- a/vendor/github.com/hashicorp/serf/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "fmt" - "github.com/mitchellh/cli" - "io/ioutil" - "log" - "os" -) - -func main() { - os.Exit(realMain()) -} - -func realMain() int { - log.SetOutput(ioutil.Discard) - - // Get the command line args. We shortcut "--version" and "-v" to - // just show the version. - args := os.Args[1:] - for _, arg := range args { - if arg == "-v" || arg == "--version" { - newArgs := make([]string, len(args)+1) - newArgs[0] = "version" - copy(newArgs[1:], args) - args = newArgs - break - } - } - - cli := &cli.CLI{ - Args: args, - Commands: Commands, - HelpFunc: cli.BasicHelpFunc("serf"), - } - - exitCode, err := cli.Run() - if err != nil { - fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) - return 1 - } - - return exitCode -} diff --git a/vendor/github.com/hashicorp/serf/serf/broadcast.go b/vendor/github.com/hashicorp/serf/serf/broadcast.go deleted file mode 100644 index d20728f3f..000000000 --- a/vendor/github.com/hashicorp/serf/serf/broadcast.go +++ /dev/null @@ -1,27 +0,0 @@ -package serf - -import ( - "github.com/hashicorp/memberlist" -) - -// broadcast is an implementation of memberlist.Broadcast and is used -// to manage broadcasts across the memberlist channel that are related -// only to Serf. -type broadcast struct { - msg []byte - notify chan<- struct{} -} - -func (b *broadcast) Invalidates(other memberlist.Broadcast) bool { - return false -} - -func (b *broadcast) Message() []byte { - return b.msg -} - -func (b *broadcast) Finished() { - if b.notify != nil { - close(b.notify) - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/coalesce.go b/vendor/github.com/hashicorp/serf/serf/coalesce.go deleted file mode 100644 index 567943be1..000000000 --- a/vendor/github.com/hashicorp/serf/serf/coalesce.go +++ /dev/null @@ -1,80 +0,0 @@ -package serf - -import ( - "time" -) - -// coalescer is a simple interface that must be implemented to be -// used inside of a coalesceLoop -type coalescer interface { - // Can the coalescer handle this event, if not it is - // directly passed through to the destination channel - Handle(Event) bool - - // Invoked to coalesce the given event - Coalesce(Event) - - // Invoked to flush the coalesced events - Flush(outChan chan<- Event) -} - -// coalescedEventCh returns an event channel where the events are coalesced -// using the given coalescer. -func coalescedEventCh(outCh chan<- Event, shutdownCh <-chan struct{}, - cPeriod time.Duration, qPeriod time.Duration, c coalescer) chan<- Event { - inCh := make(chan Event, 1024) - go coalesceLoop(inCh, outCh, shutdownCh, cPeriod, qPeriod, c) - return inCh -} - -// coalesceLoop is a simple long-running routine that manages the high-level -// flow of coalescing based on quiescence and a maximum quantum period. -func coalesceLoop(inCh <-chan Event, outCh chan<- Event, shutdownCh <-chan struct{}, - coalescePeriod time.Duration, quiescentPeriod time.Duration, c coalescer) { - var quiescent <-chan time.Time - var quantum <-chan time.Time - shutdown := false - -INGEST: - // Reset the timers - quantum = nil - quiescent = nil - - for { - select { - case e := <-inCh: - // Ignore any non handled events - if !c.Handle(e) { - outCh <- e - continue - } - - // Start a new quantum if we need to - // and restart the quiescent timer - if quantum == nil { - quantum = time.After(coalescePeriod) - } - quiescent = time.After(quiescentPeriod) - - // Coalesce the event - c.Coalesce(e) - - case <-quantum: - goto FLUSH - case <-quiescent: - goto FLUSH - case <-shutdownCh: - shutdown = true - goto FLUSH - } - } - -FLUSH: - // Flush the coalesced events - c.Flush(outCh) - - // Restart ingestion if we are not done - if !shutdown { - goto INGEST - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/coalesce_member.go b/vendor/github.com/hashicorp/serf/serf/coalesce_member.go deleted file mode 100644 index 82fdb8dac..000000000 --- a/vendor/github.com/hashicorp/serf/serf/coalesce_member.go +++ /dev/null @@ -1,68 +0,0 @@ -package serf - -type coalesceEvent struct { - Type EventType - Member *Member -} - -type memberEventCoalescer struct { - lastEvents map[string]EventType - latestEvents map[string]coalesceEvent -} - -func (c *memberEventCoalescer) Handle(e Event) bool { - switch e.EventType() { - case EventMemberJoin: - return true - case EventMemberLeave: - return true - case EventMemberFailed: - return true - case EventMemberUpdate: - return true - case EventMemberReap: - return true - default: - return false - } -} - -func (c *memberEventCoalescer) Coalesce(raw Event) { - e := raw.(MemberEvent) - for _, m := range e.Members { - c.latestEvents[m.Name] = coalesceEvent{ - Type: e.Type, - Member: &m, - } - } -} - -func (c *memberEventCoalescer) Flush(outCh chan<- Event) { - // Coalesce the various events we got into a single set of events. - events := make(map[EventType]*MemberEvent) - for name, cevent := range c.latestEvents { - previous, ok := c.lastEvents[name] - - // If we sent the same event before, then ignore - // unless it is a MemberUpdate - if ok && previous == cevent.Type && cevent.Type != EventMemberUpdate { - continue - } - - // Update our last event - c.lastEvents[name] = cevent.Type - - // Add it to our event - newEvent, ok := events[cevent.Type] - if !ok { - newEvent = &MemberEvent{Type: cevent.Type} - events[cevent.Type] = newEvent - } - newEvent.Members = append(newEvent.Members, *cevent.Member) - } - - // Send out those events - for _, event := range events { - outCh <- *event - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/coalesce_user.go b/vendor/github.com/hashicorp/serf/serf/coalesce_user.go deleted file mode 100644 index 1551b6c52..000000000 --- a/vendor/github.com/hashicorp/serf/serf/coalesce_user.go +++ /dev/null @@ -1,52 +0,0 @@ -package serf - -type latestUserEvents struct { - LTime LamportTime - Events []Event -} - -type userEventCoalescer struct { - // Maps an event name into the latest versions - events map[string]*latestUserEvents -} - -func (c *userEventCoalescer) Handle(e Event) bool { - // Only handle EventUser messages - if e.EventType() != EventUser { - return false - } - - // Check if coalescing is enabled - user := e.(UserEvent) - return user.Coalesce -} - -func (c *userEventCoalescer) Coalesce(e Event) { - user := e.(UserEvent) - latest, ok := c.events[user.Name] - - // Create a new entry if there are none, or - // if this message has the newest LTime - if !ok || latest.LTime < user.LTime { - latest = &latestUserEvents{ - LTime: user.LTime, - Events: []Event{e}, - } - c.events[user.Name] = latest - return - } - - // If the the same age, save it - if latest.LTime == user.LTime { - latest.Events = append(latest.Events, e) - } -} - -func (c *userEventCoalescer) Flush(outChan chan<- Event) { - for _, latest := range c.events { - for _, e := range latest.Events { - outChan <- e - } - } - c.events = make(map[string]*latestUserEvents) -} diff --git a/vendor/github.com/hashicorp/serf/serf/config.go b/vendor/github.com/hashicorp/serf/serf/config.go deleted file mode 100644 index e8edd6902..000000000 --- a/vendor/github.com/hashicorp/serf/serf/config.go +++ /dev/null @@ -1,259 +0,0 @@ -package serf - -import ( - "io" - "os" - "time" - - "github.com/hashicorp/memberlist" -) - -// ProtocolVersionMap is the mapping of Serf delegate protocol versions -// to memberlist protocol versions. We mask the memberlist protocols using -// our own protocol version. -var ProtocolVersionMap map[uint8]uint8 - -func init() { - ProtocolVersionMap = map[uint8]uint8{ - 4: 2, - 3: 2, - 2: 2, - } -} - -// Config is the configuration for creating a Serf instance. -type Config struct { - // The name of this node. This must be unique in the cluster. If this - // is not set, Serf will set it to the hostname of the running machine. - NodeName string - - // The tags for this role, if any. This is used to provide arbitrary - // key/value metadata per-node. For example, a "role" tag may be used to - // differentiate "load-balancer" from a "web" role as parts of the same cluster. - // Tags are deprecating 'Role', and instead it acts as a special key in this - // map. - Tags map[string]string - - // EventCh is a channel that receives all the Serf events. The events - // are sent on this channel in proper ordering. Care must be taken that - // this channel doesn't block, either by processing the events quick - // enough or buffering the channel, otherwise it can block state updates - // within Serf itself. If no EventCh is specified, no events will be fired, - // but point-in-time snapshots of members can still be retrieved by - // calling Members on Serf. - EventCh chan<- Event - - // ProtocolVersion is the protocol version to speak. This must be between - // ProtocolVersionMin and ProtocolVersionMax. - ProtocolVersion uint8 - - // BroadcastTimeout is the amount of time to wait for a broadcast - // message to be sent to the cluster. Broadcast messages are used for - // things like leave messages and force remove messages. If this is not - // set, a timeout of 5 seconds will be set. - BroadcastTimeout time.Duration - - // The settings below relate to Serf's event coalescence feature. Serf - // is able to coalesce multiple events into single events in order to - // reduce the amount of noise that is sent along the EventCh. For example - // if five nodes quickly join, the EventCh will be sent one EventMemberJoin - // containing the five nodes rather than five individual EventMemberJoin - // events. Coalescence can mitigate potential flapping behavior. - // - // Coalescence is disabled by default and can be enabled by setting - // CoalescePeriod. - // - // CoalescePeriod specifies the time duration to coalesce events. - // For example, if this is set to 5 seconds, then all events received - // within 5 seconds that can be coalesced will be. - // - // QuiescentPeriod specifies the duration of time where if no events - // are received, coalescence immediately happens. For example, if - // CoalscePeriod is set to 10 seconds but QuiscentPeriod is set to 2 - // seconds, then the events will be coalesced and dispatched if no - // new events are received within 2 seconds of the last event. Otherwise, - // every event will always be delayed by at least 10 seconds. - CoalescePeriod time.Duration - QuiescentPeriod time.Duration - - // The settings below relate to Serf's user event coalescing feature. - // The settings operate like above but only affect user messages and - // not the Member* messages that Serf generates. - UserCoalescePeriod time.Duration - UserQuiescentPeriod time.Duration - - // The settings below relate to Serf keeping track of recently - // failed/left nodes and attempting reconnects. - // - // ReapInterval is the interval when the reaper runs. If this is not - // set (it is zero), it will be set to a reasonable default. - // - // ReconnectInterval is the interval when we attempt to reconnect - // to failed nodes. If this is not set (it is zero), it will be set - // to a reasonable default. - // - // ReconnectTimeout is the amount of time to attempt to reconnect to - // a failed node before giving up and considering it completely gone. - // - // TombstoneTimeout is the amount of time to keep around nodes - // that gracefully left as tombstones for syncing state with other - // Serf nodes. - ReapInterval time.Duration - ReconnectInterval time.Duration - ReconnectTimeout time.Duration - TombstoneTimeout time.Duration - - // FlapTimeout is the amount of time less than which we consider a node - // being failed and rejoining looks like a flap for telemetry purposes. - // This should be set less than a typical reboot time, but large enough - // to see actual events, given our expected detection times for a failed - // node. - FlapTimeout time.Duration - - // QueueDepthWarning is used to generate warning message if the - // number of queued messages to broadcast exceeds this number. This - // is to provide the user feedback if events are being triggered - // faster than they can be disseminated - QueueDepthWarning int - - // MaxQueueDepth is used to start dropping messages if the number - // of queued messages to broadcast exceeds this number. This is to - // prevent an unbounded growth of memory utilization - MaxQueueDepth int - - // RecentIntentBuffer is used to set the size of recent join and leave intent - // messages that will be buffered. This is used to guard against - // the case where Serf broadcasts an intent that arrives before the - // Memberlist event. It is important that this not be too small to avoid - // continuous rebroadcasting of dead events. - RecentIntentBuffer int - - // EventBuffer is used to control how many events are buffered. - // This is used to prevent re-delivery of events to a client. The buffer - // must be large enough to handle all "recent" events, since Serf will - // not deliver messages that are older than the oldest entry in the buffer. - // Thus if a client is generating too many events, it's possible that the - // buffer gets overrun and messages are not delivered. - EventBuffer int - - // QueryBuffer is used to control how many queries are buffered. - // This is used to prevent re-delivery of queries to a client. The buffer - // must be large enough to handle all "recent" events, since Serf will not - // deliver queries older than the oldest entry in the buffer. - // Thus if a client is generating too many queries, it's possible that the - // buffer gets overrun and messages are not delivered. - QueryBuffer int - - // QueryTimeoutMult configures the default timeout multipler for a query to run if no - // specific value is provided. Queries are real-time by nature, where the - // reply is time sensitive. As a result, results are collected in an async - // fashion, however the query must have a bounded duration. We want the timeout - // to be long enough that all nodes have time to receive the message, run a handler, - // and generate a reply. Once the timeout is exceeded, any further replies are ignored. - // The default value is - // - // Timeout = GossipInterval * QueryTimeoutMult * log(N+1) - // - QueryTimeoutMult int - - // QueryResponseSizeLimit and QuerySizeLimit limit the inbound and - // outbound payload sizes for queries, respectively. These must fit - // in a UDP packet with some additional overhead, so tuning these - // past the default values of 1024 will depend on your network - // configuration. - QueryResponseSizeLimit int - QuerySizeLimit int - - // MemberlistConfig is the memberlist configuration that Serf will - // use to do the underlying membership management and gossip. Some - // fields in the MemberlistConfig will be overwritten by Serf no - // matter what: - // - // * Name - This will always be set to the same as the NodeName - // in this configuration. - // - // * Events - Serf uses a custom event delegate. - // - // * Delegate - Serf uses a custom delegate. - // - MemberlistConfig *memberlist.Config - - // LogOutput is the location to write logs to. If this is not set, - // logs will go to stderr. - LogOutput io.Writer - - // SnapshotPath if provided is used to snapshot live nodes as well - // as lamport clock values. When Serf is started with a snapshot, - // it will attempt to join all the previously known nodes until one - // succeeds and will also avoid replaying old user events. - SnapshotPath string - - // RejoinAfterLeave controls our interaction with the snapshot file. - // When set to false (default), a leave causes a Serf to not rejoin - // the cluster until an explicit join is received. If this is set to - // true, we ignore the leave, and rejoin the cluster on start. - RejoinAfterLeave bool - - // EnableNameConflictResolution controls if Serf will actively attempt - // to resolve a name conflict. Since each Serf member must have a unique - // name, a cluster can run into issues if multiple nodes claim the same - // name. Without automatic resolution, Serf merely logs some warnings, but - // otherwise does not take any action. Automatic resolution detects the - // conflict and issues a special query which asks the cluster for the - // Name -> IP:Port mapping. If there is a simple majority of votes, that - // node stays while the other node will leave the cluster and exit. - EnableNameConflictResolution bool - - // DisableCoordinates controls if Serf will maintain an estimate of this - // node's network coordinate internally. A network coordinate is useful - // for estimating the network distance (i.e. round trip time) between - // two nodes. Enabling this option adds some overhead to ping messages. - DisableCoordinates bool - - // KeyringFile provides the location of a writable file where Serf can - // persist changes to the encryption keyring. - KeyringFile string - - // Merge can be optionally provided to intercept a cluster merge - // and conditionally abort the merge. - Merge MergeDelegate -} - -// Init allocates the subdata structures -func (c *Config) Init() { - if c.Tags == nil { - c.Tags = make(map[string]string) - } -} - -// DefaultConfig returns a Config struct that contains reasonable defaults -// for most of the configurations. -func DefaultConfig() *Config { - hostname, err := os.Hostname() - if err != nil { - panic(err) - } - - return &Config{ - NodeName: hostname, - BroadcastTimeout: 5 * time.Second, - EventBuffer: 512, - QueryBuffer: 512, - LogOutput: os.Stderr, - ProtocolVersion: ProtocolVersionMax, - ReapInterval: 15 * time.Second, - RecentIntentBuffer: 128, - ReconnectInterval: 30 * time.Second, - ReconnectTimeout: 24 * time.Hour, - QueueDepthWarning: 128, - MaxQueueDepth: 4096, - TombstoneTimeout: 24 * time.Hour, - FlapTimeout: 60 * time.Second, - MemberlistConfig: memberlist.DefaultLANConfig(), - QueryTimeoutMult: 16, - QueryResponseSizeLimit: 1024, - QuerySizeLimit: 1024, - EnableNameConflictResolution: true, - DisableCoordinates: false, - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/conflict_delegate.go b/vendor/github.com/hashicorp/serf/serf/conflict_delegate.go deleted file mode 100644 index 65a50156c..000000000 --- a/vendor/github.com/hashicorp/serf/serf/conflict_delegate.go +++ /dev/null @@ -1,13 +0,0 @@ -package serf - -import ( - "github.com/hashicorp/memberlist" -) - -type conflictDelegate struct { - serf *Serf -} - -func (c *conflictDelegate) NotifyConflict(existing, other *memberlist.Node) { - c.serf.handleNodeConflict(existing, other) -} diff --git a/vendor/github.com/hashicorp/serf/serf/delegate.go b/vendor/github.com/hashicorp/serf/serf/delegate.go deleted file mode 100644 index d19ca3090..000000000 --- a/vendor/github.com/hashicorp/serf/serf/delegate.go +++ /dev/null @@ -1,254 +0,0 @@ -package serf - -import ( - "fmt" - - "github.com/armon/go-metrics" -) - -// delegate is the memberlist.Delegate implementation that Serf uses. -type delegate struct { - serf *Serf -} - -func (d *delegate) NodeMeta(limit int) []byte { - roleBytes := d.serf.encodeTags(d.serf.config.Tags) - if len(roleBytes) > limit { - panic(fmt.Errorf("Node tags '%v' exceeds length limit of %d bytes", d.serf.config.Tags, limit)) - } - - return roleBytes -} - -func (d *delegate) NotifyMsg(buf []byte) { - // If we didn't actually receive any data, then ignore it. - if len(buf) == 0 { - return - } - metrics.AddSample([]string{"serf", "msgs", "received"}, float32(len(buf))) - - rebroadcast := false - rebroadcastQueue := d.serf.broadcasts - t := messageType(buf[0]) - switch t { - case messageLeaveType: - var leave messageLeave - if err := decodeMessage(buf[1:], &leave); err != nil { - d.serf.logger.Printf("[ERR] serf: Error decoding leave message: %s", err) - break - } - - d.serf.logger.Printf("[DEBUG] serf: messageLeaveType: %s", leave.Node) - rebroadcast = d.serf.handleNodeLeaveIntent(&leave) - - case messageJoinType: - var join messageJoin - if err := decodeMessage(buf[1:], &join); err != nil { - d.serf.logger.Printf("[ERR] serf: Error decoding join message: %s", err) - break - } - - d.serf.logger.Printf("[DEBUG] serf: messageJoinType: %s", join.Node) - rebroadcast = d.serf.handleNodeJoinIntent(&join) - - case messageUserEventType: - var event messageUserEvent - if err := decodeMessage(buf[1:], &event); err != nil { - d.serf.logger.Printf("[ERR] serf: Error decoding user event message: %s", err) - break - } - - d.serf.logger.Printf("[DEBUG] serf: messageUserEventType: %s", event.Name) - rebroadcast = d.serf.handleUserEvent(&event) - rebroadcastQueue = d.serf.eventBroadcasts - - case messageQueryType: - var query messageQuery - if err := decodeMessage(buf[1:], &query); err != nil { - d.serf.logger.Printf("[ERR] serf: Error decoding query message: %s", err) - break - } - - d.serf.logger.Printf("[DEBUG] serf: messageQueryType: %s", query.Name) - rebroadcast = d.serf.handleQuery(&query) - rebroadcastQueue = d.serf.queryBroadcasts - - case messageQueryResponseType: - var resp messageQueryResponse - if err := decodeMessage(buf[1:], &resp); err != nil { - d.serf.logger.Printf("[ERR] serf: Error decoding query response message: %s", err) - break - } - - d.serf.logger.Printf("[DEBUG] serf: messageQueryResponseType: %v", resp.From) - d.serf.handleQueryResponse(&resp) - - default: - d.serf.logger.Printf("[WARN] serf: Received message of unknown type: %d", t) - } - - if rebroadcast { - // Copy the buffer since it we cannot rely on the slice not changing - newBuf := make([]byte, len(buf)) - copy(newBuf, buf) - - rebroadcastQueue.QueueBroadcast(&broadcast{ - msg: newBuf, - notify: nil, - }) - } -} - -func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte { - msgs := d.serf.broadcasts.GetBroadcasts(overhead, limit) - - // Determine the bytes used already - bytesUsed := 0 - for _, msg := range msgs { - lm := len(msg) - bytesUsed += lm + overhead - metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm)) - } - - // Get any additional query broadcasts - queryMsgs := d.serf.queryBroadcasts.GetBroadcasts(overhead, limit-bytesUsed) - if queryMsgs != nil { - for _, m := range queryMsgs { - lm := len(m) - bytesUsed += lm + overhead - metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm)) - } - msgs = append(msgs, queryMsgs...) - } - - // Get any additional event broadcasts - eventMsgs := d.serf.eventBroadcasts.GetBroadcasts(overhead, limit-bytesUsed) - if eventMsgs != nil { - for _, m := range eventMsgs { - lm := len(m) - bytesUsed += lm + overhead - metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm)) - } - msgs = append(msgs, eventMsgs...) - } - - return msgs -} - -func (d *delegate) LocalState(join bool) []byte { - d.serf.memberLock.RLock() - defer d.serf.memberLock.RUnlock() - d.serf.eventLock.RLock() - defer d.serf.eventLock.RUnlock() - - // Create the message to send - pp := messagePushPull{ - LTime: d.serf.clock.Time(), - StatusLTimes: make(map[string]LamportTime, len(d.serf.members)), - LeftMembers: make([]string, 0, len(d.serf.leftMembers)), - EventLTime: d.serf.eventClock.Time(), - Events: d.serf.eventBuffer, - QueryLTime: d.serf.queryClock.Time(), - } - - // Add all the join LTimes - for name, member := range d.serf.members { - pp.StatusLTimes[name] = member.statusLTime - } - - // Add all the left nodes - for _, member := range d.serf.leftMembers { - pp.LeftMembers = append(pp.LeftMembers, member.Name) - } - - // Encode the push pull state - buf, err := encodeMessage(messagePushPullType, &pp) - if err != nil { - d.serf.logger.Printf("[ERR] serf: Failed to encode local state: %v", err) - return nil - } - return buf -} - -func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) { - // Ensure we have a message - if len(buf) == 0 { - d.serf.logger.Printf("[ERR] serf: Remote state is zero bytes") - return - } - - // Check the message type - if messageType(buf[0]) != messagePushPullType { - d.serf.logger.Printf("[ERR] serf: Remote state has bad type prefix: %v", buf[0]) - return - } - - // Attempt a decode - pp := messagePushPull{} - if err := decodeMessage(buf[1:], &pp); err != nil { - d.serf.logger.Printf("[ERR] serf: Failed to decode remote state: %v", err) - return - } - - // Witness the Lamport clocks first. - // We subtract 1 since no message with that clock has been sent yet - if pp.LTime > 0 { - d.serf.clock.Witness(pp.LTime - 1) - } - if pp.EventLTime > 0 { - d.serf.eventClock.Witness(pp.EventLTime - 1) - } - if pp.QueryLTime > 0 { - d.serf.queryClock.Witness(pp.QueryLTime - 1) - } - - // Process the left nodes first to avoid the LTimes from being increment - // in the wrong order - leftMap := make(map[string]struct{}, len(pp.LeftMembers)) - leave := messageLeave{} - for _, name := range pp.LeftMembers { - leftMap[name] = struct{}{} - leave.LTime = pp.StatusLTimes[name] - leave.Node = name - d.serf.handleNodeLeaveIntent(&leave) - } - - // Update any other LTimes - join := messageJoin{} - for name, statusLTime := range pp.StatusLTimes { - // Skip the left nodes - if _, ok := leftMap[name]; ok { - continue - } - - // Create an artificial join message - join.LTime = statusLTime - join.Node = name - d.serf.handleNodeJoinIntent(&join) - } - - // If we are doing a join, and eventJoinIgnore is set - // then we set the eventMinTime to the EventLTime. This - // prevents any of the incoming events from being processed - if isJoin && d.serf.eventJoinIgnore { - d.serf.eventLock.Lock() - if pp.EventLTime > d.serf.eventMinTime { - d.serf.eventMinTime = pp.EventLTime - } - d.serf.eventLock.Unlock() - } - - // Process all the events - userEvent := messageUserEvent{} - for _, events := range pp.Events { - if events == nil { - continue - } - userEvent.LTime = events.LTime - for _, e := range events.Events { - userEvent.Name = e.Name - userEvent.Payload = e.Payload - d.serf.handleUserEvent(&userEvent) - } - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/event.go b/vendor/github.com/hashicorp/serf/serf/event.go deleted file mode 100644 index 8337e95ea..000000000 --- a/vendor/github.com/hashicorp/serf/serf/event.go +++ /dev/null @@ -1,168 +0,0 @@ -package serf - -import ( - "fmt" - "net" - "sync" - "time" -) - -// EventType are all the types of events that may occur and be sent -// along the Serf channel. -type EventType int - -const ( - EventMemberJoin EventType = iota - EventMemberLeave - EventMemberFailed - EventMemberUpdate - EventMemberReap - EventUser - EventQuery -) - -func (t EventType) String() string { - switch t { - case EventMemberJoin: - return "member-join" - case EventMemberLeave: - return "member-leave" - case EventMemberFailed: - return "member-failed" - case EventMemberUpdate: - return "member-update" - case EventMemberReap: - return "member-reap" - case EventUser: - return "user" - case EventQuery: - return "query" - default: - panic(fmt.Sprintf("unknown event type: %d", t)) - } -} - -// Event is a generic interface for exposing Serf events -// Clients will usually need to use a type switches to get -// to a more useful type -type Event interface { - EventType() EventType - String() string -} - -// MemberEvent is the struct used for member related events -// Because Serf coalesces events, an event may contain multiple members. -type MemberEvent struct { - Type EventType - Members []Member -} - -func (m MemberEvent) EventType() EventType { - return m.Type -} - -func (m MemberEvent) String() string { - switch m.Type { - case EventMemberJoin: - return "member-join" - case EventMemberLeave: - return "member-leave" - case EventMemberFailed: - return "member-failed" - case EventMemberUpdate: - return "member-update" - case EventMemberReap: - return "member-reap" - default: - panic(fmt.Sprintf("unknown event type: %d", m.Type)) - } -} - -// UserEvent is the struct used for events that are triggered -// by the user and are not related to members -type UserEvent struct { - LTime LamportTime - Name string - Payload []byte - Coalesce bool -} - -func (u UserEvent) EventType() EventType { - return EventUser -} - -func (u UserEvent) String() string { - return fmt.Sprintf("user-event: %s", u.Name) -} - -// Query is the struct used EventQuery type events -type Query struct { - LTime LamportTime - Name string - Payload []byte - - serf *Serf - id uint32 // ID is not exported, since it may change - addr []byte // Address to respond to - port uint16 // Port to respond to - deadline time.Time // Must respond by this deadline - respLock sync.Mutex -} - -func (q *Query) EventType() EventType { - return EventQuery -} - -func (q *Query) String() string { - return fmt.Sprintf("query: %s", q.Name) -} - -// Deadline returns the time by which a response must be sent -func (q *Query) Deadline() time.Time { - return q.deadline -} - -// Respond is used to send a response to the user query -func (q *Query) Respond(buf []byte) error { - q.respLock.Lock() - defer q.respLock.Unlock() - - // Check if we've already responded - if q.deadline.IsZero() { - return fmt.Errorf("Response already sent") - } - - // Ensure we aren't past our response deadline - if time.Now().After(q.deadline) { - return fmt.Errorf("Response is past the deadline") - } - - // Create response - resp := messageQueryResponse{ - LTime: q.LTime, - ID: q.id, - From: q.serf.config.NodeName, - Payload: buf, - } - - // Format the response - raw, err := encodeMessage(messageQueryResponseType, &resp) - if err != nil { - return fmt.Errorf("Failed to format response: %v", err) - } - - // Check the size limit - if len(raw) > q.serf.config.QueryResponseSizeLimit { - return fmt.Errorf("response exceeds limit of %d bytes", q.serf.config.QueryResponseSizeLimit) - } - - // Send the response - addr := net.UDPAddr{IP: q.addr, Port: int(q.port)} - if err := q.serf.memberlist.SendTo(&addr, raw); err != nil { - return err - } - - // Clera the deadline, response sent - q.deadline = time.Time{} - return nil -} diff --git a/vendor/github.com/hashicorp/serf/serf/event_delegate.go b/vendor/github.com/hashicorp/serf/serf/event_delegate.go deleted file mode 100644 index e20132281..000000000 --- a/vendor/github.com/hashicorp/serf/serf/event_delegate.go +++ /dev/null @@ -1,21 +0,0 @@ -package serf - -import ( - "github.com/hashicorp/memberlist" -) - -type eventDelegate struct { - serf *Serf -} - -func (e *eventDelegate) NotifyJoin(n *memberlist.Node) { - e.serf.handleNodeJoin(n) -} - -func (e *eventDelegate) NotifyLeave(n *memberlist.Node) { - e.serf.handleNodeLeave(n) -} - -func (e *eventDelegate) NotifyUpdate(n *memberlist.Node) { - e.serf.handleNodeUpdate(n) -} diff --git a/vendor/github.com/hashicorp/serf/serf/internal_query.go b/vendor/github.com/hashicorp/serf/serf/internal_query.go deleted file mode 100644 index 128b2cf21..000000000 --- a/vendor/github.com/hashicorp/serf/serf/internal_query.go +++ /dev/null @@ -1,312 +0,0 @@ -package serf - -import ( - "encoding/base64" - "log" - "strings" -) - -const ( - // This is the prefix we use for queries that are internal to Serf. - // They are handled internally, and not forwarded to a client. - InternalQueryPrefix = "_serf_" - - // pingQuery is run to check for reachability - pingQuery = "ping" - - // conflictQuery is run to resolve a name conflict - conflictQuery = "conflict" - - // installKeyQuery is used to install a new key - installKeyQuery = "install-key" - - // useKeyQuery is used to change the primary encryption key - useKeyQuery = "use-key" - - // removeKeyQuery is used to remove a key from the keyring - removeKeyQuery = "remove-key" - - // listKeysQuery is used to list all known keys in the cluster - listKeysQuery = "list-keys" -) - -// internalQueryName is used to generate a query name for an internal query -func internalQueryName(name string) string { - return InternalQueryPrefix + name -} - -// serfQueries is used to listen for queries that start with -// _serf and respond to them as appropriate. -type serfQueries struct { - inCh chan Event - logger *log.Logger - outCh chan<- Event - serf *Serf - shutdownCh <-chan struct{} -} - -// nodeKeyResponse is used to store the result from an individual node while -// replying to key modification queries -type nodeKeyResponse struct { - // Result indicates true/false if there were errors or not - Result bool - - // Message contains error messages or other information - Message string - - // Keys is used in listing queries to relay a list of installed keys - Keys []string -} - -// newSerfQueries is used to create a new serfQueries. We return an event -// channel that is ingested and forwarded to an outCh. Any Queries that -// have the InternalQueryPrefix are handled instead of forwarded. -func newSerfQueries(serf *Serf, logger *log.Logger, outCh chan<- Event, shutdownCh <-chan struct{}) (chan<- Event, error) { - inCh := make(chan Event, 1024) - q := &serfQueries{ - inCh: inCh, - logger: logger, - outCh: outCh, - serf: serf, - shutdownCh: shutdownCh, - } - go q.stream() - return inCh, nil -} - -// stream is a long running routine to ingest the event stream -func (s *serfQueries) stream() { - for { - select { - case e := <-s.inCh: - // Check if this is a query we should process - if q, ok := e.(*Query); ok && strings.HasPrefix(q.Name, InternalQueryPrefix) { - go s.handleQuery(q) - - } else if s.outCh != nil { - s.outCh <- e - } - - case <-s.shutdownCh: - return - } - } -} - -// handleQuery is invoked when we get an internal query -func (s *serfQueries) handleQuery(q *Query) { - // Get the queryName after the initial prefix - queryName := q.Name[len(InternalQueryPrefix):] - switch queryName { - case pingQuery: - // Nothing to do, we will ack the query - case conflictQuery: - s.handleConflict(q) - case installKeyQuery: - s.handleInstallKey(q) - case useKeyQuery: - s.handleUseKey(q) - case removeKeyQuery: - s.handleRemoveKey(q) - case listKeysQuery: - s.handleListKeys(q) - default: - s.logger.Printf("[WARN] serf: Unhandled internal query '%s'", queryName) - } -} - -// handleConflict is invoked when we get a query that is attempting to -// disambiguate a name conflict. They payload is a node name, and the response -// should the address we believe that node is at, if any. -func (s *serfQueries) handleConflict(q *Query) { - // The target node name is the payload - node := string(q.Payload) - - // Do not respond to the query if it is about us - if node == s.serf.config.NodeName { - return - } - s.logger.Printf("[DEBUG] serf: Got conflict resolution query for '%s'", node) - - // Look for the member info - var out *Member - s.serf.memberLock.Lock() - if member, ok := s.serf.members[node]; ok { - out = &member.Member - } - s.serf.memberLock.Unlock() - - // Encode the response - buf, err := encodeMessage(messageConflictResponseType, out) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to encode conflict query response: %v", err) - return - } - - // Send our answer - if err := q.Respond(buf); err != nil { - s.logger.Printf("[ERR] serf: Failed to respond to conflict query: %v", err) - } -} - -// sendKeyResponse handles responding to key-related queries. -func (s *serfQueries) sendKeyResponse(q *Query, resp *nodeKeyResponse) { - buf, err := encodeMessage(messageKeyResponseType, resp) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to encode key response: %v", err) - return - } - - if err := q.Respond(buf); err != nil { - s.logger.Printf("[ERR] serf: Failed to respond to key query: %v", err) - return - } -} - -// handleInstallKey is invoked whenever a new encryption key is received from -// another member in the cluster, and handles the process of installing it onto -// the memberlist keyring. This type of query may fail if the provided key does -// not fit the constraints that memberlist enforces. If the query fails, the -// response will contain the error message so that it may be relayed. -func (s *serfQueries) handleInstallKey(q *Query) { - response := nodeKeyResponse{Result: false} - keyring := s.serf.config.MemberlistConfig.Keyring - req := keyRequest{} - - err := decodeMessage(q.Payload[1:], &req) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err) - goto SEND - } - - if !s.serf.EncryptionEnabled() { - response.Message = "No keyring to modify (encryption not enabled)" - s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)") - goto SEND - } - - s.logger.Printf("[INFO] serf: Received install-key query") - if err := keyring.AddKey(req.Key); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to install key: %s", err) - goto SEND - } - - if err := s.serf.writeKeyringFile(); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err) - goto SEND - } - - response.Result = true - -SEND: - s.sendKeyResponse(q, &response) -} - -// handleUseKey is invoked whenever a query is received to mark a different key -// in the internal keyring as the primary key. This type of query may fail due -// to operator error (requested key not in ring), and thus sends error messages -// back in the response. -func (s *serfQueries) handleUseKey(q *Query) { - response := nodeKeyResponse{Result: false} - keyring := s.serf.config.MemberlistConfig.Keyring - req := keyRequest{} - - err := decodeMessage(q.Payload[1:], &req) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err) - goto SEND - } - - if !s.serf.EncryptionEnabled() { - response.Message = "No keyring to modify (encryption not enabled)" - s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)") - goto SEND - } - - s.logger.Printf("[INFO] serf: Received use-key query") - if err := keyring.UseKey(req.Key); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to change primary key: %s", err) - goto SEND - } - - if err := s.serf.writeKeyringFile(); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err) - goto SEND - } - - response.Result = true - -SEND: - s.sendKeyResponse(q, &response) -} - -// handleRemoveKey is invoked when a query is received to remove a particular -// key from the keyring. This type of query can fail if the key requested for -// deletion is currently the primary key in the keyring, so therefore it will -// reply to the query with any relevant errors from the operation. -func (s *serfQueries) handleRemoveKey(q *Query) { - response := nodeKeyResponse{Result: false} - keyring := s.serf.config.MemberlistConfig.Keyring - req := keyRequest{} - - err := decodeMessage(q.Payload[1:], &req) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err) - goto SEND - } - - if !s.serf.EncryptionEnabled() { - response.Message = "No keyring to modify (encryption not enabled)" - s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)") - goto SEND - } - - s.logger.Printf("[INFO] serf: Received remove-key query") - if err := keyring.RemoveKey(req.Key); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to remove key: %s", err) - goto SEND - } - - if err := s.serf.writeKeyringFile(); err != nil { - response.Message = err.Error() - s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err) - goto SEND - } - - response.Result = true - -SEND: - s.sendKeyResponse(q, &response) -} - -// handleListKeys is invoked when a query is received to return a list of all -// installed keys the Serf instance knows of. For performance, the keys are -// encoded to base64 on each of the members to remove this burden from the -// node asking for the results. -func (s *serfQueries) handleListKeys(q *Query) { - response := nodeKeyResponse{Result: false} - keyring := s.serf.config.MemberlistConfig.Keyring - - if !s.serf.EncryptionEnabled() { - response.Message = "Keyring is empty (encryption not enabled)" - s.logger.Printf("[ERR] serf: Keyring is empty (encryption not enabled)") - goto SEND - } - - s.logger.Printf("[INFO] serf: Received list-keys query") - for _, keyBytes := range keyring.GetKeys() { - // Encode the keys before sending the response. This should help take - // some the burden of doing this off of the asking member. - key := base64.StdEncoding.EncodeToString(keyBytes) - response.Keys = append(response.Keys, key) - } - response.Result = true - -SEND: - s.sendKeyResponse(q, &response) -} diff --git a/vendor/github.com/hashicorp/serf/serf/keymanager.go b/vendor/github.com/hashicorp/serf/serf/keymanager.go deleted file mode 100644 index 72a319449..000000000 --- a/vendor/github.com/hashicorp/serf/serf/keymanager.go +++ /dev/null @@ -1,166 +0,0 @@ -package serf - -import ( - "encoding/base64" - "fmt" - "sync" -) - -// KeyManager encapsulates all functionality within Serf for handling -// encryption keyring changes across a cluster. -type KeyManager struct { - serf *Serf - - // Lock to protect read and write operations - l sync.RWMutex -} - -// keyRequest is used to contain input parameters which get broadcasted to all -// nodes as part of a key query operation. -type keyRequest struct { - Key []byte -} - -// KeyResponse is used to relay a query for a list of all keys in use. -type KeyResponse struct { - Messages map[string]string // Map of node name to response message - NumNodes int // Total nodes memberlist knows of - NumResp int // Total responses received - NumErr int // Total errors from request - - // Keys is a mapping of the base64-encoded value of the key bytes to the - // number of nodes that have the key installed. - Keys map[string]int -} - -// streamKeyResp takes care of reading responses from a channel and composing -// them into a KeyResponse. It will update a KeyResponse *in place* and -// therefore has nothing to return. -func (k *KeyManager) streamKeyResp(resp *KeyResponse, ch <-chan NodeResponse) { - for r := range ch { - var nodeResponse nodeKeyResponse - - resp.NumResp++ - - // Decode the response - if len(r.Payload) < 1 || messageType(r.Payload[0]) != messageKeyResponseType { - resp.Messages[r.From] = fmt.Sprintf( - "Invalid key query response type: %v", r.Payload) - resp.NumErr++ - goto NEXT - } - if err := decodeMessage(r.Payload[1:], &nodeResponse); err != nil { - resp.Messages[r.From] = fmt.Sprintf( - "Failed to decode key query response: %v", r.Payload) - resp.NumErr++ - goto NEXT - } - - if !nodeResponse.Result { - resp.Messages[r.From] = nodeResponse.Message - resp.NumErr++ - } - - // Currently only used for key list queries, this adds keys to a counter - // and increments them for each node response which contains them. - for _, key := range nodeResponse.Keys { - if _, ok := resp.Keys[key]; !ok { - resp.Keys[key] = 1 - } else { - resp.Keys[key]++ - } - } - - NEXT: - // Return early if all nodes have responded. This allows us to avoid - // waiting for the full timeout when there is nothing left to do. - if resp.NumResp == resp.NumNodes { - return - } - } -} - -// handleKeyRequest performs query broadcasting to all members for any type of -// key operation and manages gathering responses and packing them up into a -// KeyResponse for uniform response handling. -func (k *KeyManager) handleKeyRequest(key, query string) (*KeyResponse, error) { - resp := &KeyResponse{ - Messages: make(map[string]string), - Keys: make(map[string]int), - } - qName := internalQueryName(query) - - // Decode the new key into raw bytes - rawKey, err := base64.StdEncoding.DecodeString(key) - if err != nil { - return resp, err - } - - // Encode the query request - req, err := encodeMessage(messageKeyRequestType, keyRequest{Key: rawKey}) - if err != nil { - return resp, err - } - - qParam := k.serf.DefaultQueryParams() - queryResp, err := k.serf.Query(qName, req, qParam) - if err != nil { - return resp, err - } - - // Handle the response stream and populate the KeyResponse - resp.NumNodes = k.serf.memberlist.NumMembers() - k.streamKeyResp(resp, queryResp.respCh) - - // Check the response for any reported failure conditions - if resp.NumErr != 0 { - return resp, fmt.Errorf("%d/%d nodes reported failure", resp.NumErr, resp.NumNodes) - } - if resp.NumResp != resp.NumNodes { - return resp, fmt.Errorf("%d/%d nodes reported success", resp.NumResp, resp.NumNodes) - } - - return resp, nil -} - -// InstallKey handles broadcasting a query to all members and gathering -// responses from each of them, returning a list of messages from each node -// and any applicable error conditions. -func (k *KeyManager) InstallKey(key string) (*KeyResponse, error) { - k.l.Lock() - defer k.l.Unlock() - - return k.handleKeyRequest(key, installKeyQuery) -} - -// UseKey handles broadcasting a primary key change to all members in the -// cluster, and gathering any response messages. If successful, there should -// be an empty KeyResponse returned. -func (k *KeyManager) UseKey(key string) (*KeyResponse, error) { - k.l.Lock() - defer k.l.Unlock() - - return k.handleKeyRequest(key, useKeyQuery) -} - -// RemoveKey handles broadcasting a key to the cluster for removal. Each member -// will receive this event, and if they have the key in their keyring, remove -// it. If any errors are encountered, RemoveKey will collect and relay them. -func (k *KeyManager) RemoveKey(key string) (*KeyResponse, error) { - k.l.Lock() - defer k.l.Unlock() - - return k.handleKeyRequest(key, removeKeyQuery) -} - -// ListKeys is used to collect installed keys from members in a Serf cluster -// and return an aggregated list of all installed keys. This is useful to -// operators to ensure that there are no lingering keys installed on any agents. -// Since having multiple keys installed can cause performance penalties in some -// cases, it's important to verify this information and remove unneeded keys. -func (k *KeyManager) ListKeys() (*KeyResponse, error) { - k.l.RLock() - defer k.l.RUnlock() - - return k.handleKeyRequest("", listKeysQuery) -} diff --git a/vendor/github.com/hashicorp/serf/serf/lamport.go b/vendor/github.com/hashicorp/serf/serf/lamport.go deleted file mode 100644 index 08f4aa7a6..000000000 --- a/vendor/github.com/hashicorp/serf/serf/lamport.go +++ /dev/null @@ -1,45 +0,0 @@ -package serf - -import ( - "sync/atomic" -) - -// LamportClock is a thread safe implementation of a lamport clock. It -// uses efficient atomic operations for all of its functions, falling back -// to a heavy lock only if there are enough CAS failures. -type LamportClock struct { - counter uint64 -} - -// LamportTime is the value of a LamportClock. -type LamportTime uint64 - -// Time is used to return the current value of the lamport clock -func (l *LamportClock) Time() LamportTime { - return LamportTime(atomic.LoadUint64(&l.counter)) -} - -// Increment is used to increment and return the value of the lamport clock -func (l *LamportClock) Increment() LamportTime { - return LamportTime(atomic.AddUint64(&l.counter, 1)) -} - -// Witness is called to update our local clock if necessary after -// witnessing a clock value received from another process -func (l *LamportClock) Witness(v LamportTime) { -WITNESS: - // If the other value is old, we do not need to do anything - cur := atomic.LoadUint64(&l.counter) - other := uint64(v) - if other < cur { - return - } - - // Ensure that our local clock is at least one ahead. - if !atomic.CompareAndSwapUint64(&l.counter, cur, other+1) { - // The CAS failed, so we just retry. Eventually our CAS should - // succeed or a future witness will pass us by and our witness - // will end. - goto WITNESS - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/merge_delegate.go b/vendor/github.com/hashicorp/serf/serf/merge_delegate.go deleted file mode 100644 index 7fdc73288..000000000 --- a/vendor/github.com/hashicorp/serf/serf/merge_delegate.go +++ /dev/null @@ -1,44 +0,0 @@ -package serf - -import ( - "net" - - "github.com/hashicorp/memberlist" -) - -type MergeDelegate interface { - NotifyMerge([]*Member) error -} - -type mergeDelegate struct { - serf *Serf -} - -func (m *mergeDelegate) NotifyMerge(nodes []*memberlist.Node) error { - members := make([]*Member, len(nodes)) - for idx, n := range nodes { - members[idx] = m.nodeToMember(n) - } - return m.serf.config.Merge.NotifyMerge(members) -} - -func (m *mergeDelegate) NotifyAlive(peer *memberlist.Node) error { - member := m.nodeToMember(peer) - return m.serf.config.Merge.NotifyMerge([]*Member{member}) -} - -func (m *mergeDelegate) nodeToMember(n *memberlist.Node) *Member { - return &Member{ - Name: n.Name, - Addr: net.IP(n.Addr), - Port: n.Port, - Tags: m.serf.decodeTags(n.Meta), - Status: StatusNone, - ProtocolMin: n.PMin, - ProtocolMax: n.PMax, - ProtocolCur: n.PCur, - DelegateMin: n.DMin, - DelegateMax: n.DMax, - DelegateCur: n.DCur, - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/messages.go b/vendor/github.com/hashicorp/serf/serf/messages.go deleted file mode 100644 index c90c96450..000000000 --- a/vendor/github.com/hashicorp/serf/serf/messages.go +++ /dev/null @@ -1,147 +0,0 @@ -package serf - -import ( - "bytes" - "github.com/hashicorp/go-msgpack/codec" - "time" -) - -// messageType are the types of gossip messages Serf will send along -// memberlist. -type messageType uint8 - -const ( - messageLeaveType messageType = iota - messageJoinType - messagePushPullType - messageUserEventType - messageQueryType - messageQueryResponseType - messageConflictResponseType - messageKeyRequestType - messageKeyResponseType -) - -const ( - // Ack flag is used to force receiver to send an ack back - queryFlagAck uint32 = 1 << iota - - // NoBroadcast is used to prevent re-broadcast of a query. - // this can be used to selectively send queries to individual members - queryFlagNoBroadcast -) - -// filterType is used with a queryFilter to specify the type of -// filter we are sending -type filterType uint8 - -const ( - filterNodeType filterType = iota - filterTagType -) - -// messageJoin is the message broadcasted after we join to -// associated the node with a lamport clock -type messageJoin struct { - LTime LamportTime - Node string -} - -// messageLeave is the message broadcasted to signal the intentional to -// leave. -type messageLeave struct { - LTime LamportTime - Node string -} - -// messagePushPullType is used when doing a state exchange. This -// is a relatively large message, but is sent infrequently -type messagePushPull struct { - LTime LamportTime // Current node lamport time - StatusLTimes map[string]LamportTime // Maps the node to its status time - LeftMembers []string // List of left nodes - EventLTime LamportTime // Lamport time for event clock - Events []*userEvents // Recent events - QueryLTime LamportTime // Lamport time for query clock -} - -// messageUserEvent is used for user-generated events -type messageUserEvent struct { - LTime LamportTime - Name string - Payload []byte - CC bool // "Can Coalesce". Zero value is compatible with Serf 0.1 -} - -// messageQuery is used for query events -type messageQuery struct { - LTime LamportTime // Event lamport time - ID uint32 // Query ID, randomly generated - Addr []byte // Source address, used for a direct reply - Port uint16 // Source port, used for a direct reply - Filters [][]byte // Potential query filters - Flags uint32 // Used to provide various flags - Timeout time.Duration // Maximum time between delivery and response - Name string // Query name - Payload []byte // Query payload -} - -// Ack checks if the ack flag is set -func (m *messageQuery) Ack() bool { - return (m.Flags & queryFlagAck) != 0 -} - -// NoBroadcast checks if the no broadcast flag is set -func (m *messageQuery) NoBroadcast() bool { - return (m.Flags & queryFlagNoBroadcast) != 0 -} - -// filterNode is used with the filterNodeType, and is a list -// of node names -type filterNode []string - -// filterTag is used with the filterTagType and is a regular -// expression to apply to a tag -type filterTag struct { - Tag string - Expr string -} - -// messageQueryResponse is used to respond to a query -type messageQueryResponse struct { - LTime LamportTime // Event lamport time - ID uint32 // Query ID - From string // Node name - Flags uint32 // Used to provide various flags - Payload []byte // Optional response payload -} - -// Ack checks if the ack flag is set -func (m *messageQueryResponse) Ack() bool { - return (m.Flags & queryFlagAck) != 0 -} - -func decodeMessage(buf []byte, out interface{}) error { - var handle codec.MsgpackHandle - return codec.NewDecoder(bytes.NewReader(buf), &handle).Decode(out) -} - -func encodeMessage(t messageType, msg interface{}) ([]byte, error) { - buf := bytes.NewBuffer(nil) - buf.WriteByte(uint8(t)) - - handle := codec.MsgpackHandle{} - encoder := codec.NewEncoder(buf, &handle) - err := encoder.Encode(msg) - return buf.Bytes(), err -} - -func encodeFilter(f filterType, filt interface{}) ([]byte, error) { - buf := bytes.NewBuffer(nil) - buf.WriteByte(uint8(f)) - - handle := codec.MsgpackHandle{} - encoder := codec.NewEncoder(buf, &handle) - err := encoder.Encode(filt) - return buf.Bytes(), err -} diff --git a/vendor/github.com/hashicorp/serf/serf/ping_delegate.go b/vendor/github.com/hashicorp/serf/serf/ping_delegate.go deleted file mode 100644 index a482685a2..000000000 --- a/vendor/github.com/hashicorp/serf/serf/ping_delegate.go +++ /dev/null @@ -1,89 +0,0 @@ -package serf - -import ( - "bytes" - "log" - "time" - - "github.com/armon/go-metrics" - "github.com/hashicorp/go-msgpack/codec" - "github.com/hashicorp/memberlist" - "github.com/hashicorp/serf/coordinate" -) - -// pingDelegate is notified when memberlist successfully completes a direct ping -// of a peer node. We use this to update our estimated network coordinate, as -// well as cache the coordinate of the peer. -type pingDelegate struct { - serf *Serf -} - -const ( - // PingVersion is an internal version for the ping message, above the normal - // versioning we get from the protocol version. This enables small updates - // to the ping message without a full protocol bump. - PingVersion = 1 -) - -// AckPayload is called to produce a payload to send back in response to a ping -// request. -func (p *pingDelegate) AckPayload() []byte { - var buf bytes.Buffer - - // The first byte is the version number, forming a simple header. - version := []byte{PingVersion} - buf.Write(version) - - // The rest of the message is the serialized coordinate. - enc := codec.NewEncoder(&buf, &codec.MsgpackHandle{}) - if err := enc.Encode(p.serf.coordClient.GetCoordinate()); err != nil { - log.Printf("[ERR] serf: Failed to encode coordinate: %v\n", err) - } - return buf.Bytes() -} - -// NotifyPingComplete is called when this node successfully completes a direct ping -// of a peer node. -func (p *pingDelegate) NotifyPingComplete(other *memberlist.Node, rtt time.Duration, payload []byte) { - if payload == nil || len(payload) == 0 { - return - } - - // Verify ping version in the header. - version := payload[0] - if version != PingVersion { - log.Printf("[ERR] serf: Unsupported ping version: %v", version) - return - } - - // Process the remainder of the message as a coordinate. - r := bytes.NewReader(payload[1:]) - dec := codec.NewDecoder(r, &codec.MsgpackHandle{}) - var coord coordinate.Coordinate - if err := dec.Decode(&coord); err != nil { - log.Printf("[ERR] serf: Failed to decode coordinate from ping: %v", err) - } - - // Apply the update. Since this is a coordinate coming from some place - // else we harden this and look for dimensionality problems proactively. - before := p.serf.coordClient.GetCoordinate() - if before.IsCompatibleWith(&coord) { - after := p.serf.coordClient.Update(other.Name, &coord, rtt) - - // Publish some metrics to give us an idea of how much we are - // adjusting each time we update. - d := float32(before.DistanceTo(after).Seconds() * 1.0e3) - metrics.AddSample([]string{"serf", "coordinate", "adjustment-ms"}, d) - - // Cache the coordinate for the other node, and add our own - // to the cache as well since it just got updated. This lets - // users call GetCachedCoordinate with our node name, which is - // more friendly. - p.serf.coordCacheLock.Lock() - p.serf.coordCache[other.Name] = &coord - p.serf.coordCache[p.serf.config.NodeName] = p.serf.coordClient.GetCoordinate() - p.serf.coordCacheLock.Unlock() - } else { - log.Printf("[ERR] serf: Rejected bad coordinate: %v\n", coord) - } -} diff --git a/vendor/github.com/hashicorp/serf/serf/query.go b/vendor/github.com/hashicorp/serf/serf/query.go deleted file mode 100644 index f29a3b3c5..000000000 --- a/vendor/github.com/hashicorp/serf/serf/query.go +++ /dev/null @@ -1,210 +0,0 @@ -package serf - -import ( - "math" - "regexp" - "sync" - "time" -) - -// QueryParam is provided to Query() to configure the parameters of the -// query. If not provided, sane defaults will be used. -type QueryParam struct { - // If provided, we restrict the nodes that should respond to those - // with names in this list - FilterNodes []string - - // FilterTags maps a tag name to a regular expression that is applied - // to restrict the nodes that should respond - FilterTags map[string]string - - // If true, we are requesting an delivery acknowledgement from - // every node that meets the filter requirement. This means nodes - // the receive the message but do not pass the filters, will not - // send an ack. - RequestAck bool - - // The timeout limits how long the query is left open. If not provided, - // then a default timeout is used based on the configuration of Serf - Timeout time.Duration -} - -// DefaultQueryTimeout returns the default timeout value for a query -// Computed as GossipInterval * QueryTimeoutMult * log(N+1) -func (s *Serf) DefaultQueryTimeout() time.Duration { - n := s.memberlist.NumMembers() - timeout := s.config.MemberlistConfig.GossipInterval - timeout *= time.Duration(s.config.QueryTimeoutMult) - timeout *= time.Duration(math.Ceil(math.Log10(float64(n + 1)))) - return timeout -} - -// DefaultQueryParam is used to return the default query parameters -func (s *Serf) DefaultQueryParams() *QueryParam { - return &QueryParam{ - FilterNodes: nil, - FilterTags: nil, - RequestAck: false, - Timeout: s.DefaultQueryTimeout(), - } -} - -// encodeFilters is used to convert the filters into the wire format -func (q *QueryParam) encodeFilters() ([][]byte, error) { - var filters [][]byte - - // Add the node filter - if len(q.FilterNodes) > 0 { - if buf, err := encodeFilter(filterNodeType, q.FilterNodes); err != nil { - return nil, err - } else { - filters = append(filters, buf) - } - } - - // Add the tag filters - for tag, expr := range q.FilterTags { - filt := filterTag{tag, expr} - if buf, err := encodeFilter(filterTagType, &filt); err != nil { - return nil, err - } else { - filters = append(filters, buf) - } - } - - return filters, nil -} - -// QueryResponse is returned for each new Query. It is used to collect -// Ack's as well as responses and to provide those back to a client. -type QueryResponse struct { - // ackCh is used to send the name of a node for which we've received an ack - ackCh chan string - - // deadline is the query end time (start + query timeout) - deadline time.Time - - // Query ID - id uint32 - - // Stores the LTime of the query - lTime LamportTime - - // respCh is used to send a response from a node - respCh chan NodeResponse - - closed bool - closeLock sync.Mutex -} - -// newQueryResponse is used to construct a new query response -func newQueryResponse(n int, q *messageQuery) *QueryResponse { - resp := &QueryResponse{ - deadline: time.Now().Add(q.Timeout), - id: q.ID, - lTime: q.LTime, - respCh: make(chan NodeResponse, n), - } - if q.Ack() { - resp.ackCh = make(chan string, n) - } - return resp -} - -// Close is used to close the query, which will close the underlying -// channels and prevent further deliveries -func (r *QueryResponse) Close() { - r.closeLock.Lock() - defer r.closeLock.Unlock() - if r.closed { - return - } - r.closed = true - if r.ackCh != nil { - close(r.ackCh) - } - if r.respCh != nil { - close(r.respCh) - } -} - -// Deadline returns the ending deadline of the query -func (r *QueryResponse) Deadline() time.Time { - return r.deadline -} - -// Finished returns if the query is finished running -func (r *QueryResponse) Finished() bool { - return r.closed || time.Now().After(r.deadline) -} - -// AckCh returns a channel that can be used to listen for acks -// Channel will be closed when the query is finished. This is nil, -// if the query did not specify RequestAck. -func (r *QueryResponse) AckCh() <-chan string { - return r.ackCh -} - -// ResponseCh returns a channel that can be used to listen for responses. -// Channel will be closed when the query is finished. -func (r *QueryResponse) ResponseCh() <-chan NodeResponse { - return r.respCh -} - -// NodeResponse is used to represent a single response from a node -type NodeResponse struct { - From string - Payload []byte -} - -// shouldProcessQuery checks if a query should be proceeded given -// a set of filers. -func (s *Serf) shouldProcessQuery(filters [][]byte) bool { - for _, filter := range filters { - switch filterType(filter[0]) { - case filterNodeType: - // Decode the filter - var nodes filterNode - if err := decodeMessage(filter[1:], &nodes); err != nil { - s.logger.Printf("[WARN] serf: failed to decode filterNodeType: %v", err) - return false - } - - // Check if we are being targeted - found := false - for _, n := range nodes { - if n == s.config.NodeName { - found = true - break - } - } - if !found { - return false - } - - case filterTagType: - // Decode the filter - var filt filterTag - if err := decodeMessage(filter[1:], &filt); err != nil { - s.logger.Printf("[WARN] serf: failed to decode filterTagType: %v", err) - return false - } - - // Check if we match this regex - tags := s.config.Tags - matched, err := regexp.MatchString(filt.Expr, tags[filt.Tag]) - if err != nil { - s.logger.Printf("[WARN] serf: failed to compile filter regex (%s): %v", filt.Expr, err) - return false - } - if !matched { - return false - } - - default: - s.logger.Printf("[WARN] serf: query has unrecognized filter type: %d", filter[0]) - return false - } - } - return true -} diff --git a/vendor/github.com/hashicorp/serf/serf/serf.go b/vendor/github.com/hashicorp/serf/serf/serf.go deleted file mode 100644 index 04b300a9b..000000000 --- a/vendor/github.com/hashicorp/serf/serf/serf.go +++ /dev/null @@ -1,1698 +0,0 @@ -package serf - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "log" - "math/rand" - "net" - "strconv" - "sync" - "time" - - "github.com/armon/go-metrics" - "github.com/hashicorp/go-msgpack/codec" - "github.com/hashicorp/memberlist" - "github.com/hashicorp/serf/coordinate" -) - -// These are the protocol versions that Serf can _understand_. These are -// Serf-level protocol versions that are passed down as the delegate -// version to memberlist below. -const ( - ProtocolVersionMin uint8 = 2 - ProtocolVersionMax = 4 -) - -const ( - // Used to detect if the meta data is tags - // or if it is a raw role - tagMagicByte uint8 = 255 -) - -var ( - // FeatureNotSupported is returned if a feature cannot be used - // due to an older protocol version being used. - FeatureNotSupported = fmt.Errorf("Feature not supported") -) - -func init() { - // Seed the random number generator - rand.Seed(time.Now().UnixNano()) -} - -// Serf is a single node that is part of a single cluster that gets -// events about joins/leaves/failures/etc. It is created with the Create -// method. -// -// All functions on the Serf structure are safe to call concurrently. -type Serf struct { - // The clocks for different purposes. These MUST be the first things - // in this struct due to Golang issue #599. - clock LamportClock - eventClock LamportClock - queryClock LamportClock - - broadcasts *memberlist.TransmitLimitedQueue - config *Config - failedMembers []*memberState - leftMembers []*memberState - memberlist *memberlist.Memberlist - memberLock sync.RWMutex - members map[string]*memberState - - // Circular buffers for recent intents, used - // in case we get the intent before the relevant event - recentLeave []nodeIntent - recentLeaveIndex int - recentJoin []nodeIntent - recentJoinIndex int - - eventBroadcasts *memberlist.TransmitLimitedQueue - eventBuffer []*userEvents - eventJoinIgnore bool - eventMinTime LamportTime - eventLock sync.RWMutex - - queryBroadcasts *memberlist.TransmitLimitedQueue - queryBuffer []*queries - queryMinTime LamportTime - queryResponse map[LamportTime]*QueryResponse - queryLock sync.RWMutex - - logger *log.Logger - joinLock sync.Mutex - stateLock sync.Mutex - state SerfState - shutdownCh chan struct{} - - snapshotter *Snapshotter - keyManager *KeyManager - - coordClient *coordinate.Client - coordCache map[string]*coordinate.Coordinate - coordCacheLock sync.RWMutex -} - -// SerfState is the state of the Serf instance. -type SerfState int - -const ( - SerfAlive SerfState = iota - SerfLeaving - SerfLeft - SerfShutdown -) - -func (s SerfState) String() string { - switch s { - case SerfAlive: - return "alive" - case SerfLeaving: - return "leaving" - case SerfLeft: - return "left" - case SerfShutdown: - return "shutdown" - default: - return "unknown" - } -} - -// Member is a single member of the Serf cluster. -type Member struct { - Name string - Addr net.IP - Port uint16 - Tags map[string]string - Status MemberStatus - - // The minimum, maximum, and current values of the protocol versions - // and delegate (Serf) protocol versions that each member can understand - // or is speaking. - ProtocolMin uint8 - ProtocolMax uint8 - ProtocolCur uint8 - DelegateMin uint8 - DelegateMax uint8 - DelegateCur uint8 -} - -// MemberStatus is the state that a member is in. -type MemberStatus int - -const ( - StatusNone MemberStatus = iota - StatusAlive - StatusLeaving - StatusLeft - StatusFailed -) - -func (s MemberStatus) String() string { - switch s { - case StatusNone: - return "none" - case StatusAlive: - return "alive" - case StatusLeaving: - return "leaving" - case StatusLeft: - return "left" - case StatusFailed: - return "failed" - default: - panic(fmt.Sprintf("unknown MemberStatus: %d", s)) - } -} - -// memberState is used to track members that are no longer active due to -// leaving, failing, partitioning, etc. It tracks the member along with -// when that member was marked as leaving. -type memberState struct { - Member - statusLTime LamportTime // lamport clock time of last received message - leaveTime time.Time // wall clock time of leave -} - -// nodeIntent is used to buffer intents for out-of-order deliveries -type nodeIntent struct { - LTime LamportTime - Node string -} - -// userEvent is used to buffer events to prevent re-delivery -type userEvent struct { - Name string - Payload []byte -} - -func (ue *userEvent) Equals(other *userEvent) bool { - if ue.Name != other.Name { - return false - } - if bytes.Compare(ue.Payload, other.Payload) != 0 { - return false - } - return true -} - -// userEvents stores all the user events at a specific time -type userEvents struct { - LTime LamportTime - Events []userEvent -} - -// queries stores all the query ids at a specific time -type queries struct { - LTime LamportTime - QueryIDs []uint32 -} - -const ( - UserEventSizeLimit = 512 // Maximum byte size for event name and payload - snapshotSizeLimit = 128 * 1024 // Maximum 128 KB snapshot -) - -// Create creates a new Serf instance, starting all the background tasks -// to maintain cluster membership information. -// -// After calling this function, the configuration should no longer be used -// or modified by the caller. -func Create(conf *Config) (*Serf, error) { - conf.Init() - if conf.ProtocolVersion < ProtocolVersionMin { - return nil, fmt.Errorf("Protocol version '%d' too low. Must be in range: [%d, %d]", - conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax) - } else if conf.ProtocolVersion > ProtocolVersionMax { - return nil, fmt.Errorf("Protocol version '%d' too high. Must be in range: [%d, %d]", - conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax) - } - - serf := &Serf{ - config: conf, - logger: log.New(conf.LogOutput, "", log.LstdFlags), - members: make(map[string]*memberState), - queryResponse: make(map[LamportTime]*QueryResponse), - shutdownCh: make(chan struct{}), - state: SerfAlive, - } - - // Check that the meta data length is okay - if len(serf.encodeTags(conf.Tags)) > memberlist.MetaMaxSize { - return nil, fmt.Errorf("Encoded length of tags exceeds limit of %d bytes", memberlist.MetaMaxSize) - } - - // Check if serf member event coalescing is enabled - if conf.CoalescePeriod > 0 && conf.QuiescentPeriod > 0 && conf.EventCh != nil { - c := &memberEventCoalescer{ - lastEvents: make(map[string]EventType), - latestEvents: make(map[string]coalesceEvent), - } - - conf.EventCh = coalescedEventCh(conf.EventCh, serf.shutdownCh, - conf.CoalescePeriod, conf.QuiescentPeriod, c) - } - - // Check if user event coalescing is enabled - if conf.UserCoalescePeriod > 0 && conf.UserQuiescentPeriod > 0 && conf.EventCh != nil { - c := &userEventCoalescer{ - events: make(map[string]*latestUserEvents), - } - - conf.EventCh = coalescedEventCh(conf.EventCh, serf.shutdownCh, - conf.UserCoalescePeriod, conf.UserQuiescentPeriod, c) - } - - // Listen for internal Serf queries. This is setup before the snapshotter, since - // we want to capture the query-time, but the internal listener does not passthrough - // the queries - outCh, err := newSerfQueries(serf, serf.logger, conf.EventCh, serf.shutdownCh) - if err != nil { - return nil, fmt.Errorf("Failed to setup serf query handler: %v", err) - } - conf.EventCh = outCh - - // Set up network coordinate client. - if !conf.DisableCoordinates { - serf.coordClient, err = coordinate.NewClient(coordinate.DefaultConfig()) - if err != nil { - return nil, fmt.Errorf("Failed to create coordinate client: %v", err) - } - } - - // Try access the snapshot - var oldClock, oldEventClock, oldQueryClock LamportTime - var prev []*PreviousNode - if conf.SnapshotPath != "" { - eventCh, snap, err := NewSnapshotter( - conf.SnapshotPath, - snapshotSizeLimit, - conf.RejoinAfterLeave, - serf.logger, - &serf.clock, - serf.coordClient, - conf.EventCh, - serf.shutdownCh) - if err != nil { - return nil, fmt.Errorf("Failed to setup snapshot: %v", err) - } - serf.snapshotter = snap - conf.EventCh = eventCh - prev = snap.AliveNodes() - oldClock = snap.LastClock() - oldEventClock = snap.LastEventClock() - oldQueryClock = snap.LastQueryClock() - serf.eventMinTime = oldEventClock + 1 - serf.queryMinTime = oldQueryClock + 1 - } - - // Set up the coordinate cache. We do this after we read the snapshot to - // make sure we get a good initial value from there, if we got one. - if !conf.DisableCoordinates { - serf.coordCache = make(map[string]*coordinate.Coordinate) - serf.coordCache[conf.NodeName] = serf.coordClient.GetCoordinate() - } - - // Setup the various broadcast queues, which we use to send our own - // custom broadcasts along the gossip channel. - serf.broadcasts = &memberlist.TransmitLimitedQueue{ - NumNodes: func() int { - return len(serf.members) - }, - RetransmitMult: conf.MemberlistConfig.RetransmitMult, - } - serf.eventBroadcasts = &memberlist.TransmitLimitedQueue{ - NumNodes: func() int { - return len(serf.members) - }, - RetransmitMult: conf.MemberlistConfig.RetransmitMult, - } - serf.queryBroadcasts = &memberlist.TransmitLimitedQueue{ - NumNodes: func() int { - return len(serf.members) - }, - RetransmitMult: conf.MemberlistConfig.RetransmitMult, - } - - // Create the buffer for recent intents - serf.recentJoin = make([]nodeIntent, conf.RecentIntentBuffer) - serf.recentLeave = make([]nodeIntent, conf.RecentIntentBuffer) - - // Create a buffer for events and queries - serf.eventBuffer = make([]*userEvents, conf.EventBuffer) - serf.queryBuffer = make([]*queries, conf.QueryBuffer) - - // Ensure our lamport clock is at least 1, so that the default - // join LTime of 0 does not cause issues - serf.clock.Increment() - serf.eventClock.Increment() - serf.queryClock.Increment() - - // Restore the clock from snap if we have one - serf.clock.Witness(oldClock) - serf.eventClock.Witness(oldEventClock) - serf.queryClock.Witness(oldQueryClock) - - // Modify the memberlist configuration with keys that we set - conf.MemberlistConfig.Events = &eventDelegate{serf: serf} - conf.MemberlistConfig.Conflict = &conflictDelegate{serf: serf} - conf.MemberlistConfig.Delegate = &delegate{serf: serf} - conf.MemberlistConfig.DelegateProtocolVersion = conf.ProtocolVersion - conf.MemberlistConfig.DelegateProtocolMin = ProtocolVersionMin - conf.MemberlistConfig.DelegateProtocolMax = ProtocolVersionMax - conf.MemberlistConfig.Name = conf.NodeName - conf.MemberlistConfig.ProtocolVersion = ProtocolVersionMap[conf.ProtocolVersion] - if !conf.DisableCoordinates { - conf.MemberlistConfig.Ping = &pingDelegate{serf: serf} - } - - // Setup a merge delegate if necessary - if conf.Merge != nil { - md := &mergeDelegate{serf: serf} - conf.MemberlistConfig.Merge = md - conf.MemberlistConfig.Alive = md - } - - // Create the underlying memberlist that will manage membership - // and failure detection for the Serf instance. - memberlist, err := memberlist.Create(conf.MemberlistConfig) - if err != nil { - return nil, fmt.Errorf("Failed to create memberlist: %v", err) - } - - serf.memberlist = memberlist - - // Create a key manager for handling all encryption key changes - serf.keyManager = &KeyManager{serf: serf} - - // Start the background tasks. See the documentation above each method - // for more information on their role. - go serf.handleReap() - go serf.handleReconnect() - go serf.checkQueueDepth("Intent", serf.broadcasts) - go serf.checkQueueDepth("Event", serf.eventBroadcasts) - go serf.checkQueueDepth("Query", serf.queryBroadcasts) - - // Attempt to re-join the cluster if we have known nodes - if len(prev) != 0 { - go serf.handleRejoin(prev) - } - - return serf, nil -} - -// ProtocolVersion returns the current protocol version in use by Serf. -// This is the Serf protocol version, not the memberlist protocol version. -func (s *Serf) ProtocolVersion() uint8 { - return s.config.ProtocolVersion -} - -// EncryptionEnabled is a predicate that determines whether or not encryption -// is enabled, which can be possible in one of 2 cases: -// - Single encryption key passed at agent start (no persistence) -// - Keyring file provided at agent start -func (s *Serf) EncryptionEnabled() bool { - return s.config.MemberlistConfig.Keyring != nil -} - -// KeyManager returns the key manager for the current Serf instance. -func (s *Serf) KeyManager() *KeyManager { - return s.keyManager -} - -// UserEvent is used to broadcast a custom user event with a given -// name and payload. The events must be fairly small, and if the -// size limit is exceeded and error will be returned. If coalesce is enabled, -// nodes are allowed to coalesce this event. Coalescing is only available -// starting in v0.2 -func (s *Serf) UserEvent(name string, payload []byte, coalesce bool) error { - // Check the size limit - if len(name)+len(payload) > UserEventSizeLimit { - return fmt.Errorf("user event exceeds limit of %d bytes", UserEventSizeLimit) - } - - // Create a message - msg := messageUserEvent{ - LTime: s.eventClock.Time(), - Name: name, - Payload: payload, - CC: coalesce, - } - s.eventClock.Increment() - - // Process update locally - s.handleUserEvent(&msg) - - // Start broadcasting the event - raw, err := encodeMessage(messageUserEventType, &msg) - if err != nil { - return err - } - s.eventBroadcasts.QueueBroadcast(&broadcast{ - msg: raw, - }) - return nil -} - -// Query is used to broadcast a new query. The query must be fairly small, -// and an error will be returned if the size limit is exceeded. This is only -// available with protocol version 4 and newer. Query parameters are optional, -// and if not provided, a sane set of defaults will be used. -func (s *Serf) Query(name string, payload []byte, params *QueryParam) (*QueryResponse, error) { - // Check that the latest protocol is in use - if s.ProtocolVersion() < 4 { - return nil, FeatureNotSupported - } - - // Provide default parameters if none given - if params == nil { - params = s.DefaultQueryParams() - } else if params.Timeout == 0 { - params.Timeout = s.DefaultQueryTimeout() - } - - // Get the local node - local := s.memberlist.LocalNode() - - // Encode the filters - filters, err := params.encodeFilters() - if err != nil { - return nil, fmt.Errorf("Failed to format filters: %v", err) - } - - // Setup the flags - var flags uint32 - if params.RequestAck { - flags |= queryFlagAck - } - - // Create a message - q := messageQuery{ - LTime: s.queryClock.Time(), - ID: uint32(rand.Int31()), - Addr: local.Addr, - Port: local.Port, - Filters: filters, - Flags: flags, - Timeout: params.Timeout, - Name: name, - Payload: payload, - } - - // Encode the query - raw, err := encodeMessage(messageQueryType, &q) - if err != nil { - return nil, err - } - - // Check the size - if len(raw) > s.config.QuerySizeLimit { - return nil, fmt.Errorf("query exceeds limit of %d bytes", s.config.QuerySizeLimit) - } - - // Register QueryResponse to track acks and responses - resp := newQueryResponse(s.memberlist.NumMembers(), &q) - s.registerQueryResponse(params.Timeout, resp) - - // Process query locally - s.handleQuery(&q) - - // Start broadcasting the event - s.queryBroadcasts.QueueBroadcast(&broadcast{ - msg: raw, - }) - return resp, nil -} - -// registerQueryResponse is used to setup the listeners for the query, -// and to schedule closing the query after the timeout. -func (s *Serf) registerQueryResponse(timeout time.Duration, resp *QueryResponse) { - s.queryLock.Lock() - defer s.queryLock.Unlock() - - // Map the LTime to the QueryResponse. This is necessarily 1-to-1, - // since we increment the time for each new query. - s.queryResponse[resp.lTime] = resp - - // Setup a timer to close the response and deregister after the timeout - time.AfterFunc(timeout, func() { - s.queryLock.Lock() - delete(s.queryResponse, resp.lTime) - resp.Close() - s.queryLock.Unlock() - }) -} - -// SetTags is used to dynamically update the tags associated with -// the local node. This will propagate the change to the rest of -// the cluster. Blocks until a the message is broadcast out. -func (s *Serf) SetTags(tags map[string]string) error { - // Check that the meta data length is okay - if len(s.encodeTags(tags)) > memberlist.MetaMaxSize { - return fmt.Errorf("Encoded length of tags exceeds limit of %d bytes", - memberlist.MetaMaxSize) - } - - // Update the config - s.config.Tags = tags - - // Trigger a memberlist update - return s.memberlist.UpdateNode(s.config.BroadcastTimeout) -} - -// Join joins an existing Serf cluster. Returns the number of nodes -// successfully contacted. The returned error will be non-nil only in the -// case that no nodes could be contacted. If ignoreOld is true, then any -// user messages sent prior to the join will be ignored. -func (s *Serf) Join(existing []string, ignoreOld bool) (int, error) { - // Do a quick state check - if s.State() != SerfAlive { - return 0, fmt.Errorf("Serf can't Join after Leave or Shutdown") - } - - // Hold the joinLock, this is to make eventJoinIgnore safe - s.joinLock.Lock() - defer s.joinLock.Unlock() - - // Ignore any events from a potential join. This is safe since we hold - // the joinLock and nobody else can be doing a Join - if ignoreOld { - s.eventJoinIgnore = true - defer func() { - s.eventJoinIgnore = false - }() - } - - // Have memberlist attempt to join - num, err := s.memberlist.Join(existing) - - // If we joined any nodes, broadcast the join message - if num > 0 { - // Start broadcasting the update - if err := s.broadcastJoin(s.clock.Time()); err != nil { - return num, err - } - } - - return num, err -} - -// broadcastJoin broadcasts a new join intent with a -// given clock value. It is used on either join, or if -// we need to refute an older leave intent. Cannot be called -// with the memberLock held. -func (s *Serf) broadcastJoin(ltime LamportTime) error { - // Construct message to update our lamport clock - msg := messageJoin{ - LTime: ltime, - Node: s.config.NodeName, - } - s.clock.Witness(ltime) - - // Process update locally - s.handleNodeJoinIntent(&msg) - - // Start broadcasting the update - if err := s.broadcast(messageJoinType, &msg, nil); err != nil { - s.logger.Printf("[WARN] serf: Failed to broadcast join intent: %v", err) - return err - } - return nil -} - -// Leave gracefully exits the cluster. It is safe to call this multiple -// times. -func (s *Serf) Leave() error { - // Check the current state - s.stateLock.Lock() - if s.state == SerfLeft { - s.stateLock.Unlock() - return nil - } else if s.state == SerfLeaving { - s.stateLock.Unlock() - return fmt.Errorf("Leave already in progress") - } else if s.state == SerfShutdown { - s.stateLock.Unlock() - return fmt.Errorf("Leave called after Shutdown") - } - s.state = SerfLeaving - s.stateLock.Unlock() - - // If we have a snapshot, mark we are leaving - if s.snapshotter != nil { - s.snapshotter.Leave() - } - - // Construct the message for the graceful leave - msg := messageLeave{ - LTime: s.clock.Time(), - Node: s.config.NodeName, - } - s.clock.Increment() - - // Process the leave locally - s.handleNodeLeaveIntent(&msg) - - // Only broadcast the leave message if there is at least one - // other node alive. - if s.hasAliveMembers() { - notifyCh := make(chan struct{}) - if err := s.broadcast(messageLeaveType, &msg, notifyCh); err != nil { - return err - } - - select { - case <-notifyCh: - case <-time.After(s.config.BroadcastTimeout): - return errors.New("timeout while waiting for graceful leave") - } - } - - // Attempt the memberlist leave - err := s.memberlist.Leave(s.config.BroadcastTimeout) - if err != nil { - return err - } - - // Transition to Left only if we not already shutdown - s.stateLock.Lock() - if s.state != SerfShutdown { - s.state = SerfLeft - } - s.stateLock.Unlock() - return nil -} - -// hasAliveMembers is called to check for any alive members other than -// ourself. -func (s *Serf) hasAliveMembers() bool { - s.memberLock.RLock() - defer s.memberLock.RUnlock() - - hasAlive := false - for _, m := range s.members { - // Skip ourself, we want to know if OTHER members are alive - if m.Name == s.config.NodeName { - continue - } - - if m.Status == StatusAlive { - hasAlive = true - break - } - } - return hasAlive -} - -// LocalMember returns the Member information for the local node -func (s *Serf) LocalMember() Member { - s.memberLock.RLock() - defer s.memberLock.RUnlock() - return s.members[s.config.NodeName].Member -} - -// Members returns a point-in-time snapshot of the members of this cluster. -func (s *Serf) Members() []Member { - s.memberLock.RLock() - defer s.memberLock.RUnlock() - - members := make([]Member, 0, len(s.members)) - for _, m := range s.members { - members = append(members, m.Member) - } - - return members -} - -// RemoveFailedNode forcibly removes a failed node from the cluster -// immediately, instead of waiting for the reaper to eventually reclaim it. -// This also has the effect that Serf will no longer attempt to reconnect -// to this node. -func (s *Serf) RemoveFailedNode(node string) error { - // Construct the message to broadcast - msg := messageLeave{ - LTime: s.clock.Time(), - Node: node, - } - s.clock.Increment() - - // Process our own event - s.handleNodeLeaveIntent(&msg) - - // If we have no members, then we don't need to broadcast - if !s.hasAliveMembers() { - return nil - } - - // Broadcast the remove - notifyCh := make(chan struct{}) - if err := s.broadcast(messageLeaveType, &msg, notifyCh); err != nil { - return err - } - - // Wait for the broadcast - select { - case <-notifyCh: - case <-time.After(s.config.BroadcastTimeout): - return fmt.Errorf("timed out broadcasting node removal") - } - - return nil -} - -// Shutdown forcefully shuts down the Serf instance, stopping all network -// activity and background maintenance associated with the instance. -// -// This is not a graceful shutdown, and should be preceded by a call -// to Leave. Otherwise, other nodes in the cluster will detect this node's -// exit as a node failure. -// -// It is safe to call this method multiple times. -func (s *Serf) Shutdown() error { - s.stateLock.Lock() - defer s.stateLock.Unlock() - - if s.state == SerfShutdown { - return nil - } - - if s.state != SerfLeft { - s.logger.Printf("[WARN] serf: Shutdown without a Leave") - } - - s.state = SerfShutdown - close(s.shutdownCh) - - err := s.memberlist.Shutdown() - if err != nil { - return err - } - - // Wait for the snapshoter to finish if we have one - if s.snapshotter != nil { - s.snapshotter.Wait() - } - - return nil -} - -// ShutdownCh returns a channel that can be used to wait for -// Serf to shutdown. -func (s *Serf) ShutdownCh() <-chan struct{} { - return s.shutdownCh -} - -// Memberlist is used to get access to the underlying Memberlist instance -func (s *Serf) Memberlist() *memberlist.Memberlist { - return s.memberlist -} - -// State is the current state of this Serf instance. -func (s *Serf) State() SerfState { - s.stateLock.Lock() - defer s.stateLock.Unlock() - return s.state -} - -// broadcast takes a Serf message type, encodes it for the wire, and queues -// the broadcast. If a notify channel is given, this channel will be closed -// when the broadcast is sent. -func (s *Serf) broadcast(t messageType, msg interface{}, notify chan<- struct{}) error { - raw, err := encodeMessage(t, msg) - if err != nil { - return err - } - - s.broadcasts.QueueBroadcast(&broadcast{ - msg: raw, - notify: notify, - }) - return nil -} - -// handleNodeJoin is called when a node join event is received -// from memberlist. -func (s *Serf) handleNodeJoin(n *memberlist.Node) { - s.memberLock.Lock() - defer s.memberLock.Unlock() - - var oldStatus MemberStatus - member, ok := s.members[n.Name] - if !ok { - oldStatus = StatusNone - member = &memberState{ - Member: Member{ - Name: n.Name, - Addr: net.IP(n.Addr), - Port: n.Port, - Tags: s.decodeTags(n.Meta), - Status: StatusAlive, - }, - } - - // Check if we have a join intent and use the LTime - if join := recentIntent(s.recentJoin, n.Name); join != nil { - member.statusLTime = join.LTime - } - - // Check if we have a leave intent - if leave := recentIntent(s.recentLeave, n.Name); leave != nil { - if leave.LTime > member.statusLTime { - member.Status = StatusLeaving - member.statusLTime = leave.LTime - } - } - - s.members[n.Name] = member - } else { - oldStatus = member.Status - deadTime := time.Now().Sub(member.leaveTime) - if oldStatus == StatusFailed && deadTime < s.config.FlapTimeout { - metrics.IncrCounter([]string{"serf", "member", "flap"}, 1) - } - - member.Status = StatusAlive - member.leaveTime = time.Time{} - member.Addr = net.IP(n.Addr) - member.Port = n.Port - member.Tags = s.decodeTags(n.Meta) - } - - // Update the protocol versions every time we get an event - member.ProtocolMin = n.PMin - member.ProtocolMax = n.PMax - member.ProtocolCur = n.PCur - member.DelegateMin = n.DMin - member.DelegateMax = n.DMax - member.DelegateCur = n.DCur - - // If node was previously in a failed state, then clean up some - // internal accounting. - // TODO(mitchellh): needs tests to verify not reaped - if oldStatus == StatusFailed || oldStatus == StatusLeft { - s.failedMembers = removeOldMember(s.failedMembers, member.Name) - s.leftMembers = removeOldMember(s.leftMembers, member.Name) - } - - // Update some metrics - metrics.IncrCounter([]string{"serf", "member", "join"}, 1) - - // Send an event along - s.logger.Printf("[INFO] serf: EventMemberJoin: %s %s", - member.Member.Name, member.Member.Addr) - if s.config.EventCh != nil { - s.config.EventCh <- MemberEvent{ - Type: EventMemberJoin, - Members: []Member{member.Member}, - } - } -} - -// handleNodeLeave is called when a node leave event is received -// from memberlist. -func (s *Serf) handleNodeLeave(n *memberlist.Node) { - s.memberLock.Lock() - defer s.memberLock.Unlock() - - member, ok := s.members[n.Name] - if !ok { - // We've never even heard of this node that is supposedly - // leaving. Just ignore it completely. - return - } - - switch member.Status { - case StatusLeaving: - member.Status = StatusLeft - member.leaveTime = time.Now() - s.leftMembers = append(s.leftMembers, member) - case StatusAlive: - member.Status = StatusFailed - member.leaveTime = time.Now() - s.failedMembers = append(s.failedMembers, member) - default: - // Unknown state that it was in? Just don't do anything - s.logger.Printf("[WARN] serf: Bad state when leave: %d", member.Status) - return - } - - // Send an event along - event := EventMemberLeave - eventStr := "EventMemberLeave" - if member.Status != StatusLeft { - event = EventMemberFailed - eventStr = "EventMemberFailed" - } - - // Update some metrics - metrics.IncrCounter([]string{"serf", "member", member.Status.String()}, 1) - - s.logger.Printf("[INFO] serf: %s: %s %s", - eventStr, member.Member.Name, member.Member.Addr) - if s.config.EventCh != nil { - s.config.EventCh <- MemberEvent{ - Type: event, - Members: []Member{member.Member}, - } - } -} - -// handleNodeUpdate is called when a node meta data update -// has taken place -func (s *Serf) handleNodeUpdate(n *memberlist.Node) { - s.memberLock.Lock() - defer s.memberLock.Unlock() - - member, ok := s.members[n.Name] - if !ok { - // We've never even heard of this node that is updating. - // Just ignore it completely. - return - } - - // Update the member attributes - member.Addr = net.IP(n.Addr) - member.Port = n.Port - member.Tags = s.decodeTags(n.Meta) - - // Snag the latest versions. NOTE - the current memberlist code will NOT - // fire an update event if the metadata (for Serf, tags) stays the same - // and only the protocol versions change. If we wake any Serf-level - // protocol changes where we want to get this event under those - // circumstances, we will need to update memberlist to do a check of - // versions as well as the metadata. - member.ProtocolMin = n.PMin - member.ProtocolMax = n.PMax - member.ProtocolCur = n.PCur - member.DelegateMin = n.DMin - member.DelegateMax = n.DMax - member.DelegateCur = n.DCur - - // Update some metrics - metrics.IncrCounter([]string{"serf", "member", "update"}, 1) - - // Send an event along - s.logger.Printf("[INFO] serf: EventMemberUpdate: %s", member.Member.Name) - if s.config.EventCh != nil { - s.config.EventCh <- MemberEvent{ - Type: EventMemberUpdate, - Members: []Member{member.Member}, - } - } -} - -// handleNodeLeaveIntent is called when an intent to leave is received. -func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool { - // Witness a potentially newer time - s.clock.Witness(leaveMsg.LTime) - - s.memberLock.Lock() - defer s.memberLock.Unlock() - - member, ok := s.members[leaveMsg.Node] - if !ok { - // If we've already seen this message don't rebroadcast - if recentIntent(s.recentLeave, leaveMsg.Node) != nil { - return false - } - - // We don't know this member so store it in a buffer for now - s.recentLeave[s.recentLeaveIndex] = nodeIntent{ - LTime: leaveMsg.LTime, - Node: leaveMsg.Node, - } - s.recentLeaveIndex = (s.recentLeaveIndex + 1) % len(s.recentLeave) - return true - } - - // If the message is old, then it is irrelevant and we can skip it - if leaveMsg.LTime <= member.statusLTime { - return false - } - - // Refute us leaving if we are in the alive state - // Must be done in another goroutine since we have the memberLock - if leaveMsg.Node == s.config.NodeName && s.state == SerfAlive { - s.logger.Printf("[DEBUG] serf: Refuting an older leave intent") - go s.broadcastJoin(s.clock.Time()) - return false - } - - // State transition depends on current state - switch member.Status { - case StatusAlive: - member.Status = StatusLeaving - member.statusLTime = leaveMsg.LTime - return true - case StatusFailed: - member.Status = StatusLeft - member.statusLTime = leaveMsg.LTime - - // Remove from the failed list and add to the left list. We add - // to the left list so that when we do a sync, other nodes will - // remove it from their failed list. - s.failedMembers = removeOldMember(s.failedMembers, member.Name) - s.leftMembers = append(s.leftMembers, member) - - // We must push a message indicating the node has now - // left to allow higher-level applications to handle the - // graceful leave. - s.logger.Printf("[INFO] serf: EventMemberLeave (forced): %s %s", - member.Member.Name, member.Member.Addr) - if s.config.EventCh != nil { - s.config.EventCh <- MemberEvent{ - Type: EventMemberLeave, - Members: []Member{member.Member}, - } - } - return true - default: - return false - } -} - -// handleNodeJoinIntent is called when a node broadcasts a -// join message to set the lamport time of its join -func (s *Serf) handleNodeJoinIntent(joinMsg *messageJoin) bool { - // Witness a potentially newer time - s.clock.Witness(joinMsg.LTime) - - s.memberLock.Lock() - defer s.memberLock.Unlock() - - member, ok := s.members[joinMsg.Node] - if !ok { - // If we've already seen this message don't rebroadcast - if recentIntent(s.recentJoin, joinMsg.Node) != nil { - return false - } - - // We don't know this member so store it in a buffer for now - s.recentJoin[s.recentJoinIndex] = nodeIntent{LTime: joinMsg.LTime, Node: joinMsg.Node} - s.recentJoinIndex = (s.recentJoinIndex + 1) % len(s.recentJoin) - return true - } - - // Check if this time is newer than what we have - if joinMsg.LTime <= member.statusLTime { - return false - } - - // Update the LTime - member.statusLTime = joinMsg.LTime - - // If we are in the leaving state, we should go back to alive, - // since the leaving message must have been for an older time - if member.Status == StatusLeaving { - member.Status = StatusAlive - } - return true -} - -// handleUserEvent is called when a user event broadcast is -// received. Returns if the message should be rebroadcast. -func (s *Serf) handleUserEvent(eventMsg *messageUserEvent) bool { - // Witness a potentially newer time - s.eventClock.Witness(eventMsg.LTime) - - s.eventLock.Lock() - defer s.eventLock.Unlock() - - // Ignore if it is before our minimum event time - if eventMsg.LTime < s.eventMinTime { - return false - } - - // Check if this message is too old - curTime := s.eventClock.Time() - if curTime > LamportTime(len(s.eventBuffer)) && - eventMsg.LTime < curTime-LamportTime(len(s.eventBuffer)) { - s.logger.Printf( - "[WARN] serf: received old event %s from time %d (current: %d)", - eventMsg.Name, - eventMsg.LTime, - s.eventClock.Time()) - return false - } - - // Check if we've already seen this - idx := eventMsg.LTime % LamportTime(len(s.eventBuffer)) - seen := s.eventBuffer[idx] - userEvent := userEvent{Name: eventMsg.Name, Payload: eventMsg.Payload} - if seen != nil && seen.LTime == eventMsg.LTime { - for _, previous := range seen.Events { - if previous.Equals(&userEvent) { - return false - } - } - } else { - seen = &userEvents{LTime: eventMsg.LTime} - s.eventBuffer[idx] = seen - } - - // Add to recent events - seen.Events = append(seen.Events, userEvent) - - // Update some metrics - metrics.IncrCounter([]string{"serf", "events"}, 1) - metrics.IncrCounter([]string{"serf", "events", eventMsg.Name}, 1) - - if s.config.EventCh != nil { - s.config.EventCh <- UserEvent{ - LTime: eventMsg.LTime, - Name: eventMsg.Name, - Payload: eventMsg.Payload, - Coalesce: eventMsg.CC, - } - } - return true -} - -// handleQuery is called when a query broadcast is -// received. Returns if the message should be rebroadcast. -func (s *Serf) handleQuery(query *messageQuery) bool { - // Witness a potentially newer time - s.queryClock.Witness(query.LTime) - - s.queryLock.Lock() - defer s.queryLock.Unlock() - - // Ignore if it is before our minimum query time - if query.LTime < s.queryMinTime { - return false - } - - // Check if this message is too old - curTime := s.queryClock.Time() - if curTime > LamportTime(len(s.queryBuffer)) && - query.LTime < curTime-LamportTime(len(s.queryBuffer)) { - s.logger.Printf( - "[WARN] serf: received old query %s from time %d (current: %d)", - query.Name, - query.LTime, - s.queryClock.Time()) - return false - } - - // Check if we've already seen this - idx := query.LTime % LamportTime(len(s.queryBuffer)) - seen := s.queryBuffer[idx] - if seen != nil && seen.LTime == query.LTime { - for _, previous := range seen.QueryIDs { - if previous == query.ID { - // Seen this ID already - return false - } - } - } else { - seen = &queries{LTime: query.LTime} - s.queryBuffer[idx] = seen - } - - // Add to recent queries - seen.QueryIDs = append(seen.QueryIDs, query.ID) - - // Update some metrics - metrics.IncrCounter([]string{"serf", "queries"}, 1) - metrics.IncrCounter([]string{"serf", "queries", query.Name}, 1) - - // Check if we should rebroadcast, this may be disabled by a flag - rebroadcast := true - if query.NoBroadcast() { - rebroadcast = false - } - - // Filter the query - if !s.shouldProcessQuery(query.Filters) { - // Even if we don't process it further, we should rebroadcast, - // since it is the first time we've seen this. - return rebroadcast - } - - // Send ack if requested, without waiting for client to Respond() - if query.Ack() { - ack := messageQueryResponse{ - LTime: query.LTime, - ID: query.ID, - From: s.config.NodeName, - Flags: queryFlagAck, - } - raw, err := encodeMessage(messageQueryResponseType, &ack) - if err != nil { - s.logger.Printf("[ERR] serf: failed to format ack: %v", err) - } else { - addr := net.UDPAddr{IP: query.Addr, Port: int(query.Port)} - if err := s.memberlist.SendTo(&addr, raw); err != nil { - s.logger.Printf("[ERR] serf: failed to send ack: %v", err) - } - } - } - - if s.config.EventCh != nil { - s.config.EventCh <- &Query{ - LTime: query.LTime, - Name: query.Name, - Payload: query.Payload, - serf: s, - id: query.ID, - addr: query.Addr, - port: query.Port, - deadline: time.Now().Add(query.Timeout), - } - } - return rebroadcast -} - -// handleResponse is called when a query response is -// received. -func (s *Serf) handleQueryResponse(resp *messageQueryResponse) { - // Look for a corresponding QueryResponse - s.queryLock.RLock() - query, ok := s.queryResponse[resp.LTime] - s.queryLock.RUnlock() - if !ok { - s.logger.Printf("[WARN] serf: reply for non-running query (LTime: %d, ID: %d) From: %s", - resp.LTime, resp.ID, resp.From) - return - } - - // Verify the ID matches - if query.id != resp.ID { - s.logger.Printf("[WARN] serf: query reply ID mismatch (Local: %d, Response: %d)", - query.id, resp.ID) - return - } - - // Check if the query is closed - if query.Finished() { - return - } - - // Process each type of response - if resp.Ack() { - metrics.IncrCounter([]string{"serf", "query_acks"}, 1) - select { - case query.ackCh <- resp.From: - default: - s.logger.Printf("[WARN] serf: Failed to delivery query ack, dropping") - } - } else { - metrics.IncrCounter([]string{"serf", "query_responses"}, 1) - select { - case query.respCh <- NodeResponse{From: resp.From, Payload: resp.Payload}: - default: - s.logger.Printf("[WARN] serf: Failed to delivery query response, dropping") - } - } -} - -// handleNodeConflict is invoked when a join detects a conflict over a name. -// This means two different nodes (IP/Port) are claiming the same name. Memberlist -// will reject the "new" node mapping, but we can still be notified -func (s *Serf) handleNodeConflict(existing, other *memberlist.Node) { - // Log a basic warning if the node is not us... - if existing.Name != s.config.NodeName { - s.logger.Printf("[WARN] serf: Name conflict for '%s' both %s:%d and %s:%d are claiming", - existing.Name, existing.Addr, existing.Port, other.Addr, other.Port) - return - } - - // The current node is conflicting! This is an error - s.logger.Printf("[ERR] serf: Node name conflicts with another node at %s:%d. Names must be unique! (Resolution enabled: %v)", - other.Addr, other.Port, s.config.EnableNameConflictResolution) - - // If automatic resolution is enabled, kick off the resolution - if s.config.EnableNameConflictResolution { - go s.resolveNodeConflict() - } -} - -// resolveNodeConflict is used to determine which node should remain during -// a name conflict. This is done by running an internal query. -func (s *Serf) resolveNodeConflict() { - // Get the local node - local := s.memberlist.LocalNode() - - // Start a name resolution query - qName := internalQueryName(conflictQuery) - payload := []byte(s.config.NodeName) - resp, err := s.Query(qName, payload, nil) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to start name resolution query: %v", err) - return - } - - // Counter to determine winner - var responses, matching int - - // Gather responses - respCh := resp.ResponseCh() - for r := range respCh { - // Decode the response - if len(r.Payload) < 1 || messageType(r.Payload[0]) != messageConflictResponseType { - s.logger.Printf("[ERR] serf: Invalid conflict query response type: %v", r.Payload) - continue - } - var member Member - if err := decodeMessage(r.Payload[1:], &member); err != nil { - s.logger.Printf("[ERR] serf: Failed to decode conflict query response: %v", err) - continue - } - - // Update the counters - responses++ - if bytes.Equal(member.Addr, local.Addr) && member.Port == local.Port { - matching++ - } - } - - // Query over, determine if we should live - majority := (responses / 2) + 1 - if matching >= majority { - s.logger.Printf("[INFO] serf: majority in name conflict resolution [%d / %d]", - matching, responses) - return - } - - // Since we lost the vote, we need to exit - s.logger.Printf("[WARN] serf: minority in name conflict resolution, quiting [%d / %d]", - matching, responses) - if err := s.Shutdown(); err != nil { - s.logger.Printf("[ERR] serf: Failed to shutdown: %v", err) - } -} - -// handleReap periodically reaps the list of failed and left members. -func (s *Serf) handleReap() { - for { - select { - case <-time.After(s.config.ReapInterval): - s.memberLock.Lock() - s.failedMembers = s.reap(s.failedMembers, s.config.ReconnectTimeout) - s.leftMembers = s.reap(s.leftMembers, s.config.TombstoneTimeout) - s.memberLock.Unlock() - case <-s.shutdownCh: - return - } - } -} - -// handleReconnect attempts to reconnect to recently failed nodes -// on configured intervals. -func (s *Serf) handleReconnect() { - for { - select { - case <-time.After(s.config.ReconnectInterval): - s.reconnect() - case <-s.shutdownCh: - return - } - } -} - -// reap is called with a list of old members and a timeout, and removes -// members that have exceeded the timeout. The members are removed from -// both the old list and the members itself. Locking is left to the caller. -func (s *Serf) reap(old []*memberState, timeout time.Duration) []*memberState { - now := time.Now() - n := len(old) - for i := 0; i < n; i++ { - m := old[i] - - // Skip if the timeout is not yet reached - if now.Sub(m.leaveTime) <= timeout { - continue - } - - // Delete from the list - old[i], old[n-1] = old[n-1], nil - old = old[:n-1] - n-- - i-- - - // Delete from members - delete(s.members, m.Name) - - // Tell the coordinate client the node has gone away and delete - // its cached coordinates. - if !s.config.DisableCoordinates { - s.coordClient.ForgetNode(m.Name) - - s.coordCacheLock.Lock() - delete(s.coordCache, m.Name) - s.coordCacheLock.Unlock() - } - - // Send an event along - s.logger.Printf("[INFO] serf: EventMemberReap: %s", m.Name) - if s.config.EventCh != nil { - s.config.EventCh <- MemberEvent{ - Type: EventMemberReap, - Members: []Member{m.Member}, - } - } - } - - return old -} - -// reconnect attempts to reconnect to recently fail nodes. -func (s *Serf) reconnect() { - s.memberLock.RLock() - - // Nothing to do if there are no failed members - n := len(s.failedMembers) - if n == 0 { - s.memberLock.RUnlock() - return - } - - // Probability we should attempt to reconect is given - // by num failed / (num members - num failed - num left) - // This means that we probabilistically expect the cluster - // to attempt to connect to each failed member once per - // reconnect interval - numFailed := float32(len(s.failedMembers)) - numAlive := float32(len(s.members) - len(s.failedMembers) - len(s.leftMembers)) - if numAlive == 0 { - numAlive = 1 // guard against zero divide - } - prob := numFailed / numAlive - if rand.Float32() > prob { - s.memberLock.RUnlock() - s.logger.Printf("[DEBUG] serf: forgoing reconnect for random throttling") - return - } - - // Select a random member to try and join - idx := int(rand.Uint32() % uint32(n)) - mem := s.failedMembers[idx] - s.memberLock.RUnlock() - - // Format the addr - addr := net.UDPAddr{IP: mem.Addr, Port: int(mem.Port)} - s.logger.Printf("[INFO] serf: attempting reconnect to %v %s", mem.Name, addr.String()) - - // Attempt to join at the memberlist level - s.memberlist.Join([]string{addr.String()}) -} - -// checkQueueDepth periodically checks the size of a queue to see if -// it is too large -func (s *Serf) checkQueueDepth(name string, queue *memberlist.TransmitLimitedQueue) { - for { - select { - case <-time.After(time.Second): - numq := queue.NumQueued() - metrics.AddSample([]string{"serf", "queue", name}, float32(numq)) - if numq >= s.config.QueueDepthWarning { - s.logger.Printf("[WARN] serf: %s queue depth: %d", name, numq) - } - if numq > s.config.MaxQueueDepth { - s.logger.Printf("[WARN] serf: %s queue depth (%d) exceeds limit (%d), dropping messages!", - name, numq, s.config.MaxQueueDepth) - queue.Prune(s.config.MaxQueueDepth) - } - case <-s.shutdownCh: - return - } - } -} - -// removeOldMember is used to remove an old member from a list of old -// members. -func removeOldMember(old []*memberState, name string) []*memberState { - for i, m := range old { - if m.Name == name { - n := len(old) - old[i], old[n-1] = old[n-1], nil - return old[:n-1] - } - } - - return old -} - -// recentIntent checks the recent intent buffer for a matching -// entry for a given node, and either returns the message or nil -func recentIntent(recent []nodeIntent, node string) (intent *nodeIntent) { - for i := 0; i < len(recent); i++ { - // Break fast if we hit a zero entry - if recent[i].LTime == 0 { - break - } - - // Check for a node match - if recent[i].Node == node { - // Take the most recent entry - if intent == nil || recent[i].LTime > intent.LTime { - intent = &recent[i] - } - } - } - return -} - -// handleRejoin attempts to reconnect to previously known alive nodes -func (s *Serf) handleRejoin(previous []*PreviousNode) { - for _, prev := range previous { - // Do not attempt to join ourself - if prev.Name == s.config.NodeName { - continue - } - - s.logger.Printf("[INFO] serf: Attempting re-join to previously known node: %s", prev) - _, err := s.memberlist.Join([]string{prev.Addr}) - if err == nil { - s.logger.Printf("[INFO] serf: Re-joined to previously known node: %s", prev) - return - } - } - s.logger.Printf("[WARN] serf: Failed to re-join any previously known node") -} - -// encodeTags is used to encode a tag map -func (s *Serf) encodeTags(tags map[string]string) []byte { - // Support role-only backwards compatibility - if s.ProtocolVersion() < 3 { - role := tags["role"] - return []byte(role) - } - - // Use a magic byte prefix and msgpack encode the tags - var buf bytes.Buffer - buf.WriteByte(tagMagicByte) - enc := codec.NewEncoder(&buf, &codec.MsgpackHandle{}) - if err := enc.Encode(tags); err != nil { - panic(fmt.Sprintf("Failed to encode tags: %v", err)) - } - return buf.Bytes() -} - -// decodeTags is used to decode a tag map -func (s *Serf) decodeTags(buf []byte) map[string]string { - tags := make(map[string]string) - - // Backwards compatibility mode - if len(buf) == 0 || buf[0] != tagMagicByte { - tags["role"] = string(buf) - return tags - } - - // Decode the tags - r := bytes.NewReader(buf[1:]) - dec := codec.NewDecoder(r, &codec.MsgpackHandle{}) - if err := dec.Decode(&tags); err != nil { - s.logger.Printf("[ERR] serf: Failed to decode tags: %v", err) - } - return tags -} - -// Stats is used to provide operator debugging information -func (s *Serf) Stats() map[string]string { - toString := func(v uint64) string { - return strconv.FormatUint(v, 10) - } - stats := map[string]string{ - "members": toString(uint64(len(s.members))), - "failed": toString(uint64(len(s.failedMembers))), - "left": toString(uint64(len(s.leftMembers))), - "health_score": toString(uint64(s.memberlist.GetHealthScore())), - "member_time": toString(uint64(s.clock.Time())), - "event_time": toString(uint64(s.eventClock.Time())), - "query_time": toString(uint64(s.queryClock.Time())), - "intent_queue": toString(uint64(s.broadcasts.NumQueued())), - "event_queue": toString(uint64(s.eventBroadcasts.NumQueued())), - "query_queue": toString(uint64(s.queryBroadcasts.NumQueued())), - "encrypted": fmt.Sprintf("%v", s.EncryptionEnabled()), - } - return stats -} - -// WriteKeyringFile will serialize the current keyring and save it to a file. -func (s *Serf) writeKeyringFile() error { - if len(s.config.KeyringFile) == 0 { - return nil - } - - keyring := s.config.MemberlistConfig.Keyring - keysRaw := keyring.GetKeys() - keysEncoded := make([]string, len(keysRaw)) - - for i, key := range keysRaw { - keysEncoded[i] = base64.StdEncoding.EncodeToString(key) - } - - encodedKeys, err := json.MarshalIndent(keysEncoded, "", " ") - if err != nil { - return fmt.Errorf("Failed to encode keys: %s", err) - } - - // Use 0600 for permissions because key data is sensitive - if err = ioutil.WriteFile(s.config.KeyringFile, encodedKeys, 0600); err != nil { - return fmt.Errorf("Failed to write keyring file: %s", err) - } - - // Success! - return nil -} - -// GetCoordinate returns the network coordinate of the local node. -func (s *Serf) GetCoordinate() (*coordinate.Coordinate, error) { - if !s.config.DisableCoordinates { - return s.coordClient.GetCoordinate(), nil - } - - return nil, fmt.Errorf("Coordinates are disabled") -} - -// GetCachedCoordinate returns the network coordinate for the node with the given -// name. This will only be valid if DisableCoordinates is set to false. -func (s *Serf) GetCachedCoordinate(name string) (coord *coordinate.Coordinate, ok bool) { - if !s.config.DisableCoordinates { - s.coordCacheLock.RLock() - defer s.coordCacheLock.RUnlock() - if coord, ok = s.coordCache[name]; ok { - return coord, true - } - - return nil, false - } - - return nil, false -} - -// NumNodes returns the number of nodes in the serf cluster, regardless of -// their health or status. -func (s *Serf) NumNodes() (numNodes int) { - s.memberLock.RLock() - numNodes = len(s.members) - s.memberLock.RUnlock() - - return numNodes -} diff --git a/vendor/github.com/hashicorp/serf/serf/snapshot.go b/vendor/github.com/hashicorp/serf/serf/snapshot.go deleted file mode 100644 index 44f8a5175..000000000 --- a/vendor/github.com/hashicorp/serf/serf/snapshot.go +++ /dev/null @@ -1,560 +0,0 @@ -package serf - -import ( - "bufio" - "encoding/json" - "fmt" - "log" - "math/rand" - "net" - "os" - "strconv" - "strings" - "time" - - "github.com/armon/go-metrics" - "github.com/hashicorp/serf/coordinate" -) - -/* -Serf supports using a "snapshot" file that contains various -transactional data that is used to help Serf recover quickly -and gracefully from a failure. We append member events, as well -as the latest clock values to the file during normal operation, -and periodically checkpoint and roll over the file. During a restore, -we can replay the various member events to recall a list of known -nodes to re-join, as well as restore our clock values to avoid replaying -old events. -*/ - -const flushInterval = 500 * time.Millisecond -const clockUpdateInterval = 500 * time.Millisecond -const coordinateUpdateInterval = 60 * time.Second -const tmpExt = ".compact" - -// Snapshotter is responsible for ingesting events and persisting -// them to disk, and providing a recovery mechanism at start time. -type Snapshotter struct { - aliveNodes map[string]string - clock *LamportClock - coordClient *coordinate.Client - fh *os.File - buffered *bufio.Writer - inCh <-chan Event - lastFlush time.Time - lastClock LamportTime - lastEventClock LamportTime - lastQueryClock LamportTime - leaveCh chan struct{} - leaving bool - logger *log.Logger - maxSize int64 - path string - offset int64 - outCh chan<- Event - rejoinAfterLeave bool - shutdownCh <-chan struct{} - waitCh chan struct{} -} - -// PreviousNode is used to represent the previously known alive nodes -type PreviousNode struct { - Name string - Addr string -} - -func (p PreviousNode) String() string { - return fmt.Sprintf("%s: %s", p.Name, p.Addr) -} - -// NewSnapshotter creates a new Snapshotter that records events up to a -// max byte size before rotating the file. It can also be used to -// recover old state. Snapshotter works by reading an event channel it returns, -// passing through to an output channel, and persisting relevant events to disk. -// Setting rejoinAfterLeave makes leave not clear the state, and can be used -// if you intend to rejoin the same cluster after a leave. -func NewSnapshotter(path string, - maxSize int, - rejoinAfterLeave bool, - logger *log.Logger, - clock *LamportClock, - coordClient *coordinate.Client, - outCh chan<- Event, - shutdownCh <-chan struct{}) (chan<- Event, *Snapshotter, error) { - inCh := make(chan Event, 1024) - - // Try to open the file - fh, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755) - if err != nil { - return nil, nil, fmt.Errorf("failed to open snapshot: %v", err) - } - - // Determine the offset - info, err := fh.Stat() - if err != nil { - fh.Close() - return nil, nil, fmt.Errorf("failed to stat snapshot: %v", err) - } - offset := info.Size() - - // Create the snapshotter - snap := &Snapshotter{ - aliveNodes: make(map[string]string), - clock: clock, - coordClient: coordClient, - fh: fh, - buffered: bufio.NewWriter(fh), - inCh: inCh, - lastClock: 0, - lastEventClock: 0, - lastQueryClock: 0, - leaveCh: make(chan struct{}), - logger: logger, - maxSize: int64(maxSize), - path: path, - offset: offset, - outCh: outCh, - rejoinAfterLeave: rejoinAfterLeave, - shutdownCh: shutdownCh, - waitCh: make(chan struct{}), - } - - // Recover the last known state - if err := snap.replay(); err != nil { - fh.Close() - return nil, nil, err - } - - // Start handling new commands - go snap.stream() - return inCh, snap, nil -} - -// LastClock returns the last known clock time -func (s *Snapshotter) LastClock() LamportTime { - return s.lastClock -} - -// LastEventClock returns the last known event clock time -func (s *Snapshotter) LastEventClock() LamportTime { - return s.lastEventClock -} - -// LastQueryClock returns the last known query clock time -func (s *Snapshotter) LastQueryClock() LamportTime { - return s.lastQueryClock -} - -// AliveNodes returns the last known alive nodes -func (s *Snapshotter) AliveNodes() []*PreviousNode { - // Copy the previously known - previous := make([]*PreviousNode, 0, len(s.aliveNodes)) - for name, addr := range s.aliveNodes { - previous = append(previous, &PreviousNode{name, addr}) - } - - // Randomize the order, prevents hot shards - for i := range previous { - j := rand.Intn(i + 1) - previous[i], previous[j] = previous[j], previous[i] - } - return previous -} - -// Wait is used to wait until the snapshotter finishes shut down -func (s *Snapshotter) Wait() { - <-s.waitCh -} - -// Leave is used to remove known nodes to prevent a restart from -// causing a join. Otherwise nodes will re-join after leaving! -func (s *Snapshotter) Leave() { - select { - case s.leaveCh <- struct{}{}: - case <-s.shutdownCh: - } -} - -// stream is a long running routine that is used to handle events -func (s *Snapshotter) stream() { - clockTicker := time.NewTicker(clockUpdateInterval) - defer clockTicker.Stop() - - coordinateTicker := time.NewTicker(coordinateUpdateInterval) - defer coordinateTicker.Stop() - - for { - select { - case <-s.leaveCh: - s.leaving = true - - // If we plan to re-join, keep our state - if !s.rejoinAfterLeave { - s.aliveNodes = make(map[string]string) - } - s.tryAppend("leave\n") - if err := s.buffered.Flush(); err != nil { - s.logger.Printf("[ERR] serf: failed to flush leave to snapshot: %v", err) - } - if err := s.fh.Sync(); err != nil { - s.logger.Printf("[ERR] serf: failed to sync leave to snapshot: %v", err) - } - - case e := <-s.inCh: - // Forward the event immediately - if s.outCh != nil { - s.outCh <- e - } - - // Stop recording events after a leave is issued - if s.leaving { - continue - } - switch typed := e.(type) { - case MemberEvent: - s.processMemberEvent(typed) - case UserEvent: - s.processUserEvent(typed) - case *Query: - s.processQuery(typed) - default: - s.logger.Printf("[ERR] serf: Unknown event to snapshot: %#v", e) - } - - case <-clockTicker.C: - s.updateClock() - - case <-coordinateTicker.C: - s.updateCoordinate() - - case <-s.shutdownCh: - if err := s.buffered.Flush(); err != nil { - s.logger.Printf("[ERR] serf: failed to flush snapshot: %v", err) - } - if err := s.fh.Sync(); err != nil { - s.logger.Printf("[ERR] serf: failed to sync snapshot: %v", err) - } - s.fh.Close() - close(s.waitCh) - return - } - } -} - -// processMemberEvent is used to handle a single member event -func (s *Snapshotter) processMemberEvent(e MemberEvent) { - switch e.Type { - case EventMemberJoin: - for _, mem := range e.Members { - addr := net.TCPAddr{IP: mem.Addr, Port: int(mem.Port)} - s.aliveNodes[mem.Name] = addr.String() - s.tryAppend(fmt.Sprintf("alive: %s %s\n", mem.Name, addr.String())) - } - - case EventMemberLeave: - fallthrough - case EventMemberFailed: - for _, mem := range e.Members { - delete(s.aliveNodes, mem.Name) - s.tryAppend(fmt.Sprintf("not-alive: %s\n", mem.Name)) - } - } - s.updateClock() -} - -// updateClock is called periodically to check if we should udpate our -// clock value. This is done after member events but should also be done -// periodically due to race conditions with join and leave intents -func (s *Snapshotter) updateClock() { - lastSeen := s.clock.Time() - 1 - if lastSeen > s.lastClock { - s.lastClock = lastSeen - s.tryAppend(fmt.Sprintf("clock: %d\n", s.lastClock)) - } -} - -// updateCoordinate is called periodically to write out the current local -// coordinate. It's safe to call this if coordinates aren't enabled (nil -// client) and it will be a no-op. -func (s *Snapshotter) updateCoordinate() { - if s.coordClient != nil { - encoded, err := json.Marshal(s.coordClient.GetCoordinate()) - if err != nil { - s.logger.Printf("[ERR] serf: Failed to encode coordinate: %v", err) - } else { - s.tryAppend(fmt.Sprintf("coordinate: %s\n", encoded)) - } - } -} - -// processUserEvent is used to handle a single user event -func (s *Snapshotter) processUserEvent(e UserEvent) { - // Ignore old clocks - if e.LTime <= s.lastEventClock { - return - } - s.lastEventClock = e.LTime - s.tryAppend(fmt.Sprintf("event-clock: %d\n", e.LTime)) -} - -// processQuery is used to handle a single query event -func (s *Snapshotter) processQuery(q *Query) { - // Ignore old clocks - if q.LTime <= s.lastQueryClock { - return - } - s.lastQueryClock = q.LTime - s.tryAppend(fmt.Sprintf("query-clock: %d\n", q.LTime)) -} - -// tryAppend will invoke append line but will not return an error -func (s *Snapshotter) tryAppend(l string) { - if err := s.appendLine(l); err != nil { - s.logger.Printf("[ERR] serf: Failed to update snapshot: %v", err) - } -} - -// appendLine is used to append a line to the existing log -func (s *Snapshotter) appendLine(l string) error { - defer metrics.MeasureSince([]string{"serf", "snapshot", "appendLine"}, time.Now()) - - n, err := s.buffered.WriteString(l) - if err != nil { - return err - } - - // Check if we should flush - now := time.Now() - if now.Sub(s.lastFlush) > flushInterval { - s.lastFlush = now - if err := s.buffered.Flush(); err != nil { - return err - } - } - - // Check if a compaction is necessary - s.offset += int64(n) - if s.offset > s.maxSize { - return s.compact() - } - return nil -} - -// Compact is used to compact the snapshot once it is too large -func (s *Snapshotter) compact() error { - defer metrics.MeasureSince([]string{"serf", "snapshot", "compact"}, time.Now()) - - // Try to open the file to new fiel - newPath := s.path + tmpExt - fh, err := os.OpenFile(newPath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0755) - if err != nil { - return fmt.Errorf("failed to open new snapshot: %v", err) - } - - // Create a buffered writer - buf := bufio.NewWriter(fh) - - // Write out the live nodes - var offset int64 - for name, addr := range s.aliveNodes { - line := fmt.Sprintf("alive: %s %s\n", name, addr) - n, err := buf.WriteString(line) - if err != nil { - fh.Close() - return err - } - offset += int64(n) - } - - // Write out the clocks - line := fmt.Sprintf("clock: %d\n", s.lastClock) - n, err := buf.WriteString(line) - if err != nil { - fh.Close() - return err - } - offset += int64(n) - - line = fmt.Sprintf("event-clock: %d\n", s.lastEventClock) - n, err = buf.WriteString(line) - if err != nil { - fh.Close() - return err - } - offset += int64(n) - - line = fmt.Sprintf("query-clock: %d\n", s.lastQueryClock) - n, err = buf.WriteString(line) - if err != nil { - fh.Close() - return err - } - offset += int64(n) - - // Write out the coordinate. - if s.coordClient != nil { - encoded, err := json.Marshal(s.coordClient.GetCoordinate()) - if err != nil { - fh.Close() - return err - } - - line = fmt.Sprintf("coordinate: %s\n", encoded) - n, err = buf.WriteString(line) - if err != nil { - fh.Close() - return err - } - offset += int64(n) - } - - // Flush the new snapshot - err = buf.Flush() - fh.Close() - if err != nil { - return fmt.Errorf("failed to flush new snapshot: %v", err) - } - - // We now need to swap the old snapshot file with the new snapshot. - // Turns out, Windows won't let us rename the files if we have - // open handles to them or if the destination already exists. This - // means we are forced to close the existing handles, delete the - // old file, move the new one in place, and then re-open the file - // handles. - - // Flush the existing snapshot, ignoring errors since we will - // delete it momentarily. - s.buffered.Flush() - s.buffered = nil - - // Close the file handle to the old snapshot - s.fh.Close() - s.fh = nil - - // Delete the old file - if err := os.Remove(s.path); err != nil { - return fmt.Errorf("failed to remove old snapshot: %v", err) - } - - // Move the new file into place - if err := os.Rename(newPath, s.path); err != nil { - return fmt.Errorf("failed to install new snapshot: %v", err) - } - - // Open the new snapshot - fh, err = os.OpenFile(s.path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755) - if err != nil { - return fmt.Errorf("failed to open snapshot: %v", err) - } - buf = bufio.NewWriter(fh) - - // Rotate our handles - s.fh = fh - s.buffered = buf - s.offset = offset - s.lastFlush = time.Now() - return nil -} - -// replay is used to seek to reset our internal state by replaying -// the snapshot file. It is used at initialization time to read old -// state -func (s *Snapshotter) replay() error { - // Seek to the beginning - if _, err := s.fh.Seek(0, os.SEEK_SET); err != nil { - return err - } - - // Read each line - reader := bufio.NewReader(s.fh) - for { - line, err := reader.ReadString('\n') - if err != nil { - break - } - - // Skip the newline - line = line[:len(line)-1] - - // Switch on the prefix - if strings.HasPrefix(line, "alive: ") { - info := strings.TrimPrefix(line, "alive: ") - addrIdx := strings.LastIndex(info, " ") - if addrIdx == -1 { - s.logger.Printf("[WARN] serf: Failed to parse address: %v", line) - continue - } - addr := info[addrIdx+1:] - name := info[:addrIdx] - s.aliveNodes[name] = addr - - } else if strings.HasPrefix(line, "not-alive: ") { - name := strings.TrimPrefix(line, "not-alive: ") - delete(s.aliveNodes, name) - - } else if strings.HasPrefix(line, "clock: ") { - timeStr := strings.TrimPrefix(line, "clock: ") - timeInt, err := strconv.ParseUint(timeStr, 10, 64) - if err != nil { - s.logger.Printf("[WARN] serf: Failed to convert clock time: %v", err) - continue - } - s.lastClock = LamportTime(timeInt) - - } else if strings.HasPrefix(line, "event-clock: ") { - timeStr := strings.TrimPrefix(line, "event-clock: ") - timeInt, err := strconv.ParseUint(timeStr, 10, 64) - if err != nil { - s.logger.Printf("[WARN] serf: Failed to convert event clock time: %v", err) - continue - } - s.lastEventClock = LamportTime(timeInt) - - } else if strings.HasPrefix(line, "query-clock: ") { - timeStr := strings.TrimPrefix(line, "query-clock: ") - timeInt, err := strconv.ParseUint(timeStr, 10, 64) - if err != nil { - s.logger.Printf("[WARN] serf: Failed to convert query clock time: %v", err) - continue - } - s.lastQueryClock = LamportTime(timeInt) - - } else if strings.HasPrefix(line, "coordinate: ") { - if s.coordClient == nil { - s.logger.Printf("[WARN] serf: Ignoring snapshot coordinates since they are disabled") - continue - } - - coordStr := strings.TrimPrefix(line, "coordinate: ") - var coord coordinate.Coordinate - err := json.Unmarshal([]byte(coordStr), &coord) - if err != nil { - s.logger.Printf("[WARN] serf: Failed to decode coordinate: %v", err) - continue - } - s.coordClient.SetCoordinate(&coord) - } else if line == "leave" { - // Ignore a leave if we plan on re-joining - if s.rejoinAfterLeave { - s.logger.Printf("[INFO] serf: Ignoring previous leave in snapshot") - continue - } - s.aliveNodes = make(map[string]string) - s.lastClock = 0 - s.lastEventClock = 0 - s.lastQueryClock = 0 - - } else if strings.HasPrefix(line, "#") { - // Skip comment lines - - } else { - s.logger.Printf("[WARN] serf: Unrecognized snapshot line: %v", line) - } - } - - // Seek to the end - if _, err := s.fh.Seek(0, os.SEEK_END); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/hashicorp/serf/version.go b/vendor/github.com/hashicorp/serf/version.go deleted file mode 100644 index a288b9d0d..000000000 --- a/vendor/github.com/hashicorp/serf/version.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -// The git commit that was compiled. This will be filled in by the compiler. -var GitCommit string - -// The main version number that is being run at the moment. -const Version = "0.7.0" - -// A pre-release marker for the version. If this is "" (empty string) -// then it means that it is a final release. Otherwise, this is a pre-release -// such as "dev" (in development), "beta", "rc1", etc. -const VersionPrerelease = "" diff --git a/vendor/github.com/mattn/go-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE new file mode 100644 index 000000000..91b5cef30 --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go new file mode 100644 index 000000000..a7fe19a8c --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -0,0 +1,27 @@ +// +build !windows + +package colorable + +import ( + "io" + "os" +) + +// NewColorable return new instance of Writer which handle escape sequence. +func NewColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + return file +} + +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. +func NewColorableStdout() io.Writer { + return os.Stdout +} + +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. +func NewColorableStderr() io.Writer { + return os.Stderr +} diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go new file mode 100644 index 000000000..628ad904e --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -0,0 +1,820 @@ +package colorable + +import ( + "bytes" + "io" + "math" + "os" + "strconv" + "strings" + "syscall" + "unsafe" + + "github.com/mattn/go-isatty" +) + +const ( + foregroundBlue = 0x1 + foregroundGreen = 0x2 + foregroundRed = 0x4 + foregroundIntensity = 0x8 + foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) + backgroundBlue = 0x10 + backgroundGreen = 0x20 + backgroundRed = 0x40 + backgroundIntensity = 0x80 + backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) +) + +type wchar uint16 +type short int16 +type dword uint32 +type word uint16 + +type coord struct { + x short + y short +} + +type smallRect struct { + left short + top short + right short + bottom short +} + +type consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord +} + +type consoleCursorInfo struct { + size dword + visible int32 +} + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") + procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") + procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") + procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") +) + +type Writer struct { + out io.Writer + handle syscall.Handle + lastbuf bytes.Buffer + oldattr word + oldpos coord +} + +// NewColorable return new instance of Writer which handle escape sequence from File. +func NewColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + if isatty.IsTerminal(file.Fd()) { + var csbi consoleScreenBufferInfo + handle := syscall.Handle(file.Fd()) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} + } else { + return file + } +} + +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. +func NewColorableStdout() io.Writer { + return NewColorable(os.Stdout) +} + +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. +func NewColorableStderr() io.Writer { + return NewColorable(os.Stderr) +} + +var color256 = map[int]int{ + 0: 0x000000, + 1: 0x800000, + 2: 0x008000, + 3: 0x808000, + 4: 0x000080, + 5: 0x800080, + 6: 0x008080, + 7: 0xc0c0c0, + 8: 0x808080, + 9: 0xff0000, + 10: 0x00ff00, + 11: 0xffff00, + 12: 0x0000ff, + 13: 0xff00ff, + 14: 0x00ffff, + 15: 0xffffff, + 16: 0x000000, + 17: 0x00005f, + 18: 0x000087, + 19: 0x0000af, + 20: 0x0000d7, + 21: 0x0000ff, + 22: 0x005f00, + 23: 0x005f5f, + 24: 0x005f87, + 25: 0x005faf, + 26: 0x005fd7, + 27: 0x005fff, + 28: 0x008700, + 29: 0x00875f, + 30: 0x008787, + 31: 0x0087af, + 32: 0x0087d7, + 33: 0x0087ff, + 34: 0x00af00, + 35: 0x00af5f, + 36: 0x00af87, + 37: 0x00afaf, + 38: 0x00afd7, + 39: 0x00afff, + 40: 0x00d700, + 41: 0x00d75f, + 42: 0x00d787, + 43: 0x00d7af, + 44: 0x00d7d7, + 45: 0x00d7ff, + 46: 0x00ff00, + 47: 0x00ff5f, + 48: 0x00ff87, + 49: 0x00ffaf, + 50: 0x00ffd7, + 51: 0x00ffff, + 52: 0x5f0000, + 53: 0x5f005f, + 54: 0x5f0087, + 55: 0x5f00af, + 56: 0x5f00d7, + 57: 0x5f00ff, + 58: 0x5f5f00, + 59: 0x5f5f5f, + 60: 0x5f5f87, + 61: 0x5f5faf, + 62: 0x5f5fd7, + 63: 0x5f5fff, + 64: 0x5f8700, + 65: 0x5f875f, + 66: 0x5f8787, + 67: 0x5f87af, + 68: 0x5f87d7, + 69: 0x5f87ff, + 70: 0x5faf00, + 71: 0x5faf5f, + 72: 0x5faf87, + 73: 0x5fafaf, + 74: 0x5fafd7, + 75: 0x5fafff, + 76: 0x5fd700, + 77: 0x5fd75f, + 78: 0x5fd787, + 79: 0x5fd7af, + 80: 0x5fd7d7, + 81: 0x5fd7ff, + 82: 0x5fff00, + 83: 0x5fff5f, + 84: 0x5fff87, + 85: 0x5fffaf, + 86: 0x5fffd7, + 87: 0x5fffff, + 88: 0x870000, + 89: 0x87005f, + 90: 0x870087, + 91: 0x8700af, + 92: 0x8700d7, + 93: 0x8700ff, + 94: 0x875f00, + 95: 0x875f5f, + 96: 0x875f87, + 97: 0x875faf, + 98: 0x875fd7, + 99: 0x875fff, + 100: 0x878700, + 101: 0x87875f, + 102: 0x878787, + 103: 0x8787af, + 104: 0x8787d7, + 105: 0x8787ff, + 106: 0x87af00, + 107: 0x87af5f, + 108: 0x87af87, + 109: 0x87afaf, + 110: 0x87afd7, + 111: 0x87afff, + 112: 0x87d700, + 113: 0x87d75f, + 114: 0x87d787, + 115: 0x87d7af, + 116: 0x87d7d7, + 117: 0x87d7ff, + 118: 0x87ff00, + 119: 0x87ff5f, + 120: 0x87ff87, + 121: 0x87ffaf, + 122: 0x87ffd7, + 123: 0x87ffff, + 124: 0xaf0000, + 125: 0xaf005f, + 126: 0xaf0087, + 127: 0xaf00af, + 128: 0xaf00d7, + 129: 0xaf00ff, + 130: 0xaf5f00, + 131: 0xaf5f5f, + 132: 0xaf5f87, + 133: 0xaf5faf, + 134: 0xaf5fd7, + 135: 0xaf5fff, + 136: 0xaf8700, + 137: 0xaf875f, + 138: 0xaf8787, + 139: 0xaf87af, + 140: 0xaf87d7, + 141: 0xaf87ff, + 142: 0xafaf00, + 143: 0xafaf5f, + 144: 0xafaf87, + 145: 0xafafaf, + 146: 0xafafd7, + 147: 0xafafff, + 148: 0xafd700, + 149: 0xafd75f, + 150: 0xafd787, + 151: 0xafd7af, + 152: 0xafd7d7, + 153: 0xafd7ff, + 154: 0xafff00, + 155: 0xafff5f, + 156: 0xafff87, + 157: 0xafffaf, + 158: 0xafffd7, + 159: 0xafffff, + 160: 0xd70000, + 161: 0xd7005f, + 162: 0xd70087, + 163: 0xd700af, + 164: 0xd700d7, + 165: 0xd700ff, + 166: 0xd75f00, + 167: 0xd75f5f, + 168: 0xd75f87, + 169: 0xd75faf, + 170: 0xd75fd7, + 171: 0xd75fff, + 172: 0xd78700, + 173: 0xd7875f, + 174: 0xd78787, + 175: 0xd787af, + 176: 0xd787d7, + 177: 0xd787ff, + 178: 0xd7af00, + 179: 0xd7af5f, + 180: 0xd7af87, + 181: 0xd7afaf, + 182: 0xd7afd7, + 183: 0xd7afff, + 184: 0xd7d700, + 185: 0xd7d75f, + 186: 0xd7d787, + 187: 0xd7d7af, + 188: 0xd7d7d7, + 189: 0xd7d7ff, + 190: 0xd7ff00, + 191: 0xd7ff5f, + 192: 0xd7ff87, + 193: 0xd7ffaf, + 194: 0xd7ffd7, + 195: 0xd7ffff, + 196: 0xff0000, + 197: 0xff005f, + 198: 0xff0087, + 199: 0xff00af, + 200: 0xff00d7, + 201: 0xff00ff, + 202: 0xff5f00, + 203: 0xff5f5f, + 204: 0xff5f87, + 205: 0xff5faf, + 206: 0xff5fd7, + 207: 0xff5fff, + 208: 0xff8700, + 209: 0xff875f, + 210: 0xff8787, + 211: 0xff87af, + 212: 0xff87d7, + 213: 0xff87ff, + 214: 0xffaf00, + 215: 0xffaf5f, + 216: 0xffaf87, + 217: 0xffafaf, + 218: 0xffafd7, + 219: 0xffafff, + 220: 0xffd700, + 221: 0xffd75f, + 222: 0xffd787, + 223: 0xffd7af, + 224: 0xffd7d7, + 225: 0xffd7ff, + 226: 0xffff00, + 227: 0xffff5f, + 228: 0xffff87, + 229: 0xffffaf, + 230: 0xffffd7, + 231: 0xffffff, + 232: 0x080808, + 233: 0x121212, + 234: 0x1c1c1c, + 235: 0x262626, + 236: 0x303030, + 237: 0x3a3a3a, + 238: 0x444444, + 239: 0x4e4e4e, + 240: 0x585858, + 241: 0x626262, + 242: 0x6c6c6c, + 243: 0x767676, + 244: 0x808080, + 245: 0x8a8a8a, + 246: 0x949494, + 247: 0x9e9e9e, + 248: 0xa8a8a8, + 249: 0xb2b2b2, + 250: 0xbcbcbc, + 251: 0xc6c6c6, + 252: 0xd0d0d0, + 253: 0xdadada, + 254: 0xe4e4e4, + 255: 0xeeeeee, +} + +// Write write data on console +func (w *Writer) Write(data []byte) (n int, err error) { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + + er := bytes.NewReader(data) + var bw [1]byte +loop: + for { + r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if r1 == 0 { + break loop + } + + c1, err := er.ReadByte() + if err != nil { + break loop + } + if c1 != 0x1b { + bw[0] = c1 + w.out.Write(bw[:]) + continue + } + c2, err := er.ReadByte() + if err != nil { + w.lastbuf.WriteByte(c1) + break loop + } + if c2 != 0x5b { + w.lastbuf.WriteByte(c1) + w.lastbuf.WriteByte(c2) + continue + } + + var buf bytes.Buffer + var m byte + for { + c, err := er.ReadByte() + if err != nil { + w.lastbuf.WriteByte(c1) + w.lastbuf.WriteByte(c2) + w.lastbuf.Write(buf.Bytes()) + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + m = c + break + } + buf.Write([]byte(string(c))) + } + + var csbi consoleScreenBufferInfo + switch m { + case 'A': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'B': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'C': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'D': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + if n, err = strconv.Atoi(buf.String()); err == nil { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + } + case 'E': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'F': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'G': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = short(n - 1) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'H': + token := strings.Split(buf.String(), ";") + if len(token) != 2 { + continue + } + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + n2, err := strconv.Atoi(token[1]) + if err != nil { + continue + } + csbi.cursorPosition.x = short(n2 - 1) + csbi.cursorPosition.y = short(n1 - 1) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'J': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'K': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'm': + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + attr := csbi.attributes + cs := buf.String() + if cs == "" { + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + continue + } + token := strings.Split(cs, ";") + for i := 0; i < len(token); i++ { + ns := token[i] + if n, err = strconv.Atoi(ns); err == nil { + switch { + case n == 0 || n == 100: + attr = w.oldattr + case 1 <= n && n <= 5: + attr |= foregroundIntensity + case n == 7: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 22 == n || n == 25 || n == 25: + attr |= foregroundIntensity + case n == 27: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 30 <= n && n <= 37: + attr &= backgroundMask + if (n-30)&1 != 0 { + attr |= foregroundRed + } + if (n-30)&2 != 0 { + attr |= foregroundGreen + } + if (n-30)&4 != 0 { + attr |= foregroundBlue + } + case n == 38: // set foreground color. + if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256foreAttr == nil { + n256setup() + } + attr &= backgroundMask + attr |= n256foreAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & backgroundMask) + } + case n == 39: // reset foreground color. + attr &= backgroundMask + attr |= w.oldattr & foregroundMask + case 40 <= n && n <= 47: + attr &= foregroundMask + if (n-40)&1 != 0 { + attr |= backgroundRed + } + if (n-40)&2 != 0 { + attr |= backgroundGreen + } + if (n-40)&4 != 0 { + attr |= backgroundBlue + } + case n == 48: // set background color. + if i < len(token)-2 && token[i+1] == "5" { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256backAttr == nil { + n256setup() + } + attr &= foregroundMask + attr |= n256backAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & foregroundMask) + } + case n == 49: // reset foreground color. + attr &= foregroundMask + attr |= w.oldattr & backgroundMask + case 90 <= n && n <= 97: + attr = (attr & backgroundMask) + attr |= foregroundIntensity + if (n-90)&1 != 0 { + attr |= foregroundRed + } + if (n-90)&2 != 0 { + attr |= foregroundGreen + } + if (n-90)&4 != 0 { + attr |= foregroundBlue + } + case 100 <= n && n <= 107: + attr = (attr & foregroundMask) + attr |= backgroundIntensity + if (n-100)&1 != 0 { + attr |= backgroundRed + } + if (n-100)&2 != 0 { + attr |= backgroundGreen + } + if (n-100)&4 != 0 { + attr |= backgroundBlue + } + } + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + } + } + case 'h': + cs := buf.String() + if cs == "?25" { + var ci consoleCursorInfo + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 1 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } + case 'l': + cs := buf.String() + if cs == "?25" { + var ci consoleCursorInfo + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 0 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } + case 's': + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + w.oldpos = csbi.cursorPosition + case 'u': + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + } + } + return len(data) - w.lastbuf.Len(), nil +} + +type consoleColor struct { + rgb int + red bool + green bool + blue bool + intensity bool +} + +func (c consoleColor) foregroundAttr() (attr word) { + if c.red { + attr |= foregroundRed + } + if c.green { + attr |= foregroundGreen + } + if c.blue { + attr |= foregroundBlue + } + if c.intensity { + attr |= foregroundIntensity + } + return +} + +func (c consoleColor) backgroundAttr() (attr word) { + if c.red { + attr |= backgroundRed + } + if c.green { + attr |= backgroundGreen + } + if c.blue { + attr |= backgroundBlue + } + if c.intensity { + attr |= backgroundIntensity + } + return +} + +var color16 = []consoleColor{ + consoleColor{0x000000, false, false, false, false}, + consoleColor{0x000080, false, false, true, false}, + consoleColor{0x008000, false, true, false, false}, + consoleColor{0x008080, false, true, true, false}, + consoleColor{0x800000, true, false, false, false}, + consoleColor{0x800080, true, false, true, false}, + consoleColor{0x808000, true, true, false, false}, + consoleColor{0xc0c0c0, true, true, true, false}, + consoleColor{0x808080, false, false, false, true}, + consoleColor{0x0000ff, false, false, true, true}, + consoleColor{0x00ff00, false, true, false, true}, + consoleColor{0x00ffff, false, true, true, true}, + consoleColor{0xff0000, true, false, false, true}, + consoleColor{0xff00ff, true, false, true, true}, + consoleColor{0xffff00, true, true, false, true}, + consoleColor{0xffffff, true, true, true, true}, +} + +type hsv struct { + h, s, v float32 +} + +func (a hsv) dist(b hsv) float32 { + dh := a.h - b.h + switch { + case dh > 0.5: + dh = 1 - dh + case dh < -0.5: + dh = -1 - dh + } + ds := a.s - b.s + dv := a.v - b.v + return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) +} + +func toHSV(rgb int) hsv { + r, g, b := float32((rgb&0xFF0000)>>16)/256.0, + float32((rgb&0x00FF00)>>8)/256.0, + float32(rgb&0x0000FF)/256.0 + min, max := minmax3f(r, g, b) + h := max - min + if h > 0 { + if max == r { + h = (g - b) / h + if h < 0 { + h += 6 + } + } else if max == g { + h = 2 + (b-r)/h + } else { + h = 4 + (r-g)/h + } + } + h /= 6.0 + s := max - min + if max != 0 { + s /= max + } + v := max + return hsv{h: h, s: s, v: v} +} + +type hsvTable []hsv + +func toHSVTable(rgbTable []consoleColor) hsvTable { + t := make(hsvTable, len(rgbTable)) + for i, c := range rgbTable { + t[i] = toHSV(c.rgb) + } + return t +} + +func (t hsvTable) find(rgb int) consoleColor { + hsv := toHSV(rgb) + n := 7 + l := float32(5.0) + for i, p := range t { + d := hsv.dist(p) + if d < l { + l, n = d, i + } + } + return color16[n] +} + +func minmax3f(a, b, c float32) (min, max float32) { + if a < b { + if b < c { + return a, c + } else if a < c { + return a, b + } else { + return c, b + } + } else { + if a < c { + return b, c + } else if b < c { + return b, a + } else { + return c, a + } + } +} + +var n256foreAttr []word +var n256backAttr []word + +func n256setup() { + n256foreAttr = make([]word, 256) + n256backAttr = make([]word, 256) + t := toHSVTable(color16) + for i, rgb := range color256 { + c := t.find(rgb) + n256foreAttr[i] = c.foregroundAttr() + n256backAttr[i] = c.backgroundAttr() + } +} diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go new file mode 100644 index 000000000..ca588c78a --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -0,0 +1,61 @@ +package colorable + +import ( + "bytes" + "io" +) + +// NonColorable hold writer but remove escape sequence. +type NonColorable struct { + out io.Writer + lastbuf bytes.Buffer +} + +// NewNonColorable return new instance of Writer which remove escape sequence from Writer. +func NewNonColorable(w io.Writer) io.Writer { + return &NonColorable{out: w} +} + +// Write write data on console +func (w *NonColorable) Write(data []byte) (n int, err error) { + er := bytes.NewReader(data) + var bw [1]byte +loop: + for { + c1, err := er.ReadByte() + if err != nil { + break loop + } + if c1 != 0x1b { + bw[0] = c1 + w.out.Write(bw[:]) + continue + } + c2, err := er.ReadByte() + if err != nil { + w.lastbuf.WriteByte(c1) + break loop + } + if c2 != 0x5b { + w.lastbuf.WriteByte(c1) + w.lastbuf.WriteByte(c2) + continue + } + + var buf bytes.Buffer + for { + c, err := er.ReadByte() + if err != nil { + w.lastbuf.WriteByte(c1) + w.lastbuf.WriteByte(c2) + w.lastbuf.Write(buf.Bytes()) + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + break + } + buf.Write([]byte(string(c))) + } + } + return len(data) - w.lastbuf.Len(), nil +} diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 000000000..65dc692b6 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go new file mode 100644 index 000000000..17d4f90eb --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/doc.go @@ -0,0 +1,2 @@ +// Package isatty implements interface to isatty +package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go new file mode 100644 index 000000000..9584a9884 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_appengine.go @@ -0,0 +1,15 @@ +// +build appengine + +package isatty + +// IsTerminal returns true if the file descriptor is terminal which +// is always false on on appengine classic which is a sandboxed PaaS. +func IsTerminal(fd uintptr) bool { + return false +} + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go new file mode 100644 index 000000000..42f2514d1 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -0,0 +1,18 @@ +// +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TIOCGETA + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go new file mode 100644 index 000000000..9d24bac1d --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_linux.go @@ -0,0 +1,18 @@ +// +build linux +// +build !appengine + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TCGETS + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go new file mode 100644 index 000000000..ff4de3d9a --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -0,0 +1,10 @@ +// +build !windows +// +build !appengine + +package isatty + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go new file mode 100644 index 000000000..1f0c6bf53 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -0,0 +1,16 @@ +// +build solaris +// +build !appengine + +package isatty + +import ( + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +func IsTerminal(fd uintptr) bool { + var termio unix.Termio + err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) + return err == nil +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go new file mode 100644 index 000000000..af51cbcaa --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -0,0 +1,94 @@ +// +build windows +// +build !appengine + +package isatty + +import ( + "strings" + "syscall" + "unicode/utf16" + "unsafe" +) + +const ( + fileNameInfo uintptr = 2 + fileTypePipe = 3 +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx") + procGetFileType = kernel32.NewProc("GetFileType") +) + +func init() { + // Check if GetFileInformationByHandleEx is available. + if procGetFileInformationByHandleEx.Find() != nil { + procGetFileInformationByHandleEx = nil + } +} + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +// Check pipe name is used for cygwin/msys2 pty. +// Cygwin/MSYS2 PTY has a name like: +// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master +func isCygwinPipeName(name string) bool { + token := strings.Split(name, "-") + if len(token) < 5 { + return false + } + + if token[0] != `\msys` && token[0] != `\cygwin` { + return false + } + + if token[1] == "" { + return false + } + + if !strings.HasPrefix(token[2], "pty") { + return false + } + + if token[3] != `from` && token[3] != `to` { + return false + } + + if token[4] != "master" { + return false + } + + return true +} + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. +func IsCygwinTerminal(fd uintptr) bool { + if procGetFileInformationByHandleEx == nil { + return false + } + + // Cygwin/msys's pty is a pipe. + ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0) + if ft != fileTypePipe || e != 0 { + return false + } + + var buf [2 + syscall.MAX_PATH]uint16 + r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), + 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)), + uintptr(len(buf)*2), 0, 0) + if r == 0 || e != 0 { + return false + } + + l := *(*uint32)(unsafe.Pointer(&buf)) + return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2]))) +} diff --git a/vendor/github.com/mattn/go-shellwords/LICENSE b/vendor/github.com/mattn/go-shellwords/LICENSE new file mode 100644 index 000000000..740fa9313 --- /dev/null +++ b/vendor/github.com/mattn/go-shellwords/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/mattn/go-shellwords/shellwords.go b/vendor/github.com/mattn/go-shellwords/shellwords.go index 1abaa6c9d..107803927 100644 --- a/vendor/github.com/mattn/go-shellwords/shellwords.go +++ b/vendor/github.com/mattn/go-shellwords/shellwords.go @@ -4,7 +4,6 @@ import ( "errors" "os" "regexp" - "strings" ) var ( @@ -35,21 +34,24 @@ func replaceEnv(s string) string { type Parser struct { ParseEnv bool ParseBacktick bool + Position int } func NewParser() *Parser { - return &Parser{ParseEnv, ParseBacktick} + return &Parser{ParseEnv, ParseBacktick, 0} } func (p *Parser) Parse(line string) ([]string, error) { - line = strings.TrimSpace(line) - args := []string{} buf := "" var escaped, doubleQuoted, singleQuoted, backQuote bool backtick := "" - for _, r := range line { + pos := -1 + got := false + +loop: + for i, r := range line { if escaped { buf += string(r) escaped = false @@ -69,12 +71,13 @@ func (p *Parser) Parse(line string) ([]string, error) { if singleQuoted || doubleQuoted || backQuote { buf += string(r) backtick += string(r) - } else if buf != "" { + } else if got { if p.ParseEnv { buf = replaceEnv(buf) } args = append(args, buf) buf = "" + got = false } continue } @@ -107,15 +110,21 @@ func (p *Parser) Parse(line string) ([]string, error) { singleQuoted = !singleQuoted continue } + case ';', '&', '|', '<', '>': + if !(escaped || singleQuoted || doubleQuoted || backQuote) { + pos = i + break loop + } } + got = true buf += string(r) if backQuote { backtick += string(r) } } - if buf != "" { + if got { if p.ParseEnv { buf = replaceEnv(buf) } @@ -126,6 +135,8 @@ func (p *Parser) Parse(line string) ([]string, error) { return nil, errors.New("invalid command line string") } + p.Position = pos + return args, nil } diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE index 13f15dfce..8dada3eda 100644 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE @@ -178,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2013 Matt T. Proud + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE new file mode 100644 index 000000000..5d8cb5b72 --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE @@ -0,0 +1 @@ +Copyright 2012 Matt T. Proud (matt.proud@gmail.com) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go index 66d9b5458..258c0636a 100644 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go @@ -38,7 +38,7 @@ var errInvalidVarint = errors.New("invalid varint32 encountered") func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) { // Per AbstractParser#parsePartialDelimitedFrom with // CodedInputStream#readRawVarint32. - headerBuf := make([]byte, binary.MaxVarintLen32) + var headerBuf [binary.MaxVarintLen32]byte var bytesRead, varIntBytes int var messageLength uint64 for varIntBytes == 0 { // i.e. no varint has been decoded yet. diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go index 4b76ea9a1..8fb59ad22 100644 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go @@ -33,8 +33,8 @@ func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) { return 0, err } - buf := make([]byte, binary.MaxVarintLen32) - encodedLength := binary.PutUvarint(buf, uint64(len(buffer))) + var buf [binary.MaxVarintLen32]byte + encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer))) sync, err := w.Write(buf[:encodedLength]) if err != nil { diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go index b0ab89b63..6dee0ef0a 100644 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go @@ -1,5 +1,5 @@ // The mapstructure package exposes functionality to convert an -// abitrary map[string]interface{} into a native Go structure. +// arbitrary map[string]interface{} into a native Go structure. // // The Go structure can be arbitrarily complex, containing slices, // other structs, etc. and the decoder will properly decode nested @@ -69,6 +69,9 @@ type DecoderConfig struct { // - empty array = empty map and vice versa // - negative numbers to overflowed uint values (base 10) // - slice of maps to a merged map + // - single values are converted to slices if required. Each + // element is weakly decoded. For example: "4" can become []int{4} + // if the target type is an int slice. // WeaklyTypedInput bool @@ -202,7 +205,7 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error d.config.DecodeHook, dataVal.Type(), val.Type(), data) if err != nil { - return err + return fmt.Errorf("error decoding '%s': %s", name, err) } } @@ -229,6 +232,8 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error err = d.decodePtr(name, data, val) case reflect.Slice: err = d.decodeSlice(name, data, val) + case reflect.Func: + err = d.decodeFunc(name, data, val) default: // If we reached this point then we weren't able to decode it return fmt.Errorf("%s: unsupported type: %s", name, dataKind) @@ -546,7 +551,12 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er // into that. Then set the value of the pointer to this type. valType := val.Type() valElemType := valType.Elem() - realVal := reflect.New(valElemType) + + realVal := val + if realVal.IsNil() || d.config.ZeroFields { + realVal = reflect.New(valElemType) + } + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { return err } @@ -555,6 +565,19 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er return nil } +func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + dataVal := reflect.Indirect(reflect.ValueOf(data)) + if val.Type() != dataVal.Type() { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + val.Set(dataVal) + return nil +} + func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind() @@ -562,26 +585,44 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) valElemType := valType.Elem() sliceType := reflect.SliceOf(valElemType) - // Check input type - if dataValKind != reflect.Array && dataValKind != reflect.Slice { - // Accept empty map instead of array/slice in weakly typed mode - if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { - val.Set(reflect.MakeSlice(sliceType, 0, 0)) - return nil - } else { + valSlice := val + if valSlice.IsNil() || d.config.ZeroFields { + // Check input type + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + if d.config.WeaklyTypedInput { + switch { + // Empty maps turn into empty slices + case dataValKind == reflect.Map: + if dataVal.Len() == 0 { + val.Set(reflect.MakeSlice(sliceType, 0, 0)) + return nil + } + + // All other types we try to convert to the slice type + // and "lift" it into it. i.e. a string becomes a string slice. + default: + // Just re-try this function with data as a slice. + return d.decodeSlice(name, []interface{}{data}, val) + } + } + return fmt.Errorf( "'%s': source data must be an array or slice, got %s", name, dataValKind) - } - } - // Make a new slice to hold our result, same size as the original data. - valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + } + + // Make a new slice to hold our result, same size as the original data. + valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + } // Accumulate any errors errors := make([]string, 0) for i := 0; i < dataVal.Len(); i++ { currentData := dataVal.Index(i).Interface() + for valSlice.Len() <= i { + valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) + } currentField := valSlice.Index(i) fieldName := fmt.Sprintf("%s[%d]", name, i) diff --git a/vendor/github.com/mvdan/xurls/regex.go b/vendor/github.com/mvdan/xurls/regex.go index 2b4601eb7..c7f7d1023 100644 --- a/vendor/github.com/mvdan/xurls/regex.go +++ b/vendor/github.com/mvdan/xurls/regex.go @@ -3,6 +3,6 @@ package xurls const ( - gtld = `(?i)(aaa|aarp|abarth|abb|abbott|abbvie|abc|able|abogado|abudhabi|ac|academy|accenture|accountant|accountants|aco|active|actor|ad|adac|ads|adult|ae|aeg|aero|aetna|af|afamilycompany|afl|africa|ag|agakhan|agency|ai|aig|aigo|airbus|airforce|airtel|akdn|al|alfaromeo|alibaba|alipay|allfinanz|allstate|ally|alsace|alstom|am|americanexpress|americanfamily|amex|amfam|amica|amsterdam|analytics|android|anquan|anz|ao|aol|apartments|app|apple|aq|aquarelle|ar|arab|aramco|archi|army|arpa|art|arte|as|asda|asia|associates|at|athleta|attorney|au|auction|audi|audible|audio|auspost|author|auto|autos|avianca|aw|aws|ax|axa|az|azure|ba|baby|baidu|banamex|bananarepublic|band|bank|bar|barcelona|barclaycard|barclays|barefoot|bargains|baseball|basketball|bauhaus|bayern|bb|bbc|bbt|bbva|bcg|bcn|bd|be|beats|beauty|beer|bentley|berlin|best|bestbuy|bet|bf|bg|bh|bharti|bi|bible|bid|bike|bing|bingo|bio|bit|biz|bj|black|blackfriday|blanco|blockbuster|blog|bloomberg|blue|bm|bms|bmw|bn|bnl|bnpparibas|bo|boats|boehringer|bofa|bom|bond|boo|book|booking|boots|bosch|bostik|boston|bot|boutique|box|br|bradesco|bridgestone|broadway|broker|brother|brussels|bs|bt|budapest|bugatti|build|builders|business|buy|buzz|bv|bw|by|bz|bzh|ca|cab|cafe|cal|call|calvinklein|cam|camera|camp|cancerresearch|canon|capetown|capital|capitalone|car|caravan|cards|care|career|careers|cars|cartier|casa|case|caseih|cash|casino|cat|catering|catholic|cba|cbn|cbre|cbs|cc|cd|ceb|center|ceo|cern|cf|cfa|cfd|cg|ch|chanel|channel|chase|chat|cheap|chintai|chloe|christmas|chrome|chrysler|church|ci|cipriani|circle|cisco|citadel|citi|citic|city|cityeats|ck|cl|claims|cleaning|click|clinic|clinique|clothing|cloud|club|clubmed|cm|cn|co|coach|codes|coffee|college|cologne|com|comcast|commbank|community|company|compare|computer|comsec|condos|construction|consulting|contact|contractors|cooking|cookingchannel|cool|coop|corsica|country|coupon|coupons|courses|cr|credit|creditcard|creditunion|cricket|crown|crs|cruise|cruises|csc|cu|cuisinella|cv|cw|cx|cy|cymru|cyou|cz|dabur|dad|dance|data|date|dating|datsun|day|dclk|dds|de|deal|dealer|deals|degree|delivery|dell|deloitte|delta|democrat|dental|dentist|desi|design|dev|dhl|diamonds|diet|digital|direct|directory|discount|discover|dish|diy|dj|dk|dm|dnp|do|docs|doctor|dodge|dog|doha|domains|dot|download|drive|dtv|dubai|duck|dunlop|duns|dupont|durban|dvag|dvr|dwg|dz|earth|eat|ec|eco|edeka|edu|education|ee|eg|email|emerck|energy|engineer|engineering|enterprises|epost|epson|equipment|er|ericsson|erni|es|esq|estate|esurance|et|etisalat|eu|eurovision|eus|events|everbank|example|exchange|exit|expert|exposed|express|extraspace|fage|fail|fairwinds|faith|family|fan|fans|farm|farmers|fashion|fast|fedex|feedback|ferrari|ferrero|fi|fiat|fidelity|fido|film|final|finance|financial|fire|firestone|firmdale|fish|fishing|fit|fitness|fj|fk|flickr|flights|flir|florist|flowers|fly|fm|fo|foo|food|foodnetwork|football|ford|forex|forsale|forum|foundation|fox|fr|free|fresenius|frl|frogans|frontdoor|frontier|ftr|fujitsu|fujixerox|fun|fund|furniture|futbol|fyi|ga|gal|gallery|gallo|gallup|game|games|gap|garden|gb|gbiz|gd|gdn|ge|gea|gent|genting|george|gf|gg|ggee|gh|gi|gift|gifts|gives|giving|gl|glade|glass|gle|global|globo|gm|gmail|gmbh|gmo|gmx|gn|gnu|godaddy|gold|goldpoint|golf|goo|goodhands|goodyear|goog|google|gop|got|gov|gp|gq|gr|grainger|graphics|gratis|green|gripe|grocery|group|gs|gt|gu|guardian|gucci|guge|guide|guitars|guru|gw|gy|hair|hamburg|hangout|haus|hbo|hdfc|hdfcbank|health|healthcare|help|helsinki|here|hermes|hgtv|hiphop|hisamitsu|hitachi|hiv|hk|hkt|hm|hn|hockey|holdings|holiday|homedepot|homegoods|homes|homesense|honda|honeywell|horse|hospital|host|hosting|hot|hoteles|hotels|hotmail|house|how|hr|hsbc|ht|htc|hu|hughes|hyatt|hyundai|i2p|ibm|icbc|ice|icu|id|ie|ieee|ifm|iinet|ikano|il|im|imamat|imdb|immo|immobilien|in|industries|infiniti|info|ing|ink|institute|insurance|insure|int|intel|international|intuit|invalid|investments|io|ipiranga|iq|ir|irish|is|iselect|ismaili|ist|istanbul|it|itau|itv|iveco|iwc|jaguar|java|jcb|jcp|je|jeep|jetzt|jewelry|jio|jlc|jll|jm|jmp|jnj|jo|jobs|joburg|jot|joy|jp|jpmorgan|jprs|juegos|juniper|kaufen|kddi|ke|kerryhotels|kerrylogistics|kerryproperties|kfh|kg|kh|ki|kia|kim|kinder|kindle|kitchen|kiwi|km|kn|koeln|komatsu|kosher|kp|kpmg|kpn|kr|krd|kred|kuokgroup|kw|ky|kyoto|kz|la|lacaixa|ladbrokes|lamborghini|lamer|lancaster|lancia|lancome|land|landrover|lanxess|lasalle|lat|latino|latrobe|law|lawyer|lb|lc|lds|lease|leclerc|lefrak|legal|lego|lexus|lgbt|li|liaison|lidl|life|lifeinsurance|lifestyle|lighting|like|lilly|limited|limo|lincoln|linde|link|lipsy|live|living|lixil|lk|loan|loans|local|localhost|locker|locus|loft|lol|london|lotte|lotto|love|lpl|lplfinancial|lr|ls|lt|ltd|ltda|lu|lundbeck|lupin|luxe|luxury|lv|ly|ma|macys|madrid|maif|maison|makeup|man|management|mango|map|market|marketing|markets|marriott|marshalls|maserati|mattel|mba|mc|mcd|mcdonalds|mckinsey|md|me|med|media|meet|melbourne|meme|memorial|men|menu|meo|merckmsd|metlife|mg|mh|miami|microsoft|mil|mini|mint|mit|mitsubishi|mk|ml|mlb|mls|mm|mma|mn|mo|mobi|mobile|mobily|moda|moe|moi|mom|monash|money|monster|montblanc|mopar|mormon|mortgage|moscow|moto|motorcycles|mov|movie|movistar|mp|mq|mr|ms|msd|mt|mtn|mtpc|mtr|mu|museum|mutual|mutuelle|mv|mw|mx|my|mz|na|nab|nadex|nagoya|name|nationwide|natura|navy|nba|nc|ne|nec|net|netbank|netflix|network|neustar|new|newholland|news|next|nextdirect|nexus|nf|nfl|ng|ngo|nhk|ni|nico|nike|nikon|ninja|nissan|nissay|nl|no|nokia|northwesternmutual|norton|now|nowruz|nowtv|np|nr|nra|nrw|ntt|nu|nyc|nz|obi|observer|off|office|okinawa|olayan|olayangroup|oldnavy|ollo|om|omega|one|ong|onion|onl|online|onyourside|ooo|open|oracle|orange|org|organic|orientexpress|origins|osaka|otsuka|ott|ovh|pa|page|pamperedchef|panasonic|panerai|paris|pars|partners|parts|party|passagens|pay|pccw|pe|pet|pf|pfizer|pg|ph|pharmacy|phd|philips|phone|photo|photography|photos|physio|piaget|pics|pictet|pictures|pid|pin|ping|pink|pioneer|pizza|pk|pl|place|play|playstation|plumbing|plus|pm|pn|pnc|pohl|poker|politie|porn|post|pr|pramerica|praxi|press|prime|pro|prod|productions|prof|progressive|promo|properties|property|protection|pru|prudential|ps|pt|pub|pw|pwc|py|qa|qpon|quebec|quest|qvc|racing|radio|raid|re|read|realestate|realtor|realty|recipes|red|redstone|redumbrella|rehab|reise|reisen|reit|reliance|ren|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rexroth|rich|richardli|ricoh|rightathome|ril|rio|rip|rmit|ro|rocher|rocks|rodeo|rogers|room|rs|rsvp|ru|ruhr|run|rw|rwe|ryukyu|sa|saarland|safe|safety|sakura|sale|salon|samsclub|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|sas|save|saxo|sb|sbi|sbs|sc|sca|scb|schaeffler|schmidt|scholarships|school|schule|schwarz|science|scjohnson|scor|scot|sd|se|search|seat|secure|security|seek|select|sener|services|ses|seven|sew|sex|sexy|sfr|sg|sh|shangrila|sharp|shaw|shell|shia|shiksha|shoes|shop|shopping|shouji|show|showtime|shriram|si|silk|sina|singles|site|sj|sk|ski|skin|sky|skype|sl|sling|sm|smart|smile|sn|sncf|so|soccer|social|softbank|software|sohu|solar|solutions|song|sony|soy|space|spiegel|spot|spreadbetting|sr|srl|srt|st|stada|staples|star|starhub|statebank|statefarm|statoil|stc|stcgroup|stockholm|storage|store|stream|studio|study|style|su|sucks|supplies|supply|support|surf|surgery|suzuki|sv|swatch|swiftcover|swiss|sx|sy|sydney|symantec|systems|sz|tab|taipei|talk|taobao|target|tatamotors|tatar|tattoo|tax|taxi|tc|tci|td|tdk|team|tech|technology|tel|telecity|telefonica|temasek|tennis|test|teva|tf|tg|th|thd|theater|theatre|theguardian|tiaa|tickets|tienda|tiffany|tips|tires|tirol|tj|tjmaxx|tjx|tk|tkmaxx|tl|tm|tmall|tn|to|today|tokyo|tools|top|toray|toshiba|total|tours|town|toyota|toys|tr|trade|trading|training|travel|travelchannel|travelers|travelersinsurance|trust|trv|tt|tube|tui|tunes|tushu|tv|tvs|tw|tz|ua|ubank|ubs|uconnect|ug|uk|unicom|university|uno|uol|ups|us|uy|uz|va|vacations|vana|vanguard|vc|ve|vegas|ventures|verisign|vermögensberater|vermögensberatung|versicherung|vet|vg|vi|viajes|video|vig|viking|villas|vin|vip|virgin|visa|vision|vista|vistaprint|viva|vivo|vlaanderen|vn|vodka|volkswagen|volvo|vote|voting|voto|voyage|vu|vuelos|wales|walmart|walter|wang|wanggou|warman|watch|watches|weather|weatherchannel|webcam|weber|website|wed|wedding|weibo|weir|wf|whoswho|wien|wiki|williamhill|win|windows|wine|winners|wme|wolterskluwer|woodside|work|works|world|wow|ws|wtc|wtf|xbox|xerox|xfinity|xihuan|xin|xn--11b4c3d|xn--1ck2e1b|xn--1qqw23a|xn--30rr7y|xn--3bst00m|xn--3ds443g|xn--3e0b707e|xn--3oq18vl8pn36a|xn--3pxu8k|xn--42c2d9a|xn--45brj9c|xn--45q11c|xn--4gbrim|xn--4gq48lf9j|xn--54b7fta0cc|xn--55qw42g|xn--55qx5d|xn--5su34j936bgsg|xn--5tzm5g|xn--6frz82g|xn--6qq986b3xl|xn--80adxhks|xn--80ao21a|xn--80aqecdr1a|xn--80asehdb|xn--80aswg|xn--8y0a063a|xn--90a3ac|xn--90ais|xn--9dbq2a|xn--9et52u|xn--9krt00a|xn--b4w605ferd|xn--bck1b9a5dre4c|xn--c1avg|xn--c2br7g|xn--cck2b3b|xn--cg4bki|xn--clchc0ea0b2g2a9gcd|xn--czr694b|xn--czrs0t|xn--czru2d|xn--d1acj3b|xn--d1alf|xn--e1a4c|xn--eckvdtc9d|xn--efvy88h|xn--estv75g|xn--fct429k|xn--fhbei|xn--fiq228c5hs|xn--fiq64b|xn--fiqs8s|xn--fiqz9s|xn--fjq720a|xn--flw351e|xn--fpcrj9c3d|xn--fzc2c9e2c|xn--fzys8d69uvgm|xn--g2xx48c|xn--gckr3f0f|xn--gecrj9c|xn--gk3at1e|xn--h2brj9c|xn--hxt814e|xn--i1b6b1a6a2e|xn--imr513n|xn--io0a7i|xn--j1aef|xn--j1amh|xn--j6w193g|xn--jlq61u9w7b|xn--jvr189m|xn--kcrx77d1x4a|xn--kprw13d|xn--kpry57d|xn--kpu716f|xn--kput3i|xn--l1acc|xn--lgbbat1ad8j|xn--mgb2ddes|xn--mgb9awbf|xn--mgba3a3ejt|xn--mgba3a4f16a|xn--mgba3a4fra|xn--mgba7c0bbn0a|xn--mgbaakc7dvf|xn--mgbaam7a8h|xn--mgbab2bd|xn--mgbai9a5eva00b|xn--mgbai9azgqp6j|xn--mgbayh7gpa|xn--mgbb9fbpob|xn--mgbbh1a71e|xn--mgbc0a9azcg|xn--mgbca7dzdo|xn--mgberp4a5d4a87g|xn--mgberp4a5d4ar|xn--mgbi4ecexp|xn--mgbpl2fh|xn--mgbqly7c0a67fbc|xn--mgbqly7cvafr|xn--mgbt3dhd|xn--mgbtf8fl|xn--mgbtx2b|xn--mgbx4cd0ab|xn--mix082f|xn--mix891f|xn--mk1bu44c|xn--mxtq1m|xn--ngbc5azd|xn--ngbe9e0a|xn--ngbrx|xn--nnx388a|xn--node|xn--nqv7f|xn--nqv7fs00ema|xn--nyqy26a|xn--o3cw4h|xn--ogbpf8fl|xn--p1acf|xn--p1ai|xn--pbt977c|xn--pgbs0dh|xn--pssy2u|xn--q9jyb4c|xn--qcka1pmc|xn--qxam|xn--rhqv96g|xn--rovu88b|xn--s9brj9c|xn--ses554g|xn--t60b56a|xn--tckwe|xn--tiq49xqyj|xn--unup4y|xn--vermgensberater-ctb|xn--vermgensberatung-pwb|xn--vhquv|xn--vuq861b|xn--w4r85el8fhu5dnra|xn--w4rs40l|xn--wgbh1c|xn--wgbl6a|xn--xhq521b|xn--xkc2al3hye2a|xn--xkc2dl3a5ee0h|xn--y9a3aq|xn--yfro4i67o|xn--ygbi2ammx|xn--zfr164b|xperia|xxx|xyz|yachts|yahoo|yamaxun|yandex|ye|yodobashi|yoga|yokohama|you|youtube|yt|yun|za|zappos|zara|zero|zip|zippo|zkey|zm|zone|zuerich|zw|ελ|бел|дети|ею|католик|ком|мкд|мон|москва|онлайн|орг|рус|рф|сайт|срб|укр|қаз|հայ|קום|ابوظبي|اتصالات|ارامكو|الاردن|الجزائر|السعودية|السعوديه|السعودیة|السعودیۃ|العليان|المغرب|اليمن|امارات|ايران|ایران|بازار|بيتك|بھارت|تونس|سودان|سوريا|سورية|شبكة|عراق|عرب|عمان|فلسطين|قطر|كاثوليك|كوم|مصر|مليسيا|موبايلي|موقع|همراه|پاكستان|پاکستان|कॉम|नेट|भारत|संगठन|বাংলা|ভারত|ਭਾਰਤ|ભારત|இந்தியா|இலங்கை|சிங்கப்பூர்|భారత్|ලංකා|คอม|ไทย|გე|みんな|クラウド|グーグル|コム|ストア|セール|ファッション|ポイント|一号店|世界|中信|中国|中國|中文网|企业|佛山|信息|健康|八卦|公司|公益|台湾|台灣|商城|商店|商标|嘉里|嘉里大酒店|在线|大众汽车|大拿|天主教|娱乐|家電|工行|广东|微博|慈善|我爱你|手机|手表|政务|政府|新加坡|新闻|时尚|書籍|机构|淡马锡|游戏|澳門|澳门|点看|珠宝|移动|组织机构|网址|网店|网站|网络|联通|臺灣|诺基亚|谷歌|购物|通販|集团|電訊盈科|飞利浦|食品|餐厅|香格里拉|香港|닷넷|닷컴|삼성|한국)(?-i)` + gtld = `(?i)(aaa|aarp|abarth|abb|abbott|abbvie|abc|able|abogado|abudhabi|ac|academy|accenture|accountant|accountants|aco|active|actor|ad|adac|ads|adult|ae|aeg|aero|aetna|af|afamilycompany|afl|africa|ag|agakhan|agency|ai|aig|aigo|airbus|airforce|airtel|akdn|al|alfaromeo|alibaba|alipay|allfinanz|allstate|ally|alsace|alstom|am|americanexpress|americanfamily|amex|amfam|amica|amsterdam|analytics|android|anquan|anz|ao|aol|apartments|app|apple|aq|aquarelle|ar|arab|aramco|archi|army|arpa|art|arte|as|asda|asia|associates|at|athleta|attorney|au|auction|audi|audible|audio|auspost|author|auto|autos|avianca|aw|aws|ax|axa|az|azure|ba|baby|baidu|banamex|bananarepublic|band|bank|bar|barcelona|barclaycard|barclays|barefoot|bargains|baseball|basketball|bauhaus|bayern|bb|bbc|bbt|bbva|bcg|bcn|bd|be|beats|beauty|beer|bentley|berlin|best|bestbuy|bet|bf|bg|bh|bharti|bi|bible|bid|bike|bing|bingo|bio|bit|biz|bj|black|blackfriday|blanco|blockbuster|blog|bloomberg|blue|bm|bms|bmw|bn|bnl|bnpparibas|bo|boats|boehringer|bofa|bom|bond|boo|book|booking|boots|bosch|bostik|boston|bot|boutique|box|br|bradesco|bridgestone|broadway|broker|brother|brussels|bs|bt|budapest|bugatti|build|builders|business|buy|buzz|bv|bw|by|bz|bzh|ca|cab|cafe|cal|call|calvinklein|cam|camera|camp|cancerresearch|canon|capetown|capital|capitalone|car|caravan|cards|care|career|careers|cars|cartier|casa|case|caseih|cash|casino|cat|catering|catholic|cba|cbn|cbre|cbs|cc|cd|ceb|center|ceo|cern|cf|cfa|cfd|cg|ch|chanel|channel|chase|chat|cheap|chintai|chloe|christmas|chrome|chrysler|church|ci|cipriani|circle|cisco|citadel|citi|citic|city|cityeats|ck|cl|claims|cleaning|click|clinic|clinique|clothing|cloud|club|clubmed|cm|cn|co|coach|codes|coffee|college|cologne|com|comcast|commbank|community|company|compare|computer|comsec|condos|construction|consulting|contact|contractors|cooking|cookingchannel|cool|coop|corsica|country|coupon|coupons|courses|cr|credit|creditcard|creditunion|cricket|crown|crs|cruise|cruises|csc|cu|cuisinella|cv|cw|cx|cy|cymru|cyou|cz|dabur|dad|dance|data|date|dating|datsun|day|dclk|dds|de|deal|dealer|deals|degree|delivery|dell|deloitte|delta|democrat|dental|dentist|desi|design|dev|dhl|diamonds|diet|digital|direct|directory|discount|discover|dish|diy|dj|dk|dm|dnp|do|docs|doctor|dodge|dog|doha|domains|dot|download|drive|dtv|dubai|duck|dunlop|duns|dupont|durban|dvag|dvr|dz|earth|eat|ec|eco|edeka|edu|education|ee|eg|email|emerck|energy|engineer|engineering|enterprises|epost|epson|equipment|er|ericsson|erni|es|esq|estate|esurance|et|etisalat|eu|eurovision|eus|events|everbank|example|exchange|exit|expert|exposed|express|extraspace|fage|fail|fairwinds|faith|family|fan|fans|farm|farmers|fashion|fast|fedex|feedback|ferrari|ferrero|fi|fiat|fidelity|fido|film|final|finance|financial|fire|firestone|firmdale|fish|fishing|fit|fitness|fj|fk|flickr|flights|flir|florist|flowers|fly|fm|fo|foo|food|foodnetwork|football|ford|forex|forsale|forum|foundation|fox|fr|free|fresenius|frl|frogans|frontdoor|frontier|ftr|fujitsu|fujixerox|fun|fund|furniture|futbol|fyi|ga|gal|gallery|gallo|gallup|game|games|gap|garden|gb|gbiz|gd|gdn|ge|gea|gent|genting|george|gf|gg|ggee|gh|gi|gift|gifts|gives|giving|gl|glade|glass|gle|global|globo|gm|gmail|gmbh|gmo|gmx|gn|gnu|godaddy|gold|goldpoint|golf|goo|goodhands|goodyear|goog|google|gop|got|gov|gp|gq|gr|grainger|graphics|gratis|green|gripe|grocery|group|gs|gt|gu|guardian|gucci|guge|guide|guitars|guru|gw|gy|hair|hamburg|hangout|haus|hbo|hdfc|hdfcbank|health|healthcare|help|helsinki|here|hermes|hgtv|hiphop|hisamitsu|hitachi|hiv|hk|hkt|hm|hn|hockey|holdings|holiday|homedepot|homegoods|homes|homesense|honda|honeywell|horse|hospital|host|hosting|hot|hoteles|hotels|hotmail|house|how|hr|hsbc|ht|htc|hu|hughes|hyatt|hyundai|i2p|ibm|icbc|ice|icu|id|ie|ieee|ifm|ikano|il|im|imamat|imdb|immo|immobilien|in|industries|infiniti|info|ing|ink|institute|insurance|insure|int|intel|international|intuit|invalid|investments|io|ipiranga|iq|ir|irish|is|iselect|ismaili|ist|istanbul|it|itau|itv|iveco|iwc|jaguar|java|jcb|jcp|je|jeep|jetzt|jewelry|jio|jlc|jll|jm|jmp|jnj|jo|jobs|joburg|jot|joy|jp|jpmorgan|jprs|juegos|juniper|kaufen|kddi|ke|kerryhotels|kerrylogistics|kerryproperties|kfh|kg|kh|ki|kia|kim|kinder|kindle|kitchen|kiwi|km|kn|koeln|komatsu|kosher|kp|kpmg|kpn|kr|krd|kred|kuokgroup|kw|ky|kyoto|kz|la|lacaixa|ladbrokes|lamborghini|lamer|lancaster|lancia|lancome|land|landrover|lanxess|lasalle|lat|latino|latrobe|law|lawyer|lb|lc|lds|lease|leclerc|lefrak|legal|lego|lexus|lgbt|li|liaison|lidl|life|lifeinsurance|lifestyle|lighting|like|lilly|limited|limo|lincoln|linde|link|lipsy|live|living|lixil|lk|loan|loans|local|localhost|locker|locus|loft|lol|london|lotte|lotto|love|lpl|lplfinancial|lr|ls|lt|ltd|ltda|lu|lundbeck|lupin|luxe|luxury|lv|ly|ma|macys|madrid|maif|maison|makeup|man|management|mango|map|market|marketing|markets|marriott|marshalls|maserati|mattel|mba|mc|mcd|mcdonalds|mckinsey|md|me|med|media|meet|melbourne|meme|memorial|men|menu|meo|merckmsd|metlife|mg|mh|miami|microsoft|mil|mini|mint|mit|mitsubishi|mk|ml|mlb|mls|mm|mma|mn|mo|mobi|mobile|mobily|moda|moe|moi|mom|monash|money|monster|montblanc|mopar|mormon|mortgage|moscow|moto|motorcycles|mov|movie|movistar|mp|mq|mr|ms|msd|mt|mtn|mtpc|mtr|mu|museum|mutual|mv|mw|mx|my|mz|na|nab|nadex|nagoya|name|nationwide|natura|navy|nba|nc|ne|nec|net|netbank|netflix|network|neustar|new|newholland|news|next|nextdirect|nexus|nf|nfl|ng|ngo|nhk|ni|nico|nike|nikon|ninja|nissan|nissay|nl|no|nokia|northwesternmutual|norton|now|nowruz|nowtv|np|nr|nra|nrw|ntt|nu|nyc|nz|obi|observer|off|office|okinawa|olayan|olayangroup|oldnavy|ollo|om|omega|one|ong|onion|onl|online|onyourside|ooo|open|oracle|orange|org|organic|orientexpress|origins|osaka|otsuka|ott|ovh|pa|page|pamperedchef|panasonic|panerai|paris|pars|partners|parts|party|passagens|pay|pccw|pe|pet|pf|pfizer|pg|ph|pharmacy|phd|philips|phone|photo|photography|photos|physio|piaget|pics|pictet|pictures|pid|pin|ping|pink|pioneer|pizza|pk|pl|place|play|playstation|plumbing|plus|pm|pn|pnc|pohl|poker|politie|porn|post|pr|pramerica|praxi|press|prime|pro|prod|productions|prof|progressive|promo|properties|property|protection|pru|prudential|ps|pt|pub|pw|pwc|py|qa|qpon|quebec|quest|qvc|racing|radio|raid|re|read|realestate|realtor|realty|recipes|red|redstone|redumbrella|rehab|reise|reisen|reit|reliance|ren|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rexroth|rich|richardli|ricoh|rightathome|ril|rio|rip|rmit|ro|rocher|rocks|rodeo|rogers|room|rs|rsvp|ru|rugby|ruhr|run|rw|rwe|ryukyu|sa|saarland|safe|safety|sakura|sale|salon|samsclub|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|sas|save|saxo|sb|sbi|sbs|sc|sca|scb|schaeffler|schmidt|scholarships|school|schule|schwarz|science|scjohnson|scor|scot|sd|se|search|seat|secure|security|seek|select|sener|services|ses|seven|sew|sex|sexy|sfr|sg|sh|shangrila|sharp|shaw|shell|shia|shiksha|shoes|shop|shopping|shouji|show|showtime|shriram|si|silk|sina|singles|site|sj|sk|ski|skin|sky|skype|sl|sling|sm|smart|smile|sn|sncf|so|soccer|social|softbank|software|sohu|solar|solutions|song|sony|soy|space|spiegel|spot|spreadbetting|sr|srl|srt|st|stada|staples|star|starhub|statebank|statefarm|statoil|stc|stcgroup|stockholm|storage|store|stream|studio|study|style|su|sucks|supplies|supply|support|surf|surgery|suzuki|sv|swatch|swiftcover|swiss|sx|sy|sydney|symantec|systems|sz|tab|taipei|talk|taobao|target|tatamotors|tatar|tattoo|tax|taxi|tc|tci|td|tdk|team|tech|technology|tel|telecity|telefonica|temasek|tennis|test|teva|tf|tg|th|thd|theater|theatre|tiaa|tickets|tienda|tiffany|tips|tires|tirol|tj|tjmaxx|tjx|tk|tkmaxx|tl|tm|tmall|tn|to|today|tokyo|tools|top|toray|toshiba|total|tours|town|toyota|toys|tr|trade|trading|training|travel|travelchannel|travelers|travelersinsurance|trust|trv|tt|tube|tui|tunes|tushu|tv|tvs|tw|tz|ua|ubank|ubs|uconnect|ug|uk|unicom|university|uno|uol|ups|us|uy|uz|va|vacations|vana|vanguard|vc|ve|vegas|ventures|verisign|vermögensberater|vermögensberatung|versicherung|vet|vg|vi|viajes|video|vig|viking|villas|vin|vip|virgin|visa|vision|vista|vistaprint|viva|vivo|vlaanderen|vn|vodka|volkswagen|volvo|vote|voting|voto|voyage|vu|vuelos|wales|walmart|walter|wang|wanggou|warman|watch|watches|weather|weatherchannel|webcam|weber|website|wed|wedding|weibo|weir|wf|whoswho|wien|wiki|williamhill|win|windows|wine|winners|wme|wolterskluwer|woodside|work|works|world|wow|ws|wtc|wtf|xbox|xerox|xfinity|xihuan|xin|xn--11b4c3d|xn--1ck2e1b|xn--1qqw23a|xn--30rr7y|xn--3bst00m|xn--3ds443g|xn--3e0b707e|xn--3oq18vl8pn36a|xn--3pxu8k|xn--42c2d9a|xn--45brj9c|xn--45q11c|xn--4gbrim|xn--54b7fta0cc|xn--55qw42g|xn--55qx5d|xn--5su34j936bgsg|xn--5tzm5g|xn--6frz82g|xn--6qq986b3xl|xn--80adxhks|xn--80ao21a|xn--80aqecdr1a|xn--80asehdb|xn--80aswg|xn--8y0a063a|xn--90a3ac|xn--90ais|xn--9dbq2a|xn--9et52u|xn--9krt00a|xn--b4w605ferd|xn--bck1b9a5dre4c|xn--c1avg|xn--c2br7g|xn--cck2b3b|xn--cg4bki|xn--clchc0ea0b2g2a9gcd|xn--czr694b|xn--czrs0t|xn--czru2d|xn--d1acj3b|xn--d1alf|xn--e1a4c|xn--eckvdtc9d|xn--efvy88h|xn--estv75g|xn--fct429k|xn--fhbei|xn--fiq228c5hs|xn--fiq64b|xn--fiqs8s|xn--fiqz9s|xn--fjq720a|xn--flw351e|xn--fpcrj9c3d|xn--fzc2c9e2c|xn--fzys8d69uvgm|xn--g2xx48c|xn--gckr3f0f|xn--gecrj9c|xn--gk3at1e|xn--h2brj9c|xn--hxt814e|xn--i1b6b1a6a2e|xn--imr513n|xn--io0a7i|xn--j1aef|xn--j1amh|xn--j6w193g|xn--jlq61u9w7b|xn--jvr189m|xn--kcrx77d1x4a|xn--kprw13d|xn--kpry57d|xn--kpu716f|xn--kput3i|xn--l1acc|xn--lgbbat1ad8j|xn--mgb2ddes|xn--mgb9awbf|xn--mgba3a3ejt|xn--mgba3a4f16a|xn--mgba3a4fra|xn--mgba7c0bbn0a|xn--mgbaakc7dvf|xn--mgbaam7a8h|xn--mgbab2bd|xn--mgbai9a5eva00b|xn--mgbai9azgqp6j|xn--mgbayh7gpa|xn--mgbb9fbpob|xn--mgbbh1a71e|xn--mgbc0a9azcg|xn--mgbca7dzdo|xn--mgberp4a5d4a87g|xn--mgberp4a5d4ar|xn--mgbi4ecexp|xn--mgbpl2fh|xn--mgbqly7c0a67fbc|xn--mgbqly7cvafr|xn--mgbt3dhd|xn--mgbtf8fl|xn--mgbtx2b|xn--mgbx4cd0ab|xn--mix082f|xn--mix891f|xn--mk1bu44c|xn--mxtq1m|xn--ngbc5azd|xn--ngbe9e0a|xn--ngbrx|xn--nnx388a|xn--node|xn--nqv7f|xn--nqv7fs00ema|xn--nyqy26a|xn--o3cw4h|xn--ogbpf8fl|xn--p1acf|xn--p1ai|xn--pbt977c|xn--pgbs0dh|xn--pssy2u|xn--q9jyb4c|xn--qcka1pmc|xn--qxam|xn--rhqv96g|xn--rovu88b|xn--s9brj9c|xn--ses554g|xn--t60b56a|xn--tckwe|xn--tiq49xqyj|xn--unup4y|xn--vermgensberater-ctb|xn--vermgensberatung-pwb|xn--vhquv|xn--vuq861b|xn--w4r85el8fhu5dnra|xn--w4rs40l|xn--wgbh1c|xn--wgbl6a|xn--xhq521b|xn--xkc2al3hye2a|xn--xkc2dl3a5ee0h|xn--y9a3aq|xn--yfro4i67o|xn--ygbi2ammx|xn--zfr164b|xperia|xxx|xyz|yachts|yahoo|yamaxun|yandex|ye|yodobashi|yoga|yokohama|you|youtube|yt|yun|za|zappos|zara|zero|zip|zippo|zkey|zm|zone|zuerich|zw|ελ|бел|дети|ею|католик|ком|мкд|мон|москва|онлайн|орг|рус|рф|сайт|срб|укр|қаз|հայ|קום|ابوظبي|اتصالات|ارامكو|الاردن|الجزائر|السعودية|السعوديه|السعودیة|السعودیۃ|العليان|المغرب|اليمن|امارات|ايران|ایران|بازار|بيتك|بھارت|تونس|سودان|سوريا|سورية|شبكة|عراق|عرب|عمان|فلسطين|قطر|كاثوليك|كوم|مصر|مليسيا|موبايلي|موقع|همراه|پاكستان|پاکستان|कॉम|नेट|भारत|संगठन|বাংলা|ভারত|ਭਾਰਤ|ભારત|இந்தியா|இலங்கை|சிங்கப்பூர்|భారత్|ලංකා|คอม|ไทย|გე|みんな|クラウド|グーグル|コム|ストア|セール|ファッション|ポイント|世界|中信|中国|中國|中文网|企业|佛山|信息|健康|八卦|公司|公益|台湾|台灣|商城|商店|商标|嘉里|嘉里大酒店|在线|大众汽车|大拿|天主教|娱乐|家電|工行|广东|微博|慈善|我爱你|手机|手表|政务|政府|新加坡|新闻|时尚|書籍|机构|淡马锡|游戏|澳門|澳门|点看|珠宝|移动|组织机构|网址|网店|网站|网络|联通|臺灣|诺基亚|谷歌|购物|通販|集团|電訊盈科|飞利浦|食品|餐厅|香格里拉|香港|닷넷|닷컴|삼성|한국)(?-i)` otherScheme = `(?i)(bitcoin|file|magnet|mailto|sms|tel|xmpp)(?-i):` ) diff --git a/vendor/github.com/mvdan/xurls/tlds.go b/vendor/github.com/mvdan/xurls/tlds.go index 946ff9ec6..bc38ad383 100644 --- a/vendor/github.com/mvdan/xurls/tlds.go +++ b/vendor/github.com/mvdan/xurls/tlds.go @@ -385,7 +385,6 @@ var TLDs = []string{ `durban`, `dvag`, `dvr`, - `dwg`, `dz`, `earth`, `eat`, @@ -618,7 +617,6 @@ var TLDs = []string{ `ie`, `ieee`, `ifm`, - `iinet`, `ikano`, `il`, `im`, @@ -865,7 +863,6 @@ var TLDs = []string{ `mu`, `museum`, `mutual`, - `mutuelle`, `mv`, `mw`, `mx`, @@ -935,6 +932,7 @@ var TLDs = []string{ `omega`, `one`, `ong`, + `onion`, `onl`, `online`, `onyourside`, @@ -1074,6 +1072,7 @@ var TLDs = []string{ `rs`, `rsvp`, `ru`, + `rugby`, `ruhr`, `run`, `rw`, @@ -1244,7 +1243,6 @@ var TLDs = []string{ `thd`, `theater`, `theatre`, - `theguardian`, `tiaa`, `tickets`, `tienda`, @@ -1492,7 +1490,6 @@ var TLDs = []string{ `セール`, `ファッション`, `ポイント`, - `一号店`, `世界`, `中信`, `中国`, diff --git a/vendor/github.com/mvdan/xurls/tlds_pseudo.go b/vendor/github.com/mvdan/xurls/tlds_pseudo.go index 4183bd5b1..94c67d15b 100644 --- a/vendor/github.com/mvdan/xurls/tlds_pseudo.go +++ b/vendor/github.com/mvdan/xurls/tlds_pseudo.go @@ -19,7 +19,6 @@ var PseudoTLDs = []string{ `invalid`, // Invalid domain `local`, // Local network `localhost`, // Local network - `onion`, // Tor hidden services `test`, // Test domain `zkey`, // GNS domain name } diff --git a/vendor/github.com/mvdan/xurls/xurls.go b/vendor/github.com/mvdan/xurls/xurls.go index 6a99b5d45..8a619d8a5 100644 --- a/vendor/github.com/mvdan/xurls/xurls.go +++ b/vendor/github.com/mvdan/xurls/xurls.go @@ -11,12 +11,14 @@ import "regexp" const ( letter = `\p{L}` + mark = `\p{M}` number = `\p{N}` - iriChar = letter + number + iriChar = letter + mark + number currency = `\p{Sc}` otherSymb = `\p{So}` endChar = iriChar + `/\-+_&~*%=#` + currency + otherSymb - midChar = endChar + `@.,:;'?!|` + otherPunc = `\p{Po}` + midChar = endChar + `|` + otherPunc wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)` wellBrack = `\[[` + midChar + `]*(\[[` + midChar + `]*\][` + midChar + `]*)*\]` wellBrace = `\{[` + midChar + `]*(\{[` + midChar + `]*\}[` + midChar + `]*)*\}` diff --git a/vendor/github.com/opencontainers/runc/checkpoint.go b/vendor/github.com/opencontainers/runc/checkpoint.go index 0a1533f48..78977d71a 100644 --- a/vendor/github.com/opencontainers/runc/checkpoint.go +++ b/vendor/github.com/opencontainers/runc/checkpoint.go @@ -24,20 +24,37 @@ checkpointed.`, Flags: []cli.Flag{ cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, + cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"}, cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"}, + cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"}, cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'"}, cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properies"}, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + // XXX: Currently this is untested with rootless containers. + if isRootless() { + return fmt.Errorf("runc checkpoint requires root") + } + container, err := getContainer(context) if err != nil { return err } + status, err := container.Status() + if err != nil { + return err + } + if status == libcontainer.Created { + fatalf("Container cannot be checkpointed in created state") + } defer destroy(container) options := criuOptions(context) // these are the mandatory criu options for a container @@ -95,7 +112,7 @@ func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) } } -var namespaceMapping = map[specs.NamespaceType]int{ +var namespaceMapping = map[specs.LinuxNamespaceType]int{ specs.NetworkNamespace: syscall.CLONE_NEWNET, } @@ -103,7 +120,7 @@ func setEmptyNsMask(context *cli.Context, options *libcontainer.CriuOpts) error var nsmask int for _, ns := range context.StringSlice("empty-ns") { - f, exists := namespaceMapping[specs.NamespaceType(ns)] + f, exists := namespaceMapping[specs.LinuxNamespaceType(ns)] if !exists { return fmt.Errorf("namespace %q is not supported", ns) } diff --git a/vendor/github.com/opencontainers/runc/create.go b/vendor/github.com/opencontainers/runc/create.go index 899e54caa..096e8e335 100644 --- a/vendor/github.com/opencontainers/runc/create.go +++ b/vendor/github.com/opencontainers/runc/create.go @@ -29,9 +29,9 @@ command(s) that get executed on start, edit the args parameter of the spec. See Usage: `path to the root of the bundle directory, defaults to the current directory`, }, cli.StringFlag{ - Name: "console", + Name: "console-socket", Value: "", - Usage: "specify the pty slave path for use with the container", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, cli.StringFlag{ Name: "pid-file", @@ -46,8 +46,18 @@ command(s) that get executed on start, edit the args parameter of the spec. See Name: "no-new-keyring", Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", }, + cli.IntFlag{ + Name: "preserve-fds", + Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", + }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err + } spec, err := setupSpec(context) if err != nil { return err diff --git a/vendor/github.com/opencontainers/runc/delete.go b/vendor/github.com/opencontainers/runc/delete.go index 803bdcda9..b43dcaa7c 100644 --- a/vendor/github.com/opencontainers/runc/delete.go +++ b/vendor/github.com/opencontainers/runc/delete.go @@ -14,10 +14,10 @@ import ( ) func killContainer(container libcontainer.Container) error { - container.Signal(syscall.SIGKILL) + _ = container.Signal(syscall.SIGKILL, false) for i := 0; i < 100; i++ { time.Sleep(100 * time.Millisecond) - if err := container.Signal(syscall.Signal(0)); err != nil { + if err := container.Signal(syscall.Signal(0), false); err != nil { destroy(container) return nil } @@ -27,7 +27,7 @@ func killContainer(container libcontainer.Container) error { var deleteCommand = cli.Command{ Name: "delete", - Usage: "delete any resources held by the container often used with detached containers", + Usage: "delete any resources held by the container often used with detached container", ArgsUsage: ` Where "" is the name for the instance of the container. @@ -41,21 +41,26 @@ status of "ubuntu01" as "stopped" the following will delete resources held for Flags: []cli.Flag{ cli.BoolFlag{ Name: "force, f", - Usage: "Forcibly kills the container if it is still running", + Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)", }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + + id := context.Args().First() container, err := getContainer(context) if err != nil { if lerr, ok := err.(libcontainer.Error); ok && lerr.Code() == libcontainer.ContainerNotExists { // if there was an aborted start or something of the sort then the container's directory could exist but // libcontainer does not see it because the state.json file inside that directory was never created. - path := filepath.Join(context.GlobalString("root"), context.Args().First()) - if err := os.RemoveAll(path); err != nil { - return err + path := filepath.Join(context.GlobalString("root"), id) + if e := os.RemoveAll(path); e != nil { + fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e) } } - return nil + return err } s, err := container.Status() if err != nil { @@ -69,9 +74,11 @@ status of "ubuntu01" as "stopped" the following will delete resources held for default: if context.Bool("force") { return killContainer(container) + } else { + return fmt.Errorf("cannot delete container %s that is not stopped: %s\n", id, s) } - return fmt.Errorf("cannot delete container that is not stopped: %s", s) } + return nil }, } diff --git a/vendor/github.com/opencontainers/runc/events.go b/vendor/github.com/opencontainers/runc/events.go index da6d1f5f5..6c21e5259 100644 --- a/vendor/github.com/opencontainers/runc/events.go +++ b/vendor/github.com/opencontainers/runc/events.go @@ -24,7 +24,7 @@ type event struct { // stats is the runc specific stats structure for stability when encoding and decoding stats. type stats struct { - Cpu cpu `json:"cpu"` + CPU cpu `json:"cpu"` Memory memory `json:"memory"` Pids pids `json:"pids"` Blkio blkio `json:"blkio"` @@ -108,6 +108,9 @@ information is displayed once every 5 seconds.`, cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"}, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -121,7 +124,6 @@ information is displayed once every 5 seconds.`, return err } if status == libcontainer.Stopped { - fatalf("container with id %s is not running", container.ID()) return fmt.Errorf("container with id %s is not running", container.ID()) } var ( @@ -196,13 +198,13 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *stats { s.Pids.Current = cg.PidsStats.Current s.Pids.Limit = cg.PidsStats.Limit - s.Cpu.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode - s.Cpu.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode - s.Cpu.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage - s.Cpu.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage - s.Cpu.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods - s.Cpu.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods - s.Cpu.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime + s.CPU.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode + s.CPU.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode + s.CPU.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage + s.CPU.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage + s.CPU.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods + s.CPU.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods + s.CPU.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime s.Memory.Cache = cg.MemoryStats.Cache s.Memory.Kernel = convertMemoryEntry(cg.MemoryStats.KernelUsage) diff --git a/vendor/github.com/opencontainers/runc/exec.go b/vendor/github.com/opencontainers/runc/exec.go index 55a5aeda4..22f2689ab 100644 --- a/vendor/github.com/opencontainers/runc/exec.go +++ b/vendor/github.com/opencontainers/runc/exec.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" + "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" "github.com/urfave/cli" @@ -17,20 +18,21 @@ import ( var execCommand = cli.Command{ Name: "exec", Usage: "execute new process inside the container", - ArgsUsage: ` + ArgsUsage: ` [command options] || -p process.json Where "" is the name for the instance of the container and -"" is the command to be executed in the container. +"" is the command to be executed in the container. +"" can't be empty unless a "-p" flag provided. EXAMPLE: For example, if the container is configured to run the linux ps command the following will output a list of processes running in the container: - + # runc exec ps`, Flags: []cli.Flag{ cli.StringFlag{ - Name: "console", - Usage: "specify the pty slave path for use with the container", + Name: "console-socket", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, cli.StringFlag{ Name: "cwd", @@ -79,13 +81,17 @@ following will output a list of processes running in the container: Usage: "add a capability to the bounding set for the process", }, cli.BoolFlag{ - Name: "no-subreaper", - Usage: "disable the use of the subreaper used to reap reparented processes", + Name: "no-subreaper", + Usage: "disable the use of the subreaper used to reap reparented processes", + Hidden: true, }, }, Action: func(context *cli.Context) error { - if os.Geteuid() != 0 { - return fmt.Errorf("runc should be run as root") + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err } status, err := execProcess(context) if err == nil { @@ -93,6 +99,7 @@ following will output a list of processes running in the container: } return fmt.Errorf("exec failed: %v", err) }, + SkipArgReorder: true, } func execProcess(context *cli.Context) (int, error) { @@ -100,6 +107,13 @@ func execProcess(context *cli.Context) (int, error) { if err != nil { return -1, err } + status, err := container.Status() + if err != nil { + return -1, err + } + if status == libcontainer.Stopped { + return -1, fmt.Errorf("cannot exec a container that has stopped") + } path := context.String("process") if path == "" && len(context.Args()) == 1 { return -1, fmt.Errorf("process args cannot be empty") @@ -115,10 +129,10 @@ func execProcess(context *cli.Context) (int, error) { return -1, err } r := &runner{ - enableSubreaper: !context.Bool("no-subreaper"), + enableSubreaper: false, shouldDestroy: false, container: container, - console: context.String("console"), + consoleSocket: context.String("console-socket"), detach: detach, pidFile: context.String("pid-file"), } @@ -159,12 +173,17 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { p.SelinuxLabel = l } if caps := context.StringSlice("cap"); len(caps) > 0 { - p.Capabilities = caps + for _, c := range caps { + p.Capabilities.Bounding = append(p.Capabilities.Bounding, c) + p.Capabilities.Inheritable = append(p.Capabilities.Inheritable, c) + p.Capabilities.Effective = append(p.Capabilities.Effective, c) + p.Capabilities.Permitted = append(p.Capabilities.Permitted, c) + p.Capabilities.Ambient = append(p.Capabilities.Ambient, c) + } } // append the passed env variables - for _, e := range context.StringSlice("env") { - p.Env = append(p.Env, e) - } + p.Env = append(p.Env, context.StringSlice("env")...) + // set the tty if context.IsSet("tty") { p.Terminal = context.Bool("tty") diff --git a/vendor/github.com/opencontainers/runc/kill.go b/vendor/github.com/opencontainers/runc/kill.go index 34d62abd7..f80c4db78 100644 --- a/vendor/github.com/opencontainers/runc/kill.go +++ b/vendor/github.com/opencontainers/runc/kill.go @@ -52,17 +52,29 @@ var signalMap = map[string]syscall.Signal{ var killCommand = cli.Command{ Name: "kill", Usage: "kill sends the specified signal (default: SIGTERM) to the container's init process", - ArgsUsage: ` + ArgsUsage: ` [signal] Where "" is the name for the instance of the container and -"" is the signal to be sent to the init process. +"[signal]" is the signal to be sent to the init process. EXAMPLE: For example, if the container id is "ubuntu01" the following will send a "KILL" signal to the init process of the "ubuntu01" container: # runc kill ubuntu01 KILL`, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "send the specified signal to all processes inside the container", + }, + }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + if err := checkArgs(context, 2, maxArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -77,8 +89,7 @@ signal to the init process of the "ubuntu01" container: if err != nil { return err } - - if err := container.Signal(signal); err != nil { + if err := container.Signal(signal, context.Bool("all")); err != nil { return err } return nil @@ -88,7 +99,13 @@ signal to the init process of the "ubuntu01" container: func parseSignal(rawSignal string) (syscall.Signal, error) { s, err := strconv.Atoi(rawSignal) if err == nil { - return syscall.Signal(s), nil + sig := syscall.Signal(s) + for _, msig := range signalMap { + if sig == msig { + return sig, nil + } + } + return -1, fmt.Errorf("unknown signal %q", rawSignal) } signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] if !ok { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go index 43fd39ef5..8962cab33 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go @@ -199,18 +199,16 @@ type ExecUser struct { // files cannot be opened for any reason, the error is ignored and a nil // io.Reader is passed instead. func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) { - passwd, err := os.Open(passwdPath) - if err != nil { - passwd = nil - } else { - defer passwd.Close() + var passwd, group io.Reader + + if passwdFile, err := os.Open(passwdPath); err == nil { + passwd = passwdFile + defer passwdFile.Close() } - group, err := os.Open(groupPath) - if err != nil { - group = nil - } else { - defer group.Close() + if groupFile, err := os.Open(groupPath); err == nil { + group = groupFile + defer groupFile.Close() } return GetExecUser(userSpec, defaults, passwd, group) @@ -343,7 +341,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( if len(groups) > 0 { // First match wins, even if there's more than one matching entry. user.Gid = groups[0].Gid - } else if groupArg != "" { + } else { // If we can't find a group with the given name, the only other valid // option is if it's a numeric group name with no associated entry in group. @@ -433,9 +431,11 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err // that opens the groupPath given and gives it as an argument to // GetAdditionalGroups. func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) { - group, err := os.Open(groupPath) - if err == nil { - defer group.Close() + var group io.Reader + + if groupFile, err := os.Open(groupPath); err == nil { + group = groupFile + defer groupFile.Close() } return GetAdditionalGroups(additionalGroups, group) } diff --git a/vendor/github.com/opencontainers/runc/list.go b/vendor/github.com/opencontainers/runc/list.go index c9610312c..1c3b9aa83 100644 --- a/vendor/github.com/opencontainers/runc/list.go +++ b/vendor/github.com/opencontainers/runc/list.go @@ -7,11 +7,14 @@ import ( "io/ioutil" "os" "path/filepath" + "syscall" "text/tabwriter" "time" "encoding/json" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/user" "github.com/opencontainers/runc/libcontainer/utils" "github.com/urfave/cli" ) @@ -21,6 +24,8 @@ const formatOptions = `table or json` // containerState represents the platform agnostic pieces relating to a // running container's status and state type containerState struct { + // Version is the OCI version for the container + Version string `json:"ociVersion"` // ID is the container ID ID string `json:"id"` // InitProcessPid is the init process id in the parent namespace @@ -29,10 +34,14 @@ type containerState struct { Status string `json:"status"` // Bundle is the path on the filesystem to the bundle Bundle string `json:"bundle"` + // Rootfs is a path to a directory containing the container's root filesystem. + Rootfs string `json:"rootfs"` // Created is the unix timestamp for the creation time of the container in UTC Created time.Time `json:"created"` // Annotations is the user defined annotations added to the config. Annotations map[string]string `json:"annotations,omitempty"` + // The owner of the state directory (the owner of the container). + Owner string `json:"owner"` } var listCommand = cli.Command{ @@ -62,6 +71,9 @@ To list containers created using a non-default value for "--root": }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 0, exactArgs); err != nil { + return err + } s, err := getContainers(context) if err != nil { return err @@ -77,14 +89,15 @@ To list containers created using a non-default value for "--root": switch context.String("format") { case "table": w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0) - fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\n") + fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n") for _, item := range s { - fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\n", + fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\n", item.ID, item.InitProcessPid, item.Status, item.Bundle, - item.Created.Format(time.RFC3339Nano)) + item.Created.Format(time.RFC3339Nano), + item.Owner) } if err := w.Flush(); err != nil { return err @@ -118,26 +131,43 @@ func getContainers(context *cli.Context) ([]containerState, error) { var s []containerState for _, item := range list { if item.IsDir() { + // This cast is safe on Linux. + stat := item.Sys().(*syscall.Stat_t) + owner, err := user.LookupUid(int(stat.Uid)) + if err != nil { + owner.Name = string(stat.Uid) + } + container, err := factory.Load(item.Name()) if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "load container %s: %v\n", item.Name(), err) + continue } containerStatus, err := container.Status() if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "status for %s: %v\n", item.Name(), err) + continue } state, err := container.State() if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "state for %s: %v\n", item.Name(), err) + continue + } + pid := state.BaseState.InitProcessPid + if containerStatus == libcontainer.Stopped { + pid = 0 } bundle, annotations := utils.Annotations(state.Config.Labels) s = append(s, containerState{ + Version: state.BaseState.Config.Version, ID: state.BaseState.ID, - InitProcessPid: state.BaseState.InitProcessPid, + InitProcessPid: pid, Status: containerStatus.String(), Bundle: bundle, + Rootfs: state.BaseState.Config.Rootfs, Created: state.BaseState.Created, Annotations: annotations, + Owner: owner.Name, }) } } diff --git a/vendor/github.com/opencontainers/runc/main.go b/vendor/github.com/opencontainers/runc/main.go index 540656578..1cb8f4dbf 100644 --- a/vendor/github.com/opencontainers/runc/main.go +++ b/vendor/github.com/opencontainers/runc/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io" "os" "strings" @@ -129,7 +130,20 @@ func main() { } return nil } + // If the command returns an error, cli takes upon itself to print + // the error on cli.ErrWriter and exit. + // Use our own writer here to ensure the log gets sent to the right location. + cli.ErrWriter = &FatalWriter{cli.ErrWriter} if err := app.Run(os.Args); err != nil { fatal(err) } } + +type FatalWriter struct { + cliErrWriter io.Writer +} + +func (f *FatalWriter) Write(p []byte) (n int, err error) { + logrus.Error(string(p)) + return f.cliErrWriter.Write(p) +} diff --git a/vendor/github.com/opencontainers/runc/notify_socket.go b/vendor/github.com/opencontainers/runc/notify_socket.go new file mode 100644 index 000000000..2bd678893 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/notify_socket.go @@ -0,0 +1,108 @@ +// +build linux + +package main + +import ( + "bytes" + "fmt" + "net" + "path/filepath" + + "github.com/Sirupsen/logrus" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/urfave/cli" +) + +type notifySocket struct { + socket *net.UnixConn + host string + socketPath string +} + +func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *notifySocket { + if notifySocketHost == "" { + return nil + } + + root := filepath.Join(context.GlobalString("root"), id) + path := filepath.Join(root, "notify.sock") + + notifySocket := ¬ifySocket{ + socket: nil, + host: notifySocketHost, + socketPath: path, + } + + return notifySocket +} + +func (ns *notifySocket) Close() error { + return ns.socket.Close() +} + +// If systemd is supporting sd_notify protocol, this function will add support +// for sd_notify protocol from within the container. +func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) { + mount := specs.Mount{Destination: s.host, Type: "bind", Source: s.socketPath, Options: []string{"bind"}} + spec.Mounts = append(spec.Mounts, mount) + spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host)) +} + +func (s *notifySocket) setupSocket() error { + addr := net.UnixAddr{ + Name: s.socketPath, + Net: "unixgram", + } + + socket, err := net.ListenUnixgram("unixgram", &addr) + if err != nil { + return err + } + + s.socket = socket + return nil +} + +// pid1 must be set only with -d, as it is used to set the new process as the main process +// for the service in systemd +func (notifySocket *notifySocket) run(pid1 int) { + buf := make([]byte, 512) + notifySocketHostAddr := net.UnixAddr{Name: notifySocket.host, Net: "unixgram"} + client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) + if err != nil { + logrus.Error(err) + return + } + for { + r, err := notifySocket.socket.Read(buf) + if err != nil { + break + } + var out bytes.Buffer + for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) { + if bytes.HasPrefix(line, []byte("READY=")) { + _, err = out.Write(line) + if err != nil { + return + } + + _, err = out.Write([]byte{'\n'}) + if err != nil { + return + } + + _, err = client.Write(out.Bytes()) + if err != nil { + return + } + + // now we can inform systemd to use pid1 as the pid to monitor + if pid1 > 0 { + newPid := fmt.Sprintf("MAINPID=%d\n", pid1) + client.Write([]byte(newPid)) + } + return + } + } + } +} diff --git a/vendor/github.com/opencontainers/runc/pause.go b/vendor/github.com/opencontainers/runc/pause.go index 22c2164dc..3b98dbbbf 100644 --- a/vendor/github.com/opencontainers/runc/pause.go +++ b/vendor/github.com/opencontainers/runc/pause.go @@ -15,6 +15,9 @@ paused. `, Use runc list to identiy instances of containers and their current status.`, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -22,6 +25,7 @@ Use runc list to identiy instances of containers and their current status.`, if err := container.Pause(); err != nil { return err } + return nil }, } @@ -37,6 +41,9 @@ resumed.`, Use runc list to identiy instances of containers and their current status.`, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -44,6 +51,7 @@ Use runc list to identiy instances of containers and their current status.`, if err := container.Resume(); err != nil { return err } + return nil }, } diff --git a/vendor/github.com/opencontainers/runc/ps.go b/vendor/github.com/opencontainers/runc/ps.go index 3b462a0a5..6e0c7376a 100644 --- a/vendor/github.com/opencontainers/runc/ps.go +++ b/vendor/github.com/opencontainers/runc/ps.go @@ -20,11 +20,19 @@ var psCommand = cli.Command{ Flags: []cli.Flag{ cli.StringFlag{ Name: "format, f", - Value: "", + Value: "table", Usage: `select one of: ` + formatOptions, }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + // XXX: Currently not supported with rootless containers. + if isRootless() { + return fmt.Errorf("runc ps requires root") + } + container, err := getContainer(context) if err != nil { return err @@ -35,21 +43,27 @@ var psCommand = cli.Command{ return err } - if context.String("format") == "json" { - if err := json.NewEncoder(os.Stdout).Encode(pids); err != nil { - return err - } - return nil + switch context.String("format") { + case "table": + case "json": + return json.NewEncoder(os.Stdout).Encode(pids) + default: + return fmt.Errorf("invalid format option") } - psArgs := context.Args().Get(1) - if psArgs == "" { - psArgs = "-ef" + // [1:] is to remove command name, ex: + // context.Args(): [containet_id ps_arg1 ps_arg2 ...] + // psArgs: [ps_arg1 ps_arg2 ...] + // + psArgs := context.Args()[1:] + if len(psArgs) == 0 { + psArgs = []string{"-ef"} } - output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output() + cmd := exec.Command("ps", psArgs...) + output, err := cmd.CombinedOutput() if err != nil { - return err + return fmt.Errorf("%s: %s", err, output) } lines := strings.Split(string(output), "\n") @@ -78,6 +92,7 @@ var psCommand = cli.Command{ } return nil }, + SkipArgReorder: true, } func getPidIndex(title string) (int, error) { diff --git a/vendor/github.com/opencontainers/runc/restore.go b/vendor/github.com/opencontainers/runc/restore.go index 7de15242a..06f635f13 100644 --- a/vendor/github.com/opencontainers/runc/restore.go +++ b/vendor/github.com/opencontainers/runc/restore.go @@ -3,6 +3,7 @@ package main import ( + "fmt" "os" "syscall" @@ -83,6 +84,14 @@ using the runc checkpoint command.`, }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + // XXX: Currently this is untested with rootless containers. + if isRootless() { + return fmt.Errorf("runc restore requires root") + } + imagePath := context.String("image-path") id := context.Args().First() if id == "" { @@ -147,7 +156,7 @@ func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Co setManageCgroupsMode(context, options) - if err := setEmptyNsMask(context, options); err != nil { + if err = setEmptyNsMask(context, options); err != nil { return -1, err } @@ -158,29 +167,34 @@ func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Co defer destroy(container) } process := &libcontainer.Process{} - tty, err := setupIO(process, rootuid, rootgid, "", false, detach) + tty, err := setupIO(process, rootuid, rootgid, false, detach, "") if err != nil { return -1, err } - defer tty.Close() - handler := newSignalHandler(tty, !context.Bool("no-subreaper")) + + notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id) + if notifySocket != nil { + notifySocket.setupSpec(context, spec) + notifySocket.setupSocket() + } + + handler := newSignalHandler(!context.Bool("no-subreaper"), notifySocket) if err := container.Restore(process, options); err != nil { return -1, err } + // We don't need to do a tty.recvtty because config.Terminal is always false. + defer tty.Close() if err := tty.ClosePostStart(); err != nil { return -1, err } if pidFile := context.String("pid-file"); pidFile != "" { if err := createPidFile(pidFile, process); err != nil { - process.Signal(syscall.SIGKILL) - process.Wait() + _ = process.Signal(syscall.SIGKILL) + _, _ = process.Wait() return -1, err } } - if detach { - return 0, nil - } - return handler.forward(process) + return handler.forward(process, tty, detach) } func criuOptions(context *cli.Context) *libcontainer.CriuOpts { @@ -191,10 +205,12 @@ func criuOptions(context *cli.Context) *libcontainer.CriuOpts { return &libcontainer.CriuOpts{ ImagesDirectory: imagePath, WorkDirectory: context.String("work-path"), + ParentImage: context.String("parent-path"), LeaveRunning: context.Bool("leave-running"), TcpEstablished: context.Bool("tcp-established"), ExternalUnixConnections: context.Bool("ext-unix-sk"), ShellJob: context.Bool("shell-job"), FileLocks: context.Bool("file-locks"), + PreDump: context.Bool("pre-dump"), } } diff --git a/vendor/github.com/opencontainers/runc/rlimit_linux.go b/vendor/github.com/opencontainers/runc/rlimit_linux.go index 0de8b0b21..c97a0fb4e 100644 --- a/vendor/github.com/opencontainers/runc/rlimit_linux.go +++ b/vendor/github.com/opencontainers/runc/rlimit_linux.go @@ -43,7 +43,7 @@ var rlimitMap = map[string]int{ func strToRlimit(key string) (int, error) { rl, ok := rlimitMap[key] if !ok { - return 0, fmt.Errorf("Wrong rlimit value: %s", key) + return 0, fmt.Errorf("wrong rlimit value: %s", key) } return rl, nil } diff --git a/vendor/github.com/opencontainers/runc/run.go b/vendor/github.com/opencontainers/runc/run.go index 3eb63de97..ebec222ec 100644 --- a/vendor/github.com/opencontainers/runc/run.go +++ b/vendor/github.com/opencontainers/runc/run.go @@ -32,9 +32,9 @@ command(s) that get executed on start, edit the args parameter of the spec. See Usage: `path to the root of the bundle directory, defaults to the current directory`, }, cli.StringFlag{ - Name: "console", + Name: "console-socket", Value: "", - Usage: "specify the pty slave path for use with the container", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, cli.BoolFlag{ Name: "detach, d", @@ -57,8 +57,18 @@ command(s) that get executed on start, edit the args parameter of the spec. See Name: "no-new-keyring", Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", }, + cli.IntFlag{ + Name: "preserve-fds", + Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", + }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err + } spec, err := setupSpec(context) if err != nil { return err diff --git a/vendor/github.com/opencontainers/runc/signals.go b/vendor/github.com/opencontainers/runc/signals.go index 5eee44e76..d787c940b 100644 --- a/vendor/github.com/opencontainers/runc/signals.go +++ b/vendor/github.com/opencontainers/runc/signals.go @@ -17,7 +17,9 @@ const signalBufferSize = 2048 // newSignalHandler returns a signal handler for processing SIGCHLD and SIGWINCH signals // while still forwarding all other signals to the process. -func newSignalHandler(tty *tty, enableSubreaper bool) *signalHandler { +// If notifySocket is present, use it to read systemd notifications from the container and +// forward them to notifySocketHost. +func newSignalHandler(enableSubreaper bool, notifySocket *notifySocket) *signalHandler { if enableSubreaper { // set us as the subreaper before registering the signal handler for the container if err := system.SetSubreaper(1); err != nil { @@ -30,8 +32,8 @@ func newSignalHandler(tty *tty, enableSubreaper bool) *signalHandler { // handle all signals for the process. signal.Notify(s) return &signalHandler{ - tty: tty, - signals: s, + signals: s, + notifySocket: notifySocket, } } @@ -43,25 +45,39 @@ type exit struct { } type signalHandler struct { - signals chan os.Signal - tty *tty + signals chan os.Signal + notifySocket *notifySocket } // forward handles the main signal event loop forwarding, resizing, or reaping depending // on the signal received. -func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { +func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach bool) (int, error) { // make sure we know the pid of our main process so that we can return // after it dies. + if detach && h.notifySocket == nil { + return 0, nil + } + pid1, err := process.Pid() if err != nil { return -1, err } + + if h.notifySocket != nil { + if detach { + h.notifySocket.run(pid1) + return 0, nil + } else { + go h.notifySocket.run(0) + } + } + // perform the initial tty resize. - h.tty.resize() + tty.resize() for s := range h.signals { switch s { case syscall.SIGWINCH: - h.tty.resize() + tty.resize() case syscall.SIGCHLD: exits, err := h.reap() if err != nil { @@ -77,6 +93,9 @@ func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { // status because we must ensure that any of the go specific process // fun such as flushing pipes are complete before we return. process.Wait() + if h.notifySocket != nil { + h.notifySocket.Close() + } return e.status, nil } } diff --git a/vendor/github.com/opencontainers/runc/spec.go b/vendor/github.com/opencontainers/runc/spec.go index 59e47bd10..9024ad4cd 100644 --- a/vendor/github.com/opencontainers/runc/spec.go +++ b/vendor/github.com/opencontainers/runc/spec.go @@ -10,6 +10,7 @@ import ( "runtime" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/specconv" "github.com/opencontainers/runtime-spec/specs-go" "github.com/urfave/cli" ) @@ -48,9 +49,9 @@ In the run command above, "container1" is the name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host. -An alternative for generating a customized spec config is to use "ocitools", the -sub-command "ocitools generate" has lots of options that can be used to do any -customizations as you want, see [ocitools](https://github.com/opencontainers/ocitools) +An alternative for generating a customized spec config is to use "oci-runtime-tool", the +sub-command "oci-runtime-tool generate" has lots of options that can be used to do any +customizations as you want, see [runtime-tools](https://github.com/opencontainers/runtime-tools) to get more information. When starting a container through runc, runc needs root privilege. If not @@ -63,129 +64,20 @@ container on your host.`, Value: "", Usage: "path to the root of the bundle directory", }, + cli.BoolFlag{ + Name: "rootless", + Usage: "generate a configuration for a rootless container", + }, }, Action: func(context *cli.Context) error { - spec := specs.Spec{ - Version: specs.Version, - Platform: specs.Platform{ - OS: runtime.GOOS, - Arch: runtime.GOARCH, - }, - Root: specs.Root{ - Path: "rootfs", - Readonly: true, - }, - Process: specs.Process{ - Terminal: true, - User: specs.User{}, - Args: []string{ - "sh", - }, - Env: []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM=xterm", - }, - Cwd: "/", - NoNewPrivileges: true, - Capabilities: []string{ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE", - }, - Rlimits: []specs.Rlimit{ - { - Type: "RLIMIT_NOFILE", - Hard: uint64(1024), - Soft: uint64(1024), - }, - }, - }, - Hostname: "runc", - Mounts: []specs.Mount{ - { - Destination: "/proc", - Type: "proc", - Source: "proc", - Options: nil, - }, - { - Destination: "/dev", - Type: "tmpfs", - Source: "tmpfs", - Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, - }, - { - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, - }, - { - Destination: "/dev/shm", - Type: "tmpfs", - Source: "shm", - Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, - }, - { - Destination: "/dev/mqueue", - Type: "mqueue", - Source: "mqueue", - Options: []string{"nosuid", "noexec", "nodev"}, - }, - { - Destination: "/sys", - Type: "sysfs", - Source: "sysfs", - Options: []string{"nosuid", "noexec", "nodev", "ro"}, - }, - { - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, - }, - }, - Linux: specs.Linux{ - MaskedPaths: []string{ - "/proc/kcore", - "/proc/latency_stats", - "/proc/timer_stats", - "/proc/sched_debug", - }, - ReadonlyPaths: []string{ - "/proc/asound", - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger", - }, - Resources: &specs.Resources{ - Devices: []specs.DeviceCgroup{ - { - Allow: false, - Access: sPtr("rwm"), - }, - }, - }, - Namespaces: []specs.Namespace{ - { - Type: "pid", - }, - { - Type: "network", - }, - { - Type: "ipc", - }, - { - Type: "uts", - }, - { - Type: "mount", - }, - }, - }, + if err := checkArgs(context, 0, exactArgs); err != nil { + return err + } + spec := specconv.Example() + + rootless := context.Bool("rootless") + if rootless { + specconv.ToRootless(spec) } checkNoFile := func(name string) error { @@ -207,7 +99,7 @@ container on your host.`, if err := checkNoFile(specConfig); err != nil { return err } - data, err := json.MarshalIndent(&spec, "", "\t") + data, err := json.MarshalIndent(spec, "", "\t") if err != nil { return err } @@ -218,11 +110,7 @@ container on your host.`, }, } -func sPtr(s string) *string { return &s } -func rPtr(r rune) *rune { return &r } -func iPtr(i int64) *int64 { return &i } -func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } -func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } +func sPtr(s string) *string { return &s } // loadSpec loads the specification from the provided path. func loadSpec(cPath string) (spec *specs.Spec, err error) { @@ -238,17 +126,30 @@ func loadSpec(cPath string) (spec *specs.Spec, err error) { if err = json.NewDecoder(cf).Decode(&spec); err != nil { return nil, err } + if err = validatePlatform(&spec.Platform); err != nil { + return nil, err + } return spec, validateProcessSpec(&spec.Process) } -func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) { +func createLibContainerRlimit(rlimit specs.LinuxRlimit) (configs.Rlimit, error) { rl, err := strToRlimit(rlimit.Type) if err != nil { return configs.Rlimit{}, err } return configs.Rlimit{ Type: rl, - Hard: uint64(rlimit.Hard), - Soft: uint64(rlimit.Soft), + Hard: rlimit.Hard, + Soft: rlimit.Soft, }, nil } + +func validatePlatform(platform *specs.Platform) error { + if platform.OS != runtime.GOOS { + return fmt.Errorf("target os %s mismatch with current os %s", platform.OS, runtime.GOOS) + } + if platform.Arch != runtime.GOARCH { + return fmt.Errorf("target arch %s mismatch with current arch %s", platform.Arch, runtime.GOARCH) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/start.go b/vendor/github.com/opencontainers/runc/start.go index 2dd3cddbc..2bb698b20 100644 --- a/vendor/github.com/opencontainers/runc/start.go +++ b/vendor/github.com/opencontainers/runc/start.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "github.com/opencontainers/runc/libcontainer" @@ -9,14 +10,17 @@ import ( var startCommand = cli.Command{ Name: "start", - Usage: "start signals a created container to execute the user defined process", + Usage: "executes the user defined process in a created container", ArgsUsage: ` Where "" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host.`, - Description: `The start command signals the container to start the user's defined process.`, + Description: `The start command executes the user defined process in a created container.`, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -29,11 +33,11 @@ your host.`, case libcontainer.Created: return container.Exec() case libcontainer.Stopped: - return fmt.Errorf("cannot start a container that has run and stopped") + return errors.New("cannot start a container that has stopped") case libcontainer.Running: - return fmt.Errorf("cannot start an already running container") + return errors.New("cannot start an already running container") default: - return fmt.Errorf("cannot start a container in the %s state", status) + return fmt.Errorf("cannot start a container in the %s state\n", status) } }, } diff --git a/vendor/github.com/opencontainers/runc/state.go b/vendor/github.com/opencontainers/runc/state.go index 9bdb4af87..718813c36 100644 --- a/vendor/github.com/opencontainers/runc/state.go +++ b/vendor/github.com/opencontainers/runc/state.go @@ -5,35 +5,12 @@ package main import ( "encoding/json" "os" - "time" + "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/utils" "github.com/urfave/cli" ) -// cState represents the platform agnostic pieces relating to a running -// container's status and state. Note: The fields in this structure adhere to -// the opencontainers/runtime-spec/specs-go requirement for json fields that must be returned -// in a state command. -type cState struct { - // Version is the OCI version for the container - Version string `json:"ociVersion"` - // ID is the container ID - ID string `json:"id"` - // InitProcessPid is the init process id in the parent namespace - InitProcessPid int `json:"pid"` - // Bundle is the path on the filesystem to the bundle - Bundle string `json:"bundlePath"` - // Rootfs is a path to a directory containing the container's root filesystem. - Rootfs string `json:"rootfsPath"` - // Status is the current status of the container, running, paused, ... - Status string `json:"status"` - // Created is the unix timestamp for the creation time of the container in UTC - Created time.Time `json:"created"` - // Annotations is the user defined annotations added to the config. - Annotations map[string]string `json:"annotations,omitempty"` -} - var stateCommand = cli.Command{ Name: "state", Usage: "output the state of a container", @@ -43,6 +20,9 @@ Where "" is your name for the instance of the container.`, Description: `The state command outputs current state information for the instance of a container.`, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err @@ -55,11 +35,15 @@ instance of a container.`, if err != nil { return err } + pid := state.BaseState.InitProcessPid + if containerStatus == libcontainer.Stopped { + pid = 0 + } bundle, annotations := utils.Annotations(state.Config.Labels) - cs := cState{ + cs := containerState{ Version: state.BaseState.Config.Version, ID: state.BaseState.ID, - InitProcessPid: state.BaseState.InitProcessPid, + InitProcessPid: pid, Status: containerStatus.String(), Bundle: bundle, Rootfs: state.BaseState.Config.Rootfs, diff --git a/vendor/github.com/opencontainers/runc/tty.go b/vendor/github.com/opencontainers/runc/tty.go index 5a76ebe39..9824df144 100644 --- a/vendor/github.com/opencontainers/runc/tty.go +++ b/vendor/github.com/opencontainers/runc/tty.go @@ -10,11 +10,27 @@ import ( "github.com/docker/docker/pkg/term" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/utils" ) -// setup standard pipes so that the TTY of the calling runc process -// is not inherited by the container. -func createStdioPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) { +type tty struct { + console libcontainer.Console + state *term.State + closers []io.Closer + postStart []io.Closer + wg sync.WaitGroup + consoleC chan error +} + +func (t *tty) copyIO(w io.Writer, r io.ReadCloser) { + defer t.wg.Done() + io.Copy(w, r) + r.Close() +} + +// setup pipes for the process so that advanced features like c/r are able to easily checkpoint +// and restore the process's IO without depending on a host specific path or device +func setupProcessPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) { i, err := p.InitializeIO(rootuid, rootgid) if err != nil { return nil, err @@ -46,45 +62,37 @@ func createStdioPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, erro return t, nil } -func (t *tty) copyIO(w io.Writer, r io.ReadCloser) { - defer t.wg.Done() - io.Copy(w, r) - r.Close() +func inheritStdio(process *libcontainer.Process) error { + process.Stdin = os.Stdin + process.Stdout = os.Stdout + process.Stderr = os.Stderr + return nil } -func createTty(p *libcontainer.Process, rootuid, rootgid int, consolePath string) (*tty, error) { - if consolePath != "" { - if err := p.ConsoleFromPath(consolePath); err != nil { - return nil, err - } - return &tty{}, nil - } - console, err := p.NewConsole(rootuid, rootgid) +func (t *tty) recvtty(process *libcontainer.Process, socket *os.File) error { + f, err := utils.RecvFd(socket) if err != nil { - return nil, err + return err } + console := libcontainer.ConsoleFromFile(f) go io.Copy(console, os.Stdin) - go io.Copy(os.Stdout, console) - + t.wg.Add(1) + go t.copyIO(os.Stdout, console) state, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { - return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err) + return fmt.Errorf("failed to set the terminal from the stdin: %v", err) } - return &tty{ - console: console, - state: state, - closers: []io.Closer{ - console, - }, - }, nil + t.state = state + t.console = console + t.closers = []io.Closer{console} + return nil } -type tty struct { - console libcontainer.Console - state *term.State - closers []io.Closer - postStart []io.Closer - wg sync.WaitGroup +func (t *tty) waitConsole() error { + if t.consoleC != nil { + return <-t.consoleC + } + return nil } // ClosePostStart closes any fds that are provided to the container and dup2'd @@ -122,5 +130,5 @@ func (t *tty) resize() error { if err != nil { return err } - return term.SetWinsize(t.console.Fd(), ws) + return term.SetWinsize(t.console.File().Fd(), ws) } diff --git a/vendor/github.com/opencontainers/runc/update.go b/vendor/github.com/opencontainers/runc/update.go index 058211f0e..7af3a9cdf 100644 --- a/vendor/github.com/opencontainers/runc/update.go +++ b/vendor/github.com/opencontainers/runc/update.go @@ -13,6 +13,7 @@ import ( "github.com/urfave/cli" ) +func i64Ptr(i int64) *int64 { return &i } func u64Ptr(i uint64) *uint64 { return &i } func u16Ptr(i uint16) *uint16 { return &i } @@ -40,12 +41,14 @@ The accepted format is as follow (unchanged values can be omitted): "shares": 0, "quota": 0, "period": 0, + "realtimeRuntime": 0, + "realtimePeriod": 0, "cpus": "", "mems": "" }, "blockIO": { "blkioWeight": 0 - }, + } } Note: if data is to be read from a file or the standard input, all @@ -59,16 +62,24 @@ other options are ignored. }, cli.StringFlag{ Name: "cpu-period", - Usage: "CPU period to be used for hardcapping (in usecs). 0 to use system default", + Usage: "CPU CFS period to be used for hardcapping (in usecs). 0 to use system default", }, cli.StringFlag{ Name: "cpu-quota", - Usage: "CPU hardcap limit (in usecs). Allowed cpu time in a given period", + Usage: "CPU CFS hardcap limit (in usecs). Allowed cpu time in a given period", }, cli.StringFlag{ Name: "cpu-share", Usage: "CPU shares (relative weight vs. other containers)", }, + cli.StringFlag{ + Name: "cpu-rt-period", + Usage: "CPU realtime period to be used for hardcapping (in usecs). 0 to use system default", + }, + cli.StringFlag{ + Name: "cpu-rt-runtime", + Usage: "CPU realtime hardcap limit (in usecs). Allowed cpu time in a given period", + }, cli.StringFlag{ Name: "cpuset-cpus", Usage: "CPU(s) to use", @@ -99,27 +110,32 @@ other options are ignored. }, }, Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { return err } - r := specs.Resources{ - Memory: &specs.Memory{ + r := specs.LinuxResources{ + Memory: &specs.LinuxMemory{ Limit: u64Ptr(0), Reservation: u64Ptr(0), Swap: u64Ptr(0), Kernel: u64Ptr(0), KernelTCP: u64Ptr(0), }, - CPU: &specs.CPU{ - Shares: u64Ptr(0), - Quota: u64Ptr(0), - Period: u64Ptr(0), - Cpus: sPtr(""), - Mems: sPtr(""), + CPU: &specs.LinuxCPU{ + Shares: u64Ptr(0), + Quota: i64Ptr(0), + Period: u64Ptr(0), + RealtimeRuntime: i64Ptr(0), + RealtimePeriod: u64Ptr(0), + Cpus: "", + Mems: "", }, - BlockIO: &specs.BlockIO{ + BlockIO: &specs.LinuxBlockIO{ Weight: u16Ptr(0), }, } @@ -149,59 +165,86 @@ other options are ignored. r.BlockIO.Weight = u16Ptr(uint16(val)) } if val := context.String("cpuset-cpus"); val != "" { - r.CPU.Cpus = &val + r.CPU.Cpus = val } if val := context.String("cpuset-mems"); val != "" { - r.CPU.Mems = &val + r.CPU.Mems = val } - for opt, dest := range map[string]*uint64{ - "cpu-period": r.CPU.Period, - "cpu-quota": r.CPU.Quota, - "cpu-share": r.CPU.Shares, + for _, pair := range []struct { + opt string + dest *uint64 + }{ + + {"cpu-period", r.CPU.Period}, + {"cpu-rt-period", r.CPU.RealtimePeriod}, + {"cpu-share", r.CPU.Shares}, } { - if val := context.String(opt); val != "" { + if val := context.String(pair.opt); val != "" { var err error - *dest, err = strconv.ParseUint(val, 10, 64) + *pair.dest, err = strconv.ParseUint(val, 10, 64) if err != nil { - return fmt.Errorf("invalid value for %s: %s", opt, err) + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) } } } + for _, pair := range []struct { + opt string + dest *int64 + }{ - for opt, dest := range map[string]*uint64{ - "kernel-memory": r.Memory.Kernel, - "kernel-memory-tcp": r.Memory.KernelTCP, - "memory": r.Memory.Limit, - "memory-reservation": r.Memory.Reservation, - "memory-swap": r.Memory.Swap, + {"cpu-quota", r.CPU.Quota}, + {"cpu-rt-runtime", r.CPU.RealtimeRuntime}, } { - if val := context.String(opt); val != "" { - v, err := units.RAMInBytes(val) + if val := context.String(pair.opt); val != "" { + var err error + *pair.dest, err = strconv.ParseInt(val, 10, 64) if err != nil { - return fmt.Errorf("invalid value for %s: %s", opt, err) + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) } - *dest = uint64(v) + } + } + for _, pair := range []struct { + opt string + dest *uint64 + }{ + {"memory", r.Memory.Limit}, + {"memory-swap", r.Memory.Swap}, + {"kernel-memory", r.Memory.Kernel}, + {"kernel-memory-tcp", r.Memory.KernelTCP}, + {"memory-reservation", r.Memory.Reservation}, + } { + if val := context.String(pair.opt); val != "" { + var v int64 + + if val != "-1" { + v, err = units.RAMInBytes(val) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) + } + } else { + v = -1 + } + *pair.dest = uint64(v) } } } // Update the value config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight - config.Cgroups.Resources.CpuPeriod = int64(*r.CPU.Period) - config.Cgroups.Resources.CpuQuota = int64(*r.CPU.Quota) - config.Cgroups.Resources.CpuShares = int64(*r.CPU.Shares) - config.Cgroups.Resources.CpusetCpus = *r.CPU.Cpus - config.Cgroups.Resources.CpusetMems = *r.CPU.Mems - config.Cgroups.Resources.KernelMemory = int64(*r.Memory.Kernel) - config.Cgroups.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP) - config.Cgroups.Resources.Memory = int64(*r.Memory.Limit) - config.Cgroups.Resources.MemoryReservation = int64(*r.Memory.Reservation) - config.Cgroups.Resources.MemorySwap = int64(*r.Memory.Swap) + config.Cgroups.Resources.CpuPeriod = *r.CPU.Period + config.Cgroups.Resources.CpuQuota = *r.CPU.Quota + config.Cgroups.Resources.CpuShares = *r.CPU.Shares + config.Cgroups.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod + config.Cgroups.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime + config.Cgroups.Resources.CpusetCpus = r.CPU.Cpus + config.Cgroups.Resources.CpusetMems = r.CPU.Mems + config.Cgroups.Resources.KernelMemory = *r.Memory.Kernel + config.Cgroups.Resources.KernelMemoryTCP = *r.Memory.KernelTCP + config.Cgroups.Resources.Memory = *r.Memory.Limit + config.Cgroups.Resources.MemoryReservation = *r.Memory.Reservation + config.Cgroups.Resources.MemorySwap = *r.Memory.Swap - if err := container.Set(config); err != nil { - return err - } - return nil + return container.Set(config) }, } diff --git a/vendor/github.com/opencontainers/runc/utils.go b/vendor/github.com/opencontainers/runc/utils.go index 55a7e9de6..98f93a4cf 100644 --- a/vendor/github.com/opencontainers/runc/utils.go +++ b/vendor/github.com/opencontainers/runc/utils.go @@ -3,12 +3,45 @@ package main import ( "fmt" "os" + "path/filepath" "github.com/Sirupsen/logrus" "github.com/opencontainers/runtime-spec/specs-go" "github.com/urfave/cli" ) +const ( + exactArgs = iota + minArgs + maxArgs +) + +func checkArgs(context *cli.Context, expected, checkType int) error { + var err error + cmdName := context.Command.Name + switch checkType { + case exactArgs: + if context.NArg() != expected { + err = fmt.Errorf("%s: %q requires exactly %d argument(s)", os.Args[0], cmdName, expected) + } + case minArgs: + if context.NArg() < expected { + err = fmt.Errorf("%s: %q requires a minimum of %d argument(s)", os.Args[0], cmdName, expected) + } + case maxArgs: + if context.NArg() > expected { + err = fmt.Errorf("%s: %q requires a maximum of %d argument(s)", os.Args[0], cmdName, expected) + } + } + + if err != nil { + fmt.Printf("Incorrect Usage.\n\n") + cli.ShowCommandHelp(context, cmdName) + return err + } + return nil +} + // fatal prints the error's details if it is a libcontainer specific error type // then exits the program with an exit status of 1. func fatal(err error) { @@ -18,7 +51,7 @@ func fatal(err error) { os.Exit(1) } -// setupSpec performs inital setup based on the cli.Context for the container +// setupSpec performs initial setup based on the cli.Context for the container func setupSpec(context *cli.Context) (*specs.Spec, error) { bundle := context.String("bundle") if bundle != "" { @@ -30,12 +63,20 @@ func setupSpec(context *cli.Context) (*specs.Spec, error) { if err != nil { return nil, err } - notifySocket := os.Getenv("NOTIFY_SOCKET") - if notifySocket != "" { - setupSdNotify(spec, notifySocket) - } - if os.Geteuid() != 0 { - return nil, fmt.Errorf("runc should be run as root") - } return spec, nil } + +func revisePidFile(context *cli.Context) error { + pidFile := context.String("pid-file") + if pidFile == "" { + return nil + } + + // convert pid-file to an absolute path so we can write to the right + // file after chdir to bundle + pidFile, err := filepath.Abs(pidFile) + if err != nil { + return err + } + return context.Set("pid-file", pidFile) +} diff --git a/vendor/github.com/opencontainers/runc/utils_linux.go b/vendor/github.com/opencontainers/runc/utils_linux.go index 6f877ab0e..c6a8c028e 100644 --- a/vendor/github.com/opencontainers/runc/utils_linux.go +++ b/vendor/github.com/opencontainers/runc/utils_linux.go @@ -5,6 +5,7 @@ package main import ( "errors" "fmt" + "net" "os" "path/filepath" "strconv" @@ -14,7 +15,9 @@ import ( "github.com/coreos/go-systemd/activation" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" + "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/specconv" + "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" "github.com/urfave/cli" ) @@ -76,11 +79,18 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) { // TODO: fix libcontainer's API to better support uid/gid in a typesafe way. User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), Cwd: p.Cwd, - Capabilities: p.Capabilities, Label: p.SelinuxLabel, NoNewPrivileges: &p.NoNewPrivileges, AppArmorProfile: p.ApparmorProfile, } + if p.Capabilities != nil { + lp.Capabilities = &configs.Capabilities{} + lp.Capabilities.Bounding = p.Capabilities.Bounding + lp.Capabilities.Effective = p.Capabilities.Effective + lp.Capabilities.Inheritable = p.Capabilities.Inheritable + lp.Capabilities.Permitted = p.Capabilities.Permitted + lp.Capabilities.Ambient = p.Capabilities.Ambient + } for _, gid := range p.User.AdditionalGids { lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10)) } @@ -94,53 +104,62 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) { return lp, nil } -func dupStdio(process *libcontainer.Process, rootuid, rootgid int) error { - process.Stdin = os.Stdin - process.Stdout = os.Stdout - process.Stderr = os.Stderr - for _, fd := range []uintptr{ - os.Stdin.Fd(), - os.Stdout.Fd(), - os.Stderr.Fd(), - } { - if err := syscall.Fchown(int(fd), rootuid, rootgid); err != nil { - return err - } - } - return nil -} - -// If systemd is supporting sd_notify protocol, this function will add support -// for sd_notify protocol from within the container. -func setupSdNotify(spec *specs.Spec, notifySocket string) { - spec.Mounts = append(spec.Mounts, specs.Mount{Destination: notifySocket, Type: "bind", Source: notifySocket, Options: []string{"bind"}}) - spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket)) -} - func destroy(container libcontainer.Container) { if err := container.Destroy(); err != nil { logrus.Error(err) } } -// setupIO sets the proper IO on the process depending on the configuration -// If there is a nil error then there must be a non nil tty returned -func setupIO(process *libcontainer.Process, rootuid, rootgid int, console string, createTTY, detach bool) (*tty, error) { - // detach and createTty will not work unless a console path is passed - // so error out here before changing any terminal settings - if createTTY && detach && console == "" { - return nil, fmt.Errorf("cannot allocate tty if runc will detach") - } +// setupIO modifies the given process config according to the options. +func setupIO(process *libcontainer.Process, rootuid, rootgid int, createTTY, detach bool, sockpath string) (*tty, error) { if createTTY { - return createTty(process, rootuid, rootgid, console) + process.Stdin = nil + process.Stdout = nil + process.Stderr = nil + t := &tty{} + if !detach { + parent, child, err := utils.NewSockPair("console") + if err != nil { + return nil, err + } + process.ConsoleSocket = child + t.postStart = append(t.postStart, parent, child) + t.consoleC = make(chan error, 1) + go func() { + if err := t.recvtty(process, parent); err != nil { + t.consoleC <- err + } + t.consoleC <- nil + }() + } else { + // the caller of runc will handle receiving the console master + conn, err := net.Dial("unix", sockpath) + if err != nil { + return nil, err + } + uc, ok := conn.(*net.UnixConn) + if !ok { + return nil, fmt.Errorf("casting to UnixConn failed") + } + t.postStart = append(t.postStart, uc) + socket, err := uc.File() + if err != nil { + return nil, err + } + t.postStart = append(t.postStart, socket) + process.ConsoleSocket = socket + } + return t, nil } + // when runc will detach the caller provides the stdio to runc via runc's 0,1,2 + // and the container's process inherits runc's stdio. if detach { - if err := dupStdio(process, rootuid, rootgid); err != nil { + if err := inheritStdio(process); err != nil { return nil, err } return &tty{}, nil } - return createStdioPipes(process, rootuid, rootgid) + return setupProcessPipes(process, rootuid, rootgid) } // createPidFile creates a file with the processes pid inside it atomically @@ -167,6 +186,11 @@ func createPidFile(path string, process *libcontainer.Process) error { return os.Rename(tmpName, path) } +// XXX: Currently we autodetect rootless mode. +func isRootless() bool { + return os.Geteuid() != 0 +} + func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcontainer.Container, error) { config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{ CgroupName: id, @@ -174,18 +198,12 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcont NoPivotRoot: context.Bool("no-pivot"), NoNewKeyring: context.Bool("no-new-keyring"), Spec: spec, + Rootless: isRootless(), }) if err != nil { return nil, err } - if _, err := os.Stat(config.Rootfs); err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("rootfs (%q) does not exist", config.Rootfs) - } - return nil, err - } - factory, err := loadFactory(context) if err != nil { return nil, err @@ -198,13 +216,19 @@ type runner struct { shouldDestroy bool detach bool listenFDs []*os.File + preserveFDs int pidFile string - console string + consoleSocket string container libcontainer.Container create bool + notifySocket *notifySocket } func (r *runner) run(config *specs.Process) (int, error) { + if err := r.checkTerminal(config); err != nil { + r.destroy() + return -1, err + } process, err := newProcess(*config) if err != nil { r.destroy() @@ -214,55 +238,66 @@ func (r *runner) run(config *specs.Process) (int, error) { process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(r.listenFDs)), "LISTEN_PID=1") process.ExtraFiles = append(process.ExtraFiles, r.listenFDs...) } - rootuid, err := r.container.Config().HostUID() + baseFd := 3 + len(process.ExtraFiles) + for i := baseFd; i < baseFd+r.preserveFDs; i++ { + process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "PreserveFD:"+strconv.Itoa(i))) + } + rootuid, err := r.container.Config().HostRootUID() if err != nil { r.destroy() return -1, err } - rootgid, err := r.container.Config().HostGID() + rootgid, err := r.container.Config().HostRootGID() if err != nil { r.destroy() return -1, err } - tty, err := setupIO(process, rootuid, rootgid, r.console, config.Terminal, r.detach || r.create) - if err != nil { - r.destroy() - return -1, err - } - handler := newSignalHandler(tty, r.enableSubreaper) - startFn := r.container.Start + var ( + detach = r.detach || r.create + startFn = r.container.Start + ) if !r.create { startFn = r.container.Run } - if err := startFn(process); err != nil { + // Setting up IO is a two stage process. We need to modify process to deal + // with detaching containers, and then we get a tty after the container has + // started. + handler := newSignalHandler(r.enableSubreaper, r.notifySocket) + tty, err := setupIO(process, rootuid, rootgid, config.Terminal, detach, r.consoleSocket) + if err != nil { r.destroy() - tty.Close() return -1, err } - if err := tty.ClosePostStart(); err != nil { + defer tty.Close() + if err = startFn(process); err != nil { + r.destroy() + return -1, err + } + if err := tty.waitConsole(); err != nil { + r.terminate(process) + r.destroy() + return -1, err + } + if err = tty.ClosePostStart(); err != nil { r.terminate(process) r.destroy() - tty.Close() return -1, err } if r.pidFile != "" { - if err := createPidFile(r.pidFile, process); err != nil { + if err = createPidFile(r.pidFile, process); err != nil { r.terminate(process) r.destroy() - tty.Close() return -1, err } } - if r.detach || r.create { - tty.Close() - return 0, nil - } - status, err := handler.forward(process) + status, err := handler.forward(process, tty, detach) if err != nil { r.terminate(process) } + if detach { + return 0, nil + } r.destroy() - tty.Close() return status, err } @@ -273,8 +308,20 @@ func (r *runner) destroy() { } func (r *runner) terminate(p *libcontainer.Process) { - p.Signal(syscall.SIGKILL) - p.Wait() + _ = p.Signal(syscall.SIGKILL) + _, _ = p.Wait() +} + +func (r *runner) checkTerminal(config *specs.Process) error { + detach := r.detach || r.create + // Check command-line for sanity. + if detach && config.Terminal && r.consoleSocket == "" { + return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket") + } + if (!detach || !config.Terminal) && r.consoleSocket != "" { + return fmt.Errorf("cannot use console socket if runc will not detach or allocate tty") + } + return nil } func validateProcessSpec(spec *specs.Process) error { @@ -295,11 +342,21 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e if id == "" { return -1, errEmptyID } + + notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id) + if notifySocket != nil { + notifySocket.setupSpec(context, spec) + } + container, err := createContainer(context, id, spec) if err != nil { return -1, err } - detach := context.Bool("detach") + + if notifySocket != nil { + notifySocket.setupSocket() + } + // Support on-demand socket activation by passing file descriptors into the container init process. listenFDs := []*os.File{} if os.Getenv("LISTEN_FDS") != "" { @@ -310,9 +367,11 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e shouldDestroy: true, container: container, listenFDs: listenFDs, - console: context.String("console"), - detach: detach, + notifySocket: notifySocket, + consoleSocket: context.String("console-socket"), + detach: context.Bool("detach"), pidFile: context.String("pid-file"), + preserveFDs: context.Int("preserve-fds"), create: create, } return r.run(&spec.Process) diff --git a/vendor/github.com/ovh/go-ovh/LICENSE b/vendor/github.com/ovh/go-ovh/LICENSE index 874121799..d847c8afb 100644 --- a/vendor/github.com/ovh/go-ovh/LICENSE +++ b/vendor/github.com/ovh/go-ovh/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2016, OVH SAS. +Copyright (c) 2015-2017, OVH SAS. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index ee37949ad..72d5256a5 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -30,16 +30,8 @@ type Counter interface { Metric Collector - // Set is used to set the Counter to an arbitrary value. It is only used - // if you have to transfer a value from an external counter into this - // Prometheus metric. Do not use it for regular handling of a - // Prometheus counter (as it can be used to break the contract of - // monotonically increasing values). - // - // Deprecated: Use NewConstMetric to create a counter for an external - // value. A Counter should never be set. - Set(float64) - // Inc increments the counter by 1. + // Inc increments the counter by 1. Use Add to increment it by arbitrary + // non-negative values. Inc() // Add adds the given value to the counter. It panics if the value is < // 0. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 77f4b30e8..1835b16f6 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -16,20 +16,15 @@ package prometheus import ( "errors" "fmt" - "regexp" "sort" "strings" "github.com/golang/protobuf/proto" + "github.com/prometheus/common/model" dto "github.com/prometheus/client_model/go" ) -var ( - metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`) - labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") -) - // reservedLabelPrefix is a prefix which is not legal in user-supplied // label names. const reservedLabelPrefix = "__" @@ -78,7 +73,7 @@ type Desc struct { // Help string. Each Desc with the same fqName must have the same // dimHash. dimHash uint64 - // err is an error that occured during construction. It is reported on + // err is an error that occurred during construction. It is reported on // registration time. err error } @@ -103,7 +98,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * d.err = errors.New("empty help string") return d } - if !metricNameRE.MatchString(fqName) { + if !model.IsValidMetricName(model.LabelValue(fqName)) { d.err = fmt.Errorf("%q is not a valid metric name", fqName) return d } @@ -200,6 +195,6 @@ func (d *Desc) String() string { } func checkLabelName(l string) bool { - return labelNameRE.MatchString(l) && + return model.LabelName(l).IsValid() && !strings.HasPrefix(l, reservedLabelPrefix) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index b15a2d3b9..1fdef9edb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -17,7 +17,7 @@ // Pushgateway (package push). // // All exported functions and methods are safe to be used concurrently unless -//specified otherwise. +// specified otherwise. // // A Basic Example // @@ -59,7 +59,7 @@ // // The Handler function provides a default handler to expose metrics // // via an HTTP server. "/metrics" is the usual endpoint for that. // http.Handle("/metrics", promhttp.Handler()) -// http.ListenAndServe(":8080", nil) +// log.Fatal(http.ListenAndServe(":8080", nil)) // } // // @@ -69,7 +69,7 @@ // Metrics // // The number of exported identifiers in this package might appear a bit -// overwhelming. Hovever, in addition to the basic plumbing shown in the example +// overwhelming. However, in addition to the basic plumbing shown in the example // above, you only need to understand the different metric types and their // vector versions for basic usage. // @@ -95,8 +95,8 @@ // SummaryVec, HistogramVec, and UntypedVec are not. // // To create instances of Metrics and their vector versions, you need a suitable -// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, -// HistogramOpts, or UntypedOpts. +// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, HistogramOpts, or +// UntypedOpts. // // Custom Collectors and constant Metrics // @@ -114,8 +114,8 @@ // Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and // NewConstSummary (and their respective Must… versions). That will happen in // the Collect method. The Describe method has to return separate Desc -// instances, representative of the “throw-away” metrics to be created -// later. NewDesc comes in handy to create those Desc instances. +// instances, representative of the “throw-away” metrics to be created later. +// NewDesc comes in handy to create those Desc instances. // // The Collector example illustrates the use case. You can also look at the // source code of the processCollector (mirroring process metrics), the @@ -129,32 +129,32 @@ // Advanced Uses of the Registry // // While MustRegister is the by far most common way of registering a Collector, -// sometimes you might want to handle the errors the registration might -// cause. As suggested by the name, MustRegister panics if an error occurs. With -// the Register function, the error is returned and can be handled. +// sometimes you might want to handle the errors the registration might cause. +// As suggested by the name, MustRegister panics if an error occurs. With the +// Register function, the error is returned and can be handled. // // An error is returned if the registered Collector is incompatible or // inconsistent with already registered metrics. The registry aims for -// consistency of the collected metrics according to the Prometheus data -// model. Inconsistencies are ideally detected at registration time, not at -// collect time. The former will usually be detected at start-up time of a -// program, while the latter will only happen at scrape time, possibly not even -// on the first scrape if the inconsistency only becomes relevant later. That is -// the main reason why a Collector and a Metric have to describe themselves to -// the registry. +// consistency of the collected metrics according to the Prometheus data model. +// Inconsistencies are ideally detected at registration time, not at collect +// time. The former will usually be detected at start-up time of a program, +// while the latter will only happen at scrape time, possibly not even on the +// first scrape if the inconsistency only becomes relevant later. That is the +// main reason why a Collector and a Metric have to describe themselves to the +// registry. // // So far, everything we did operated on the so-called default registry, as it // can be found in the global DefaultRegistry variable. With NewRegistry, you // can create a custom registry, or you can even implement the Registerer or -// Gatherer interfaces yourself. The methods Register and Unregister work in -// the same way on a custom registry as the global functions Register and -// Unregister on the default registry. +// Gatherer interfaces yourself. The methods Register and Unregister work in the +// same way on a custom registry as the global functions Register and Unregister +// on the default registry. // -// There are a number of uses for custom registries: You can use registries -// with special properties, see NewPedanticRegistry. You can avoid global state, -// as it is imposed by the DefaultRegistry. You can use multiple registries at -// the same time to expose different metrics in different ways. You can use -// separate registries for testing purposes. +// There are a number of uses for custom registries: You can use registries with +// special properties, see NewPedanticRegistry. You can avoid global state, as +// it is imposed by the DefaultRegistry. You can use multiple registries at the +// same time to expose different metrics in different ways. You can use separate +// registries for testing purposes. // // Also note that the DefaultRegistry comes registered with a Collector for Go // runtime metrics (via NewGoCollector) and a Collector for process metrics (via @@ -166,16 +166,20 @@ // The Registry implements the Gatherer interface. The caller of the Gather // method can then expose the gathered metrics in some way. Usually, the metrics // are served via HTTP on the /metrics endpoint. That's happening in the example -// above. The tools to expose metrics via HTTP are in the promhttp -// sub-package. (The top-level functions in the prometheus package are -// deprecated.) +// above. The tools to expose metrics via HTTP are in the promhttp sub-package. +// (The top-level functions in the prometheus package are deprecated.) // // Pushing to the Pushgateway // // Function for pushing to the Pushgateway can be found in the push sub-package. // +// Graphite Bridge +// +// Functions and examples to push metrics from a Gatherer to Graphite can be +// found in the graphite sub-package. +// // Other Means of Exposition // -// More ways of exposing metrics can easily be added. Sending metrics to -// Graphite would be an example that will soon be implemented. +// More ways of exposing metrics can easily be added by following the approaches +// of the existing implementations. package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index 8b70e5141..9ab5a3d62 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -27,16 +27,21 @@ type Gauge interface { // Set sets the Gauge to an arbitrary value. Set(float64) - // Inc increments the Gauge by 1. + // Inc increments the Gauge by 1. Use Add to increment it by arbitrary + // values. Inc() - // Dec decrements the Gauge by 1. + // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary + // values. Dec() - // Add adds the given value to the Gauge. (The value can be - // negative, resulting in a decrease of the Gauge.) + // Add adds the given value to the Gauge. (The value can be negative, + // resulting in a decrease of the Gauge.) Add(float64) // Sub subtracts the given value from the Gauge. (The value can be // negative, resulting in an increase of the Gauge.) Sub(float64) + + // SetToCurrentTime sets the Gauge to the current Unix time in seconds. + SetToCurrentTime() } // GaugeOpts is an alias for Opts. See there for doc comments. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go index abc9d4ec4..f96764559 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go @@ -8,8 +8,9 @@ import ( ) type goCollector struct { - goroutines Gauge - gcDesc *Desc + goroutinesDesc *Desc + threadsDesc *Desc + gcDesc *Desc // metrics to describe and collect metrics memStatsMetrics @@ -19,11 +20,14 @@ type goCollector struct { // go process. func NewGoCollector() Collector { return &goCollector{ - goroutines: NewGauge(GaugeOpts{ - Namespace: "go", - Name: "goroutines", - Help: "Number of goroutines that currently exist.", - }), + goroutinesDesc: NewDesc( + "go_goroutines", + "Number of goroutines that currently exist.", + nil, nil), + threadsDesc: NewDesc( + "go_threads", + "Number of OS threads created", + nil, nil), gcDesc: NewDesc( "go_gc_duration_seconds", "A summary of the GC invocation durations.", @@ -48,7 +52,7 @@ func NewGoCollector() Collector { }, { desc: NewDesc( memstatNamespace("sys_bytes"), - "Number of bytes obtained by system. Sum of all system allocations.", + "Number of bytes obtained from system.", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) }, @@ -111,12 +115,12 @@ func NewGoCollector() Collector { valType: GaugeValue, }, { desc: NewDesc( - memstatNamespace("heap_released_bytes_total"), - "Total number of heap bytes released to OS.", + memstatNamespace("heap_released_bytes"), + "Number of heap bytes released to OS.", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) }, - valType: CounterValue, + valType: GaugeValue, }, { desc: NewDesc( memstatNamespace("heap_objects"), @@ -213,6 +217,14 @@ func NewGoCollector() Collector { ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 }, valType: GaugeValue, + }, { + desc: NewDesc( + memstatNamespace("gc_cpu_fraction"), + "The fraction of this program's available CPU time used by the GC since the program started.", + nil, nil, + ), + eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction }, + valType: GaugeValue, }, }, } @@ -224,9 +236,9 @@ func memstatNamespace(s string) string { // Describe returns all descriptions of the collector. func (c *goCollector) Describe(ch chan<- *Desc) { - ch <- c.goroutines.Desc() + ch <- c.goroutinesDesc + ch <- c.threadsDesc ch <- c.gcDesc - for _, i := range c.metrics { ch <- i.desc } @@ -234,8 +246,9 @@ func (c *goCollector) Describe(ch chan<- *Desc) { // Collect returns the current state of all metrics of the collector. func (c *goCollector) Collect(ch chan<- Metric) { - c.goroutines.Set(float64(runtime.NumGoroutine())) - ch <- c.goroutines + ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) + n, _ := runtime.ThreadCreateProfile(nil) + ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) var stats debug.GCStats stats.PauseQuantiles = make([]time.Duration, 5) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http.go b/vendor/github.com/prometheus/client_golang/prometheus/http.go index 67ee5ac79..d74fb4881 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/http.go @@ -62,7 +62,7 @@ func giveBuf(buf *bytes.Buffer) { // // Deprecated: Please note the issues described in the doc comment of // InstrumentHandler. You might want to consider using promhttp.Handler instead -// (which is non instrumented). +// (which is not instrumented). func Handler() http.Handler { return InstrumentHandler("prometheus", UninstrumentedHandler()) } @@ -172,6 +172,9 @@ func nowSeries(t ...time.Time) nower { // httputil.ReverseProxy is a prominent example for a handler // performing such writes. // +// - It has additional issues with HTTP/2, cf. +// https://github.com/prometheus/client_golang/issues/272. +// // Upcoming versions of this package will provide ways of instrumenting HTTP // handlers that are more flexible and have fewer issues. Please prefer direct // instrumentation in the meantime. @@ -190,6 +193,7 @@ func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWri SummaryOpts{ Subsystem: "http", ConstLabels: Labels{"handler": handlerName}, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }, handlerFunc, ) @@ -245,34 +249,52 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo }, instLabels, ) + if err := Register(reqCnt); err != nil { + if are, ok := err.(AlreadyRegisteredError); ok { + reqCnt = are.ExistingCollector.(*CounterVec) + } else { + panic(err) + } + } opts.Name = "request_duration_microseconds" opts.Help = "The HTTP request latencies in microseconds." reqDur := NewSummary(opts) + if err := Register(reqDur); err != nil { + if are, ok := err.(AlreadyRegisteredError); ok { + reqDur = are.ExistingCollector.(Summary) + } else { + panic(err) + } + } opts.Name = "request_size_bytes" opts.Help = "The HTTP request sizes in bytes." reqSz := NewSummary(opts) + if err := Register(reqSz); err != nil { + if are, ok := err.(AlreadyRegisteredError); ok { + reqSz = are.ExistingCollector.(Summary) + } else { + panic(err) + } + } opts.Name = "response_size_bytes" opts.Help = "The HTTP response sizes in bytes." resSz := NewSummary(opts) - - regReqCnt := MustRegisterOrGet(reqCnt).(*CounterVec) - regReqDur := MustRegisterOrGet(reqDur).(Summary) - regReqSz := MustRegisterOrGet(reqSz).(Summary) - regResSz := MustRegisterOrGet(resSz).(Summary) + if err := Register(resSz); err != nil { + if are, ok := err.(AlreadyRegisteredError); ok { + resSz = are.ExistingCollector.(Summary) + } else { + panic(err) + } + } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { now := time.Now() delegate := &responseWriterDelegator{ResponseWriter: w} - out := make(chan int) - urlLen := 0 - if r.URL != nil { - urlLen = len(r.URL.String()) - } - go computeApproximateRequestSize(r, out, urlLen) + out := computeApproximateRequestSize(r) _, cn := w.(http.CloseNotifier) _, fl := w.(http.Flusher) @@ -290,30 +312,44 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo method := sanitizeMethod(r.Method) code := sanitizeCode(delegate.status) - regReqCnt.WithLabelValues(method, code).Inc() - regReqDur.Observe(elapsed) - regResSz.Observe(float64(delegate.written)) - regReqSz.Observe(float64(<-out)) + reqCnt.WithLabelValues(method, code).Inc() + reqDur.Observe(elapsed) + resSz.Observe(float64(delegate.written)) + reqSz.Observe(float64(<-out)) }) } -func computeApproximateRequestSize(r *http.Request, out chan int, s int) { - s += len(r.Method) - s += len(r.Proto) - for name, values := range r.Header { - s += len(name) - for _, value := range values { - s += len(value) +func computeApproximateRequestSize(r *http.Request) <-chan int { + // Get URL length in current go routine for avoiding a race condition. + // HandlerFunc that runs in parallel may modify the URL. + s := 0 + if r.URL != nil { + s += len(r.URL.String()) + } + + out := make(chan int, 1) + + go func() { + s += len(r.Method) + s += len(r.Proto) + for name, values := range r.Header { + s += len(name) + for _, value := range values { + s += len(value) + } } - } - s += len(r.Host) + s += len(r.Host) - // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. + // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. - if r.ContentLength != -1 { - s += int(r.ContentLength) - } - out <- s + if r.ContentLength != -1 { + s += int(r.ContentLength) + } + out <- s + close(out) + }() + + return out } type responseWriterDelegator struct { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go index e31e62e78..94b2553e1 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go @@ -19,10 +19,10 @@ type processCollector struct { pid int collectFn func(chan<- Metric) pidFn func() (int, error) - cpuTotal Counter - openFDs, maxFDs Gauge - vsize, rss Gauge - startTime Gauge + cpuTotal *Desc + openFDs, maxFDs *Desc + vsize, rss *Desc + startTime *Desc } // NewProcessCollector returns a collector which exports the current state of @@ -44,40 +44,45 @@ func NewProcessCollectorPIDFn( pidFn func() (int, error), namespace string, ) Collector { + ns := "" + if len(namespace) > 0 { + ns = namespace + "_" + } + c := processCollector{ pidFn: pidFn, collectFn: func(chan<- Metric) {}, - cpuTotal: NewCounter(CounterOpts{ - Namespace: namespace, - Name: "process_cpu_seconds_total", - Help: "Total user and system CPU time spent in seconds.", - }), - openFDs: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_open_fds", - Help: "Number of open file descriptors.", - }), - maxFDs: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_max_fds", - Help: "Maximum number of open file descriptors.", - }), - vsize: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_virtual_memory_bytes", - Help: "Virtual memory size in bytes.", - }), - rss: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_resident_memory_bytes", - Help: "Resident memory size in bytes.", - }), - startTime: NewGauge(GaugeOpts{ - Namespace: namespace, - Name: "process_start_time_seconds", - Help: "Start time of the process since unix epoch in seconds.", - }), + cpuTotal: NewDesc( + ns+"process_cpu_seconds_total", + "Total user and system CPU time spent in seconds.", + nil, nil, + ), + openFDs: NewDesc( + ns+"process_open_fds", + "Number of open file descriptors.", + nil, nil, + ), + maxFDs: NewDesc( + ns+"process_max_fds", + "Maximum number of open file descriptors.", + nil, nil, + ), + vsize: NewDesc( + ns+"process_virtual_memory_bytes", + "Virtual memory size in bytes.", + nil, nil, + ), + rss: NewDesc( + ns+"process_resident_memory_bytes", + "Resident memory size in bytes.", + nil, nil, + ), + startTime: NewDesc( + ns+"process_start_time_seconds", + "Start time of the process since unix epoch in seconds.", + nil, nil, + ), } // Set up process metric collection if supported by the runtime. @@ -90,12 +95,12 @@ func NewProcessCollectorPIDFn( // Describe returns all descriptions of the collector. func (c *processCollector) Describe(ch chan<- *Desc) { - ch <- c.cpuTotal.Desc() - ch <- c.openFDs.Desc() - ch <- c.maxFDs.Desc() - ch <- c.vsize.Desc() - ch <- c.rss.Desc() - ch <- c.startTime.Desc() + ch <- c.cpuTotal + ch <- c.openFDs + ch <- c.maxFDs + ch <- c.vsize + ch <- c.rss + ch <- c.startTime } // Collect returns the current state of all metrics of the collector. @@ -117,26 +122,19 @@ func (c *processCollector) processCollect(ch chan<- Metric) { } if stat, err := p.NewStat(); err == nil { - c.cpuTotal.Set(stat.CPUTime()) - ch <- c.cpuTotal - c.vsize.Set(float64(stat.VirtualMemory())) - ch <- c.vsize - c.rss.Set(float64(stat.ResidentMemory())) - ch <- c.rss - + ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime()) + ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory())) + ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory())) if startTime, err := stat.StartTime(); err == nil { - c.startTime.Set(startTime) - ch <- c.startTime + ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime) } } if fds, err := p.FileDescriptorsLen(); err == nil { - c.openFDs.Set(float64(fds)) - ch <- c.openFDs + ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds)) } if limits, err := p.NewLimits(); err == nil { - c.maxFDs.Set(float64(limits.OpenFiles)) - ch <- c.maxFDs + ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles)) } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index 32a3986b0..8c6b5bd8e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -152,38 +152,6 @@ func MustRegister(cs ...Collector) { DefaultRegisterer.MustRegister(cs...) } -// RegisterOrGet registers the provided Collector with the DefaultRegisterer and -// returns the Collector, unless an equal Collector was registered before, in -// which case that Collector is returned. -// -// Deprecated: RegisterOrGet is merely a convenience function for the -// implementation as described in the documentation for -// AlreadyRegisteredError. As the use case is relatively rare, this function -// will be removed in a future version of this package to clean up the -// namespace. -func RegisterOrGet(c Collector) (Collector, error) { - if err := Register(c); err != nil { - if are, ok := err.(AlreadyRegisteredError); ok { - return are.ExistingCollector, nil - } - return nil, err - } - return c, nil -} - -// MustRegisterOrGet behaves like RegisterOrGet but panics instead of returning -// an error. -// -// Deprecated: This is deprecated for the same reason RegisterOrGet is. See -// there for details. -func MustRegisterOrGet(c Collector) Collector { - c, err := RegisterOrGet(c) - if err != nil { - panic(err) - } - return c -} - // Unregister removes the registration of the provided Collector from the // DefaultRegisterer. // @@ -201,25 +169,6 @@ func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) { return gf() } -// SetMetricFamilyInjectionHook replaces the DefaultGatherer with one that -// gathers from the previous DefaultGatherers but then merges the MetricFamily -// protobufs returned from the provided hook function with the MetricFamily -// protobufs returned from the original DefaultGatherer. -// -// Deprecated: This function manipulates the DefaultGatherer variable. Consider -// the implications, i.e. don't do this concurrently with any uses of the -// DefaultGatherer. In the rare cases where you need to inject MetricFamily -// protobufs directly, it is recommended to use a custom Registry and combine it -// with a custom Gatherer using the Gatherers type (see -// there). SetMetricFamilyInjectionHook only exists for compatibility reasons -// with previous versions of this package. -func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) { - DefaultGatherer = Gatherers{ - DefaultGatherer, - GathererFunc(func() ([]*dto.MetricFamily, error) { return hook(), nil }), - } -} - // AlreadyRegisteredError is returned by the Register method if the Collector to // be registered has already been registered before, or a different Collector // that collects the same metrics has been registered before. Registration fails @@ -294,7 +243,7 @@ func (r *Registry) Register(c Collector) error { }() r.mtx.Lock() defer r.mtx.Unlock() - // Coduct various tests... + // Conduct various tests... for desc := range descChan { // Is the descriptor valid at all? @@ -447,7 +396,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { // Drain metricChan in case of premature return. defer func() { - for _ = range metricChan { + for range metricChan { } }() @@ -683,7 +632,7 @@ func (s metricSorter) Less(i, j int) bool { return s[i].GetTimestampMs() < s[j].GetTimestampMs() } -// normalizeMetricFamilies returns a MetricFamily slice whith empty +// normalizeMetricFamilies returns a MetricFamily slice with empty // MetricFamilies pruned and the remaining MetricFamilies sorted by name within // the slice, with the contained Metrics sorted within each MetricFamily. func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index bce05bf9a..82b885019 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -54,6 +54,9 @@ type Summary interface { } // DefObjectives are the default Summary quantile values. +// +// Deprecated: DefObjectives will not be used as the default objectives in +// v0.10 of the library. The default Summary will have no quantiles then. var ( DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001} @@ -113,9 +116,15 @@ type SummaryOpts struct { ConstLabels Labels // Objectives defines the quantile rank estimates with their respective - // absolute error. If Objectives[q] = e, then the value reported - // for q will be the φ-quantile value for some φ between q-e and q+e. - // The default value is DefObjectives. + // absolute error. If Objectives[q] = e, then the value reported for q + // will be the φ-quantile value for some φ between q-e and q+e. The + // default value is DefObjectives. It is used if Objectives is left at + // its zero value (i.e. nil). To create a Summary without Objectives, + // set it to an empty map (i.e. map[float64]float64{}). + // + // Deprecated: Note that the current value of DefObjectives is + // deprecated. It will be replaced by an empty map in v0.10 of the + // library. Please explicitly set Objectives to the desired value. Objectives map[float64]float64 // MaxAge defines the duration for which an observation stays relevant @@ -183,7 +192,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { } } - if len(opts.Objectives) == 0 { + if opts.Objectives == nil { opts.Objectives = DefObjectives } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go new file mode 100644 index 000000000..f4cac5a0a --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -0,0 +1,74 @@ +// Copyright 2016 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 prometheus + +import "time" + +// Observer is the interface that wraps the Observe method, which is used by +// Histogram and Summary to add observations. +type Observer interface { + Observe(float64) +} + +// The ObserverFunc type is an adapter to allow the use of ordinary +// functions as Observers. If f is a function with the appropriate +// signature, ObserverFunc(f) is an Observer that calls f. +// +// This adapter is usually used in connection with the Timer type, and there are +// two general use cases: +// +// The most common one is to use a Gauge as the Observer for a Timer. +// See the "Gauge" Timer example. +// +// The more advanced use case is to create a function that dynamically decides +// which Observer to use for observing the duration. See the "Complex" Timer +// example. +type ObserverFunc func(float64) + +// Observe calls f(value). It implements Observer. +func (f ObserverFunc) Observe(value float64) { + f(value) +} + +// Timer is a helper type to time functions. Use NewTimer to create new +// instances. +type Timer struct { + begin time.Time + observer Observer +} + +// NewTimer creates a new Timer. The provided Observer is used to observe a +// duration in seconds. Timer is usually used to time a function call in the +// following way: +// func TimeMe() { +// timer := NewTimer(myHistogram) +// defer timer.ObserveDuration() +// // Do actual work. +// } +func NewTimer(o Observer) *Timer { + return &Timer{ + begin: time.Now(), + observer: o, + } +} + +// ObserveDuration records the duration passed since the Timer was created with +// NewTimer. It calls the Observe method of the Observer provided during +// construction with the duration in seconds as an argument. ObserveDuration is +// usually called with a defer statement. +func (t *Timer) ObserveDuration() { + if t.observer != nil { + t.observer.Observe(time.Since(t.begin).Seconds()) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go index 5faf7e6e3..065501d38 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go @@ -20,6 +20,11 @@ package prometheus // no type information is implied. // // To create Untyped instances, use NewUntyped. +// +// Deprecated: The Untyped type is deprecated because it doesn't make sense in +// direct instrumentation. If you need to mirror an external metric of unknown +// type (usually while writing exporters), Use MustNewConstMetric to create an +// untyped metric instance on the fly. type Untyped interface { Metric Collector diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index a944c3775..ff75ce585 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -19,6 +19,7 @@ import ( "math" "sort" "sync/atomic" + "time" dto "github.com/prometheus/client_model/go" @@ -43,7 +44,7 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality") // ValueType. This is a low-level building block used by the library to back the // implementations of Counter, Gauge, and Untyped. type value struct { - // valBits containst the bits of the represented float64 value. It has + // valBits contains the bits of the represented float64 value. It has // to go first in the struct to guarantee alignment for atomic // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG valBits uint64 @@ -80,6 +81,10 @@ func (v *value) Set(val float64) { atomic.StoreUint64(&v.valBits, math.Float64bits(val)) } +func (v *value) SetToCurrentTime() { + v.Set(float64(time.Now().UnixNano()) / 1e9) +} + func (v *value) Inc() { v.Add(1) } diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go index b72c9bede..a7a42d5ef 100644 --- a/vendor/github.com/prometheus/common/expfmt/decode.go +++ b/vendor/github.com/prometheus/common/expfmt/decode.go @@ -31,6 +31,7 @@ type Decoder interface { Decode(*dto.MetricFamily) error } +// DecodeOptions contains options used by the Decoder and in sample extraction. type DecodeOptions struct { // Timestamp is added to each value from the stream that has no explicit timestamp set. Timestamp model.Time @@ -46,10 +47,7 @@ func ResponseFormat(h http.Header) Format { return FmtUnknown } - const ( - textType = "text/plain" - jsonType = "application/json" - ) + const textType = "text/plain" switch mediatype { case ProtoType: @@ -66,22 +64,6 @@ func ResponseFormat(h http.Header) Format { return FmtUnknown } return FmtText - - case jsonType: - var prometheusAPIVersion string - - if params["schema"] == "prometheus/telemetry" && params["version"] != "" { - prometheusAPIVersion = params["version"] - } else { - prometheusAPIVersion = h.Get("X-Prometheus-API-Version") - } - - switch prometheusAPIVersion { - case "0.0.2", "": - return fmtJSON2 - default: - return FmtUnknown - } } return FmtUnknown @@ -93,8 +75,6 @@ func NewDecoder(r io.Reader, format Format) Decoder { switch format { case FmtProtoDelim: return &protoDecoder{r: r} - case fmtJSON2: - return newJSON2Decoder(r) } return &textDecoder{r: r} } @@ -107,10 +87,32 @@ type protoDecoder struct { // Decode implements the Decoder interface. func (d *protoDecoder) Decode(v *dto.MetricFamily) error { _, err := pbutil.ReadDelimited(d.r, v) - return err + if err != nil { + return err + } + if !model.IsValidMetricName(model.LabelValue(v.GetName())) { + return fmt.Errorf("invalid metric name %q", v.GetName()) + } + for _, m := range v.GetMetric() { + if m == nil { + continue + } + for _, l := range m.GetLabel() { + if l == nil { + continue + } + if !model.LabelValue(l.GetValue()).IsValid() { + return fmt.Errorf("invalid label value %q", l.GetValue()) + } + if !model.LabelName(l.GetName()).IsValid() { + return fmt.Errorf("invalid label name %q", l.GetName()) + } + } + } + return nil } -// textDecoder implements the Decoder interface for the text protcol. +// textDecoder implements the Decoder interface for the text protocol. type textDecoder struct { r io.Reader p TextParser @@ -141,6 +143,8 @@ func (d *textDecoder) Decode(v *dto.MetricFamily) error { return nil } +// SampleDecoder wraps a Decoder to extract samples from the metric families +// decoded by the wrapped Decoder. type SampleDecoder struct { Dec Decoder Opts *DecodeOptions @@ -148,37 +152,51 @@ type SampleDecoder struct { f dto.MetricFamily } +// Decode calls the Decode method of the wrapped Decoder and then extracts the +// samples from the decoded MetricFamily into the provided model.Vector. func (sd *SampleDecoder) Decode(s *model.Vector) error { - if err := sd.Dec.Decode(&sd.f); err != nil { + err := sd.Dec.Decode(&sd.f) + if err != nil { return err } - *s = extractSamples(&sd.f, sd.Opts) - return nil + *s, err = extractSamples(&sd.f, sd.Opts) + return err } -// Extract samples builds a slice of samples from the provided metric families. -func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) model.Vector { - var all model.Vector +// ExtractSamples builds a slice of samples from the provided metric +// families. If an error occurs during sample extraction, it continues to +// extract from the remaining metric families. The returned error is the last +// error that has occured. +func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) { + var ( + all model.Vector + lastErr error + ) for _, f := range fams { - all = append(all, extractSamples(f, o)...) + some, err := extractSamples(f, o) + if err != nil { + lastErr = err + continue + } + all = append(all, some...) } - return all + return all, lastErr } -func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector { +func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) { switch f.GetType() { case dto.MetricType_COUNTER: - return extractCounter(o, f) + return extractCounter(o, f), nil case dto.MetricType_GAUGE: - return extractGauge(o, f) + return extractGauge(o, f), nil case dto.MetricType_SUMMARY: - return extractSummary(o, f) + return extractSummary(o, f), nil case dto.MetricType_UNTYPED: - return extractUntyped(o, f) + return extractUntyped(o, f), nil case dto.MetricType_HISTOGRAM: - return extractHistogram(o, f) + return extractHistogram(o, f), nil } - panic("expfmt.extractSamples: unknown metric family type") + return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType()) } func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector { diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go index 392ca90ee..11839ed65 100644 --- a/vendor/github.com/prometheus/common/expfmt/encode.go +++ b/vendor/github.com/prometheus/common/expfmt/encode.go @@ -18,9 +18,9 @@ import ( "io" "net/http" - "bitbucket.org/ww/goautoneg" "github.com/golang/protobuf/proto" "github.com/matttproud/golang_protobuf_extensions/pbutil" + "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" dto "github.com/prometheus/client_model/go" ) diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go index 366fbde98..371ac7503 100644 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go @@ -11,14 +11,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// A package for reading and writing Prometheus metrics. +// Package expfmt contains tools for reading and writing Prometheus metrics. package expfmt +// Format specifies the HTTP content type of the different wire protocols. type Format string +// Constants to assemble the Content-Type values for the different wire protocols. const ( - TextVersion = "0.0.4" - + TextVersion = "0.0.4" ProtoType = `application/vnd.google.protobuf` ProtoProtocol = `io.prometheus.client.MetricFamily` ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" @@ -29,9 +30,6 @@ const ( FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` FmtProtoText Format = ProtoFmt + ` encoding=text` FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` - - // fmtJSON2 is hidden as it is deprecated. - fmtJSON2 Format = `application/json; version=0.0.2` ) const ( diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go index 14f920146..dc2eedeef 100644 --- a/vendor/github.com/prometheus/common/expfmt/fuzz.go +++ b/vendor/github.com/prometheus/common/expfmt/fuzz.go @@ -20,8 +20,8 @@ import "bytes" // Fuzz text metric parser with with github.com/dvyukov/go-fuzz: // -// go-fuzz-build github.com/prometheus/client_golang/text -// go-fuzz -bin text-fuzz.zip -workdir fuzz +// go-fuzz-build github.com/prometheus/common/expfmt +// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz // // Further input samples should go in the folder fuzz/corpus. func Fuzz(in []byte) int { diff --git a/vendor/github.com/prometheus/common/expfmt/json_decode.go b/vendor/github.com/prometheus/common/expfmt/json_decode.go deleted file mode 100644 index 67e3a0d4d..000000000 --- a/vendor/github.com/prometheus/common/expfmt/json_decode.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2015 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 expfmt - -import ( - "encoding/json" - "fmt" - "io" - "sort" - - "github.com/golang/protobuf/proto" - dto "github.com/prometheus/client_model/go" - - "github.com/prometheus/common/model" -) - -type json2Decoder struct { - dec *json.Decoder - fams []*dto.MetricFamily -} - -func newJSON2Decoder(r io.Reader) Decoder { - return &json2Decoder{ - dec: json.NewDecoder(r), - } -} - -type histogram002 struct { - Labels model.LabelSet `json:"labels"` - Values map[string]float64 `json:"value"` -} - -type counter002 struct { - Labels model.LabelSet `json:"labels"` - Value float64 `json:"value"` -} - -func protoLabelSet(base, ext model.LabelSet) []*dto.LabelPair { - labels := base.Clone().Merge(ext) - delete(labels, model.MetricNameLabel) - - names := make([]string, 0, len(labels)) - for ln := range labels { - names = append(names, string(ln)) - } - sort.Strings(names) - - pairs := make([]*dto.LabelPair, 0, len(labels)) - - for _, ln := range names { - lv := labels[model.LabelName(ln)] - - pairs = append(pairs, &dto.LabelPair{ - Name: proto.String(ln), - Value: proto.String(string(lv)), - }) - } - - return pairs -} - -func (d *json2Decoder) more() error { - var entities []struct { - BaseLabels model.LabelSet `json:"baseLabels"` - Docstring string `json:"docstring"` - Metric struct { - Type string `json:"type"` - Values json.RawMessage `json:"value"` - } `json:"metric"` - } - - if err := d.dec.Decode(&entities); err != nil { - return err - } - for _, e := range entities { - f := &dto.MetricFamily{ - Name: proto.String(string(e.BaseLabels[model.MetricNameLabel])), - Help: proto.String(e.Docstring), - Type: dto.MetricType_UNTYPED.Enum(), - Metric: []*dto.Metric{}, - } - - d.fams = append(d.fams, f) - - switch e.Metric.Type { - case "counter", "gauge": - var values []counter002 - - if err := json.Unmarshal(e.Metric.Values, &values); err != nil { - return fmt.Errorf("could not extract %s value: %s", e.Metric.Type, err) - } - - for _, ctr := range values { - f.Metric = append(f.Metric, &dto.Metric{ - Label: protoLabelSet(e.BaseLabels, ctr.Labels), - Untyped: &dto.Untyped{ - Value: proto.Float64(ctr.Value), - }, - }) - } - - case "histogram": - var values []histogram002 - - if err := json.Unmarshal(e.Metric.Values, &values); err != nil { - return fmt.Errorf("could not extract %s value: %s", e.Metric.Type, err) - } - - for _, hist := range values { - quants := make([]string, 0, len(values)) - for q := range hist.Values { - quants = append(quants, q) - } - - sort.Strings(quants) - - for _, q := range quants { - value := hist.Values[q] - // The correct label is "quantile" but to not break old expressions - // this remains "percentile" - hist.Labels["percentile"] = model.LabelValue(q) - - f.Metric = append(f.Metric, &dto.Metric{ - Label: protoLabelSet(e.BaseLabels, hist.Labels), - Untyped: &dto.Untyped{ - Value: proto.Float64(value), - }, - }) - } - } - - default: - return fmt.Errorf("unknown metric type %q", e.Metric.Type) - } - } - return nil -} - -// Decode implements the Decoder interface. -func (d *json2Decoder) Decode(v *dto.MetricFamily) error { - if len(d.fams) == 0 { - if err := d.more(); err != nil { - return err - } - } - - *v = *d.fams[0] - d.fams = d.fams[1:] - - return nil -} diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go index 0bb9c14cc..f11321cd0 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_create.go +++ b/vendor/github.com/prometheus/common/expfmt/text_create.go @@ -14,7 +14,6 @@ package expfmt import ( - "bytes" "fmt" "io" "math" @@ -26,9 +25,12 @@ import ( // MetricFamilyToText converts a MetricFamily proto message into text format and // writes the resulting lines to 'out'. It returns the number of bytes written -// and any error encountered. This function does not perform checks on the -// content of the metric and label names, i.e. invalid metric or label names +// and any error encountered. The output will have the same order as the input, +// no further sorting is performed. Furthermore, this function assumes the input +// is already sanitized and does not perform any sanity checks. If the input +// contains duplicate metrics or invalid metric or label names, the conversion // will result in invalid text format output. +// // This method fulfills the type 'prometheus.encoder'. func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { var written int @@ -285,21 +287,17 @@ func labelPairsToText( return written, nil } +var ( + escape = strings.NewReplacer("\\", `\\`, "\n", `\n`) + escapeWithDoubleQuote = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`) +) + // escapeString replaces '\' by '\\', new line character by '\n', and - if // includeDoubleQuote is true - '"' by '\"'. func escapeString(v string, includeDoubleQuote bool) string { - result := bytes.NewBuffer(make([]byte, 0, len(v))) - for _, c := range v { - switch { - case c == '\\': - result.WriteString(`\\`) - case includeDoubleQuote && c == '"': - result.WriteString(`\"`) - case c == '\n': - result.WriteString(`\n`) - default: - result.WriteRune(c) - } + if includeDoubleQuote { + return escapeWithDoubleQuote.Replace(v) } - return result.String() + + return escape.Replace(v) } diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go index 84433bc4f..ef9a15077 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go @@ -47,7 +47,7 @@ func (e ParseError) Error() string { } // TextParser is used to parse the simple and flat text-based exchange format. Its -// nil value is ready to use. +// zero value is ready to use. type TextParser struct { metricFamiliesByName map[string]*dto.MetricFamily buf *bufio.Reader // Where the parsed input is read through. @@ -108,6 +108,13 @@ func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricF delete(p.metricFamiliesByName, k) } } + // If p.err is io.EOF now, we have run into a premature end of the input + // stream. Turn this error into something nicer and more + // meaningful. (io.EOF is often used as a signal for the legitimate end + // of an input stream.) + if p.err == io.EOF { + p.parseError("unexpected end of input stream") + } return p.metricFamiliesByName, p.err } diff --git a/vendor/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go similarity index 100% rename from vendor/bitbucket.org/ww/goautoneg/autoneg.go rename to vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go diff --git a/vendor/github.com/prometheus/common/model/alert.go b/vendor/github.com/prometheus/common/model/alert.go index b027e9f3d..35e739c7a 100644 --- a/vendor/github.com/prometheus/common/model/alert.go +++ b/vendor/github.com/prometheus/common/model/alert.go @@ -35,8 +35,9 @@ type Alert struct { Annotations LabelSet `json:"annotations"` // The known time range for this alert. Both ends are optional. - StartsAt time.Time `json:"startsAt,omitempty"` - EndsAt time.Time `json:"endsAt,omitempty"` + StartsAt time.Time `json:"startsAt,omitempty"` + EndsAt time.Time `json:"endsAt,omitempty"` + GeneratorURL string `json:"generatorURL"` } // Name returns the name of the alert. It is equivalent to the "alertname" label. @@ -60,10 +61,16 @@ func (a *Alert) String() string { // Resolved returns true iff the activity interval ended in the past. func (a *Alert) Resolved() bool { + return a.ResolvedAt(time.Now()) +} + +// ResolvedAt returns true off the activity interval ended before +// the given timestamp. +func (a *Alert) ResolvedAt(ts time.Time) bool { if a.EndsAt.IsZero() { return false } - return !a.EndsAt.After(time.Now()) + return !a.EndsAt.After(ts) } // Status returns the status of the alert. @@ -74,6 +81,26 @@ func (a *Alert) Status() AlertStatus { return AlertFiring } +// Validate checks whether the alert data is inconsistent. +func (a *Alert) Validate() error { + if a.StartsAt.IsZero() { + return fmt.Errorf("start time missing") + } + if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) { + return fmt.Errorf("start time must be before end time") + } + if err := a.Labels.Validate(); err != nil { + return fmt.Errorf("invalid label set: %s", err) + } + if len(a.Labels) == 0 { + return fmt.Errorf("at least one label pair required") + } + if err := a.Annotations.Validate(); err != nil { + return fmt.Errorf("invalid annotations: %s", err) + } + return nil +} + // Alert is a list of alerts that can be sorted in chronological order. type Alerts []*Alert diff --git a/vendor/github.com/prometheus/common/model/fnv.go b/vendor/github.com/prometheus/common/model/fnv.go new file mode 100644 index 000000000..038fc1c90 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/fnv.go @@ -0,0 +1,42 @@ +// Copyright 2015 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 model + +// Inline and byte-free variant of hash/fnv's fnv64a. + +const ( + offset64 = 14695981039346656037 + prime64 = 1099511628211 +) + +// hashNew initializies a new fnv64a hash value. +func hashNew() uint64 { + return offset64 +} + +// hashAdd adds a string to a fnv64a hash value, returning the updated hash. +func hashAdd(h uint64, s string) uint64 { + for i := 0; i < len(s); i++ { + h ^= uint64(s[i]) + h *= prime64 + } + return h +} + +// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. +func hashAddByte(h uint64, b byte) uint64 { + h ^= uint64(b) + h *= prime64 + return h +} diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go index 6459c8f79..41051a01a 100644 --- a/vendor/github.com/prometheus/common/model/labels.go +++ b/vendor/github.com/prometheus/common/model/labels.go @@ -17,8 +17,8 @@ import ( "encoding/json" "fmt" "regexp" - "sort" "strings" + "unicode/utf8" ) const ( @@ -80,20 +80,37 @@ const ( QuantileLabel = "quantile" ) -// LabelNameRE is a regular expression matching valid label names. +// LabelNameRE is a regular expression matching valid label names. Note that the +// IsValid method of LabelName performs the same check but faster than a match +// with this regular expression. var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") // A LabelName is a key for a LabelSet or Metric. It has a value associated // therewith. type LabelName string +// IsValid is true iff the label name matches the pattern of LabelNameRE. This +// method, however, does not use LabelNameRE for the check but a much faster +// hardcoded implementation. +func (ln LabelName) IsValid() bool { + if len(ln) == 0 { + return false + } + for i, b := range ln { + if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { + return false + } + } + return true +} + // UnmarshalYAML implements the yaml.Unmarshaler interface. func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string if err := unmarshal(&s); err != nil { return err } - if !LabelNameRE.MatchString(s) { + if !LabelName(s).IsValid() { return fmt.Errorf("%q is not a valid label name", s) } *ln = LabelName(s) @@ -106,7 +123,7 @@ func (ln *LabelName) UnmarshalJSON(b []byte) error { if err := json.Unmarshal(b, &s); err != nil { return err } - if !LabelNameRE.MatchString(s) { + if !LabelName(s).IsValid() { return fmt.Errorf("%q is not a valid label name", s) } *ln = LabelName(s) @@ -139,6 +156,11 @@ func (l LabelNames) String() string { // A LabelValue is an associated value for a LabelName. type LabelValue string +// IsValid returns true iff the string is a valid UTF8. +func (lv LabelValue) IsValid() bool { + return utf8.ValidString(string(lv)) +} + // LabelValues is a sortable LabelValue slice. It implements sort.Interface. type LabelValues []LabelValue @@ -147,7 +169,7 @@ func (l LabelValues) Len() int { } func (l LabelValues) Less(i, j int) bool { - return sort.StringsAreSorted([]string{string(l[i]), string(l[j])}) + return string(l[i]) < string(l[j]) } func (l LabelValues) Swap(i, j int) { diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go index 142b9d1e2..6eda08a73 100644 --- a/vendor/github.com/prometheus/common/model/labelset.go +++ b/vendor/github.com/prometheus/common/model/labelset.go @@ -27,6 +27,21 @@ import ( // match. type LabelSet map[LabelName]LabelValue +// Validate checks whether all names and values in the label set +// are valid. +func (ls LabelSet) Validate() error { + for ln, lv := range ls { + if !ln.IsValid() { + return fmt.Errorf("invalid name %q", ln) + } + if !lv.IsValid() { + return fmt.Errorf("invalid value %q", lv) + } + } + return nil +} + +// Equal returns true iff both label sets have exactly the same key/value pairs. func (ls LabelSet) Equal(o LabelSet) bool { if len(ls) != len(o) { return false @@ -90,6 +105,7 @@ func (ls LabelSet) Before(o LabelSet) bool { return false } +// Clone returns a copy of the label set. func (ls LabelSet) Clone() LabelSet { lsn := make(LabelSet, len(ls)) for ln, lv := range ls { @@ -144,7 +160,7 @@ func (l *LabelSet) UnmarshalJSON(b []byte) error { // LabelName as a string and does not call its UnmarshalJSON method. // Thus, we have to replicate the behavior here. for ln := range m { - if !LabelNameRE.MatchString(string(ln)) { + if !ln.IsValid() { return fmt.Errorf("%q is not a valid label name", ln) } } diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index 25fc3c942..f7250909b 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -15,11 +15,18 @@ package model import ( "fmt" + "regexp" "sort" "strings" ) -var separator = []byte{0} +var ( + separator = []byte{0} + // MetricNameRE is a regular expression matching valid metric + // names. Note that the IsValidMetricName function performs the same + // check but faster than a match with this regular expression. + MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) +) // A Metric is similar to a LabelSet, but the key difference is that a Metric is // a singleton and refers to one and only one stream of samples. @@ -37,7 +44,7 @@ func (m Metric) Before(o Metric) bool { // Clone returns a copy of the Metric. func (m Metric) Clone() Metric { - clone := Metric{} + clone := make(Metric, len(m)) for k, v := range m { clone[k] = v } @@ -79,3 +86,18 @@ func (m Metric) Fingerprint() Fingerprint { func (m Metric) FastFingerprint() Fingerprint { return LabelSet(m).FastFingerprint() } + +// IsValidMetricName returns true iff name matches the pattern of MetricNameRE. +// This function, however, does not use MetricNameRE for the check but a much +// faster hardcoded implementation. +func IsValidMetricName(n LabelValue) bool { + if len(n) == 0 { + return false + } + for i, b := range n { + if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) { + return false + } + } + return true +} diff --git a/vendor/github.com/prometheus/common/model/model.go b/vendor/github.com/prometheus/common/model/model.go index 88f013a47..a7b969170 100644 --- a/vendor/github.com/prometheus/common/model/model.go +++ b/vendor/github.com/prometheus/common/model/model.go @@ -12,5 +12,5 @@ // limitations under the License. // Package model contains common data structures that are shared across -// Prometheus componenets and libraries. +// Prometheus components and libraries. package model diff --git a/vendor/github.com/prometheus/common/model/signature.go b/vendor/github.com/prometheus/common/model/signature.go index 28f370065..8762b13c6 100644 --- a/vendor/github.com/prometheus/common/model/signature.go +++ b/vendor/github.com/prometheus/common/model/signature.go @@ -14,11 +14,7 @@ package model import ( - "bytes" - "hash" - "hash/fnv" "sort" - "sync" ) // SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is @@ -28,30 +24,9 @@ const SeparatorByte byte = 255 var ( // cache the signature of an empty label set. - emptyLabelSignature = fnv.New64a().Sum64() - - hashAndBufPool sync.Pool + emptyLabelSignature = hashNew() ) -type hashAndBuf struct { - h hash.Hash64 - b bytes.Buffer -} - -func getHashAndBuf() *hashAndBuf { - hb := hashAndBufPool.Get() - if hb == nil { - return &hashAndBuf{h: fnv.New64a()} - } - return hb.(*hashAndBuf) -} - -func putHashAndBuf(hb *hashAndBuf) { - hb.h.Reset() - hb.b.Reset() - hashAndBufPool.Put(hb) -} - // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a // given label set. (Collisions are possible but unlikely if the number of label // sets the function is applied to is small.) @@ -66,18 +41,14 @@ func LabelsToSignature(labels map[string]string) uint64 { } sort.Strings(labelNames) - hb := getHashAndBuf() - defer putHashAndBuf(hb) - + sum := hashNew() for _, labelName := range labelNames { - hb.b.WriteString(labelName) - hb.b.WriteByte(SeparatorByte) - hb.b.WriteString(labels[labelName]) - hb.b.WriteByte(SeparatorByte) - hb.h.Write(hb.b.Bytes()) - hb.b.Reset() + sum = hashAdd(sum, labelName) + sum = hashAddByte(sum, SeparatorByte) + sum = hashAdd(sum, labels[labelName]) + sum = hashAddByte(sum, SeparatorByte) } - return hb.h.Sum64() + return sum } // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as @@ -93,18 +64,14 @@ func labelSetToFingerprint(ls LabelSet) Fingerprint { } sort.Sort(labelNames) - hb := getHashAndBuf() - defer putHashAndBuf(hb) - + sum := hashNew() for _, labelName := range labelNames { - hb.b.WriteString(string(labelName)) - hb.b.WriteByte(SeparatorByte) - hb.b.WriteString(string(ls[labelName])) - hb.b.WriteByte(SeparatorByte) - hb.h.Write(hb.b.Bytes()) - hb.b.Reset() + sum = hashAdd(sum, string(labelName)) + sum = hashAddByte(sum, SeparatorByte) + sum = hashAdd(sum, string(ls[labelName])) + sum = hashAddByte(sum, SeparatorByte) } - return Fingerprint(hb.h.Sum64()) + return Fingerprint(sum) } // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a @@ -116,17 +83,12 @@ func labelSetToFastFingerprint(ls LabelSet) Fingerprint { } var result uint64 - hb := getHashAndBuf() - defer putHashAndBuf(hb) - for labelName, labelValue := range ls { - hb.b.WriteString(string(labelName)) - hb.b.WriteByte(SeparatorByte) - hb.b.WriteString(string(labelValue)) - hb.h.Write(hb.b.Bytes()) - result ^= hb.h.Sum64() - hb.h.Reset() - hb.b.Reset() + sum := hashNew() + sum = hashAdd(sum, string(labelName)) + sum = hashAddByte(sum, SeparatorByte) + sum = hashAdd(sum, string(labelValue)) + result ^= sum } return Fingerprint(result) } @@ -136,24 +98,20 @@ func labelSetToFastFingerprint(ls LabelSet) Fingerprint { // specified LabelNames into the signature calculation. The labels passed in // will be sorted by this function. func SignatureForLabels(m Metric, labels ...LabelName) uint64 { - if len(m) == 0 || len(labels) == 0 { + if len(labels) == 0 { return emptyLabelSignature } sort.Sort(LabelNames(labels)) - hb := getHashAndBuf() - defer putHashAndBuf(hb) - + sum := hashNew() for _, label := range labels { - hb.b.WriteString(string(label)) - hb.b.WriteByte(SeparatorByte) - hb.b.WriteString(string(m[label])) - hb.b.WriteByte(SeparatorByte) - hb.h.Write(hb.b.Bytes()) - hb.b.Reset() + sum = hashAdd(sum, string(label)) + sum = hashAddByte(sum, SeparatorByte) + sum = hashAdd(sum, string(m[label])) + sum = hashAddByte(sum, SeparatorByte) } - return hb.h.Sum64() + return sum } // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as @@ -175,16 +133,12 @@ func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 { } sort.Sort(labelNames) - hb := getHashAndBuf() - defer putHashAndBuf(hb) - + sum := hashNew() for _, labelName := range labelNames { - hb.b.WriteString(string(labelName)) - hb.b.WriteByte(SeparatorByte) - hb.b.WriteString(string(m[labelName])) - hb.b.WriteByte(SeparatorByte) - hb.h.Write(hb.b.Bytes()) - hb.b.Reset() + sum = hashAdd(sum, string(labelName)) + sum = hashAddByte(sum, SeparatorByte) + sum = hashAdd(sum, string(m[labelName])) + sum = hashAddByte(sum, SeparatorByte) } - return hb.h.Sum64() + return sum } diff --git a/vendor/github.com/prometheus/common/model/silence.go b/vendor/github.com/prometheus/common/model/silence.go index b4b96eae9..7538e2997 100644 --- a/vendor/github.com/prometheus/common/model/silence.go +++ b/vendor/github.com/prometheus/common/model/silence.go @@ -44,6 +44,21 @@ func (m *Matcher) UnmarshalJSON(b []byte) error { return nil } +// Validate returns true iff all fields of the matcher have valid values. +func (m *Matcher) Validate() error { + if !m.Name.IsValid() { + return fmt.Errorf("invalid name %q", m.Name) + } + if m.IsRegex { + if _, err := regexp.Compile(m.Value); err != nil { + return fmt.Errorf("invalid regular expression %q", m.Value) + } + } else if !LabelValue(m.Value).IsValid() || len(m.Value) == 0 { + return fmt.Errorf("invalid value %q", m.Value) + } + return nil +} + // Silence defines the representation of a silence definiton // in the Prometheus eco-system. type Silence struct { @@ -58,3 +73,34 @@ type Silence struct { CreatedBy string `json:"createdBy"` Comment string `json:"comment,omitempty"` } + +// Validate returns true iff all fields of the silence have valid values. +func (s *Silence) Validate() error { + if len(s.Matchers) == 0 { + return fmt.Errorf("at least one matcher required") + } + for _, m := range s.Matchers { + if err := m.Validate(); err != nil { + return fmt.Errorf("invalid matcher: %s", err) + } + } + if s.StartsAt.IsZero() { + return fmt.Errorf("start time missing") + } + if s.EndsAt.IsZero() { + return fmt.Errorf("end time missing") + } + if s.EndsAt.Before(s.StartsAt) { + return fmt.Errorf("start time must be before end time") + } + if s.CreatedBy == "" { + return fmt.Errorf("creator information missing") + } + if s.Comment == "" { + return fmt.Errorf("comment missing") + } + if s.CreatedAt.IsZero() { + return fmt.Errorf("creation timestamp missing") + } + return nil +} diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index ebc8bf6cc..548968aeb 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -163,51 +163,70 @@ func (t *Time) UnmarshalJSON(b []byte) error { // This type should not propagate beyond the scope of input/output processing. type Duration time.Duration +var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") + // StringToDuration parses a string into a time.Duration, assuming that a year -// a day always has 24h. +// always has 365d, a week always has 7d, and a day always has 24h. func ParseDuration(durationStr string) (Duration, error) { matches := durationRE.FindStringSubmatch(durationStr) if len(matches) != 3 { return 0, fmt.Errorf("not a valid duration string: %q", durationStr) } - durSeconds, _ := strconv.Atoi(matches[1]) - dur := time.Duration(durSeconds) * time.Second - unit := matches[2] - switch unit { + var ( + n, _ = strconv.Atoi(matches[1]) + dur = time.Duration(n) * time.Millisecond + ) + switch unit := matches[2]; unit { + case "y": + dur *= 1000 * 60 * 60 * 24 * 365 + case "w": + dur *= 1000 * 60 * 60 * 24 * 7 case "d": - dur *= 60 * 60 * 24 + dur *= 1000 * 60 * 60 * 24 case "h": - dur *= 60 * 60 + dur *= 1000 * 60 * 60 case "m": - dur *= 60 + dur *= 1000 * 60 case "s": - dur *= 1 + dur *= 1000 + case "ms": + // Value already correct default: return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) } return Duration(dur), nil } -var durationRE = regexp.MustCompile("^([0-9]+)([ywdhms]+)$") - func (d Duration) String() string { - seconds := int64(time.Duration(d) / time.Second) + var ( + ms = int64(time.Duration(d) / time.Millisecond) + unit = "ms" + ) factors := map[string]int64{ - "d": 60 * 60 * 24, - "h": 60 * 60, - "m": 60, - "s": 1, + "y": 1000 * 60 * 60 * 24 * 365, + "w": 1000 * 60 * 60 * 24 * 7, + "d": 1000 * 60 * 60 * 24, + "h": 1000 * 60 * 60, + "m": 1000 * 60, + "s": 1000, + "ms": 1, } - unit := "s" + switch int64(0) { - case seconds % factors["d"]: + case ms % factors["y"]: + unit = "y" + case ms % factors["w"]: + unit = "w" + case ms % factors["d"]: unit = "d" - case seconds % factors["h"]: + case ms % factors["h"]: unit = "h" - case seconds % factors["m"]: + case ms % factors["m"]: unit = "m" + case ms % factors["s"]: + unit = "s" } - return fmt.Sprintf("%v%v", seconds/factors[unit], unit) + return fmt.Sprintf("%v%v", ms/factors[unit], unit) } // MarshalYAML implements the yaml.Marshaler interface. diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go index 10ffb0bd6..c9ed3ffd8 100644 --- a/vendor/github.com/prometheus/common/model/value.go +++ b/vendor/github.com/prometheus/common/model/value.go @@ -16,11 +16,28 @@ package model import ( "encoding/json" "fmt" + "math" "sort" "strconv" "strings" ) +var ( + // ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a + // non-existing sample pair. It is a SamplePair with timestamp Earliest and + // value 0.0. Note that the natural zero value of SamplePair has a timestamp + // of 0, which is possible to appear in a real SamplePair and thus not + // suitable to signal a non-existing SamplePair. + ZeroSamplePair = SamplePair{Timestamp: Earliest} + + // ZeroSample is the pseudo zero-value of Sample used to signal a + // non-existing sample. It is a Sample with timestamp Earliest, value 0.0, + // and metric nil. Note that the natural zero value of Sample has a timestamp + // of 0, which is possible to appear in a real Sample and thus not suitable + // to signal a non-existing Sample. + ZeroSample = Sample{Timestamp: Earliest} +) + // A SampleValue is a representation of a value for a given sample at a given // time. type SampleValue float64 @@ -43,8 +60,14 @@ func (v *SampleValue) UnmarshalJSON(b []byte) error { return nil } +// Equal returns true if the value of v and o is equal or if both are NaN. Note +// that v==o is false if both are NaN. If you want the conventional float +// behavior, use == to compare two SampleValues. func (v SampleValue) Equal(o SampleValue) bool { - return v == o + if v == o { + return true + } + return math.IsNaN(float64(v)) && math.IsNaN(float64(o)) } func (v SampleValue) String() string { @@ -77,9 +100,9 @@ func (s *SamplePair) UnmarshalJSON(b []byte) error { } // Equal returns true if this SamplePair and o have equal Values and equal -// Timestamps. +// Timestamps. The sematics of Value equality is defined by SampleValue.Equal. func (s *SamplePair) Equal(o *SamplePair) bool { - return s == o || (s.Value == o.Value && s.Timestamp.Equal(o.Timestamp)) + return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp)) } func (s SamplePair) String() string { @@ -93,7 +116,8 @@ type Sample struct { Timestamp Time `json:"timestamp"` } -// Equal compares first the metrics, then the timestamp, then the value. +// Equal compares first the metrics, then the timestamp, then the value. The +// sematics of value equality is defined by SampleValue.Equal. func (s *Sample) Equal(o *Sample) bool { if s == o { return true @@ -105,11 +129,8 @@ func (s *Sample) Equal(o *Sample) bool { if !s.Timestamp.Equal(o.Timestamp) { return false } - if s.Value != o.Value { - return false - } - return true + return s.Value.Equal(o.Value) } func (s Sample) String() string { diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go new file mode 100644 index 000000000..680a9842a --- /dev/null +++ b/vendor/github.com/prometheus/procfs/buddyinfo.go @@ -0,0 +1,95 @@ +// Copyright 2017 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 procfs + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" +) + +// A BuddyInfo is the details parsed from /proc/buddyinfo. +// The data is comprised of an array of free fragments of each size. +// The sizes are 2^n*PAGE_SIZE, where n is the array index. +type BuddyInfo struct { + Node string + Zone string + Sizes []float64 +} + +// NewBuddyInfo reads the buddyinfo statistics. +func NewBuddyInfo() ([]BuddyInfo, error) { + fs, err := NewFS(DefaultMountPoint) + if err != nil { + return nil, err + } + + return fs.NewBuddyInfo() +} + +// NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. +func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) { + file, err := os.Open(fs.Path("buddyinfo")) + if err != nil { + return nil, err + } + defer file.Close() + + return parseBuddyInfo(file) +} + +func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { + var ( + buddyInfo = []BuddyInfo{} + scanner = bufio.NewScanner(r) + bucketCount = -1 + ) + + for scanner.Scan() { + var err error + line := scanner.Text() + parts := strings.Fields(string(line)) + + if len(parts) < 4 { + return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") + } + + node := strings.TrimRight(parts[1], ",") + zone := strings.TrimRight(parts[3], ",") + arraySize := len(parts[4:]) + + if bucketCount == -1 { + bucketCount = arraySize + } else { + if bucketCount != arraySize { + return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize) + } + } + + sizes := make([]float64, arraySize) + for i := 0; i < arraySize; i++ { + sizes[i], err = strconv.ParseFloat(parts[i+4], 64) + if err != nil { + return nil, fmt.Errorf("invalid value in buddyinfo: %s", err) + } + } + + buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes}) + } + + return buddyInfo, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go index 6a8d97b11..17546756b 100644 --- a/vendor/github.com/prometheus/procfs/fs.go +++ b/vendor/github.com/prometheus/procfs/fs.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "path" + + "github.com/prometheus/procfs/xfs" ) // FS represents the pseudo-filesystem proc, which provides an interface to @@ -27,14 +29,18 @@ func NewFS(mountPoint string) (FS, error) { return FS(mountPoint), nil } -func (fs FS) stat(p string) (os.FileInfo, error) { - return os.Stat(path.Join(string(fs), p)) +// Path returns the path of the given subsystem relative to the procfs root. +func (fs FS) Path(p ...string) string { + return path.Join(append([]string{string(fs)}, p...)...) } -func (fs FS) open(p string) (*os.File, error) { - return os.Open(path.Join(string(fs), p)) -} +// XFSStats retrieves XFS filesystem runtime statistics. +func (fs FS) XFSStats() (*xfs.Stats, error) { + f, err := os.Open(fs.Path("fs/xfs/stat")) + if err != nil { + return nil, err + } + defer f.Close() -func (fs FS) readlink(p string) (string, error) { - return os.Readlink(path.Join(string(fs), p)) + return xfs.ParseStats(f) } diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index 26da5000e..e7012f732 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "net" + "os" "strconv" "strings" ) @@ -58,7 +59,7 @@ func NewIPVSStats() (IPVSStats, error) { // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. func (fs FS) NewIPVSStats() (IPVSStats, error) { - file, err := fs.open("net/ip_vs_stats") + file, err := os.Open(fs.Path("net/ip_vs_stats")) if err != nil { return IPVSStats{}, err } @@ -127,7 +128,7 @@ func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { - file, err := fs.open("net/ip_vs") + file, err := os.Open(fs.Path("net/ip_vs")) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go index 09ed6b5eb..d7a248c0d 100644 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ b/vendor/github.com/prometheus/procfs/mdstat.go @@ -3,7 +3,6 @@ package procfs import ( "fmt" "io/ioutil" - "path" "regexp" "strconv" "strings" @@ -32,36 +31,22 @@ type MDStat struct { // ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { - mdStatusFilePath := path.Join(string(fs), "mdstat") + mdStatusFilePath := fs.Path("mdstat") content, err := ioutil.ReadFile(mdStatusFilePath) if err != nil { return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) } - mdStatusFile := string(content) - - lines := strings.Split(mdStatusFile, "\n") - var currentMD string - - // Each md has at least the deviceline, statusline and one empty line afterwards - // so we will have probably something of the order len(lines)/3 devices - // so we use that for preallocation. - estimateMDs := len(lines) / 3 - mdStates := make([]MDStat, 0, estimateMDs) - + mdStates := []MDStat{} + lines := strings.Split(string(content), "\n") for i, l := range lines { if l == "" { - // Skip entirely empty lines. continue } - if l[0] == ' ' { - // Those lines are not the beginning of a md-section. continue } - if strings.HasPrefix(l, "Personalities") || strings.HasPrefix(l, "unused") { - // We aren't interested in lines with general info. continue } @@ -69,32 +54,30 @@ func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { if len(mainLine) < 3 { return mdStates, fmt.Errorf("error parsing mdline: %s", l) } - currentMD = mainLine[0] // name of md-device - activityState := mainLine[2] // activity status of said md-device + mdName := mainLine[0] + activityState := mainLine[2] if len(lines) <= i+3 { - return mdStates, fmt.Errorf("error parsing %s: entry for %s has fewer lines than expected", mdStatusFilePath, currentMD) + return mdStates, fmt.Errorf( + "error parsing %s: too few lines for md device %s", + mdStatusFilePath, + mdName, + ) } - active, total, size, err := evalStatusline(lines[i+1]) // parse statusline, always present + active, total, size, err := evalStatusline(lines[i+1]) if err != nil { return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) } - // - // Now get the number of synced blocks. - // - - // Get the line number of the syncing-line. - var j int - if strings.Contains(lines[i+2], "bitmap") { // then skip the bitmap line + // j is the line number of the syncing-line. + j := i + 2 + if strings.Contains(lines[i+2], "bitmap") { // skip bitmap line j = i + 3 - } else { - j = i + 2 } - // If device is syncing at the moment, get the number of currently synced bytes, - // otherwise that number equals the size of the device. + // If device is syncing at the moment, get the number of currently + // synced bytes, otherwise that number equals the size of the device. syncedBlocks := size if strings.Contains(lines[j], "recovery") || strings.Contains(lines[j], "resync") { syncedBlocks, err = evalBuildline(lines[j]) @@ -103,8 +86,14 @@ func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { } } - mdStates = append(mdStates, MDStat{currentMD, activityState, active, total, size, syncedBlocks}) - + mdStates = append(mdStates, MDStat{ + Name: mdName, + ActivityState: activityState, + DisksActive: active, + DisksTotal: total, + BlocksTotal: size, + BlocksSynced: syncedBlocks, + }) } return mdStates, nil @@ -112,47 +101,38 @@ func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { func evalStatusline(statusline string) (active, total, size int64, err error) { matches := statuslineRE.FindStringSubmatch(statusline) - - // +1 to make it more obvious that the whole string containing the info is also returned as matches[0]. - if len(matches) != 3+1 { - return 0, 0, 0, fmt.Errorf("unexpected number matches found in statusline: %s", statusline) + if len(matches) != 4 { + return 0, 0, 0, fmt.Errorf("unexpected statusline: %s", statusline) } size, err = strconv.ParseInt(matches[1], 10, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("%s in statusline: %s", err, statusline) + return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) } total, err = strconv.ParseInt(matches[2], 10, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("%s in statusline: %s", err, statusline) + return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) } active, err = strconv.ParseInt(matches[3], 10, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("%s in statusline: %s", err, statusline) + return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) } return active, total, size, nil } -// Gets the size that has already been synced out of the sync-line. -func evalBuildline(buildline string) (int64, error) { +func evalBuildline(buildline string) (syncedBlocks int64, err error) { matches := buildlineRE.FindStringSubmatch(buildline) - - // +1 to make it more obvious that the whole string containing the info is also returned as matches[0]. - if len(matches) < 1+1 { - return 0, fmt.Errorf("too few matches found in buildline: %s", buildline) + if len(matches) != 2 { + return 0, fmt.Errorf("unexpected buildline: %s", buildline) } - if len(matches) > 1+1 { - return 0, fmt.Errorf("too many matches found in buildline: %s", buildline) - } - - syncedSize, err := strconv.ParseInt(matches[1], 10, 64) + syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) if err != nil { return 0, fmt.Errorf("%s in buildline: %s", err, buildline) } - return syncedSize, nil + return syncedBlocks, nil } diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go new file mode 100644 index 000000000..fe8f1f6a2 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/mountstats.go @@ -0,0 +1,552 @@ +package procfs + +// While implementing parsing of /proc/[pid]/mountstats, this blog was used +// heavily as a reference: +// https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex +// +// Special thanks to Chris Siebenmann for all of his posts explaining the +// various statistics available for NFS. + +import ( + "bufio" + "fmt" + "io" + "strconv" + "strings" + "time" +) + +// Constants shared between multiple functions. +const ( + deviceEntryLen = 8 + + fieldBytesLen = 8 + fieldEventsLen = 27 + + statVersion10 = "1.0" + statVersion11 = "1.1" + + fieldTransport10Len = 10 + fieldTransport11Len = 13 +) + +// A Mount is a device mount parsed from /proc/[pid]/mountstats. +type Mount struct { + // Name of the device. + Device string + // The mount point of the device. + Mount string + // The filesystem type used by the device. + Type string + // If available additional statistics related to this Mount. + // Use a type assertion to determine if additional statistics are available. + Stats MountStats +} + +// A MountStats is a type which contains detailed statistics for a specific +// type of Mount. +type MountStats interface { + mountStats() +} + +// A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts. +type MountStatsNFS struct { + // The version of statistics provided. + StatVersion string + // The age of the NFS mount. + Age time.Duration + // Statistics related to byte counters for various operations. + Bytes NFSBytesStats + // Statistics related to various NFS event occurrences. + Events NFSEventsStats + // Statistics broken down by filesystem operation. + Operations []NFSOperationStats + // Statistics about the NFS RPC transport. + Transport NFSTransportStats +} + +// mountStats implements MountStats. +func (m MountStatsNFS) mountStats() {} + +// A NFSBytesStats contains statistics about the number of bytes read and written +// by an NFS client to and from an NFS server. +type NFSBytesStats struct { + // Number of bytes read using the read() syscall. + Read uint64 + // Number of bytes written using the write() syscall. + Write uint64 + // Number of bytes read using the read() syscall in O_DIRECT mode. + DirectRead uint64 + // Number of bytes written using the write() syscall in O_DIRECT mode. + DirectWrite uint64 + // Number of bytes read from the NFS server, in total. + ReadTotal uint64 + // Number of bytes written to the NFS server, in total. + WriteTotal uint64 + // Number of pages read directly via mmap()'d files. + ReadPages uint64 + // Number of pages written directly via mmap()'d files. + WritePages uint64 +} + +// A NFSEventsStats contains statistics about NFS event occurrences. +type NFSEventsStats struct { + // Number of times cached inode attributes are re-validated from the server. + InodeRevalidate uint64 + // Number of times cached dentry nodes are re-validated from the server. + DnodeRevalidate uint64 + // Number of times an inode cache is cleared. + DataInvalidate uint64 + // Number of times cached inode attributes are invalidated. + AttributeInvalidate uint64 + // Number of times files or directories have been open()'d. + VFSOpen uint64 + // Number of times a directory lookup has occurred. + VFSLookup uint64 + // Number of times permissions have been checked. + VFSAccess uint64 + // Number of updates (and potential writes) to pages. + VFSUpdatePage uint64 + // Number of pages read directly via mmap()'d files. + VFSReadPage uint64 + // Number of times a group of pages have been read. + VFSReadPages uint64 + // Number of pages written directly via mmap()'d files. + VFSWritePage uint64 + // Number of times a group of pages have been written. + VFSWritePages uint64 + // Number of times directory entries have been read with getdents(). + VFSGetdents uint64 + // Number of times attributes have been set on inodes. + VFSSetattr uint64 + // Number of pending writes that have been forcefully flushed to the server. + VFSFlush uint64 + // Number of times fsync() has been called on directories and files. + VFSFsync uint64 + // Number of times locking has been attempted on a file. + VFSLock uint64 + // Number of times files have been closed and released. + VFSFileRelease uint64 + // Unknown. Possibly unused. + CongestionWait uint64 + // Number of times files have been truncated. + Truncation uint64 + // Number of times a file has been grown due to writes beyond its existing end. + WriteExtension uint64 + // Number of times a file was removed while still open by another process. + SillyRename uint64 + // Number of times the NFS server gave less data than expected while reading. + ShortRead uint64 + // Number of times the NFS server wrote less data than expected while writing. + ShortWrite uint64 + // Number of times the NFS server indicated EJUKEBOX; retrieving data from + // offline storage. + JukeboxDelay uint64 + // Number of NFS v4.1+ pNFS reads. + PNFSRead uint64 + // Number of NFS v4.1+ pNFS writes. + PNFSWrite uint64 +} + +// A NFSOperationStats contains statistics for a single operation. +type NFSOperationStats struct { + // The name of the operation. + Operation string + // Number of requests performed for this operation. + Requests uint64 + // Number of times an actual RPC request has been transmitted for this operation. + Transmissions uint64 + // Number of times a request has had a major timeout. + MajorTimeouts uint64 + // Number of bytes sent for this operation, including RPC headers and payload. + BytesSent uint64 + // Number of bytes received for this operation, including RPC headers and payload. + BytesReceived uint64 + // Duration all requests spent queued for transmission before they were sent. + CumulativeQueueTime time.Duration + // Duration it took to get a reply back after the request was transmitted. + CumulativeTotalResponseTime time.Duration + // Duration from when a request was enqueued to when it was completely handled. + CumulativeTotalRequestTime time.Duration +} + +// A NFSTransportStats contains statistics for the NFS mount RPC requests and +// responses. +type NFSTransportStats struct { + // The local port used for the NFS mount. + Port uint64 + // Number of times the client has had to establish a connection from scratch + // to the NFS server. + Bind uint64 + // Number of times the client has made a TCP connection to the NFS server. + Connect uint64 + // Duration (in jiffies, a kernel internal unit of time) the NFS mount has + // spent waiting for connections to the server to be established. + ConnectIdleTime uint64 + // Duration since the NFS mount last saw any RPC traffic. + IdleTime time.Duration + // Number of RPC requests for this mount sent to the NFS server. + Sends uint64 + // Number of RPC responses for this mount received from the NFS server. + Receives uint64 + // Number of times the NFS server sent a response with a transaction ID + // unknown to this client. + BadTransactionIDs uint64 + // A running counter, incremented on each request as the current difference + // ebetween sends and receives. + CumulativeActiveRequests uint64 + // A running counter, incremented on each request by the current backlog + // queue size. + CumulativeBacklog uint64 + + // Stats below only available with stat version 1.1. + + // Maximum number of simultaneously active RPC requests ever used. + MaximumRPCSlotsUsed uint64 + // A running counter, incremented on each request as the current size of the + // sending queue. + CumulativeSendingQueue uint64 + // A running counter, incremented on each request as the current size of the + // pending queue. + CumulativePendingQueue uint64 +} + +// parseMountStats parses a /proc/[pid]/mountstats file and returns a slice +// of Mount structures containing detailed information about each mount. +// If available, statistics for each mount are parsed as well. +func parseMountStats(r io.Reader) ([]*Mount, error) { + const ( + device = "device" + statVersionPrefix = "statvers=" + + nfs3Type = "nfs" + nfs4Type = "nfs4" + ) + + var mounts []*Mount + + s := bufio.NewScanner(r) + for s.Scan() { + // Only look for device entries in this function + ss := strings.Fields(string(s.Bytes())) + if len(ss) == 0 || ss[0] != device { + continue + } + + m, err := parseMount(ss) + if err != nil { + return nil, err + } + + // Does this mount also possess statistics information? + if len(ss) > deviceEntryLen { + // Only NFSv3 and v4 are supported for parsing statistics + if m.Type != nfs3Type && m.Type != nfs4Type { + return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type) + } + + statVersion := strings.TrimPrefix(ss[8], statVersionPrefix) + + stats, err := parseMountStatsNFS(s, statVersion) + if err != nil { + return nil, err + } + + m.Stats = stats + } + + mounts = append(mounts, m) + } + + return mounts, s.Err() +} + +// parseMount parses an entry in /proc/[pid]/mountstats in the format: +// device [device] mounted on [mount] with fstype [type] +func parseMount(ss []string) (*Mount, error) { + if len(ss) < deviceEntryLen { + return nil, fmt.Errorf("invalid device entry: %v", ss) + } + + // Check for specific words appearing at specific indices to ensure + // the format is consistent with what we expect + format := []struct { + i int + s string + }{ + {i: 0, s: "device"}, + {i: 2, s: "mounted"}, + {i: 3, s: "on"}, + {i: 5, s: "with"}, + {i: 6, s: "fstype"}, + } + + for _, f := range format { + if ss[f.i] != f.s { + return nil, fmt.Errorf("invalid device entry: %v", ss) + } + } + + return &Mount{ + Device: ss[1], + Mount: ss[4], + Type: ss[7], + }, nil +} + +// parseMountStatsNFS parses a MountStatsNFS by scanning additional information +// related to NFS statistics. +func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { + // Field indicators for parsing specific types of data + const ( + fieldAge = "age:" + fieldBytes = "bytes:" + fieldEvents = "events:" + fieldPerOpStats = "per-op" + fieldTransport = "xprt:" + ) + + stats := &MountStatsNFS{ + StatVersion: statVersion, + } + + for s.Scan() { + ss := strings.Fields(string(s.Bytes())) + if len(ss) == 0 { + break + } + if len(ss) < 2 { + return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) + } + + switch ss[0] { + case fieldAge: + // Age integer is in seconds + d, err := time.ParseDuration(ss[1] + "s") + if err != nil { + return nil, err + } + + stats.Age = d + case fieldBytes: + bstats, err := parseNFSBytesStats(ss[1:]) + if err != nil { + return nil, err + } + + stats.Bytes = *bstats + case fieldEvents: + estats, err := parseNFSEventsStats(ss[1:]) + if err != nil { + return nil, err + } + + stats.Events = *estats + case fieldTransport: + if len(ss) < 3 { + return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss) + } + + tstats, err := parseNFSTransportStats(ss[2:], statVersion) + if err != nil { + return nil, err + } + + stats.Transport = *tstats + } + + // When encountering "per-operation statistics", we must break this + // loop and parse them separately to ensure we can terminate parsing + // before reaching another device entry; hence why this 'if' statement + // is not just another switch case + if ss[0] == fieldPerOpStats { + break + } + } + + if err := s.Err(); err != nil { + return nil, err + } + + // NFS per-operation stats appear last before the next device entry + perOpStats, err := parseNFSOperationStats(s) + if err != nil { + return nil, err + } + + stats.Operations = perOpStats + + return stats, nil +} + +// parseNFSBytesStats parses a NFSBytesStats line using an input set of +// integer fields. +func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) { + if len(ss) != fieldBytesLen { + return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss) + } + + ns := make([]uint64, 0, fieldBytesLen) + for _, s := range ss { + n, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil, err + } + + ns = append(ns, n) + } + + return &NFSBytesStats{ + Read: ns[0], + Write: ns[1], + DirectRead: ns[2], + DirectWrite: ns[3], + ReadTotal: ns[4], + WriteTotal: ns[5], + ReadPages: ns[6], + WritePages: ns[7], + }, nil +} + +// parseNFSEventsStats parses a NFSEventsStats line using an input set of +// integer fields. +func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) { + if len(ss) != fieldEventsLen { + return nil, fmt.Errorf("invalid NFS events stats: %v", ss) + } + + ns := make([]uint64, 0, fieldEventsLen) + for _, s := range ss { + n, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil, err + } + + ns = append(ns, n) + } + + return &NFSEventsStats{ + InodeRevalidate: ns[0], + DnodeRevalidate: ns[1], + DataInvalidate: ns[2], + AttributeInvalidate: ns[3], + VFSOpen: ns[4], + VFSLookup: ns[5], + VFSAccess: ns[6], + VFSUpdatePage: ns[7], + VFSReadPage: ns[8], + VFSReadPages: ns[9], + VFSWritePage: ns[10], + VFSWritePages: ns[11], + VFSGetdents: ns[12], + VFSSetattr: ns[13], + VFSFlush: ns[14], + VFSFsync: ns[15], + VFSLock: ns[16], + VFSFileRelease: ns[17], + CongestionWait: ns[18], + Truncation: ns[19], + WriteExtension: ns[20], + SillyRename: ns[21], + ShortRead: ns[22], + ShortWrite: ns[23], + JukeboxDelay: ns[24], + PNFSRead: ns[25], + PNFSWrite: ns[26], + }, nil +} + +// parseNFSOperationStats parses a slice of NFSOperationStats by scanning +// additional information about per-operation statistics until an empty +// line is reached. +func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { + const ( + // Number of expected fields in each per-operation statistics set + numFields = 9 + ) + + var ops []NFSOperationStats + + for s.Scan() { + ss := strings.Fields(string(s.Bytes())) + if len(ss) == 0 { + // Must break when reading a blank line after per-operation stats to + // enable top-level function to parse the next device entry + break + } + + if len(ss) != numFields { + return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss) + } + + // Skip string operation name for integers + ns := make([]uint64, 0, numFields-1) + for _, st := range ss[1:] { + n, err := strconv.ParseUint(st, 10, 64) + if err != nil { + return nil, err + } + + ns = append(ns, n) + } + + ops = append(ops, NFSOperationStats{ + Operation: strings.TrimSuffix(ss[0], ":"), + Requests: ns[0], + Transmissions: ns[1], + MajorTimeouts: ns[2], + BytesSent: ns[3], + BytesReceived: ns[4], + CumulativeQueueTime: time.Duration(ns[5]) * time.Millisecond, + CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond, + CumulativeTotalRequestTime: time.Duration(ns[7]) * time.Millisecond, + }) + } + + return ops, s.Err() +} + +// parseNFSTransportStats parses a NFSTransportStats line using an input set of +// integer fields matched to a specific stats version. +func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) { + switch statVersion { + case statVersion10: + if len(ss) != fieldTransport10Len { + return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss) + } + case statVersion11: + if len(ss) != fieldTransport11Len { + return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss) + } + default: + return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion) + } + + // Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay + // in a v1.0 response + ns := make([]uint64, 0, fieldTransport11Len) + for _, s := range ss { + n, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil, err + } + + ns = append(ns, n) + } + + return &NFSTransportStats{ + Port: ns[0], + Bind: ns[1], + Connect: ns[2], + ConnectIdleTime: ns[3], + IdleTime: time.Duration(ns[4]) * time.Second, + Sends: ns[5], + Receives: ns[6], + BadTransactionIDs: ns[7], + CumulativeActiveRequests: ns[8], + CumulativeBacklog: ns[9], + MaximumRPCSlotsUsed: ns[10], + CumulativeSendingQueue: ns[11], + CumulativePendingQueue: ns[12], + }, nil +} diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go index efc850278..8717e1fe0 100644 --- a/vendor/github.com/prometheus/procfs/proc.go +++ b/vendor/github.com/prometheus/procfs/proc.go @@ -4,7 +4,6 @@ import ( "fmt" "io/ioutil" "os" - "path" "strconv" "strings" ) @@ -42,7 +41,7 @@ func NewProc(pid int) (Proc, error) { return fs.NewProc(pid) } -// AllProcs returns a list of all currently avaible processes under /proc. +// AllProcs returns a list of all currently available processes under /proc. func AllProcs() (Procs, error) { fs, err := NewFS(DefaultMountPoint) if err != nil { @@ -53,7 +52,7 @@ func AllProcs() (Procs, error) { // Self returns a process for the current process. func (fs FS) Self() (Proc, error) { - p, err := fs.readlink("self") + p, err := os.Readlink(fs.Path("self")) if err != nil { return Proc{}, err } @@ -66,15 +65,15 @@ func (fs FS) Self() (Proc, error) { // NewProc returns a process for the given pid. func (fs FS) NewProc(pid int) (Proc, error) { - if _, err := fs.stat(strconv.Itoa(pid)); err != nil { + if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { return Proc{}, err } return Proc{PID: pid, fs: fs}, nil } -// AllProcs returns a list of all currently avaible processes. +// AllProcs returns a list of all currently available processes. func (fs FS) AllProcs() (Procs, error) { - d, err := fs.open("") + d, err := os.Open(fs.Path()) if err != nil { return Procs{}, err } @@ -99,7 +98,7 @@ func (fs FS) AllProcs() (Procs, error) { // CmdLine returns the command line of a process. func (p Proc) CmdLine() ([]string, error) { - f, err := p.open("cmdline") + f, err := os.Open(p.path("cmdline")) if err != nil { return nil, err } @@ -117,10 +116,25 @@ func (p Proc) CmdLine() ([]string, error) { return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil } +// Comm returns the command name of a process. +func (p Proc) Comm() (string, error) { + f, err := os.Open(p.path("comm")) + if err != nil { + return "", err + } + defer f.Close() + + data, err := ioutil.ReadAll(f) + if err != nil { + return "", err + } + + return strings.TrimSpace(string(data)), nil +} + // Executable returns the absolute path of the executable command of a process. func (p Proc) Executable() (string, error) { - exe, err := p.readlink("exe") - + exe, err := os.Readlink(p.path("exe")) if os.IsNotExist(err) { return "", nil } @@ -158,7 +172,7 @@ func (p Proc) FileDescriptorTargets() ([]string, error) { targets := make([]string, len(names)) for i, name := range names { - target, err := p.readlink("fd/" + name) + target, err := os.Readlink(p.path("fd", name)) if err == nil { targets[i] = target } @@ -178,8 +192,20 @@ func (p Proc) FileDescriptorsLen() (int, error) { return len(fds), nil } +// MountStats retrieves statistics and configuration for mount points in a +// process's namespace. +func (p Proc) MountStats() ([]*Mount, error) { + f, err := os.Open(p.path("mountstats")) + if err != nil { + return nil, err + } + defer f.Close() + + return parseMountStats(f) +} + func (p Proc) fileDescriptors() ([]string, error) { - d, err := p.open("fd") + d, err := os.Open(p.path("fd")) if err != nil { return nil, err } @@ -193,10 +219,6 @@ func (p Proc) fileDescriptors() ([]string, error) { return names, nil } -func (p Proc) open(pa string) (*os.File, error) { - return p.fs.open(path.Join(strconv.Itoa(p.PID), pa)) -} - -func (p Proc) readlink(pa string) (string, error) { - return p.fs.readlink(path.Join(strconv.Itoa(p.PID), pa)) +func (p Proc) path(pa ...string) string { + return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) } diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go index 7c6dc8697..b4e31d7ba 100644 --- a/vendor/github.com/prometheus/procfs/proc_io.go +++ b/vendor/github.com/prometheus/procfs/proc_io.go @@ -3,6 +3,7 @@ package procfs import ( "fmt" "io/ioutil" + "os" ) // ProcIO models the content of /proc//io. @@ -29,7 +30,7 @@ type ProcIO struct { func (p Proc) NewIO() (ProcIO, error) { pio := ProcIO{} - f, err := p.open("io") + f, err := os.Open(p.path("io")) if err != nil { return pio, err } diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go index 9f080b9f6..2df997ce1 100644 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ b/vendor/github.com/prometheus/procfs/proc_limits.go @@ -3,29 +3,56 @@ package procfs import ( "bufio" "fmt" + "os" "regexp" "strconv" ) // ProcLimits represents the soft limits for each of the process's resource -// limits. +// limits. For more information see getrlimit(2): +// http://man7.org/linux/man-pages/man2/getrlimit.2.html. type ProcLimits struct { - CPUTime int - FileSize int - DataSize int - StackSize int - CoreFileSize int - ResidentSet int - Processes int - OpenFiles int - LockedMemory int - AddressSpace int - FileLocks int - PendingSignals int - MsqqueueSize int - NicePriority int + // CPU time limit in seconds. + CPUTime int + // Maximum size of files that the process may create. + FileSize int + // Maximum size of the process's data segment (initialized data, + // uninitialized data, and heap). + DataSize int + // Maximum size of the process stack in bytes. + StackSize int + // Maximum size of a core file. + CoreFileSize int + // Limit of the process's resident set in pages. + ResidentSet int + // Maximum number of processes that can be created for the real user ID of + // the calling process. + Processes int + // Value one greater than the maximum file descriptor number that can be + // opened by this process. + OpenFiles int + // Maximum number of bytes of memory that may be locked into RAM. + LockedMemory int + // Maximum size of the process's virtual memory address space in bytes. + AddressSpace int + // Limit on the combined number of flock(2) locks and fcntl(2) leases that + // this process may establish. + FileLocks int + // Limit of signals that may be queued for the real user ID of the calling + // process. + PendingSignals int + // Limit on the number of bytes that can be allocated for POSIX message + // queues for the real user ID of the calling process. + MsqqueueSize int + // Limit of the nice priority set using setpriority(2) or nice(2). + NicePriority int + // Limit of the real-time priority set using sched_setscheduler(2) or + // sched_setparam(2). RealtimePriority int - RealtimeTimeout int + // Limit (in microseconds) on the amount of CPU time that a process + // scheduled under a real-time scheduling policy may consume without making + // a blocking system call. + RealtimeTimeout int } const ( @@ -39,7 +66,7 @@ var ( // NewLimits returns the current soft limits of the process. func (p Proc) NewLimits() (ProcLimits, error) { - f, err := p.open("limits") + f, err := os.Open(p.path("limits")) if err != nil { return ProcLimits{}, err } @@ -60,7 +87,7 @@ func (p Proc) NewLimits() (ProcLimits, error) { case "Max cpu time": l.CPUTime, err = parseInt(fields[1]) case "Max file size": - l.FileLocks, err = parseInt(fields[1]) + l.FileSize, err = parseInt(fields[1]) case "Max data size": l.DataSize, err = parseInt(fields[1]) case "Max stack size": @@ -90,7 +117,6 @@ func (p Proc) NewLimits() (ProcLimits, error) { case "Max realtime timeout": l.RealtimeTimeout, err = parseInt(fields[1]) } - if err != nil { return ProcLimits{}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 30a403b6c..724e271b9 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -7,15 +7,15 @@ import ( "os" ) -// Originally, this USER_HZ value was dynamically retrieved via a sysconf call which -// required cgo. However, that caused a lot of problems regarding +// Originally, this USER_HZ value was dynamically retrieved via a sysconf call +// which required cgo. However, that caused a lot of problems regarding // cross-compilation. Alternatives such as running a binary to determine the -// value, or trying to derive it in some other way were all problematic. -// After much research it was determined that USER_HZ is actually hardcoded to -// 100 on all Go-supported platforms as of the time of this writing. This is -// why we decided to hardcode it here as well. It is not impossible that there -// could be systems with exceptions, but they should be very exotic edge cases, -// and in that case, the worst outcome will be two misreported metrics. +// value, or trying to derive it in some other way were all problematic. After +// much research it was determined that USER_HZ is actually hardcoded to 100 on +// all Go-supported platforms as of the time of this writing. This is why we +// decided to hardcode it here as well. It is not impossible that there could +// be systems with exceptions, but they should be very exotic edge cases, and +// in that case, the worst outcome will be two misreported metrics. // // See also the following discussions: // @@ -91,7 +91,7 @@ type ProcStat struct { // NewStat returns the current status information of the process. func (p Proc) NewStat() (ProcStat, error) { - f, err := p.open("stat") + f, err := os.Open(p.path("stat")) if err != nil { return ProcStat{}, err } diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index 26fefb0fa..1ca217e8c 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -3,6 +3,7 @@ package procfs import ( "bufio" "fmt" + "os" "strconv" "strings" ) @@ -25,7 +26,7 @@ func NewStat() (Stat, error) { // NewStat returns an information about current kernel/system statistics. func (fs FS) NewStat() (Stat, error) { - f, err := fs.open("stat") + f, err := os.Open(fs.Path("stat")) if err != nil { return Stat{}, err } diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go new file mode 100644 index 000000000..d1285fa6c --- /dev/null +++ b/vendor/github.com/prometheus/procfs/xfs/parse.go @@ -0,0 +1,361 @@ +// Copyright 2017 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 xfs + +import ( + "bufio" + "fmt" + "io" + "log" + "strconv" + "strings" +) + +// ParseStats parses a Stats from an input io.Reader, using the format +// found in /proc/fs/xfs/stat. +func ParseStats(r io.Reader) (*Stats, error) { + const ( + // Fields parsed into stats structures. + fieldExtentAlloc = "extent_alloc" + fieldAbt = "abt" + fieldBlkMap = "blk_map" + fieldBmbt = "bmbt" + fieldDir = "dir" + fieldTrans = "trans" + fieldIg = "ig" + fieldLog = "log" + fieldRw = "rw" + fieldAttr = "attr" + fieldIcluster = "icluster" + fieldVnodes = "vnodes" + fieldBuf = "buf" + fieldXpc = "xpc" + + // Unimplemented at this time due to lack of documentation. + fieldPushAil = "push_ail" + fieldXstrat = "xstrat" + fieldAbtb2 = "abtb2" + fieldAbtc2 = "abtc2" + fieldBmbt2 = "bmbt2" + fieldIbt2 = "ibt2" + fieldFibt2 = "fibt2" + fieldQm = "qm" + fieldDebug = "debug" + ) + + var xfss Stats + + s := bufio.NewScanner(r) + for s.Scan() { + // Expect at least a string label and a single integer value, ex: + // - abt 0 + // - rw 1 2 + ss := strings.Fields(string(s.Bytes())) + if len(ss) < 2 { + continue + } + label := ss[0] + + // Extended precision counters are uint64 values. + if label == fieldXpc { + us, err := parseUint64s(ss[1:]) + if err != nil { + return nil, err + } + + xfss.ExtendedPrecision, err = extendedPrecisionStats(us) + if err != nil { + return nil, err + } + + continue + } + + // All other counters are uint32 values. + us, err := parseUint32s(ss[1:]) + if err != nil { + return nil, err + } + + switch label { + case fieldExtentAlloc: + xfss.ExtentAllocation, err = extentAllocationStats(us) + case fieldAbt: + xfss.AllocationBTree, err = btreeStats(us) + case fieldBlkMap: + xfss.BlockMapping, err = blockMappingStats(us) + case fieldBmbt: + xfss.BlockMapBTree, err = btreeStats(us) + case fieldDir: + xfss.DirectoryOperation, err = directoryOperationStats(us) + case fieldTrans: + xfss.Transaction, err = transactionStats(us) + case fieldIg: + xfss.InodeOperation, err = inodeOperationStats(us) + case fieldLog: + xfss.LogOperation, err = logOperationStats(us) + case fieldRw: + xfss.ReadWrite, err = readWriteStats(us) + case fieldAttr: + xfss.AttributeOperation, err = attributeOperationStats(us) + case fieldIcluster: + xfss.InodeClustering, err = inodeClusteringStats(us) + case fieldVnodes: + xfss.Vnode, err = vnodeStats(us) + case fieldBuf: + xfss.Buffer, err = bufferStats(us) + } + if err != nil { + return nil, err + } + } + + return &xfss, s.Err() +} + +// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s. +func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) { + if l := len(us); l != 4 { + return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l) + } + + return ExtentAllocationStats{ + ExtentsAllocated: us[0], + BlocksAllocated: us[1], + ExtentsFreed: us[2], + BlocksFreed: us[3], + }, nil +} + +// btreeStats builds a BTreeStats from a slice of uint32s. +func btreeStats(us []uint32) (BTreeStats, error) { + if l := len(us); l != 4 { + return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l) + } + + return BTreeStats{ + Lookups: us[0], + Compares: us[1], + RecordsInserted: us[2], + RecordsDeleted: us[3], + }, nil +} + +// BlockMappingStat builds a BlockMappingStats from a slice of uint32s. +func blockMappingStats(us []uint32) (BlockMappingStats, error) { + if l := len(us); l != 7 { + return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l) + } + + return BlockMappingStats{ + Reads: us[0], + Writes: us[1], + Unmaps: us[2], + ExtentListInsertions: us[3], + ExtentListDeletions: us[4], + ExtentListLookups: us[5], + ExtentListCompares: us[6], + }, nil +} + +// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s. +func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) { + if l := len(us); l != 4 { + return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l) + } + + return DirectoryOperationStats{ + Lookups: us[0], + Creates: us[1], + Removes: us[2], + Getdents: us[3], + }, nil +} + +// TransactionStats builds a TransactionStats from a slice of uint32s. +func transactionStats(us []uint32) (TransactionStats, error) { + if l := len(us); l != 3 { + return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l) + } + + return TransactionStats{ + Sync: us[0], + Async: us[1], + Empty: us[2], + }, nil +} + +// InodeOperationStats builds an InodeOperationStats from a slice of uint32s. +func inodeOperationStats(us []uint32) (InodeOperationStats, error) { + if l := len(us); l != 7 { + return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l) + } + + return InodeOperationStats{ + Attempts: us[0], + Found: us[1], + Recycle: us[2], + Missed: us[3], + Duplicate: us[4], + Reclaims: us[5], + AttributeChange: us[6], + }, nil +} + +// LogOperationStats builds a LogOperationStats from a slice of uint32s. +func logOperationStats(us []uint32) (LogOperationStats, error) { + if l := len(us); l != 5 { + return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l) + } + + return LogOperationStats{ + Writes: us[0], + Blocks: us[1], + NoInternalBuffers: us[2], + Force: us[3], + ForceSleep: us[4], + }, nil +} + +// ReadWriteStats builds a ReadWriteStats from a slice of uint32s. +func readWriteStats(us []uint32) (ReadWriteStats, error) { + if l := len(us); l != 2 { + return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l) + } + + return ReadWriteStats{ + Read: us[0], + Write: us[1], + }, nil +} + +// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s. +func attributeOperationStats(us []uint32) (AttributeOperationStats, error) { + if l := len(us); l != 4 { + return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l) + } + + return AttributeOperationStats{ + Get: us[0], + Set: us[1], + Remove: us[2], + List: us[3], + }, nil +} + +// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s. +func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) { + if l := len(us); l != 3 { + return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l) + } + + return InodeClusteringStats{ + Iflush: us[0], + Flush: us[1], + FlushInode: us[2], + }, nil +} + +// VnodeStats builds a VnodeStats from a slice of uint32s. +func vnodeStats(us []uint32) (VnodeStats, error) { + // The attribute "Free" appears to not be available on older XFS + // stats versions. Therefore, 7 or 8 elements may appear in + // this slice. + l := len(us) + log.Println(l) + if l != 7 && l != 8 { + return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l) + } + + s := VnodeStats{ + Active: us[0], + Allocate: us[1], + Get: us[2], + Hold: us[3], + Release: us[4], + Reclaim: us[5], + Remove: us[6], + } + + // Skip adding free, unless it is present. The zero value will + // be used in place of an actual count. + if l == 7 { + return s, nil + } + + s.Free = us[7] + return s, nil +} + +// BufferStats builds a BufferStats from a slice of uint32s. +func bufferStats(us []uint32) (BufferStats, error) { + if l := len(us); l != 9 { + return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l) + } + + return BufferStats{ + Get: us[0], + Create: us[1], + GetLocked: us[2], + GetLockedWaited: us[3], + BusyLocked: us[4], + MissLocked: us[5], + PageRetries: us[6], + PageFound: us[7], + GetRead: us[8], + }, nil +} + +// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s. +func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { + if l := len(us); l != 3 { + return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l) + } + + return ExtendedPrecisionStats{ + FlushBytes: us[0], + WriteBytes: us[1], + ReadBytes: us[2], + }, nil +} + +// parseUint32s parses a slice of strings into a slice of uint32s. +func parseUint32s(ss []string) ([]uint32, error) { + us := make([]uint32, 0, len(ss)) + for _, s := range ss { + u, err := strconv.ParseUint(s, 10, 32) + if err != nil { + return nil, err + } + + us = append(us, uint32(u)) + } + + return us, nil +} + +// parseUint64s parses a slice of strings into a slice of uint64s. +func parseUint64s(ss []string) ([]uint64, error) { + us := make([]uint64, 0, len(ss)) + for _, s := range ss { + u, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil, err + } + + us = append(us, u) + } + + return us, nil +} diff --git a/vendor/github.com/prometheus/procfs/xfs/xfs.go b/vendor/github.com/prometheus/procfs/xfs/xfs.go new file mode 100644 index 000000000..ed77d907a --- /dev/null +++ b/vendor/github.com/prometheus/procfs/xfs/xfs.go @@ -0,0 +1,158 @@ +// Copyright 2017 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 xfs provides access to statistics exposed by the XFS filesystem. +package xfs + +// Stats contains XFS filesystem runtime statistics, parsed from +// /proc/fs/xfs/stat. +// +// The names and meanings of each statistic were taken from +// http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux +// kernel source. Most counters are uint32s (same data types used in +// xfs_stats.h), but some of the "extended precision stats" are uint64s. +type Stats struct { + ExtentAllocation ExtentAllocationStats + AllocationBTree BTreeStats + BlockMapping BlockMappingStats + BlockMapBTree BTreeStats + DirectoryOperation DirectoryOperationStats + Transaction TransactionStats + InodeOperation InodeOperationStats + LogOperation LogOperationStats + ReadWrite ReadWriteStats + AttributeOperation AttributeOperationStats + InodeClustering InodeClusteringStats + Vnode VnodeStats + Buffer BufferStats + ExtendedPrecision ExtendedPrecisionStats +} + +// ExtentAllocationStats contains statistics regarding XFS extent allocations. +type ExtentAllocationStats struct { + ExtentsAllocated uint32 + BlocksAllocated uint32 + ExtentsFreed uint32 + BlocksFreed uint32 +} + +// BTreeStats contains statistics regarding an XFS internal B-tree. +type BTreeStats struct { + Lookups uint32 + Compares uint32 + RecordsInserted uint32 + RecordsDeleted uint32 +} + +// BlockMappingStats contains statistics regarding XFS block maps. +type BlockMappingStats struct { + Reads uint32 + Writes uint32 + Unmaps uint32 + ExtentListInsertions uint32 + ExtentListDeletions uint32 + ExtentListLookups uint32 + ExtentListCompares uint32 +} + +// DirectoryOperationStats contains statistics regarding XFS directory entries. +type DirectoryOperationStats struct { + Lookups uint32 + Creates uint32 + Removes uint32 + Getdents uint32 +} + +// TransactionStats contains statistics regarding XFS metadata transactions. +type TransactionStats struct { + Sync uint32 + Async uint32 + Empty uint32 +} + +// InodeOperationStats contains statistics regarding XFS inode operations. +type InodeOperationStats struct { + Attempts uint32 + Found uint32 + Recycle uint32 + Missed uint32 + Duplicate uint32 + Reclaims uint32 + AttributeChange uint32 +} + +// LogOperationStats contains statistics regarding the XFS log buffer. +type LogOperationStats struct { + Writes uint32 + Blocks uint32 + NoInternalBuffers uint32 + Force uint32 + ForceSleep uint32 +} + +// ReadWriteStats contains statistics regarding the number of read and write +// system calls for XFS filesystems. +type ReadWriteStats struct { + Read uint32 + Write uint32 +} + +// AttributeOperationStats contains statistics regarding manipulation of +// XFS extended file attributes. +type AttributeOperationStats struct { + Get uint32 + Set uint32 + Remove uint32 + List uint32 +} + +// InodeClusteringStats contains statistics regarding XFS inode clustering +// operations. +type InodeClusteringStats struct { + Iflush uint32 + Flush uint32 + FlushInode uint32 +} + +// VnodeStats contains statistics regarding XFS vnode operations. +type VnodeStats struct { + Active uint32 + Allocate uint32 + Get uint32 + Hold uint32 + Release uint32 + Reclaim uint32 + Remove uint32 + Free uint32 +} + +// BufferStats contains statistics regarding XFS read/write I/O buffers. +type BufferStats struct { + Get uint32 + Create uint32 + GetLocked uint32 + GetLockedWaited uint32 + BusyLocked uint32 + MissLocked uint32 + PageRetries uint32 + PageFound uint32 + GetRead uint32 +} + +// ExtendedPrecisionStats contains high precision counters used to track the +// total number of bytes read, written, or flushed, during XFS operations. +type ExtendedPrecisionStats struct { + FlushBytes uint64 + WriteBytes uint64 + ReadBytes uint64 +} diff --git a/vendor/github.com/pyr/egoscale/exo.go b/vendor/github.com/pyr/egoscale/exo.go index 07cb15217..7a3c445ce 100644 --- a/vendor/github.com/pyr/egoscale/exo.go +++ b/vendor/github.com/pyr/egoscale/exo.go @@ -3,115 +3,37 @@ package main import ( "egoscale" "fmt" + "flag" "os" - "time" ) +var apikey = flag.String("xk", "", "Exoscale API Key") +var apisecret = flag.String("xs", "", "Exoscale API Secret") +var endpoint = flag.String("xe", "https://api.exoscale.ch/compute", "Exoscale API Endpoint") + func main() { - endpoint := os.Getenv("EXOSCALE_ENDPOINT") - apiKey := os.Getenv("EXOSCALE_API_KEY") - apiSecret := os.Getenv("EXOSCALE_API_SECRET") - client := egoscale.NewClient(endpoint, apiKey, apiSecret) + flag.Parse() + client := egoscale.NewClient(*endpoint, *apikey, *apisecret) - topo, err := client.GetTopology() + + vms, err := client.ListVirtualMachines() if err != nil { - fmt.Printf("got error: %+v\n", err) - return + fmt.Printf("got error: %s\n", err) + os.Exit(1) } - rules := []egoscale.SecurityGroupRule{ - { - SecurityGroupId: "", - Cidr: "0.0.0.0/0", - Protocol: "TCP", - Port: 22, - }, - { - SecurityGroupId: "", - Cidr: "0.0.0.0/0", - Protocol: "TCP", - Port: 2376, - }, - { - SecurityGroupId: "", - Cidr: "0.0.0.0/0", - Protocol: "ICMP", - IcmpType: 8, - IcmpCode: 0, - }, - } + for _, vm := range(vms) { - sgid, present := topo.SecurityGroups["egoscale"] - if !present { - resp, err := client.CreateSecurityGroupWithRules("egoscale", rules, make([]egoscale.SecurityGroupRule, 0, 0)) - if err != nil { - fmt.Printf("got error: %+v\n", err) - return + fmt.Println("vm:", vm.Displayname) + for _, nic := range(vm.Nic) { + fmt.Println("ip:", nic.Ipaddress) } - sgid = resp.Id - } - - agid, present := topo.AffinityGroups["egoscale"] - if !present { - //Affinity Group Create is an async call - jobid, err := client.CreateAffinityGroup("egoscale") - - var resp *egoscale.QueryAsyncJobResultResponse - for i := 0; i <= 10; i++ { - resp, err = client.PollAsyncJob(jobid) - if err != nil { - fmt.Printf("got error: %+v\n", err) - return - } - - if resp.Jobstatus == 1 { - break - } - time.Sleep(5 * time.Second) + for _, sg := range(vm.SecurityGroups) { + fmt.Println("securitygroup:", sg.Name) } } - fmt.Printf("Affinity Group ID :%v\n", agid) + os.Exit(0) - profile := egoscale.MachineProfile{ - Template: topo.Images["ubuntu-14.04"][10], - ServiceOffering: topo.Profiles["large"], - SecurityGroups: []string{sgid}, - Keypair: topo.Keypairs[0], - AffinityGroups: []string{"egoscale"}, - Userdata: "#cloud-config\nmanage_etc_hosts: true\nfqdn: deployed-by-egoscale\n", - Zone: topo.Zones["ch-gva-2"], - Name: "deployed-by-egoscale", - } - - jobid, err := client.CreateVirtualMachine(profile) - - if err != nil { - fmt.Printf("got error: %+v\n", err) - return - } - - var resp *egoscale.QueryAsyncJobResultResponse - - for i := 0; i <= 10; i++ { - resp, err = client.PollAsyncJob(jobid) - if err != nil { - fmt.Printf("got error: %+v\n", err) - return - } - - if resp.Jobstatus == 1 { - break - } - time.Sleep(5 * time.Second) - } - - vm, err := client.AsyncToVirtualMachine(*resp) - - if err != nil { - fmt.Printf("got error: %+v\n", err) - } - - fmt.Printf("new machine up and running at: %s\n", vm.Nic[0].Ipaddress) } diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/groups.go b/vendor/github.com/pyr/egoscale/src/egoscale/groups.go index dc4406867..f51eb82fe 100644 --- a/vendor/github.com/pyr/egoscale/src/egoscale/groups.go +++ b/vendor/github.com/pyr/egoscale/src/egoscale/groups.go @@ -10,9 +10,21 @@ func (exo *Client) CreateEgressRule(rule SecurityGroupRule) (*AuthorizeSecurityG params := url.Values{} params.Set("securitygroupid", rule.SecurityGroupId) - params.Set("cidrlist", rule.Cidr) - params.Set("protocol", rule.Protocol) + + if rule.Cidr != "" { + params.Set("cidrlist", rule.Cidr) + } else if len(rule.UserSecurityGroupList) > 0 { + usg,err := json.Marshal(rule.UserSecurityGroupList) + if err != nil { + return nil, err + } + params.Set("usersecuritygrouplist", string(usg)) + } else { + return nil, fmt.Errorf("No Egress rule CIDR or Security Group List provided") + } + params.Set("protocol", rule.Protocol) + if rule.Protocol == "ICMP" { params.Set("icmpcode", fmt.Sprintf("%d", rule.IcmpCode)) params.Set("icmptype", fmt.Sprintf("%d", rule.IcmpType)) @@ -40,7 +52,19 @@ func (exo *Client) CreateIngressRule(rule SecurityGroupRule) (*AuthorizeSecurity params := url.Values{} params.Set("securitygroupid", rule.SecurityGroupId) - params.Set("cidrlist", rule.Cidr) + + if rule.Cidr != "" { + params.Set("cidrlist", rule.Cidr) + } else if len(rule.UserSecurityGroupList) >0 { + for i := 0; i < len(rule.UserSecurityGroupList); i++ { + params.Set(fmt.Sprintf("usersecuritygrouplist[%d].account", i), rule.UserSecurityGroupList[i].Account) + params.Set(fmt.Sprintf("usersecuritygrouplist[%d].group", i), rule.UserSecurityGroupList[i].Group) + + } + } else { + return nil, fmt.Errorf("No Ingress rule CIDR or Security Group List provided") + } + params.Set("protocol", rule.Protocol) if rule.Protocol == "ICMP" { @@ -53,6 +77,8 @@ func (exo *Client) CreateIngressRule(rule SecurityGroupRule) (*AuthorizeSecurity return nil, fmt.Errorf("Invalid Egress rule Protocol: %s", rule.Protocol) } + fmt.Printf("## params: %+v\n", params) + resp, err := exo.Request("authorizeSecurityGroupIngress", params) if err != nil { @@ -114,4 +140,4 @@ func (exo *Client) DeleteSecurityGroup(name string) (error) { fmt.Printf("## response: %+v\n", resp) return nil -} \ No newline at end of file +} diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/ip.go b/vendor/github.com/pyr/egoscale/src/egoscale/ip.go new file mode 100644 index 000000000..3c84d4ccc --- /dev/null +++ b/vendor/github.com/pyr/egoscale/src/egoscale/ip.go @@ -0,0 +1,40 @@ +package egoscale + +import ( + "encoding/json" + "net/url" +) + +func (exo *Client) AddIpToNic(nic_id string, ip_address string) (string, error) { + params := url.Values{} + params.Set("nicid", nic_id) + params.Set("ipaddress", ip_address) + + resp, err := exo.Request("addIpToNic", params) + if err != nil { + return "", err + } + + var r AddIpToNicResponse + if err := json.Unmarshal(resp, &r); err != nil { + return "", err + } + + return r.Id, nil +} + +func (exo *Client) RemoveIpFromNic(nic_id string) (string, error) { + params := url.Values{} + params.Set("id", nic_id) + + resp, err := exo.Request("removeIpFromNic", params) + if err != nil { + return "", err + } + + var r RemoveIpFromNicResponse + if err := json.Unmarshal(resp, &r); err != nil { + return "", err + } + return r.JobID, nil +} diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/request.go b/vendor/github.com/pyr/egoscale/src/egoscale/request.go index cc4b891d3..8de806b79 100644 --- a/vendor/github.com/pyr/egoscale/src/egoscale/request.go +++ b/vendor/github.com/pyr/egoscale/src/egoscale/request.go @@ -10,8 +10,17 @@ import ( "net/http" "net/url" "strings" + "sort" ) +func csQuotePlus(s string) string { + return strings.Replace(s, "+", "%20", -1) +} + +func csEncode(s string) string { + return csQuotePlus(url.QueryEscape(s)) +} + func rawValue(b json.RawMessage) (json.RawMessage, error) { var m map[string]json.RawMessage @@ -21,7 +30,6 @@ func rawValue(b json.RawMessage) (json.RawMessage, error) { for _, v := range m { return v, nil } - //return nil, fmt.Errorf("Unable to extract raw value from:\n\n%s\n\n", string(b)) return nil, nil } @@ -51,7 +59,6 @@ func (exo *Client) ParseResponse(resp *http.Response) (json.RawMessage, error) { } if resp.StatusCode >= 400 { - fmt.Printf("ERROR: %s\n", b) var e Error if err := json.Unmarshal(b, &e); err != nil { return nil, err @@ -75,17 +82,27 @@ func (exo *Client) ParseResponse(resp *http.Response) (json.RawMessage, error) { func (exo *Client) Request(command string, params url.Values) (json.RawMessage, error) { mac := hmac.New(sha1.New, []byte(exo.apiSecret)) + keys := make([]string, 0) + unencoded := make([]string, 0) params.Set("apikey", exo.apiKey) params.Set("command", command) params.Set("response", "json") - s := strings.Replace(strings.ToLower(params.Encode()), "+", "%20", -1) - mac.Write([]byte(s)) - signature := url.QueryEscape(base64.StdEncoding.EncodeToString(mac.Sum(nil))) + for k, _ := range(params) { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range(keys) { + arg := k + "=" + csEncode(params[k][0]) + unencoded = append(unencoded, arg) + } + sign_string := strings.ToLower(strings.Join(unencoded, "&")) - s = params.Encode() - url := exo.endpoint + "?" + s + "&signature=" + signature + mac.Write([]byte(sign_string)) + signature := csEncode(base64.StdEncoding.EncodeToString(mac.Sum(nil))) + query := params.Encode() + url := exo.endpoint + "?" + csQuotePlus(query) + "&signature=" + signature resp, err := exo.client.Get(url) if err != nil { diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/types.go b/vendor/github.com/pyr/egoscale/src/egoscale/types.go index d9e659ef8..2f918a057 100644 --- a/vendor/github.com/pyr/egoscale/src/egoscale/types.go +++ b/vendor/github.com/pyr/egoscale/src/egoscale/types.go @@ -39,6 +39,12 @@ type SecurityGroupRule struct { Port int Protocol string SecurityGroupId string + UserSecurityGroupList []UserSecurityGroup `json:"usersecuritygrouplist,omitempty"` +} + +type UserSecurityGroup struct { + Group string `json:"group,omitempty"` + Account string `json:"account,omitempty"` } type MachineProfile struct { @@ -397,7 +403,10 @@ type VirtualMachine struct { Netmask string `json:"netmask,omitempty"` Networkid string `json:"networkid,omitempty"` Networkname string `json:"networkname,omitempty"` - Secondaryip []string `json:"secondaryip,omitempty"` + Secondaryip []struct { + Id string `json:"id,omitempty"` + IpAddress string `json:"ipaddress,omitempty"` + } `json:"secondaryip,omitempty"` Traffictype string `json:"traffictype,omitempty"` Type string `json:"type,omitempty"` } `json:"nic,omitempty"` @@ -409,6 +418,13 @@ type VirtualMachine struct { Publicipid string `json:"publicipid,omitempty"` Rootdeviceid int64 `json:"rootdeviceid,omitempty"` Rootdevicetype string `json:"rootdevicetype,omitempty"` + SecurityGroups []struct { + Account string `json:"account,omitempty"` + Description string `json:"description,omitempty"` + Id string `json:"id,omitempty"` + Name string `json:"name,omitemtpy"` + Tags []string `json:"tags,omitempty"` + } `json:"securitygroup,omitempty"` Serviceofferingid string `json:"serviceofferingid,omitempty"` Serviceofferingname string `json:"serviceofferingname,omitempty"` Servicestate string `json:"servicestate,omitempty"` @@ -444,6 +460,18 @@ type CreateSSHKeyPairResponse struct { Privatekey string `json:"privatekey,omitempty"` } +type RemoveIpFromNicResponse struct { + JobID string `json:"jobid,omitempty"` +} + +type AddIpToNicResponse struct { + Id string `json:"id"` + IpAddress string `json:"ipaddress"` + NetworkId string `json:"networkid"` + NicId string `json:"nicid"` + VmId string `json:"virtualmachineid"` +} + type CreateAffinityGroupResponse struct { JobId string `json:"jobid,omitempty"` } diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/vm.go b/vendor/github.com/pyr/egoscale/src/egoscale/vm.go index 7735819c5..9668929c7 100644 --- a/vendor/github.com/pyr/egoscale/src/egoscale/vm.go +++ b/vendor/github.com/pyr/egoscale/src/egoscale/vm.go @@ -125,7 +125,6 @@ func (exo *Client) GetVirtualMachine(id string) (*VirtualMachine, error) { params.Set("id", id) resp, err := exo.Request("listVirtualMachines", params) - if err != nil { return nil, err } @@ -144,19 +143,14 @@ func (exo *Client) GetVirtualMachine(id string) (*VirtualMachine, error) { } } -func (exo *Client) ListVirtualMachines(id string) ([]*VirtualMachine, error) { - - params := url.Values{} - params.Set("id", id) - - resp, err := exo.Request("listVirtualMachines", params) +func (exo *Client) ListVirtualMachines() ([]*VirtualMachine, error) { + resp, err := exo.Request("listVirtualMachines", url.Values{}) if err != nil { return nil, err } var r ListVirtualMachinesResponse - if err := json.Unmarshal(resp, &r); err != nil { return nil, err } diff --git a/vendor/github.com/ryanuber/go-glob/glob.go b/vendor/github.com/ryanuber/go-glob/glob.go index d9d46379a..e67db3be1 100644 --- a/vendor/github.com/ryanuber/go-glob/glob.go +++ b/vendor/github.com/ryanuber/go-glob/glob.go @@ -30,20 +30,25 @@ func Glob(pattern, subj string) bool { trailingGlob := strings.HasSuffix(pattern, GLOB) end := len(parts) - 1 - // Check the first section. Requires special handling. - if !leadingGlob && !strings.HasPrefix(subj, parts[0]) { - return false - } + // Go over the leading parts and ensure they match. + for i := 0; i < end; i++ { + idx := strings.Index(subj, parts[i]) - // Go over the middle parts and ensure they match. - for i := 1; i < end; i++ { - if !strings.Contains(subj, parts[i]) { - return false + switch i { + case 0: + // Check the first section. Requires special handling. + if !leadingGlob && idx != 0 { + return false + } + default: + // Check that the middle parts match. + if idx < 0 { + return false + } } // Trim evaluated text from subj as we loop over the pattern. - idx := strings.Index(subj, parts[i]) + len(parts[i]) - subj = subj[idx:] + subj = subj[idx+len(parts[i]):] } // Reached the last section. Requires special handling. diff --git a/vendor/github.com/samuel/go-zookeeper/zk/conn.go b/vendor/github.com/samuel/go-zookeeper/zk/conn.go index ed87ca5ec..b6b8dbc1a 100644 --- a/vendor/github.com/samuel/go-zookeeper/zk/conn.go +++ b/vendor/github.com/samuel/go-zookeeper/zk/conn.go @@ -44,9 +44,9 @@ const ( type watchType int const ( - watchTypeData = iota - watchTypeExist = iota - watchTypeChild = iota + watchTypeData = iota + watchTypeExist + watchTypeChild ) type watchPathType struct { @@ -61,6 +61,11 @@ type Logger interface { Printf(string, ...interface{}) } +type authCreds struct { + scheme string + auth []byte +} + type Conn struct { lastZxid int64 sessionID int64 @@ -75,21 +80,28 @@ type Conn struct { server string // remember the address/port of the current server conn net.Conn eventChan chan Event + eventCallback EventCallback // may be nil shouldQuit chan struct{} pingInterval time.Duration recvTimeout time.Duration connectTimeout time.Duration + creds []authCreds + credsMu sync.Mutex // protects server + sendChan chan *request requests map[int32]*request // Xid -> pending request requestsLock sync.Mutex watchers map[watchPathType][]chan Event watchersLock sync.Mutex + closeChan chan struct{} // channel to tell send loop stop // Debug (used by unit tests) reconnectDelay time.Duration logger Logger + + buf []byte } // connOption represents a connection option. @@ -185,6 +197,7 @@ func Connect(servers []string, sessionTimeout time.Duration, options ...connOpti watchers: make(map[watchPathType][]chan Event), passwd: emptyPassword, logger: DefaultLogger, + buf: make([]byte, bufferSize), // Debug reconnectDelay: 0, @@ -224,6 +237,18 @@ func WithHostProvider(hostProvider HostProvider) connOption { } } +// EventCallback is a function that is called when an Event occurs. +type EventCallback func(Event) + +// WithEventCallback returns a connection option that specifies an event +// callback. +// The callback must not block - doing so would delay the ZK go routines. +func WithEventCallback(cb EventCallback) connOption { + return func(c *Conn) { + c.eventCallback = cb + } +} + func (c *Conn) Close() { close(c.shouldQuit) @@ -238,7 +263,7 @@ func (c *Conn) State() State { return State(atomic.LoadInt32((*int32)(&c.state))) } -// SessionId returns the current session id of the connection. +// SessionID returns the current session id of the connection. func (c *Conn) SessionID() int64 { return atomic.LoadInt64(&c.sessionID) } @@ -258,8 +283,16 @@ func (c *Conn) setTimeouts(sessionTimeoutMs int32) { func (c *Conn) setState(state State) { atomic.StoreInt32((*int32)(&c.state), int32(state)) + c.sendEvent(Event{Type: EventSession, State: state, Server: c.Server()}) +} + +func (c *Conn) sendEvent(evt Event) { + if c.eventCallback != nil { + c.eventCallback(evt) + } + select { - case c.eventChan <- Event{Type: EventSession, State: state, Server: c.Server()}: + case c.eventChan <- evt: default: // panic("zk: event channel full - it must be monitored and never allowed to be full") } @@ -296,6 +329,65 @@ func (c *Conn) connect() error { } } +func (c *Conn) resendZkAuth(reauthReadyChan chan struct{}) { + c.credsMu.Lock() + defer c.credsMu.Unlock() + + defer close(reauthReadyChan) + + c.logger.Printf("Re-submitting `%d` credentials after reconnect", + len(c.creds)) + + for _, cred := range c.creds { + resChan, err := c.sendRequest( + opSetAuth, + &setAuthRequest{Type: 0, + Scheme: cred.scheme, + Auth: cred.auth, + }, + &setAuthResponse{}, + nil) + + if err != nil { + c.logger.Printf("Call to sendRequest failed during credential resubmit: %s", err) + // FIXME(prozlach): lets ignore errors for now + continue + } + + res := <-resChan + if res.err != nil { + c.logger.Printf("Credential re-submit failed: %s", res.err) + // FIXME(prozlach): lets ignore errors for now + continue + } + } +} + +func (c *Conn) sendRequest( + opcode int32, + req interface{}, + res interface{}, + recvFunc func(*request, *responseHeader, error), +) ( + <-chan response, + error, +) { + rq := &request{ + xid: c.nextXid(), + opcode: opcode, + pkt: req, + recvStruct: res, + recvChan: make(chan response, 1), + recvFunc: recvFunc, + } + + if err := c.sendData(rq); err != nil { + return nil, err + } + + return rq.recvChan, nil +} + func (c *Conn) loop() { for { if err := c.connect(); err != nil { @@ -313,13 +405,15 @@ func (c *Conn) loop() { c.conn.Close() case err == nil: c.logger.Printf("Authenticated: id=%d, timeout=%d", c.SessionID(), c.sessionTimeoutMs) - c.hostProvider.Connected() // mark success - closeChan := make(chan struct{}) // channel to tell send loop stop - var wg sync.WaitGroup + c.hostProvider.Connected() // mark success + c.closeChan = make(chan struct{}) // channel to tell send loop stop + reauthChan := make(chan struct{}) // channel to tell send loop that authdata has been resubmitted + var wg sync.WaitGroup wg.Add(1) go func() { - err := c.sendLoop(c.conn, closeChan) + <-reauthChan + err := c.sendLoop() c.logger.Printf("Send loop terminated: err=%v", err) c.conn.Close() // causes recv loop to EOF/exit wg.Done() @@ -332,10 +426,12 @@ func (c *Conn) loop() { if err == nil { panic("zk: recvLoop should never return nil error") } - close(closeChan) // tell send loop to exit + close(c.closeChan) // tell send loop to exit wg.Done() }() + c.resendZkAuth(reauthChan) + c.sendSetWatches() wg.Wait() } @@ -507,66 +603,73 @@ func (c *Conn) authenticate() error { return nil } -func (c *Conn) sendLoop(conn net.Conn, closeChan <-chan struct{}) error { +func (c *Conn) sendData(req *request) error { + header := &requestHeader{req.xid, req.opcode} + n, err := encodePacket(c.buf[4:], header) + if err != nil { + req.recvChan <- response{-1, err} + return nil + } + + n2, err := encodePacket(c.buf[4+n:], req.pkt) + if err != nil { + req.recvChan <- response{-1, err} + return nil + } + + n += n2 + + binary.BigEndian.PutUint32(c.buf[:4], uint32(n)) + + c.requestsLock.Lock() + select { + case <-c.closeChan: + req.recvChan <- response{-1, ErrConnectionClosed} + c.requestsLock.Unlock() + return ErrConnectionClosed + default: + } + c.requests[req.xid] = req + c.requestsLock.Unlock() + + c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) + _, err = c.conn.Write(c.buf[:n+4]) + c.conn.SetWriteDeadline(time.Time{}) + if err != nil { + req.recvChan <- response{-1, err} + c.conn.Close() + return err + } + + return nil +} + +func (c *Conn) sendLoop() error { pingTicker := time.NewTicker(c.pingInterval) defer pingTicker.Stop() - buf := make([]byte, bufferSize) for { select { case req := <-c.sendChan: - header := &requestHeader{req.xid, req.opcode} - n, err := encodePacket(buf[4:], header) - if err != nil { - req.recvChan <- response{-1, err} - continue - } - - n2, err := encodePacket(buf[4+n:], req.pkt) - if err != nil { - req.recvChan <- response{-1, err} - continue - } - - n += n2 - - binary.BigEndian.PutUint32(buf[:4], uint32(n)) - - c.requestsLock.Lock() - select { - case <-closeChan: - req.recvChan <- response{-1, ErrConnectionClosed} - c.requestsLock.Unlock() - return ErrConnectionClosed - default: - } - c.requests[req.xid] = req - c.requestsLock.Unlock() - - conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) - _, err = conn.Write(buf[:n+4]) - conn.SetWriteDeadline(time.Time{}) - if err != nil { - req.recvChan <- response{-1, err} - conn.Close() + if err := c.sendData(req); err != nil { return err } case <-pingTicker.C: - n, err := encodePacket(buf[4:], &requestHeader{Xid: -2, Opcode: opPing}) + n, err := encodePacket(c.buf[4:], &requestHeader{Xid: -2, Opcode: opPing}) if err != nil { panic("zk: opPing should never fail to serialize") } - binary.BigEndian.PutUint32(buf[:4], uint32(n)) + binary.BigEndian.PutUint32(c.buf[:4], uint32(n)) - conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) - _, err = conn.Write(buf[:n+4]) - conn.SetWriteDeadline(time.Time{}) + c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) + _, err = c.conn.Write(c.buf[:n+4]) + c.conn.SetWriteDeadline(time.Time{}) if err != nil { - conn.Close() + c.conn.Close() return err } - case <-closeChan: + case <-c.closeChan: return nil } } @@ -611,10 +714,7 @@ func (c *Conn) recvLoop(conn net.Conn) error { Path: res.Path, Err: nil, } - select { - case c.eventChan <- ev: - default: - } + c.sendEvent(ev) wTypes := make([]watchType, 0, 2) switch res.Type { case EventNodeCreated: @@ -706,7 +806,28 @@ func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc func (c *Conn) AddAuth(scheme string, auth []byte) error { _, err := c.request(opSetAuth, &setAuthRequest{Type: 0, Scheme: scheme, Auth: auth}, &setAuthResponse{}, nil) - return err + + if err != nil { + return err + } + + // Remember authdata so that it can be re-submitted on reconnect + // + // FIXME(prozlach): For now we treat "userfoo:passbar" and "userfoo:passbar2" + // as two different entries, which will be re-submitted on reconnet. Some + // research is needed on how ZK treats these cases and + // then maybe switch to something like "map[username] = password" to allow + // only single password for given user with users being unique. + obj := authCreds{ + scheme: scheme, + auth: auth, + } + + c.credsMu.Lock() + c.creds = append(c.creds, obj) + c.credsMu.Unlock() + + return nil } func (c *Conn) Children(path string) ([]string, *Stat, error) { @@ -867,6 +988,7 @@ func (c *Conn) Sync(path string) (string, error) { type MultiResponse struct { Stat *Stat String string + Error error } // Multi executes multiple ZooKeeper operations or none of them. The provided @@ -897,7 +1019,7 @@ func (c *Conn) Multi(ops ...interface{}) ([]MultiResponse, error) { _, err := c.request(opMulti, req, res, nil) mr := make([]MultiResponse, len(res.Ops)) for i, op := range res.Ops { - mr[i] = MultiResponse{Stat: op.Stat, String: op.String} + mr[i] = MultiResponse{Stat: op.Stat, String: op.String, Error: op.Err.toError()} } return mr, err } diff --git a/vendor/github.com/samuel/go-zookeeper/zk/constants.go b/vendor/github.com/samuel/go-zookeeper/zk/constants.go index f9b39b904..33b5563b9 100644 --- a/vendor/github.com/samuel/go-zookeeper/zk/constants.go +++ b/vendor/github.com/samuel/go-zookeeper/zk/constants.go @@ -28,18 +28,19 @@ const ( opClose = -11 opSetAuth = 100 opSetWatches = 101 + opError = -1 // Not in protocol, used internally opWatcherEvent = -2 ) const ( - EventNodeCreated = EventType(1) - EventNodeDeleted = EventType(2) - EventNodeDataChanged = EventType(3) - EventNodeChildrenChanged = EventType(4) + EventNodeCreated EventType = 1 + EventNodeDeleted EventType = 2 + EventNodeDataChanged EventType = 3 + EventNodeChildrenChanged EventType = 4 - EventSession = EventType(-1) - EventNotWatching = EventType(-2) + EventSession EventType = -1 + EventNotWatching EventType = -2 ) var ( @@ -54,14 +55,13 @@ var ( ) const ( - StateUnknown = State(-1) - StateDisconnected = State(0) - StateConnecting = State(1) - StateAuthFailed = State(4) - StateConnectedReadOnly = State(5) - StateSaslAuthenticated = State(6) - StateExpired = State(-112) - // StateAuthFailed = State(-113) + StateUnknown State = -1 + StateDisconnected State = 0 + StateConnecting State = 1 + StateAuthFailed State = 4 + StateConnectedReadOnly State = 5 + StateSaslAuthenticated State = 6 + StateExpired State = -112 StateConnected = State(100) StateHasSession = State(101) @@ -154,20 +154,20 @@ const ( errBadArguments = -8 errInvalidState = -9 // API errors - errAPIError = ErrCode(-100) - errNoNode = ErrCode(-101) // * - errNoAuth = ErrCode(-102) - errBadVersion = ErrCode(-103) // * - errNoChildrenForEphemerals = ErrCode(-108) - errNodeExists = ErrCode(-110) // * - errNotEmpty = ErrCode(-111) - errSessionExpired = ErrCode(-112) - errInvalidCallback = ErrCode(-113) - errInvalidAcl = ErrCode(-114) - errAuthFailed = ErrCode(-115) - errClosing = ErrCode(-116) - errNothing = ErrCode(-117) - errSessionMoved = ErrCode(-118) + errAPIError ErrCode = -100 + errNoNode ErrCode = -101 // * + errNoAuth ErrCode = -102 + errBadVersion ErrCode = -103 // * + errNoChildrenForEphemerals ErrCode = -108 + errNodeExists ErrCode = -110 // * + errNotEmpty ErrCode = -111 + errSessionExpired ErrCode = -112 + errInvalidCallback ErrCode = -113 + errInvalidAcl ErrCode = -114 + errAuthFailed ErrCode = -115 + errClosing ErrCode = -116 + errNothing ErrCode = -117 + errSessionMoved ErrCode = -118 ) // Constants for ACL permissions diff --git a/vendor/github.com/samuel/go-zookeeper/zk/lock.go b/vendor/github.com/samuel/go-zookeeper/zk/lock.go index f13a8b0ba..3c35a427c 100644 --- a/vendor/github.com/samuel/go-zookeeper/zk/lock.go +++ b/vendor/github.com/samuel/go-zookeeper/zk/lock.go @@ -58,8 +58,16 @@ func (l *Lock) Lock() error { parts := strings.Split(l.path, "/") pth := "" for _, p := range parts[1:] { + var exists bool pth += "/" + p - _, err := l.c.Create(pth, []byte{}, 0, l.acl) + exists, _, err = l.c.Exists(pth) + if err != nil { + return err + } + if exists == true { + continue + } + _, err = l.c.Create(pth, []byte{}, 0, l.acl) if err != nil && err != ErrNodeExists { return err } @@ -86,7 +94,7 @@ func (l *Lock) Lock() error { } lowestSeq := seq - prevSeq := 0 + prevSeq := -1 prevSeqPath := "" for _, p := range children { s, err := parseSeq(p) diff --git a/vendor/github.com/samuel/go-zookeeper/zk/server_help.go b/vendor/github.com/samuel/go-zookeeper/zk/server_help.go index 618185a23..3663064ca 100644 --- a/vendor/github.com/samuel/go-zookeeper/zk/server_help.go +++ b/vendor/github.com/samuel/go-zookeeper/zk/server_help.go @@ -99,37 +99,41 @@ func StartTestCluster(size int, stdout, stderr io.Writer) (*TestCluster, error) return cluster, nil } -func (ts *TestCluster) Connect(idx int) (*Conn, error) { - zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15) +func (tc *TestCluster) Connect(idx int) (*Conn, error) { + zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", tc.Servers[idx].Port)}, time.Second*15) return zk, err } -func (ts *TestCluster) ConnectAll() (*Conn, <-chan Event, error) { - return ts.ConnectAllTimeout(time.Second * 15) +func (tc *TestCluster) ConnectAll() (*Conn, <-chan Event, error) { + return tc.ConnectAllTimeout(time.Second * 15) } -func (ts *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) { - hosts := make([]string, len(ts.Servers)) - for i, srv := range ts.Servers { +func (tc *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) { + return tc.ConnectWithOptions(sessionTimeout) +} + +func (tc *TestCluster) ConnectWithOptions(sessionTimeout time.Duration, options ...connOption) (*Conn, <-chan Event, error) { + hosts := make([]string, len(tc.Servers)) + for i, srv := range tc.Servers { hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port) } - zk, ch, err := Connect(hosts, sessionTimeout) + zk, ch, err := Connect(hosts, sessionTimeout, options...) return zk, ch, err } -func (ts *TestCluster) Stop() error { - for _, srv := range ts.Servers { +func (tc *TestCluster) Stop() error { + for _, srv := range tc.Servers { srv.Srv.Stop() } - defer os.RemoveAll(ts.Path) - return ts.waitForStop(5, time.Second) + defer os.RemoveAll(tc.Path) + return tc.waitForStop(5, time.Second) } // waitForStart blocks until the cluster is up -func (ts *TestCluster) waitForStart(maxRetry int, interval time.Duration) error { +func (tc *TestCluster) waitForStart(maxRetry int, interval time.Duration) error { // verify that the servers are up with SRVR - serverAddrs := make([]string, len(ts.Servers)) - for i, s := range ts.Servers { + serverAddrs := make([]string, len(tc.Servers)) + for i, s := range tc.Servers { serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port) } @@ -144,10 +148,10 @@ func (ts *TestCluster) waitForStart(maxRetry int, interval time.Duration) error } // waitForStop blocks until the cluster is down -func (ts *TestCluster) waitForStop(maxRetry int, interval time.Duration) error { +func (tc *TestCluster) waitForStop(maxRetry int, interval time.Duration) error { // verify that the servers are up with RUOK - serverAddrs := make([]string, len(ts.Servers)) - for i, s := range ts.Servers { + serverAddrs := make([]string, len(tc.Servers)) + for i, s := range tc.Servers { serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port) } @@ -188,3 +192,25 @@ func (tc *TestCluster) StopServer(server string) { } panic(fmt.Sprintf("Unknown server: %s", server)) } + +func (tc *TestCluster) StartAllServers() error { + for _, s := range tc.Servers { + if err := s.Srv.Start(); err != nil { + return fmt.Errorf( + "Failed to start server listening on port `%d` : %+v", s.Port, err) + } + } + + return nil +} + +func (tc *TestCluster) StopAllServers() error { + for _, s := range tc.Servers { + if err := s.Srv.Stop(); err != nil { + return fmt.Errorf( + "Failed to stop server listening on port `%d` : %+v", s.Port, err) + } + } + + return nil +} diff --git a/vendor/github.com/samuel/go-zookeeper/zk/structs.go b/vendor/github.com/samuel/go-zookeeper/zk/structs.go index 02cd3f353..d4af27dea 100644 --- a/vendor/github.com/samuel/go-zookeeper/zk/structs.go +++ b/vendor/github.com/samuel/go-zookeeper/zk/structs.go @@ -270,6 +270,7 @@ type multiResponseOp struct { Header multiHeader String string Stat *Stat + Err ErrCode } type multiResponse struct { Ops []multiResponseOp @@ -327,6 +328,8 @@ func (r *multiRequest) Decode(buf []byte) (int, error) { } func (r *multiResponse) Decode(buf []byte) (int, error) { + var multiErr error + r.Ops = make([]multiResponseOp, 0) r.DoneHeader = multiHeader{-1, true, -1} total := 0 @@ -347,6 +350,8 @@ func (r *multiResponse) Decode(buf []byte) (int, error) { switch header.Type { default: return total, ErrAPIError + case opError: + w = reflect.ValueOf(&res.Err) case opCreate: w = reflect.ValueOf(&res.String) case opSetData: @@ -362,8 +367,12 @@ func (r *multiResponse) Decode(buf []byte) (int, error) { total += n } r.Ops = append(r.Ops, res) + if multiErr == nil && res.Err != errOk { + // Use the first error as the error returned from Multi(). + multiErr = res.Err.toError() + } } - return total, nil + return total, multiErr } type watcherEvent struct { diff --git a/vendor/github.com/streamrail/concurrent-map/concurrent_map.go b/vendor/github.com/streamrail/concurrent-map/concurrent_map.go index 72428a4d8..f6e5c06c5 100644 --- a/vendor/github.com/streamrail/concurrent-map/concurrent_map.go +++ b/vendor/github.com/streamrail/concurrent-map/concurrent_map.go @@ -2,7 +2,6 @@ package cmap import ( "encoding/json" - "hash/fnv" "sync" ) @@ -29,9 +28,7 @@ func New() ConcurrentMap { // Returns shard under given key func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared { - hasher := fnv.New32() - hasher.Write([]byte(key)) - return m[uint(hasher.Sum32())%uint(SHARD_COUNT)] + return m[uint(fnv32(key))%uint(SHARD_COUNT)] } func (m ConcurrentMap) MSet(data map[string]interface{}) { @@ -52,6 +49,23 @@ func (m *ConcurrentMap) Set(key string, value interface{}) { shard.Unlock() } +// Callback to return new element to be inserted into the map +// It is called while lock is held, therefore it MUST NOT +// try to access other keys in same map, as it can lead to deadlock since +// Go sync.RWLock is not reentrant +type UpsertCb func(exist bool, valueInMap interface{}, newValue interface{}) interface{} + +// Insert or Update - updates existing element or inserts a new one using UpsertCb +func (m *ConcurrentMap) Upsert(key string, value interface{}, cb UpsertCb) (res interface{}) { + shard := m.GetShard(key) + shard.Lock() + v, ok := shard.items[key] + res = cb(ok, v, value) + shard.items[key] = res + shard.Unlock() + return res +} + // Sets the given value under the specified key if no value was associated with it. func (m *ConcurrentMap) SetIfAbsent(key string, value interface{}) bool { // Get map shard. @@ -108,6 +122,17 @@ func (m *ConcurrentMap) Remove(key string) { shard.Unlock() } +// Removes an element from the map and returns it +func (m *ConcurrentMap) Pop(key string) (v interface{}, exists bool) { + // Try to get shard. + shard := m.GetShard(key) + shard.Lock() + v, exists = shard.items[key] + delete(shard.items, key) + shard.Unlock() + return v, exists +} + // Checks if map is empty. func (m *ConcurrentMap) IsEmpty() bool { return m.Count() == 0 @@ -181,6 +206,25 @@ func (m ConcurrentMap) Items() map[string]interface{} { return tmp } +// Iterator callback,called for every key,value found in +// maps. RLock is held for all calls for a given shard +// therefore callback sess consistent view of a shard, +// but not across the shards +type IterCb func(key string, v interface{}) + +// Callback based iterator, cheapest way to read +// all elements in a map. +func (m *ConcurrentMap) IterCb(fn IterCb) { + for idx := range *m { + shard := (*m)[idx] + shard.RLock() + for key, value := range shard.items { + fn(key, value) + } + shard.RUnlock() + } +} + // Return all keys as []string func (m ConcurrentMap) Keys() []string { count := m.Count() @@ -224,6 +268,16 @@ func (m ConcurrentMap) MarshalJSON() ([]byte, error) { return json.Marshal(tmp) } +func fnv32(key string) uint32 { + hash := uint32(2166136261) + const prime32 = uint32(16777619) + for i := 0; i < len(key); i++ { + hash *= prime32 + hash ^= uint32(key[i]) + } + return hash +} + // Concurrent map uses Interface{} as its value, therefor JSON Unmarshal // will probably won't know which to type to unmarshal into, in such case // we'll end up with a value of type map[string]interface{}, In most cases this isn't diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index e6a796046..aa4311ff8 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -1,386 +1,351 @@ /* * CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen * THIS FILE MUST NOT BE EDITED BY HAND -*/ + */ package assert import ( - http "net/http" url "net/url" time "time" ) - // Condition uses a Comparison to assert a complex condition. func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { return Condition(a.t, comp, msgAndArgs...) } - // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. -// +// // a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") // a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") // a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { return Contains(a.t, s, contains, msgAndArgs...) } - // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. -// +// // a.Empty(obj) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { return Empty(a.t, object, msgAndArgs...) } - // Equal asserts that two objects are equal. -// +// // a.Equal(123, 123, "123 and 123 should be equal") -// +// // Returns whether the assertion was successful (true) or not (false). +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return Equal(a.t, expected, actual, msgAndArgs...) } - // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. -// +// // actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// +// a.EqualError(err, expectedErrorString, "An error was expected") +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { return EqualError(a.t, theError, errString, msgAndArgs...) } - // EqualValues asserts that two objects are equal or convertable to the same types // and equal. -// +// // a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return EqualValues(a.t, expected, actual, msgAndArgs...) } - // Error asserts that a function returned an error (i.e. not `nil`). -// +// // actualObj, err := SomeFunction() // if a.Error(err, "An error was expected") { // assert.Equal(t, err, expectedError) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { return Error(a.t, err, msgAndArgs...) } - // Exactly asserts that two objects are equal is value and type. -// +// // a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return Exactly(a.t, expected, actual, msgAndArgs...) } - // Fail reports a failure through func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { return Fail(a.t, failureMessage, msgAndArgs...) } - // FailNow fails test func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { return FailNow(a.t, failureMessage, msgAndArgs...) } - // False asserts that the specified value is false. -// +// // a.False(myBool, "myBool should be false") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { return False(a.t, value, msgAndArgs...) } - // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. -// +// // a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { return HTTPBodyContains(a.t, handler, method, url, values, str) } - // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. -// +// // a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { return HTTPBodyNotContains(a.t, handler, method, url, values, str) } - // HTTPError asserts that a specified handler returns an error status code. -// +// // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPError(a.t, handler, method, url, values) } - // HTTPRedirect asserts that a specified handler returns a redirect status code. -// +// // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPRedirect(a.t, handler, method, url, values) } - // HTTPSuccess asserts that a specified handler returns a success status code. -// +// // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPSuccess(a.t, handler, method, url, values) } - // Implements asserts that an object is implemented by the specified interface. -// +// // a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { return Implements(a.t, interfaceObject, object, msgAndArgs...) } - // InDelta asserts that the two numerals are within delta of each other. -// +// // a.InDelta(math.Pi, (22 / 7.0), 0.01) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { return InDelta(a.t, expected, actual, delta, msgAndArgs...) } - // InDeltaSlice is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) } - // InEpsilon asserts that expected and actual have a relative error less than epsilon -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) } - -// InEpsilonSlice is the same as InEpsilon, except it compares two slices. -func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - return InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...) +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) } - // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { return IsType(a.t, expectedType, object, msgAndArgs...) } - // JSONEq asserts that two JSON strings are equivalent. -// +// // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { return JSONEq(a.t, expected, actual, msgAndArgs...) } - // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. -// +// // a.Len(mySlice, 3, "The size of slice is not 3") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { return Len(a.t, object, length, msgAndArgs...) } - // Nil asserts that the specified object is nil. -// +// // a.Nil(err, "err should be nothing") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { return Nil(a.t, object, msgAndArgs...) } - // NoError asserts that a function returned no error (i.e. `nil`). -// +// // actualObj, err := SomeFunction() // if a.NoError(err) { // assert.Equal(t, actualObj, expectedObj) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { return NoError(a.t, err, msgAndArgs...) } - // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. -// +// // a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") // a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") // a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { return NotContains(a.t, s, contains, msgAndArgs...) } - // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. -// +// // if a.NotEmpty(obj) { // assert.Equal(t, "two", obj[1]) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { return NotEmpty(a.t, object, msgAndArgs...) } - // NotEqual asserts that the specified values are NOT equal. -// +// // a.NotEqual(obj1, obj2, "two objects shouldn't be equal") -// +// // Returns whether the assertion was successful (true) or not (false). +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return NotEqual(a.t, expected, actual, msgAndArgs...) } - // NotNil asserts that the specified object is not nil. -// +// // a.NotNil(err, "err should be something") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { return NotNil(a.t, object, msgAndArgs...) } - // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// +// // a.NotPanics(func(){ // RemainCalm() // }, "Calling RemainCalm() should NOT panic") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { return NotPanics(a.t, f, msgAndArgs...) } - // NotRegexp asserts that a specified regexp does not match a string. -// +// // a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp("^start", "it's not starting") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { return NotRegexp(a.t, rx, str, msgAndArgs...) } - // NotZero asserts that i is not the zero value for its type and returns the truth. func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { return NotZero(a.t, i, msgAndArgs...) } - // Panics asserts that the code inside the specified PanicTestFunc panics. -// +// // a.Panics(func(){ // GoCrazy() // }, "Calling GoCrazy() should panic") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { return Panics(a.t, f, msgAndArgs...) } - // Regexp asserts that a specified regexp matches a string. -// +// // a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp("start...$", "it's not starting") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { return Regexp(a.t, rx, str, msgAndArgs...) } - // True asserts that the specified value is true. -// +// // a.True(myBool, "myBool should be true") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { return True(a.t, value, msgAndArgs...) } - // WithinDuration asserts that the two times are within duration delta of each other. -// +// // a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) } - // Zero asserts that i is the zero value for its type and returns the truth. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { return Zero(a.t, i, msgAndArgs...) diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index b3f4e170d..d1552e5e3 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -18,10 +18,6 @@ import ( "github.com/pmezard/go-difflib/difflib" ) -func init() { - spew.Config.SortKeys = true -} - // TestingT is an interface wrapper around *testing.T type TestingT interface { Errorf(format string, args ...interface{}) @@ -157,7 +153,7 @@ func getWhitespaceString() string { parts := strings.Split(file, "/") file = parts[len(parts)-1] - return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line))) + return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line))) } @@ -174,22 +170,18 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { return "" } -// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's -// test printing (see inner comment for specifics) -func indentMessageLines(message string, tabs int) string { +// Aligns the provided message so that all lines after the first line start at the same location as the first line. +// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). +// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the +// basis on which the alignment occurs). +func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { + // no need to align first line because it starts at the correct location (after the label) if i != 0 { - outBuf.WriteRune('\n') - } - for ii := 0; ii < tabs; ii++ { - outBuf.WriteRune('\t') - // Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter - // by 1 prematurely. - if ii == 0 && i > 0 { - ii++ - } + // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab + outBuf.WriteString("\n\r\t" + strings.Repeat(" ", longestLabelLen +1) + "\t") } outBuf.WriteString(scanner.Text()) } @@ -221,29 +213,49 @@ func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool // Fail reports a failure through func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { - - message := messageFromMsgAndArgs(msgAndArgs...) - - errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t") - if len(message) > 0 { - t.Errorf("\r%s\r\tError Trace:\t%s\n"+ - "\r\tError:%s\n"+ - "\r\tMessages:\t%s\n\r", - getWhitespaceString(), - errorTrace, - indentMessageLines(failureMessage, 2), - message) - } else { - t.Errorf("\r%s\r\tError Trace:\t%s\n"+ - "\r\tError:%s\n\r", - getWhitespaceString(), - errorTrace, - indentMessageLines(failureMessage, 2)) + content := []labeledContent{ + {"Error Trace", strings.Join(CallerInfo(), "\n\r\t\t\t")}, + {"Error", failureMessage}, } + message := messageFromMsgAndArgs(msgAndArgs...) + if len(message) > 0 { + content = append(content, labeledContent{"Messages", message}) + } + + t.Errorf("\r" + getWhitespaceString() + labeledOutput(content...)) + return false } +type labeledContent struct { + label string + content string +} + +// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: +// +// \r\t{{label}}:{{align_spaces}}\t{{content}}\n +// +// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. +// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this +// alignment is achieved, "\t{{content}}\n" is added for the output. +// +// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. +func labeledOutput(content ...labeledContent) string { + longestLabel := 0 + for _, v := range content { + if len(v.label) > longestLabel { + longestLabel = len(v.label) + } + } + var output string + for _, v := range content { + output += "\r\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" + } + return output +} + // Implements asserts that an object is implemented by the specified interface. // // assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject") @@ -274,13 +286,17 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs // assert.Equal(t, 123, 123, "123 and 123 should be equal") // // Returns whether the assertion was successful (true) or not (false). +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if !ObjectsAreEqual(expected, actual) { diff := diff(expected, actual) expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: %s (expected)\n"+ - " != %s (actual)%s", expected, actual, diff), msgAndArgs...) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "received: %s%s", expected, actual, diff), msgAndArgs...) } return true @@ -294,31 +310,15 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) // with the type name, and the value will be enclosed in parenthesis similar // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { - aType := reflect.TypeOf(expected) - bType := reflect.TypeOf(actual) - - if aType != bType && isNumericType(aType) && isNumericType(bType) { - return fmt.Sprintf("%v(%#v)", aType, expected), - fmt.Sprintf("%v(%#v)", bType, actual) + if reflect.TypeOf(expected) != reflect.TypeOf(actual) { + return fmt.Sprintf("%T(%#v)", expected, expected), + fmt.Sprintf("%T(%#v)", actual, actual) } return fmt.Sprintf("%#v", expected), fmt.Sprintf("%#v", actual) } -func isNumericType(t reflect.Type) bool { - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return true - case reflect.Float32, reflect.Float64: - return true - } - - return false -} - // EqualValues asserts that two objects are equal or convertable to the same types // and equal. // @@ -328,8 +328,11 @@ func isNumericType(t reflect.Type) bool { func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if !ObjectsAreEqualValues(expected, actual) { - return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)", expected, actual), msgAndArgs...) + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "received: %s%s", expected, actual, diff), msgAndArgs...) } return true @@ -556,6 +559,9 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { // assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal") // // Returns whether the assertion was successful (true) or not (false). +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if ObjectsAreEqual(expected, actual) { @@ -882,7 +888,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m // Returns whether the assertion was successful (true) or not (false). func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if err != nil { - return Fail(t, fmt.Sprintf("Received unexpected error %+v", err), msgAndArgs...) + return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) } return true @@ -913,14 +919,18 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { // // Returns whether the assertion was successful (true) or not (false). func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { - - message := messageFromMsgAndArgs(msgAndArgs...) - if !NotNil(t, theError, "An error is expected but got nil. %s", message) { + if !Error(t, theError, msgAndArgs...) { return false } - s := "An error with value \"%s\" is expected but got \"%s\". %s" - return Equal(t, errString, theError.Error(), - s, errString, theError.Error(), message) + expected := errString + actual := theError.Error() + // don't need to use deep equals here, we know they are both strings + if expected != actual { + return Fail(t, fmt.Sprintf("Error message not equal:\n"+ + "expected: %q\n"+ + "received: %q", expected, actual), msgAndArgs...) + } + return true } // matchRegexp return true if a specified regexp matches a string. @@ -1035,8 +1045,8 @@ func diff(expected interface{}, actual interface{}) string { return "" } - e := spew.Sdump(expected) - a := spew.Sdump(actual) + e := spewConfig.Sdump(expected) + a := spewConfig.Sdump(actual) diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ A: difflib.SplitLines(e), @@ -1050,3 +1060,10 @@ func diff(expected interface{}, actual interface{}) string { return "\n\nDiff:\n" + diff } + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, +} diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go index 20d7b8b1f..744684702 100644 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -15,10 +15,6 @@ import ( "github.com/stretchr/testify/assert" ) -func inin() { - spew.Config.SortKeys = true -} - // TestingT is an interface wrapper around *testing.T type TestingT interface { Logf(format string, args ...interface{}) @@ -283,7 +279,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { functionPath := runtime.FuncForPC(pc).Name() //Next four lines are required to use GCCGO function naming conventions. //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock - //uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree + //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree //With GCCGO we need to remove interface information starting from pN
. re := regexp.MustCompile("\\.pN\\d+_") if re.MatchString(functionPath) { @@ -746,8 +742,8 @@ func diff(expected interface{}, actual interface{}) string { return "" } - e := spew.Sdump(expected) - a := spew.Sdump(actual) + e := spewConfig.Sdump(expected) + a := spewConfig.Sdump(actual) diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ A: difflib.SplitLines(e), @@ -761,3 +757,10 @@ func diff(expected interface{}, actual interface{}) string { return diff } + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, +} diff --git a/vendor/github.com/unrolled/render/buffer.go b/vendor/github.com/unrolled/render/buffer.go index 29dac7361..cdc92ffbd 100644 --- a/vendor/github.com/unrolled/render/buffer.go +++ b/vendor/github.com/unrolled/render/buffer.go @@ -39,3 +39,8 @@ func (bp *BufferPool) Put(b *bytes.Buffer) { default: // Discard the buffer if the pool is full. } } + +// Initialize buffer pool for writing templates into. +func init() { + bufPool = NewBufferPool(64) +} diff --git a/vendor/github.com/unrolled/render/engine.go b/vendor/github.com/unrolled/render/engine.go index 92da1399e..cdf1a1b16 100644 --- a/vendor/github.com/unrolled/render/engine.go +++ b/vendor/github.com/unrolled/render/engine.go @@ -5,12 +5,13 @@ import ( "encoding/json" "encoding/xml" "html/template" + "io" "net/http" ) // Engine is the generic interface for all responses. type Engine interface { - Render(http.ResponseWriter, interface{}) error + Render(io.Writer, interface{}) error } // Head defines the basic ContentType and Status fields. @@ -66,19 +67,21 @@ func (h Head) Write(w http.ResponseWriter) { } // Render a data response. -func (d Data) Render(w http.ResponseWriter, v interface{}) error { - c := w.Header().Get(ContentType) - if c != "" { - d.Head.ContentType = c +func (d Data) Render(w io.Writer, v interface{}) error { + if hw, ok := w.(http.ResponseWriter); ok { + c := hw.Header().Get(ContentType) + if c != "" { + d.Head.ContentType = c + } + d.Head.Write(hw) } - d.Head.Write(w) w.Write(v.([]byte)) return nil } // Render a HTML response. -func (h HTML) Render(w http.ResponseWriter, binding interface{}) error { +func (h HTML) Render(w io.Writer, binding interface{}) error { // Retrieve a buffer from the pool to write to. out := bufPool.Get() err := h.Templates.ExecuteTemplate(out, h.Name, binding) @@ -86,7 +89,9 @@ func (h HTML) Render(w http.ResponseWriter, binding interface{}) error { return err } - h.Head.Write(w) + if hw, ok := w.(http.ResponseWriter); ok { + h.Head.Write(hw) + } out.WriteTo(w) // Return the buffer to the pool. @@ -95,7 +100,7 @@ func (h HTML) Render(w http.ResponseWriter, binding interface{}) error { } // Render a JSON response. -func (j JSON) Render(w http.ResponseWriter, v interface{}) error { +func (j JSON) Render(w io.Writer, v interface{}) error { if j.StreamingJSON { return j.renderStreamingJSON(w, v) } @@ -121,7 +126,9 @@ func (j JSON) Render(w http.ResponseWriter, v interface{}) error { } // JSON marshaled fine, write out the result. - j.Head.Write(w) + if hw, ok := w.(http.ResponseWriter); ok { + j.Head.Write(hw) + } if len(j.Prefix) > 0 { w.Write(j.Prefix) } @@ -129,8 +136,10 @@ func (j JSON) Render(w http.ResponseWriter, v interface{}) error { return nil } -func (j JSON) renderStreamingJSON(w http.ResponseWriter, v interface{}) error { - j.Head.Write(w) +func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error { + if hw, ok := w.(http.ResponseWriter); ok { + j.Head.Write(hw) + } if len(j.Prefix) > 0 { w.Write(j.Prefix) } @@ -139,7 +148,7 @@ func (j JSON) renderStreamingJSON(w http.ResponseWriter, v interface{}) error { } // Render a JSONP response. -func (j JSONP) Render(w http.ResponseWriter, v interface{}) error { +func (j JSONP) Render(w io.Writer, v interface{}) error { var result []byte var err error @@ -153,7 +162,9 @@ func (j JSONP) Render(w http.ResponseWriter, v interface{}) error { } // JSON marshaled fine, write out the result. - j.Head.Write(w) + if hw, ok := w.(http.ResponseWriter); ok { + j.Head.Write(hw) + } w.Write([]byte(j.Callback + "(")) w.Write(result) w.Write([]byte(");")) @@ -166,19 +177,21 @@ func (j JSONP) Render(w http.ResponseWriter, v interface{}) error { } // Render a text response. -func (t Text) Render(w http.ResponseWriter, v interface{}) error { - c := w.Header().Get(ContentType) - if c != "" { - t.Head.ContentType = c +func (t Text) Render(w io.Writer, v interface{}) error { + if hw, ok := w.(http.ResponseWriter); ok { + c := hw.Header().Get(ContentType) + if c != "" { + t.Head.ContentType = c + } + t.Head.Write(hw) } - t.Head.Write(w) w.Write([]byte(v.(string))) return nil } // Render an XML response. -func (x XML) Render(w http.ResponseWriter, v interface{}) error { +func (x XML) Render(w io.Writer, v interface{}) error { var result []byte var err error @@ -193,7 +206,9 @@ func (x XML) Render(w http.ResponseWriter, v interface{}) error { } // XML marshaled fine, write out the result. - x.Head.Write(w) + if hw, ok := w.(http.ResponseWriter); ok { + x.Head.Write(hw) + } if len(x.Prefix) > 0 { w.Write(x.Prefix) } diff --git a/vendor/github.com/unrolled/render/render.go b/vendor/github.com/unrolled/render/render.go index 636a84823..662bf1ed7 100644 --- a/vendor/github.com/unrolled/render/render.go +++ b/vendor/github.com/unrolled/render/render.go @@ -4,12 +4,14 @@ import ( "bytes" "fmt" "html/template" + "io" "io/ioutil" "log" "net/http" "os" "path/filepath" "strings" + "sync" ) const ( @@ -85,6 +87,8 @@ type Options struct { RequireBlocks bool // Disables automatic rendering of http.StatusInternalServerError when an error occurs. Default is false. DisableHTTPErrorRendering bool + // Enables using partials without the current filename suffix which allows use of the same template in multiple files. e.g {{ partial "carosuel" }} inside the home template will match carosel-home or carosel. + RenderPartialsWithoutPrefix bool } // HTMLOptions is a struct for overriding some rendering Options for specific HTML call. @@ -99,6 +103,7 @@ type Render struct { // Customize Secure with an Options struct. opt Options templates *template.Template + templatesLk sync.Mutex compiledCharset string } @@ -118,11 +123,6 @@ func New(options ...Options) *Render { r.prepareOptions() r.compileTemplates() - // Create a new buffer pool for writing templates into. - if bufPool == nil { - bufPool = NewBufferPool(64) - } - return &r } @@ -270,6 +270,9 @@ func (r *Render) addLayoutFuncs(name string, binding interface{}) { "block": func(partialName string) (template.HTML, error) { log.Print("Render's `block` implementation is now depericated. Use `partial` as a drop in replacement.") fullPartialName := fmt.Sprintf("%s-%s", partialName, name) + if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix { + fullPartialName = partialName + } if r.opt.RequireBlocks || r.TemplateLookup(fullPartialName) != nil { buf, err := r.execute(fullPartialName, binding) // Return safe HTML here since we are rendering our own template. @@ -279,6 +282,9 @@ func (r *Render) addLayoutFuncs(name string, binding interface{}) { }, "partial": func(partialName string) (template.HTML, error) { fullPartialName := fmt.Sprintf("%s-%s", partialName, name) + if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix { + fullPartialName = partialName + } if r.opt.RequirePartials || r.TemplateLookup(fullPartialName) != nil { buf, err := r.execute(fullPartialName, binding) // Return safe HTML here since we are rendering our own template. @@ -303,16 +309,16 @@ func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { } // Render is the generic function called by XML, JSON, Data, HTML, and can be called by custom implementations. -func (r *Render) Render(w http.ResponseWriter, e Engine, data interface{}) error { +func (r *Render) Render(w io.Writer, e Engine, data interface{}) error { err := e.Render(w, data) - if err != nil && !r.opt.DisableHTTPErrorRendering { - http.Error(w, err.Error(), http.StatusInternalServerError) + if hw, ok := w.(http.ResponseWriter); err != nil && !r.opt.DisableHTTPErrorRendering && ok { + http.Error(hw, err.Error(), http.StatusInternalServerError) } return err } // Data writes out the raw bytes as binary data. -func (r *Render) Data(w http.ResponseWriter, status int, v []byte) error { +func (r *Render) Data(w io.Writer, status int, v []byte) error { head := Head{ ContentType: ContentBinary, Status: status, @@ -326,7 +332,10 @@ func (r *Render) Data(w http.ResponseWriter, status int, v []byte) error { } // HTML builds up the response from the specified template and bindings. -func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) error { +func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) error { + r.templatesLk.Lock() + defer r.templatesLk.Unlock() + // If we are in development mode, recompile the templates on every HTML request. if r.opt.IsDevelopment { r.compileTemplates() @@ -354,7 +363,7 @@ func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding in } // JSON marshals the given interface object and writes the JSON response. -func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) error { +func (r *Render) JSON(w io.Writer, status int, v interface{}) error { head := Head{ ContentType: ContentJSON + r.compiledCharset, Status: status, @@ -372,7 +381,7 @@ func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) error { } // JSONP marshals the given interface object and writes the JSON response. -func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v interface{}) error { +func (r *Render) JSONP(w io.Writer, status int, callback string, v interface{}) error { head := Head{ ContentType: ContentJSONP + r.compiledCharset, Status: status, @@ -388,7 +397,7 @@ func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v int } // Text writes out a string as plain text. -func (r *Render) Text(w http.ResponseWriter, status int, v string) error { +func (r *Render) Text(w io.Writer, status int, v string) error { head := Head{ ContentType: ContentText + r.compiledCharset, Status: status, @@ -402,7 +411,7 @@ func (r *Render) Text(w http.ResponseWriter, status int, v string) error { } // XML marshals the given interface object and writes the XML response. -func (r *Render) XML(w http.ResponseWriter, status int, v interface{}) error { +func (r *Render) XML(w io.Writer, status int, v interface{}) error { head := Head{ ContentType: ContentXML + r.compiledCharset, Status: status, diff --git a/vendor/github.com/vulcand/oxy/forward/fwd.go b/vendor/github.com/vulcand/oxy/forward/fwd.go index 19490443e..4b358e425 100644 --- a/vendor/github.com/vulcand/oxy/forward/fwd.go +++ b/vendor/github.com/vulcand/oxy/forward/fwd.go @@ -171,7 +171,7 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx w.WriteHeader(response.StatusCode) stream := f.streamResponse - if ! stream { + if !stream { contentType, err := utils.GetHeaderMediaType(response.Header, ContentType) if err == nil { stream = contentType == "text/event-stream" @@ -253,7 +253,7 @@ func (f *websocketForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, if outReq.URL.Scheme == "wss" { if f.TLSClientConfig == nil { - f.TLSClientConfig = &tls.Config{} + f.TLSClientConfig = http.DefaultTransport.(*http.Transport).TLSClientConfig } dial = func(network, address string) (net.Conn, error) { return tls.Dial("tcp", host, f.TLSClientConfig) @@ -282,6 +282,8 @@ func (f *websocketForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, defer underlyingConn.Close() defer targetConn.Close() + ctx.log.Infof("Writing outgoing Websocket request to target connection: %+v", outReq) + // write the modified incoming request to the dialed connection if err = outReq.Write(targetConn); err != nil { ctx.log.Errorf("Unable to copy request to target: %v", err) @@ -305,6 +307,15 @@ func (f *websocketForwarder) copyRequest(req *http.Request, u *url.URL) (outReq outReq.URL = utils.CopyURL(req.URL) outReq.URL.Scheme = u.Scheme + + //sometimes backends might be registered as HTTP/HTTPS servers so translate URLs to websocket URLs. + switch u.Scheme { + case "https": + outReq.URL.Scheme = "wss" + case "http": + outReq.URL.Scheme = "ws" + } + outReq.URL.Host = u.Host outReq.URL.Opaque = req.RequestURI // raw query is already included in RequestURI, so ignore it to avoid dupes diff --git a/vendor/gopkg.in/fsnotify.v1/fsnotify.go b/vendor/gopkg.in/fsnotify.v1/fsnotify.go index d1d39a0eb..e7f55fee7 100644 --- a/vendor/gopkg.in/fsnotify.v1/fsnotify.go +++ b/vendor/gopkg.in/fsnotify.v1/fsnotify.go @@ -30,33 +30,33 @@ const ( Chmod ) -// String returns a string representation of the event in the form -// "file: REMOVE|WRITE|..." -func (e Event) String() string { +func (op Op) String() string { // Use a buffer for efficient string concatenation var buffer bytes.Buffer - if e.Op&Create == Create { + if op&Create == Create { buffer.WriteString("|CREATE") } - if e.Op&Remove == Remove { + if op&Remove == Remove { buffer.WriteString("|REMOVE") } - if e.Op&Write == Write { + if op&Write == Write { buffer.WriteString("|WRITE") } - if e.Op&Rename == Rename { + if op&Rename == Rename { buffer.WriteString("|RENAME") } - if e.Op&Chmod == Chmod { + if op&Chmod == Chmod { buffer.WriteString("|CHMOD") } - - // If buffer remains empty, return no event names if buffer.Len() == 0 { - return fmt.Sprintf("%q: ", e.Name) + return "" } - - // Return a list of event names, with leading pipe character stripped - return fmt.Sprintf("%q: %s", e.Name, buffer.String()[1:]) + return buffer.String()[1:] // Strip leading pipe +} + +// String returns a string representation of the event in the form +// "file: REMOVE|WRITE|..." +func (e Event) String() string { + return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) } diff --git a/vendor/gopkg.in/fsnotify.v1/inotify.go b/vendor/gopkg.in/fsnotify.v1/inotify.go index 9700df55e..f3b74c51f 100644 --- a/vendor/gopkg.in/fsnotify.v1/inotify.go +++ b/vendor/gopkg.in/fsnotify.v1/inotify.go @@ -36,7 +36,7 @@ type Watcher struct { // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. func NewWatcher() (*Watcher, error) { // Create inotify fd - fd, errno := unix.InotifyInit() + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) if fd == -1 { return nil, errno } diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index 50abd815f..5211d5abc 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -37,7 +37,7 @@ const ( // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 - _VERSION = "1.23.0" + _VERSION = "1.27.0" ) // Version returns current package version literal. @@ -173,9 +173,13 @@ type LoadOptions struct { Insensitive bool // IgnoreContinuation indicates whether to ignore continuation lines while parsing. IgnoreContinuation bool + // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. + IgnoreInlineComment bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool + // AllowShadows indicates whether to keep track of keys with same name under same section. + AllowShadows bool // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise // conform to key/value pairs. Specify the names of those blocks here. UnparseableSections []string @@ -219,6 +223,12 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } +// InsensitiveLoad has exactly same functionality as Load function +// except it allows have shadow keys. +func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{AllowShadows: true}, source, others...) +} + // Empty returns an empty file object. func Empty() *File { // Ignore error here, we sure our data is good. @@ -311,6 +321,11 @@ func (f *File) Sections() []*Section { return sections } +// ChildSections returns a list of child sections of given section name. +func (f *File) ChildSections(name string) []*Section { + return f.Section(name).ChildSections() +} + // SectionStrings returns list of section names. func (f *File) SectionStrings() []string { list := make([]string, len(f.sectionList)) @@ -441,6 +456,7 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { } alignSpaces := bytes.Repeat([]byte(" "), alignLength) + KEY_LIST: for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { @@ -467,28 +483,33 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` } - if _, err = buf.WriteString(kname); err != nil { - return 0, err - } - if key.isBooleanType { - continue - } + for _, val := range key.ValueWithShadows() { + if _, err = buf.WriteString(kname); err != nil { + return 0, err + } - // Write out alignment spaces before "=" sign - if PrettyFormat { - buf.Write(alignSpaces[:alignLength-len(kname)]) - } + if key.isBooleanType { + if kname != sec.keyList[len(sec.keyList)-1] { + buf.WriteString(LineBreak) + } + continue KEY_LIST + } - val := key.value - // In case key value contains "\n", "`", "\"", "#" or ";" - if strings.ContainsAny(val, "\n`") { - val = `"""` + val + `"""` - } else if strings.ContainsAny(val, "#;") { - val = "`" + val + "`" - } - if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { - return 0, err + // Write out alignment spaces before "=" sign + if PrettyFormat { + buf.Write(alignSpaces[:alignLength-len(kname)]) + } + + // In case key value contains "\n", "`", "\"", "#" or ";" + if strings.ContainsAny(val, "\n`") { + val = `"""` + val + `"""` + } else if strings.ContainsAny(val, "#;") { + val = "`" + val + "`" + } + if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { + return 0, err + } } } diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go index 9738c55a2..838356af0 100644 --- a/vendor/gopkg.in/ini.v1/key.go +++ b/vendor/gopkg.in/ini.v1/key.go @@ -15,6 +15,7 @@ package ini import ( + "errors" "fmt" "strconv" "strings" @@ -29,9 +30,42 @@ type Key struct { isAutoIncrement bool isBooleanType bool + isShadow bool + shadows []*Key + Comment string } +// newKey simply return a key object with given values. +func newKey(s *Section, name, val string) *Key { + return &Key{ + s: s, + name: name, + value: val, + } +} + +func (k *Key) addShadow(val string) error { + if k.isShadow { + return errors.New("cannot add shadow to another shadow key") + } else if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add shadow to auto-increment or boolean key") + } + + shadow := newKey(k.s, k.name, val) + shadow.isShadow = true + k.shadows = append(k.shadows, shadow) + return nil +} + +// AddShadow adds a new shadow key to itself. +func (k *Key) AddShadow(val string) error { + if !k.s.f.options.AllowShadows { + return errors.New("shadow key is not allowed") + } + return k.addShadow(val) +} + // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv type ValueMapper func(string) string @@ -45,16 +79,29 @@ func (k *Key) Value() string { return k.value } -// String returns string representation of value. -func (k *Key) String() string { - val := k.value +// ValueWithShadows returns raw values of key and its shadows if any. +func (k *Key) ValueWithShadows() []string { + if len(k.shadows) == 0 { + return []string{k.value} + } + vals := make([]string, len(k.shadows)+1) + vals[0] = k.value + for i := range k.shadows { + vals[i+1] = k.shadows[i].value + } + return vals +} + +// transformValue takes a raw value and transforms to its final string. +func (k *Key) transformValue(val string) string { if k.s.f.ValueMapper != nil { val = k.s.f.ValueMapper(val) } - if strings.Index(val, "%") == -1 { + + // Fail-fast if no indicate char found for recursive value + if !strings.Contains(val, "%") { return val } - for i := 0; i < _DEPTH_VALUES; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { @@ -78,6 +125,11 @@ func (k *Key) String() string { return val } +// String returns string representation of value. +func (k *Key) String() string { + return k.transformValue(k.value) +} + // Validate accepts a validate function which can // return modifed result as key value. func (k *Key) Validate(fn func(string) string) string { @@ -394,45 +446,65 @@ func (k *Key) Strings(delim string) []string { vals := strings.Split(str, delim) for i := range vals { + // vals[i] = k.transformValue(strings.TrimSpace(vals[i])) vals[i] = strings.TrimSpace(vals[i]) } return vals } +// StringsWithShadows returns list of string divided by given delimiter. +// Shadows will also be appended if any. +func (k *Key) StringsWithShadows(delim string) []string { + vals := k.ValueWithShadows() + results := make([]string, 0, len(vals)*2) + for i := range vals { + if len(vals) == 0 { + continue + } + + results = append(results, strings.Split(vals[i], delim)...) + } + + for i := range results { + results[i] = k.transformValue(strings.TrimSpace(results[i])) + } + return results +} + // Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Float64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, true, false) + vals, _ := k.parseFloat64s(k.Strings(delim), true, false) return vals } // Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Ints(delim string) []int { - vals, _ := k.getInts(delim, true, false) + vals, _ := k.parseInts(k.Strings(delim), true, false) return vals } // Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Int64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, true, false) + vals, _ := k.parseInt64s(k.Strings(delim), true, false) return vals } // Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uints(delim string) []uint { - vals, _ := k.getUints(delim, true, false) + vals, _ := k.parseUints(k.Strings(delim), true, false) return vals } // Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, true, false) + vals, _ := k.parseUint64s(k.Strings(delim), true, false) return vals } // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, true, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) return vals } @@ -445,41 +517,41 @@ func (k *Key) Times(delim string) []time.Time { // ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then // it will not be included to result list. func (k *Key) ValidFloat64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, false, false) + vals, _ := k.parseFloat64s(k.Strings(delim), false, false) return vals } // ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will // not be included to result list. func (k *Key) ValidInts(delim string) []int { - vals, _ := k.getInts(delim, false, false) + vals, _ := k.parseInts(k.Strings(delim), false, false) return vals } // ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, // then it will not be included to result list. func (k *Key) ValidInt64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, false, false) + vals, _ := k.parseInt64s(k.Strings(delim), false, false) return vals } // ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, // then it will not be included to result list. func (k *Key) ValidUints(delim string) []uint { - vals, _ := k.getUints(delim, false, false) + vals, _ := k.parseUints(k.Strings(delim), false, false) return vals } // ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned // integer, then it will not be included to result list. func (k *Key) ValidUint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, false, false) + vals, _ := k.parseUint64s(k.Strings(delim), false, false) return vals } // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, false, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) return vals } @@ -490,33 +562,33 @@ func (k *Key) ValidTimes(delim string) []time.Time { // StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. func (k *Key) StrictFloat64s(delim string) ([]float64, error) { - return k.getFloat64s(delim, false, true) + return k.parseFloat64s(k.Strings(delim), false, true) } // StrictInts returns list of int divided by given delimiter or error on first invalid input. func (k *Key) StrictInts(delim string) ([]int, error) { - return k.getInts(delim, false, true) + return k.parseInts(k.Strings(delim), false, true) } // StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. func (k *Key) StrictInt64s(delim string) ([]int64, error) { - return k.getInt64s(delim, false, true) + return k.parseInt64s(k.Strings(delim), false, true) } // StrictUints returns list of uint divided by given delimiter or error on first invalid input. func (k *Key) StrictUints(delim string) ([]uint, error) { - return k.getUints(delim, false, true) + return k.parseUints(k.Strings(delim), false, true) } // StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. func (k *Key) StrictUint64s(delim string) ([]uint64, error) { - return k.getUint64s(delim, false, true) + return k.parseUint64s(k.Strings(delim), false, true) } // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { - return k.getTimesFormat(format, delim, false, true) + return k.parseTimesFormat(format, k.Strings(delim), false, true) } // StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter @@ -525,9 +597,8 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } -// getFloat64s returns list of float64 divided by given delimiter. -func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]float64, error) { - strs := k.Strings(delim) +// parseFloat64s transforms strings to float64s. +func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseFloat(str, 64) @@ -541,9 +612,8 @@ func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]flo return vals, nil } -// getInts returns list of int divided by given delimiter. -func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, error) { - strs := k.Strings(delim) +// parseInts transforms strings to ints. +func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) for _, str := range strs { val, err := strconv.Atoi(str) @@ -557,9 +627,8 @@ func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, er return vals, nil } -// getInt64s returns list of int64 divided by given delimiter. -func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64, error) { - strs := k.Strings(delim) +// parseInt64s transforms strings to int64s. +func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseInt(str, 10, 64) @@ -573,9 +642,8 @@ func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64 return vals, nil } -// getUints returns list of uint divided by given delimiter. -func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, error) { - strs := k.Strings(delim) +// parseUints transforms strings to uints. +func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 0) @@ -589,9 +657,8 @@ func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, return vals, nil } -// getUint64s returns list of uint64 divided by given delimiter. -func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint64, error) { - strs := k.Strings(delim) +// parseUint64s transforms strings to uint64s. +func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 64) @@ -605,9 +672,8 @@ func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint return vals, nil } -// getTimesFormat parses with given format and returns list of time.Time divided by given delimiter. -func (k *Key) getTimesFormat(format, delim string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { - strs := k.Strings(delim) +// parseTimesFormat transforms strings to times in given format. +func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { vals := make([]time.Time, 0, len(strs)) for _, str := range strs { val, err := time.Parse(format, str) diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index b0aabe33b..6c0b10745 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -193,7 +193,7 @@ func hasSurroundedQuote(in string, quote byte) bool { strings.IndexByte(in[1:], quote) == len(in)-2 } -func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { +func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { return "", nil @@ -217,18 +217,21 @@ func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { return line[startIdx : pos+startIdx], nil } - // Won't be able to reach here if value only contains whitespace. + // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) - // Check continuation lines when desired. + // Check continuation lines when desired if !ignoreContinuation && line[len(line)-1] == '\\' { return p.readContinuationLines(line[:len(line)-1]) } - i := strings.IndexAny(line, "#;") - if i > -1 { - p.comment.WriteString(line[i:]) - line = strings.TrimSpace(line[:i]) + // Check if ignore inline comment + if !ignoreInlineComment { + i := strings.IndexAny(line, "#;") + if i > -1 { + p.comment.WriteString(line[i:]) + line = strings.TrimSpace(line[:i]) + } } // Trim single quotes @@ -318,11 +321,14 @@ func (f *File) parse(reader io.Reader) (err error) { if err != nil { // Treat as boolean key when desired, and whole line is key name. if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { - key, err := section.NewKey(string(line), "true") + kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) if err != nil { return err } - key.isBooleanType = true key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() continue @@ -338,17 +344,16 @@ func (f *File) parse(reader io.Reader) (err error) { p.count++ } - key, err := section.NewKey(kname, "") + value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment) + if err != nil { + return err + } + + key, err := section.NewKey(kname, value) if err != nil { return err } key.isAutoIncrement = isAutoIncr - - value, err := p.readValue(line[offset:], f.options.IgnoreContinuation) - if err != nil { - return err - } - key.SetValue(value) key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index 45d2f3bfd..94f7375ed 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -68,20 +68,33 @@ func (s *Section) NewKey(name, val string) (*Key, error) { } if inSlice(name, s.keyList) { - s.keys[name].value = val + if s.f.options.AllowShadows { + if err := s.keys[name].addShadow(val); err != nil { + return nil, err + } + } else { + s.keys[name].value = val + } return s.keys[name], nil } s.keyList = append(s.keyList, name) - s.keys[name] = &Key{ - s: s, - name: name, - value: val, - } + s.keys[name] = newKey(s, name, val) s.keysHash[name] = val return s.keys[name], nil } +// NewBooleanKey creates a new boolean type key to given section. +func (s *Section) NewBooleanKey(name string) (*Key, error) { + key, err := s.NewKey(name, "true") + if err != nil { + return nil, err + } + + key.isBooleanType = true + return key, nil +} + // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { // FIXME: change to section level lock? @@ -219,3 +232,17 @@ func (s *Section) DeleteKey(name string) { } } } + +// ChildSections returns a list of child sections of current section. +// For example, "[parent.child1]" and "[parent.child12]" are child sections +// of section "[parent]". +func (s *Section) ChildSections() []*Section { + prefix := s.name + "." + children := make([]*Section, 0, 3) + for _, name := range s.f.sectionList { + if strings.HasPrefix(name, prefix) { + children = append(children, s.f.sections[name]) + } + } + return children +} diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go index d00fb4b83..031c78b8e 100644 --- a/vendor/gopkg.in/ini.v1/struct.go +++ b/vendor/gopkg.in/ini.v1/struct.go @@ -78,8 +78,14 @@ func parseDelim(actual string) string { var reflectTime = reflect.TypeOf(time.Now()).Kind() // setSliceWithProperType sets proper values to slice based on its type. -func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { - strs := key.Strings(delim) +func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { + var strs []string + if allowShadow { + strs = key.StringsWithShadows(delim) + } else { + strs = key.Strings(delim) + } + numVals := len(strs) if numVals == 0 { return nil @@ -92,17 +98,17 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { case reflect.String: vals = strs case reflect.Int: - vals = key.Ints(delim) + vals, _ = key.parseInts(strs, true, false) case reflect.Int64: - vals = key.Int64s(delim) + vals, _ = key.parseInt64s(strs, true, false) case reflect.Uint: - vals = key.Uints(delim) + vals, _ = key.parseUints(strs, true, false) case reflect.Uint64: - vals = key.Uint64s(delim) + vals, _ = key.parseUint64s(strs, true, false) case reflect.Float64: - vals = key.Float64s(delim) + vals, _ = key.parseFloat64s(strs, true, false) case reflectTime: - vals = key.Times(delim) + vals, _ = key.parseTimesFormat(time.RFC3339, strs, true, false) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } @@ -133,7 +139,7 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, // because we want to use default value that is already assigned to strcut. -func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { +func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { switch t.Kind() { case reflect.String: if len(key.String()) == 0 { @@ -174,7 +180,7 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri } field.SetUint(uintVal) - case reflect.Float64: + case reflect.Float32, reflect.Float64: floatVal, err := key.Float64() if err != nil { return nil @@ -187,13 +193,25 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri } field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: - return setSliceWithProperType(key, field, delim) + return setSliceWithProperType(key, field, delim, allowShadow) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } +func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { + opts := strings.SplitN(tag, ",", 3) + rawName = opts[0] + if len(opts) > 1 { + omitEmpty = opts[1] == "omitempty" + } + if len(opts) > 2 { + allowShadow = opts[2] == "allowshadow" + } + return rawName, omitEmpty, allowShadow +} + func (s *Section) mapTo(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() @@ -209,8 +227,8 @@ func (s *Section) mapTo(val reflect.Value) error { continue } - opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty - fieldName := s.parseFieldName(tpField.Name, opts[0]) + rawName, _, allowShadow := parseTagOptions(tag) + fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } @@ -231,7 +249,8 @@ func (s *Section) mapTo(val reflect.Value) error { } if key, err := s.GetKey(fieldName); err == nil { - if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { + delim := parseDelim(tpField.Tag.Get("delim")) + if err = setWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } } diff --git a/vendor/gopkg.in/mgo.v2/bson/bson.go b/vendor/gopkg.in/mgo.v2/bson/bson.go index 579aec13f..7fb7f8cae 100644 --- a/vendor/gopkg.in/mgo.v2/bson/bson.go +++ b/vendor/gopkg.in/mgo.v2/bson/bson.go @@ -38,6 +38,7 @@ import ( "crypto/rand" "encoding/binary" "encoding/hex" + "encoding/json" "errors" "fmt" "io" @@ -204,6 +205,7 @@ func readRandomUint32() uint32 { // machineId stores machine id generated once and used in subsequent calls // to NewObjectId function. var machineId = readMachineId() +var processId = os.Getpid() // readMachineId generates and returns a machine id. // If this function fails to get the hostname it will cause a runtime error. @@ -234,9 +236,8 @@ func NewObjectId() ObjectId { b[5] = machineId[1] b[6] = machineId[2] // Pid, 2 bytes, specs don't specify endianness, but we use big endian. - pid := os.Getpid() - b[7] = byte(pid >> 8) - b[8] = byte(pid) + b[7] = byte(processId >> 8) + b[8] = byte(processId) // Increment, 3 bytes, big endian i := atomic.AddUint32(&objectIdCounter, 1) b[9] = byte(i >> 16) @@ -276,6 +277,22 @@ var nullBytes = []byte("null") // UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. func (id *ObjectId) UnmarshalJSON(data []byte) error { + if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { + var v struct { + Id json.RawMessage `json:"$oid"` + Func struct { + Id json.RawMessage + } `json:"$oidFunc"` + } + err := jdec(data, &v) + if err == nil { + if len(v.Id) > 0 { + data = []byte(v.Id) + } else { + data = []byte(v.Func.Id) + } + } + } if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { *id = "" return nil diff --git a/vendor/gopkg.in/mgo.v2/bson/decimal.go b/vendor/gopkg.in/mgo.v2/bson/decimal.go new file mode 100644 index 000000000..3d2f70020 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/decimal.go @@ -0,0 +1,310 @@ +// BSON library for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// 2. 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 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. + +package bson + +import ( + "fmt" + "strconv" + "strings" +) + +// Decimal128 holds decimal128 BSON values. +type Decimal128 struct { + h, l uint64 +} + +func (d Decimal128) String() string { + var pos int // positive sign + var e int // exponent + var h, l uint64 // significand high/low + + if d.h>>63&1 == 0 { + pos = 1 + } + + switch d.h >> 58 & (1<<5 - 1) { + case 0x1F: + return "NaN" + case 0x1E: + return "-Inf"[pos:] + } + + l = d.l + if d.h>>61&3 == 3 { + // Bits: 1*sign 2*ignored 14*exponent 111*significand. + // Implicit 0b100 prefix in significand. + e = int(d.h>>47&(1<<14-1)) - 6176 + //h = 4<<47 | d.h&(1<<47-1) + // Spec says all of these values are out of range. + h, l = 0, 0 + } else { + // Bits: 1*sign 14*exponent 113*significand + e = int(d.h>>49&(1<<14-1)) - 6176 + h = d.h & (1<<49 - 1) + } + + // Would be handled by the logic below, but that's trivial and common. + if h == 0 && l == 0 && e == 0 { + return "-0"[pos:] + } + + var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero. + var last = len(repr) + var i = len(repr) + var dot = len(repr) + e + var rem uint32 +Loop: + for d9 := 0; d9 < 5; d9++ { + h, l, rem = divmod(h, l, 1e9) + for d1 := 0; d1 < 9; d1++ { + // Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc. + if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) { + e += len(repr) - i + i-- + repr[i] = '.' + last = i - 1 + dot = len(repr) // Unmark. + } + c := '0' + byte(rem%10) + rem /= 10 + i-- + repr[i] = c + // Handle "0E+3", "1E+3", etc. + if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) { + last = i + break Loop + } + if c != '0' { + last = i + } + // Break early. Works without it, but why. + if dot > i && l == 0 && h == 0 && rem == 0 { + break Loop + } + } + } + repr[last-1] = '-' + last-- + + if e > 0 { + return string(repr[last+pos:]) + "E+" + strconv.Itoa(e) + } + if e < 0 { + return string(repr[last+pos:]) + "E" + strconv.Itoa(e) + } + return string(repr[last+pos:]) +} + +func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { + div64 := uint64(div) + a := h >> 32 + aq := a / div64 + ar := a % div64 + b := ar<<32 + h&(1<<32-1) + bq := b / div64 + br := b % div64 + c := br<<32 + l>>32 + cq := c / div64 + cr := c % div64 + d := cr<<32 + l&(1<<32-1) + dq := d / div64 + dr := d % div64 + return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) +} + +var dNaN = Decimal128{0x1F << 58, 0} +var dPosInf = Decimal128{0x1E << 58, 0} +var dNegInf = Decimal128{0x3E << 58, 0} + +func dErr(s string) (Decimal128, error) { + return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) +} + +func ParseDecimal128(s string) (Decimal128, error) { + orig := s + if s == "" { + return dErr(orig) + } + neg := s[0] == '-' + if neg || s[0] == '+' { + s = s[1:] + } + + if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') { + if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") { + return dNaN, nil + } + if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { + if neg { + return dNegInf, nil + } + return dPosInf, nil + } + return dErr(orig) + } + + var h, l uint64 + var e int + + var add, ovr uint32 + var mul uint32 = 1 + var dot = -1 + var digits = 0 + var i = 0 + for i < len(s) { + c := s[i] + if mul == 1e9 { + h, l, ovr = muladd(h, l, mul, add) + mul, add = 1, 0 + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if c >= '0' && c <= '9' { + i++ + if c > '0' || digits > 0 { + digits++ + } + if digits > 34 { + if c == '0' { + // Exact rounding. + e++ + continue + } + return dErr(orig) + } + mul *= 10 + add *= 10 + add += uint32(c - '0') + continue + } + if c == '.' { + i++ + if dot >= 0 || i == 1 && len(s) == 1 { + return dErr(orig) + } + if i == len(s) { + break + } + if s[i] < '0' || s[i] > '9' || e > 0 { + return dErr(orig) + } + dot = i + continue + } + break + } + if i == 0 { + return dErr(orig) + } + if mul > 1 { + h, l, ovr = muladd(h, l, mul, add) + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if dot >= 0 { + e += dot - i + } + if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') { + i++ + eneg := s[i] == '-' + if eneg || s[i] == '+' { + i++ + if i == len(s) { + return dErr(orig) + } + } + n := 0 + for i < len(s) && n < 1e4 { + c := s[i] + i++ + if c < '0' || c > '9' { + return dErr(orig) + } + n *= 10 + n += int(c - '0') + } + if eneg { + n = -n + } + e += n + for e < -6176 { + // Subnormal. + var div uint32 = 1 + for div < 1e9 && e < -6176 { + div *= 10 + e++ + } + var rem uint32 + h, l, rem = divmod(h, l, div) + if rem > 0 { + return dErr(orig) + } + } + for e > 6111 { + // Clamped. + var mul uint32 = 1 + for mul < 1e9 && e > 6111 { + mul *= 10 + e-- + } + h, l, ovr = muladd(h, l, mul, 0) + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if e < -6176 || e > 6111 { + return dErr(orig) + } + } + + if i < len(s) { + return dErr(orig) + } + + h |= uint64(e+6176) & uint64(1<<14-1) << 49 + if neg { + h |= 1 << 63 + } + return Decimal128{h, l}, nil +} + +func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) { + mul64 := uint64(mul) + a := mul64 * (l & (1<<32 - 1)) + b := a>>32 + mul64*(l>>32) + c := b>>32 + mul64*(h&(1<<32-1)) + d := c>>32 + mul64*(h>>32) + + a = a&(1<<32-1) + uint64(add) + b = b&(1<<32-1) + a>>32 + c = c&(1<<32-1) + b>>32 + d = d&(1<<32-1) + c>>32 + + return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32) +} diff --git a/vendor/gopkg.in/mgo.v2/bson/decode.go b/vendor/gopkg.in/mgo.v2/bson/decode.go index 9bd73f966..7c2d8416a 100644 --- a/vendor/gopkg.in/mgo.v2/bson/decode.go +++ b/vendor/gopkg.in/mgo.v2/bson/decode.go @@ -539,6 +539,11 @@ func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) { in = MongoTimestamp(d.readInt64()) case 0x12: // Int64 in = d.readInt64() + case 0x13: // Decimal128 + in = Decimal128{ + l: uint64(d.readInt64()), + h: uint64(d.readInt64()), + } case 0x7F: // Max key in = MaxKey case 0xFF: // Min key diff --git a/vendor/gopkg.in/mgo.v2/bson/encode.go b/vendor/gopkg.in/mgo.v2/bson/encode.go index c228e28d3..add39e865 100644 --- a/vendor/gopkg.in/mgo.v2/bson/encode.go +++ b/vendor/gopkg.in/mgo.v2/bson/encode.go @@ -247,7 +247,7 @@ func (e *encoder) addElemName(kind byte, name string) { func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { if !v.IsValid() { - e.addElemName('\x0A', name) + e.addElemName(0x0A, name) return } @@ -276,29 +276,29 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { panic("ObjectIDs must be exactly 12 bytes long (got " + strconv.Itoa(len(s)) + ")") } - e.addElemName('\x07', name) + e.addElemName(0x07, name) e.addBytes([]byte(s)...) case typeSymbol: - e.addElemName('\x0E', name) + e.addElemName(0x0E, name) e.addStr(s) case typeJSONNumber: n := v.Interface().(json.Number) if i, err := n.Int64(); err == nil { - e.addElemName('\x12', name) + e.addElemName(0x12, name) e.addInt64(i) } else if f, err := n.Float64(); err == nil { - e.addElemName('\x01', name) + e.addElemName(0x01, name) e.addFloat64(f) } else { panic("failed to convert json.Number to a number: " + s) } default: - e.addElemName('\x02', name) + e.addElemName(0x02, name) e.addStr(s) } case reflect.Float32, reflect.Float64: - e.addElemName('\x01', name) + e.addElemName(0x01, name) e.addFloat64(v.Float()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: @@ -306,40 +306,40 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { if int64(u) < 0 { panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { - e.addElemName('\x10', name) + e.addElemName(0x10, name) e.addInt32(int32(u)) } else { - e.addElemName('\x12', name) + e.addElemName(0x12, name) e.addInt64(int64(u)) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch v.Type() { case typeMongoTimestamp: - e.addElemName('\x11', name) + e.addElemName(0x11, name) e.addInt64(v.Int()) case typeOrderKey: if v.Int() == int64(MaxKey) { - e.addElemName('\x7F', name) + e.addElemName(0x7F, name) } else { - e.addElemName('\xFF', name) + e.addElemName(0xFF, name) } default: i := v.Int() if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { // It fits into an int32, encode as such. - e.addElemName('\x10', name) + e.addElemName(0x10, name) e.addInt32(int32(i)) } else { - e.addElemName('\x12', name) + e.addElemName(0x12, name) e.addInt64(i) } } case reflect.Bool: - e.addElemName('\x08', name) + e.addElemName(0x08, name) if v.Bool() { e.addBytes(1) } else { @@ -347,40 +347,40 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { } case reflect.Map: - e.addElemName('\x03', name) + e.addElemName(0x03, name) e.addDoc(v) case reflect.Slice: vt := v.Type() et := vt.Elem() if et.Kind() == reflect.Uint8 { - e.addElemName('\x05', name) - e.addBinary('\x00', v.Bytes()) + e.addElemName(0x05, name) + e.addBinary(0x00, v.Bytes()) } else if et == typeDocElem || et == typeRawDocElem { - e.addElemName('\x03', name) + e.addElemName(0x03, name) e.addDoc(v) } else { - e.addElemName('\x04', name) + e.addElemName(0x04, name) e.addDoc(v) } case reflect.Array: et := v.Type().Elem() if et.Kind() == reflect.Uint8 { - e.addElemName('\x05', name) + e.addElemName(0x05, name) if v.CanAddr() { - e.addBinary('\x00', v.Slice(0, v.Len()).Interface().([]byte)) + e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte)) } else { n := v.Len() e.addInt32(int32(n)) - e.addBytes('\x00') + e.addBytes(0x00) for i := 0; i < n; i++ { el := v.Index(i) e.addBytes(byte(el.Uint())) } } } else { - e.addElemName('\x04', name) + e.addElemName(0x04, name) e.addDoc(v) } @@ -399,11 +399,16 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { e.addBytes(s.Data...) case Binary: - e.addElemName('\x05', name) + e.addElemName(0x05, name) e.addBinary(s.Kind, s.Data) + case Decimal128: + e.addElemName(0x13, name) + e.addInt64(int64(s.l)) + e.addInt64(int64(s.h)) + case DBPointer: - e.addElemName('\x0C', name) + e.addElemName(0x0C, name) e.addStr(s.Namespace) if len(s.Id) != 12 { panic("ObjectIDs must be exactly 12 bytes long (got " + @@ -412,16 +417,16 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { e.addBytes([]byte(s.Id)...) case RegEx: - e.addElemName('\x0B', name) + e.addElemName(0x0B, name) e.addCStr(s.Pattern) e.addCStr(s.Options) case JavaScript: if s.Scope == nil { - e.addElemName('\x0D', name) + e.addElemName(0x0D, name) e.addStr(s.Code) } else { - e.addElemName('\x0F', name) + e.addElemName(0x0F, name) start := e.reserveInt32() e.addStr(s.Code) e.addDoc(reflect.ValueOf(s.Scope)) @@ -430,18 +435,18 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { case time.Time: // MongoDB handles timestamps as milliseconds. - e.addElemName('\x09', name) + e.addElemName(0x09, name) e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) case url.URL: - e.addElemName('\x02', name) + e.addElemName(0x02, name) e.addStr(s.String()) case undefined: - e.addElemName('\x06', name) + e.addElemName(0x06, name) default: - e.addElemName('\x03', name) + e.addElemName(0x03, name) e.addDoc(v) } diff --git a/vendor/gopkg.in/mgo.v2/bson/json.go b/vendor/gopkg.in/mgo.v2/bson/json.go new file mode 100644 index 000000000..09df8260a --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/json.go @@ -0,0 +1,380 @@ +package bson + +import ( + "bytes" + "encoding/base64" + "fmt" + "gopkg.in/mgo.v2/internal/json" + "strconv" + "time" +) + +// UnmarshalJSON unmarshals a JSON value that may hold non-standard +// syntax as defined in BSON's extended JSON specification. +func UnmarshalJSON(data []byte, value interface{}) error { + d := json.NewDecoder(bytes.NewBuffer(data)) + d.Extend(&jsonExt) + return d.Decode(value) +} + +// MarshalJSON marshals a JSON value that may hold non-standard +// syntax as defined in BSON's extended JSON specification. +func MarshalJSON(value interface{}) ([]byte, error) { + var buf bytes.Buffer + e := json.NewEncoder(&buf) + e.Extend(&jsonExt) + err := e.Encode(value) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// jdec is used internally by the JSON decoding functions +// so they may unmarshal functions without getting into endless +// recursion due to keyed objects. +func jdec(data []byte, value interface{}) error { + d := json.NewDecoder(bytes.NewBuffer(data)) + d.Extend(&funcExt) + return d.Decode(value) +} + +var jsonExt json.Extension +var funcExt json.Extension + +// TODO +// - Shell regular expressions ("/regexp/opts") + +func init() { + jsonExt.DecodeUnquotedKeys(true) + jsonExt.DecodeTrailingCommas(true) + + funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary") + jsonExt.DecodeKeyed("$binary", jdecBinary) + jsonExt.DecodeKeyed("$binaryFunc", jdecBinary) + jsonExt.EncodeType([]byte(nil), jencBinarySlice) + jsonExt.EncodeType(Binary{}, jencBinaryType) + + funcExt.DecodeFunc("ISODate", "$dateFunc", "S") + funcExt.DecodeFunc("new Date", "$dateFunc", "S") + jsonExt.DecodeKeyed("$date", jdecDate) + jsonExt.DecodeKeyed("$dateFunc", jdecDate) + jsonExt.EncodeType(time.Time{}, jencDate) + + funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i") + jsonExt.DecodeKeyed("$timestamp", jdecTimestamp) + jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp) + + funcExt.DecodeConst("undefined", Undefined) + + jsonExt.DecodeKeyed("$regex", jdecRegEx) + jsonExt.EncodeType(RegEx{}, jencRegEx) + + funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id") + jsonExt.DecodeKeyed("$oid", jdecObjectId) + jsonExt.DecodeKeyed("$oidFunc", jdecObjectId) + jsonExt.EncodeType(ObjectId(""), jencObjectId) + + funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id") + jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef) + + funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N") + jsonExt.DecodeKeyed("$numberLong", jdecNumberLong) + jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong) + jsonExt.EncodeType(int64(0), jencNumberLong) + jsonExt.EncodeType(int(0), jencInt) + + funcExt.DecodeConst("MinKey", MinKey) + funcExt.DecodeConst("MaxKey", MaxKey) + jsonExt.DecodeKeyed("$minKey", jdecMinKey) + jsonExt.DecodeKeyed("$maxKey", jdecMaxKey) + jsonExt.EncodeType(orderKey(0), jencMinMaxKey) + + jsonExt.DecodeKeyed("$undefined", jdecUndefined) + jsonExt.EncodeType(Undefined, jencUndefined) + + jsonExt.Extend(&funcExt) +} + +func fbytes(format string, args ...interface{}) []byte { + var buf bytes.Buffer + fmt.Fprintf(&buf, format, args...) + return buf.Bytes() +} + +func jdecBinary(data []byte) (interface{}, error) { + var v struct { + Binary []byte `json:"$binary"` + Type string `json:"$type"` + Func struct { + Binary []byte `json:"$binary"` + Type int64 `json:"$type"` + } `json:"$binaryFunc"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + + var binData []byte + var binKind int64 + if v.Type == "" && v.Binary == nil { + binData = v.Func.Binary + binKind = v.Func.Type + } else if v.Type == "" { + return v.Binary, nil + } else { + binData = v.Binary + binKind, err = strconv.ParseInt(v.Type, 0, 64) + if err != nil { + binKind = -1 + } + } + + if binKind == 0 { + return binData, nil + } + if binKind < 0 || binKind > 255 { + return nil, fmt.Errorf("invalid type in binary object: %s", data) + } + + return Binary{Kind: byte(binKind), Data: binData}, nil +} + +func jencBinarySlice(v interface{}) ([]byte, error) { + in := v.([]byte) + out := make([]byte, base64.StdEncoding.EncodedLen(len(in))) + base64.StdEncoding.Encode(out, in) + return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil +} + +func jencBinaryType(v interface{}) ([]byte, error) { + in := v.(Binary) + out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data))) + base64.StdEncoding.Encode(out, in.Data) + return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil +} + +const jdateFormat = "2006-01-02T15:04:05.999Z" + +func jdecDate(data []byte) (interface{}, error) { + var v struct { + S string `json:"$date"` + Func struct { + S string + } `json:"$dateFunc"` + } + _ = jdec(data, &v) + if v.S == "" { + v.S = v.Func.S + } + if v.S != "" { + for _, format := range []string{jdateFormat, "2006-01-02"} { + t, err := time.Parse(format, v.S) + if err == nil { + return t, nil + } + } + return nil, fmt.Errorf("cannot parse date: %q", v.S) + } + + var vn struct { + Date struct { + N int64 `json:"$numberLong,string"` + } `json:"$date"` + Func struct { + S int64 + } `json:"$dateFunc"` + } + err := jdec(data, &vn) + if err != nil { + return nil, fmt.Errorf("cannot parse date: %q", data) + } + n := vn.Date.N + if n == 0 { + n = vn.Func.S + } + return time.Unix(n/1000, n%1000*1e6).UTC(), nil +} + +func jencDate(v interface{}) ([]byte, error) { + t := v.(time.Time) + return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil +} + +func jdecTimestamp(data []byte) (interface{}, error) { + var v struct { + Func struct { + T int32 `json:"t"` + I int32 `json:"i"` + } `json:"$timestamp"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil +} + +func jencTimestamp(v interface{}) ([]byte, error) { + ts := uint64(v.(MongoTimestamp)) + return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil +} + +func jdecRegEx(data []byte) (interface{}, error) { + var v struct { + Regex string `json:"$regex"` + Options string `json:"$options"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + return RegEx{v.Regex, v.Options}, nil +} + +func jencRegEx(v interface{}) ([]byte, error) { + re := v.(RegEx) + type regex struct { + Regex string `json:"$regex"` + Options string `json:"$options"` + } + return json.Marshal(regex{re.Pattern, re.Options}) +} + +func jdecObjectId(data []byte) (interface{}, error) { + var v struct { + Id string `json:"$oid"` + Func struct { + Id string + } `json:"$oidFunc"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.Id == "" { + v.Id = v.Func.Id + } + return ObjectIdHex(v.Id), nil +} + +func jencObjectId(v interface{}) ([]byte, error) { + return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil +} + +func jdecDBRef(data []byte) (interface{}, error) { + // TODO Support unmarshaling $ref and $id into the input value. + var v struct { + Obj map[string]interface{} `json:"$dbrefFunc"` + } + // TODO Fix this. Must not be required. + v.Obj = make(map[string]interface{}) + err := jdec(data, &v) + if err != nil { + return nil, err + } + return v.Obj, nil +} + +func jdecNumberLong(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$numberLong,string"` + Func struct { + N int64 `json:",string"` + } `json:"$numberLongFunc"` + } + var vn struct { + N int64 `json:"$numberLong"` + Func struct { + N int64 + } `json:"$numberLongFunc"` + } + err := jdec(data, &v) + if err != nil { + err = jdec(data, &vn) + v.N = vn.N + v.Func.N = vn.Func.N + } + if err != nil { + return nil, err + } + if v.N != 0 { + return v.N, nil + } + return v.Func.N, nil +} + +func jencNumberLong(v interface{}) ([]byte, error) { + n := v.(int64) + f := `{"$numberLong":"%d"}` + if n <= 1<<53 { + f = `{"$numberLong":%d}` + } + return fbytes(f, n), nil +} + +func jencInt(v interface{}) ([]byte, error) { + n := v.(int) + f := `{"$numberLong":"%d"}` + if int64(n) <= 1<<53 { + f = `%d` + } + return fbytes(f, n), nil +} + +func jdecMinKey(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$minKey"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.N != 1 { + return nil, fmt.Errorf("invalid $minKey object: %s", data) + } + return MinKey, nil +} + +func jdecMaxKey(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$maxKey"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.N != 1 { + return nil, fmt.Errorf("invalid $maxKey object: %s", data) + } + return MaxKey, nil +} + +func jencMinMaxKey(v interface{}) ([]byte, error) { + switch v.(orderKey) { + case MinKey: + return []byte(`{"$minKey":1}`), nil + case MaxKey: + return []byte(`{"$maxKey":1}`), nil + } + panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v)) +} + +func jdecUndefined(data []byte) (interface{}, error) { + var v struct { + B bool `json:"$undefined"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if !v.B { + return nil, fmt.Errorf("invalid $undefined object: %s", data) + } + return Undefined, nil +} + +func jencUndefined(v interface{}) ([]byte, error) { + return []byte(`{"$undefined":true}`), nil +} diff --git a/vendor/gopkg.in/mgo.v2/cluster.go b/vendor/gopkg.in/mgo.v2/cluster.go index e28af5b45..c3bf8b013 100644 --- a/vendor/gopkg.in/mgo.v2/cluster.go +++ b/vendor/gopkg.in/mgo.v2/cluster.go @@ -588,7 +588,10 @@ func (cluster *mongoCluster) AcquireSocket(mode Mode, slaveOk bool, syncTimeout mastersLen := cluster.masters.Len() slavesLen := cluster.servers.Len() - mastersLen debugf("Cluster has %d known masters and %d known slaves.", mastersLen, slavesLen) - if !(slaveOk && mode == Secondary) && mastersLen > 0 || slaveOk && slavesLen > 0 { + if mastersLen > 0 && !(slaveOk && mode == Secondary) || slavesLen > 0 && slaveOk { + break + } + if mastersLen > 0 && mode == Secondary && cluster.masters.HasMongos() { break } if started.IsZero() { diff --git a/vendor/gopkg.in/mgo.v2/gridfs.go b/vendor/gopkg.in/mgo.v2/gridfs.go index 2ac4ff576..421472095 100644 --- a/vendor/gopkg.in/mgo.v2/gridfs.go +++ b/vendor/gopkg.in/mgo.v2/gridfs.go @@ -359,7 +359,7 @@ func (file *GridFile) assertMode(mode gfsFileMode) { // SetChunkSize sets size of saved chunks. Once the file is written to, it // will be split in blocks of that size and each block saved into an -// independent chunk document. The default chunk size is 256kb. +// independent chunk document. The default chunk size is 255kb. // // It is a runtime error to call this function once the file has started // being written to. diff --git a/vendor/gopkg.in/mgo.v2/internal/json/LICENSE b/vendor/gopkg.in/mgo.v2/internal/json/LICENSE new file mode 100644 index 000000000..744875676 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/mgo.v2/internal/json/decode.go b/vendor/gopkg.in/mgo.v2/internal/json/decode.go new file mode 100644 index 000000000..ce7c7d249 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/decode.go @@ -0,0 +1,1685 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "errors" + "fmt" + "reflect" + "runtime" + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. +// Unmarshal will only set exported fields of the struct. +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores key- +// value pairs from the JSON object into the map. The map's key type must +// either be a string or implement encoding.TextUnmarshaler. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes +} + +func (e *UnmarshalTypeError) Error() string { + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// (No longer used; kept for compatibility.) +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v interface{}) (err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + err = r.(error) + } + }() + + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + d.value(rv) + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// isValidNumber reports whether s is a valid JSON number literal. +func isValidNumber(s string) bool { + // This function implements the JSON numbers grammar. + // See https://tools.ietf.org/html/rfc7159#section-6 + // and http://json.org/number.gif + + if s == "" { + return false + } + + // Optional - + if s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + + // Digits + switch { + default: + return false + + case s[0] == '0': + s = s[1:] + + case '1' <= s[0] && s[0] <= '9': + s = s[1:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // . followed by 1 or more digits. + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { + s = s[2:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { + s = s[1:] + if s[0] == '+' || s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // Make sure we are at the end. + return s == "" +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // read offset in data + scan scanner + nextscan scanner // for calls to nextValue + savedError error + useNumber bool + ext Extension +} + +// errPhase is used for errors that should not happen unless +// there is a bug in the JSON decoder or something is editing +// the data slice while the decoder executes. +var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + return d +} + +// error aborts the decoding by panicking with err. +func (d *decodeState) error(err error) { + panic(err) +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = err + } +} + +// next cuts off and returns the next full JSON value in d.data[d.off:]. +// The next value is known to be an object or array, not a literal. +func (d *decodeState) next() []byte { + c := d.data[d.off] + item, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // Our scanner has seen the opening brace/bracket + // and thinks we're still in the middle of the object. + // invent a closing brace/bracket to get it out. + if c == '{' { + d.scan.step(&d.scan, '}') + } else if c == '[' { + d.scan.step(&d.scan, ']') + } else { + // Was inside a function name. Get out of it. + d.scan.step(&d.scan, '(') + d.scan.step(&d.scan, ')') + } + + return item +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +// It updates d.off and returns the new scan code. +func (d *decodeState) scanWhile(op int) int { + var newOp int + for { + if d.off >= len(d.data) { + newOp = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } else { + c := d.data[d.off] + d.off++ + newOp = d.scan.step(&d.scan, c) + } + if newOp != op { + break + } + } + return newOp +} + +// value decodes a JSON value from d.data[d.off:] into the value. +// it updates d.off to point past the decoded value. +func (d *decodeState) value(v reflect.Value) { + if !v.IsValid() { + _, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // d.scan thinks we're still at the beginning of the item. + // Feed in an empty string - the shortest, simplest value - + // so that it knows we got to the end of the value. + if d.scan.redo { + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue + } + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + + n := len(d.scan.parseState) + if n > 0 && d.scan.parseState[n-1] == parseObjectKey { + // d.scan thinks we just read an object key; finish the object + d.scan.step(&d.scan, ':') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '}') + } + + return + } + + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(v) + + case scanBeginObject: + d.object(v) + + case scanBeginLiteral: + d.literal(v) + + case scanBeginName: + d.name(v) + } +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(reflect.Value{}) + + case scanBeginObject: + d.object(reflect.Value{}) + + case scanBeginName: + switch v := d.nameInterface().(type) { + case nil, string: + return v + } + + case scanBeginLiteral: + switch v := d.literalInterface().(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// if it encounters an Unmarshaler, indirect stops and returns that. +// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. +func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, v + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, v + } + } + v = v.Elem() + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into the value v. +// the first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + } + + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + v.Set(reflect.ValueOf(d.arrayInterface())) + return + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + case reflect.Array: + case reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + d.value(v.Index(i)) + } else { + // Ran out of fixed array: skip. + d.value(reflect.Value{}) + } + i++ + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into the value v. +// the first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if d.storeKeyed(pv) { + return + } + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + v = pv + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + v.Set(reflect.ValueOf(d.objectInterface())) + return + } + + // Check type of target: + // struct or + // map[string]T or map[encoding.TextUnmarshaler]T + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind or be an encoding.TextUnmarshaler. + t := v.Type() + if t.Key().Kind() != reflect.String && + !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + + default: + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + + var mapElem reflect.Value + + empty := true + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + if !empty && !d.ext.trailingCommas { + d.syntaxError("beginning of object key string") + } + break + } + empty = false + if op == scanBeginName { + if !d.ext.unquotedKeys { + d.syntaxError("beginning of object key string") + } + } else if op != scanBeginLiteral { + d.error(errPhase) + } + unquotedKey := op == scanBeginName + + // Read key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + var key []byte + if unquotedKey { + key = item + // TODO Fix code below to quote item when necessary. + } else { + var ok bool + key, ok = unquoteBytes(item) + if !ok { + d.error(errPhase) + } + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + } + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + d.value(subv) + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := v.Type().Key() + var kv reflect.Value + switch { + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(v.Type().Key()) + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(v.Type().Key()) + d.literalStore(item, kv, true) + kv = kv.Elem() + default: + panic("json: Unexpected key type") // should never occur + } + v.SetMapIndex(kv, subv) + } + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } +} + +// isNull returns whether there's a null literal at the provided offset. +func (d *decodeState) isNull(off int) bool { + if off+4 >= len(d.data) || d.data[off] != 'n' || d.data[off+1] != 'u' || d.data[off+2] != 'l' || d.data[off+3] != 'l' { + return false + } + d.nextscan.reset() + for i, c := range d.data[off:] { + if i > 4 { + return false + } + switch d.nextscan.step(&d.nextscan, c) { + case scanContinue, scanBeginName: + continue + } + break + } + return true +} + +// name consumes a const or function from d.data[d.off-1:], decoding into the value v. +// the first byte of the function name has been read already. +func (d *decodeState) name(v reflect.Value) { + if d.isNull(d.off-1) { + d.literal(v) + return + } + + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if d.storeKeyed(pv) { + return + } + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over function in input + return + } + v = pv + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + out := d.nameInterface() + if out == nil { + v.Set(reflect.Zero(v.Type())) + } else { + v.Set(reflect.ValueOf(out)) + } + return + } + + nameStart := d.off - 1 + + op := d.scanWhile(scanContinue) + + name := d.data[nameStart : d.off-1] + if op != scanParam { + // Back up so the byte just read is consumed next. + d.off-- + d.scan.undo(op) + if l, ok := d.convertLiteral(name); ok { + d.storeValue(v, l) + return + } + d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) + } + + funcName := string(name) + funcData := d.ext.funcs[funcName] + if funcData.key == "" { + d.error(fmt.Errorf("json: unknown function %q", funcName)) + } + + // Check type of target: + // struct or + // map[string]T or map[encoding.TextUnmarshaler]T + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind or be an encoding.TextUnmarshaler. + t := v.Type() + if t.Key().Kind() != reflect.String && + !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + + default: + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + + // TODO Fix case of func field as map. + //topv := v + + // Figure out field corresponding to function. + key := []byte(funcData.key) + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + v = reflect.New(elemType).Elem() + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + for _, i := range f.index { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + v = v.Field(i) + } + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + } + } + + // Check for unmarshaler on func field itself. + u, ut, pv = d.indirect(v, false) + if u != nil { + d.off = nameStart + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + + var mapElem reflect.Value + + // Parse function arguments. + for i := 0; ; i++ { + // closing ) - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + if i >= len(funcData.args) { + d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) + } + key := []byte(funcData.args[i]) + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + } + } + + // Read value. + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + d.value(subv) + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := v.Type().Key() + var kv reflect.Value + switch { + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(v.Type().Key()) + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(v.Type().Key()) + d.literalStore(key, kv, true) + kv = kv.Elem() + default: + panic("json: Unexpected key type") // should never occur + } + v.SetMapIndex(kv, subv) + } + + // Next token must be , or ). + op = d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + if op != scanParam { + d.error(errPhase) + } + } +} + +// keyed attempts to decode an object or function using a keyed doc extension, +// and returns the value and true on success, or nil and false otherwise. +func (d *decodeState) keyed() (interface{}, bool) { + if len(d.ext.keyed) == 0 { + return nil, false + } + + unquote := false + + // Look-ahead first key to check for a keyed document extension. + d.nextscan.reset() + var start, end int + for i, c := range d.data[d.off-1:] { + switch op := d.nextscan.step(&d.nextscan, c); op { + case scanSkipSpace, scanContinue, scanBeginObject: + continue + case scanBeginLiteral, scanBeginName: + unquote = op == scanBeginLiteral + start = i + continue + } + end = i + break + } + + name := d.data[d.off-1+start : d.off-1+end] + + var key []byte + var ok bool + if unquote { + key, ok = unquoteBytes(name) + if !ok { + d.error(errPhase) + } + } else { + funcData, ok := d.ext.funcs[string(name)] + if !ok { + return nil, false + } + key = []byte(funcData.key) + } + + decode, ok := d.ext.keyed[string(key)] + if !ok { + return nil, false + } + + d.off-- + out, err := decode(d.next()) + if err != nil { + d.error(err) + } + return out, true +} + +func (d *decodeState) storeKeyed(v reflect.Value) bool { + keyed, ok := d.keyed() + if !ok { + return false + } + d.storeValue(v, keyed) + return true +} + +var ( + trueBytes = []byte("true") + falseBytes = []byte("false") + nullBytes = []byte("null") +) + +func (d *decodeState) storeValue(v reflect.Value, from interface{}) { + switch from { + case nil: + d.literalStore(nullBytes, v, false) + return + case true: + d.literalStore(trueBytes, v, false) + return + case false: + d.literalStore(falseBytes, v, false) + return + } + fromv := reflect.ValueOf(from) + for fromv.Kind() == reflect.Ptr && !fromv.IsNil() { + fromv = fromv.Elem() + } + fromt := fromv.Type() + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + vt := v.Type() + if fromt.AssignableTo(vt) { + v.Set(fromv) + } else if fromt.ConvertibleTo(vt) { + v.Set(fromv.Convert(vt)) + } else { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + } +} + +func (d *decodeState) convertLiteral(name []byte) (interface{}, bool) { + if len(name) == 0 { + return nil, false + } + switch name[0] { + case 't': + if bytes.Equal(name, trueBytes) { + return true, true + } + case 'f': + if bytes.Equal(name, falseBytes) { + return false, true + } + case 'n': + if bytes.Equal(name, nullBytes) { + return nil, true + } + } + if l, ok := d.ext.consts[string(name)]; ok { + return l, true + } + return nil, false +} + +// literal consumes a literal from d.data[d.off-1:], decoding into the value v. +// The first byte of the literal has been read already +// (that's how the caller knows it's a literal). +func (d *decodeState) literal(v reflect.Value) { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + + d.literalStore(d.data[start:d.off], v, false) +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (interface{}, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return + } + wantptr := item[0] == 'n' // null + u, ut, pv := d.indirect(v, wantptr) + if u != nil { + err := u.UnmarshalJSON(item) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + return + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + err := ut.UnmarshalText(s) + if err != nil { + d.error(err) + } + return + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := c == 't' + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + v.SetString(s) + if !isValidNumber(s) { + d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) + } + break + } + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + } + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetFloat(n) + } + } +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() interface{} { + switch d.scanWhile(scanSkipSpace) { + default: + d.error(errPhase) + panic("unreachable") + case scanBeginArray: + return d.arrayInterface() + case scanBeginObject: + return d.objectInterface() + case scanBeginLiteral: + return d.literalInterface() + case scanBeginName: + return d.nameInterface() + } +} + +func (d *decodeState) syntaxError(expected string) { + msg := fmt.Sprintf("invalid character '%c' looking for %s", d.data[d.off-1], expected) + d.error(&SyntaxError{msg, int64(d.off)}) +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []interface{} { + var v = make([]interface{}, 0) + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + if len(v) > 0 && !d.ext.trailingCommas { + d.syntaxError("beginning of value") + } + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() interface{} { + v, ok := d.keyed() + if ok { + return v + } + + m := make(map[string]interface{}) + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + if len(m) > 0 && !d.ext.trailingCommas { + d.syntaxError("beginning of object key string") + } + break + } + if op == scanBeginName { + if !d.ext.unquotedKeys { + d.syntaxError("beginning of object key string") + } + } else if op != scanBeginLiteral { + d.error(errPhase) + } + unquotedKey := op == scanBeginName + + // Read string key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + var key string + if unquotedKey { + key = string(item) + } else { + var ok bool + key, ok = unquote(item) + if !ok { + d.error(errPhase) + } + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } + return m +} + +// literalInterface is like literal but returns an interface value. +func (d *decodeState) literalInterface() interface{} { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + item := d.data[start:d.off] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + d.error(errPhase) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + d.error(errPhase) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// nameInterface is like function but returns map[string]interface{}. +func (d *decodeState) nameInterface() interface{} { + v, ok := d.keyed() + if ok { + return v + } + + nameStart := d.off - 1 + + op := d.scanWhile(scanContinue) + + name := d.data[nameStart : d.off-1] + if op != scanParam { + // Back up so the byte just read is consumed next. + d.off-- + d.scan.undo(op) + if l, ok := d.convertLiteral(name); ok { + return l + } + d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) + } + + funcName := string(name) + funcData := d.ext.funcs[funcName] + if funcData.key == "" { + d.error(fmt.Errorf("json: unknown function %q", funcName)) + } + + m := make(map[string]interface{}) + for i := 0; ; i++ { + // Look ahead for ) - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + if i >= len(funcData.args) { + d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) + } + m[funcData.args[i]] = d.valueInterface() + + // Next token must be , or ). + op = d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + if op != scanParam { + d.error(errPhase) + } + } + return map[string]interface{}{funcData.key: m} +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + r, err := strconv.ParseUint(string(s[2:6]), 16, 64) + if err != nil { + return -1 + } + return rune(r) +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/encode.go b/vendor/gopkg.in/mgo.v2/internal/json/encode.go new file mode 100644 index 000000000..67a0f0062 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/encode.go @@ -0,0 +1,1256 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 4627. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" +// to keep some browsers from misinterpreting JSON output as HTML. +// Ampersand "&" is also escaped to "\u0026" for the same reason. +// This escaping can be disabled using an Encoder with DisableHTMLEscaping. +// +// Array and slice values encode as JSON arrays, except that +// []byte encodes as a base64-encoded string, and a nil slice +// encodes as the null JSON value. +// +// Struct values encode as JSON objects. Each exported struct field +// becomes a member of the object unless +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option. +// The empty values are false, 0, any +// nil pointer or interface value, and any array, slice, map, or string of +// length zero. The object's default key string is the struct field name +// but can be specified in the struct field's tag value. The "json" key in +// the struct field's tag value is the key name, followed by an optional comma +// and options. Examples: +// +// // Field is ignored by this package. +// Field int `json:"-"` +// +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` +// +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` +// +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` +// +// The "string" option signals that a field is stored as JSON inside a +// JSON-encoded string. It applies only to fields of string, floating point, +// integer, or boolean types. This extra level of encoding is sometimes used +// when communicating with JavaScript programs: +// +// Int64String int64 `json:",string"` +// +// The key name will be used if it's a non-empty string consisting of +// only Unicode letters, digits, dollar signs, percent signs, hyphens, +// underscores and slashes. +// +// Anonymous struct fields are usually marshaled as if their inner exported fields +// were fields in the outer struct, subject to the usual Go visibility rules amended +// as described in the next paragraph. +// An anonymous struct field with a name given in its JSON tag is treated as +// having that name, rather than being anonymous. +// An anonymous struct field of interface type is treated the same as having +// that type as its name, rather than being anonymous. +// +// The Go visibility rules for struct fields are amended for JSON when +// deciding which field to marshal or unmarshal. If there are +// multiple fields at the same level, and that level is the least +// nested (and would therefore be the nesting level selected by the +// usual Go rules), the following extra rules apply: +// +// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, +// even if there are multiple untagged fields that would otherwise conflict. +// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. +// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. +// +// Handling of anonymous struct fields is new in Go 1.1. +// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of +// an anonymous struct field in both current and earlier versions, give the field +// a JSON tag of "-". +// +// Map values encode as JSON objects. The map's key type must either be a string +// or implement encoding.TextMarshaler. The map keys are used as JSON object +// keys, subject to the UTF-8 coercion described for string values above. +// +// Pointer values encode as the value pointed to. +// A nil pointer encodes as the null JSON value. +// +// Interface values encode as the value contained in the interface. +// A nil interface value encodes as the null JSON value. +// +// Channel, complex, and function values cannot be encoded in JSON. +// Attempting to encode such a value causes Marshal to return +// an UnsupportedTypeError. +// +// JSON cannot represent cyclic data structures and Marshal does not +// handle them. Passing cyclic structures to Marshal will result in +// an infinite recursion. +// +func Marshal(v interface{}) ([]byte, error) { + e := &encodeState{} + err := e.marshal(v, encOpts{escapeHTML: true}) + if err != nil { + return nil, err + } + return e.Bytes(), nil +} + +// MarshalIndent is like Marshal but applies Indent to format the output. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + b, err := Marshal(v) + if err != nil { + return nil, err + } + var buf bytes.Buffer + err = Indent(&buf, b, prefix, indent) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 +// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 +// so that the JSON will be safe to embed inside HTML