Config interface change (#2010)
This commit is contained in:
@@ -2,49 +2,41 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/loader"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config is an interface abstraction for dynamic configuration
|
||||
type Config interface {
|
||||
// provide the reader.Values interface
|
||||
reader.Values
|
||||
// Init the config
|
||||
Init(opts ...Option) error
|
||||
// Options in the config
|
||||
Options() Options
|
||||
// Stop the config loader/watcher
|
||||
Close() error
|
||||
// Load config sources
|
||||
Load(source ...source.Source) error
|
||||
// Force a source changeset sync
|
||||
Sync() error
|
||||
// Watch a value for changes
|
||||
Watch(path ...string) (Watcher, error)
|
||||
Get(path string, options ...Option) Value
|
||||
Set(path string, val interface{}, options ...Option)
|
||||
Delete(path string, options ...Option)
|
||||
}
|
||||
|
||||
// Watcher is the config watcher
|
||||
type Watcher interface {
|
||||
Next() (reader.Value, error)
|
||||
Stop() error
|
||||
// Value represents a value of any type
|
||||
type Value interface {
|
||||
Exists() bool
|
||||
Bool(def bool) bool
|
||||
Int(def int) int
|
||||
String(def string) string
|
||||
Float64(def float64) float64
|
||||
Duration(def time.Duration) time.Duration
|
||||
StringSlice(def []string) []string
|
||||
StringMap(def map[string]string) map[string]string
|
||||
Scan(val interface{}) error
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Loader loader.Loader
|
||||
Reader reader.Reader
|
||||
Source []source.Source
|
||||
|
||||
// for alternative data
|
||||
Context context.Context
|
||||
// Is the value being read a secret?
|
||||
// If true, the Config will try to decode it with `SecretKey`
|
||||
Secret bool
|
||||
}
|
||||
|
||||
// Option sets values in Options
|
||||
type Option func(o *Options)
|
||||
|
||||
// NewConfig returns new config
|
||||
func NewConfig(opts ...Option) (Config, error) {
|
||||
return newConfig(opts...)
|
||||
func Secret(isSecret bool) Option {
|
||||
return func(o *Options) {
|
||||
o.Secret = isSecret
|
||||
}
|
||||
}
|
||||
|
@@ -1,301 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/loader"
|
||||
"github.com/micro/go-micro/v3/config/loader/memory"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/reader/json"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
exit chan bool
|
||||
opts Options
|
||||
|
||||
sync.RWMutex
|
||||
// the current snapshot
|
||||
snap *loader.Snapshot
|
||||
// the current values
|
||||
vals reader.Values
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
lw loader.Watcher
|
||||
rd reader.Reader
|
||||
path []string
|
||||
value reader.Value
|
||||
}
|
||||
|
||||
func newConfig(opts ...Option) (Config, error) {
|
||||
var c config
|
||||
|
||||
if err := c.Init(opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go c.run()
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func (c *config) Init(opts ...Option) error {
|
||||
c.opts = Options{
|
||||
Reader: json.NewReader(),
|
||||
}
|
||||
c.exit = make(chan bool)
|
||||
for _, o := range opts {
|
||||
o(&c.opts)
|
||||
}
|
||||
|
||||
// default loader uses the configured reader
|
||||
if c.opts.Loader == nil {
|
||||
c.opts.Loader = memory.NewLoader(memory.WithReader(c.opts.Reader))
|
||||
}
|
||||
|
||||
err := c.opts.Loader.Load(c.opts.Source...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.snap, err = c.opts.Loader.Snapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.vals, err = c.opts.Reader.Values(c.snap.ChangeSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) Options() Options {
|
||||
return c.opts
|
||||
}
|
||||
|
||||
func (c *config) run() {
|
||||
watch := func(w loader.Watcher) error {
|
||||
for {
|
||||
// get changeset
|
||||
snap, err := w.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
|
||||
if c.snap != nil && c.snap.Version >= snap.Version {
|
||||
c.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
// save
|
||||
c.snap = snap
|
||||
|
||||
// set values
|
||||
c.vals, _ = c.opts.Reader.Values(snap.ChangeSet)
|
||||
|
||||
c.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
w, err := c.opts.Loader.Watch()
|
||||
if err != nil {
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
// the stop watch func
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
case <-c.exit:
|
||||
}
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
// block watch
|
||||
if err := watch(w); err != nil {
|
||||
// do something better
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
// close done chan
|
||||
close(done)
|
||||
|
||||
// if the config is closed exit
|
||||
select {
|
||||
case <-c.exit:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *config) Map() map[string]interface{} {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
return c.vals.Map()
|
||||
}
|
||||
|
||||
func (c *config) Scan(v interface{}) error {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
return c.vals.Scan(v)
|
||||
}
|
||||
|
||||
// sync loads all the sources, calls the parser and updates the config
|
||||
func (c *config) Sync() error {
|
||||
if err := c.opts.Loader.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
snap, err := c.opts.Loader.Snapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.snap = snap
|
||||
vals, err := c.opts.Reader.Values(snap.ChangeSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.vals = vals
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) Close() error {
|
||||
select {
|
||||
case <-c.exit:
|
||||
return nil
|
||||
default:
|
||||
close(c.exit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) Get(path ...string) reader.Value {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
// did sync actually work?
|
||||
if c.vals != nil {
|
||||
return c.vals.Get(path...)
|
||||
}
|
||||
|
||||
// no value
|
||||
return newValue()
|
||||
}
|
||||
|
||||
func (c *config) Set(val interface{}, path ...string) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if c.vals != nil {
|
||||
c.vals.Set(val, path...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *config) Del(path ...string) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if c.vals != nil {
|
||||
c.vals.Del(path...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *config) Bytes() []byte {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
if c.vals == nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
return c.vals.Bytes()
|
||||
}
|
||||
|
||||
func (c *config) Load(sources ...source.Source) error {
|
||||
if err := c.opts.Loader.Load(sources...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
snap, err := c.opts.Loader.Snapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.snap = snap
|
||||
vals, err := c.opts.Reader.Values(snap.ChangeSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.vals = vals
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) Watch(path ...string) (Watcher, error) {
|
||||
value := c.Get(path...)
|
||||
|
||||
w, err := c.opts.Loader.Watch(path...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &watcher{
|
||||
lw: w,
|
||||
rd: c.opts.Reader,
|
||||
path: path,
|
||||
value: value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *config) String() string {
|
||||
return "config"
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (reader.Value, error) {
|
||||
for {
|
||||
s, err := w.lw.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// only process changes
|
||||
if bytes.Equal(w.value.Bytes(), s.ChangeSet.Data) {
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := w.rd.Values(s.ChangeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w.value = v.Get()
|
||||
return w.value, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
return w.lw.Stop()
|
||||
}
|
@@ -1,166 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
"github.com/micro/go-micro/v3/config/source/env"
|
||||
"github.com/micro/go-micro/v3/config/source/file"
|
||||
"github.com/micro/go-micro/v3/config/source/memory"
|
||||
)
|
||||
|
||||
func createFileForIssue18(t *testing.T, content string) *os.File {
|
||||
data := []byte(content)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
fh, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = fh.Write(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
return fh
|
||||
}
|
||||
|
||||
func createFileForTest(t *testing.T) *os.File {
|
||||
data := []byte(`{"foo": "bar"}`)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
fh, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = fh.Write(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
return fh
|
||||
}
|
||||
|
||||
func TestConfigLoadWithGoodFile(t *testing.T) {
|
||||
fh := createFileForTest(t)
|
||||
path := fh.Name()
|
||||
defer func() {
|
||||
fh.Close()
|
||||
os.Remove(path)
|
||||
}()
|
||||
|
||||
// Create new config
|
||||
conf, err := NewConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error but got %v", err)
|
||||
}
|
||||
// Load file source
|
||||
if err := conf.Load(file.NewSource(
|
||||
file.WithPath(path),
|
||||
)); err != nil {
|
||||
t.Fatalf("Expected no error but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigLoadWithInvalidFile(t *testing.T) {
|
||||
fh := createFileForTest(t)
|
||||
path := fh.Name()
|
||||
defer func() {
|
||||
fh.Close()
|
||||
os.Remove(path)
|
||||
}()
|
||||
|
||||
// Create new config
|
||||
conf, err := NewConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error but got %v", err)
|
||||
}
|
||||
// Load file source
|
||||
err = conf.Load(file.NewSource(
|
||||
file.WithPath(path),
|
||||
file.WithPath("/i/do/not/exists.json"),
|
||||
))
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Expected error but none !")
|
||||
}
|
||||
if !strings.Contains(fmt.Sprintf("%v", err), "/i/do/not/exists.json") {
|
||||
t.Fatalf("Expected error to contain the unexisting file but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMerge(t *testing.T) {
|
||||
fh := createFileForIssue18(t, `{
|
||||
"amqp": {
|
||||
"host": "rabbit.platform",
|
||||
"port": 80
|
||||
},
|
||||
"handler": {
|
||||
"exchange": "springCloudBus"
|
||||
}
|
||||
}`)
|
||||
path := fh.Name()
|
||||
defer func() {
|
||||
fh.Close()
|
||||
os.Remove(path)
|
||||
}()
|
||||
os.Setenv("AMQP_HOST", "rabbit.testing.com")
|
||||
|
||||
conf, err := NewConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error but got %v", err)
|
||||
}
|
||||
if err := conf.Load(
|
||||
file.NewSource(
|
||||
file.WithPath(path),
|
||||
),
|
||||
env.NewSource(),
|
||||
); err != nil {
|
||||
t.Fatalf("Expected no error but got %v", err)
|
||||
}
|
||||
|
||||
actualHost := conf.Get("amqp", "host").String("backup")
|
||||
if actualHost != "rabbit.testing.com" {
|
||||
t.Fatalf("Expected %v but got %v",
|
||||
"rabbit.testing.com",
|
||||
actualHost)
|
||||
}
|
||||
}
|
||||
|
||||
func equalS(t *testing.T, actual, expect string) {
|
||||
if actual != expect {
|
||||
t.Errorf("Expected %s but got %s", actual, expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigWatcherDirtyOverrite(t *testing.T) {
|
||||
n := runtime.GOMAXPROCS(0)
|
||||
defer runtime.GOMAXPROCS(n)
|
||||
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
l := 100
|
||||
|
||||
ss := make([]source.Source, l, l)
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
ss[i] = memory.NewSource(memory.WithJSON([]byte(fmt.Sprintf(`{"key%d": "val%d"}`, i, i))))
|
||||
}
|
||||
|
||||
conf, _ := NewConfig()
|
||||
|
||||
for _, s := range ss {
|
||||
_ = conf.Load(s)
|
||||
}
|
||||
runtime.Gosched()
|
||||
|
||||
for i, _ := range ss {
|
||||
k := fmt.Sprintf("key%d", i)
|
||||
v := fmt.Sprintf("val%d", i)
|
||||
equalS(t, conf.Get(k).String(""), v)
|
||||
}
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
// Package encoder handles source encoding formats
|
||||
package encoder
|
||||
|
||||
type Encoder interface {
|
||||
Encode(interface{}) ([]byte, error)
|
||||
Decode([]byte, interface{}) error
|
||||
String() string
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package hcl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/hcl"
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
type hclEncoder struct{}
|
||||
|
||||
func (h hclEncoder) Encode(v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (h hclEncoder) Decode(d []byte, v interface{}) error {
|
||||
return hcl.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
func (h hclEncoder) String() string {
|
||||
return "hcl"
|
||||
}
|
||||
|
||||
func NewEncoder() encoder.Encoder {
|
||||
return hclEncoder{}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
type jsonEncoder struct{}
|
||||
|
||||
func (j jsonEncoder) Encode(v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (j jsonEncoder) Decode(d []byte, v interface{}) error {
|
||||
return json.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
func (j jsonEncoder) String() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func NewEncoder() encoder.Encoder {
|
||||
return jsonEncoder{}
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
type tomlEncoder struct{}
|
||||
|
||||
func (t tomlEncoder) Encode(v interface{}) ([]byte, error) {
|
||||
b := bytes.NewBuffer(nil)
|
||||
defer b.Reset()
|
||||
err := toml.NewEncoder(b).Encode(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (t tomlEncoder) Decode(d []byte, v interface{}) error {
|
||||
return toml.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
func (t tomlEncoder) String() string {
|
||||
return "toml"
|
||||
}
|
||||
|
||||
func NewEncoder() encoder.Encoder {
|
||||
return tomlEncoder{}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
type xmlEncoder struct{}
|
||||
|
||||
func (x xmlEncoder) Encode(v interface{}) ([]byte, error) {
|
||||
return xml.Marshal(v)
|
||||
}
|
||||
|
||||
func (x xmlEncoder) Decode(d []byte, v interface{}) error {
|
||||
return xml.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
func (x xmlEncoder) String() string {
|
||||
return "xml"
|
||||
}
|
||||
|
||||
func NewEncoder() encoder.Encoder {
|
||||
return xmlEncoder{}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
type yamlEncoder struct{}
|
||||
|
||||
func (y yamlEncoder) Encode(v interface{}) ([]byte, error) {
|
||||
return yaml.Marshal(v)
|
||||
}
|
||||
|
||||
func (y yamlEncoder) Decode(d []byte, v interface{}) error {
|
||||
return yaml.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
func (y yamlEncoder) String() string {
|
||||
return "yaml"
|
||||
}
|
||||
|
||||
func NewEncoder() encoder.Encoder {
|
||||
return yamlEncoder{}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
// package loader manages loading from multiple sources
|
||||
package loader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
// Loader manages loading sources
|
||||
type Loader interface {
|
||||
// Stop the loader
|
||||
Close() error
|
||||
// Load the sources
|
||||
Load(...source.Source) error
|
||||
// A Snapshot of loaded config
|
||||
Snapshot() (*Snapshot, error)
|
||||
// Force sync of sources
|
||||
Sync() error
|
||||
// Watch for changes
|
||||
Watch(...string) (Watcher, error)
|
||||
// Name of loader
|
||||
String() string
|
||||
}
|
||||
|
||||
// Watcher lets you watch sources and returns a merged ChangeSet
|
||||
type Watcher interface {
|
||||
// First call to next may return the current Snapshot
|
||||
// If you are watching a path then only the data from
|
||||
// that path is returned.
|
||||
Next() (*Snapshot, error)
|
||||
// Stop watching for changes
|
||||
Stop() error
|
||||
}
|
||||
|
||||
// Snapshot is a merged ChangeSet
|
||||
type Snapshot struct {
|
||||
// The merged ChangeSet
|
||||
ChangeSet *source.ChangeSet
|
||||
// Deterministic and comparable version of the snapshot
|
||||
Version string
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Reader reader.Reader
|
||||
Source []source.Source
|
||||
|
||||
// for alternative data
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
// Copy snapshot
|
||||
func Copy(s *Snapshot) *Snapshot {
|
||||
cs := *(s.ChangeSet)
|
||||
|
||||
return &Snapshot{
|
||||
ChangeSet: &cs,
|
||||
Version: s.Version,
|
||||
}
|
||||
}
|
@@ -1,459 +0,0 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/loader"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/reader/json"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type memory struct {
|
||||
exit chan bool
|
||||
opts loader.Options
|
||||
|
||||
sync.RWMutex
|
||||
// the current snapshot
|
||||
snap *loader.Snapshot
|
||||
// the current values
|
||||
vals reader.Values
|
||||
// all the sets
|
||||
sets []*source.ChangeSet
|
||||
// all the sources
|
||||
sources []source.Source
|
||||
|
||||
watchers *list.List
|
||||
}
|
||||
|
||||
type updateValue struct {
|
||||
version string
|
||||
value reader.Value
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
exit chan bool
|
||||
path []string
|
||||
value reader.Value
|
||||
reader reader.Reader
|
||||
version string
|
||||
updates chan updateValue
|
||||
}
|
||||
|
||||
func (m *memory) watch(idx int, s source.Source) {
|
||||
// watches a source for changes
|
||||
watch := func(idx int, s source.Watcher) error {
|
||||
for {
|
||||
// get changeset
|
||||
cs, err := s.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
|
||||
// save
|
||||
m.sets[idx] = cs
|
||||
|
||||
// merge sets
|
||||
set, err := m.opts.Reader.Merge(m.sets...)
|
||||
if err != nil {
|
||||
m.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// set values
|
||||
m.vals, _ = m.opts.Reader.Values(set)
|
||||
m.snap = &loader.Snapshot{
|
||||
ChangeSet: set,
|
||||
Version: genVer(),
|
||||
}
|
||||
m.Unlock()
|
||||
|
||||
// send watch updates
|
||||
m.update()
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
// watch the source
|
||||
w, err := s.Watch()
|
||||
if err != nil {
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
// the stop watch func
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
case <-m.exit:
|
||||
}
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
// block watch
|
||||
if err := watch(idx, w); err != nil {
|
||||
// do something better
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
// close done chan
|
||||
close(done)
|
||||
|
||||
// if the config is closed exit
|
||||
select {
|
||||
case <-m.exit:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *memory) loaded() bool {
|
||||
var loaded bool
|
||||
m.RLock()
|
||||
if m.vals != nil {
|
||||
loaded = true
|
||||
}
|
||||
m.RUnlock()
|
||||
return loaded
|
||||
}
|
||||
|
||||
// reload reads the sets and creates new values
|
||||
func (m *memory) reload() error {
|
||||
m.Lock()
|
||||
|
||||
// merge sets
|
||||
set, err := m.opts.Reader.Merge(m.sets...)
|
||||
if err != nil {
|
||||
m.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// set values
|
||||
m.vals, _ = m.opts.Reader.Values(set)
|
||||
m.snap = &loader.Snapshot{
|
||||
ChangeSet: set,
|
||||
Version: genVer(),
|
||||
}
|
||||
|
||||
m.Unlock()
|
||||
|
||||
// update watchers
|
||||
m.update()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memory) update() {
|
||||
watchers := make([]*watcher, 0, m.watchers.Len())
|
||||
|
||||
m.RLock()
|
||||
for e := m.watchers.Front(); e != nil; e = e.Next() {
|
||||
watchers = append(watchers, e.Value.(*watcher))
|
||||
}
|
||||
|
||||
vals := m.vals
|
||||
snap := m.snap
|
||||
m.RUnlock()
|
||||
|
||||
for _, w := range watchers {
|
||||
if w.version >= snap.Version {
|
||||
continue
|
||||
}
|
||||
|
||||
uv := updateValue{
|
||||
version: m.snap.Version,
|
||||
value: vals.Get(w.path...),
|
||||
}
|
||||
|
||||
select {
|
||||
case <-w.exit:
|
||||
continue
|
||||
default:
|
||||
}
|
||||
select {
|
||||
case w.updates <- uv:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Snapshot returns a snapshot of the current loaded config
|
||||
func (m *memory) Snapshot() (*loader.Snapshot, error) {
|
||||
if m.loaded() {
|
||||
m.RLock()
|
||||
snap := loader.Copy(m.snap)
|
||||
m.RUnlock()
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
// not loaded, sync
|
||||
if err := m.Sync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make copy
|
||||
m.RLock()
|
||||
snap := loader.Copy(m.snap)
|
||||
m.RUnlock()
|
||||
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
// Sync loads all the sources, calls the parser and updates the config
|
||||
func (m *memory) Sync() error {
|
||||
//nolint:prealloc
|
||||
var sets []*source.ChangeSet
|
||||
|
||||
m.Lock()
|
||||
|
||||
// read the source
|
||||
var gerr []string
|
||||
|
||||
for _, source := range m.sources {
|
||||
ch, err := source.Read()
|
||||
if err != nil {
|
||||
gerr = append(gerr, err.Error())
|
||||
continue
|
||||
}
|
||||
sets = append(sets, ch)
|
||||
}
|
||||
|
||||
// merge sets
|
||||
set, err := m.opts.Reader.Merge(sets...)
|
||||
if err != nil {
|
||||
m.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// set values
|
||||
vals, err := m.opts.Reader.Values(set)
|
||||
if err != nil {
|
||||
m.Unlock()
|
||||
return err
|
||||
}
|
||||
m.vals = vals
|
||||
m.snap = &loader.Snapshot{
|
||||
ChangeSet: set,
|
||||
Version: genVer(),
|
||||
}
|
||||
|
||||
m.Unlock()
|
||||
|
||||
// update watchers
|
||||
m.update()
|
||||
|
||||
if len(gerr) > 0 {
|
||||
return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memory) Close() error {
|
||||
select {
|
||||
case <-m.exit:
|
||||
return nil
|
||||
default:
|
||||
close(m.exit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memory) Get(path ...string) (reader.Value, error) {
|
||||
if !m.loaded() {
|
||||
if err := m.Sync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// did sync actually work?
|
||||
if m.vals != nil {
|
||||
return m.vals.Get(path...), nil
|
||||
}
|
||||
|
||||
// assuming vals is nil
|
||||
// create new vals
|
||||
|
||||
ch := m.snap.ChangeSet
|
||||
|
||||
// we are truly screwed, trying to load in a hacked way
|
||||
v, err := m.opts.Reader.Values(ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// lets set it just because
|
||||
m.vals = v
|
||||
|
||||
if m.vals != nil {
|
||||
return m.vals.Get(path...), nil
|
||||
}
|
||||
|
||||
// ok we're going hardcore now
|
||||
|
||||
return nil, errors.New("no values")
|
||||
}
|
||||
|
||||
func (m *memory) Load(sources ...source.Source) error {
|
||||
var gerrors []string
|
||||
|
||||
for _, source := range sources {
|
||||
set, err := source.Read()
|
||||
if err != nil {
|
||||
gerrors = append(gerrors,
|
||||
fmt.Sprintf("error loading source %s: %v",
|
||||
source,
|
||||
err))
|
||||
// continue processing
|
||||
continue
|
||||
}
|
||||
m.Lock()
|
||||
m.sources = append(m.sources, source)
|
||||
m.sets = append(m.sets, set)
|
||||
idx := len(m.sets) - 1
|
||||
m.Unlock()
|
||||
go m.watch(idx, source)
|
||||
}
|
||||
|
||||
if err := m.reload(); err != nil {
|
||||
gerrors = append(gerrors, err.Error())
|
||||
}
|
||||
|
||||
// Return errors
|
||||
if len(gerrors) != 0 {
|
||||
return errors.New(strings.Join(gerrors, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memory) Watch(path ...string) (loader.Watcher, error) {
|
||||
value, err := m.Get(path...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
|
||||
w := &watcher{
|
||||
exit: make(chan bool),
|
||||
path: path,
|
||||
value: value,
|
||||
reader: m.opts.Reader,
|
||||
updates: make(chan updateValue, 1),
|
||||
version: m.snap.Version,
|
||||
}
|
||||
|
||||
e := m.watchers.PushBack(w)
|
||||
|
||||
m.Unlock()
|
||||
|
||||
go func() {
|
||||
<-w.exit
|
||||
m.Lock()
|
||||
m.watchers.Remove(e)
|
||||
m.Unlock()
|
||||
}()
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (m *memory) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*loader.Snapshot, error) {
|
||||
update := func(v reader.Value) *loader.Snapshot {
|
||||
w.value = v
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Data: v.Bytes(),
|
||||
Format: w.reader.String(),
|
||||
Source: "memory",
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return &loader.Snapshot{
|
||||
ChangeSet: cs,
|
||||
Version: w.version,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
|
||||
case uv := <-w.updates:
|
||||
if uv.version <= w.version {
|
||||
continue
|
||||
}
|
||||
|
||||
v := uv.value
|
||||
|
||||
w.version = uv.version
|
||||
|
||||
if bytes.Equal(w.value.Bytes(), v.Bytes()) {
|
||||
continue
|
||||
}
|
||||
|
||||
return update(v), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
select {
|
||||
case <-w.exit:
|
||||
default:
|
||||
close(w.exit)
|
||||
close(w.updates)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func genVer() string {
|
||||
return fmt.Sprintf("%d", time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func NewLoader(opts ...loader.Option) loader.Loader {
|
||||
options := loader.Options{
|
||||
Reader: json.NewReader(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
m := &memory{
|
||||
exit: make(chan bool),
|
||||
opts: options,
|
||||
watchers: list.New(),
|
||||
sources: options.Source,
|
||||
}
|
||||
|
||||
m.sets = make([]*source.ChangeSet, len(options.Source))
|
||||
|
||||
for i, s := range options.Source {
|
||||
m.sets[i] = &source.ChangeSet{Source: s.String()}
|
||||
go m.watch(i, s)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config/loader"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
// WithSource appends a source to list of sources
|
||||
func WithSource(s source.Source) loader.Option {
|
||||
return func(o *loader.Options) {
|
||||
o.Source = append(o.Source, s)
|
||||
}
|
||||
}
|
||||
|
||||
// WithReader sets the config reader
|
||||
func WithReader(r reader.Reader) loader.Option {
|
||||
return func(o *loader.Options) {
|
||||
o.Reader = r
|
||||
}
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config/loader"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
// WithLoader sets the loader for manager config
|
||||
func WithLoader(l loader.Loader) Option {
|
||||
return func(o *Options) {
|
||||
o.Loader = l
|
||||
}
|
||||
}
|
||||
|
||||
// WithSource appends a source to list of sources
|
||||
func WithSource(s source.Source) Option {
|
||||
return func(o *Options) {
|
||||
o.Source = append(o.Source, s)
|
||||
}
|
||||
}
|
||||
|
||||
// WithReader sets the config reader
|
||||
func WithReader(r reader.Reader) Option {
|
||||
return func(o *Options) {
|
||||
o.Reader = r
|
||||
}
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
"github.com/micro/go-micro/v3/config/encoder/json"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type jsonReader struct {
|
||||
opts reader.Options
|
||||
json encoder.Encoder
|
||||
}
|
||||
|
||||
func (j *jsonReader) Merge(changes ...*source.ChangeSet) (*source.ChangeSet, error) {
|
||||
var merged map[string]interface{}
|
||||
|
||||
for _, m := range changes {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(m.Data) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
codec, ok := j.opts.Encoding[m.Format]
|
||||
if !ok {
|
||||
// fallback
|
||||
codec = j.json
|
||||
}
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := codec.Decode(m.Data, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := mergo.Map(&merged, data, mergo.WithOverride); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b, err := j.json.Encode(merged)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Timestamp: time.Now(),
|
||||
Data: b,
|
||||
Source: "json",
|
||||
Format: j.json.String(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (j *jsonReader) Values(ch *source.ChangeSet) (reader.Values, error) {
|
||||
if ch == nil {
|
||||
return nil, errors.New("changeset is nil")
|
||||
}
|
||||
if ch.Format != "json" {
|
||||
return nil, errors.New("unsupported format")
|
||||
}
|
||||
return newValues(ch, j.opts)
|
||||
}
|
||||
|
||||
func (j *jsonReader) String() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
// NewReader creates a json reader
|
||||
func NewReader(opts ...reader.Option) reader.Reader {
|
||||
options := reader.NewOptions(opts...)
|
||||
return &jsonReader{
|
||||
json: json.NewEncoder(),
|
||||
opts: options,
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
data := []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`)
|
||||
|
||||
testData := []struct {
|
||||
path []string
|
||||
value string
|
||||
}{
|
||||
{
|
||||
[]string{"foo"},
|
||||
"bar",
|
||||
},
|
||||
{
|
||||
[]string{"baz", "bar"},
|
||||
"cat",
|
||||
},
|
||||
}
|
||||
|
||||
values := newTestValues(t, data)
|
||||
|
||||
for _, test := range testData {
|
||||
if v := values.Get(test.path...).String(""); v != test.value {
|
||||
t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableReplaceEnvVars(t *testing.T) {
|
||||
data := []byte(`{"foo": "bar", "baz": {"bar": "test/${test}"}}`)
|
||||
|
||||
tests := []struct {
|
||||
path []string
|
||||
value string
|
||||
opts []reader.Option
|
||||
}{
|
||||
{
|
||||
[]string{"baz", "bar"},
|
||||
"test/",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]string{"baz", "bar"},
|
||||
"test/${test}",
|
||||
[]reader.Option{reader.WithDisableReplaceEnvVars()},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
values := newTestValues(t, data, test.opts...)
|
||||
|
||||
if v := values.Get(test.path...).String(""); v != test.value {
|
||||
t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newTestValues(t *testing.T, data []byte, opts ...reader.Option) reader.Values {
|
||||
r := NewReader(opts...)
|
||||
|
||||
c, err := r.Merge(&source.ChangeSet{Data: data}, &source.ChangeSet{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
values, err := r.Values(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
@@ -1,206 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
simple "github.com/bitly/go-simplejson"
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type jsonValues struct {
|
||||
ch *source.ChangeSet
|
||||
sj *simple.Json
|
||||
}
|
||||
|
||||
type jsonValue struct {
|
||||
*simple.Json
|
||||
}
|
||||
|
||||
func newValues(ch *source.ChangeSet, opts reader.Options) (reader.Values, error) {
|
||||
sj := simple.New()
|
||||
data := ch.Data
|
||||
|
||||
if !opts.DisableReplaceEnvVars {
|
||||
data, _ = reader.ReplaceEnvVars(ch.Data)
|
||||
}
|
||||
|
||||
if err := sj.UnmarshalJSON(data); err != nil {
|
||||
sj.SetPath(nil, string(ch.Data))
|
||||
}
|
||||
return &jsonValues{ch, sj}, nil
|
||||
}
|
||||
|
||||
func (j *jsonValues) Get(path ...string) reader.Value {
|
||||
return &jsonValue{j.sj.GetPath(path...)}
|
||||
}
|
||||
|
||||
func (j *jsonValues) Del(path ...string) {
|
||||
// delete the tree?
|
||||
if len(path) == 0 {
|
||||
j.sj = simple.New()
|
||||
return
|
||||
}
|
||||
|
||||
if len(path) == 1 {
|
||||
j.sj.Del(path[0])
|
||||
return
|
||||
}
|
||||
|
||||
vals := j.sj.GetPath(path[:len(path)-1]...)
|
||||
vals.Del(path[len(path)-1])
|
||||
j.sj.SetPath(path[:len(path)-1], vals.Interface())
|
||||
return
|
||||
}
|
||||
|
||||
func (j *jsonValues) Set(val interface{}, path ...string) {
|
||||
j.sj.SetPath(path, val)
|
||||
}
|
||||
|
||||
func (j *jsonValues) Bytes() []byte {
|
||||
b, _ := j.sj.MarshalJSON()
|
||||
return b
|
||||
}
|
||||
|
||||
func (j *jsonValues) Map() map[string]interface{} {
|
||||
m, _ := j.sj.Map()
|
||||
return m
|
||||
}
|
||||
|
||||
func (j *jsonValues) Scan(v interface{}) error {
|
||||
b, err := j.sj.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
func (j *jsonValues) String() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (j *jsonValue) Bool(def bool) bool {
|
||||
b, err := j.Json.Bool()
|
||||
if err == nil {
|
||||
return b
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
b, err = strconv.ParseBool(str)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (j *jsonValue) Int(def int) int {
|
||||
i, err := j.Json.Int()
|
||||
if err == nil {
|
||||
return i
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
i, err = strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (j *jsonValue) String(def string) string {
|
||||
return j.Json.MustString(def)
|
||||
}
|
||||
|
||||
func (j *jsonValue) Float64(def float64) float64 {
|
||||
f, err := j.Json.Float64()
|
||||
if err == nil {
|
||||
return f
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
f, err = strconv.ParseFloat(str, 64)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (j *jsonValue) Duration(def time.Duration) time.Duration {
|
||||
v, err := j.Json.String()
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
value, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func (j *jsonValue) StringSlice(def []string) []string {
|
||||
v, err := j.Json.String()
|
||||
if err == nil {
|
||||
sl := strings.Split(v, ",")
|
||||
if len(sl) > 1 {
|
||||
return sl
|
||||
}
|
||||
}
|
||||
return j.Json.MustStringArray(def)
|
||||
}
|
||||
|
||||
func (j *jsonValue) StringMap(def map[string]string) map[string]string {
|
||||
m, err := j.Json.Map()
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
res := map[string]string{}
|
||||
|
||||
for k, v := range m {
|
||||
res[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (j *jsonValue) Scan(v interface{}) error {
|
||||
b, err := j.Json.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
func (j *jsonValue) Bytes() []byte {
|
||||
b, err := j.Json.Bytes()
|
||||
if err != nil {
|
||||
// try return marshalled
|
||||
b, err = j.Json.MarshalJSON()
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return b
|
||||
}
|
||||
return b
|
||||
}
|
@@ -1,86 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
func TestValues(t *testing.T) {
|
||||
emptyStr := ""
|
||||
testData := []struct {
|
||||
csdata []byte
|
||||
path []string
|
||||
accepter interface{}
|
||||
value interface{}
|
||||
}{
|
||||
{
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "cat"}}`),
|
||||
[]string{"foo"},
|
||||
emptyStr,
|
||||
"bar",
|
||||
},
|
||||
{
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "cat"}}`),
|
||||
[]string{"baz", "bar"},
|
||||
emptyStr,
|
||||
"cat",
|
||||
},
|
||||
}
|
||||
|
||||
for idx, test := range testData {
|
||||
values, err := newValues(&source.ChangeSet{
|
||||
Data: test.csdata,
|
||||
}, reader.Options{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = values.Get(test.path...).Scan(&test.accepter)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if test.accepter != test.value {
|
||||
t.Fatalf("No.%d Expected %v got %v for path %v", idx, test.value, test.accepter, test.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStructArray(t *testing.T) {
|
||||
type T struct {
|
||||
Foo string
|
||||
}
|
||||
|
||||
emptyTSlice := []T{}
|
||||
|
||||
testData := []struct {
|
||||
csdata []byte
|
||||
accepter []T
|
||||
value []T
|
||||
}{
|
||||
{
|
||||
[]byte(`[{"foo": "bar"}]`),
|
||||
emptyTSlice,
|
||||
[]T{{Foo: "bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
for idx, test := range testData {
|
||||
values, err := newValues(&source.ChangeSet{
|
||||
Data: test.csdata,
|
||||
}, reader.Options{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = values.Get().Scan(&test.accepter)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.accepter, test.value) {
|
||||
t.Fatalf("No.%d Expected %v got %v", idx, test.value, test.accepter)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
"github.com/micro/go-micro/v3/config/encoder/hcl"
|
||||
"github.com/micro/go-micro/v3/config/encoder/json"
|
||||
"github.com/micro/go-micro/v3/config/encoder/toml"
|
||||
"github.com/micro/go-micro/v3/config/encoder/xml"
|
||||
"github.com/micro/go-micro/v3/config/encoder/yaml"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Encoding map[string]encoder.Encoder
|
||||
DisableReplaceEnvVars bool
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Encoding: map[string]encoder.Encoder{
|
||||
"json": json.NewEncoder(),
|
||||
"yaml": yaml.NewEncoder(),
|
||||
"toml": toml.NewEncoder(),
|
||||
"xml": xml.NewEncoder(),
|
||||
"hcl": hcl.NewEncoder(),
|
||||
"yml": yaml.NewEncoder(),
|
||||
},
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func WithEncoder(e encoder.Encoder) Option {
|
||||
return func(o *Options) {
|
||||
if o.Encoding == nil {
|
||||
o.Encoding = make(map[string]encoder.Encoder)
|
||||
}
|
||||
o.Encoding[e.String()] = e
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisableReplaceEnvVars disables the environment variable interpolation preprocessor
|
||||
func WithDisableReplaceEnvVars() Option {
|
||||
return func(o *Options) {
|
||||
o.DisableReplaceEnvVars = true
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func ReplaceEnvVars(raw []byte) ([]byte, error) {
|
||||
re := regexp.MustCompile(`\$\{([A-Za-z0-9_]+)\}`)
|
||||
if re.Match(raw) {
|
||||
dataS := string(raw)
|
||||
res := re.ReplaceAllStringFunc(dataS, replaceEnvVars)
|
||||
return []byte(res), nil
|
||||
} else {
|
||||
return raw, nil
|
||||
}
|
||||
}
|
||||
|
||||
func replaceEnvVars(element string) string {
|
||||
v := element[2 : len(element)-1]
|
||||
el := os.Getenv(v)
|
||||
return el
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReplaceEnvVars(t *testing.T) {
|
||||
os.Setenv("myBar", "cat")
|
||||
os.Setenv("MYBAR", "cat")
|
||||
os.Setenv("my_Bar", "cat")
|
||||
os.Setenv("myBar_", "cat")
|
||||
|
||||
testData := []struct {
|
||||
expected string
|
||||
data []byte
|
||||
}{
|
||||
// Right use cases
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "cat"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${myBar}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "cat"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${MYBAR}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "cat"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${my_Bar}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "cat"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${myBar_}"}}`),
|
||||
},
|
||||
// Wrong use cases
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "${myBar-}"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${myBar-}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "${}"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "$sss}"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "$sss}"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "${sss"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "${sss"}}`),
|
||||
},
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "{something}"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "{something}"}}`),
|
||||
},
|
||||
// Use cases without replace env vars
|
||||
{
|
||||
`{"foo": "bar", "baz": {"bar": "cat"}}`,
|
||||
[]byte(`{"foo": "bar", "baz": {"bar": "cat"}}`),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testData {
|
||||
res, err := ReplaceEnvVars(test.data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Compare(test.expected, string(res)) != 0 {
|
||||
t.Fatalf("Expected %s got %s", test.expected, res)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
// Package reader parses change sets and provides config values
|
||||
package reader
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
// Reader is an interface for merging changesets
|
||||
type Reader interface {
|
||||
Merge(...*source.ChangeSet) (*source.ChangeSet, error)
|
||||
Values(*source.ChangeSet) (Values, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
// Values is returned by the reader
|
||||
type Values interface {
|
||||
Bytes() []byte
|
||||
Get(path ...string) Value
|
||||
Set(val interface{}, path ...string)
|
||||
Del(path ...string)
|
||||
Map() map[string]interface{}
|
||||
Scan(v interface{}) error
|
||||
}
|
||||
|
||||
// Value represents a value of any type
|
||||
type Value interface {
|
||||
Bool(def bool) bool
|
||||
Int(def int) int
|
||||
String(def string) string
|
||||
Float64(def float64) float64
|
||||
Duration(def time.Duration) time.Duration
|
||||
StringSlice(def []string) []string
|
||||
StringMap(def map[string]string) map[string]string
|
||||
Scan(val interface{}) error
|
||||
Bytes() []byte
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Sum returns the md5 checksum of the ChangeSet data
|
||||
func (c *ChangeSet) Sum() string {
|
||||
h := md5.New()
|
||||
h.Write(c.Data)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
96
config/source/env/README.md
vendored
96
config/source/env/README.md
vendored
@@ -1,96 +0,0 @@
|
||||
# Env Source
|
||||
|
||||
The env source reads config from environment variables
|
||||
|
||||
## Format
|
||||
|
||||
We expect environment variables to be in the standard format of FOO=bar
|
||||
|
||||
Keys are converted to lowercase and split on underscore.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
DATABASE_ADDRESS=127.0.0.1
|
||||
DATABASE_PORT=3306
|
||||
```
|
||||
|
||||
Becomes
|
||||
|
||||
```json
|
||||
{
|
||||
"database": {
|
||||
"address": "127.0.0.1",
|
||||
"port": 3306
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Prefixes
|
||||
|
||||
Environment variables can be namespaced so we only have access to a subset. Two options are available:
|
||||
|
||||
```
|
||||
WithPrefix(p ...string)
|
||||
WithStrippedPrefix(p ...string)
|
||||
```
|
||||
|
||||
The former will preserve the prefix and make it a top level key in the config. The latter eliminates the prefix, reducing the nesting by one.
|
||||
|
||||
#### Example:
|
||||
|
||||
Given ENVs of:
|
||||
|
||||
```
|
||||
APP_DATABASE_ADDRESS=127.0.0.1
|
||||
APP_DATABASE_PORT=3306
|
||||
VAULT_ADDR=vault:1337
|
||||
```
|
||||
|
||||
and a source initialized as follows:
|
||||
|
||||
```
|
||||
src := env.NewSource(
|
||||
env.WithPrefix("VAULT"),
|
||||
env.WithStrippedPrefix("APP"),
|
||||
)
|
||||
```
|
||||
|
||||
The resulting config will be:
|
||||
|
||||
```
|
||||
{
|
||||
"database": {
|
||||
"address": "127.0.0.1",
|
||||
"port": 3306
|
||||
},
|
||||
"vault": {
|
||||
"addr": "vault:1337"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## New Source
|
||||
|
||||
Specify source with data
|
||||
|
||||
```go
|
||||
src := env.NewSource(
|
||||
// optionally specify prefix
|
||||
env.WithPrefix("MICRO"),
|
||||
)
|
||||
```
|
||||
|
||||
## Load Source
|
||||
|
||||
Load the source into config
|
||||
|
||||
```go
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load env source
|
||||
conf.Load(src)
|
||||
```
|
146
config/source/env/env.go
vendored
146
config/source/env/env.go
vendored
@@ -1,146 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultPrefixes = []string{}
|
||||
)
|
||||
|
||||
type env struct {
|
||||
prefixes []string
|
||||
strippedPrefixes []string
|
||||
opts source.Options
|
||||
}
|
||||
|
||||
func (e *env) Read() (*source.ChangeSet, error) {
|
||||
var changes map[string]interface{}
|
||||
|
||||
for _, env := range os.Environ() {
|
||||
|
||||
if len(e.prefixes) > 0 || len(e.strippedPrefixes) > 0 {
|
||||
notFound := true
|
||||
|
||||
if _, ok := matchPrefix(e.prefixes, env); ok {
|
||||
notFound = false
|
||||
}
|
||||
|
||||
if match, ok := matchPrefix(e.strippedPrefixes, env); ok {
|
||||
env = strings.TrimPrefix(env, match)
|
||||
notFound = false
|
||||
}
|
||||
|
||||
if notFound {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
pair := strings.SplitN(env, "=", 2)
|
||||
value := pair[1]
|
||||
keys := strings.Split(strings.ToLower(pair[0]), "_")
|
||||
reverse(keys)
|
||||
|
||||
tmp := make(map[string]interface{})
|
||||
for i, k := range keys {
|
||||
if i == 0 {
|
||||
if intValue, err := strconv.Atoi(value); err == nil {
|
||||
tmp[k] = intValue
|
||||
} else if boolValue, err := strconv.ParseBool(value); err == nil {
|
||||
tmp[k] = boolValue
|
||||
} else {
|
||||
tmp[k] = value
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
tmp = map[string]interface{}{k: tmp}
|
||||
}
|
||||
|
||||
if err := mergo.Map(&changes, tmp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b, err := e.opts.Encoder.Encode(changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Format: e.opts.Encoder.String(),
|
||||
Data: b,
|
||||
Timestamp: time.Now(),
|
||||
Source: e.String(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func matchPrefix(pre []string, s string) (string, bool) {
|
||||
for _, p := range pre {
|
||||
if strings.HasPrefix(s, p) {
|
||||
return p, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func reverse(ss []string) {
|
||||
for i := len(ss)/2 - 1; i >= 0; i-- {
|
||||
opp := len(ss) - 1 - i
|
||||
ss[i], ss[opp] = ss[opp], ss[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (e *env) Watch() (source.Watcher, error) {
|
||||
return newWatcher()
|
||||
}
|
||||
|
||||
func (e *env) Write(cs *source.ChangeSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *env) String() string {
|
||||
return "env"
|
||||
}
|
||||
|
||||
// NewSource returns a config source for parsing ENV variables.
|
||||
// Underscores are delimiters for nesting, and all keys are lowercased.
|
||||
//
|
||||
// Example:
|
||||
// "DATABASE_SERVER_HOST=localhost" will convert to
|
||||
//
|
||||
// {
|
||||
// "database": {
|
||||
// "server": {
|
||||
// "host": "localhost"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
func NewSource(opts ...source.Option) source.Source {
|
||||
options := source.NewOptions(opts...)
|
||||
|
||||
var sp []string
|
||||
var pre []string
|
||||
if p, ok := options.Context.Value(strippedPrefixKey{}).([]string); ok {
|
||||
sp = p
|
||||
}
|
||||
|
||||
if p, ok := options.Context.Value(prefixKey{}).([]string); ok {
|
||||
pre = p
|
||||
}
|
||||
|
||||
if len(sp) > 0 || len(pre) > 0 {
|
||||
pre = append(pre, DefaultPrefixes...)
|
||||
}
|
||||
return &env{prefixes: pre, strippedPrefixes: sp, opts: options}
|
||||
}
|
112
config/source/env/env_test.go
vendored
112
config/source/env/env_test.go
vendored
@@ -1,112 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
func TestEnv_Read(t *testing.T) {
|
||||
expected := map[string]map[string]string{
|
||||
"database": {
|
||||
"host": "localhost",
|
||||
"password": "password",
|
||||
"datasource": "user:password@tcp(localhost:port)/db?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
},
|
||||
}
|
||||
|
||||
os.Setenv("DATABASE_HOST", "localhost")
|
||||
os.Setenv("DATABASE_PASSWORD", "password")
|
||||
os.Setenv("DATABASE_DATASOURCE", "user:password@tcp(localhost:port)/db?charset=utf8mb4&parseTime=True&loc=Local")
|
||||
|
||||
source := NewSource()
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
if err := json.Unmarshal(c.Data, &actual); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
actualDB := actual["database"].(map[string]interface{})
|
||||
|
||||
for k, v := range expected["database"] {
|
||||
a := actualDB[k]
|
||||
|
||||
if a != v {
|
||||
t.Errorf("expected %v got %v", v, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvvar_Prefixes(t *testing.T) {
|
||||
os.Setenv("APP_DATABASE_HOST", "localhost")
|
||||
os.Setenv("APP_DATABASE_PASSWORD", "password")
|
||||
os.Setenv("VAULT_ADDR", "vault:1337")
|
||||
os.Setenv("MICRO_REGISTRY", "mdns")
|
||||
|
||||
var prefixtests = []struct {
|
||||
prefixOpts []source.Option
|
||||
expectedKeys []string
|
||||
}{
|
||||
{[]source.Option{WithPrefix("APP", "MICRO")}, []string{"app", "micro"}},
|
||||
{[]source.Option{WithPrefix("MICRO"), WithStrippedPrefix("APP")}, []string{"database", "micro"}},
|
||||
{[]source.Option{WithPrefix("MICRO"), WithStrippedPrefix("APP")}, []string{"database", "micro"}},
|
||||
}
|
||||
|
||||
for _, pt := range prefixtests {
|
||||
source := NewSource(pt.prefixOpts...)
|
||||
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
if err := json.Unmarshal(c.Data, &actual); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// assert other prefixes ignored
|
||||
if l := len(actual); l != len(pt.expectedKeys) {
|
||||
t.Errorf("expected %v top keys, got %v", len(pt.expectedKeys), l)
|
||||
}
|
||||
|
||||
for _, k := range pt.expectedKeys {
|
||||
if !containsKey(actual, k) {
|
||||
t.Errorf("expected key %v, not found", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvvar_WatchNextNoOpsUntilStop(t *testing.T) {
|
||||
src := NewSource(WithStrippedPrefix("GOMICRO_"))
|
||||
w, err := src.Watch()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
if _, err := w.Next(); err != source.ErrWatcherStopped {
|
||||
t.Errorf("expected watcher stopped error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func containsKey(m map[string]interface{}, s string) bool {
|
||||
for k := range m {
|
||||
if k == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
50
config/source/env/options.go
vendored
50
config/source/env/options.go
vendored
@@ -1,50 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type strippedPrefixKey struct{}
|
||||
type prefixKey struct{}
|
||||
|
||||
// WithStrippedPrefix sets the environment variable prefixes to scope to.
|
||||
// These prefixes will be removed from the actual config entries.
|
||||
func WithStrippedPrefix(p ...string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
|
||||
o.Context = context.WithValue(o.Context, strippedPrefixKey{}, appendUnderscore(p))
|
||||
}
|
||||
}
|
||||
|
||||
// WithPrefix sets the environment variable prefixes to scope to.
|
||||
// These prefixes will not be removed. Each prefix will be considered a top level config entry.
|
||||
func WithPrefix(p ...string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, prefixKey{}, appendUnderscore(p))
|
||||
}
|
||||
}
|
||||
|
||||
func appendUnderscore(prefixes []string) []string {
|
||||
//nolint:prealloc
|
||||
var result []string
|
||||
for _, p := range prefixes {
|
||||
if !strings.HasSuffix(p, "_") {
|
||||
result = append(result, p+"_")
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, p)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
24
config/source/env/watcher.go
vendored
24
config/source/env/watcher.go
vendored
@@ -1,24 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
exit chan struct{}
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
<-w.exit
|
||||
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
close(w.exit)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newWatcher() (source.Watcher, error) {
|
||||
return &watcher{exit: make(chan struct{})}, nil
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
# File Source
|
||||
|
||||
The file source reads config from a file.
|
||||
|
||||
It uses the File extension to determine the Format e.g `config.yaml` has the yaml format.
|
||||
It does not make use of encoders or interpet the file data. If a file extension is not present
|
||||
the source Format will default to the Encoder in options.
|
||||
|
||||
## Example
|
||||
|
||||
A config file format in json
|
||||
|
||||
```json
|
||||
{
|
||||
"hosts": {
|
||||
"database": {
|
||||
"address": "10.0.0.1",
|
||||
"port": 3306
|
||||
},
|
||||
"cache": {
|
||||
"address": "10.0.0.2",
|
||||
"port": 6379
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## New Source
|
||||
|
||||
Specify file source with path to file. Path is optional and will default to `config.json`
|
||||
|
||||
```go
|
||||
fileSource := file.NewSource(
|
||||
file.WithPath("/tmp/config.json"),
|
||||
)
|
||||
```
|
||||
|
||||
## File Format
|
||||
|
||||
To load different file formats e.g yaml, toml, xml simply specify them with their extension
|
||||
|
||||
```
|
||||
fileSource := file.NewSource(
|
||||
file.WithPath("/tmp/config.yaml"),
|
||||
)
|
||||
```
|
||||
|
||||
If you want to specify a file without extension, ensure you set the encoder to the same format
|
||||
|
||||
```
|
||||
e := toml.NewEncoder()
|
||||
|
||||
fileSource := file.NewSource(
|
||||
file.WithPath("/tmp/config"),
|
||||
source.WithEncoder(e),
|
||||
)
|
||||
```
|
||||
|
||||
## Load Source
|
||||
|
||||
Load the source into config
|
||||
|
||||
```go
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
conf.Load(fileSource)
|
||||
```
|
||||
|
@@ -1,70 +0,0 @@
|
||||
// Package file is a file source. Expected format is json
|
||||
package file
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type file struct {
|
||||
path string
|
||||
data []byte
|
||||
opts source.Options
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultPath = "config.json"
|
||||
)
|
||||
|
||||
func (f *file) Read() (*source.ChangeSet, error) {
|
||||
fh, err := os.Open(f.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fh.Close()
|
||||
b, err := ioutil.ReadAll(fh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := fh.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Format: format(f.path, f.opts.Encoder),
|
||||
Source: f.String(),
|
||||
Timestamp: info.ModTime(),
|
||||
Data: b,
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (f *file) String() string {
|
||||
return "file"
|
||||
}
|
||||
|
||||
func (f *file) Watch() (source.Watcher, error) {
|
||||
if _, err := os.Stat(f.path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWatcher(f)
|
||||
}
|
||||
|
||||
func (f *file) Write(cs *source.ChangeSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSource(opts ...source.Option) source.Source {
|
||||
options := source.NewOptions(opts...)
|
||||
path := DefaultPath
|
||||
f, ok := options.Context.Value(filePathKey{}).(string)
|
||||
if ok {
|
||||
path = f
|
||||
}
|
||||
return &file{opts: options, path: path}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
package file_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config"
|
||||
"github.com/micro/go-micro/v3/config/source/file"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
data := []byte(`{"foo": "bar"}`)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
fh, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer func() {
|
||||
fh.Close()
|
||||
os.Remove(path)
|
||||
}()
|
||||
_, err = fh.Write(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
conf, err := config.NewConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conf.Load(file.NewSource(file.WithPath(path)))
|
||||
// simulate multiple close
|
||||
go conf.Close()
|
||||
go conf.Close()
|
||||
}
|
||||
|
||||
func TestFile(t *testing.T) {
|
||||
data := []byte(`{"foo": "bar"}`)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
fh, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer func() {
|
||||
fh.Close()
|
||||
os.Remove(path)
|
||||
}()
|
||||
|
||||
_, err = fh.Write(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
f := file.NewSource(file.WithPath(path))
|
||||
c, err := f.Read()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if string(c.Data) != string(data) {
|
||||
t.Logf("%+v", c)
|
||||
t.Error("data from file does not match")
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
)
|
||||
|
||||
func format(p string, e encoder.Encoder) string {
|
||||
parts := strings.Split(p, ".")
|
||||
if len(parts) > 1 {
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
return e.String()
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
func TestFormat(t *testing.T) {
|
||||
opts := source.NewOptions()
|
||||
e := opts.Encoder
|
||||
|
||||
testCases := []struct {
|
||||
p string
|
||||
f string
|
||||
}{
|
||||
{"/foo/bar.json", "json"},
|
||||
{"/foo/bar.yaml", "yaml"},
|
||||
{"/foo/bar.xml", "xml"},
|
||||
{"/foo/bar.conf.ini", "ini"},
|
||||
{"conf", e.String()},
|
||||
}
|
||||
|
||||
for _, d := range testCases {
|
||||
f := format(d.p, e)
|
||||
if f != d.f {
|
||||
t.Fatalf("%s: expected %s got %s", d.p, d.f, f)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type filePathKey struct{}
|
||||
|
||||
// WithPath sets the path to file
|
||||
func WithPath(p string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, filePathKey{}, p)
|
||||
}
|
||||
}
|
@@ -1,77 +0,0 @@
|
||||
//+build !linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
f *file
|
||||
|
||||
fw *fsnotify.Watcher
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
func newWatcher(f *file) (source.Watcher, error) {
|
||||
fw, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fw.Add(f.path)
|
||||
|
||||
return &watcher{
|
||||
f: f,
|
||||
fw: fw,
|
||||
exit: make(chan bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
// is it closed?
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil, source.ErrWatcherStopped
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
// try get the event
|
||||
select {
|
||||
case event, _ := <-w.fw.Events:
|
||||
if event.Op == fsnotify.Rename {
|
||||
// check existence of file, and add watch again
|
||||
_, err := os.Stat(event.Name)
|
||||
if err == nil || os.IsExist(err) {
|
||||
w.fw.Add(event.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// ARCH: Darwin Kernel Version 18.7.0
|
||||
// ioutil.WriteFile truncates it before writing, but the problem is that
|
||||
// you will receive two events(fsnotify.Chmod and fsnotify.Write).
|
||||
// We can solve this problem by ignoring fsnotify.Chmod event.
|
||||
if event.Op&fsnotify.Write != fsnotify.Write {
|
||||
continue
|
||||
}
|
||||
|
||||
c, err := w.f.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
case err := <-w.fw.Errors:
|
||||
return nil, err
|
||||
case <-w.exit:
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
return w.fw.Close()
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
//+build linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
f *file
|
||||
|
||||
fw *fsnotify.Watcher
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
func newWatcher(f *file) (source.Watcher, error) {
|
||||
fw, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fw.Add(f.path)
|
||||
|
||||
return &watcher{
|
||||
f: f,
|
||||
fw: fw,
|
||||
exit: make(chan bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
// is it closed?
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil, source.ErrWatcherStopped
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
// try get the event
|
||||
select {
|
||||
case event, _ := <-w.fw.Events:
|
||||
if event.Op == fsnotify.Rename {
|
||||
// check existence of file, and add watch again
|
||||
_, err := os.Stat(event.Name)
|
||||
if err == nil || os.IsExist(err) {
|
||||
w.fw.Add(event.Name)
|
||||
}
|
||||
}
|
||||
|
||||
c, err := w.f.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ARCH: Linux centos-7.shared 3.10.0-693.5.2.el7.x86_64
|
||||
// Sometimes, ioutil.WriteFile triggers multiple fsnotify.Write events, which may be a bug.
|
||||
|
||||
// Detect if the file has changed
|
||||
if reflect.DeepEqual(c.Data, w.f.data) {
|
||||
continue
|
||||
}
|
||||
w.f.data = c.Data
|
||||
|
||||
return c, nil
|
||||
case err := <-w.fw.Errors:
|
||||
return nil, err
|
||||
case <-w.exit:
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
return w.fw.Close()
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
# Flag Source
|
||||
|
||||
The flag source reads config from flags
|
||||
|
||||
## Format
|
||||
|
||||
We expect the use of the `flag` package. Upper case flags will be lower cased. Dashes will be used as delimiters.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
dbAddress := flag.String("database_address", "127.0.0.1", "the db address")
|
||||
dbPort := flag.Int("database_port", 3306, "the db port)
|
||||
```
|
||||
|
||||
Becomes
|
||||
|
||||
```json
|
||||
{
|
||||
"database": {
|
||||
"address": "127.0.0.1",
|
||||
"port": 3306
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## New Source
|
||||
|
||||
```go
|
||||
flagSource := flag.NewSource(
|
||||
// optionally enable reading of unset flags and their default
|
||||
// values into config, defaults to false
|
||||
IncludeUnset(true)
|
||||
)
|
||||
```
|
||||
|
||||
## Load Source
|
||||
|
||||
Load the source into config
|
||||
|
||||
```go
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load flag source
|
||||
conf.Load(flagSource)
|
||||
```
|
@@ -1,101 +0,0 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type flagsrc struct {
|
||||
opts source.Options
|
||||
}
|
||||
|
||||
func (fs *flagsrc) Read() (*source.ChangeSet, error) {
|
||||
if !flag.Parsed() {
|
||||
return nil, errors.New("flags not parsed")
|
||||
}
|
||||
|
||||
var changes map[string]interface{}
|
||||
|
||||
visitFn := func(f *flag.Flag) {
|
||||
n := strings.ToLower(f.Name)
|
||||
keys := strings.FieldsFunc(n, split)
|
||||
reverse(keys)
|
||||
|
||||
tmp := make(map[string]interface{})
|
||||
for i, k := range keys {
|
||||
if i == 0 {
|
||||
tmp[k] = f.Value
|
||||
continue
|
||||
}
|
||||
|
||||
tmp = map[string]interface{}{k: tmp}
|
||||
}
|
||||
|
||||
mergo.Map(&changes, tmp) // need to sort error handling
|
||||
return
|
||||
}
|
||||
|
||||
unset, ok := fs.opts.Context.Value(includeUnsetKey{}).(bool)
|
||||
if ok && unset {
|
||||
flag.VisitAll(visitFn)
|
||||
} else {
|
||||
flag.Visit(visitFn)
|
||||
}
|
||||
|
||||
b, err := fs.opts.Encoder.Encode(changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Format: fs.opts.Encoder.String(),
|
||||
Data: b,
|
||||
Timestamp: time.Now(),
|
||||
Source: fs.String(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func split(r rune) bool {
|
||||
return r == '-' || r == '_'
|
||||
}
|
||||
|
||||
func reverse(ss []string) {
|
||||
for i := len(ss)/2 - 1; i >= 0; i-- {
|
||||
opp := len(ss) - 1 - i
|
||||
ss[i], ss[opp] = ss[opp], ss[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *flagsrc) Watch() (source.Watcher, error) {
|
||||
return source.NewNoopWatcher()
|
||||
}
|
||||
|
||||
func (fs *flagsrc) Write(cs *source.ChangeSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *flagsrc) String() string {
|
||||
return "flag"
|
||||
}
|
||||
|
||||
// NewSource returns a config source for integrating parsed flags.
|
||||
// Hyphens are delimiters for nesting, and all keys are lowercased.
|
||||
//
|
||||
// Example:
|
||||
// dbhost := flag.String("database-host", "localhost", "the db host name")
|
||||
//
|
||||
// {
|
||||
// "database": {
|
||||
// "host": "localhost"
|
||||
// }
|
||||
// }
|
||||
func NewSource(opts ...source.Option) source.Source {
|
||||
return &flagsrc{opts: source.NewOptions(opts...)}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
dbuser = flag.String("database-user", "default", "db user")
|
||||
dbhost = flag.String("database-host", "", "db host")
|
||||
dbpw = flag.String("database-password", "", "db pw")
|
||||
)
|
||||
|
||||
func initTestFlags() {
|
||||
flag.Set("database-host", "localhost")
|
||||
flag.Set("database-password", "some-password")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func TestFlagsrc_Read(t *testing.T) {
|
||||
initTestFlags()
|
||||
source := NewSource()
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
if err := json.Unmarshal(c.Data, &actual); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
actualDB := actual["database"].(map[string]interface{})
|
||||
if actualDB["host"] != *dbhost {
|
||||
t.Errorf("expected %v got %v", *dbhost, actualDB["host"])
|
||||
}
|
||||
|
||||
if actualDB["password"] != *dbpw {
|
||||
t.Errorf("expected %v got %v", *dbpw, actualDB["password"])
|
||||
}
|
||||
|
||||
// unset flags should not be loaded
|
||||
if actualDB["user"] != nil {
|
||||
t.Errorf("expected %v got %v", nil, actualDB["user"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagsrc_ReadAll(t *testing.T) {
|
||||
initTestFlags()
|
||||
source := NewSource(IncludeUnset(true))
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var actual map[string]interface{}
|
||||
if err := json.Unmarshal(c.Data, &actual); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
actualDB := actual["database"].(map[string]interface{})
|
||||
|
||||
// unset flag defaults should be loaded
|
||||
if actualDB["user"] != *dbuser {
|
||||
t.Errorf("expected %v got %v", *dbuser, actualDB["user"])
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type includeUnsetKey struct{}
|
||||
|
||||
// IncludeUnset toggles the loading of unset flags and their respective default values.
|
||||
// Default behavior is to ignore any unset flags.
|
||||
func IncludeUnset(b bool) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, includeUnsetKey{}, true)
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
# Memory Source
|
||||
|
||||
The memory source provides in-memory data as a source
|
||||
|
||||
## Memory Format
|
||||
|
||||
The expected data format is json
|
||||
|
||||
```json
|
||||
data := []byte(`{
|
||||
"hosts": {
|
||||
"database": {
|
||||
"address": "10.0.0.1",
|
||||
"port": 3306
|
||||
},
|
||||
"cache": {
|
||||
"address": "10.0.0.2",
|
||||
"port": 6379
|
||||
}
|
||||
}
|
||||
}`)
|
||||
```
|
||||
|
||||
## New Source
|
||||
|
||||
Specify source with data
|
||||
|
||||
```go
|
||||
memorySource := memory.NewSource(
|
||||
memory.WithJSON(data),
|
||||
)
|
||||
```
|
||||
|
||||
## Load Source
|
||||
|
||||
Load the source into config
|
||||
|
||||
```go
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load memory source
|
||||
conf.Load(memorySource)
|
||||
```
|
@@ -1,99 +0,0 @@
|
||||
// Package memory is a memory source
|
||||
package memory
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type memory struct {
|
||||
sync.RWMutex
|
||||
ChangeSet *source.ChangeSet
|
||||
Watchers map[string]*watcher
|
||||
}
|
||||
|
||||
func (s *memory) Read() (*source.ChangeSet, error) {
|
||||
s.RLock()
|
||||
cs := &source.ChangeSet{
|
||||
Format: s.ChangeSet.Format,
|
||||
Timestamp: s.ChangeSet.Timestamp,
|
||||
Data: s.ChangeSet.Data,
|
||||
Checksum: s.ChangeSet.Checksum,
|
||||
Source: s.ChangeSet.Source,
|
||||
}
|
||||
s.RUnlock()
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (s *memory) Watch() (source.Watcher, error) {
|
||||
w := &watcher{
|
||||
Id: uuid.New().String(),
|
||||
Updates: make(chan *source.ChangeSet, 100),
|
||||
Source: s,
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.Watchers[w.Id] = w
|
||||
s.Unlock()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (m *memory) Write(cs *source.ChangeSet) error {
|
||||
m.Update(cs)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update allows manual updates of the config data.
|
||||
func (s *memory) Update(c *source.ChangeSet) {
|
||||
// don't process nil
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// hash the file
|
||||
s.Lock()
|
||||
// update changeset
|
||||
s.ChangeSet = &source.ChangeSet{
|
||||
Data: c.Data,
|
||||
Format: c.Format,
|
||||
Source: "memory",
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
s.ChangeSet.Checksum = s.ChangeSet.Sum()
|
||||
|
||||
// update watchers
|
||||
for _, w := range s.Watchers {
|
||||
select {
|
||||
case w.Updates <- s.ChangeSet:
|
||||
default:
|
||||
}
|
||||
}
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *memory) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
||||
func NewSource(opts ...source.Option) source.Source {
|
||||
var options source.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
s := &memory{
|
||||
Watchers: make(map[string]*watcher),
|
||||
}
|
||||
|
||||
if options.Context != nil {
|
||||
c, ok := options.Context.Value(changeSetKey{}).(*source.ChangeSet)
|
||||
if ok {
|
||||
s.Update(c)
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type changeSetKey struct{}
|
||||
|
||||
func withData(d []byte, f string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, changeSetKey{}, &source.ChangeSet{
|
||||
Data: d,
|
||||
Format: f,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WithChangeSet allows a changeset to be set
|
||||
func WithChangeSet(cs *source.ChangeSet) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, changeSetKey{}, cs)
|
||||
}
|
||||
}
|
||||
|
||||
// WithJSON allows the source data to be set to json
|
||||
func WithJSON(d []byte) source.Option {
|
||||
return withData(d, "json")
|
||||
}
|
||||
|
||||
// WithYAML allows the source data to be set to yaml
|
||||
func WithYAML(d []byte) source.Option {
|
||||
return withData(d, "yaml")
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config/source"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
Id string
|
||||
Updates chan *source.ChangeSet
|
||||
Source *memory
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
cs := <-w.Updates
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
w.Source.Lock()
|
||||
delete(w.Source.Watchers, w.Id)
|
||||
w.Source.Unlock()
|
||||
return nil
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type noopWatcher struct {
|
||||
exit chan struct{}
|
||||
}
|
||||
|
||||
func (w *noopWatcher) Next() (*ChangeSet, error) {
|
||||
<-w.exit
|
||||
|
||||
return nil, errors.New("noopWatcher stopped")
|
||||
}
|
||||
|
||||
func (w *noopWatcher) Stop() error {
|
||||
close(w.exit)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNoopWatcher returns a watcher that blocks on Next() until Stop() is called.
|
||||
func NewNoopWatcher() (Watcher, error) {
|
||||
return &noopWatcher{exit: make(chan struct{})}, nil
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v3/client"
|
||||
"github.com/micro/go-micro/v3/config/encoder"
|
||||
"github.com/micro/go-micro/v3/config/encoder/json"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
// Encoder
|
||||
Encoder encoder.Encoder
|
||||
|
||||
// for alternative data
|
||||
Context context.Context
|
||||
|
||||
// Client to use for RPC
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Encoder: json.NewEncoder(),
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// WithEncoder sets the source encoder
|
||||
func WithEncoder(e encoder.Encoder) Option {
|
||||
return func(o *Options) {
|
||||
o.Encoder = e
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the source client
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
// Package source is the interface for sources
|
||||
package source
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWatcherStopped is returned when source watcher has been stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
||||
// Source is the source from which config is loaded
|
||||
type Source interface {
|
||||
Read() (*ChangeSet, error)
|
||||
Write(*ChangeSet) error
|
||||
Watch() (Watcher, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
// ChangeSet represents a set of changes from a source
|
||||
type ChangeSet struct {
|
||||
Data []byte
|
||||
Checksum string
|
||||
Format string
|
||||
Source string
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
// Watcher watches a source for changes
|
||||
type Watcher interface {
|
||||
Next() (*ChangeSet, error)
|
||||
Stop() error
|
||||
}
|
66
config/store/store.go
Normal file
66
config/store/store.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package storeconfig
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v3/config"
|
||||
"github.com/micro/go-micro/v3/store"
|
||||
)
|
||||
|
||||
// NewConfig returns new config
|
||||
func NewConfig(store store.Store, key string) (config.Config, error) {
|
||||
return newConfig(store)
|
||||
}
|
||||
|
||||
type conf struct {
|
||||
key string
|
||||
store store.Store
|
||||
}
|
||||
|
||||
func newConfig(store store.Store) (*conf, error) {
|
||||
return &conf{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func mergeOptions(old config.Options, nu ...config.Option) config.Options {
|
||||
n := config.Options{
|
||||
Secret: old.Secret,
|
||||
}
|
||||
for _, opt := range nu {
|
||||
opt(&n)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *conf) Get(path string, options ...config.Option) config.Value {
|
||||
rec, err := c.store.Read(c.key)
|
||||
dat := []byte("{}")
|
||||
if err == nil && len(rec) > 0 {
|
||||
dat = rec[0].Value
|
||||
}
|
||||
values := config.NewJSONValues(dat)
|
||||
return values.Get(path)
|
||||
}
|
||||
|
||||
func (c *conf) Set(path string, val interface{}, options ...config.Option) {
|
||||
rec, err := c.store.Read(c.key)
|
||||
dat := []byte("{}")
|
||||
if err == nil && len(rec) > 0 {
|
||||
dat = rec[0].Value
|
||||
}
|
||||
values := config.NewJSONValues(dat)
|
||||
values.Set(path, val)
|
||||
c.store.Write(&store.Record{
|
||||
Key: c.key,
|
||||
Value: values.Bytes(),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *conf) Delete(path string, options ...config.Option) {
|
||||
rec, err := c.store.Read(c.key)
|
||||
dat := []byte("{}")
|
||||
if err != nil || len(rec) == 0 {
|
||||
return
|
||||
}
|
||||
values := config.NewJSONValues(dat)
|
||||
values.Delete(path)
|
||||
}
|
230
config/value.go
230
config/value.go
@@ -1,49 +1,215 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v3/config/reader"
|
||||
simple "github.com/bitly/go-simplejson"
|
||||
)
|
||||
|
||||
type value struct{}
|
||||
|
||||
func newValue() reader.Value {
|
||||
return new(value)
|
||||
type JSONValues struct {
|
||||
values []byte
|
||||
sj *simple.Json
|
||||
}
|
||||
|
||||
func (v *value) Bool(def bool) bool {
|
||||
type JSONValue struct {
|
||||
*simple.Json
|
||||
}
|
||||
|
||||
func NewJSONValues(data []byte) *JSONValues {
|
||||
sj := simple.New()
|
||||
|
||||
if err := sj.UnmarshalJSON(data); err != nil {
|
||||
sj.SetPath(nil, string(data))
|
||||
}
|
||||
return &JSONValues{data, sj}
|
||||
}
|
||||
|
||||
func NewJSONValue(data []byte) *JSONValue {
|
||||
sj := simple.New()
|
||||
|
||||
if err := sj.UnmarshalJSON(data); err != nil {
|
||||
sj.SetPath(nil, string(data))
|
||||
}
|
||||
return &JSONValue{sj}
|
||||
}
|
||||
|
||||
func (j *JSONValues) Get(path string, options ...Option) Value {
|
||||
paths := strings.Split(path, ".")
|
||||
return &JSONValue{j.sj.GetPath(paths...)}
|
||||
}
|
||||
|
||||
func (j *JSONValues) Delete(path string, options ...Option) {
|
||||
paths := strings.Split(path, ".")
|
||||
// delete the tree?
|
||||
if len(paths) == 0 {
|
||||
j.sj = simple.New()
|
||||
return
|
||||
}
|
||||
|
||||
if len(paths) == 1 {
|
||||
j.sj.Del(paths[0])
|
||||
return
|
||||
}
|
||||
|
||||
vals := j.sj.GetPath(paths[:len(paths)-1]...)
|
||||
vals.Del(paths[len(paths)-1])
|
||||
j.sj.SetPath(paths[:len(paths)-1], vals.Interface())
|
||||
return
|
||||
}
|
||||
|
||||
func (j *JSONValues) Set(path string, val interface{}, options ...Option) {
|
||||
paths := strings.Split(path, ".")
|
||||
j.sj.SetPath(paths, val)
|
||||
}
|
||||
|
||||
func (j *JSONValues) Bytes() []byte {
|
||||
b, _ := j.sj.MarshalJSON()
|
||||
return b
|
||||
}
|
||||
|
||||
func (j *JSONValues) Map() map[string]interface{} {
|
||||
m, _ := j.sj.Map()
|
||||
return m
|
||||
}
|
||||
|
||||
func (j *JSONValues) Scan(v interface{}) error {
|
||||
b, err := j.sj.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
func (j *JSONValues) String() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (j *JSONValue) Bool(def bool) bool {
|
||||
b, err := j.Json.Bool()
|
||||
if err == nil {
|
||||
return b
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
b, err = strconv.ParseBool(str)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (j *JSONValue) Int(def int) int {
|
||||
i, err := j.Json.Int()
|
||||
if err == nil {
|
||||
return i
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
i, err = strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (j *JSONValue) String(def string) string {
|
||||
return j.Json.MustString(def)
|
||||
}
|
||||
|
||||
func (j *JSONValue) Float64(def float64) float64 {
|
||||
f, err := j.Json.Float64()
|
||||
if err == nil {
|
||||
return f
|
||||
}
|
||||
|
||||
str, ok := j.Interface().(string)
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
||||
f, err = strconv.ParseFloat(str, 64)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (j *JSONValue) Duration(def time.Duration) time.Duration {
|
||||
v, err := j.Json.String()
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
value, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func (j *JSONValue) StringSlice(def []string) []string {
|
||||
v, err := j.Json.String()
|
||||
if err == nil {
|
||||
sl := strings.Split(v, ",")
|
||||
if len(sl) > 1 {
|
||||
return sl
|
||||
}
|
||||
}
|
||||
return j.Json.MustStringArray(def)
|
||||
}
|
||||
|
||||
func (j *JSONValue) Exists() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (v *value) Int(def int) int {
|
||||
return 0
|
||||
func (j *JSONValue) StringMap(def map[string]string) map[string]string {
|
||||
m, err := j.Json.Map()
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
res := map[string]string{}
|
||||
|
||||
for k, v := range m {
|
||||
res[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (v *value) String(def string) string {
|
||||
return ""
|
||||
func (j *JSONValue) Scan(v interface{}) error {
|
||||
b, err := j.Json.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
func (v *value) Float64(def float64) float64 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func (v *value) Duration(def time.Duration) time.Duration {
|
||||
return time.Duration(0)
|
||||
}
|
||||
|
||||
func (v *value) StringSlice(def []string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *value) StringMap(def map[string]string) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (v *value) Scan(val interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *value) Bytes() []byte {
|
||||
return nil
|
||||
func (j *JSONValue) Bytes() []byte {
|
||||
b, err := j.Json.Bytes()
|
||||
if err != nil {
|
||||
// try return marshalled
|
||||
b, err = j.Json.MarshalJSON()
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return b
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
15
go.mod
15
go.mod
@@ -7,7 +7,6 @@ replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.8
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
|
||||
github.com/caddyserver/certmagic v0.10.6
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
@@ -19,24 +18,22 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-acme/lego/v3 v3.4.0
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee
|
||||
github.com/gobwas/pool v0.2.0 // indirect
|
||||
github.com/gobwas/ws v1.0.3
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hpcloud/tail v1.0.0
|
||||
github.com/imdario/mergo v0.3.9
|
||||
github.com/kr/pretty v0.2.0
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/micro/go-micro v1.18.0
|
||||
github.com/micro/micro/v3 v3.0.0-beta.4 // indirect
|
||||
github.com/miekg/dns v1.1.27
|
||||
github.com/minio/minio-go/v7 v7.0.5
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf
|
||||
github.com/xanzy/go-gitlab v0.35.1
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
@@ -45,7 +42,5 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
|
||||
google.golang.org/grpc v1.27.0
|
||||
google.golang.org/protobuf v1.25.0
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.4.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
honnef.co/go/tools v0.0.1-2019.2.3
|
||||
)
|
||||
|
193
go.sum
193
go.sum
@@ -30,21 +30,28 @@ github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvd
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c h1:YMP6olTU903X3gxQJckdmiP8/zkSMq4kN3uipsU9XjU=
|
||||
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c/go.mod h1:7xhjOwRV2+0HXGmM0jxaEu+ZiXJFoVZOTfL/dmqbrD8=
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k=
|
||||
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -52,36 +59,59 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/bwmarrin/discordgo v0.20.1/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc=
|
||||
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||
github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
|
||||
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
||||
github.com/cloudflare/cloudflare-go v0.10.9 h1:d8KOgLpYiC+Xq3T4tuO+/goM+RZvuO+T4pojuv8giL8=
|
||||
github.com/cloudflare/cloudflare-go v0.10.9/go.mod h1:5TrsWH+3f4NV6WjtS5QFp+DifH81rph40gU374Sh0dQ=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
|
||||
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
|
||||
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
@@ -89,31 +119,41 @@ github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s9
|
||||
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23 h1:oqgGT9O61YAYvI41EBsLePOr+LE6roB0xY4gpkZuFSE=
|
||||
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1 h1:jFGzikHboUMRXmMBtwD/PbxoTHPs2919Irp/3rxMbvM=
|
||||
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch/v5 v5.0.0 h1:dKTrUeykyQwKb/kx7Z+4ukDs6l+4L41HqG1XHnhX7WE=
|
||||
github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsouza/go-dockerclient v1.4.4/go.mod h1:PrwszSL5fbmsESocROrOGq/NULMXRw+bajY0ltzD6MA=
|
||||
github.com/fsouza/go-dockerclient v1.6.0 h1:f7j+AX94143JL1H3TiqSMkM4EcLDI0De1qD4GGn3Hig=
|
||||
github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||
github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
|
||||
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
@@ -122,9 +162,14 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
|
||||
github.com/go-ini/ini v1.44.0 h1:8+SRbfpRFlIunpSum4BEf1ClTtVjOgKzgBv9pHFkI6w=
|
||||
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
@@ -142,11 +187,13 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@@ -169,6 +216,8 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
|
||||
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -178,6 +227,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
@@ -187,7 +238,13 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -198,6 +255,8 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
@@ -207,22 +266,33 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
|
||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b h1:FQ7+9fxhyp82ks9vAuyPzG0/vVbWwMwLJ+P6yJI5FN8=
|
||||
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b/go.mod h1:HMcgvsgd0Fjj4XXDkbjdmlbI505rUPBs6WBMYg2pXks=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
@@ -236,20 +306,47 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
||||
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
||||
github.com/lucas-clemente/quic-go v0.12.1/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
|
||||
github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
|
||||
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
|
||||
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
|
||||
github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mholt/certmagic v0.7.5/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
|
||||
github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
|
||||
github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk=
|
||||
github.com/micro/go-micro v1.16.0/go.mod h1:A0F58bHLh2m0LAI9QyhvmbN8c1cxhAZo3cM6s+iDsrM=
|
||||
github.com/micro/go-micro v1.18.0 h1:gP70EZVHpJuUIT0YWth192JmlIci+qMOEByHm83XE9E=
|
||||
github.com/micro/go-micro v1.18.0/go.mod h1:klwUJL1gkdY1MHFyz+fFJXn52dKcty4hoe95Mp571AA=
|
||||
github.com/micro/go-micro/v3 v3.0.0-beta.2.0.20200911124113-3bb76868d194/go.mod h1:dx3ZCcO8zr6Za0Ri05Jk0F7APdTgj15wGBHje9+S++c=
|
||||
github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
|
||||
github.com/micro/micro v1.18.0 h1:v+xiQOXbT9xxotLwu1nJM81t4FbruBxZSSyIdhUfujM=
|
||||
github.com/micro/micro/v3 v3.0.0-beta.4 h1:oorPsSChZ3q4L3MQfaDHqAZM1Yl8o793ghBIRFHxluU=
|
||||
github.com/micro/micro/v3 v3.0.0-beta.4/go.mod h1:M/RuBVrEGoLE+jykBVNLecIFFj6CPa9rxJPexDwEmOg=
|
||||
github.com/micro/protoc-gen-micro v1.0.0/go.mod h1:C8ij4DJhapBmypcT00AXdb0cZ675/3PqUO02buWWqbE=
|
||||
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
|
||||
@@ -261,6 +358,7 @@ github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
@@ -272,17 +370,31 @@ github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8d
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/nats-server/v2 v2.1.0/go.mod h1:r5y0WgCag0dTj/qiHkHrXAcKQ/f5GMOZaEGdoxxnJ4I=
|
||||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
||||
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.3/go.mod h1:YZeBtGzYYEsCHp2LST/u/0NDwGkRoBtmn1cIWCJiS6M=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -293,6 +405,7 @@ github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJ
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||
@@ -300,6 +413,7 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -325,13 +439,20 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.2 h1:G+mNzkc1wEtpmM6sFS/Ghkeq+ad4Yp6EZEHyp//wGEo=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.2/go.mod h1:khesvSyKcXDUxeySCedFh621iawCks0dS/QnHPcpCws=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 h1:ofR1ZdrNSkiWcMsRrubK9tb2/SlZVWttAfqUjJi6QYc=
|
||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
@@ -342,28 +463,48 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
|
||||
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
|
||||
github.com/xanzy/go-gitlab v0.35.1 h1:jJSgT0NxjCvrSZf7Gvn2NxxV9xAYkTjYrKW8XwWhrfY=
|
||||
github.com/xanzy/go-gitlab v0.35.1/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
@@ -371,16 +512,34 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
|
||||
@@ -398,6 +557,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
@@ -415,6 +575,7 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -425,7 +586,10 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191011234655-491137f69257/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191109021931-daa7c04131f5/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -447,8 +611,11 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -458,13 +625,19 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -494,11 +667,16 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 h1:RIIXAeV6GvDBuADKumTODatUqANFZ+5BPMnzsy4hulY=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -517,6 +695,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -524,6 +703,7 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
@@ -534,6 +714,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
@@ -554,6 +736,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
@@ -565,14 +749,22 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
|
||||
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -584,3 +776,4 @@ honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXe
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
Reference in New Issue
Block a user