From 4d605d111306e70594fda70fdc40fe169a673668 Mon Sep 17 00:00:00 2001 From: Evgeniy Kulikov Date: Fri, 23 Oct 2020 03:12:37 +0300 Subject: [PATCH] [#25] Refactoring and make fixes closes #25 closes #32 Signed-off-by: Evgeniy Kulikov --- api/handler/list.go | 4 ++++ api/layer/container.go | 14 +++++++++----- api/layer/layer.go | 15 ++++++++------- api/layer/object.go | 27 +++++++++++++++++---------- api/layer/sdk.go | 14 -------------- api/layer/util.go | 9 +++++++-- api/pool/pool.go | 4 ++-- api/pool/session.go | 20 +++++++++++++++----- cmd/gate/app.go | 1 + go.mod | 5 +++-- go.sum | 20 ++++++++++++++++---- 11 files changed, 82 insertions(+), 51 deletions(-) delete mode 100644 api/layer/sdk.go diff --git a/api/handler/list.go b/api/handler/list.go index 2649c974..de0e5ec7 100644 --- a/api/handler/list.go +++ b/api/handler/list.go @@ -75,6 +75,10 @@ func (h *handler) ListBucketsHandler(w http.ResponseWriter, r *http.Request) { return } + if len(list) > 0 { + own = list[0].Owner + } + res = &ListBucketsResponse{ Owner: Owner{ ID: own.String(), diff --git a/api/layer/container.go b/api/layer/container.go index 7d8026c9..3c0041ee 100644 --- a/api/layer/container.go +++ b/api/layer/container.go @@ -7,6 +7,7 @@ import ( "github.com/nspcc-dev/neofs-api-go/pkg/client" "github.com/nspcc-dev/neofs-api-go/pkg/container" + "github.com/nspcc-dev/neofs-api-go/pkg/owner" "github.com/nspcc-dev/neofs-s3-gate/api" "github.com/nspcc-dev/neofs-s3-gate/auth" "go.uber.org/zap" @@ -16,6 +17,7 @@ type ( BucketInfo struct { Name string CID *container.ID + Owner *owner.ID Created time.Time } @@ -69,11 +71,13 @@ func (n *layer) containerInfo(ctx context.Context, cid *container.ID) (*BucketIn return nil, err } + info.Owner = owner.NewIDFromV2(res.GetOwnerID()) + for _, attr := range res.GetAttributes() { switch key, val := attr.GetKey(), attr.GetValue(); key { - case ContainerName: + case container.AttributeName: info.Name = val - case LocallyCreationTime: + case container.AttributeTimestamp: unix, err := strconv.ParseInt(attr.GetValue(), 10, 64) if err != nil { n.log.Error("could not parse container creation time", @@ -92,7 +96,7 @@ func (n *layer) containerInfo(ctx context.Context, cid *container.ID) (*BucketIn return info, nil } -func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) { +func (n *layer) containerList(ctx context.Context) ([]*BucketInfo, error) { rid := api.GetRequestID(ctx) bearer, err := auth.GetBearerToken(ctx) if err != nil { @@ -128,7 +132,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) { return nil, err } - list := make([]BucketInfo, 0, len(res)) + list := make([]*BucketInfo, 0, len(res)) for _, cid := range res { info, err := n.containerInfo(ctx, cid) if err != nil { @@ -138,7 +142,7 @@ func (n *layer) containerList(ctx context.Context) ([]BucketInfo, error) { continue } - list = append(list, *info) + list = append(list, info) } return list, nil diff --git a/api/layer/layer.go b/api/layer/layer.go index 42c4c32b..11c6db6f 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -69,7 +69,7 @@ type ( Client interface { NeoFS - ListBuckets(ctx context.Context) ([]BucketInfo, error) + ListBuckets(ctx context.Context) ([]*BucketInfo, error) GetBucketInfo(ctx context.Context, name string) (*BucketInfo, error) GetObject(ctx context.Context, p *GetObjectParams) error @@ -129,7 +129,7 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*BucketInfo, er for _, bkt := range list { if bkt.Name == name { - return &bkt, nil + return bkt, nil } } @@ -138,7 +138,7 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*BucketInfo, er // ListBuckets returns all user containers. Name of the bucket is a container // id. Timestamp is omitted since it is not saved in neofs container. -func (n *layer) ListBuckets(ctx context.Context) ([]BucketInfo, error) { +func (n *layer) ListBuckets(ctx context.Context) ([]*BucketInfo, error) { return n.containerList(ctx) } @@ -240,18 +240,18 @@ func (n *layer) GetObject(ctx context.Context, p *GetObjectParams) error { var ( err error oid *object.ID - cid = container.NewID() + bkt *BucketInfo ) - if err = cid.Parse(p.Bucket); err != nil { + if bkt, err = n.GetBucketInfo(ctx, p.Bucket); err != nil { return err - } else if oid, err = n.objectFindID(ctx, &findParams{cid: cid, val: p.Object}); err != nil { + } else if oid, err = n.objectFindID(ctx, &findParams{cid: bkt.CID, val: p.Object}); err != nil { return err } addr := object.NewAddress() addr.SetObjectID(oid) - addr.SetContainerID(cid) + addr.SetContainerID(bkt.CID) _, err = n.objectGet(ctx, &getParams{ Writer: p.Writer, @@ -293,6 +293,7 @@ func (n *layer) GetObjectInfo(ctx context.Context, bucketName, filename string) } func GetOwnerID(tkn *token.BearerToken) (*owner.ID, error) { + switch pkg.SDKVersion().GetMajor() { case 2: id := tkn.ToV2().GetBody().GetOwnerID() diff --git a/api/layer/object.go b/api/layer/object.go index a2c70ad1..453594da 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -5,6 +5,7 @@ import ( "context" "io" "net/http" + "strconv" "time" "github.com/nspcc-dev/neofs-api-go/pkg/client" @@ -62,13 +63,13 @@ func (n *layer) objectSearch(ctx context.Context, p *findParams) ([]*object.ID, } filter := object.NewSearchFilters() - filter.AddNonLeafFilter() + filter.AddRootFilter() sop := new(client.SearchObjectParams) sop.WithContainerID(p.cid) if p.val != "" { - filter.AddFilter(ObjectName, p.val, object.MatchStringEqual) + filter.AddFilter(object.AttributeFileName, p.val, object.MatchStringEqual) } sop.WithSearchFilters(filter) @@ -100,7 +101,6 @@ func (n *layer) objectHead(ctx context.Context, addr *object.Address) (*object.O ohp := new(client.ObjectHeaderParams) ohp.WithAddress(addr) ohp.WithAllFields() - ohp.WithMainFields() return cli.GetObjectHeader(ctx, ohp, client.WithSession(tkn)) } @@ -116,6 +116,7 @@ func (n *layer) objectGet(ctx context.Context, p *getParams) (*object.Object, er writer := newWriter(p.Writer, p.offset, p.length) gop := new(client.GetObjectParams) + gop.WithAddress(p.addr) gop.WithPayloadWriter(writer) return cli.GetObject(ctx, gop, client.WithSession(tkn)) @@ -126,8 +127,8 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, var ( err error own *owner.ID + bkt *BucketInfo brt *token.BearerToken - cid = container.NewID() ) if brt, err = auth.GetBearerToken(ctx); err != nil { @@ -138,7 +139,7 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, _ = own - if bkt, err := n.GetBucketInfo(ctx, p.Bucket); err != nil { + if bkt, err = n.GetBucketInfo(ctx, p.Bucket); err != nil { return nil, err } else if _, err = n.objectFindID(ctx, &findParams{cid: bkt.CID, val: p.Object}); err == nil { return nil, &api.ObjectAlreadyExists{ @@ -154,11 +155,17 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, attributes := make([]*object.Attribute, 0, len(p.Header)+1) + unix := strconv.FormatInt(time.Now().UTC().Unix(), 64) + filename := object.NewAttribute() - filename.SetKey(ObjectName) + filename.SetKey(object.AttributeFileName) filename.SetValue(p.Object) - attributes = append(attributes, filename) + createdAt := object.NewAttribute() + createdAt.SetKey(object.AttributeTimestamp) + createdAt.SetValue(unix) + + attributes = append(attributes, filename, createdAt) for k, v := range p.Header { ua := object.NewAttribute() @@ -172,8 +179,8 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, r := io.TeeReader(p.Reader, b) raw := object.NewRaw() - raw.SetOwnerID(tkn.OwnerID()) // should be replaced with BearerToken.GetOwnerID() - raw.SetContainerID(cid) + raw.SetOwnerID(tkn.OwnerID()) // should be replaced with BearerToken.Issuer() + raw.SetContainerID(bkt.CID) raw.SetAttributes(attributes...) pop := new(client.PutObjectParams) @@ -181,7 +188,7 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, pop.WithObject(raw.Object()) if _, err = cli.PutObject(ctx, pop, client.WithSession(tkn)); err != nil { - return nil, err + return nil, errors.Wrapf(err, "owner_id = %s", tkn.OwnerID()) } return &ObjectInfo{ diff --git a/api/layer/sdk.go b/api/layer/sdk.go deleted file mode 100644 index 784e368a..00000000 --- a/api/layer/sdk.go +++ /dev/null @@ -1,14 +0,0 @@ -package layer - -const ( - // TODO should be replaced with well-known types from SDK - - // ObjectName human readable name of the root object. - ObjectName = "filename" - - // ContainerName human readable name of the container (`bucket`). - ContainerName = "dirname" - - // LocallyCreationTime human readable creation time of the object / container. - LocallyCreationTime = "created_at" -) diff --git a/api/layer/util.go b/api/layer/util.go index d0de56ce..d03c09f7 100644 --- a/api/layer/util.go +++ b/api/layer/util.go @@ -1,6 +1,7 @@ package layer import ( + "fmt" "net/http" "os" "strings" @@ -62,7 +63,7 @@ func objectInfoFromMeta(meta *object.Object) *ObjectInfo { aws3name := meta.GetID().String() userHeaders := userHeaders(meta.GetAttributes()) - if name, ok := userHeaders[ObjectName]; ok { + if name, ok := userHeaders[object.AttributeFileName]; ok { aws3name = name delete(userHeaders, name) } @@ -82,8 +83,12 @@ func objectInfoFromMeta(meta *object.Object) *ObjectInfo { func nameFromObject(o *object.Object) (string, string) { var name = o.GetID().String() + fmt.Printf("OID: %s\n", name) + fmt.Println("Attributes:") for _, attr := range o.GetAttributes() { - if attr.GetKey() == ObjectName { + fmt.Printf("\t%s = %s\n", attr.GetKey(), attr.GetValue()) + + if attr.GetKey() == object.AttributeFileName { name = attr.GetValue() break diff --git a/api/pool/pool.go b/api/pool/pool.go index dbaa1262..e5132da5 100644 --- a/api/pool/pool.go +++ b/api/pool/pool.go @@ -238,7 +238,7 @@ func (p *pool) ReBalance(ctx context.Context) { { // try to prepare token ctx, cancel := context.WithTimeout(ctx, p.reqTimeout) - tkn, err = prepareToken(ctx, conn, p.key) + tkn, err = p.prepareToken(ctx, conn) cancel() } @@ -256,7 +256,7 @@ func (p *pool) ReBalance(ctx context.Context) { p.log.Debug("connected to node", zap.String("address", p.nodes[i].address)) } else if tkn, exists = p.tokens[conn.Target()]; exists { // token exists, ignore - } else if tkn, err = prepareToken(ctx, conn, p.key); err != nil { + } else if tkn, err = p.prepareToken(ctx, conn); err != nil { p.log.Error("could not prepare session token", zap.String("address", p.nodes[i].address), zap.Error(err)) diff --git a/api/pool/session.go b/api/pool/session.go index ba6594ef..20333a4a 100644 --- a/api/pool/session.go +++ b/api/pool/session.go @@ -2,9 +2,10 @@ package pool import ( "context" - "crypto/ecdsa" "math" + "go.uber.org/zap" + "github.com/nspcc-dev/neofs-api-go/pkg/client" "github.com/nspcc-dev/neofs-api-go/pkg/token" "google.golang.org/grpc" @@ -20,7 +21,7 @@ func (p *pool) Token(ctx context.Context, conn *grpc.ClientConn) (*token.Session } // prepare session token - tkn, err := prepareToken(ctx, conn, p.key) + tkn, err := p.prepareToken(ctx, conn) if err != nil { return nil, err } @@ -32,11 +33,20 @@ func (p *pool) Token(ctx context.Context, conn *grpc.ClientConn) (*token.Session } // creates token using -func prepareToken(ctx context.Context, con *grpc.ClientConn, key *ecdsa.PrivateKey) (*token.SessionToken, error) { - cli, err := client.New(key, client.WithGRPCConnection(con)) +func (p *pool) prepareToken(ctx context.Context, conn *grpc.ClientConn) (*token.SessionToken, error) { + cli, err := client.New(p.key, client.WithGRPCConnection(conn)) if err != nil { return nil, err } - return cli.CreateSession(ctx, math.MaxUint64) + tkn, err := cli.CreateSession(ctx, math.MaxUint64) + if err != nil { + return nil, err + } + + p.log.Info("token created for connection", + zap.String("address", conn.Target()), + zap.Stringer("owner", tkn.OwnerID())) + + return tkn, err } diff --git a/cmd/gate/app.go b/cmd/gate/app.go index de24a7c3..27d31cc5 100644 --- a/cmd/gate/app.go +++ b/cmd/gate/app.go @@ -235,6 +235,7 @@ func (a *App) Server(ctx context.Context) { // Use mux.Router as http.Handler srv.Handler = router + srv.ErrorLog = zap.NewStdLog(a.log) go func() { a.log.Info("starting server", diff --git a/go.mod b/go.mod index c441df37..77e1c522 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/google/uuid v1.1.2 github.com/gorilla/mux v1.7.4 github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/nspcc-dev/neofs-api-go v1.3.1-0.20201020152448-c8f46f7d9762 github.com/nspcc-dev/neofs-authmate v0.0.0 github.com/nspcc-dev/neofs-crypto v0.3.0 @@ -24,13 +25,13 @@ require ( go.uber.org/atomic v1.6.0 go.uber.org/zap v1.16.0 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect - golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/sys v0.0.0-20200806125547-5acd03effb82 // indirect golang.org/x/text v0.3.3 // indirect - golang.org/x/tools v0.0.0-20200123022218-593de606220b // indirect + golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 // indirect google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 // indirect google.golang.org/grpc v1.33.0 google.golang.org/protobuf v1.25.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/ini.v1 v1.57.0 // indirect ) diff --git a/go.sum b/go.sum index a9db83cc..6843cf4d 100644 --- a/go.sum +++ b/go.sum @@ -334,6 +334,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +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/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY= github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= @@ -438,6 +440,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I 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.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -497,6 +500,7 @@ github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= @@ -562,6 +566,8 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -581,8 +587,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -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/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -593,6 +599,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -663,15 +670,18 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/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-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200123022218-593de606220b h1:ztSlcncMErSAUzXwnVO1iTPxHwtvOHBB26SGiyYXIEE= -golang.org/x/tools v0.0.0-20200123022218-593de606220b/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 h1:hzJjkvxUIF3bSt+v8N5tBQNx/605vszZJ+3XsIamzZo= +golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= 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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -732,6 +742,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=