diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad008af802..9ac9724c92b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ You can find a list of previous releases on the [github releases](https://github - Change `--connect-attributes` in `cadence-sql-tool` from URL encoding to the format of k1=v1,k2=v2... - Change `--domain_data` in `cadence domain update/register` from the format of k1:v1,k2:v2... to the format of k1=v1,k2=v2... - Deprecate local domains. All new domains should be created as global domains. +- Server will deep merge configuration files when loading. No need to copy the whole config section, specify only those fields that needs overriding. (#4165) ## [0.18.0] - 2021-01-22 diff --git a/common/config/loader.go b/common/config/loader.go index 303fe52db60..d4d6ad97534 100644 --- a/common/config/loader.go +++ b/common/config/loader.go @@ -22,12 +22,11 @@ package config import ( "fmt" - "io/ioutil" "log" "os" + uconfig "go.uber.org/config" "gopkg.in/validator.v2" - "gopkg.in/yaml.v2" ) const ( @@ -80,17 +79,18 @@ func Load(env string, configDir string, zone string, config interface{}) error { log.Printf("Loading configFiles=%v\n", files) + var options []uconfig.YAMLOption for _, f := range files { - // This is tagged nosec because the file names being read are for config files that are not user supplied - // #nosec - data, err := ioutil.ReadFile(f) - if err != nil { - return err - } - err = yaml.Unmarshal(data, config) - if err != nil { - return err - } + options = append(options, uconfig.File(f)) + } + yaml, err := uconfig.NewYAML(options...) + if err != nil { + return err + } + + err = yaml.Get(uconfig.Root).Populate(config) + if err != nil { + return err } return validator.Validate(config) diff --git a/common/config/loader_test.go b/common/config/loader_test.go index 0432f78ea1f..dff085c9aa7 100644 --- a/common/config/loader_test.go +++ b/common/config/loader_test.go @@ -59,9 +59,10 @@ func (s *LoaderSuite) TestBaseYaml() { s.Nil(err) defer os.RemoveAll(dir) - data := buildConfig("", "") - err = ioutil.WriteFile(path(dir, "base.yaml"), []byte(data), fileMode) - s.Nil(err) + s.createFile(dir, "base.yaml", ` +items: + item1: base1 + item2: base2`) envs := []string{"", "prod"} zones := []string{"", "us-east-1a"} @@ -71,8 +72,8 @@ func (s *LoaderSuite) TestBaseYaml() { var cfg testConfig err = Load(env, dir, zone, &cfg) s.Nil(err) - s.Equal("hello__", cfg.Items.Item1) - s.Equal("world__", cfg.Items.Item2) + s.Equal("base1", cfg.Items.Item1) + s.Equal("base2", cfg.Items.Item2) } } } @@ -83,10 +84,22 @@ func (s *LoaderSuite) TestHierarchy() { s.Nil(err) defer os.RemoveAll(dir) - s.createFile(dir, "base.yaml", "", "") - s.createFile(dir, "development.yaml", "development", "") - s.createFile(dir, "prod.yaml", "prod", "") - s.createFile(dir, "prod_dca.yaml", "prod", "dca") + s.createFile(dir, "base.yaml", ` +items: + item1: base1 + item2: base2`) + + s.createFile(dir, "development.yaml", ` +items: + item1: development1`) + + s.createFile(dir, "prod.yaml", ` +items: + item1: prod1`) + + s.createFile(dir, "prod_dca.yaml", ` +items: + item1: prod_dca1`) testCases := []struct { env string @@ -94,15 +107,15 @@ func (s *LoaderSuite) TestHierarchy() { item1 string item2 string }{ - {"", "", "hello_development_", "world_development_"}, - {"", "dca", "hello_development_", "world_development_"}, - {"", "pdx", "hello_development_", "world_development_"}, - {"development", "", "hello_development_", "world_development_"}, - {"development", "dca", "hello_development_", "world_development_"}, - {"development", "pdx", "hello_development_", "world_development_"}, - {"prod", "", "hello_prod_", "world_prod_"}, - {"prod", "dca", "hello_prod_dca", "world_prod_dca"}, - {"prod", "pdx", "hello_prod_", "world_prod_"}, + {"", "", "development1", "base2"}, + {"", "dca", "development1", "base2"}, + {"", "pdx", "development1", "base2"}, + {"development", "", "development1", "base2"}, + {"development", "dca", "development1", "base2"}, + {"development", "pdx", "development1", "base2"}, + {"prod", "", "prod1", "base2"}, + {"prod", "dca", "prod_dca1", "base2"}, + {"prod", "pdx", "prod1", "base2"}, } for _, tc := range testCases { @@ -120,16 +133,7 @@ func (s *LoaderSuite) TestInvalidPath() { s.NotNil(err) } -func (s *LoaderSuite) createFile(dir string, file string, env string, zone string) { - err := ioutil.WriteFile(path(dir, file), []byte(buildConfig(env, zone)), fileMode) +func (s *LoaderSuite) createFile(dir string, file string, content string) { + err := ioutil.WriteFile(path(dir, file), []byte(content), fileMode) s.Nil(err) } - -func buildConfig(env, zone string) string { - item1 := concat("hello", concat(env, zone)) - item2 := concat("world", concat(env, zone)) - return ` - items: - item1: ` + item1 + ` - item2: ` + item2 -} diff --git a/config/development_es.yaml b/config/development_es.yaml index 5fad4caf5e3..7bb7bd205d2 100644 --- a/config/development_es.yaml +++ b/config/development_es.yaml @@ -1,13 +1,6 @@ persistence: - defaultStore: cass-default advancedVisibilityStore: es-visibility - numHistoryShards: 4 datastores: - cass-default: - nosql: - pluginName: "cassandra" - hosts: "127.0.0.1" - keyspace: "cadence" es-visibility: elasticsearch: url: @@ -16,101 +9,6 @@ persistence: indices: visibility: cadence-visibility-dev -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: ["127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935"] - maxJoinDuration: 30s - -services: - frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7936 - - matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7938 - - history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7937 - - worker: - rpc: - port: 7939 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - kafka: tls: enabled: false @@ -128,13 +26,5 @@ kafka: topic: cadence-visibility-dev dlq-topic: cadence-visibility-dev-dlq -publicClient: - hostPort: "localhost:7933" - dynamicConfigClient: filepath: "config/dynamicconfig/development_es.yaml" - pollInterval: "10s" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" diff --git a/config/development_es_v7.yaml b/config/development_es_v7.yaml index e804d81412b..9f16a567832 100644 --- a/config/development_es_v7.yaml +++ b/config/development_es_v7.yaml @@ -1,13 +1,6 @@ persistence: - defaultStore: cass-default advancedVisibilityStore: es-visibility - numHistoryShards: 4 datastores: - cass-default: - nosql: - pluginName: "cassandra" - hosts: "127.0.0.1" - keyspace: "cadence" es-visibility: elasticsearch: version: "v7" @@ -17,101 +10,6 @@ persistence: indices: visibility: cadence-visibility-dev -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: ["127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935"] - maxJoinDuration: 30s - -services: - frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7936 - - matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7938 - - history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7937 - - worker: - rpc: - port: 7939 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - kafka: tls: enabled: false @@ -129,13 +27,5 @@ kafka: topic: cadence-visibility-dev dlq-topic: cadence-visibility-dev-dlq -publicClient: - hostPort: "localhost:7933" - dynamicConfigClient: filepath: "config/dynamicconfig/development_es.yaml" - pollInterval: "10s" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" diff --git a/config/development_mysql.yaml b/config/development_mysql.yaml index 1adfbd61f08..ff078e9a582 100644 --- a/config/development_mysql.yaml +++ b/config/development_mysql.yaml @@ -1,7 +1,6 @@ persistence: defaultStore: mysql-default visibilityStore: mysql-visibility - numHistoryShards: 4 datastores: mysql-default: sql: @@ -24,106 +23,4 @@ persistence: password: "uber" maxConns: 2 maxIdleConns: 2 - maxConnLifetime: "1h" - -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: [ "127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935" ] - maxJoinDuration: 30s - -services: - frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7936 - - matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7938 - - history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7937 - - worker: - rpc: - port: 7939 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - -publicClient: - hostPort: "localhost:7933" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" + maxConnLifetime: "1h" \ No newline at end of file diff --git a/config/development_postgres.yaml b/config/development_postgres.yaml index d746752f7ac..1698737ace0 100644 --- a/config/development_postgres.yaml +++ b/config/development_postgres.yaml @@ -1,7 +1,6 @@ persistence: defaultStore: postgres-default visibilityStore: postgres-visibility - numHistoryShards: 4 datastores: postgres-default: sql: @@ -24,106 +23,4 @@ persistence: password: "cadence" maxConns: 2 maxIdleConns: 2 - maxConnLifetime: "1h" - -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: [ "127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935" ] - maxJoinDuration: 30s - -services: - frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7936 - - matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7938 - - history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7937 - - worker: - rpc: - port: 7939 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - -publicClient: - hostPort: "localhost:7933" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" + maxConnLifetime: "1h" \ No newline at end of file diff --git a/config/development_prometheus.yaml b/config/development_prometheus.yaml index 39a6d1699e3..242347d9ddb 100644 --- a/config/development_prometheus.yaml +++ b/config/development_prometheus.yaml @@ -1,117 +1,28 @@ -persistence: - defaultStore: cass-default - visibilityStore: cass-visibility - numHistoryShards: 4 - datastores: - cass-default: - nosql: - pluginName: "cassandra" - hosts: "127.0.0.1" - keyspace: "cadence" - cass-visibility: - nosql: - pluginName: "cassandra" - hosts: "127.0.0.1" - keyspace: "cadence_visibility" - -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: [ "127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935" ] - maxJoinDuration: 30s - services: frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true metrics: + statsd: ~ prometheus: timerType: "histogram" listenAddress: "127.0.0.1:8000" - pprof: - port: 7936 matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true metrics: + statsd: ~ prometheus: timerType: "histogram" listenAddress: "127.0.0.1:8001" - pprof: - port: 7938 history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true metrics: + statsd: ~ prometheus: timerType: "histogram" listenAddress: "127.0.0.1:8002" - pprof: - port: 7937 worker: - rpc: - port: 7939 - bindOnLocalHost: true metrics: + statsd: ~ prometheus: timerType: "histogram" listenAddress: "127.0.0.1:8003" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - -publicClient: - hostPort: "localhost:7933" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" diff --git a/config/development_scylla.yaml b/config/development_scylla.yaml index 3ff2b2b2a20..2b3d70b3c01 100644 --- a/config/development_scylla.yaml +++ b/config/development_scylla.yaml @@ -1,7 +1,6 @@ persistence: defaultStore: scylla-default visibilityStore: scylla-visibility - numHistoryShards: 4 datastores: scylla-default: nosql: @@ -13,111 +12,3 @@ persistence: pluginName: "cassandra" hosts: "127.0.0.1" keyspace: "cadence_visibility" - -ringpop: - name: cadence - bootstrapMode: hosts - bootstrapHosts: [ "127.0.0.1:7933", "127.0.0.1:7934", "127.0.0.1:7935" ] - maxJoinDuration: 30s - -services: - frontend: - rpc: - port: 7933 - grpcPort: 7833 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7936 - - matching: - rpc: - port: 7935 - grpcPort: 7835 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7938 - - history: - rpc: - port: 7934 - grpcPort: 7834 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7937 - - worker: - rpc: - port: 7939 - bindOnLocalHost: true - metrics: - statsd: - hostPort: "127.0.0.1:8125" - prefix: "cadence" - pprof: - port: 7940 - -clusterMetadata: - enableGlobalDomain: true - failoverVersionIncrement: 10 - primaryClusterName: "active" - currentClusterName: "active" - clusterInformation: - active: - enabled: true - initialFailoverVersion: 0 - rpcName: "cadence-frontend" - rpcAddress: "localhost:7933" - -dcRedirectionPolicy: - policy: "noop" - toDC: "" - -archival: - history: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - gstorage: - credentialsPath: "/tmp/gcloud/keyfile.json" - visibility: - status: "enabled" - enableRead: true - provider: - filestore: - fileMode: "0666" - dirMode: "0766" - -domainDefaults: - archival: - history: - status: "enabled" - URI: "file:///tmp/cadence_archival/development" - visibility: - status: "enabled" - URI: "file:///tmp/cadence_vis_archival/development" - -publicClient: - hostPort: "localhost:7933" - -dynamicConfigClient: - filepath: "config/dynamicconfig/development.yaml" - pollInterval: "10s" - -blobstore: - filestore: - outputDirectory: "/tmp/blobstore" diff --git a/go.mod b/go.mod index 238707caf42..dd797389e01 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( go.opencensus.io v0.22.5 // indirect go.uber.org/atomic v1.7.0 go.uber.org/cadence v0.17.1-0.20210609205819-61495d91ff9d + go.uber.org/config v1.4.0 go.uber.org/fx v1.10.0 go.uber.org/multierr v1.6.0 go.uber.org/thriftrw v1.25.0 diff --git a/go.sum b/go.sum index 95e382e740f..f0e18655356 100644 --- a/go.sum +++ b/go.sum @@ -413,6 +413,8 @@ go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/cadence v0.17.1-0.20210609205819-61495d91ff9d h1:y7vc87iC3d+1hLUAe5LhmW5nsOe9CyW/WqsQ5volgo0= go.uber.org/cadence v0.17.1-0.20210609205819-61495d91ff9d/go.mod h1:WNw63zcxMVCzEUU6cFOFuMh9s//jbc57kr2IfH1cyfs= +go.uber.org/config v1.4.0 h1:upnMPpMm6WlbZtXoasNkK4f0FhxwS+W4Iqz5oNznehQ= +go.uber.org/config v1.4.0/go.mod h1:aCyrMHmUAc/s2h9sv1koP84M9ZF/4K+g2oleyESO/Ig= go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.10.0 h1:S2K/H8oNied0Je/mLKdWzEWKZfv9jtxSDm8CnwK+5Fg= @@ -585,6 +587,7 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191104232314-dc038396d1f0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=