WIP
This commit is contained in:
parent
bb446505a8
commit
9d2e3cc0bb
13 changed files with 391 additions and 18 deletions
1
distbuild/disttest/.gitignore
vendored
Normal file
1
distbuild/disttest/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
workdir
|
127
distbuild/disttest/fixture.go
Normal file
127
distbuild/disttest/fixture.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package disttest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/client"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/dist"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/worker"
|
||||
"gitlab.com/slon/shad-go/tools/testtool"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type env struct {
|
||||
RootDir string
|
||||
Logger *zap.Logger
|
||||
|
||||
Ctx context.Context
|
||||
|
||||
Client *client.Client
|
||||
Coordinator *dist.Coordinator
|
||||
Workers []*worker.Worker
|
||||
|
||||
HTTP *http.Server
|
||||
}
|
||||
|
||||
const nWorkers = 4
|
||||
|
||||
func newEnv(t *testing.T) (e *env, cancel func()) {
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
absCWD, err := filepath.Abs(cwd)
|
||||
require.NoError(t, err)
|
||||
|
||||
env := &env{
|
||||
RootDir: filepath.Join(absCWD, "workdir", t.Name()),
|
||||
}
|
||||
|
||||
require.NoError(t, os.RemoveAll(env.RootDir))
|
||||
require.NoError(t, os.MkdirAll(env.RootDir, 0777))
|
||||
|
||||
cfg := zap.NewDevelopmentConfig()
|
||||
cfg.OutputPaths = []string{filepath.Join(env.RootDir, "test.log")}
|
||||
env.Logger, err = cfg.Build()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Helper()
|
||||
t.Logf("test is running inside %s; see test.log file for more info", filepath.Join("workdir", t.Name()))
|
||||
|
||||
port, err := testtool.GetFreePort()
|
||||
require.NoError(t, err)
|
||||
addr := "127.0.0.1:" + port
|
||||
coordinatorEndpoint := "http://" + addr + "/coordinator"
|
||||
|
||||
var cancelRootContext func()
|
||||
env.Ctx, cancelRootContext = context.WithCancel(context.Background())
|
||||
|
||||
env.Client = &client.Client{
|
||||
CoordinatorEndpoint: coordinatorEndpoint,
|
||||
SourceDir: filepath.Join(absCWD, "testdata/src"),
|
||||
Log: env.Logger.Named("client"),
|
||||
}
|
||||
|
||||
coordinatorCache, err := filecache.New(filepath.Join(env.RootDir, "coordinator", "filecache"))
|
||||
require.NoError(t, err)
|
||||
|
||||
env.Coordinator = dist.NewCoordinator(
|
||||
env.Logger.Named("coordinator"),
|
||||
coordinatorCache,
|
||||
)
|
||||
|
||||
for i := 0; i < nWorkers; i++ {
|
||||
workerName := fmt.Sprintf("worker%d", i)
|
||||
workerDir := filepath.Join(env.RootDir, workerName)
|
||||
|
||||
fileCache, err := filecache.New(filepath.Join(workerDir, "filecache"))
|
||||
require.NoError(t, err)
|
||||
|
||||
artifacts, err := artifact.NewCache(filepath.Join(workerDir, "artifacts"))
|
||||
require.NoError(t, err)
|
||||
|
||||
w := worker.New(
|
||||
coordinatorEndpoint,
|
||||
env.Logger.Named(workerName),
|
||||
fileCache,
|
||||
artifacts,
|
||||
)
|
||||
|
||||
env.Workers = append(env.Workers, w)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/coordinator/", http.StripPrefix("/coordinator", env.Coordinator))
|
||||
|
||||
for i, w := range env.Workers {
|
||||
workerPrefix := fmt.Sprintf("/worker/%d", i)
|
||||
mux.Handle(workerPrefix+"/", http.StripPrefix(workerPrefix, w))
|
||||
}
|
||||
|
||||
env.HTTP = &http.Server{
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
lsn, err := net.Listen("tcp", env.HTTP.Addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
go func() {
|
||||
env.Logger.Error("http server stopped", zap.Error(env.HTTP.Serve(lsn)))
|
||||
}()
|
||||
|
||||
return env, func() {
|
||||
cancelRootContext()
|
||||
_ = env.HTTP.Shutdown(context.Background())
|
||||
_ = env.Logger.Sync()
|
||||
}
|
||||
}
|
57
distbuild/disttest/recorder.go
Normal file
57
distbuild/disttest/recorder.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package disttest
|
||||
|
||||
import (
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
)
|
||||
|
||||
type JobResult struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
|
||||
Code *int
|
||||
Error string
|
||||
}
|
||||
|
||||
type Recorder struct {
|
||||
Jobs map[build.ID]*JobResult
|
||||
}
|
||||
|
||||
func NewRecorder() *Recorder {
|
||||
return &Recorder{
|
||||
Jobs: map[build.ID]*JobResult{},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Recorder) job(jobID build.ID) *JobResult {
|
||||
j, ok := r.Jobs[jobID]
|
||||
if !ok {
|
||||
j = &JobResult{}
|
||||
r.Jobs[jobID] = j
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func (r *Recorder) OnJobStdout(jobID build.ID, stdout []byte) error {
|
||||
j := r.job(jobID)
|
||||
j.Stdout += string(stdout)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Recorder) OnJobStderr(jobID build.ID, stderr []byte) error {
|
||||
j := r.job(jobID)
|
||||
j.Stderr += string(stderr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Recorder) OnJobFinished(jobID build.ID) error {
|
||||
j := r.job(jobID)
|
||||
j.Code = new(int)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Recorder) OnJobFailed(jobID build.ID, code int, error string) error {
|
||||
j := r.job(jobID)
|
||||
j.Code = &code
|
||||
j.Error = error
|
||||
return nil
|
||||
}
|
31
distbuild/disttest/simple_test.go
Normal file
31
distbuild/disttest/simple_test.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package disttest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
)
|
||||
|
||||
var echoGraph = build.Graph{
|
||||
Jobs: []build.Job{
|
||||
{
|
||||
ID: build.ID{'a'},
|
||||
Name: "echo",
|
||||
Cmds: []build.Cmd{
|
||||
{Exec: []string{"echo", "-n", "OK"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestSingleCommand(t *testing.T) {
|
||||
env, cancel := newEnv(t)
|
||||
defer cancel()
|
||||
|
||||
var recorder Recorder
|
||||
require.NoError(t, env.Client.Build(env.Ctx, echoGraph, &recorder))
|
||||
|
||||
require.Equal(t, &JobResult{Stdout: "OK", Code: new(int)}, recorder.Jobs[build.ID{'a'}])
|
||||
}
|
|
@ -16,7 +16,7 @@ var (
|
|||
type Cache struct{}
|
||||
|
||||
func NewCache(root string) (*Cache, error) {
|
||||
panic("implement me")
|
||||
return &Cache{}, nil
|
||||
}
|
||||
|
||||
func (c *Cache) Range(artifactFn func(file build.ID) error) error {
|
||||
|
|
|
@ -1,9 +1,37 @@
|
|||
package build
|
||||
|
||||
import "crypto/sha1"
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ID [sha1.Size]byte
|
||||
|
||||
var (
|
||||
_ = encoding.TextMarshaler(ID{})
|
||||
_ = encoding.TextUnmarshaler(&ID{})
|
||||
)
|
||||
|
||||
func (id ID) MarshalText() ([]byte, error) {
|
||||
return []byte(hex.EncodeToString(id[:])), nil
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalText(b []byte) error {
|
||||
raw, err := hex.DecodeString(string(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(raw) != len(id) {
|
||||
return fmt.Errorf("invalid id size: %q", b)
|
||||
}
|
||||
|
||||
copy(id[:], raw)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Job описывает одну вершину графа сборки.
|
||||
type Job struct {
|
||||
// ID задаёт уникальный идентификатор джоба.
|
||||
|
|
|
@ -8,26 +8,28 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/proto"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
CoordinatorEndpoint string
|
||||
|
||||
SourceDir string
|
||||
SourceDir string
|
||||
Log *zap.Logger
|
||||
}
|
||||
|
||||
type BuildListener interface {
|
||||
OnJobStdout(jobID build.ID, stdout []byte) error
|
||||
OnJobStderr(jobID build.ID, stdout []byte) error
|
||||
OnJobStderr(jobID build.ID, stderr []byte) error
|
||||
|
||||
OnJobFinished(jobID build.ID) error
|
||||
OnJobFailed(jobID build.ID, code int, error string) error
|
||||
}
|
||||
|
||||
func (c *Client) uploadSources(ctx context.Context, src proto.MissingSources) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Build(ctx context.Context, graph build.Graph, lsn BuildListener) error {
|
||||
|
@ -43,6 +45,8 @@ func (c *Client) Build(ctx context.Context, graph build.Graph, lsn BuildListener
|
|||
req.Header.Add("Content-Type", "application/json")
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
c.Log.Debug("sending build request", zap.String("url", req.URL.String()))
|
||||
|
||||
rsp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build failed: %w", err)
|
||||
|
@ -58,7 +62,7 @@ func (c *Client) Build(ctx context.Context, graph build.Graph, lsn BuildListener
|
|||
|
||||
var missing proto.MissingSources
|
||||
if err := d.Decode(&missing); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error receiving source list: %w", err)
|
||||
}
|
||||
|
||||
if err := c.uploadSources(ctx, missing); err != nil {
|
||||
|
@ -68,7 +72,7 @@ func (c *Client) Build(ctx context.Context, graph build.Graph, lsn BuildListener
|
|||
for {
|
||||
var update proto.StatusUpdate
|
||||
if err := d.Decode(&update); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error receiving status update: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
|
4
distbuild/pkg/dist/build.go
vendored
4
distbuild/pkg/dist/build.go
vendored
|
@ -1,4 +0,0 @@
|
|||
package dist
|
||||
|
||||
type Build struct {
|
||||
}
|
71
distbuild/pkg/dist/coordinator.go
vendored
Normal file
71
distbuild/pkg/dist/coordinator.go
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
package dist
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/proto"
|
||||
)
|
||||
|
||||
type Build struct {
|
||||
}
|
||||
|
||||
type Coordinator struct {
|
||||
log *zap.Logger
|
||||
mux *http.ServeMux
|
||||
fileCache *filecache.Cache
|
||||
}
|
||||
|
||||
func NewCoordinator(
|
||||
log *zap.Logger,
|
||||
fileCache *filecache.Cache,
|
||||
) *Coordinator {
|
||||
c := &Coordinator{
|
||||
log: log,
|
||||
mux: http.NewServeMux(),
|
||||
fileCache: fileCache,
|
||||
}
|
||||
|
||||
c.mux.HandleFunc("/build", c.Build)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Coordinator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
c.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (c *Coordinator) doBuild(w http.ResponseWriter, r *http.Request) error {
|
||||
graphJS, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var g build.Graph
|
||||
if err := json.Unmarshal(graphJS, &g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
enc := json.NewEncoder(w)
|
||||
if err := enc.Encode(proto.MissingSources{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("coordinator not implemented")
|
||||
}
|
||||
|
||||
func (c *Coordinator) Build(w http.ResponseWriter, r *http.Request) {
|
||||
if err := c.doBuild(w, r); err != nil {
|
||||
c.log.Error("build failed", zap.Error(err))
|
||||
|
||||
errorUpdate := proto.StatusUpdate{BuildFailed: &proto.BuildFailed{Error: err.Error()}}
|
||||
errorJS, _ := json.Marshal(errorUpdate)
|
||||
_, _ = w.Write(errorJS)
|
||||
}
|
||||
}
|
|
@ -2,8 +2,10 @@ package filecache
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
)
|
||||
|
@ -15,10 +17,16 @@ var (
|
|||
)
|
||||
|
||||
type Cache struct {
|
||||
rootDir string
|
||||
}
|
||||
|
||||
func New(rootDir string) (*Cache, error) {
|
||||
panic("implement me")
|
||||
if err := os.MkdirAll(rootDir, 0777); err != nil {
|
||||
return nil, fmt.Errorf("error creating filecache: %w", err)
|
||||
}
|
||||
|
||||
c := &Cache{rootDir: rootDir}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Cache) Range(fileFn func(file build.ID) error) error {
|
||||
|
|
|
@ -2,26 +2,53 @@ package worker
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/build"
|
||||
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
|
||||
)
|
||||
|
||||
type Worker struct {
|
||||
CoordinatorEndpoint string
|
||||
coordinatorEndpoint string
|
||||
|
||||
SourceFiles *filecache.Cache
|
||||
Artifacts *artifact.Cache
|
||||
log *zap.Logger
|
||||
|
||||
fileCache *filecache.Cache
|
||||
artifacts *artifact.Cache
|
||||
|
||||
mux *http.ServeMux
|
||||
|
||||
mu sync.Mutex
|
||||
newArtifacts []build.ID
|
||||
newSources []build.ID
|
||||
}
|
||||
|
||||
func New(
|
||||
coordinatorEndpoint string,
|
||||
log *zap.Logger,
|
||||
fileCache *filecache.Cache,
|
||||
artifacts *artifact.Cache,
|
||||
) *Worker {
|
||||
return &Worker{
|
||||
coordinatorEndpoint: coordinatorEndpoint,
|
||||
log: log,
|
||||
fileCache: fileCache,
|
||||
artifacts: artifacts,
|
||||
|
||||
mux: http.NewServeMux(),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Worker) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
w.mux.ServeHTTP(rw, r)
|
||||
}
|
||||
|
||||
func (w *Worker) recover() error {
|
||||
err := w.SourceFiles.Range(func(file build.ID) error {
|
||||
err := w.fileCache.Range(func(file build.ID) error {
|
||||
w.newSources = append(w.newSources, file)
|
||||
return nil
|
||||
})
|
||||
|
@ -29,7 +56,7 @@ func (w *Worker) recover() error {
|
|||
return err
|
||||
}
|
||||
|
||||
return w.Artifacts.Range(func(file build.ID) error {
|
||||
return w.artifacts.Range(func(file build.ID) error {
|
||||
w.newArtifacts = append(w.newArtifacts, file)
|
||||
return nil
|
||||
})
|
||||
|
|
1
go.mod
1
go.mod
|
@ -11,6 +11,7 @@ require (
|
|||
github.com/spf13/cobra v0.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
go.uber.org/goleak v1.0.0
|
||||
go.uber.org/zap v1.14.0
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7
|
||||
golang.org/x/perf v0.0.0-20191209155426-36b577b0eb03
|
||||
golang.org/x/tools v0.0.0-20200125223703-d33eef8e6825
|
||||
|
|
22
go.sum
22
go.sum
|
@ -1,4 +1,5 @@
|
|||
cloud.google.com/go v0.0.0-20170206221025-ce650573d812/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
|
||||
github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes=
|
||||
|
@ -25,6 +26,7 @@ github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+
|
|||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks=
|
||||
github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A=
|
||||
github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
|
@ -33,6 +35,7 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
@ -43,8 +46,10 @@ github.com/mattn/go-sqlite3 v0.0.0-20161215041557-2d44decb4941/go.mod h1:FPy6Kqz
|
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
|
@ -57,17 +62,28 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
|||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
|
||||
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.14.0 h1:/pduUoebOeeJzTDFuoMgC6nRkiasr1sBCIEorly7m4o=
|
||||
go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -89,6 +105,9 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq
|
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200125223703-d33eef8e6825 h1:aNQeSIHKi0RWpKA5NO0CqyLjx6Beh5l0LLUEnndEjz0=
|
||||
golang.org/x/tools v0.0.0-20200125223703-d33eef8e6825/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
|
@ -102,9 +121,12 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
Loading…
Reference in a new issue