diff --git a/config/config.go b/config/config.go index a41a7881..08f01908 100644 --- a/config/config.go +++ b/config/config.go @@ -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 + } } diff --git a/config/default.go b/config/default.go deleted file mode 100644 index 41d357d3..00000000 --- a/config/default.go +++ /dev/null @@ -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() -} diff --git a/config/default_test.go b/config/default_test.go deleted file mode 100644 index 46350963..00000000 --- a/config/default_test.go +++ /dev/null @@ -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) - } -} diff --git a/config/encoder/encoder.go b/config/encoder/encoder.go deleted file mode 100644 index 0ef0654a..00000000 --- a/config/encoder/encoder.go +++ /dev/null @@ -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 -} diff --git a/config/encoder/hcl/hcl.go b/config/encoder/hcl/hcl.go deleted file mode 100644 index 72fad9df..00000000 --- a/config/encoder/hcl/hcl.go +++ /dev/null @@ -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{} -} diff --git a/config/encoder/json/json.go b/config/encoder/json/json.go deleted file mode 100644 index 13f179f9..00000000 --- a/config/encoder/json/json.go +++ /dev/null @@ -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{} -} diff --git a/config/encoder/toml/toml.go b/config/encoder/toml/toml.go deleted file mode 100644 index 91109073..00000000 --- a/config/encoder/toml/toml.go +++ /dev/null @@ -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{} -} diff --git a/config/encoder/xml/xml.go b/config/encoder/xml/xml.go deleted file mode 100644 index 8e32a14e..00000000 --- a/config/encoder/xml/xml.go +++ /dev/null @@ -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{} -} diff --git a/config/encoder/yaml/yaml.go b/config/encoder/yaml/yaml.go deleted file mode 100644 index b3da7ba5..00000000 --- a/config/encoder/yaml/yaml.go +++ /dev/null @@ -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{} -} diff --git a/config/loader/loader.go b/config/loader/loader.go deleted file mode 100644 index 1e2dc13a..00000000 --- a/config/loader/loader.go +++ /dev/null @@ -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, - } -} diff --git a/config/loader/memory/memory.go b/config/loader/memory/memory.go deleted file mode 100644 index c8746266..00000000 --- a/config/loader/memory/memory.go +++ /dev/null @@ -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 -} diff --git a/config/loader/memory/options.go b/config/loader/memory/options.go deleted file mode 100644 index 34a8441c..00000000 --- a/config/loader/memory/options.go +++ /dev/null @@ -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 - } -} diff --git a/config/options.go b/config/options.go deleted file mode 100644 index d29f8f86..00000000 --- a/config/options.go +++ /dev/null @@ -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 - } -} diff --git a/config/reader/json/json.go b/config/reader/json/json.go deleted file mode 100644 index f356fe94..00000000 --- a/config/reader/json/json.go +++ /dev/null @@ -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, - } -} diff --git a/config/reader/json/json_test.go b/config/reader/json/json_test.go deleted file mode 100644 index 6c0818ba..00000000 --- a/config/reader/json/json_test.go +++ /dev/null @@ -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 -} diff --git a/config/reader/json/values.go b/config/reader/json/values.go deleted file mode 100644 index 7f0fe13c..00000000 --- a/config/reader/json/values.go +++ /dev/null @@ -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 -} diff --git a/config/reader/json/values_test.go b/config/reader/json/values_test.go deleted file mode 100644 index 2f86b003..00000000 --- a/config/reader/json/values_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/config/reader/options.go b/config/reader/options.go deleted file mode 100644 index 51fecd05..00000000 --- a/config/reader/options.go +++ /dev/null @@ -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 - } -} diff --git a/config/reader/preprocessor.go b/config/reader/preprocessor.go deleted file mode 100644 index 2895be4f..00000000 --- a/config/reader/preprocessor.go +++ /dev/null @@ -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 -} diff --git a/config/reader/preprocessor_test.go b/config/reader/preprocessor_test.go deleted file mode 100644 index ba5485fe..00000000 --- a/config/reader/preprocessor_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/config/reader/reader.go b/config/reader/reader.go deleted file mode 100644 index abc3ad94..00000000 --- a/config/reader/reader.go +++ /dev/null @@ -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 -} diff --git a/config/source/changeset.go b/config/source/changeset.go deleted file mode 100644 index 9958f61d..00000000 --- a/config/source/changeset.go +++ /dev/null @@ -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)) -} diff --git a/config/source/env/README.md b/config/source/env/README.md deleted file mode 100644 index 61a18f8d..00000000 --- a/config/source/env/README.md +++ /dev/null @@ -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) -``` diff --git a/config/source/env/env.go b/config/source/env/env.go deleted file mode 100644 index 1d0ed295..00000000 --- a/config/source/env/env.go +++ /dev/null @@ -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} -} diff --git a/config/source/env/env_test.go b/config/source/env/env_test.go deleted file mode 100644 index 50b1bce7..00000000 --- a/config/source/env/env_test.go +++ /dev/null @@ -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 -} diff --git a/config/source/env/options.go b/config/source/env/options.go deleted file mode 100644 index dd362610..00000000 --- a/config/source/env/options.go +++ /dev/null @@ -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 -} diff --git a/config/source/env/watcher.go b/config/source/env/watcher.go deleted file mode 100644 index f698bb8f..00000000 --- a/config/source/env/watcher.go +++ /dev/null @@ -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 -} diff --git a/config/source/file/README.md b/config/source/file/README.md deleted file mode 100644 index 89c0930c..00000000 --- a/config/source/file/README.md +++ /dev/null @@ -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) -``` - diff --git a/config/source/file/file.go b/config/source/file/file.go deleted file mode 100644 index 6b42fd19..00000000 --- a/config/source/file/file.go +++ /dev/null @@ -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} -} diff --git a/config/source/file/file_test.go b/config/source/file/file_test.go deleted file mode 100644 index fb725496..00000000 --- a/config/source/file/file_test.go +++ /dev/null @@ -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") - } -} diff --git a/config/source/file/format.go b/config/source/file/format.go deleted file mode 100644 index 4bd9dd22..00000000 --- a/config/source/file/format.go +++ /dev/null @@ -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() -} diff --git a/config/source/file/format_test.go b/config/source/file/format_test.go deleted file mode 100644 index dca78cee..00000000 --- a/config/source/file/format_test.go +++ /dev/null @@ -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) - } - } - -} diff --git a/config/source/file/options.go b/config/source/file/options.go deleted file mode 100644 index f9721cb4..00000000 --- a/config/source/file/options.go +++ /dev/null @@ -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) - } -} diff --git a/config/source/file/watcher.go b/config/source/file/watcher.go deleted file mode 100644 index 953050b5..00000000 --- a/config/source/file/watcher.go +++ /dev/null @@ -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() -} diff --git a/config/source/file/watcher_linux.go b/config/source/file/watcher_linux.go deleted file mode 100644 index 4f8be6da..00000000 --- a/config/source/file/watcher_linux.go +++ /dev/null @@ -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() -} diff --git a/config/source/flag/README.md b/config/source/flag/README.md deleted file mode 100644 index 79e5cb54..00000000 --- a/config/source/flag/README.md +++ /dev/null @@ -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) -``` diff --git a/config/source/flag/flag.go b/config/source/flag/flag.go deleted file mode 100644 index 1eef5fc7..00000000 --- a/config/source/flag/flag.go +++ /dev/null @@ -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...)} -} diff --git a/config/source/flag/flag_test.go b/config/source/flag/flag_test.go deleted file mode 100644 index e412c904..00000000 --- a/config/source/flag/flag_test.go +++ /dev/null @@ -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"]) - } -} diff --git a/config/source/flag/options.go b/config/source/flag/options.go deleted file mode 100644 index b770d2dd..00000000 --- a/config/source/flag/options.go +++ /dev/null @@ -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) - } -} diff --git a/config/source/memory/README.md b/config/source/memory/README.md deleted file mode 100644 index adef980b..00000000 --- a/config/source/memory/README.md +++ /dev/null @@ -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) -``` diff --git a/config/source/memory/memory.go b/config/source/memory/memory.go deleted file mode 100644 index a48d0e29..00000000 --- a/config/source/memory/memory.go +++ /dev/null @@ -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 -} diff --git a/config/source/memory/options.go b/config/source/memory/options.go deleted file mode 100644 index 46f98e05..00000000 --- a/config/source/memory/options.go +++ /dev/null @@ -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") -} diff --git a/config/source/memory/watcher.go b/config/source/memory/watcher.go deleted file mode 100644 index c44ff110..00000000 --- a/config/source/memory/watcher.go +++ /dev/null @@ -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 -} diff --git a/config/source/noop.go b/config/source/noop.go deleted file mode 100644 index fc444411..00000000 --- a/config/source/noop.go +++ /dev/null @@ -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 -} diff --git a/config/source/options.go b/config/source/options.go deleted file mode 100644 index 34090b03..00000000 --- a/config/source/options.go +++ /dev/null @@ -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 - } -} diff --git a/config/source/source.go b/config/source/source.go deleted file mode 100644 index 0cf8b9fb..00000000 --- a/config/source/source.go +++ /dev/null @@ -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 -} diff --git a/config/store/store.go b/config/store/store.go new file mode 100644 index 00000000..71eab439 --- /dev/null +++ b/config/store/store.go @@ -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) +} diff --git a/config/value.go b/config/value.go index 3cf1a2e4..dee42c50 100644 --- a/config/value.go +++ b/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 } diff --git a/go.mod b/go.mod index 43548676..5061e30d 100644 --- a/go.mod +++ b/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 ) diff --git a/go.sum b/go.sum index bcb4c592..3b833ba3 100644 --- a/go.sum +++ b/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=