mirror of
https://github.com/neilotoole/sq.git
synced 2024-12-25 01:04:55 +03:00
parent
b5fdc5c0d3
commit
6870327508
@ -131,4 +131,4 @@ run:
|
||||
service:
|
||||
golangci-lint-version: 1.27.x # use the fixed version to not introduce new linters unexpectedly
|
||||
prepare:
|
||||
- echo "here I can run custom commands, but no preparation needed for this repo"
|
||||
- echo "here I can run custom commands, but no preparation needed for this repo"
|
||||
|
@ -101,7 +101,7 @@ brews:
|
||||
name: sq
|
||||
homepage: "https://sq.io"
|
||||
description: "sq is a swiss army knife for data"
|
||||
caveats: "This is a preview release of sq. Use with caution."
|
||||
caveats: "For shell completion installation instructions, execute: sq completion --help"
|
||||
|
||||
tap:
|
||||
owner: neilotoole
|
||||
|
@ -16,6 +16,7 @@ or dropping tables.
|
||||
|
||||
For other installation options, see [here](https://github.com/neilotoole/sq/wiki/Home#Install).
|
||||
|
||||
It is strongly advised to install [shell completion](#shell-completion).
|
||||
|
||||
### macOS
|
||||
|
||||
@ -52,6 +53,11 @@ sudo rpm -i https://github.com/neilotoole/sq/releases/latest/download/sq-linux-a
|
||||
yum localinstall -y https://github.com/neilotoole/sq/releases/latest/download/sq-linux-amd64.rpm
|
||||
```
|
||||
|
||||
## Shell completion
|
||||
|
||||
Shell completion is available for `bash`, `zsh`, `fish`, and `powershell`.
|
||||
|
||||
Execute `sq completion --help` for installation instructions.
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
228
cli/cli.go
228
cli/cli.go
@ -32,6 +32,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/mattn/go-colorable"
|
||||
@ -68,6 +69,10 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cobra.EnableCommandSorting = false
|
||||
}
|
||||
|
||||
// errNoMsg is a sentinel error indicating that a command
|
||||
// has failed, but that no error message should be printed.
|
||||
// This is useful in the case where any error information may
|
||||
@ -77,7 +82,7 @@ var errNoMsg = errors.New("")
|
||||
// Execute builds a RunContext using ctx and default
|
||||
// settings, and invokes ExecuteWith.
|
||||
func Execute(ctx context.Context, stdin *os.File, stdout, stderr io.Writer, args []string) error {
|
||||
rc, err := newDefaultRunContext(ctx, stdin, stdout, stderr)
|
||||
rc, err := newDefaultRunContext(stdin, stdout, stderr)
|
||||
if err != nil {
|
||||
printError(rc, err)
|
||||
return err
|
||||
@ -85,65 +90,95 @@ func Execute(ctx context.Context, stdin *os.File, stdout, stderr io.Writer, args
|
||||
|
||||
defer rc.Close() // ok to call rc.Close on nil rc
|
||||
|
||||
return ExecuteWith(rc, args)
|
||||
return ExecuteWith(ctx, rc, args)
|
||||
}
|
||||
|
||||
// ExecuteWith invokes the cobra CLI framework, ultimately
|
||||
// resulting in a command being executed. The caller must
|
||||
// invoke rc.Close.
|
||||
func ExecuteWith(rc *RunContext, args []string) error {
|
||||
func ExecuteWith(ctx context.Context, rc *RunContext, args []string) error {
|
||||
rc.Log.Debugf("EXECUTE: %s", strings.Join(args, " "))
|
||||
rc.Log.Debugf("Build: %s %s %s", buildinfo.Version, buildinfo.Commit, buildinfo.Timestamp)
|
||||
rc.Log.Debugf("Config (cfg version %q) from: %s", rc.Config.Version, rc.ConfigStore.Location())
|
||||
|
||||
// NOTE: (Feb 2021): The project has been finally been upgraded
|
||||
// to spf13/cobra v1.1.3, which does provide support
|
||||
// for context.Context. However, the sq codebase is still using
|
||||
// the workaround to smuggle Context to the commands. Presumably
|
||||
// we'll refactor the code at some point to make use of cobra's
|
||||
// support for Context.
|
||||
|
||||
ctx = WithRunContext(ctx, rc)
|
||||
|
||||
rootCmd := newCommandTree(rc)
|
||||
var err error
|
||||
|
||||
// The following is a workaround for the fact that cobra doesn't
|
||||
// currently (as of 2017) support executing the root command with
|
||||
// arbitrary args. That is to say, if you execute:
|
||||
//
|
||||
// sq arg1 arg2
|
||||
// $ sq @sakila_sl3.actor
|
||||
//
|
||||
// then cobra will look for a command named "arg1", and when it
|
||||
// doesn't find such a command, it returns an "unknown command"
|
||||
// error.
|
||||
cmd, _, err := rootCmd.Find(args[1:])
|
||||
if err != nil {
|
||||
// This err will be the "unknown command" error.
|
||||
// cobra still returns cmd though. It should be
|
||||
// the root cmd.
|
||||
if cmd == nil || cmd.Name() != rootCmd.Name() {
|
||||
// should never happen
|
||||
panic(fmt.Sprintf("bad cobra cmd state: %v", cmd))
|
||||
}
|
||||
// then cobra will look for a command named "@sakila_sl3.actor",
|
||||
// and when it doesn't find such a command, it returns
|
||||
// an "unknown command" error.
|
||||
//
|
||||
// NOTE: This entire mechanism is ancient. Perhaps cobra
|
||||
// now handles this situation?
|
||||
|
||||
// If we have args [sq, arg1, arg2] then we redirect
|
||||
// to the "slq" command by modifying args to
|
||||
// look like: [query, arg1, arg2] -- noting that SetArgs
|
||||
// doesn't want the first args element.
|
||||
queryCmdArgs := append([]string{"slq"}, args[1:]...)
|
||||
rootCmd.SetArgs(queryCmdArgs)
|
||||
} else {
|
||||
if cmd.Name() == rootCmd.Name() {
|
||||
// Not sure why we have two paths to this, but it appears
|
||||
// that we've found the root cmd again, so again
|
||||
// we redirect to "query" cmd.
|
||||
|
||||
a := append([]string{"slq"}, args[1:]...)
|
||||
rootCmd.SetArgs(a)
|
||||
// We need to perform handling for autocomplete
|
||||
if len(args) > 0 && args[0] == "__complete" {
|
||||
if hasMatchingChildCommand(rootCmd, args[1]) {
|
||||
// If there is a matching child command, we let rootCmd
|
||||
// handle it, as per normal.
|
||||
rootCmd.SetArgs(args)
|
||||
} else {
|
||||
// It's just a normal command like "sq ls" or such.
|
||||
// There's no command matching the first argument to __complete.
|
||||
// Therefore, we assume that we want to perform completion
|
||||
// for the "slq" command (which is the pseudo-root command).
|
||||
effectiveArgs := append([]string{"__complete", "slq"}, args[1:]...)
|
||||
rootCmd.SetArgs(effectiveArgs)
|
||||
}
|
||||
} else {
|
||||
var cmd *cobra.Command
|
||||
cmd, _, err = rootCmd.Find(args)
|
||||
if err != nil {
|
||||
// This err will be the "unknown command" error.
|
||||
// cobra still returns cmd though. It should be
|
||||
// the root cmd.
|
||||
if cmd == nil || cmd.Name() != rootCmd.Name() {
|
||||
// Not sure if this can happen anymore? Can prob delete?
|
||||
panic(fmt.Sprintf("bad cobra cmd state: %v", cmd))
|
||||
}
|
||||
|
||||
// Explicitly set the args on rootCmd as this makes
|
||||
// cobra happy when this func is executed via tests.
|
||||
// Haven't explored the reason why.
|
||||
rootCmd.SetArgs(args[1:])
|
||||
// If we have args [sq, arg1, arg2] then we redirect
|
||||
// to the "slq" command by modifying args to
|
||||
// look like: [query, arg1, arg2] -- noting that SetArgs
|
||||
// doesn't want the first args element.
|
||||
effectiveArgs := append([]string{"slq"}, args...)
|
||||
rootCmd.SetArgs(effectiveArgs)
|
||||
} else {
|
||||
if cmd.Name() == rootCmd.Name() {
|
||||
// Not sure why we have two paths to this, but it appears
|
||||
// that we've found the root cmd again, so again
|
||||
// we redirect to "slq" cmd.
|
||||
|
||||
a := append([]string{"slq"}, args...)
|
||||
rootCmd.SetArgs(a)
|
||||
} else {
|
||||
// It's just a normal command like "sq ls" or such.
|
||||
|
||||
// Explicitly set the args on rootCmd as this makes
|
||||
// cobra happy when this func is executed via tests.
|
||||
// Haven't explored the reason why.
|
||||
rootCmd.SetArgs(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the rootCmd; cobra will find the appropriate
|
||||
// Execute rootCmd; cobra will find the appropriate
|
||||
// sub-command, and ultimately execute that command.
|
||||
err = rootCmd.Execute()
|
||||
err = rootCmd.ExecuteContext(ctx)
|
||||
if err != nil {
|
||||
printError(rc, err)
|
||||
}
|
||||
@ -151,11 +186,17 @@ func ExecuteWith(rc *RunContext, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// cobraMu exists because cobra relies upon package-level
|
||||
// constructs. This does not sit well with parallel tests.
|
||||
var cobraMu sync.Mutex
|
||||
|
||||
// newCommandTree builds sq's command tree, returning
|
||||
// the root cobra command.
|
||||
func newCommandTree(rc *RunContext) (rootCmd *cobra.Command) {
|
||||
rootCmd = newRootCmd()
|
||||
cobraMu.Lock()
|
||||
defer cobraMu.Unlock()
|
||||
|
||||
rootCmd = newRootCmd()
|
||||
rootCmd.SetOut(rc.Out)
|
||||
rootCmd.SetErr(rc.ErrOut)
|
||||
|
||||
@ -164,42 +205,52 @@ func newCommandTree(rc *RunContext) (rootCmd *cobra.Command) {
|
||||
// The behavior of cobra in this regard seems to have
|
||||
// changed? This particular incantation currently does the trick.
|
||||
rootCmd.Flags().Bool(flagHelp, false, "Show sq help")
|
||||
helpCmd := addCmd(rc, rootCmd, newHelpCmd)
|
||||
rootCmd.Flags().SortFlags = false
|
||||
helpCmd := addCmd(rc, rootCmd, newHelpCmd())
|
||||
rootCmd.SetHelpCommand(helpCmd)
|
||||
|
||||
addCmd(rc, rootCmd, newSLQCmd)
|
||||
addCmd(rc, rootCmd, newSQLCmd)
|
||||
addCmd(rc, rootCmd, newSLQCmd())
|
||||
addCmd(rc, rootCmd, newSQLCmd())
|
||||
|
||||
addCmd(rc, rootCmd, newSrcCommand)
|
||||
addCmd(rc, rootCmd, newSrcAddCmd)
|
||||
addCmd(rc, rootCmd, newSrcListCmd)
|
||||
addCmd(rc, rootCmd, newSrcRemoveCmd)
|
||||
addCmd(rc, rootCmd, newScratchCmd)
|
||||
addCmd(rc, rootCmd, newSrcCommand())
|
||||
addCmd(rc, rootCmd, newSrcAddCmd())
|
||||
addCmd(rc, rootCmd, newSrcListCmd())
|
||||
addCmd(rc, rootCmd, newSrcRemoveCmd())
|
||||
addCmd(rc, rootCmd, newScratchCmd())
|
||||
|
||||
addCmd(rc, rootCmd, newInspectCmd)
|
||||
addCmd(rc, rootCmd, newPingCmd)
|
||||
addCmd(rc, rootCmd, newInspectCmd())
|
||||
addCmd(rc, rootCmd, newPingCmd())
|
||||
|
||||
addCmd(rc, rootCmd, newVersionCmd)
|
||||
addCmd(rc, rootCmd, newDriversCmd)
|
||||
addCmd(rc, rootCmd, newVersionCmd())
|
||||
|
||||
tblCmd := addCmd(rc, rootCmd, newTblCmd)
|
||||
addCmd(rc, tblCmd, newTblCopyCmd)
|
||||
addCmd(rc, tblCmd, newTblTruncateCmd)
|
||||
addCmd(rc, tblCmd, newTblDropCmd)
|
||||
driverCmd := addCmd(rc, rootCmd, newDriverCmd())
|
||||
addCmd(rc, driverCmd, newDriverListCmd())
|
||||
|
||||
addCmd(rc, rootCmd, newInstallBashCompletionCmd)
|
||||
addCmd(rc, rootCmd, newGenerateZshCompletionCmd)
|
||||
tblCmd := addCmd(rc, rootCmd, newTblCmd())
|
||||
addCmd(rc, tblCmd, newTblCopyCmd())
|
||||
addCmd(rc, tblCmd, newTblTruncateCmd())
|
||||
addCmd(rc, tblCmd, newTblDropCmd())
|
||||
|
||||
addCmd(rc, rootCmd, newCompletionCmd())
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
// runFunc is an expansion of cobra's RunE func that
|
||||
// adds a RunContext as the first param.
|
||||
type runFunc func(rc *RunContext, cmd *cobra.Command, args []string) error
|
||||
// hasMatchingChildCommand returns true if s is a full or prefix
|
||||
// match for any of cmd's children. For example, if cmd has
|
||||
// children [inspect, ls, rm], then "insp" or "ls" would return true.
|
||||
func hasMatchingChildCommand(cmd *cobra.Command, s string) bool {
|
||||
for _, child := range cmd.Commands() {
|
||||
if strings.HasPrefix(child.Name(), s) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// addCmd adds the command returned by cmdFn to parentCmd.
|
||||
func addCmd(rc *RunContext, parentCmd *cobra.Command, cmdFn func() (*cobra.Command, runFunc)) *cobra.Command {
|
||||
cmd, fn := cmdFn()
|
||||
func addCmd(rc *RunContext, parentCmd, cmd *cobra.Command) *cobra.Command {
|
||||
cmd.Flags().SortFlags = false
|
||||
|
||||
if cmd.Name() != "help" {
|
||||
// Don't add the --help flag to the help command.
|
||||
@ -209,18 +260,19 @@ func addCmd(rc *RunContext, parentCmd *cobra.Command, cmdFn func() (*cobra.Comma
|
||||
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
rc.Cmd = cmd
|
||||
rc.Args = args
|
||||
err := rc.preRunE()
|
||||
err := rc.init()
|
||||
return err
|
||||
}
|
||||
|
||||
runE := cmd.RunE
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
if cmd.Flags().Changed(flagVersion) {
|
||||
// Bit of a hack: flag --version on any command
|
||||
// results in execVersion being invoked
|
||||
return execVersion(rc, cmd, args)
|
||||
return execVersion(cmd, args)
|
||||
}
|
||||
|
||||
return fn(rc, cmd, args)
|
||||
return runE(cmd, args)
|
||||
}
|
||||
|
||||
// We handle the errors ourselves (rather than let cobra do it)
|
||||
@ -232,13 +284,26 @@ func addCmd(rc *RunContext, parentCmd *cobra.Command, cmdFn func() (*cobra.Comma
|
||||
return cmd
|
||||
}
|
||||
|
||||
type runContextKey struct{}
|
||||
|
||||
// WithRunContext returns ctx with rc added as a value.
|
||||
func WithRunContext(ctx context.Context, rc *RunContext) context.Context {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, runContextKey{}, rc)
|
||||
}
|
||||
|
||||
// RunContextFrom extracts the RunContext added to ctx via WithRunContext.
|
||||
func RunContextFrom(ctx context.Context) *RunContext {
|
||||
return ctx.Value(runContextKey{}).(*RunContext)
|
||||
}
|
||||
|
||||
// RunContext is a container for injectable resources passed
|
||||
// to all execX funcs. The Close method should be invoked when
|
||||
// the RunContext is no longer needed.
|
||||
type RunContext struct {
|
||||
// Context is the run's context.Context.
|
||||
Context context.Context
|
||||
|
||||
// Stdin typically is os.Stdin, but can be changed for testing.
|
||||
Stdin *os.File
|
||||
|
||||
@ -269,6 +334,9 @@ type RunContext struct {
|
||||
// Log is the run's logger.
|
||||
Log lg.Log
|
||||
|
||||
initOnce sync.Once
|
||||
initErr error
|
||||
|
||||
// writers holds the various writer types that
|
||||
// the CLI uses to print output.
|
||||
writers *writers
|
||||
@ -288,12 +356,11 @@ type RunContext struct {
|
||||
// example if there's a config error). We do this to provide
|
||||
// enough framework so that such an error can be logged or
|
||||
// printed per the normal mechanisms if at all possible.
|
||||
func newDefaultRunContext(ctx context.Context, stdin *os.File, stdout, stderr io.Writer) (*RunContext, error) {
|
||||
func newDefaultRunContext(stdin *os.File, stdout, stderr io.Writer) (*RunContext, error) {
|
||||
rc := &RunContext{
|
||||
Context: ctx,
|
||||
Stdin: stdin,
|
||||
Out: stdout,
|
||||
ErrOut: stderr,
|
||||
Stdin: stdin,
|
||||
Out: stdout,
|
||||
ErrOut: stderr,
|
||||
}
|
||||
|
||||
log, clnup, loggingErr := defaultLogging()
|
||||
@ -325,10 +392,21 @@ func newDefaultRunContext(ctx context.Context, stdin *os.File, stdout, stderr io
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// preRunE is invoked by cobra prior to the command RunE being
|
||||
// init is invoked by cobra prior to the command RunE being
|
||||
// invoked. It sets up the registry, databases, writers and related
|
||||
// fundamental components.
|
||||
func (rc *RunContext) preRunE() error {
|
||||
// fundamental components. Subsequent invocations of this method
|
||||
// are no-op.
|
||||
func (rc *RunContext) init() error {
|
||||
rc.initOnce.Do(func() {
|
||||
rc.initErr = rc.doInit()
|
||||
})
|
||||
|
||||
return rc.initErr
|
||||
}
|
||||
|
||||
// doInit performs the actual work of initializing rc.
|
||||
// It must only be invoked once.
|
||||
func (rc *RunContext) doInit() error {
|
||||
rc.clnup = cleanup.New()
|
||||
log, cfg := rc.Log, rc.Config
|
||||
|
||||
|
@ -2,6 +2,7 @@ package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image/gif"
|
||||
"io/ioutil"
|
||||
@ -28,27 +29,23 @@ func TestSmoke(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Execute a bunch of smoke test cases.
|
||||
|
||||
sqargs := func(a ...string) []string {
|
||||
return append([]string{"sq"}, a...)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
a []string
|
||||
// errBecause, if non-empty, indicates an error is expected.
|
||||
errBecause string
|
||||
}{
|
||||
{a: sqargs("ls")},
|
||||
{a: sqargs("ls", "-v")},
|
||||
{a: sqargs("ls", "--help")},
|
||||
{a: sqargs("inspect"), errBecause: "no active data source"},
|
||||
{a: sqargs("inspect", "--help")},
|
||||
{a: sqargs("version")},
|
||||
{a: sqargs("--version")},
|
||||
{a: sqargs("help")},
|
||||
{a: sqargs("--help")},
|
||||
{a: sqargs("ping", "all")},
|
||||
{a: sqargs("ping", "--help")},
|
||||
{a: sqargs("ping"), errBecause: "no active data source"},
|
||||
{a: []string{"ls"}},
|
||||
{a: []string{"ls", "-v"}},
|
||||
{a: []string{"ls", "--help"}},
|
||||
{a: []string{"inspect"}, errBecause: "no active data source"},
|
||||
{a: []string{"inspect", "--help"}},
|
||||
{a: []string{"version"}},
|
||||
{a: []string{"--version"}},
|
||||
{a: []string{"help"}},
|
||||
{a: []string{"--help"}},
|
||||
{a: []string{"ping", "all"}},
|
||||
{a: []string{"ping", "--help"}},
|
||||
{a: []string{"ping"}, errBecause: "no active data source"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -58,7 +55,7 @@ func TestSmoke(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rc, out, errOut := newTestRunCtx(testlg.New(t))
|
||||
err := cli.ExecuteWith(rc, tc.a)
|
||||
err := cli.ExecuteWith(context.Background(), rc, tc.a)
|
||||
|
||||
// We log sq's output before doing assert, because it reads
|
||||
// better in testing's output that way.
|
||||
|
@ -12,34 +12,34 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func newSrcAddCmd() (*cobra.Command, runFunc) {
|
||||
func newSrcAddCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add [--driver=TYPE] [--handle=@HANDLE] LOCATION",
|
||||
Use: "add [--driver=TYPE] [--handle=@HANDLE] LOCATION",
|
||||
RunE: execSrcAdd,
|
||||
Example: ` # add a Postgres source; will have generated handle @sakila_pg
|
||||
sq add 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
$ sq add 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
|
||||
# same as above, but explicitly setting flags
|
||||
sq add --handle=@sakila_pg --driver=postgres 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
$ sq add --handle=@sakila_pg --driver=postgres 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
|
||||
# same as above, but with short flags
|
||||
sq add -h @sakila_pg --d postgres 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
$ sq add -h @sakila_pg --d postgres 'postgres://user:pass@localhost/sakila?sslmode=disable'
|
||||
|
||||
# add a SQL Server source; will have generated handle @sakila_mssql
|
||||
sq add 'sqlserver://user:pass@localhost?database=sakila'
|
||||
# add a SQL Server source; will have generated handle @sakila_mssql or similar
|
||||
$ sq add 'sqlserver://user:pass@localhost?database=sakila'
|
||||
|
||||
# add a sqlite db
|
||||
sq add ./testdata/sqlite1.db
|
||||
$ sq add ./testdata/sqlite1.db
|
||||
|
||||
# add an Excel spreadsheet, with options
|
||||
sq add ./testdata/test1.xlsx --opts=header=true
|
||||
$ sq add ./testdata/test1.xlsx --opts=header=true
|
||||
|
||||
# add a CSV source, with options
|
||||
sq add ./testdata/person.csv --opts='header=true'
|
||||
$ sq add ./testdata/person.csv --opts=header=true
|
||||
|
||||
# add a CSV source from a server (will be downloaded)
|
||||
sq add https://sq.io/testdata/actor.csv
|
||||
$ sq add https://sq.io/testdata/actor.csv
|
||||
`,
|
||||
Short: "Add data source",
|
||||
Long: `Add data source specified by LOCATION and optionally identified by @HANDLE.
|
||||
The format of LOCATION varies, but is generally a DB connection string, a
|
||||
file path, or a URL.
|
||||
@ -53,35 +53,41 @@ on LOCATION and the source driver type.
|
||||
|
||||
If flag --driver is omitted, sq will attempt to determine the
|
||||
type from LOCATION via file suffix, content type, etc.. If the result
|
||||
is ambiguous, specify the driver tye type via flag --driver.
|
||||
is ambiguous, specify the driver type via flag --driver.
|
||||
|
||||
Flag --opts sets source specific options. Generally opts are relevant
|
||||
Flag --opts sets source-specific options. Generally opts are relevant
|
||||
to document source types (such as a CSV file). The most common
|
||||
use is to specify that the document has a header row:
|
||||
|
||||
sq add actor.csv --opts=header=true
|
||||
$ sq add actor.csv --opts=header=true
|
||||
|
||||
Available source driver types can be listed via "sq drivers".
|
||||
Available source driver types can be listed via "sq driver ls".
|
||||
|
||||
At a minimum, the following drivers are bundled:
|
||||
|
||||
sqlite3 SQLite3
|
||||
postgres Postgres
|
||||
sqlserver Microsoft SQL Server
|
||||
xlsx Microsoft Excel XLSX
|
||||
mysql MySQL
|
||||
csv Comma-Separated Values
|
||||
tsv Tab-Separated Values
|
||||
sqlite3 SQLite
|
||||
postgres PostgreSQL
|
||||
sqlserver Microsoft SQL Server
|
||||
mysql MySQL
|
||||
csv Comma-Separated Values
|
||||
tsv Tab-Separated Values
|
||||
json JSON
|
||||
jsona JSON Array: LF-delimited JSON arrays
|
||||
jsonl JSON Lines: LF-delimited JSON objects
|
||||
xlsx Microsoft Excel XLSX
|
||||
`,
|
||||
Short: "Add data source",
|
||||
}
|
||||
|
||||
cmd.Flags().StringP(flagDriver, flagDriverShort, "", flagDriverUsage)
|
||||
_ = cmd.RegisterFlagCompletionFunc(flagDriver, completeDriverType)
|
||||
cmd.Flags().StringP(flagSrcOptions, "", "", flagSrcOptionsUsage)
|
||||
cmd.Flags().StringP(flagHandle, flagHandleShort, "", flagHandleUsage)
|
||||
return cmd, execSrcAdd
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSrcAdd(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execSrcAdd(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
if len(args) != 1 {
|
||||
return errz.Errorf(msgInvalidArgs)
|
||||
}
|
||||
@ -94,9 +100,8 @@ func execSrcAdd(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if cmd.Flags().Changed(flagDriver) {
|
||||
val, _ := cmd.Flags().GetString(flagDriver)
|
||||
typ = source.Type(strings.TrimSpace(val))
|
||||
|
||||
} else {
|
||||
typ, err = rc.files.Type(rc.Context, loc)
|
||||
typ, err = rc.files.Type(cmd.Context(), loc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -148,8 +153,8 @@ func execSrcAdd(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
// unlike the other SQL DBs sq supports so far.
|
||||
// Both of these forms are allowed:
|
||||
//
|
||||
// sq add sqlite3:///path/to/sakila.db
|
||||
// sq add /path/to/sakila.db
|
||||
// $ sq add sqlite3:///path/to/sakila.db
|
||||
// $ sq add /path/to/sakila.db
|
||||
//
|
||||
// The second form is particularly nice for bash completion etc.
|
||||
if typ == sqlite3.Type {
|
||||
@ -182,7 +187,7 @@ func execSrcAdd(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// TODO: should we really be pinging this src right now?
|
||||
err = drvr.Ping(rc.Context, src)
|
||||
err = drvr.Ping(cmd.Context(), src)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "failed to ping %s [%s]", src.Handle, src.RedactedLocation())
|
||||
}
|
||||
|
@ -1,109 +1,75 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
const bashCompletionFunc = `
|
||||
|
||||
__sq_list_sources()
|
||||
{
|
||||
local sq_output out
|
||||
if sq_output=$(sq ls 2>/dev/null); then
|
||||
out=($(echo "${sq_output}" | awk 'NR > 1 {print $1}'))
|
||||
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
|
||||
fi
|
||||
}
|
||||
|
||||
__sq_get_resource()
|
||||
{
|
||||
if [[ ${#nouns[@]} -eq 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
__sq_list_sources ${nouns[${#nouns[@]} -1]}
|
||||
if [[ $? -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
__custom_func() {
|
||||
case ${last_command} in
|
||||
sq_ls | sq_src | sq_rm | sq_inspect )
|
||||
__sq_list_sources
|
||||
return
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
}
|
||||
`
|
||||
|
||||
func newInstallBashCompletionCmd() (*cobra.Command, runFunc) {
|
||||
func newCompletionCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "install-bash-completion",
|
||||
Short: "Install bash completion script on Unix-ish systems.",
|
||||
Hidden: true,
|
||||
Use: "completion [bash|zsh|fish|powershell]",
|
||||
Short: "Generate completion script",
|
||||
RunE: execCompletion,
|
||||
Long: `To load completions:
|
||||
|
||||
Bash:
|
||||
|
||||
$ source <(sq completion bash)
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
Linux:
|
||||
$ sq completion bash > /etc/bash_completion.d/sq
|
||||
MacOS:
|
||||
$ sq completion bash > /usr/local/etc/bash_completion.d/sq
|
||||
|
||||
Zsh:
|
||||
|
||||
# If shell completion is not already enabled in your environment you will need
|
||||
# to enable it. You can execute the following once:
|
||||
|
||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ sq completion zsh > "${fpath[1]}/_sq"
|
||||
|
||||
# You will need to start a new shell for this setup to take effect.
|
||||
|
||||
Fish:
|
||||
|
||||
$ sq completion fish | source
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ sq completion fish > ~/.config/fish/completions/sq.fish
|
||||
|
||||
Powershell:
|
||||
|
||||
PS> sq completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
# To load completions for every new session, run:
|
||||
PS> sq completion powershell > sq.ps1
|
||||
# and source this file from your powershell profile.
|
||||
`,
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||
Args: cobra.ExactValidArgs(1),
|
||||
}
|
||||
|
||||
return cmd, execInstallBashCompletion
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execInstallBashCompletion(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
log := rc.Log
|
||||
var path string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
log.Warnf("skipping install bash completion on windows")
|
||||
return nil
|
||||
case "darwin":
|
||||
path = "/usr/local/etc/bash_completion.d/sq"
|
||||
func execCompletion(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
switch args[0] {
|
||||
case "bash":
|
||||
return cmd.Root().GenBashCompletion(rc.Out)
|
||||
case "zsh":
|
||||
return cmd.Root().GenZshCompletion(rc.Out)
|
||||
case "fish":
|
||||
return cmd.Root().GenFishCompletion(rc.Out, true)
|
||||
case "powershell":
|
||||
return cmd.Root().GenPowerShellCompletion(rc.Out)
|
||||
default:
|
||||
// it's unixish
|
||||
path = " /etc/bash_completion.d/sq"
|
||||
return errz.Errorf("invalid arg: %s", args[0])
|
||||
}
|
||||
|
||||
// TODO: only write if necessary (check for version/timestamp/checksum)
|
||||
err := cmd.Root().GenBashCompletionFile(path)
|
||||
if err != nil {
|
||||
log.Warnf("failed to write bash completion to %q: %v", path, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newGenerateZshCompletionCmd() (*cobra.Command, runFunc) {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gen-zsh-completion",
|
||||
Short: "Generate zsh completion script on Unix-ish systems.",
|
||||
Hidden: true,
|
||||
}
|
||||
return cmd, execGenerateZshCompletion
|
||||
}
|
||||
|
||||
func execGenerateZshCompletion(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
log := rc.Log
|
||||
var path string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
log.Warnf("skipping install zsh completion on windows")
|
||||
return nil
|
||||
case "darwin":
|
||||
path = "/usr/local/etc/bash_completion.d/sq"
|
||||
default:
|
||||
// it's unixish
|
||||
path = " /etc/bash_completion.d/sq"
|
||||
}
|
||||
|
||||
err := cmd.Root().GenZshCompletion(os.Stdout)
|
||||
if err != nil {
|
||||
log.Warnf("failed to write zsh completion to %q: %v", path, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
46
cli/cmd_driver.go
Normal file
46
cli/cmd_driver.go
Normal file
@ -0,0 +1,46 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newDriverCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "driver",
|
||||
Short: "List or manage drivers",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
|
||||
Example: ` # List drivers
|
||||
$ sq driver ls
|
||||
|
||||
# Install User Driver [TBD]
|
||||
$ sq driver install ./rss.sq.yml
|
||||
`,
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newDriverListCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List available drivers",
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: execDriverList,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
cmd.Flags().BoolP(flagHeader, flagHeaderShort, false, flagHeaderUsage)
|
||||
cmd.Flags().BoolP(flagMonochrome, flagMonochromeShort, false, flagMonochromeUsage)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execDriverList(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
drvrs := rc.registry.DriversMetadata()
|
||||
return rc.writers.metaw.DriverMetadata(drvrs)
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
func newDriversCmd() (*cobra.Command, runFunc) {
|
||||
cmd := &cobra.Command{
|
||||
Use: "drivers",
|
||||
Short: "List available drivers",
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
cmd.Flags().BoolP(flagHeader, flagHeaderShort, false, flagHeaderUsage)
|
||||
cmd.Flags().BoolP(flagMonochrome, flagMonochromeShort, false, flagMonochromeUsage)
|
||||
|
||||
return cmd, execDrivers
|
||||
}
|
||||
|
||||
func execDrivers(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return errz.Errorf("invalid arguments: zero arguments expected")
|
||||
}
|
||||
|
||||
drvrs := rc.registry.DriversMetadata()
|
||||
return rc.writers.metaw.DriverMetadata(drvrs)
|
||||
}
|
@ -2,16 +2,17 @@ package cli
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
func newHelpCmd() (*cobra.Command, runFunc) {
|
||||
func newHelpCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "help",
|
||||
Short: "Show sq help",
|
||||
Hidden: true,
|
||||
RunE: execHelp,
|
||||
}
|
||||
|
||||
return cmd, execHelp
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execHelp(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execHelp(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Root().Help()
|
||||
}
|
||||
|
@ -7,40 +7,44 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func newInspectCmd() (*cobra.Command, runFunc) {
|
||||
func newInspectCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "inspect [@HANDLE|@HANDLE.TABLE|.TABLE]",
|
||||
Example: ` # inspect active data source
|
||||
sq inspect
|
||||
|
||||
# inspect @pg1 data source
|
||||
sq inspect @pg1
|
||||
|
||||
# inspect 'tbluser' in @pg1 data source
|
||||
sq inspect @pg1.tbluser
|
||||
|
||||
# inspect 'tbluser' in active data source
|
||||
sq inspect .tbluser
|
||||
|
||||
# inspect piped data
|
||||
cat data.xlsx | sq inspect`,
|
||||
Use: "inspect [@HANDLE|@HANDLE.TABLE|.TABLE]",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
ValidArgsFunction: (&handleTableCompleter{
|
||||
max: 1,
|
||||
}).complete,
|
||||
RunE: execInspect,
|
||||
Short: "Inspect data source schema and stats",
|
||||
Long: `Inspect a data source, or a particular table in a source,
|
||||
listing table details, column names and types, row counts, etc.
|
||||
If @HANDLE is not provided, the active data source is assumed.`,
|
||||
Example: ` # inspect active data source
|
||||
$ sq inspect
|
||||
|
||||
# inspect @pg1 data source
|
||||
$ sq inspect @pg1
|
||||
|
||||
# inspect 'actor' in @pg1 data source
|
||||
$ sq inspect @pg1.actor
|
||||
|
||||
# inspect 'actor' in active data source
|
||||
$ sq inspect .actor
|
||||
|
||||
# inspect piped data
|
||||
$ cat data.xlsx | sq inspect`,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
cmd.Flags().Bool(flagInspectFull, false, flagInspectFullUsage)
|
||||
|
||||
return cmd, execInspect
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execInspect(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 {
|
||||
return errz.Errorf("too many arguments")
|
||||
}
|
||||
func execInspect(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
rc := RunContextFrom(ctx)
|
||||
|
||||
srcs := rc.Config.Sources
|
||||
|
||||
@ -56,7 +60,7 @@ func execInspect(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
// - We're inspecting the active src
|
||||
|
||||
// check if there's input on stdin
|
||||
src, err = checkStdinSource(rc)
|
||||
src, err = checkStdinSource(ctx, rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -107,15 +111,14 @@ func execInspect(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
dbase, err := rc.databases.Open(rc.Context, src)
|
||||
dbase, err := rc.databases.Open(ctx, src)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "failed to inspect %s", src.Handle)
|
||||
}
|
||||
//defer rc.Log.WarnIfCloseError(dbase)
|
||||
|
||||
if table != "" {
|
||||
var tblMeta *source.TableMetadata
|
||||
tblMeta, err = dbase.TableMetadata(rc.Context, table)
|
||||
tblMeta, err = dbase.TableMetadata(ctx, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -123,7 +126,7 @@ func execInspect(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
return rc.writers.metaw.TableMetadata(tblMeta)
|
||||
}
|
||||
|
||||
meta, err := dbase.SourceMetadata(rc.Context)
|
||||
meta, err := dbase.SourceMetadata(ctx)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "failed to read %s source metadata", src.Handle)
|
||||
}
|
||||
|
@ -2,25 +2,23 @@ package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
func newSrcListCmd() (*cobra.Command, runFunc) {
|
||||
func newSrcListCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List data sources",
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: execSrcList,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagVerbose, flagVerboseShort, false, flagVerboseUsage)
|
||||
cmd.Flags().BoolP(flagHeader, flagHeaderShort, false, flagHeaderUsage)
|
||||
return cmd, execSrcList
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSrcList(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errz.Errorf(msgInvalidArgs)
|
||||
}
|
||||
func execSrcList(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
|
||||
return rc.writers.srcw.SourceSet(rc.Config.Sources)
|
||||
}
|
||||
|
@ -14,27 +14,41 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func newPingCmd() (*cobra.Command, runFunc) {
|
||||
func newPingCmd() *cobra.Command {
|
||||
argsFn := func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// Suggestions are: handles, plus the string "all".
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
suggestions := append([]string{"all"}, rc.Config.Sources.Handles()...)
|
||||
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "ping [@HANDLE|all]",
|
||||
Use: "ping [all|@HANDLE [@HANDLE_N]]",
|
||||
//Args: cobra.MaximumNArgs(1),
|
||||
RunE: execPing,
|
||||
ValidArgsFunction: argsFn,
|
||||
|
||||
Short: "Ping data sources",
|
||||
Long: `Ping data sources to check connection health. If no arguments provided, the
|
||||
active data source is pinged. Provide the handles of one or more sources
|
||||
to ping those sources, or "all" to ping all sources.
|
||||
|
||||
The exit code is 1 if ping fails for any of the sources.`,
|
||||
Example: ` # ping active data source
|
||||
sq ping
|
||||
$ sq ping
|
||||
|
||||
# ping all data sources
|
||||
sq ping all
|
||||
$ sq ping all
|
||||
|
||||
# ping @my1 and @pg1
|
||||
$ sq ping @my1 @pg1
|
||||
|
||||
# ping @my1 with 2s timeout
|
||||
sq ping @my1 --timeout=2s
|
||||
|
||||
# ping @my1 and @pg1
|
||||
sq ping @my1 @pg1
|
||||
$ sq ping @my1 --timeout=2s
|
||||
|
||||
# output in TSV format
|
||||
sq ping --tsv @my1`,
|
||||
|
||||
Short: "Check data source connection health",
|
||||
Long: `Ping data sources to check connection health. If no arguments provided, the
|
||||
active data source is pinged. The exit code is 1 if ping fails for any of the sources.`,
|
||||
$ sq ping --tsv @my1`,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
@ -42,10 +56,11 @@ active data source is pinged. The exit code is 1 if ping fails for any of the so
|
||||
cmd.Flags().BoolP(flagTSV, flagTSVShort, false, flagTSVUsage)
|
||||
cmd.Flags().Duration(flagTimeout, time.Second*10, flagTimeoutPingUsage)
|
||||
|
||||
return cmd, execPing
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execPing(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execPing(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
cfg := rc.Config
|
||||
var srcs []*source.Source
|
||||
var gotAll bool
|
||||
@ -93,19 +108,23 @@ func execPing(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
timeout := cfg.Defaults.Timeout
|
||||
timeout := cfg.Defaults.PingTimeout
|
||||
if cmdFlagChanged(cmd, flagTimeout) {
|
||||
timeout, _ = cmd.Flags().GetDuration(flagTimeout)
|
||||
}
|
||||
|
||||
rc.Log.Debugf("Using timeout value: %s", timeout)
|
||||
|
||||
return pingSources(rc.Context, rc.Log, rc.registry, srcs, rc.writers.pingw, timeout)
|
||||
return pingSources(cmd.Context(), rc.Log, rc.registry, srcs, rc.writers.pingw, timeout)
|
||||
}
|
||||
|
||||
// pingSources pings each of the sources in srcs, and prints results
|
||||
// to w. If any error occurs pinging any of srcs, that error is printed
|
||||
// inline as part of the ping results, and an errNoMsg is returned.
|
||||
//
|
||||
// NOTE: This ping code has an ancient lineage, in that it was written
|
||||
// originally laid down before context.Context was a thing. Thus,
|
||||
// the entire thing could probably be rewritten for simplicity.
|
||||
func pingSources(ctx context.Context, log lg.Log, dp driver.Provider, srcs []*source.Source, w output.PingWriter, timeout time.Duration) error {
|
||||
w.Open(srcs)
|
||||
defer log.WarnIfFuncError(w.Close)
|
||||
|
@ -4,26 +4,23 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
func newSrcRemoveCmd() (*cobra.Command, runFunc) {
|
||||
func newSrcRemoveCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "rm @HANDLE",
|
||||
Example: ` sq rm @my1`,
|
||||
Aliases: []string{"remove"},
|
||||
Short: "Remove data source",
|
||||
Use: "rm @HANDLE",
|
||||
Example: ` $ sq rm @my1`,
|
||||
Short: "Remove data source",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: execSrcRemove,
|
||||
ValidArgsFunction: completeHandle(1),
|
||||
}
|
||||
|
||||
return cmd, execSrcRemove
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSrcRemove(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errz.Errorf(msgInvalidArgs)
|
||||
}
|
||||
|
||||
func execSrcRemove(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
cfg := rc.Config
|
||||
src, err := cfg.Sources.Get(args[0])
|
||||
if err != nil {
|
||||
|
@ -19,66 +19,67 @@ output to a database table.
|
||||
|
||||
You can query using sq's own jq-like syntax, or in native SQL.
|
||||
|
||||
Execute "sq completion --help" for how to install shell completion.
|
||||
|
||||
More at https://sq.io
|
||||
`,
|
||||
Example: ` # pipe an Excel file and output the first 10 rows from sheet1
|
||||
cat data.xlsx | sq '.sheet1 | .[0:10]'
|
||||
$ cat data.xlsx | sq '.sheet1 | .[0:10]'
|
||||
|
||||
# add Postgres source identified by handle @sakila_pg
|
||||
sq add --handle=@sakila_pg 'postgres://user:pass@localhost:5432/sakila?sslmode=disable'
|
||||
$ sq add --handle=@sakila_pg 'postgres://user:pass@localhost:5432/sakila?sslmode=disable'
|
||||
|
||||
# add SQL Server source; will have generated handle @sakila_mssql
|
||||
sq add 'sqlserver://user:pass@localhost?database=sakila'
|
||||
$ sq add 'sqlserver://user:pass@localhost?database=sakila'
|
||||
|
||||
# list available data sources
|
||||
sq ls
|
||||
$ sq ls
|
||||
|
||||
# ping all data sources
|
||||
sq ping all
|
||||
$ sq ping all
|
||||
|
||||
# set active data source
|
||||
sq src @sakila_pg
|
||||
$ sq src @sakila_pg
|
||||
|
||||
# get specified cols from table address in active data source
|
||||
sq '.address | .address_id, .city, .country'
|
||||
$ sq '.address | .address_id, .city, .country'
|
||||
|
||||
# get metadata (schema, stats etc) for data source
|
||||
sq inspect @sakila_pg
|
||||
$ sq inspect @sakila_pg
|
||||
|
||||
# get metadata for a table
|
||||
sq inspect @pg1.person
|
||||
$ sq inspect @pg1.person
|
||||
|
||||
# output in JSON
|
||||
sq -j '.person | .uid, .username, .email'
|
||||
$ sq -j '.person | .uid, .username, .email'
|
||||
|
||||
# output in table format (with header)
|
||||
sq -th '.person | .uid, .username, .email'
|
||||
$ sq -th '.person | .uid, .username, .email'
|
||||
|
||||
# output in table format (no header)
|
||||
sq -t '.person | .uid, .username, .email'
|
||||
$ sq -t '.person | .uid, .username, .email'
|
||||
|
||||
# output to a HTML file
|
||||
sq --html '@sakila_sl3.actor' -o actor.html
|
||||
$ sq --html '@sakila_sl3.actor' -o actor.html
|
||||
|
||||
# join across data sources
|
||||
sq '@my1.person, @pg1.address | join(.uid) | .username, .email, .city'
|
||||
$ sq '@my1.person, @pg1.address | join(.uid) | .username, .email, .city'
|
||||
|
||||
# insert query results into a table in another data source
|
||||
sq --insert=@pg1.person '@my1.person | .username, .email'
|
||||
$ sq --insert=@pg1.person '@my1.person | .username, .email'
|
||||
|
||||
# execute a database-native SQL query, specifying the source
|
||||
sq sql --src=@pg1 'SELECT uid, username, email FROM person LIMIT 2'
|
||||
$ sq sql --src=@pg1 'SELECT uid, username, email FROM person LIMIT 2'
|
||||
|
||||
# copy a table (in the same source)
|
||||
sq tbl copy @sakila_sl3.actor .actor2
|
||||
$ sq tbl copy @sakila_sl3.actor .actor2
|
||||
|
||||
# truncate tables
|
||||
sq tbl truncate @sakila_sl3.actor2
|
||||
$ sq tbl truncate @sakila_sl3.actor2
|
||||
|
||||
# drop table
|
||||
sq tbl drop @sakila_sl3.actor2
|
||||
$ sq tbl drop @sakila_sl3.actor2
|
||||
`,
|
||||
BashCompletionFunction: bashCompletionFunc,
|
||||
}
|
||||
|
||||
addQueryCmdFlags(cmd)
|
||||
|
@ -2,7 +2,6 @@ package cli
|
||||
|
||||
import (
|
||||
"github.com/neilotoole/sq/drivers/sqlite3"
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@ -10,24 +9,26 @@ import (
|
||||
|
||||
// TODO: dump all this "internal" stuff: make the options as follows: @HANDLE, file, memory
|
||||
|
||||
func newScratchCmd() (*cobra.Command, runFunc) {
|
||||
func newScratchCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "scratch [@HANDLE|internal|internal:file|internal:mem|@scratch]",
|
||||
// This command is likely to be ditched in favor of a generalized "config" cmd
|
||||
// such as "sq config scratchdb=@my1"
|
||||
Hidden: true,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: execScratch,
|
||||
Example: ` # get scratch data source
|
||||
sq scratch
|
||||
$ sq scratch
|
||||
# set @my1 as scratch data source
|
||||
sq scratch @my1
|
||||
$ sq scratch @my1
|
||||
# use the default embedded db
|
||||
sq scratch internal
|
||||
$ sq scratch internal
|
||||
# explicitly specify use of embedded file db
|
||||
sq scratch internal:file
|
||||
$ sq scratch internal:file
|
||||
# explicitly specify use of embedded memory db
|
||||
sq scratch internal:mem
|
||||
$ sq scratch internal:mem
|
||||
# restore default scratch db (equivalent to "internal")
|
||||
sq scratch @scratch`,
|
||||
$ sq scratch @scratch`,
|
||||
Short: "Get or set scratch data source",
|
||||
Long: `Get or set scratch data source. The scratch db is used internally by sq for multiple purposes such as
|
||||
importing non-SQL data, or cross-database joins. If no argument provided, get the current scratch data
|
||||
@ -35,14 +36,11 @@ source. Otherwise, set @HANDLE or an internal db as the scratch data source. The
|
||||
`,
|
||||
}
|
||||
|
||||
return cmd, execScratch
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execScratch(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 {
|
||||
return errz.Errorf(msgInvalidArgs)
|
||||
}
|
||||
|
||||
func execScratch(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
cfg := rc.Config
|
||||
|
||||
var src *source.Source
|
||||
|
@ -15,24 +15,28 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func newSLQCmd() (*cobra.Command, runFunc) {
|
||||
func newSLQCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "slq",
|
||||
Short: "Execute SLQ query",
|
||||
Hidden: false,
|
||||
Use: "slq",
|
||||
Short: "Execute SLQ query",
|
||||
Hidden: true,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: execSLQ,
|
||||
ValidArgsFunction: completeSLQ,
|
||||
}
|
||||
|
||||
addQueryCmdFlags(cmd)
|
||||
cmd.Flags().Bool(flagVersion, false, flagVersionUsage)
|
||||
|
||||
return cmd, execSLQ
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSLQ(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execSLQ(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
srcs := rc.Config.Sources
|
||||
|
||||
// check if there's input on stdin
|
||||
src, err := checkStdinSource(rc)
|
||||
src, err := checkStdinSource(cmd.Context(), rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -65,7 +69,7 @@ func execSLQ(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if !cmdFlagChanged(cmd, flagInsert) {
|
||||
// The user didn't specify the --insert=@src.tbl flag,
|
||||
// so we just want to print the records.
|
||||
return execSLQPrint(rc)
|
||||
return execSLQPrint(cmd.Context(), rc)
|
||||
}
|
||||
|
||||
// Instead of printing the records, they will be
|
||||
@ -85,19 +89,19 @@ func execSLQ(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return execSLQInsert(rc, destSrc, destTbl)
|
||||
return execSLQInsert(cmd.Context(), rc, destSrc, destTbl)
|
||||
}
|
||||
|
||||
// execSQLInsert executes the SLQ and inserts resulting records
|
||||
// into destTbl in destSrc.
|
||||
func execSLQInsert(rc *RunContext, destSrc *source.Source, destTbl string) error {
|
||||
func execSLQInsert(ctx context.Context, rc *RunContext, destSrc *source.Source, destTbl string) error {
|
||||
args, srcs, dbases := rc.Args, rc.Config.Sources, rc.databases
|
||||
slq, err := preprocessUserSLQ(rc, args)
|
||||
slq, err := preprocessUserSLQ(ctx, rc, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFn := context.WithCancel(rc.Context)
|
||||
ctx, cancelFn := context.WithCancel(ctx)
|
||||
defer cancelFn()
|
||||
|
||||
destDB, err := dbases.Open(ctx, destSrc)
|
||||
@ -132,14 +136,14 @@ func execSLQInsert(rc *RunContext, destSrc *source.Source, destTbl string) error
|
||||
}
|
||||
|
||||
// execSLQPrint executes the SLQ query, and prints output to writer.
|
||||
func execSLQPrint(rc *RunContext) error {
|
||||
slq, err := preprocessUserSLQ(rc, rc.Args)
|
||||
func execSLQPrint(ctx context.Context, rc *RunContext) error {
|
||||
slq, err := preprocessUserSLQ(ctx, rc, rc.Args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recw := output.NewRecordWriterAdapter(rc.writers.recordw)
|
||||
execErr := libsq.ExecuteSLQ(rc.Context, rc.Log, rc.databases, rc.databases, rc.Config.Sources, slq, recw)
|
||||
execErr := libsq.ExecuteSLQ(ctx, rc.Log, rc.databases, rc.databases, rc.Config.Sources, slq, recw)
|
||||
_, waitErr := recw.Wait()
|
||||
if execErr != nil {
|
||||
return execErr
|
||||
@ -171,8 +175,8 @@ func execSLQPrint(rc *RunContext) error {
|
||||
// to the query. This allows a query where the first selector
|
||||
// segment is the table name.
|
||||
//
|
||||
// $ sq '.person' --> sq '@active.person'
|
||||
func preprocessUserSLQ(rc *RunContext, args []string) (string, error) {
|
||||
// $ sq '.person' --> $ sq '@active.person'
|
||||
func preprocessUserSLQ(ctx context.Context, rc *RunContext, args []string) (string, error) {
|
||||
log, reg, dbases, srcs := rc.Log, rc.registry, rc.databases, rc.Config.Sources
|
||||
activeSrc := srcs.Active()
|
||||
|
||||
@ -204,13 +208,13 @@ func preprocessUserSLQ(rc *RunContext, args []string) (string, error) {
|
||||
// This isn't a monotable src, so we can't
|
||||
// just select @stdin.data. Instead we'll select
|
||||
// the first table name, as found in the source meta.
|
||||
dbase, err := dbases.Open(rc.Context, activeSrc)
|
||||
dbase, err := dbases.Open(ctx, activeSrc)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer log.WarnIfCloseError(dbase)
|
||||
|
||||
srcMeta, err := dbase.SourceMetadata(rc.Context)
|
||||
srcMeta, err := dbase.SourceMetadata(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -299,9 +303,14 @@ func addQueryCmdFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().BoolP(flagPretty, "", true, flagPrettyUsage)
|
||||
|
||||
cmd.Flags().StringP(flagInsert, "", "", flagInsertUsage)
|
||||
_ = cmd.RegisterFlagCompletionFunc(flagInsert, (&handleTableCompleter{onlySQL: true, handleRequired: true}).complete)
|
||||
|
||||
cmd.Flags().StringP(flagActiveSrc, "", "", flagActiveSrcUsage)
|
||||
_ = cmd.RegisterFlagCompletionFunc(flagActiveSrc, completeHandle(0))
|
||||
|
||||
// The driver flag can be used if data is piped to sq over stdin
|
||||
cmd.Flags().StringP(flagDriver, "", "", flagQueryDriverUsage)
|
||||
_ = cmd.RegisterFlagCompletionFunc(flagDriver, completeDriverType)
|
||||
|
||||
cmd.Flags().StringP(flagSrcOptions, "", "", flagQuerySrcOptionsUsage)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/core/stringz"
|
||||
)
|
||||
|
||||
func newSQLCmd() (*cobra.Command, runFunc) {
|
||||
func newSQLCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "sql QUERY|STMT",
|
||||
Short: "Execute DB-native SQL query or statement",
|
||||
@ -28,17 +28,18 @@ If flag --query is set, sq will run the input as a query
|
||||
(SELECT) and return the query rows. If flag --exec is set,
|
||||
sq will execute the input and return the result. If neither
|
||||
flag is set, sq attempts to determine the appropriate mode.`,
|
||||
RunE: execSQL,
|
||||
Example: ` # Select from active source
|
||||
sq sql 'SELECT * FROM actor'
|
||||
$ sq sql 'SELECT * FROM actor'
|
||||
|
||||
# Select from a specified source
|
||||
sq sql --src=@sakila_pg12 'SELECT * FROM actor'
|
||||
$ sq sql --src=@sakila_pg12 'SELECT * FROM actor'
|
||||
|
||||
# Drop table @sakila_pg12.actor
|
||||
sq sql --exec --src=@sakila_pg12 'DROP TABLE actor'
|
||||
$ sq sql --exec --src=@sakila_pg12 'DROP TABLE actor'
|
||||
|
||||
# Select from active source and write results to @sakila_ms17.actor
|
||||
sq sql 'SELECT * FROM actor' --insert=@sakila_ms17.actor`,
|
||||
$ sq sql 'SELECT * FROM actor' --insert=@sakila_ms17.actor`,
|
||||
}
|
||||
|
||||
addQueryCmdFlags(cmd)
|
||||
@ -48,10 +49,11 @@ flag is set, sq attempts to determine the appropriate mode.`,
|
||||
// User explicitly wants to execute the SQL using sql.DB.Exec
|
||||
cmd.Flags().Bool(flagSQLExec, false, flagSQLExecUsage)
|
||||
|
||||
return cmd, execSQL
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSQL(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execSQL(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
switch len(args) {
|
||||
default:
|
||||
// FIXME: we should allow multiple args and concat them
|
||||
@ -64,7 +66,7 @@ func execSQL(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
err := determineSources(rc)
|
||||
err := determineSources(cmd.Context(), rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -77,7 +79,7 @@ func execSQL(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if !cmdFlagChanged(cmd, flagInsert) {
|
||||
// The user didn't specify the --insert=@src.tbl flag,
|
||||
// so we just want to print the records.
|
||||
return execSQLPrint(rc, activeSrc)
|
||||
return execSQLPrint(cmd.Context(), rc, activeSrc)
|
||||
}
|
||||
|
||||
// Instead of printing the records, they will be
|
||||
@ -97,20 +99,20 @@ func execSQL(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return execSQLInsert(rc, activeSrc, destSrc, destTbl)
|
||||
return execSQLInsert(cmd.Context(), rc, activeSrc, destSrc, destTbl)
|
||||
}
|
||||
|
||||
// execSQLPrint executes the SQL and prints resulting records
|
||||
// to the configured writer.
|
||||
func execSQLPrint(rc *RunContext, fromSrc *source.Source) error {
|
||||
func execSQLPrint(ctx context.Context, rc *RunContext, fromSrc *source.Source) error {
|
||||
args := rc.Args
|
||||
dbase, err := rc.databases.Open(rc.Context, fromSrc)
|
||||
dbase, err := rc.databases.Open(ctx, fromSrc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recw := output.NewRecordWriterAdapter(rc.writers.recordw)
|
||||
err = libsq.QuerySQL(rc.Context, rc.Log, dbase, recw, args[0])
|
||||
err = libsq.QuerySQL(ctx, rc.Log, dbase, recw, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -120,10 +122,10 @@ func execSQLPrint(rc *RunContext, fromSrc *source.Source) error {
|
||||
|
||||
// execSQLInsert executes the SQL and inserts resulting records
|
||||
// into destTbl in destSrc.
|
||||
func execSQLInsert(rc *RunContext, fromSrc, destSrc *source.Source, destTbl string) error {
|
||||
func execSQLInsert(ctx context.Context, rc *RunContext, fromSrc, destSrc *source.Source, destTbl string) error {
|
||||
args := rc.Args
|
||||
dbases := rc.databases
|
||||
ctx, cancelFn := context.WithCancel(rc.Context)
|
||||
ctx, cancelFn := context.WithCancel(ctx)
|
||||
defer cancelFn()
|
||||
|
||||
fromDB, err := dbases.Open(ctx, fromSrc)
|
||||
|
@ -2,35 +2,29 @@ package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/core/errz"
|
||||
)
|
||||
|
||||
func newSrcCommand() (*cobra.Command, runFunc) {
|
||||
func newSrcCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "src [@HANDLE]",
|
||||
Use: "src [@HANDLE]",
|
||||
RunE: execSrc,
|
||||
Example: ` # get active data source
|
||||
sq src
|
||||
$ sq src
|
||||
|
||||
# set @my1 as active data source
|
||||
sq src @my1`,
|
||||
// RunE: execSrc,
|
||||
Short: "Get or set active data source",
|
||||
$ sq src @my1`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
ValidArgsFunction: completeHandle(1),
|
||||
Short: "Get or set active data source",
|
||||
Long: `Get or set active data source. If no argument provided, get the active data
|
||||
source. Otherwise, set @HANDLE as the active data source.`,
|
||||
}
|
||||
|
||||
//cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
//cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
//cmd.Flags().BoolP(flagHeader, flagHeaderShort, false, flagHeaderUsage)
|
||||
|
||||
return cmd, execSrc
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execSrc(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 {
|
||||
return errz.Errorf(msgInvalidArgs)
|
||||
}
|
||||
|
||||
func execSrc(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
cfg := rc.Config
|
||||
|
||||
if len(args) == 0 {
|
||||
|
@ -11,52 +11,55 @@ import (
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
func newTblCmd() (*cobra.Command, runFunc) {
|
||||
func newTblCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tbl",
|
||||
Short: "Common actions on tables (copy, truncate, drop)",
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
Example: ` # Copy table actor to new table actor2
|
||||
sq tbl copy @sakila_sl3.actor actor2
|
||||
$ sq tbl copy @sakila_sl3.actor actor2
|
||||
|
||||
# Truncate table actor2
|
||||
sq tbl truncate @sakila_sl3.actor2
|
||||
$ sq tbl truncate @sakila_sl3.actor2
|
||||
|
||||
# Drop table actor2
|
||||
sq tbl drop @sakila_sl3.actor2`,
|
||||
$ sq tbl drop @sakila_sl3.actor2`,
|
||||
}
|
||||
|
||||
return cmd, func(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newTblCopyCmd() (*cobra.Command, runFunc) {
|
||||
func newTblCopyCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "copy @HANDLE.TABLE NEWTABLE",
|
||||
Short: "Make a copy of a table",
|
||||
Long: `Make a copy of a table in the same database. The table data is also copied by default.`,
|
||||
Example: ` # Copy table "actor" in @sakila_sl3" to new table "actor2"
|
||||
sq tbl copy @sakila_sl3.actor .actor2
|
||||
Use: "copy @HANDLE.TABLE NEWTABLE",
|
||||
Short: "Make a copy of a table",
|
||||
Long: `Make a copy of a table in the same database. The table data is also copied by default.`,
|
||||
ValidArgsFunction: completeTblCopy,
|
||||
RunE: execTblCopy,
|
||||
Example: ` # Copy table "actor" in @sakila_sl3 to new table "actor2"
|
||||
$ sq tbl copy @sakila_sl3.actor .actor2
|
||||
|
||||
# Copy table "actor" in active src to table "actor2"
|
||||
sq tbl copy .actor .actor2
|
||||
$ sq tbl copy .actor .actor2
|
||||
|
||||
# Copy table "actor" in active src to generated table name (e.g. "@sakila_sl3.actor_copy__1ae03e9b")
|
||||
sq tbl copy .actor
|
||||
$ sq tbl copy .actor
|
||||
|
||||
# Copy table structure, but don't copy table data
|
||||
sq tbl copy --data=false .actor
|
||||
$ sq tbl copy --data=false .actor
|
||||
`,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
cmd.Flags().Bool(flagTblData, true, flagTblDataUsage)
|
||||
|
||||
return cmd, execTblCopy
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execTblCopy(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execTblCopy(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
if len(args) == 0 || len(args) > 2 {
|
||||
return errz.New("one or two table args required")
|
||||
}
|
||||
@ -108,12 +111,12 @@ func execTblCopy(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
var dbase driver.Database
|
||||
dbase, err = rc.databases.Open(rc.Context, tblHandles[0].src)
|
||||
dbase, err = rc.databases.Open(cmd.Context(), tblHandles[0].src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copied, err := sqlDrvr.CopyTable(rc.Context, dbase.DB(), tblHandles[0].tbl, tblHandles[1].tbl, copyData)
|
||||
copied, err := sqlDrvr.CopyTable(cmd.Context(), dbase.DB(), tblHandles[0].tbl, tblHandles[1].tbl, copyData)
|
||||
if err != nil {
|
||||
return errz.Wrapf(err, "failed tbl copy %s.%s --> %s.%s",
|
||||
tblHandles[0].handle, tblHandles[0].tbl,
|
||||
@ -137,28 +140,35 @@ func execTblCopy(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newTblTruncateCmd() (*cobra.Command, runFunc) {
|
||||
func newTblTruncateCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "truncate @HANDLE.TABLE",
|
||||
Use: "truncate @HANDLE.TABLE|.TABLE",
|
||||
Short: "Truncate one or more tables",
|
||||
Long: `Truncate one or more tables. Note that this command
|
||||
only applies to SQL sources.`,
|
||||
RunE: execTblTruncate,
|
||||
ValidArgsFunction: (&handleTableCompleter{
|
||||
onlySQL: true,
|
||||
}).complete,
|
||||
Example: ` # truncate table "actor"" in source @sakila_sl3
|
||||
sq tbl truncate @sakila_sl3.actor
|
||||
$ sq tbl truncate @sakila_sl3.actor
|
||||
|
||||
# truncate table "payment"" in the active src
|
||||
sq tbl truncate .payment
|
||||
$ sq tbl truncate .payment
|
||||
|
||||
# truncate multiple tables
|
||||
sq tbl truncate .payment @sakila_sl3.actor
|
||||
$ sq tbl truncate .payment @sakila_sl3.actor
|
||||
`,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
|
||||
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
|
||||
|
||||
return cmd, execTblTruncate
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execTblTruncate(rc *RunContext, cmd *cobra.Command, args []string) (err error) {
|
||||
func execTblTruncate(cmd *cobra.Command, args []string) (err error) {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
var tblHandles []tblHandle
|
||||
tblHandles, err = parseTableHandleArgs(rc.registry, rc.Config.Sources, args)
|
||||
if err != nil {
|
||||
@ -167,7 +177,7 @@ func execTblTruncate(rc *RunContext, cmd *cobra.Command, args []string) (err err
|
||||
|
||||
for _, tblH := range tblHandles {
|
||||
var affected int64
|
||||
affected, err = tblH.drvr.Truncate(rc.Context, tblH.src, tblH.tbl, true)
|
||||
affected, err = tblH.drvr.Truncate(cmd.Context(), tblH.src, tblH.tbl, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -180,25 +190,32 @@ func execTblTruncate(rc *RunContext, cmd *cobra.Command, args []string) (err err
|
||||
return nil
|
||||
}
|
||||
|
||||
func newTblDropCmd() (*cobra.Command, runFunc) {
|
||||
func newTblDropCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "drop @HANDLE.TABLE",
|
||||
Short: "Drop one or more tables",
|
||||
Long: `Drop one or more tables. Note that this command
|
||||
only applies to SQL sources.`,
|
||||
RunE: execTblDrop,
|
||||
ValidArgsFunction: (&handleTableCompleter{
|
||||
onlySQL: true,
|
||||
}).complete,
|
||||
Example: `# drop table "actor" in src @sakila_sl3
|
||||
sq tbl drop @sakila_sl3.actor
|
||||
$ sq tbl drop @sakila_sl3.actor
|
||||
|
||||
# drop table "payment"" in the active src
|
||||
sq tbl drop .payment
|
||||
$ sq tbl drop .payment
|
||||
|
||||
# drop multiple tables
|
||||
sq drop .payment @sakila_sl3.actor
|
||||
$ sq drop .payment @sakila_sl3.actor
|
||||
`,
|
||||
}
|
||||
|
||||
return cmd, execTblDrop
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execTblDrop(rc *RunContext, cmd *cobra.Command, args []string) (err error) {
|
||||
func execTblDrop(cmd *cobra.Command, args []string) (err error) {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
var tblHandles []tblHandle
|
||||
tblHandles, err = parseTableHandleArgs(rc.registry, rc.Config.Sources, args)
|
||||
if err != nil {
|
||||
@ -212,11 +229,11 @@ func execTblDrop(rc *RunContext, cmd *cobra.Command, args []string) (err error)
|
||||
}
|
||||
|
||||
var dbase driver.Database
|
||||
dbase, err = rc.databases.Open(rc.Context, tblH.src)
|
||||
dbase, err = rc.databases.Open(cmd.Context(), tblH.src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = sqlDrvr.DropTable(rc.Context, dbase.DB(), tblH.tbl, false)
|
||||
err = sqlDrvr.DropTable(cmd.Context(), dbase.DB(), tblH.tbl, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -8,16 +8,18 @@ import (
|
||||
"github.com/neilotoole/sq/cli/buildinfo"
|
||||
)
|
||||
|
||||
func newVersionCmd() (*cobra.Command, runFunc) {
|
||||
func newVersionCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print sq version",
|
||||
RunE: execVersion,
|
||||
}
|
||||
|
||||
return cmd, execVersion
|
||||
return cmd
|
||||
}
|
||||
|
||||
func execVersion(rc *RunContext, cmd *cobra.Command, args []string) error {
|
||||
func execVersion(cmd *cobra.Command, args []string) error {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
rc.writers.fmt.Hilite.Fprintf(rc.Out, "sq %s", buildinfo.Version)
|
||||
|
||||
if len(buildinfo.Commit) > 0 {
|
||||
|
362
cli/completion.go
Normal file
362
cli/completion.go
Normal file
@ -0,0 +1,362 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/neilotoole/sq/libsq/source"
|
||||
)
|
||||
|
||||
// completionFunc is a shell completion function.
|
||||
type completionFunc func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
|
||||
|
||||
var (
|
||||
_ completionFunc = completeDriverType
|
||||
_ completionFunc = completeSLQ
|
||||
_ completionFunc = new(handleTableCompleter).complete
|
||||
)
|
||||
|
||||
// completeHandle is a completionFunc that suggests handles.
|
||||
// The max arg is the maximum number of completions. Set to 0
|
||||
// for no limit.
|
||||
func completeHandle(max int) completionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if max > 0 && len(args) >= max {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
handles := rc.Config.Sources.Handles()
|
||||
|
||||
return handles, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
|
||||
// completeSLQ is a completionFunc that completes SLQ queries.
|
||||
// The completion functionality is rudimentary: it only
|
||||
// completes the "table select" segment (that is, the @HANDLE.NAME)
|
||||
// segment.
|
||||
func completeSLQ(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
c := &handleTableCompleter{}
|
||||
return c.complete(cmd, args, toComplete)
|
||||
}
|
||||
|
||||
// completeDriverType is a completionFunc that suggests drivers.
|
||||
func completeDriverType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
if rc.databases == nil {
|
||||
err := rc.init()
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
}
|
||||
|
||||
drivers := rc.registry.Drivers()
|
||||
types := make([]string, len(drivers))
|
||||
for i, driver := range rc.registry.Drivers() {
|
||||
types[i] = string(driver.DriverMetadata().Type)
|
||||
}
|
||||
|
||||
return types, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// completeTblCopy is a completionFunc for the "tbl copy" command.
|
||||
func completeTblCopy(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// Example invocation:
|
||||
//
|
||||
// sq tbl copy @sakila_sl3.actor .new_table
|
||||
//
|
||||
// Note that the second arg can only be a table name (and
|
||||
// not a @HANDLE.TABLE), and it must also be a _new_ table
|
||||
// (because we can't copy over an existing table), thus
|
||||
// we only suggest "." for the second arg, forcing the user
|
||||
// to supply the rest of that new table name.
|
||||
switch len(args) {
|
||||
case 0:
|
||||
c := &handleTableCompleter{onlySQL: true}
|
||||
return c.complete(cmd, args, toComplete)
|
||||
case 1:
|
||||
return []string{"."}, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
|
||||
default:
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
}
|
||||
|
||||
// handleTableCompleter encapsulates completion of a handle
|
||||
// ("@sakila_sl3"), table (".actor"), or @HANDLE.TABLE
|
||||
// ("@sakila_sl3.actor"). Its complete method is a completionFunc.
|
||||
type handleTableCompleter struct {
|
||||
// onlySQL, when true, filters out non-SQL sources.
|
||||
onlySQL bool
|
||||
|
||||
// handleRequired, when true, means that only @HANDLE.TABLE
|
||||
// suggestions are offered. That is, naked .TABLE suggestions
|
||||
// will not be offered.
|
||||
handleRequired bool
|
||||
|
||||
// max indicates the maximum number of completions
|
||||
// to offer. Use 0 to indicate no limit. Frequently this
|
||||
// is set to 1 to if the command accepts only one argument.
|
||||
max int
|
||||
}
|
||||
|
||||
// complete is the completionFunc for handleTableCompleter.
|
||||
func (c *handleTableCompleter) complete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
rc := RunContextFrom(cmd.Context())
|
||||
if err := rc.init(); err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
// We don't want the user to wait around forever for
|
||||
// shell completion, so we set a timeout. Typically
|
||||
// this is something like 500ms.
|
||||
ctx, cancelFn := context.WithTimeout(cmd.Context(), rc.Config.Defaults.ShellCompletionTimeout)
|
||||
defer cancelFn()
|
||||
|
||||
if c.max > 0 && len(args) >= c.max {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
if toComplete == "" {
|
||||
if c.handleRequired {
|
||||
return c.completeHandle(ctx, rc, args, toComplete)
|
||||
}
|
||||
return c.completeEither(ctx, rc, args, toComplete)
|
||||
}
|
||||
|
||||
// There's some input. We expect the input to be of the
|
||||
// the form "@handle" or ".table". That is, the input should
|
||||
// start with either '@' or '.'.
|
||||
switch toComplete[0] {
|
||||
default:
|
||||
// User input was something other than '@' or '.'
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
case '@':
|
||||
return c.completeHandle(ctx, rc, args, toComplete)
|
||||
case '.':
|
||||
if c.handleRequired {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return c.completeTableOnly(ctx, rc, args, toComplete)
|
||||
}
|
||||
}
|
||||
|
||||
// completeTableOnly returns suggestions given input beginning with
|
||||
// a period. Effectively this is completion for tables in the
|
||||
// active src.
|
||||
func (c *handleTableCompleter) completeTableOnly(ctx context.Context, rc *RunContext, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
activeSrc := rc.Config.Sources.Active()
|
||||
if activeSrc == nil {
|
||||
rc.Log.Error("Active source is nil")
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(rc, activeSrc.Handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
if !isSQL {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
|
||||
tables, err := getTableNamesForHandle(ctx, rc, activeSrc.Handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
var suggestions []string
|
||||
for _, table := range tables {
|
||||
if strings.HasPrefix(table, toComplete[1:]) {
|
||||
suggestions = append(suggestions, "."+table)
|
||||
}
|
||||
}
|
||||
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// completeHandle returns suggestions given input beginning with
|
||||
// a '@'. The returned suggestions could be @HANDLE, or @HANDLE.TABLE.
|
||||
func (c *handleTableCompleter) completeHandle(ctx context.Context, rc *RunContext, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// We're dealing with a handle.
|
||||
|
||||
// But we could be dealing with just the handle ("@sakila_sl3")
|
||||
// or a @HANDLE.TABLE ("@sakila_sl3.actor").
|
||||
if strings.ContainsRune(toComplete, '.') {
|
||||
if strings.Count(toComplete, ".") > 1 {
|
||||
// Can only have one period
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
// It's a handle with a full handle and at least a
|
||||
// partial table name, such as "@sakila_sl3.fil"
|
||||
handle, partialTbl, err := source.ParseTableHandle(strings.TrimSuffix(toComplete, "."))
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(rc, handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if !isSQL {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
|
||||
tables, err := getTableNamesForHandle(ctx, rc, handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
var suggestions []string
|
||||
for _, table := range tables {
|
||||
if strings.HasPrefix(table, partialTbl) {
|
||||
suggestions = append(suggestions, handle+"."+table)
|
||||
}
|
||||
}
|
||||
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
handles := rc.Config.Sources.Handles()
|
||||
// Else, we're dealing with just a handle so far
|
||||
var matchingHandles []string
|
||||
for _, handle := range handles {
|
||||
if strings.HasPrefix(handle, toComplete) {
|
||||
if c.onlySQL {
|
||||
isSQL, err := handleIsSQLDriver(rc, handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
if !isSQL {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
matchingHandles = append(matchingHandles, handle)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(matchingHandles) {
|
||||
default:
|
||||
return matchingHandles, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
|
||||
case 0:
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
case 1:
|
||||
// Only one handle match, so we will present that complete
|
||||
// handle, plus a suggestion (@HANDLE.TABLE) for each of the tables
|
||||
// for that handle
|
||||
}
|
||||
|
||||
tables, err := getTableNamesForHandle(ctx, rc, matchingHandles[0])
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
suggestions := []string{matchingHandles[0]}
|
||||
for _, table := range tables {
|
||||
suggestions = append(suggestions, matchingHandles[0]+"."+table)
|
||||
}
|
||||
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
func (c *handleTableCompleter) completeEither(ctx context.Context, rc *RunContext, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// There's no input yet.
|
||||
// Therefore we want to return a union of all handles
|
||||
// plus the tables from the active source.
|
||||
activeSrc := rc.Config.Sources.Active()
|
||||
if activeSrc == nil {
|
||||
rc.Log.Error("Active source is nil")
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
var activeSrcTables []string
|
||||
isSQL, err := handleIsSQLDriver(rc, activeSrc.Handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
if !c.onlySQL || isSQL {
|
||||
activeSrcTables, err = getTableNamesForHandle(ctx, rc, activeSrc.Handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
}
|
||||
|
||||
var suggestions []string
|
||||
for _, table := range activeSrcTables {
|
||||
suggestions = append(suggestions, "."+table)
|
||||
}
|
||||
|
||||
for _, src := range rc.Config.Sources.Items() {
|
||||
if c.onlySQL {
|
||||
isSQL, err = handleIsSQLDriver(rc, src.Handle)
|
||||
if err != nil {
|
||||
rc.Log.Error(err)
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
if !isSQL {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
suggestions = append(suggestions, src.Handle)
|
||||
}
|
||||
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
|
||||
}
|
||||
|
||||
func handleIsSQLDriver(rc *RunContext, handle string) (bool, error) {
|
||||
src, err := rc.Config.Sources.Get(handle)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
driver, err := rc.registry.DriverFor(src.Type)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return driver.DriverMetadata().IsSQL, nil
|
||||
}
|
||||
|
||||
func getTableNamesForHandle(ctx context.Context, rc *RunContext, handle string) ([]string, error) {
|
||||
src, err := rc.Config.Sources.Get(handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := rc.databases.Open(ctx, src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
md, err := db.SourceMetadata(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return md.TableNames(), nil
|
||||
}
|
@ -36,11 +36,21 @@ type Ext struct {
|
||||
UserDrivers []*userdriver.DriverDef `yaml:"user_drivers" json:"user_drivers"`
|
||||
}
|
||||
|
||||
// Defaults contains sq default values.
|
||||
// Defaults contains default config values.
|
||||
type Defaults struct {
|
||||
Timeout time.Duration `yaml:"timeout" json:"timeout"`
|
||||
Format Format `yaml:"output_format" json:"output_format"`
|
||||
Header bool `yaml:"output_header" json:"output_header"`
|
||||
// Format is the default output format: json, table, etc.
|
||||
Format Format `yaml:"output_format" json:"output_format"`
|
||||
|
||||
// Header determines if a header should be printed (if relevant
|
||||
// for the output format).
|
||||
Header bool `yaml:"output_header" json:"output_header"`
|
||||
|
||||
// PingTimeout is the allowed time for a ping.
|
||||
PingTimeout time.Duration `yaml:"ping_timeout" json:"ping_timeout"`
|
||||
|
||||
// ShellCompletionTimeout is the time allowed for the shell
|
||||
// completion callback to execute.
|
||||
ShellCompletionTimeout time.Duration `yaml:"shell_completion_timeout" json:"shell_completion_timeout"`
|
||||
}
|
||||
|
||||
// New returns a config instance with default options set.
|
||||
@ -66,11 +76,15 @@ func initCfg(cfg *Config) {
|
||||
cfg.Defaults.Format = FormatTable
|
||||
}
|
||||
|
||||
if cfg.Defaults.Timeout == 0 {
|
||||
if cfg.Defaults.PingTimeout == 0 {
|
||||
// Probably should be setting this in the New function,
|
||||
// but we haven't yet defined cli's behavior wrt
|
||||
// a zero timeout. Does it mean no timeout?
|
||||
cfg.Defaults.Timeout = 10 * time.Second
|
||||
cfg.Defaults.PingTimeout = 10 * time.Second
|
||||
}
|
||||
|
||||
if cfg.Defaults.ShellCompletionTimeout == 0 {
|
||||
cfg.Defaults.ShellCompletionTimeout = time.Millisecond * 500
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/neilotoole/sq/cli/config"
|
||||
"github.com/neilotoole/sq/testh"
|
||||
"github.com/neilotoole/sq/testh/proj"
|
||||
)
|
||||
|
||||
@ -70,14 +71,21 @@ func TestFileStore_Load(t *testing.T) {
|
||||
fs := &config.YAMLFileStore{HookLoad: hookExpand}
|
||||
|
||||
for _, match := range good {
|
||||
fs.Path = match
|
||||
_, err = fs.Load()
|
||||
require.NoError(t, err, match)
|
||||
match := match
|
||||
t.Run(testh.Name(match), func(t *testing.T) {
|
||||
fs.Path = match
|
||||
_, err = fs.Load()
|
||||
require.NoError(t, err, match)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
for _, match := range bad {
|
||||
fs.Path = match
|
||||
_, err = fs.Load()
|
||||
require.Error(t, err, match)
|
||||
match := match
|
||||
t.Run(testh.Name(match), func(t *testing.T) {
|
||||
fs.Path = match
|
||||
_, err = fs.Load()
|
||||
require.Error(t, err, match)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
2
cli/config/testdata/bad.01.sq.yml
vendored
2
cli/config/testdata/bad.01.sq.yml
vendored
@ -1,2 +1,2 @@
|
||||
defaults:
|
||||
timeout: not_a_duration
|
||||
ping_timeout: not_a_duration
|
||||
|
2
cli/config/testdata/bad.08.sq.yml
vendored
Normal file
2
cli/config/testdata/bad.08.sq.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
defaults:
|
||||
shell_completion_timeout: not_a_duration
|
3
cli/config/testdata/good.01.sq.yml
vendored
3
cli/config/testdata/good.01.sq.yml
vendored
@ -1,5 +1,6 @@
|
||||
defaults:
|
||||
timeout: 10s
|
||||
ping_timeout: 10s
|
||||
shell_completion_timeout: 1s
|
||||
output_format: table
|
||||
output_header: true
|
||||
sources:
|
||||
|
@ -96,7 +96,7 @@ func (w *mdWriter) SourceMetadata(meta *source.Metadata) error {
|
||||
meta.Name,
|
||||
stringz.ByteSized(meta.Size, 1, ""),
|
||||
fmt.Sprintf("%d", len(meta.Tables)),
|
||||
meta.Location,
|
||||
source.RedactLocation(meta.Location),
|
||||
}
|
||||
} else {
|
||||
headers = []string{"HANDLE", "DRIVER", "NAME", "FQ NAME", "SIZE", "TABLES", "LOCATION"}
|
||||
@ -110,7 +110,7 @@ func (w *mdWriter) SourceMetadata(meta *source.Metadata) error {
|
||||
meta.FQName,
|
||||
stringz.ByteSized(meta.Size, 1, ""),
|
||||
fmt.Sprintf("%d", len(meta.Tables)),
|
||||
meta.Location,
|
||||
source.RedactLocation(meta.Location),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ func newTestRunCtx(log lg.Log) (rc *cli.RunContext, out, errOut *bytes.Buffer) {
|
||||
errOut = &bytes.Buffer{}
|
||||
|
||||
rc = &cli.RunContext{
|
||||
Context: context.Background(),
|
||||
Stdin: os.Stdin,
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
@ -102,11 +101,7 @@ func (ru *run) exec(args ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) > 0 && args[0] != "sq" {
|
||||
args = append([]string{"sq"}, args...)
|
||||
}
|
||||
|
||||
execErr := cli.ExecuteWith(ru.rc, args)
|
||||
execErr := cli.ExecuteWith(context.Background(), ru.rc, args)
|
||||
|
||||
if !ru.hushOutput {
|
||||
// We log sq's output now (before calling rc.Close) because
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/neilotoole/lg"
|
||||
@ -17,7 +18,7 @@ import (
|
||||
// mutate rc.Config.Sources as necessary. If no error
|
||||
// is returned, it is guaranteed that there's an active
|
||||
// source on the source set.
|
||||
func determineSources(rc *RunContext) error {
|
||||
func determineSources(ctx context.Context, rc *RunContext) error {
|
||||
cmd, srcs := rc.Cmd, rc.Config.Sources
|
||||
activeSrc, err := activeSrcFromFlagsOrConfig(cmd, srcs)
|
||||
if err != nil {
|
||||
@ -26,7 +27,7 @@ func determineSources(rc *RunContext) error {
|
||||
// Note: ^ activeSrc could still be nil
|
||||
|
||||
// check if there's input on stdin
|
||||
stdinSrc, err := checkStdinSource(rc)
|
||||
stdinSrc, err := checkStdinSource(ctx, rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -95,7 +96,7 @@ func activeSrcFromFlagsOrConfig(cmd *cobra.Command, srcs *source.Set) (*source.S
|
||||
// If there is, that pipe is inspected, and if it has recognizable
|
||||
// input, a new source instance with handle @stdin is constructed
|
||||
// and returned.
|
||||
func checkStdinSource(rc *RunContext) (*source.Source, error) {
|
||||
func checkStdinSource(ctx context.Context, rc *RunContext) (*source.Source, error) {
|
||||
cmd := rc.Cmd
|
||||
|
||||
f := rc.Stdin
|
||||
@ -140,7 +141,7 @@ func checkStdinSource(rc *RunContext) (*source.Source, error) {
|
||||
}
|
||||
|
||||
if typ == source.TypeNone {
|
||||
typ, err = rc.files.TypeStdin(rc.Context)
|
||||
typ, err = rc.files.TypeStdin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
stmt += " WHERE 0"
|
||||
}
|
||||
|
||||
affected, err := sqlz.ExecResult(ctx, db, stmt)
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
if err != nil {
|
||||
return 0, errz.Err(err)
|
||||
}
|
||||
@ -324,7 +324,7 @@ func (d *driveri) Truncate(ctx context.Context, src *source.Source, tbl string,
|
||||
return 0, errz.Append(err, errz.Err(tx.Rollback()))
|
||||
}
|
||||
|
||||
affected, err = sqlz.ExecResult(ctx, tx, fmt.Sprintf("TRUNCATE TABLE `%s`", tbl))
|
||||
affected, err = sqlz.ExecAffected(ctx, tx, fmt.Sprintf("TRUNCATE TABLE `%s`", tbl))
|
||||
if err != nil {
|
||||
return affected, errz.Append(err, errz.Err(tx.Rollback()))
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
stmt += " WITH NO DATA"
|
||||
}
|
||||
|
||||
affected, err := sqlz.ExecResult(ctx, db, stmt)
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
if err != nil {
|
||||
return 0, errz.Err(err)
|
||||
}
|
||||
|
@ -103,16 +103,27 @@ func (d *driveri) Truncate(ctx context.Context, src *source.Source, tbl string,
|
||||
return 0, errz.Err(err)
|
||||
}
|
||||
|
||||
affected, err = sqlz.ExecResult(ctx, tx, fmt.Sprintf("DELETE FROM %q", tbl))
|
||||
affected, err = sqlz.ExecAffected(ctx, tx, fmt.Sprintf("DELETE FROM %q", tbl))
|
||||
if err != nil {
|
||||
return affected, errz.Append(err, errz.Err(tx.Rollback()))
|
||||
}
|
||||
|
||||
if reset {
|
||||
_, err = sqlz.ExecResult(ctx, tx, "UPDATE sqlite_sequence SET seq = 0 WHERE name = ?", tbl)
|
||||
// First check that the sqlite_sequence table event exists. It
|
||||
// may not exist if there are no auto-increment columns?
|
||||
const q = `SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='sqlite_sequence'`
|
||||
var count int64
|
||||
err = tx.QueryRowContext(ctx, q).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, errz.Append(err, errz.Err(tx.Rollback()))
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
_, err = tx.ExecContext(ctx, "UPDATE sqlite_sequence SET seq = 0 WHERE name = ?", tbl)
|
||||
if err != nil {
|
||||
return 0, errz.Append(err, errz.Err(tx.Rollback()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affected, errz.Err(tx.Commit())
|
||||
@ -188,7 +199,7 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
}
|
||||
|
||||
stmt := fmt.Sprintf("INSERT INTO %q SELECT * FROM %q", toTable, fromTable)
|
||||
affected, err := sqlz.ExecResult(ctx, db, stmt)
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
if err != nil {
|
||||
return 0, errz.Err(err)
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (d *driveri) Truncate(ctx context.Context, src *source.Source, tbl string,
|
||||
}
|
||||
defer d.log.WarnIfFuncError(db.Close)
|
||||
|
||||
affected, err = sqlz.ExecResult(ctx, db, fmt.Sprintf("DELETE FROM %q", tbl))
|
||||
affected, err = sqlz.ExecAffected(ctx, db, fmt.Sprintf("DELETE FROM %q", tbl))
|
||||
if err != nil {
|
||||
return affected, errz.Wrapf(err, "truncate: failed to delete from %q", tbl)
|
||||
}
|
||||
@ -285,7 +285,7 @@ func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable
|
||||
stmt = fmt.Sprintf("SELECT TOP(0) * INTO %q FROM %q", toTable, fromTable)
|
||||
}
|
||||
|
||||
affected, err := sqlz.ExecResult(ctx, db, stmt)
|
||||
affected, err := sqlz.ExecAffected(ctx, db, stmt)
|
||||
if err != nil {
|
||||
return 0, errz.Err(err)
|
||||
}
|
||||
|
38
go.mod
38
go.mod
@ -1,60 +1,48 @@
|
||||
module github.com/neilotoole/sq
|
||||
|
||||
go 1.14
|
||||
go 1.15
|
||||
|
||||
// Using forked cobra for now because v1.1.3 does not pass Context
|
||||
// to valid args completion funcs. There's an open PR for
|
||||
// this: https://github.com/spf13/cobra/pull/1265
|
||||
replace github.com/spf13/cobra v1.1.3 => github.com/neilotoole/cobra v1.1.4-0.20210220092732-c11dbd416310
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 // indirect
|
||||
github.com/antlr/antlr4 v0.0.0-20191011202612-ad2bd05285ca
|
||||
github.com/aws/aws-sdk-go v1.12.10 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/buger/jsonparser v1.0.0
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
|
||||
github.com/c2h5oh/datasize v0.0.0-20170519143321-54516c931ae9
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible // indirect
|
||||
github.com/cpuguy83/go-md2man v1.0.10 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec
|
||||
github.com/djherbis/fscache v0.10.1
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/emirpasic/gods v1.9.0
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/go-ini/ini v1.30.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/h2non/filetype v1.1.0
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20170211013415-3573b8b52aa7 // indirect
|
||||
github.com/hashicorp/go-getter v0.0.0-20171007181130-2f449c791e6a
|
||||
github.com/hashicorp/go-version v0.0.0-20170914154128-fc61389e27c7 // indirect
|
||||
github.com/jackc/pgconn v1.5.0
|
||||
github.com/jackc/pgx/v4 v4.6.0
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 // indirect
|
||||
github.com/jondot/goweight v1.0.5 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/magefile/mage v1.9.0
|
||||
github.com/mattn/go-colorable v0.1.4
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-runewidth v0.0.4
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/mattn/go-zglob v0.0.3 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
|
||||
github.com/neilotoole/errgroup v0.1.5
|
||||
github.com/neilotoole/lg v0.3.0
|
||||
github.com/nlopes/slack v0.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/ryboe/q v1.0.12
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/segmentio/encoding v0.1.14
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.3
|
||||
github.com/spf13/cobra v1.1.3
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tbruyelle/hipchat-go v0.0.0-20160921153256-749fb9e14beb
|
||||
github.com/tealeg/xlsx/v2 v2.0.1
|
||||
github.com/testcontainers/testcontainers-go v0.5.0
|
||||
github.com/thoas/go-funk v0.7.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.4 // indirect
|
||||
github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
|
||||
go.uber.org/atomic v1.5.0
|
||||
go.uber.org/multierr v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||
@ -62,5 +50,5 @@ require (
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
|
||||
gopkg.in/djherbis/atime.v1 v1.0.0 // indirect
|
||||
gopkg.in/djherbis/stream.v1 v1.3.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
267
go.sum
267
go.sum
@ -1,45 +1,60 @@
|
||||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 h1:EBTWhcAX7rNQ80RLwLCpHZBBrJuzallFHnF+yMXo928=
|
||||
github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/antlr/antlr4 v0.0.0-20191011202612-ad2bd05285ca h1:QHbltbNkVcw97h4zA/L8gA4o3dJiFvBZ0gyZHrYXHbs=
|
||||
github.com/antlr/antlr4 v0.0.0-20191011202612-ad2bd05285ca/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aws/aws-sdk-go v1.12.10 h1:ihg0UOujHVcFciyc6zs/q5VLhoG1K+oDLqgpCxkAh04=
|
||||
github.com/aws/aws-sdk-go v1.12.10/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/buger/jsonparser v1.0.0 h1:etJTGF5ESxjI0Ic2UaLQs2LQQpa8G9ykQScukbh4L8A=
|
||||
github.com/buger/jsonparser v1.0.0/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/c2h5oh/datasize v0.0.0-20170519143321-54516c931ae9 h1:N6In6gI4jApKZ6F8QqeVgPti7612P5EdLISBNbjQ8tk=
|
||||
github.com/c2h5oh/datasize v0.0.0-20170519143321-54516c931ae9/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -47,6 +62,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec h1:NfhRXXFDPxcF5Cwo06DzeIaE7uuJtAUhsDwH3LNsjos=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9lk=
|
||||
github.com/djherbis/fscache v0.10.1/go.mod h1:yyPYtkNnnPXsW+81lAcQS6yab3G2CRfnPLotBvtbf0c=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE=
|
||||
@ -57,22 +74,22 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d h1:lDrio3iIdNb0Gw9CgH7cQF+iuB5mOOjdJ9ERNJCBgb4=
|
||||
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo=
|
||||
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
|
||||
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-ini/ini v1.30.0 h1:bcFeUQUA+99t1cZPXmtc7HpGv2KTlZGIFeBDWQh2DRw=
|
||||
github.com/go-ini/ini v1.30.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
@ -84,39 +101,69 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/h2non/filetype v1.1.0 h1:Or/gjocJrJRNK/Cri/TDEKFjAR+cfG6eK65NGYB6gBA=
|
||||
github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20170211013415-3573b8b52aa7 h1:67fHcS+inUoiIqWCKIqeDuq2AlPHNHPiTqp97LdQ+bc=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20170211013415-3573b8b52aa7/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v0.0.0-20171007181130-2f449c791e6a h1:deqk3CV92a9CYhyfYjIJPAB2X4/vheVghmoBCno6WQM=
|
||||
github.com/hashicorp/go-getter v0.0.0-20171007181130-2f449c791e6a/go.mod h1:6rdJFnhkXnzGOJbvkrdv4t9nLwKcVA+tmbQeUlkIzrU=
|
||||
github.com/hashicorp/go-version v0.0.0-20170914154128-fc61389e27c7 h1:Tijq+ZHupzK8WfomfH2s5dpKkpZd2TcN2i1LDbzWbwk=
|
||||
github.com/hashicorp/go-version v0.0.0-20170914154128-fc61389e27c7/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
@ -163,17 +210,18 @@ github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oA
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jondot/goweight v1.0.5 h1:aRpnyj1G8BLLNhem8xezuuV0GlFz4G11e3/UtBU/FlQ=
|
||||
github.com/jondot/goweight v1.0.5/go.mod h1:3PRcpOwkyspe1t4+KCNgauas+aNDTSSCwZ6AQ4kDD/A=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
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/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
@ -192,10 +240,13 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
|
||||
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
@ -208,25 +259,31 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-zglob v0.0.0-20180803001819-2ea3427bfa53 h1:tGfIHhDghvEnneeRhODvGYOt305TPwingKt6p90F4MU=
|
||||
github.com/mattn/go-zglob v0.0.0-20180803001819-2ea3427bfa53/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
github.com/mattn/go-zglob v0.0.3 h1:6Ry4EYsScDyt5di4OI6xw1bYhOqfE5S33Z1OPy+d+To=
|
||||
github.com/mattn/go-zglob v0.0.3/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/neilotoole/cobra v1.1.4-0.20210220092732-c11dbd416310 h1:++ilwBgxD5woFaMRfHmbJDbZ4mpoJT/ghS2I5pjrn+A=
|
||||
github.com/neilotoole/cobra v1.1.4-0.20210220092732-c11dbd416310/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/neilotoole/errgroup v0.1.5 h1:DxEGoIfFm5ooGicidR+okiHjoOaGRKFaSxDPVZuuu2I=
|
||||
github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE=
|
||||
github.com/neilotoole/lg v0.3.0 h1:2/IESY8l903AeK9nvH3AWVI/p8up+8wmKWIuts7PpxY=
|
||||
github.com/neilotoole/lg v0.3.0/go.mod h1:CUHyAinxegpXWV2uPbGP8R3OzRMlAd78YxtA9xiOeFA=
|
||||
github.com/nlopes/slack v0.1.0 h1:YnVhdQvWT/m0TDh3VNpSoCBDlD7Y4pz1qUqb/NrNyUs=
|
||||
github.com/nlopes/slack v0.1.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@ -238,6 +295,7 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
@ -246,36 +304,55 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryboe/q v1.0.12 h1:Ehx4fAUEaZ5KW9Cf9w+ShQ41r5Znc5076jPdnqbfZ3o=
|
||||
github.com/ryboe/q v1.0.12/go.mod h1:6xM6Lm3ZAh5H8d85zLohckSJcqIjJspf1gGkWWS8YGs=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/encoding v0.1.14 h1:BfnglNbNRohLaBLf93uP5/IwKqeWrezXK/g6IRnj75c=
|
||||
github.com/segmentio/encoding v0.1.14/go.mod h1:RWhr02uzMB9gQC1x+MfYxedtmBibb9cZ6Vv9VxRSSbw=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
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=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
@ -287,25 +364,23 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tbruyelle/hipchat-go v0.0.0-20160921153256-749fb9e14beb h1:mb7xv0kx9XpGsLy5kCCa6+3HqSj495cEBQNMgljqZ48=
|
||||
github.com/tbruyelle/hipchat-go v0.0.0-20160921153256-749fb9e14beb/go.mod h1:CJEWrlDz1qHCF/nywogFd3AqHUWbKCdpu9pSAdf1OzY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tealeg/xlsx/v2 v2.0.1 h1:RP+VEscpPFjH2FnpKh1p9HVLAk1htqb9Urcxi2AU1ns=
|
||||
github.com/tealeg/xlsx/v2 v2.0.1/go.mod h1:l9GvhCCjdaIGkAyZcFedDALcYcXUOei55f6umRMOz9c=
|
||||
github.com/testcontainers/testcontainers-go v0.5.0 h1:u7jCdf130QHBY5KK9xkFzZpkep24Rtl8HdWscMO9H/8=
|
||||
github.com/testcontainers/testcontainers-go v0.5.0/go.mod h1:BXwe1JilTOLT8cmVyPMDbIw7e+8UCGeAhxjBwguG5wQ=
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713 h1:knaxjm6QMbUMNvuaSnJZmw0gRX4V/79JVUQiziJGM84=
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713/go.mod h1:mlR+dHGb+4YgXkf13rkQTuzrneeHANxOm6+ZnEV9HsA=
|
||||
github.com/thoas/go-funk v0.7.0 h1:GmirKrs6j6zJbhJIficOsz2aAI7700KsU/5YrdHRM1Y=
|
||||
github.com/thoas/go-funk v0.7.0/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ulikunitz/xz v0.5.4 h1:zATC2OoZ8H1TZll3FpbX+ikwmadbO699PE06cIkm9oU=
|
||||
github.com/ulikunitz/xz v0.5.4/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3 h1:NC3CI7do3KHtiuYhk1CdS9V2qS3jNa7Fs2Afcnnt+IE=
|
||||
github.com/xo/dburl v0.0.0-20200124232849-e9ec94f52bc3/go.mod h1:A47W3pdWONaZmXuLZgfKLAVgUY0qvfTRM5vVDKS40S4=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
@ -321,6 +396,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@ -328,6 +404,7 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@ -335,36 +412,75 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+v
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
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/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=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
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 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
@ -372,32 +488,67 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -411,15 +562,25 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0=
|
||||
gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
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/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
@ -42,9 +42,9 @@ type DB interface {
|
||||
Preparer
|
||||
}
|
||||
|
||||
// ExecResult invokes db.ExecContext, returning the count of rows
|
||||
// ExecAffected invokes db.ExecContext, returning the count of rows
|
||||
// affected and any error.
|
||||
func ExecResult(ctx context.Context, db Execer, query string, args ...interface{}) (affected int64, err error) {
|
||||
func ExecAffected(ctx context.Context, db Execer, query string, args ...interface{}) (affected int64, err error) {
|
||||
var res sql.Result
|
||||
res, err = db.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
|
@ -135,7 +135,7 @@ type SQLDriver interface {
|
||||
// must honor the table name and column names and kinds from tblDef.
|
||||
CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.TableDef) error
|
||||
|
||||
// TableExists returns true if there's an exist table tbl in db.
|
||||
// TableExists returns true if there's an existing table tbl in db.
|
||||
TableExists(ctx context.Context, db sqlz.DB, tbl string) (bool, error)
|
||||
|
||||
// CopyTable copies fromTable into a new table toTable.
|
||||
|
@ -90,14 +90,6 @@ func (s *Set) Add(src *Source) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IndexOf returns the index of handle in s.
|
||||
func (s *Set) IndexOf(handle string) (int, *Source) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.indexOf(handle)
|
||||
}
|
||||
|
||||
// Exists returns true if handle already exists in the set.
|
||||
func (s *Set) Exists(handle string) bool {
|
||||
s.mu.Lock()
|
||||
@ -263,6 +255,19 @@ func (s *Set) Remove(handle string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handles returns the set of source handles.
|
||||
func (s *Set) Handles() []string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
handles := make([]string, len(s.data.Items))
|
||||
for i := range s.data.Items {
|
||||
handles[i] = s.data.Items[i].Handle
|
||||
}
|
||||
|
||||
return handles
|
||||
}
|
||||
|
||||
// VerifySetIntegrity verifies the internal state of s.
|
||||
// Typically this func is invoked after s has been loaded
|
||||
// from config, verifying that the config is not corrupt.
|
||||
|
@ -67,8 +67,13 @@ func (s *Source) RedactedLocation() string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
loc := s.Location
|
||||
return RedactLocation(s.Location)
|
||||
}
|
||||
|
||||
// RedactLocation returns a redacted version of the source
|
||||
// location loc, with the password component (if any) of
|
||||
// the location masked.
|
||||
func RedactLocation(loc string) string {
|
||||
switch {
|
||||
case loc == "":
|
||||
return ""
|
||||
|
Loading…
Reference in New Issue
Block a user