forked from TrueCloudLab/frostfs-s3-gw
[#25] Refactoring and make fixes
closes #25 closes #32 Signed-off-by: Evgeniy Kulikov <kim@nspcc.ru>
This commit is contained in:
parent
fbd4a83602
commit
4d605d1113
11 changed files with 82 additions and 51 deletions
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
)
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
5
go.mod
5
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
|
||||
)
|
||||
|
||||
|
|
20
go.sum
20
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=
|
||||
|
|
Loading…
Reference in a new issue