cmd/uplinkng: initial commit with skeleton
Change-Id: I764618cc60c46882955e9b08b72b3c162aa4929f
This commit is contained in:
parent
10372afbe4
commit
a1bf9ab6de
68
cmd/uplinkng/access_permissions.go
Normal file
68
cmd/uplinkng/access_permissions.go
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
// accessPermissions holds flags and provides a Setup method for commands that
|
||||
// have to modify permissions on access grants.
|
||||
type accessPermissions struct {
|
||||
paths []string // paths is the set of path prefixes that the grant will be limited to
|
||||
|
||||
readonly bool // implies disallowWrites and disallowDeletes
|
||||
writeonly bool // implies disallowReads and disallowLists
|
||||
|
||||
disallowDeletes bool
|
||||
disallowLists bool
|
||||
disallowReads bool
|
||||
disallowWrites bool
|
||||
|
||||
notBefore time.Time
|
||||
notAfter time.Time
|
||||
}
|
||||
|
||||
func (ap *accessPermissions) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
ap.paths = f.New("path", "Path prefix access will be restricted to", []string{},
|
||||
clingy.Repeated).([]string)
|
||||
|
||||
ap.readonly = f.New("readonly", "Implies --disallow-writes and --disallow-deletes", true,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
ap.writeonly = f.New("writeonly", "Implies --disallow-reads and --disallow-lists", false,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
|
||||
ap.disallowDeletes = f.New("disallow-deletes", "Disallow deletes with the access", false,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
ap.disallowLists = f.New("disallow-lists", "Disallow lists with the access", false,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
ap.disallowReads = f.New("disallow-reads", "Disallow reasd with the access", false,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
ap.disallowWrites = f.New("disallow-writes", "Disallow writes with the access", false,
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
|
||||
ap.notBefore = f.New("not-before",
|
||||
"Disallow access before this time (e.g. '+2h', '2020-01-02T15:04:05Z0700')",
|
||||
time.Time{}, clingy.Transform(parseRelativeTime), clingy.Type("relative_time")).(time.Time)
|
||||
ap.notAfter = f.New("not-after",
|
||||
"Disallow access after this time (e.g. '+2h', '2020-01-02T15:04:05Z0700')",
|
||||
time.Time{}, clingy.Transform(parseRelativeTime), clingy.Type("relative_time")).(time.Time)
|
||||
}
|
||||
|
||||
func parseRelativeTime(v string) (time.Time, error) {
|
||||
if len(v) == 0 {
|
||||
return time.Time{}, nil
|
||||
} else if v[0] == '+' || v[0] == '-' {
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Now().Add(d), nil
|
||||
} else {
|
||||
return time.Parse(time.RFC3339, v)
|
||||
}
|
||||
}
|
32
cmd/uplinkng/cmd_access_create.go
Normal file
32
cmd/uplinkng/cmd_access_create.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdAccessCreate struct {
|
||||
accessPermissions
|
||||
|
||||
token string
|
||||
passphrase string
|
||||
name string
|
||||
save bool
|
||||
}
|
||||
|
||||
func (c *cmdAccessCreate) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.token = f.New("token", "Setup token from satellite UI (prompted if unspecified)", "").(string)
|
||||
c.passphrase = f.New("passphrase", "Passphrase used for encryption (prompted if unspecified)", "").(string)
|
||||
c.name = f.New("name", "Name to save newly created access, if --save is true", "default").(string)
|
||||
c.save = f.New("save", "Save the access", true, clingy.Transform(strconv.ParseBool)).(bool)
|
||||
|
||||
c.accessPermissions.Setup(a, f)
|
||||
}
|
||||
|
||||
func (c *cmdAccessCreate) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
32
cmd/uplinkng/cmd_access_delete.go
Normal file
32
cmd/uplinkng/cmd_access_delete.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
type cmdAccessDelete struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *cmdAccessDelete) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.name = a.New("name", "Access to delete").(string)
|
||||
}
|
||||
|
||||
func (c *cmdAccessDelete) Execute(ctx clingy.Context) error {
|
||||
accessDefault, accesses, err := gf.GetAccessInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.name == accessDefault {
|
||||
return errs.New("cannot delete current access")
|
||||
}
|
||||
if _, ok := accesses[c.name]; !ok {
|
||||
return errs.New("unknown access: %q", c.name)
|
||||
}
|
||||
delete(accesses, c.name)
|
||||
return gf.SaveAccessInfo(accessDefault, accesses)
|
||||
}
|
73
cmd/uplinkng/cmd_access_list.go
Normal file
73
cmd/uplinkng/cmd_access_list.go
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
|
||||
"storj.io/uplink"
|
||||
)
|
||||
|
||||
type cmdAccessList struct {
|
||||
verbose bool
|
||||
}
|
||||
|
||||
func (c *cmdAccessList) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.verbose = f.New("verbose", "Verbose output of accesses", false,
|
||||
clingy.Short('v'),
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
}
|
||||
|
||||
func (c *cmdAccessList) Execute(ctx clingy.Context) error {
|
||||
accessDefault, accesses, err := gf.GetAccessInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tw := tabwriter.NewWriter(ctx.Stdout(), 4, 4, 4, ' ', 0)
|
||||
defer func() { _ = tw.Flush() }()
|
||||
|
||||
if c.verbose {
|
||||
fmt.Fprintln(tw, "CURRENT\tNAME\tSATELLITE\tVALUE")
|
||||
} else {
|
||||
fmt.Fprintln(tw, "CURRENT\tNAME\tSATELLITE")
|
||||
}
|
||||
|
||||
var names []string
|
||||
for name := range accesses {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for _, name := range names {
|
||||
access, err := uplink.ParseAccess(accesses[name])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
address := access.SatelliteAddress()
|
||||
if idx := strings.IndexByte(address, '@'); !c.verbose && idx >= 0 {
|
||||
address = address[idx+1:]
|
||||
}
|
||||
|
||||
inUse := ' '
|
||||
if name == accessDefault {
|
||||
inUse = '*'
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
fmt.Fprintf(tw, "%c\t%s\t%s\t%s\n", inUse, name, address, accesses[name])
|
||||
} else {
|
||||
fmt.Fprintf(tw, "%c\t%s\t%s\n", inUse, name, address)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
16
cmd/uplinkng/cmd_access_revoke.go
Normal file
16
cmd/uplinkng/cmd_access_revoke.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/zeebo/clingy"
|
||||
|
||||
type cmdAccessRevoke struct {
|
||||
}
|
||||
|
||||
func (c *cmdAccessRevoke) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
}
|
||||
|
||||
func (c *cmdAccessRevoke) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
61
cmd/uplinkng/cmd_access_save.go
Normal file
61
cmd/uplinkng/cmd_access_save.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
|
||||
"storj.io/uplink"
|
||||
)
|
||||
|
||||
type cmdAccessSave struct {
|
||||
access string
|
||||
name string
|
||||
force bool
|
||||
use bool
|
||||
}
|
||||
|
||||
func (c *cmdAccessSave) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.access = f.New("access", "Access to save (prompted if unspecified)", "").(string)
|
||||
c.name = f.New("name", "Name to save the access grant under", "default").(string)
|
||||
|
||||
c.force = f.New("force", "Force overwrite an existing saved access grant", false,
|
||||
clingy.Short('f'),
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
c.use = f.New("use", "Set the saved access to be the one used by default", false,
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
}
|
||||
|
||||
func (c *cmdAccessSave) Execute(ctx clingy.Context) error {
|
||||
// TODO(jeff): need to distinguish errors from reading the file from
|
||||
// errors due to the file not existing. otherwise, there's no way
|
||||
// to save the first access.
|
||||
|
||||
accessDefault, accesses, err := gf.GetAccessInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.access == "" {
|
||||
return errs.New("TODO: implement prompting for the access")
|
||||
}
|
||||
if _, err := uplink.ParseAccess(c.access); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := accesses[c.name]; ok && !c.force {
|
||||
return errs.New("Access %q already exists. Overwrite by specifying --force", c.name)
|
||||
}
|
||||
|
||||
accesses[c.name] = c.access
|
||||
if c.use {
|
||||
accessDefault = c.name
|
||||
}
|
||||
|
||||
return gf.SaveAccessInfo(accessDefault, accesses)
|
||||
}
|
28
cmd/uplinkng/cmd_access_use.go
Normal file
28
cmd/uplinkng/cmd_access_use.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
type cmdAccessUse struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *cmdAccessUse) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.name = a.New("name", "Access to use").(string)
|
||||
}
|
||||
|
||||
func (c *cmdAccessUse) Execute(ctx clingy.Context) error {
|
||||
_, accesses, err := gf.GetAccessInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := accesses[c.name]; !ok {
|
||||
return errs.New("unknown access: %q", c.name)
|
||||
}
|
||||
return gf.SaveAccessInfo(c.name, accesses)
|
||||
}
|
34
cmd/uplinkng/cmd_cp.go
Normal file
34
cmd/uplinkng/cmd_cp.go
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdCp struct {
|
||||
projectProvider
|
||||
|
||||
recursive bool
|
||||
source string
|
||||
dest string
|
||||
}
|
||||
|
||||
func (c *cmdCp) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.recursive = f.New("recursive", "Peform a recursive copy", false,
|
||||
clingy.Short('r'),
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
|
||||
c.source = a.New("source", "Source to copy").(string)
|
||||
c.dest = a.New("dest", "Desination to copy").(string)
|
||||
}
|
||||
|
||||
func (c *cmdCp) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
61
cmd/uplinkng/cmd_ls.go
Normal file
61
cmd/uplinkng/cmd_ls.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
type cmdLs struct {
|
||||
projectProvider
|
||||
|
||||
recursive bool
|
||||
encrypted bool
|
||||
|
||||
path *string
|
||||
}
|
||||
|
||||
func (c *cmdLs) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.recursive = f.New("recursive", "List recursively", false,
|
||||
clingy.Short('r'),
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
c.encrypted = f.New("encrypted", "Shows paths as base64-encoded encrypted paths", false,
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
|
||||
c.path = a.New("path", "Path to list (sj://BUCKET[/KEY])", clingy.Optional).(*string)
|
||||
}
|
||||
|
||||
func (c *cmdLs) Execute(ctx clingy.Context) error {
|
||||
if c.path == nil {
|
||||
return c.listBuckets(ctx)
|
||||
}
|
||||
return c.listPath(ctx, *c.path)
|
||||
}
|
||||
|
||||
func (c *cmdLs) listBuckets(ctx clingy.Context) error {
|
||||
project, err := c.OpenProject(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = project.Close() }()
|
||||
|
||||
iter := project.ListBuckets(ctx, nil)
|
||||
for iter.Next() {
|
||||
item := iter.Item()
|
||||
fmt.Fprintln(ctx, "BKT", item.Created.Local().Format("2006-01-02 15:04:05"), item.Name)
|
||||
}
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
func (c *cmdLs) listPath(ctx clingy.Context, path string) error {
|
||||
return errs.New("TODO")
|
||||
}
|
24
cmd/uplinkng/cmd_mb.go
Normal file
24
cmd/uplinkng/cmd_mb.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdMb struct {
|
||||
projectProvider
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *cmdMb) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.name = a.New("name", "Bucket name (sj://BUCKET)").(string)
|
||||
}
|
||||
|
||||
func (c *cmdMb) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
26
cmd/uplinkng/cmd_meta_get.go
Normal file
26
cmd/uplinkng/cmd_meta_get.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdMetaGet struct {
|
||||
projectProvider
|
||||
|
||||
path string
|
||||
entry *string
|
||||
}
|
||||
|
||||
func (c *cmdMetaGet) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.path = a.New("path", "Path to object (sj://BUCKET/KEY)").(string)
|
||||
c.entry = a.New("entry", "Metadata entry to get", clingy.Optional).(*string)
|
||||
}
|
||||
|
||||
func (c *cmdMetaGet) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
32
cmd/uplinkng/cmd_rb.go
Normal file
32
cmd/uplinkng/cmd_rb.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdRb struct {
|
||||
projectProvider
|
||||
|
||||
force bool
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *cmdRb) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.force = f.New("force", "Deletes any objects in bucket first", false,
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
|
||||
c.name = a.New("name", "Bucket name (sj://BUCKET)").(string)
|
||||
}
|
||||
|
||||
func (c *cmdRb) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
37
cmd/uplinkng/cmd_rm.go
Normal file
37
cmd/uplinkng/cmd_rm.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type cmdRm struct {
|
||||
projectProvider
|
||||
|
||||
recursive bool
|
||||
encrypted bool
|
||||
|
||||
path string
|
||||
}
|
||||
|
||||
func (c *cmdRm) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
|
||||
c.recursive = f.New("recursive", "List recursively", false,
|
||||
clingy.Short('r'),
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
c.encrypted = f.New("encrypted", "Shows paths as base64-encoded encrypted paths", false,
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
).(bool)
|
||||
|
||||
c.path = a.New("path", "Path to remove (sj://BUCKET[/KEY])").(string)
|
||||
}
|
||||
|
||||
func (c *cmdRm) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
18
cmd/uplinkng/cmd_share.go
Normal file
18
cmd/uplinkng/cmd_share.go
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/zeebo/clingy"
|
||||
|
||||
type cmdShare struct {
|
||||
projectProvider
|
||||
}
|
||||
|
||||
func (c *cmdShare) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.projectProvider.Setup(a, f)
|
||||
}
|
||||
|
||||
func (c *cmdShare) Execute(ctx clingy.Context) error {
|
||||
return nil
|
||||
}
|
45
cmd/uplinkng/cmd_version.go
Normal file
45
cmd/uplinkng/cmd_version.go
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
type cmdVersion struct {
|
||||
verbose bool
|
||||
}
|
||||
|
||||
func (c *cmdVersion) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
c.verbose = f.New(
|
||||
"verbose", "prints all dependency versions", false,
|
||||
clingy.Short('v'),
|
||||
clingy.Transform(strconv.ParseBool)).(bool)
|
||||
}
|
||||
|
||||
func (c *cmdVersion) Execute(ctx clingy.Context) error {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return errs.New("unable to read build info")
|
||||
}
|
||||
|
||||
tw := tabwriter.NewWriter(ctx.Stdout(), 4, 4, 4, ' ', 0)
|
||||
defer func() { _ = tw.Flush() }()
|
||||
|
||||
fmt.Fprintf(tw, "%s\t%s\n", bi.Main.Path, bi.Main.Version)
|
||||
for _, mod := range bi.Deps {
|
||||
if c.verbose || strings.HasPrefix(mod.Path, "storj.io/") {
|
||||
fmt.Fprintf(tw, " %s\t%s\n", mod.Path, mod.Version)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
203
cmd/uplinkng/global_flags.go
Normal file
203
cmd/uplinkng/global_flags.go
Normal file
@ -0,0 +1,203 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
"github.com/zeebo/errs"
|
||||
"github.com/zeebo/ini"
|
||||
)
|
||||
|
||||
type globalFlags struct {
|
||||
interactive bool
|
||||
configDir string
|
||||
oldConfigDir string
|
||||
|
||||
setup bool
|
||||
migrated bool
|
||||
|
||||
configLoaded bool
|
||||
config map[string][]string
|
||||
|
||||
accessesLoaded bool
|
||||
accessDefault string
|
||||
accesses map[string]string
|
||||
}
|
||||
|
||||
func newGlobalFlags() *globalFlags {
|
||||
return &globalFlags{}
|
||||
}
|
||||
|
||||
func (g *globalFlags) Setup(f clingy.Flags) {
|
||||
g.interactive = f.New(
|
||||
"interactive", "Controls if interactive input is allowed", true,
|
||||
clingy.Transform(strconv.ParseBool),
|
||||
clingy.Advanced,
|
||||
).(bool)
|
||||
|
||||
g.configDir = f.New(
|
||||
"config-dir", "Directory that stores the configuration", appDir(false, "storj", "uplink"),
|
||||
).(string)
|
||||
|
||||
g.oldConfigDir = f.New(
|
||||
"old-config-dir", "Directory that stores legacy configuration. Only used during migration", appDir(true, "storj", "uplink"),
|
||||
clingy.Advanced,
|
||||
).(string)
|
||||
|
||||
g.setup = true
|
||||
}
|
||||
|
||||
func (g *globalFlags) accessFile() string { return filepath.Join(g.configDir, "access.json") }
|
||||
func (g *globalFlags) configFile() string { return filepath.Join(g.configDir, "config.ini") }
|
||||
func (g *globalFlags) oldConfigFile() string { return filepath.Join(g.oldConfigDir, "config.yaml") }
|
||||
|
||||
func (g *globalFlags) Dynamic(name string) (vals []string, err error) {
|
||||
if !g.setup {
|
||||
return nil, nil
|
||||
}
|
||||
if err := g.migrate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := g.loadConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := "UPLINK_" + strings.ToUpper(strings.ReplaceAll(name, "-", "_"))
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return []string{val}, nil
|
||||
}
|
||||
return g.config[name], nil
|
||||
}
|
||||
|
||||
// loadConfig loads the configuration file from disk if it is not already loaded.
|
||||
// This makes calls to loadConfig idempotent.
|
||||
func (g *globalFlags) loadConfig() error {
|
||||
if g.config != nil {
|
||||
return nil
|
||||
}
|
||||
g.config = make(map[string][]string)
|
||||
|
||||
fh, err := os.Open(g.configFile())
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
defer func() { _ = fh.Close() }()
|
||||
|
||||
err = ini.Read(fh, func(ent ini.Entry) error {
|
||||
if ent.Section != "" {
|
||||
ent.Key = ent.Section + "." + ent.Key
|
||||
}
|
||||
g.config[ent.Key] = append(g.config[ent.Key], ent.Value)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.configLoaded = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *globalFlags) loadAccesses() error {
|
||||
if g.accesses != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fh, err := os.Open(g.accessFile())
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
defer func() { _ = fh.Close() }()
|
||||
|
||||
var jsonInput struct {
|
||||
Default string
|
||||
Accesses map[string]string
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(fh).Decode(&jsonInput); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
g.accessDefault = jsonInput.Default
|
||||
g.accesses = jsonInput.Accesses
|
||||
g.accessesLoaded = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *globalFlags) GetAccessInfo() (string, map[string]string, error) {
|
||||
if !g.accessesLoaded {
|
||||
if err := g.loadAccesses(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if !g.accessesLoaded {
|
||||
return "", nil, errs.New("must configure accesses")
|
||||
}
|
||||
}
|
||||
|
||||
// return a copy to avoid mutations messing things up
|
||||
accesses := make(map[string]string)
|
||||
for name, accessData := range g.accesses {
|
||||
accesses[name] = accessData
|
||||
}
|
||||
|
||||
return g.accessDefault, accesses, nil
|
||||
}
|
||||
|
||||
// SaveAccessInfo writes out the access file using the provided values.
|
||||
func (g *globalFlags) SaveAccessInfo(accessDefault string, accesses map[string]string) error {
|
||||
// TODO(jeff): write it atomically
|
||||
|
||||
accessFh, err := os.OpenFile(g.accessFile(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
defer func() { _ = accessFh.Close() }()
|
||||
|
||||
var jsonOutput = struct {
|
||||
Default string
|
||||
Accesses map[string]string
|
||||
}{
|
||||
Default: accessDefault,
|
||||
Accesses: accesses,
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(jsonOutput, "", "\t")
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
if _, err := accessFh.Write(data); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
if err := accessFh.Sync(); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
if err := accessFh.Close(); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *globalFlags) Wrap(ctx clingy.Context, cmd clingy.Cmd) error {
|
||||
if err := g.migrate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !g.configLoaded {
|
||||
// TODO(jeff): prompt for initial config setup
|
||||
_ = false
|
||||
}
|
||||
return cmd.Execute(ctx)
|
||||
}
|
170
cmd/uplinkng/global_flags_migrate.go
Normal file
170
cmd/uplinkng/global_flags_migrate.go
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/zeebo/errs"
|
||||
"github.com/zeebo/ini"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// migrate attempts to create the config file from the old config file if the
|
||||
// config file does not exist. It will only attempt to do so at most once
|
||||
// and so calls to migrate are idempotent.
|
||||
func (g *globalFlags) migrate() (err error) {
|
||||
if g.migrated {
|
||||
return nil
|
||||
}
|
||||
g.migrated = true
|
||||
|
||||
// if the config file exists, there is no need to migrate
|
||||
if _, err := os.Stat(g.configFile()); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the old config file does not exist, we cannot migrate
|
||||
oldFh, err := os.Open(g.oldConfigFile())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer func() { _ = oldFh.Close() }()
|
||||
|
||||
// load the information necessary to write the new config from
|
||||
// the old file.
|
||||
access, accesses, entries, err := g.loadOldConfig(oldFh)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
// ensure the directory that will hold the config files exists.
|
||||
if err := os.MkdirAll(g.configDir, 0755); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
// first, create and write the access file. that way, if there's an error
|
||||
// creating the config file, we will recreate this file.
|
||||
if err := g.SaveAccessInfo(access, accesses); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
// now, write out the config file from the stored entries.
|
||||
if err := g.saveConfig(entries); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
// migration complete!
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadOldConfig loads the default access name, the map of available accesses, and
|
||||
// a list of config entries from the yaml file in the reader.
|
||||
func (g *globalFlags) loadOldConfig(r io.Reader) (string, map[string]string, []ini.Entry, error) {
|
||||
access := ""
|
||||
accesses := make(map[string]string)
|
||||
entries := make([]ini.Entry, 0)
|
||||
|
||||
// load the old config if possible and write out a new config
|
||||
var node yaml.Node
|
||||
if err := yaml.NewDecoder(r).Decode(&node); err != nil {
|
||||
return "", nil, nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
// walking a yaml node is unfortunately recursive, so we have to do this
|
||||
// predeclaration trick to do a recursive inline function.
|
||||
var walk func(*yaml.Node, []string) error
|
||||
walk = func(node *yaml.Node, stack []string) error {
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return errs.New("unexpected non-map node in yaml document")
|
||||
} else if len(node.Content)%2 != 0 {
|
||||
return errs.New("map has odd number of content entries in yaml document")
|
||||
}
|
||||
|
||||
section := strings.Join(stack, ".")
|
||||
|
||||
// walk the map entries in pairs. the first entry is the key, and the second is
|
||||
// the value.
|
||||
for i := 0; i < len(node.Content); i += 2 {
|
||||
keyn, valuen := node.Content[i], node.Content[i+1]
|
||||
key, value := keyn.Value, valuen.Value
|
||||
|
||||
// we don't support key kinds other than scalar. yaml may not either. shrug.
|
||||
if keyn.Kind != yaml.ScalarNode {
|
||||
return errs.New("map has non-scalar key type")
|
||||
}
|
||||
|
||||
switch valuen.Kind {
|
||||
case yaml.ScalarNode:
|
||||
// we want to intercept the access and accesses values from the config
|
||||
// because they go into a separate file now. check for keys that match
|
||||
// one of those and stuff them away outside of entries.
|
||||
if key == "access" {
|
||||
access = key
|
||||
} else if strings.HasPrefix(key, "accesses.") {
|
||||
accesses[key[len("accesses."):]] = value
|
||||
} else if section == "accesses" {
|
||||
accesses[key] = value
|
||||
} else {
|
||||
entries = append(entries, ini.Entry{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Section: section,
|
||||
})
|
||||
}
|
||||
|
||||
case yaml.MappingNode:
|
||||
if err := walk(valuen, append(stack, key)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return errs.New("yaml map contains non-scalar or map content entry")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.Kind != yaml.DocumentNode {
|
||||
return "", nil, nil, errs.New("yaml root node is not document")
|
||||
}
|
||||
if len(node.Content) != 1 || node.Content[0].Kind != yaml.MappingNode {
|
||||
return "", nil, nil, errs.New("yaml root node does not contain a single map")
|
||||
}
|
||||
if err := walk(node.Content[0], nil); err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
return access, accesses, entries, nil
|
||||
}
|
||||
|
||||
// saveConfig writes out the config file using the provided values.
|
||||
// It is only intended to be used during initial migration.
|
||||
func (g *globalFlags) saveConfig(entries []ini.Entry) error {
|
||||
// TODO(jeff): write it atomically
|
||||
|
||||
newFh, err := os.Create(g.configFile())
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
defer func() { _ = newFh.Close() }()
|
||||
|
||||
err = ini.Write(newFh, func(emit func(ini.Entry)) {
|
||||
for _, ent := range entries {
|
||||
emit(ent)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
if err := newFh.Close(); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
57
cmd/uplinkng/main.go
Normal file
57
cmd/uplinkng/main.go
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
var gf = newGlobalFlags()
|
||||
|
||||
func main() {
|
||||
env := clingy.Environment{
|
||||
Name: "uplink",
|
||||
Args: os.Args[1:],
|
||||
|
||||
Dynamic: gf.Dynamic,
|
||||
Wrap: gf.Wrap,
|
||||
}
|
||||
|
||||
ok, err := env.Run(context.Background(), func(c clingy.Commands, f clingy.Flags) {
|
||||
// setup the dynamic global flags first so that they may be consulted
|
||||
// by the stdlib flags during their definition.
|
||||
gf.Setup(f)
|
||||
newStdlibFlags(flag.CommandLine).Setup(f)
|
||||
|
||||
c.Group("access", "Access related commands", func() {
|
||||
c.New("save", "Save an existing access", new(cmdAccessSave))
|
||||
c.New("create", "Create an access from a setup token", new(cmdAccessCreate))
|
||||
c.New("delete", "Delete an access from local store", new(cmdAccessDelete))
|
||||
c.New("list", "List saved accesses", new(cmdAccessList))
|
||||
c.New("use", "Set default access to use", new(cmdAccessUse))
|
||||
c.New("revoke", "Revoke an access", new(cmdAccessRevoke))
|
||||
})
|
||||
c.New("share", "Shares restricted accesses to objects", new(cmdShare))
|
||||
c.New("mb", "Create a new bucket", new(cmdMb))
|
||||
c.New("rb", "Remove a bucket bucket", new(cmdRb))
|
||||
c.New("cp", "Copies files or objects into or out of tardigrade", new(cmdCp))
|
||||
c.New("ls", "Lists buckets, prefixes, or objects", new(cmdLs))
|
||||
c.New("rm", "Remove an object", new(cmdRm))
|
||||
c.Group("meta", "Object metadata related commands", func() {
|
||||
c.New("get", "Get an object's metadata", new(cmdMetaGet))
|
||||
})
|
||||
c.New("version", "Prints version information", new(cmdVersion))
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
||||
}
|
||||
if !ok || err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
46
cmd/uplinkng/project_provider.go
Normal file
46
cmd/uplinkng/project_provider.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
|
||||
"storj.io/uplink"
|
||||
)
|
||||
|
||||
type projectProvider struct {
|
||||
access string
|
||||
openProject func(ctx context.Context) (*uplink.Project, error)
|
||||
}
|
||||
|
||||
func (pp *projectProvider) Setup(a clingy.Arguments, f clingy.Flags) {
|
||||
pp.access = f.New("access", "Which access to use", "").(string)
|
||||
}
|
||||
|
||||
func (pp *projectProvider) OpenProject(ctx context.Context) (*uplink.Project, error) {
|
||||
if pp.openProject != nil {
|
||||
return pp.openProject(ctx)
|
||||
}
|
||||
|
||||
accessDefault, accesses, err := gf.GetAccessInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pp.access != "" {
|
||||
accessDefault = pp.access
|
||||
}
|
||||
|
||||
var access *uplink.Access
|
||||
if data, ok := accesses[accessDefault]; ok {
|
||||
access, err = uplink.ParseAccess(data)
|
||||
} else {
|
||||
access, err = uplink.ParseAccess(accessDefault)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uplink.OpenProject(ctx, access)
|
||||
}
|
36
cmd/uplinkng/stdlib_flags.go
Normal file
36
cmd/uplinkng/stdlib_flags.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/zeebo/clingy"
|
||||
)
|
||||
|
||||
type stdlibFlags struct {
|
||||
fs *flag.FlagSet
|
||||
}
|
||||
|
||||
func newStdlibFlags(fs *flag.FlagSet) *stdlibFlags {
|
||||
return &stdlibFlags{
|
||||
fs: fs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stdlibFlags) Setup(f clingy.Flags) {
|
||||
// we use the Transform function to store the value as a side
|
||||
// effect so that we can return an error if one occurs through
|
||||
// the expected clingy pipeline.
|
||||
s.fs.VisitAll(func(fl *flag.Flag) {
|
||||
name, _ := flag.UnquoteUsage(fl)
|
||||
f.New(fl.Name, fl.Usage, fl.DefValue,
|
||||
clingy.Advanced,
|
||||
clingy.Type(name),
|
||||
clingy.Transform(func(val string) (string, error) {
|
||||
return "", fl.Value.Set(val)
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
57
cmd/uplinkng/utils.go
Normal file
57
cmd/uplinkng/utils.go
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// appDir returns best base directory for the currently running operating system. It
|
||||
// has a legacy bool to have it return the same values that storj.io/common/fpath.ApplicationDir
|
||||
// would have returned.
|
||||
func appDir(legacy bool, subdir ...string) string {
|
||||
for i := range subdir {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||
subdir[i] = strings.Title(subdir[i])
|
||||
} else {
|
||||
subdir[i] = strings.ToLower(subdir[i])
|
||||
}
|
||||
}
|
||||
var appdir string
|
||||
home := os.Getenv("HOME")
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
// Windows standards: https://msdn.microsoft.com/en-us/library/windows/apps/hh465094.aspx?f=255&MSPPError=-2147217396
|
||||
for _, env := range []string{"AppData", "AppDataLocal", "UserProfile", "Home"} {
|
||||
val := os.Getenv(env)
|
||||
if val != "" {
|
||||
appdir = val
|
||||
break
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
// Mac standards: https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
|
||||
appdir = filepath.Join(home, "Library", "Application Support")
|
||||
case "linux":
|
||||
fallthrough
|
||||
default:
|
||||
// Linux standards: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
if legacy {
|
||||
appdir = os.Getenv("XDG_DATA_HOME")
|
||||
if appdir == "" && home != "" {
|
||||
appdir = filepath.Join(home, ".local", "share")
|
||||
}
|
||||
} else {
|
||||
appdir = os.Getenv("XDG_CONFIG_HOME")
|
||||
if appdir == "" && home != "" {
|
||||
appdir = filepath.Join(home, ".config")
|
||||
}
|
||||
}
|
||||
}
|
||||
return filepath.Join(append([]string{appdir}, subdir...)...)
|
||||
}
|
7
go.mod
7
go.mod
@ -27,6 +27,7 @@ require (
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
|
||||
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
|
||||
github.com/shopspring/decimal v1.2.0
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.10
|
||||
@ -38,8 +39,11 @@ require (
|
||||
github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||
github.com/zeebo/assert v1.3.0
|
||||
github.com/zeebo/clingy v0.0.0-20210406153335-0504f579bda1
|
||||
github.com/zeebo/errs v1.2.2
|
||||
github.com/zeebo/ini v0.0.0-20210331155437-86af75b4f524
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.16.0
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
@ -48,9 +52,10 @@ require (
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||
google.golang.org/api v0.20.0 // indirect
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f
|
||||
storj.io/drpc v0.0.20
|
||||
storj.io/monkit-jaeger v0.0.0-20210426161729-debb1cbcbbd7
|
||||
storj.io/private v0.0.0-20210511083637-239fca6e9894
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210506124440-cfeb286eeeb9
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9
|
||||
)
|
||||
|
21
go.sum
21
go.sum
@ -386,8 +386,9 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
|
||||
github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0=
|
||||
github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@ -518,13 +519,19 @@ github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivll
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/clingy v0.0.0-20210406153335-0504f579bda1 h1:fxciFdO44MX0vCX58l+BQUi3jXw5CJu4uytNwvmS9r4=
|
||||
github.com/zeebo/clingy v0.0.0-20210406153335-0504f579bda1/go.mod h1:8+xc/32PGdlAA4nzjz2Bgb3Rf/LAN8/KGrXxIfnlPmw=
|
||||
github.com/zeebo/errs v1.1.1/go.mod h1:Yj8dHrUQwls1bF3dr/vcSIu+qf4mI7idnTcHfoACc6I=
|
||||
github.com/zeebo/errs v1.2.2 h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g=
|
||||
github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
github.com/zeebo/errs/v2 v2.0.3 h1:WwqAmopgot4ZC+CgIveP+H91Nf78NDEGWjtAXen45Hw=
|
||||
github.com/zeebo/errs/v2 v2.0.3/go.mod h1:OKmvVZt4UqpyJrYFykDKm168ZquJ55pbbIVUICNmLN0=
|
||||
github.com/zeebo/float16 v0.1.0 h1:kRqxv5og6z1emEyz5FpW0/BVHe5VfxEAw6b1ljCZlUc=
|
||||
github.com/zeebo/float16 v0.1.0/go.mod h1:fssGvvXu+XS8MH57cKmyrLB/cqioYeYX/2mXCN3a5wo=
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54 h1:+cwNE5KJ3pika4HuzmDHkDlK5myo0G9Sv+eO7WWxnUQ=
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54/go.mod h1:EI8LcOBDlSL3POyqwC1eJhOYlMBMidES+613EtmmT5w=
|
||||
github.com/zeebo/ini v0.0.0-20210331155437-86af75b4f524 h1:B+9mpufIVeXdXTCnW11CwWb/dYBJ53N4ew829SODXF0=
|
||||
github.com/zeebo/ini v0.0.0-20210331155437-86af75b4f524/go.mod h1:oiTrvEJ3c6v+Kpfz1tun0BO+EuR3eKdH4tF+WvEbjw8=
|
||||
github.com/zeebo/structs v1.0.2 h1:kvcd7s2LqXuO9cdV5LqrGHCOAfCBXaZpKCA3jD9SJIc=
|
||||
github.com/zeebo/structs v1.0.2/go.mod h1:LphfpprlqJQcbCq+eA3iIK/NsejMwk9mlfH/tM1XuKQ=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
@ -546,12 +553,13 @@ go.opentelemetry.io/otel/trace v0.18.0 h1:ilCfc/fptVKaDMK1vWk0elxpolurJbEgey9J6g
|
||||
go.opentelemetry.io/otel/trace v0.18.0/go.mod h1:FzdUu3BPwZSZebfQ1vl5/tAa8LyMLXSJN57AXIt/iDk=
|
||||
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.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
@ -841,7 +849,6 @@ sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
storj.io/common v0.0.0-20200424175742-65ac59022f4f/go.mod h1:pZyXiIE7bGETIRXtfs0nICqMwp7PM8HqnDuyUeldNA0=
|
||||
storj.io/common v0.0.0-20201026135900-1aaeec90670b/go.mod h1:GqdmNf3fLm2UZX/7Zr0BLFCJ4gFjgm6eHrk/fnmr5jQ=
|
||||
storj.io/common v0.0.0-20210429174118-60091ebbbdaf/go.mod h1:PdP3eTld9RqSV3E4K44JSlw7Z/zNsymj9rnKuHFKhJE=
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f h1:TwWEzxjvhnkCKUGds4HQKtAgFBjzf/C0hcA1luiNuKI=
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f/go.mod h1:PdP3eTld9RqSV3E4K44JSlw7Z/zNsymj9rnKuHFKhJE=
|
||||
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
|
||||
@ -853,5 +860,5 @@ storj.io/monkit-jaeger v0.0.0-20210426161729-debb1cbcbbd7 h1:zi0w9zoBfvuqysSAqxJ
|
||||
storj.io/monkit-jaeger v0.0.0-20210426161729-debb1cbcbbd7/go.mod h1:gj4vuCeyCRjRmH8LIrgoyU9Dc9uR6H+/GcDUXmTbf80=
|
||||
storj.io/private v0.0.0-20210511083637-239fca6e9894 h1:ANILx94AKXmvXAf+hs0HMb85Qi2Y4k7RjEb9S7OhK+M=
|
||||
storj.io/private v0.0.0-20210511083637-239fca6e9894/go.mod h1:iAc+LGwXYCe+YRRTlkfkg95ZBEL8pWHLVZ508/KQjOs=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210506124440-cfeb286eeeb9 h1:rSP8cSfLqkYtRLUlGkwj1CeafNf7YPRgTstgwHu0tC8=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210506124440-cfeb286eeeb9/go.mod h1:VzJd+P1sfcVnGCxm0mPPhOBkbov0gLZ+/QXeKkkZ1tI=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9 h1:F+A+Ki4eo3uzYXxesihRBq7PYBhU8MgfZeebd4O8hio=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9/go.mod h1:geRW2dh4rvPhgruFZbN71LSYkMmCJLpwg0y8K/uLr3Y=
|
||||
|
Loading…
Reference in New Issue
Block a user