Options refactoring (#395)

* options.Opt now has a separate options.Flag field.
This commit is contained in:
Neil O'Toole 2024-02-09 17:06:07 -07:00 committed by GitHub
parent fabc46c758
commit 07cbe46bde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 224 additions and 250 deletions

View File

@ -10,15 +10,15 @@ Breaking changes are annotated with ☢️, and alpha/beta features with 🐥.
## [v0.47.4] - UPCOMING ## [v0.47.4] - UPCOMING
Minor release with changes to flags. Patch release with changes to flags.
See the earlier [`v0.47.0`](https://github.com/neilotoole/sq/releases/tag/v0.47.0) See the earlier [`v0.47.0`](https://github.com/neilotoole/sq/releases/tag/v0.47.0)
release for recent headline features. release for recent headline features.
### Added ### Added
- By default, `sq` prints source locations with the password redacted. This is a sensible default, but - By default, `sq` prints source locations with the password redacted. This is a sensible default, but
there are legitimate reasons to access the unredacted connection string. There's a new there are legitimate reasons to access the unredacted connection string. Thus a new
global flag `--no-redact` for that (and a corresponding [`redact`](https://sq.io/docs/config#redact) config option). global flag `--no-redact` (and a corresponding [`redact`](https://sq.io/docs/config#redact) config option).
```shell ```shell
# Default behavior: password is redacted # Default behavior: password is redacted
@ -30,6 +30,11 @@ release for recent headline features.
@sakila/pg12 postgres postgres://sakila:p_ssW0rd@192.168.50.132/sakila @sakila/pg12 postgres postgres://sakila:p_ssW0rd@192.168.50.132/sakila
``` ```
- Previously, if an error occurred when [`verbose`](https://sq.io/docs/config#verbose) was true,
and [`error.format`](https://sq.io/docs/config#errorformat) was `text`, `sq` would print a stack trace
to `stderr`. This was poor default behavior, flooding the user terminal, so the default is now no stack trace.
To restore the previous behavior, use the new `-E` (`--error.stack`) flag, or set the [`error.stack`](https://sq.io/docs/config#errorstack) config option.
### Changed ### Changed

View File

@ -26,7 +26,7 @@ import (
"github.com/neilotoole/sq/libsq/source/location" "github.com/neilotoole/sq/libsq/source/location"
) )
func newSrcAddCmd() *cobra.Command { //nolint:funlen func newSrcAddCmd() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "add [--handle @HANDLE] LOCATION", Use: "add [--handle @HANDLE] LOCATION",
RunE: execSrcAdd, RunE: execSrcAdd,
@ -172,12 +172,9 @@ More examples:
cmd.Flags().BoolP(flag.AddActive, flag.AddActiveShort, false, flag.AddActiveUsage) cmd.Flags().BoolP(flag.AddActive, flag.AddActiveShort, false, flag.AddActiveUsage)
addOptionFlag(cmd.Flags(), driver.OptIngestHeader) addOptionFlag(cmd.Flags(), driver.OptIngestHeader)
// cmd.Flags().Bool(flag.IngestHeader, false, flag.IngestHeaderUsage)
addOptionFlag(cmd.Flags(), csv.OptEmptyAsNull) addOptionFlag(cmd.Flags(), csv.OptEmptyAsNull)
addOptionFlag(cmd.Flags(), csv.OptDelim) addOptionFlag(cmd.Flags(), csv.OptDelim)
// cmd.Flags().Bool(flag.CSVEmptyAsNull, true, flag.CSVEmptyAsNullUsage) panicOn(cmd.RegisterFlagCompletionFunc(csv.OptDelim.Flag().Name, completeStrings(-1, csv.NamedDelims()...)))
// cmd.Flags().String(flag.CSVDelim, flag.CSVDelimDefault, flag.CSVDelimUsage)
panicOn(cmd.RegisterFlagCompletionFunc(csv.OptDelim.Flag(), completeStrings(-1, csv.NamedDelims()...)))
return cmd return cmd
} }

View File

@ -18,8 +18,7 @@ import (
var OptDiffNumLines = options.NewInt( var OptDiffNumLines = options.NewInt(
"diff.lines", "diff.lines",
"unified", &options.Flag{Name: "unified", Short: 'U'},
'U',
3, 3,
"Generate diffs with <n> lines of context", "Generate diffs with <n> lines of context",
`Generate diffs with <n> lines of context, where n >= 0.`, `Generate diffs with <n> lines of context, where n >= 0.`,
@ -28,8 +27,7 @@ var OptDiffNumLines = options.NewInt(
var OptDiffDataFormat = format.NewOpt( var OptDiffDataFormat = format.NewOpt(
"diff.data.format", "diff.data.format",
"format", &options.Flag{Name: "format", Short: 'f'},
'f',
format.Text, format.Text,
func(f format.Format) error { func(f format.Format) error {
switch f { //nolint:exhaustive switch f { //nolint:exhaustive
@ -187,7 +185,7 @@ The default (3) can be changed via:
} }
panicOn(cmd.RegisterFlagCompletionFunc( panicOn(cmd.RegisterFlagCompletionFunc(
OptDiffDataFormat.Flag(), OptDiffDataFormat.Flag().Name,
completeStrings(-1, stringz.Strings(diffFormats)...), completeStrings(-1, stringz.Strings(diffFormats)...),
)) ))

View File

@ -26,8 +26,7 @@ import (
// operations. // operations.
var OptPingCmdTimeout = options.NewDuration( var OptPingCmdTimeout = options.NewDuration(
"ping.timeout", "ping.timeout",
"", nil,
0,
time.Second*10, time.Second*10,
"ping command timeout duration", "ping command timeout duration",
"How long the ping command waits before timeout occurs. Example: 500ms or 2m10s.", "How long the ping command waits before timeout occurs. Example: 500ms or 2m10s.",
@ -38,7 +37,6 @@ func newPingCmd() *cobra.Command {
Use: "ping [@HANDLE|GROUP]*", Use: "ping [@HANDLE|GROUP]*",
RunE: execPing, RunE: execPing,
ValidArgsFunction: completeHandleOrGroup, ValidArgsFunction: completeHandleOrGroup,
Short: "Ping data sources", Short: "Ping data sources",
Long: `Ping data sources (or groups of sources) to check connection health. Long: `Ping data sources (or groups of sources) to check connection health.
If no arguments provided, the active data source is pinged. Otherwise, ping If no arguments provided, the active data source is pinged. Otherwise, ping

View File

@ -111,12 +111,12 @@ See docs and more: https://sq.io`,
cmd.PersistentFlags().String(flag.Config, "", flag.ConfigUsage) cmd.PersistentFlags().String(flag.Config, "", flag.ConfigUsage)
addOptionFlag(cmd.PersistentFlags(), OptLogEnabled) addOptionFlag(cmd.PersistentFlags(), OptLogEnabled)
panicOn(cmd.RegisterFlagCompletionFunc(OptLogEnabled.Flag(), completeBool)) panicOn(cmd.RegisterFlagCompletionFunc(OptLogEnabled.Flag().Name, completeBool))
addOptionFlag(cmd.PersistentFlags(), OptLogFile) addOptionFlag(cmd.PersistentFlags(), OptLogFile)
addOptionFlag(cmd.PersistentFlags(), OptLogLevel) addOptionFlag(cmd.PersistentFlags(), OptLogLevel)
panicOn(cmd.RegisterFlagCompletionFunc(OptLogLevel.Flag(), completeStrings( panicOn(cmd.RegisterFlagCompletionFunc(OptLogLevel.Flag().Name, completeStrings(
1, 1,
slog.LevelDebug.String(), slog.LevelDebug.String(),
slog.LevelInfo.String(), slog.LevelInfo.String(),
@ -125,11 +125,14 @@ See docs and more: https://sq.io`,
))) )))
addOptionFlag(cmd.PersistentFlags(), OptLogFormat) addOptionFlag(cmd.PersistentFlags(), OptLogFormat)
panicOn(cmd.RegisterFlagCompletionFunc(OptLogFormat.Flag(), completeStrings( panicOn(cmd.RegisterFlagCompletionFunc(OptLogFormat.Flag().Name, completeStrings(
1, 1,
string(format.Text), string(format.Text),
string(format.JSON), string(format.JSON),
))) )))
addOptionFlag(cmd.PersistentFlags(), OptErrorFormat)
addOptionFlag(cmd.PersistentFlags(), OptErrorStack)
return cmd return cmd
} }

View File

@ -325,12 +325,12 @@ func addTextFormatFlags(cmd *cobra.Command) {
func addQueryCmdFlags(cmd *cobra.Command) { func addQueryCmdFlags(cmd *cobra.Command) {
addOptionFlag(cmd.Flags(), OptFormat) addOptionFlag(cmd.Flags(), OptFormat)
panicOn(cmd.RegisterFlagCompletionFunc( panicOn(cmd.RegisterFlagCompletionFunc(
OptFormat.Flag(), OptFormat.Flag().Name,
completeStrings(-1, stringz.Strings(format.All())...), completeStrings(-1, stringz.Strings(format.All())...),
)) ))
addResultFormatFlags(cmd) addResultFormatFlags(cmd)
cmd.MarkFlagsMutuallyExclusive(append( cmd.MarkFlagsMutuallyExclusive(append(
[]string{OptFormat.Flag()}, []string{OptFormat.Flag().Name},
flag.OutputFormatFlags..., flag.OutputFormatFlags...,
)...) )...)

View File

@ -122,7 +122,7 @@ func TestCmdSQL_SelectFromUserDriver(t *testing.T) {
func TestCmdSQL_StdinQuery(t *testing.T) { func TestCmdSQL_StdinQuery(t *testing.T) {
t.Parallel() t.Parallel()
flagIngestHeader := driver.OptIngestHeader.Flag() flagIngestHeader := driver.OptIngestHeader.Flag().Name
testCases := []struct { testCases := []struct {
fpath string fpath string

View File

@ -24,8 +24,7 @@ import (
var OptShellCompletionTimeout = options.NewDuration( var OptShellCompletionTimeout = options.NewDuration(
"shell-completion.timeout", "shell-completion.timeout",
"", nil,
0,
time.Millisecond*500, time.Millisecond*500,
"Shell completion timeout", "Shell completion timeout",
`How long shell completion should wait before giving up. This can become relevant `How long shell completion should wait before giving up. This can become relevant
@ -35,9 +34,7 @@ tables in a source.`,
var OptShellCompletionLog = options.NewBool( var OptShellCompletionLog = options.NewBool(
"shell-completion.log", "shell-completion.log",
"", nil,
false,
0,
false, false,
"Enable logging of shell completion activity", "Enable logging of shell completion activity",
`Enable logging of shell completion activity. This is really only useful for `Enable logging of shell completion activity. This is really only useful for
@ -50,9 +47,7 @@ timeout triggers logging of errors.`,
var OptShellCompletionGroupFilter = options.NewBool( var OptShellCompletionGroupFilter = options.NewBool(
"shell-completion.group-filter", "shell-completion.group-filter",
"", nil,
false,
0,
true, true,
"Shell completion initial source suggestions from active group only", "Shell completion initial source suggestions from active group only",
`When true, shell completion initially suggests only sources within the active `When true, shell completion initially suggests only sources within the active

View File

@ -75,8 +75,7 @@ func (DiscardStore) Location() string {
// OptConfigLockTimeout is the time allowed to acquire the config lock. // OptConfigLockTimeout is the time allowed to acquire the config lock.
var OptConfigLockTimeout = options.NewDuration( var OptConfigLockTimeout = options.NewDuration(
"config.lock.timeout", "config.lock.timeout",
"", nil,
0,
time.Second*5, time.Second*5,
"Wait timeout to acquire config lock", "Wait timeout to acquire config lock",
`Wait timeout to acquire the config lock (which prevents multiple sq instances `Wait timeout to acquire the config lock (which prevents multiple sq instances

View File

@ -28,9 +28,7 @@ import (
var ( var (
OptLogEnabled = options.NewBool( OptLogEnabled = options.NewBool(
"log", "log",
"", nil,
false,
0,
false, false,
"Enable logging", "Enable logging",
"Enable logging.", "Enable logging.",
@ -38,8 +36,7 @@ var (
OptLogFile = options.NewString( OptLogFile = options.NewString(
"log.file", "log.file",
"", nil,
0,
getDefaultLogFilePath(), getDefaultLogFilePath(),
nil, nil,
"Log file path", "Log file path",
@ -55,8 +52,7 @@ var (
OptLogFormat = format.NewOpt( OptLogFormat = format.NewOpt(
"log.format", "log.format",
"", nil,
0,
format.Text, format.Text,
func(f format.Format) error { func(f format.Format) error {
if f == format.Text || f == format.JSON { if f == format.Text || f == format.JSON {
@ -65,7 +61,7 @@ var (
return errz.Errorf("option {log.format} allows only %q or %q", format.Text, format.JSON) return errz.Errorf("option {log.format} allows only %q or %q", format.Text, format.JSON)
}, },
"Log output format", "Log output format (text or json)",
fmt.Sprintf( fmt.Sprintf(
`Log output format. Allowed formats are %q (human-friendly) or %q.`, format.Text, format.JSON), `Log output format. Allowed formats are %q (human-friendly) or %q.`, format.Text, format.JSON),
) )
@ -216,7 +212,7 @@ func getLogEnabled(ctx context.Context, osArgs []string, cfg *config.Config) boo
bootLog := lg.FromContext(ctx) bootLog := lg.FromContext(ctx)
var enabled bool var enabled bool
flg := OptLogEnabled.Flag() flg := OptLogEnabled.Flag().Name
val, ok, err := getBootstrapFlagValue(flg, "", OptLogEnabled.Usage(), osArgs) val, ok, err := getBootstrapFlagValue(flg, "", OptLogEnabled.Usage(), osArgs)
if err != nil { if err != nil {
bootLog.Warn("Reading log 'enabled' from flag", lga.Flag, flg, lga.Err, err) bootLog.Warn("Reading log 'enabled' from flag", lga.Flag, flg, lga.Err, err)
@ -275,7 +271,7 @@ func getLogEnabled(ctx context.Context, osArgs []string, cfg *config.Config) boo
func getLogLevel(ctx context.Context, osArgs []string, cfg *config.Config) slog.Level { func getLogLevel(ctx context.Context, osArgs []string, cfg *config.Config) slog.Level {
bootLog := lg.FromContext(ctx) bootLog := lg.FromContext(ctx)
flg := OptLogLevel.Flag() flg := OptLogLevel.Flag().Name
val, ok, err := getBootstrapFlagValue(flg, "", OptLogLevel.Usage(), osArgs) val, ok, err := getBootstrapFlagValue(flg, "", OptLogLevel.Usage(), osArgs)
if err != nil { if err != nil {
bootLog.Warn("Reading log level from flag", lga.Flag, flg, lga.Err, err) bootLog.Warn("Reading log level from flag", lga.Flag, flg, lga.Err, err)
@ -320,7 +316,7 @@ func getLogLevel(ctx context.Context, osArgs []string, cfg *config.Config) slog.
func getLogFormat(ctx context.Context, osArgs []string, cfg *config.Config) format.Format { func getLogFormat(ctx context.Context, osArgs []string, cfg *config.Config) format.Format {
bootLog := lg.FromContext(ctx) bootLog := lg.FromContext(ctx)
flg := OptLogFormat.Flag() flg := OptLogFormat.Flag().Name
val, ok, err := getBootstrapFlagValue(flg, "", OptLogFormat.Usage(), osArgs) val, ok, err := getBootstrapFlagValue(flg, "", OptLogFormat.Usage(), osArgs)
if err != nil { if err != nil {
bootLog.Warn("Error reading log format from flag", lga.Flag, flg, lga.Err, err) bootLog.Warn("Error reading log format from flag", lga.Flag, flg, lga.Err, err)
@ -373,7 +369,7 @@ func getLogFormat(ctx context.Context, osArgs []string, cfg *config.Config) form
func getLogFilePath(ctx context.Context, osArgs []string, cfg *config.Config) string { func getLogFilePath(ctx context.Context, osArgs []string, cfg *config.Config) string {
bootLog := lg.FromContext(ctx) bootLog := lg.FromContext(ctx)
flg := OptLogFile.Flag() flg := OptLogFile.Flag().Name
fp, ok, err := getBootstrapFlagValue(flg, "", OptLogFile.Usage(), osArgs) fp, ok, err := getBootstrapFlagValue(flg, "", OptLogFile.Usage(), osArgs)
if err != nil { if err != nil {
bootLog.Warn("Reading log file from flag", lga.Flag, flg, lga.Err, err) bootLog.Warn("Reading log file from flag", lga.Flag, flg, lga.Err, err)
@ -426,7 +422,7 @@ var _ options.Opt = LogLevelOpt{}
// NewLogLevelOpt returns a new LogLevelOpt instance. // NewLogLevelOpt returns a new LogLevelOpt instance.
func NewLogLevelOpt(key string, defaultVal slog.Level, usage, help string) LogLevelOpt { func NewLogLevelOpt(key string, defaultVal slog.Level, usage, help string) LogLevelOpt {
opt := options.NewBaseOpt(key, "", 0, usage, help) opt := options.NewBaseOpt(key, nil, usage, help)
return LogLevelOpt{BaseOpt: opt, defaultVal: defaultVal} return LogLevelOpt{BaseOpt: opt, defaultVal: defaultVal}
} }

View File

@ -30,7 +30,7 @@ import (
func getOptionsFromFlags(flags *pflag.FlagSet, reg *options.Registry) (options.Options, error) { func getOptionsFromFlags(flags *pflag.FlagSet, reg *options.Registry) (options.Options, error) {
o := options.Options{} o := options.Options{}
err := reg.Visit(func(opt options.Opt) error { err := reg.Visit(func(opt options.Opt) error {
f := flags.Lookup(opt.Flag()) f := flags.Lookup(opt.Flag().Name)
if f == nil { if f == nil {
return nil return nil
} }
@ -47,12 +47,12 @@ func getOptionsFromFlags(flags *pflag.FlagSet, reg *options.Registry) (options.O
if bOpt, ok := opt.(options.Bool); ok { if bOpt, ok := opt.(options.Bool); ok {
// Special handling for bool, because // Special handling for bool, because
// the flag value could be inverted. // the flag value could be inverted.
val, err := flags.GetBool(bOpt.Flag()) val, err := flags.GetBool(bOpt.Flag().Name)
if err != nil { if err != nil {
return errz.Err(err) return errz.Err(err)
} }
if bOpt.FlagInverted() { if bOpt.Flag().Invert {
val = !val val = !val
} }
o[bOpt.Key()] = val o[bOpt.Key()] = val
@ -154,6 +154,7 @@ func RegisterDefaultOpts(reg *options.Registry) {
reg.Add( reg.Add(
OptFormat, OptFormat,
OptErrorFormat, OptErrorFormat,
OptErrorStack,
OptDatetimeFormat, OptDatetimeFormat,
OptDatetimeFormatAsNumber, OptDatetimeFormatAsNumber,
OptDateFormat, OptDateFormat,
@ -242,36 +243,37 @@ func filterOptionsForSrc(typ drivertype.Type, opts ...options.Opt) []options.Opt
// addOptionFlag adds a flag derived from opt to flags, returning the // addOptionFlag adds a flag derived from opt to flags, returning the
// flag name used. // flag name used.
func addOptionFlag(flags *pflag.FlagSet, opt options.Opt) (key string) { func addOptionFlag(flags *pflag.FlagSet, opt options.Opt) (key string) {
key = opt.Flag() flg := opt.Flag()
key = flg.Name
switch opt := opt.(type) { switch opt := opt.(type) {
case options.Int: case options.Int:
if opt.Short() == 0 { if flg.Short == 0 {
flags.Int(key, opt.Default(), opt.Usage()) flags.Int(key, opt.Default(), flg.Usage)
return key return key
} }
flags.IntP(key, string(opt.Short()), opt.Default(), opt.Usage()) flags.IntP(key, string(flg.Short), opt.Default(), flg.Usage)
return key return key
case options.Bool: case options.Bool:
defVal := opt.Default() defVal := opt.Default()
if opt.FlagInverted() { if flg.Invert {
defVal = !defVal defVal = !defVal
} }
if opt.Short() == 0 { if flg.Short == 0 {
flags.Bool(key, defVal, opt.Usage()) flags.Bool(key, defVal, flg.Usage)
return key return key
} }
flags.BoolP(key, string(opt.Short()), defVal, opt.Usage()) flags.BoolP(key, string(flg.Short), defVal, flg.Usage)
return key return key
case options.Duration: case options.Duration:
if opt.Short() == 0 { if flg.Short == 0 {
flags.Duration(key, opt.Default(), opt.Usage()) flags.Duration(key, opt.Default(), flg.Usage)
return key return key
} }
flags.DurationP(key, string(opt.Short()), opt.Get(nil), opt.Usage()) flags.DurationP(key, string(flg.Short), opt.Get(nil), flg.Usage)
default: default:
// Treat as string // Treat as string
} }
@ -281,12 +283,12 @@ func addOptionFlag(flags *pflag.FlagSet, opt options.Opt) (key string) {
defVal = fmt.Sprintf("%v", v) defVal = fmt.Sprintf("%v", v)
} }
if opt.Short() == 0 { if flg.Short == 0 {
flags.String(key, defVal, opt.Usage()) flags.String(key, defVal, flg.Usage)
return key return key
} }
flags.StringP(key, string(opt.Short()), defVal, opt.Usage()) flags.StringP(key, string(flg.Short), defVal, flg.Usage)
return key return key
} }

View File

@ -11,15 +11,12 @@ import (
) )
func TestRegisterDefaultOpts(t *testing.T) { func TestRegisterDefaultOpts(t *testing.T) {
log := lgt.New(t)
reg := &options.Registry{} reg := &options.Registry{}
log.Debug("options.Registry (before)", "reg", reg)
cli.RegisterDefaultOpts(reg) cli.RegisterDefaultOpts(reg)
log.Debug("options.Registry (after)", "reg", reg) lgt.New(t).Debug("options.Registry (after)", "reg", reg)
keys := reg.Keys() keys := reg.Keys()
require.Len(t, keys, 53) require.Len(t, keys, 54)
for _, opt := range reg.Opts() { for _, opt := range reg.Opts() {
opt := opt opt := opt
@ -30,7 +27,8 @@ func TestRegisterDefaultOpts(t *testing.T) {
require.NotNil(t, opt.DefaultAny()) require.NotNil(t, opt.DefaultAny())
require.Equal(t, opt.GetAny(nil), opt.DefaultAny()) require.Equal(t, opt.GetAny(nil), opt.DefaultAny())
require.NotEmpty(t, opt.Usage()) require.NotEmpty(t, opt.Usage())
require.True(t, opt.Short() >= 0) require.NotEmpty(t, opt.Flag().Usage)
require.True(t, opt.Flag().Short >= 0)
require.Equal(t, opt.Key(), opt.String()) require.Equal(t, opt.Key(), opt.String())
require.NotEmpty(t, opt.Help()) require.NotEmpty(t, opt.Help())
}) })

View File

@ -38,9 +38,7 @@ import (
var ( var (
OptPrintHeader = options.NewBool( OptPrintHeader = options.NewBool(
"header", "header",
"", nil,
false,
0,
true, true,
"Print header row", "Print header row",
`Controls whether a header row is printed. This applies only to certain formats, `Controls whether a header row is printed. This applies only to certain formats,
@ -50,8 +48,7 @@ such as "text" or "csv".`,
OptFormat = format.NewOpt( OptFormat = format.NewOpt(
"format", "format",
"format", &options.Flag{Short: 'f'},
'f',
format.Text, format.Text,
nil, nil,
"Specify output format", "Specify output format",
@ -66,8 +63,7 @@ command, sq falls back to "text". Available formats:
OptErrorFormat = format.NewOpt( OptErrorFormat = format.NewOpt(
"error.format", "error.format",
"", nil,
0,
format.Text, format.Text,
func(f format.Format) error { func(f format.Format) error {
if f == format.Text || f == format.JSON { if f == format.Text || f == format.JSON {
@ -80,11 +76,19 @@ command, sq falls back to "text". Available formats:
fmt.Sprintf(`The format to output errors in. Allowed formats are %q or %q.`, format.Text, format.JSON), fmt.Sprintf(`The format to output errors in. Allowed formats are %q or %q.`, format.Text, format.JSON),
) )
OptErrorStack = options.NewBool(
"error.stack",
&options.Flag{Short: 'E'},
false,
"Print error stack trace to stderr",
`Print error stack trace to stderr. This only applies when error.format is
"text"; when error.format is "json", the stack trace is always printed.`,
options.TagOutput,
)
OptVerbose = options.NewBool( OptVerbose = options.NewBool(
"verbose", "verbose",
"", &options.Flag{Short: 'v'},
false,
'v',
false, false,
"Print verbose output", "Print verbose output",
`Print verbose output.`, `Print verbose output.`,
@ -93,9 +97,7 @@ command, sq falls back to "text". Available formats:
OptMonochrome = options.NewBool( OptMonochrome = options.NewBool(
"monochrome", "monochrome",
"", &options.Flag{Short: 'M'},
false,
'M',
false, false,
"Don't print color output", "Don't print color output",
`Don't print color output.`, `Don't print color output.`,
@ -104,9 +106,11 @@ command, sq falls back to "text". Available formats:
OptRedact = options.NewBool( OptRedact = options.NewBool(
"redact", "redact",
"no-redact", &options.Flag{
true, Name: "no-redact",
0, Invert: true,
Usage: "Don't redact passwords in output",
},
true, true,
"Redact passwords in output", "Redact passwords in output",
`Redact passwords in output.`, `Redact passwords in output.`,
@ -115,19 +119,20 @@ command, sq falls back to "text". Available formats:
OptProgress = options.NewBool( OptProgress = options.NewBool(
"progress", "progress",
"no-progress", &options.Flag{
Name: "no-progress",
Invert: true,
Usage: "Don't show progress bar",
},
true, true,
0, "Show progress bar for long-running operations",
true, `Show progress bar for long-running operations.`,
"Progress bar for long-running operations",
`Progress bar for long-running operations.`,
options.TagOutput, options.TagOutput,
) )
OptProgressDelay = options.NewDuration( OptProgressDelay = options.NewDuration(
"progress.delay", "progress.delay",
"", nil,
0,
time.Second*2, time.Second*2,
"Progress bar render delay", "Progress bar render delay",
`Delay before showing a progress bar.`, `Delay before showing a progress bar.`,
@ -135,8 +140,7 @@ command, sq falls back to "text". Available formats:
OptDebugTrackMemory = options.NewDuration( OptDebugTrackMemory = options.NewDuration(
"debug.stats.frequency", "debug.stats.frequency",
"", nil,
0,
0, 0,
"Memory usage sampling interval.", "Memory usage sampling interval.",
`Memory usage sampling interval. If non-zero, peak memory usage is periodically `Memory usage sampling interval. If non-zero, peak memory usage is periodically
@ -145,9 +149,7 @@ sampled, and reported on exit. If zero, memory usage sampling is disabled.`,
OptCompact = options.NewBool( OptCompact = options.NewBool(
"compact", "compact",
"", &options.Flag{Short: 'c'},
false,
'c',
false, false,
"Compact instead of pretty-printed output", "Compact instead of pretty-printed output",
`Compact instead of pretty-printed output.`, `Compact instead of pretty-printed output.`,
@ -156,8 +158,7 @@ sampled, and reported on exit. If zero, memory usage sampling is disabled.`,
OptTuningFlushThreshold = options.NewInt( OptTuningFlushThreshold = options.NewInt(
"tuning.flush-threshold", "tuning.flush-threshold",
"", nil,
0,
1000, 1000,
"Output writer buffer flush threshold in bytes", "Output writer buffer flush threshold in bytes",
`Size in bytes after which output writers should flush any internal buffer. `Size in bytes after which output writers should flush any internal buffer.
@ -171,8 +172,7 @@ Generally, it is not necessary to fiddle this knob.`,
OptDatetimeFormat = options.NewString( OptDatetimeFormat = options.NewString(
"format.datetime", "format.datetime",
"", nil,
0,
"RFC3339", "RFC3339",
nil, nil,
"Timestamp format: constant such as RFC3339 or a strftime format", "Timestamp format: constant such as RFC3339 or a strftime format",
@ -185,9 +185,7 @@ Generally, it is not necessary to fiddle this knob.`,
OptDatetimeFormatAsNumber = options.NewBool( OptDatetimeFormatAsNumber = options.NewBool(
"format.datetime.number", "format.datetime.number",
"", nil,
false,
0,
true, true,
"Render numeric datetime value as number instead of string", "Render numeric datetime value as number instead of string",
`Render numeric datetime value as number instead of string, if possible. If `Render numeric datetime value as number instead of string, if possible. If
@ -207,8 +205,7 @@ is not an integer.
OptDateFormat = options.NewString( OptDateFormat = options.NewString(
"format.date", "format.date",
"", nil,
0,
"DateOnly", "DateOnly",
nil, nil,
"Date format: constant such as DateOnly or a strftime format", "Date format: constant such as DateOnly or a strftime format",
@ -223,9 +220,7 @@ situation, use format.datetime instead.
OptDateFormatAsNumber = options.NewBool( OptDateFormatAsNumber = options.NewBool(
"format.date.number", "format.date.number",
"", nil,
false,
0,
true, true,
"Render numeric date value as number instead of string", "Render numeric date value as number instead of string",
`Render numeric date value as number instead of string, if possible. If `Render numeric date value as number instead of string, if possible. If
@ -244,8 +239,7 @@ that this option is no-op if the rendered value is not an integer.
OptTimeFormat = options.NewString( OptTimeFormat = options.NewString(
"format.time", "format.time",
"", nil,
0,
"TimeOnly", "TimeOnly",
nil, nil,
"Time format: constant such as TimeOnly or a strftime format", "Time format: constant such as TimeOnly or a strftime format",
@ -260,13 +254,10 @@ situation, use format.datetime instead.
OptTimeFormatAsNumber = options.NewBool( OptTimeFormatAsNumber = options.NewBool(
"format.time.number", "format.time.number",
"", nil,
false,
0,
true, true,
"Render numeric time value as number instead of string", "Render numeric time value as number instead of string",
` `Render numeric time value as number instead of string, if possible. If format.time
Render numeric time value as number instead of string, if possible. If format.time
renders a numeric value (e.g. "59"), that value is typically rendered as a string. renders a numeric value (e.g. "59"), that value is typically rendered as a string.
For some output formats, such as JSON, it can be useful to instead render the For some output formats, such as JSON, it can be useful to instead render the
value as a naked number instead of a string. Note that this option is no-op if value as a naked number instead of a string. Note that this option is no-op if
@ -304,7 +295,7 @@ func newWriters(cmd *cobra.Command, clnup *cleanup.Cleanup, o options.Options,
Metadata: tablew.NewMetadataWriter(outCfg.out, outCfg.outPr), Metadata: tablew.NewMetadataWriter(outCfg.out, outCfg.outPr),
Source: tablew.NewSourceWriter(outCfg.out, outCfg.outPr), Source: tablew.NewSourceWriter(outCfg.out, outCfg.outPr),
Ping: tablew.NewPingWriter(outCfg.out, outCfg.outPr), Ping: tablew.NewPingWriter(outCfg.out, outCfg.outPr),
Error: tablew.NewErrorWriter(outCfg.errOut, outCfg.errOutPr), Error: tablew.NewErrorWriter(outCfg.errOut, outCfg.errOutPr, OptErrorStack.Get(o)),
Version: tablew.NewVersionWriter(outCfg.out, outCfg.outPr), Version: tablew.NewVersionWriter(outCfg.out, outCfg.outPr),
Config: tablew.NewConfigWriter(outCfg.out, outCfg.outPr), Config: tablew.NewConfigWriter(outCfg.out, outCfg.outPr),
} }

View File

@ -9,10 +9,10 @@ var _ options.Opt = Opt{}
// NewOpt returns a new format.Opt instance. If validFn is non-nil, it // NewOpt returns a new format.Opt instance. If validFn is non-nil, it
// is executed against possible values. // is executed against possible values.
func NewOpt(key, flag string, short rune, defaultVal Format, func NewOpt(key string, flag *options.Flag, defaultVal Format,
validFn func(Format) error, usage, help string, validFn func(Format) error, usage, help string,
) Opt { ) Opt {
opt := options.NewBaseOpt(key, flag, short, usage, help, options.TagOutput) opt := options.NewBaseOpt(key, flag, usage, help, options.TagOutput)
return Opt{BaseOpt: opt, defaultVal: defaultVal, validFn: validFn} return Opt{BaseOpt: opt, defaultVal: defaultVal, validFn: validFn}
} }

View File

@ -20,6 +20,7 @@ type VerboseOpt struct { //nolint:govet // field alignment
IsSet bool `json:"is_set"` IsSet bool `json:"is_set"`
DefaultValue any `json:"default_value"` DefaultValue any `json:"default_value"`
Value any `json:"value"` Value any `json:"value"`
// FIXME: Add Flag?
Help string `json:"help"` Help string `json:"help"`
} }

View File

@ -14,18 +14,19 @@ import (
type errorWriter struct { type errorWriter struct {
w io.Writer w io.Writer
pr *output.Printing pr *output.Printing
stacktrace bool
} }
// NewErrorWriter returns an output.ErrorWriter that // NewErrorWriter returns an output.ErrorWriter that
// outputs in text format. // outputs in text format.
func NewErrorWriter(w io.Writer, pr *output.Printing) output.ErrorWriter { func NewErrorWriter(w io.Writer, pr *output.Printing, stacktrace bool) output.ErrorWriter {
return &errorWriter{w: w, pr: pr} return &errorWriter{w: w, pr: pr, stacktrace: stacktrace}
} }
// Error implements output.ErrorWriter. // Error implements output.ErrorWriter.
func (w *errorWriter) Error(systemErr, humanErr error) { func (w *errorWriter) Error(systemErr, humanErr error) {
fmt.Fprintln(w.w, w.pr.Error.Sprintf("sq: %v", humanErr)) fmt.Fprintln(w.w, w.pr.Error.Sprintf("sq: %v", humanErr))
if !w.pr.Verbose { if !w.stacktrace {
return return
} }

View File

@ -14,8 +14,7 @@ var (
// OptDatetimeFormat is Excel's custom datetime format string. // OptDatetimeFormat is Excel's custom datetime format string.
OptDatetimeFormat = options.NewString( OptDatetimeFormat = options.NewString(
"format.excel.datetime", "format.excel.datetime",
"", nil,
0,
"yyyy-mm-dd hh:mm", "yyyy-mm-dd hh:mm",
func(s string) error { func(s string) error {
err := validateDatetimeFormatString(s) err := validateDatetimeFormatString(s)
@ -38,8 +37,7 @@ Examples:
// OptDateFormat is Excel's custom date-only format string. // OptDateFormat is Excel's custom date-only format string.
OptDateFormat = options.NewString( OptDateFormat = options.NewString(
"format.excel.date", "format.excel.date",
"", nil,
0,
"yyyy-mm-dd", "yyyy-mm-dd",
func(s string) error { func(s string) error {
err := validateDatetimeFormatString(s) err := validateDatetimeFormatString(s)
@ -60,8 +58,7 @@ Examples:
// OptTimeFormat is Excel's custom time format string. // OptTimeFormat is Excel's custom time format string.
OptTimeFormat = options.NewString( OptTimeFormat = options.NewString(
"format.excel.time", "format.excel.time",
"", nil,
0,
"hh:mm:ss", "hh:mm:ss",
func(s string) error { func(s string) error {
err := validateDatetimeFormatString(s) err := validateDatetimeFormatString(s)

View File

@ -26,9 +26,7 @@ import (
// or as the zero value for the kind of that field. // or as the zero value for the kind of that field.
var OptEmptyAsNull = options.NewBool( var OptEmptyAsNull = options.NewBool(
"driver.csv.empty-as-null", "driver.csv.empty-as-null",
"", nil,
false,
0,
true, true,
"Treat ingest empty CSV fields as NULL", "Treat ingest empty CSV fields as NULL",
`When true, empty CSV fields are treated as NULL. When false, `When true, empty CSV fields are treated as NULL. When false,
@ -41,8 +39,7 @@ the zero value for that type is used, e.g. empty string or 0.`,
// OptDelim specifies the CSV delimiter to use. // OptDelim specifies the CSV delimiter to use.
var OptDelim = options.NewString( var OptDelim = options.NewString(
"driver.csv.delim", "driver.csv.delim",
"", nil,
0,
delimCommaKey, delimCommaKey,
nil, nil,
"Delimiter for ingest CSV data", "Delimiter for ingest CSV data",

View File

@ -46,18 +46,13 @@ type Opt interface {
// Key returns the Opt key, such as "ping.timeout". // Key returns the Opt key, such as "ping.timeout".
Key() string Key() string
// Flag is the long flag name to use, which is typically the same value // Flag is the computed flag config for the Opt.
// as returned by Opt.Key. However, a distinct value can be supplied, such Flag() Flag
// that flag usage and config usage have different keys. For example,
// an Opt might have a key "diff.num-lines", but a flag "lines".
Flag() string
// Short is the short key. The zero value indicates no short key.
// For example, if the key is "json", the short key could be 'j'.
Short() rune
// Usage is a one-line description of the Opt. Additional detail can be // Usage is a one-line description of the Opt. Additional detail can be
// found in Help. // found in Help. It is typically the case that [Flag.Usage] is the same value
// as Usage, but it can be overridden if the flag usage text should differ
// from the Opt usage text.
Usage() string Usage() string
// Help returns the Opt's help text, which typically provides more detail // Help returns the Opt's help text, which typically provides more detail
@ -93,34 +88,63 @@ type Opt interface {
Process(o Options) (Options, error) Process(o Options) (Options, error)
} }
// Flag describe an Opt's behavior as a command-line flag. It can be passed to
// the "NewX" Opt constructor functions, e.g. [NewBool], to override the Opt's
// flag configuration. The computed Flag value is available via Opt.Flag.
// It is common to pass a nil *Flag to the Opt constructors; the value returned
// by Opt.Flag will be appropriately populated with default values.
type Flag struct {
// Name is the flag name to use. Defaults to [Opt.Key].
Name string
// Usage is the flag's usage text. Defaults to [Opt.Usage], but can be
// overridden if the flag usage text should differ from the [Opt] usage text.
// This is typically only the case when [Flag.Invert] is true.
Usage string
// Short is the short flag name, e.g. 'v' for "verbose". The zero value
// indicates no short name.
Short rune
// Invert indicates that the flag's boolean value is inverted vs the flag
// name. For example, if [Opt.Key] is "progress", but [Flag.Name] is
// "no-progress", then [Flag.Invert] should be true. This field is ignored for
// non-boolean [Opt] types.
Invert bool
}
// BaseOpt is a partial implementation of options.Opt that concrete // BaseOpt is a partial implementation of options.Opt that concrete
// types can build on. // types can build on.
type BaseOpt struct { type BaseOpt struct {
flag Flag
key string key string
flag string
usage string usage string
help string help string
tags []string tags []string
short rune
}
// NewBaseOpt returns a new BaseOpt. If flag is empty string, key is
// used as the flag value.
func NewBaseOpt(key, flag string, short rune, usage, help string, tags ...string) BaseOpt {
if flag == "" {
flag = key
} }
// NewBaseOpt returns a new BaseOpt.
func NewBaseOpt(key string, flag *Flag, usage, help string, tags ...string) BaseOpt {
slices.Sort(tags) slices.Sort(tags)
return BaseOpt{ opt := BaseOpt{
key: key, key: key,
flag: flag,
short: short,
usage: usage, usage: usage,
help: help, help: help,
tags: tags, tags: tags,
} }
if flag != nil {
opt.flag = *flag
}
if opt.flag.Name == "" {
opt.flag.Name = key
}
if opt.flag.Usage == "" {
opt.flag.Usage = usage
}
return opt
} }
// Key implements options.Opt. // Key implements options.Opt.
@ -129,15 +153,10 @@ func (op BaseOpt) Key() string {
} }
// Flag implements options.Opt. // Flag implements options.Opt.
func (op BaseOpt) Flag() string { func (op BaseOpt) Flag() Flag {
return op.flag return op.flag
} }
// Short implements options.Opt.
func (op BaseOpt) Short() rune {
return op.short
}
// Usage implements options.Opt. // Usage implements options.Opt.
func (op BaseOpt) Usage() string { func (op BaseOpt) Usage() string {
return op.usage return op.usage
@ -190,16 +209,16 @@ func (op BaseOpt) Process(o Options) (Options, error) {
var _ Opt = String{} var _ Opt = String{}
// NewString returns an options.String instance. If flag is empty, the // NewString returns an options.String instance. If validFn is non-nil, it is
// value of key is used. If valid Fn is non-nil, it is called from // called by [String.Process].
// the process function. func NewString(key string, flag *Flag, defaultVal string, validFn func(string) error,
// usage, help string, tags ...string,
//nolint:revive
func NewString(key, flag string, short rune, defaultVal string,
validFn func(string) error, usage, help string, tags ...string,
) String { ) String {
if flag == nil {
flag = &Flag{}
}
return String{ return String{
BaseOpt: NewBaseOpt(key, flag, short, usage, help, tags...), BaseOpt: NewBaseOpt(key, flag, usage, help, tags...),
defaultVal: defaultVal, defaultVal: defaultVal,
validFn: validFn, validFn: validFn,
} }
@ -275,11 +294,14 @@ func (op String) Process(o Options) (Options, error) {
var _ Opt = Int{} var _ Opt = Int{}
// NewInt returns an options.Int instance. If flag is empty, the // NewInt returns an options.Int instance.
// value of key is used. func NewInt(key string, flag *Flag, defaultVal int, usage, help string, tags ...string) Int {
func NewInt(key, flag string, short rune, defaultVal int, usage, help string, tags ...string) Int { if flag == nil {
flag = &Flag{}
}
return Int{ return Int{
BaseOpt: NewBaseOpt(key, flag, short, usage, help, tags...), BaseOpt: NewBaseOpt(key, flag, usage, help, tags...),
defaultVal: defaultVal, defaultVal: defaultVal,
} }
} }
@ -403,17 +425,18 @@ func (op Int) Process(o Options) (Options, error) {
var _ Opt = Bool{} var _ Opt = Bool{}
// NewBool returns an options.Bool instance. If flag is empty, the value // NewBool returns an options.Bool instance. If arg flag is non-nil and
// of key is used. If invertFlag is true, the flag's boolean value // [Flag.Invert] is true, the flag's boolean value is inverted to set the option.
// is inverted to set the option. For example, if the Opt is "progress", // For example, if [Opt.Key] is progress, and [Flag.Name] is "--no-progress",
// and the flag is "--no-progress", then invertFlag should be true. // then [Flag.Invert] should be true.
func NewBool(key, flag string, invertFlag bool, short rune, //nolint:revive func NewBool(key string, flag *Flag, defaultVal bool, usage, help string, tags ...string) Bool {
defaultVal bool, usage, help string, tags ...string, if flag == nil {
) Bool { flag = &Flag{}
}
return Bool{ return Bool{
BaseOpt: NewBaseOpt(key, flag, short, usage, help, tags...), BaseOpt: NewBaseOpt(key, flag, usage, help, tags...),
defaultVal: defaultVal, defaultVal: defaultVal,
flagInverted: invertFlag,
} }
} }
@ -421,14 +444,6 @@ func NewBool(key, flag string, invertFlag bool, short rune, //nolint:revive
type Bool struct { type Bool struct {
BaseOpt BaseOpt
defaultVal bool defaultVal bool
flagInverted bool
}
// FlagInverted returns true Opt value is the inverse of the flag value.
// For example, if the Opt is "progress", and the flag is "--no-progress",
// then FlagInverted will return true.
func (op Bool) FlagInverted() bool {
return op.flagInverted
} }
// GetAny implements options.Opt. // GetAny implements options.Opt.
@ -519,13 +534,16 @@ func (op Bool) Process(o Options) (Options, error) {
var _ Opt = Duration{} var _ Opt = Duration{}
// NewDuration returns an options.Duration instance. If flag is empty, the // NewDuration returns an options.Duration instance.
// value of key is used. func NewDuration(key string, flag *Flag, defaultVal time.Duration,
func NewDuration(key, flag string, short rune, defaultVal time.Duration,
usage, help string, tags ...string, usage, help string, tags ...string,
) Duration { ) Duration {
if flag == nil {
flag = &Flag{}
}
return Duration{ return Duration{
BaseOpt: NewBaseOpt(key, flag, short, usage, help, tags...), BaseOpt: NewBaseOpt(key, flag, usage, help, tags...),
defaultVal: defaultVal, defaultVal: defaultVal,
} }
} }

View File

@ -69,7 +69,7 @@ func TestInt(t *testing.T) {
t.Run(tu.Name(i, tc.key), func(t *testing.T) { t.Run(tu.Name(i, tc.key), func(t *testing.T) {
reg := &options.Registry{} reg := &options.Registry{}
opt := options.NewInt(tc.key, "", 0, tc.defaultVal, "", "") opt := options.NewInt(tc.key, nil, tc.defaultVal, "", "")
reg.Add(opt) reg.Add(opt)
o := options.Options{tc.key: tc.input} o := options.Options{tc.key: tc.input}
@ -115,7 +115,7 @@ func TestBool(t *testing.T) {
t.Run(tu.Name(i, tc.key), func(t *testing.T) { t.Run(tu.Name(i, tc.key), func(t *testing.T) {
reg := &options.Registry{} reg := &options.Registry{}
opt := options.NewBool(tc.key, "", false, 0, tc.defaultVal, "", "") opt := options.NewBool(tc.key, nil, tc.defaultVal, "", "")
reg.Add(opt) reg.Add(opt)
o := options.Options{tc.key: tc.input} o := options.Options{tc.key: tc.input}
@ -156,8 +156,8 @@ func TestOptions_LogValue(t *testing.T) {
} }
func TestEffective(t *testing.T) { func TestEffective(t *testing.T) {
optHello := options.NewString("hello", "", 0, "world", nil, "", "") optHello := options.NewString("hello", nil, "world", nil, "", "")
optCount := options.NewInt("count", "", 0, 1, "", "") optCount := options.NewInt("count", nil, 1, "", "")
in := options.Options{"count": 7} in := options.Options{"count": 7}
want := options.Options{"count": 7, "hello": "world"} want := options.Options{"count": 7, "hello": "world"}

View File

@ -464,8 +464,7 @@ func barRenderDelay(b *Bar, d time.Duration) <-chan struct{} {
// progress impl is stable. // progress impl is stable.
var OptDebugSleep = options.NewDuration( var OptDebugSleep = options.NewDuration(
"debug.progress.sleep", "debug.progress.sleep",
"", nil,
0,
0, 0,
"DEBUG: Sleep during operations to facilitate testing progress bars", "DEBUG: Sleep during operations to facilitate testing progress bars",
`DEBUG: Sleep during operations to facilitate testing progress bars.`, `DEBUG: Sleep during operations to facilitate testing progress bars.`,

View File

@ -12,9 +12,7 @@ import (
// If not set, the ingester *may* try to detect if the input has a header. // If not set, the ingester *may* try to detect if the input has a header.
var OptIngestHeader = options.NewBool( var OptIngestHeader = options.NewBool(
"ingest.header", "ingest.header",
"", nil,
false,
0,
false, false,
"Ingest data has a header row", "Ingest data has a header row",
`Specifies whether ingested data has a header row or not. `Specifies whether ingested data has a header row or not.
@ -28,9 +26,11 @@ to detect the header.`,
// OptIngestCache specifies whether ingested data is cached or not. // OptIngestCache specifies whether ingested data is cached or not.
var OptIngestCache = options.NewBool( var OptIngestCache = options.NewBool(
"ingest.cache", "ingest.cache",
"no-cache", &options.Flag{
true, Name: "no-cache",
0, Invert: true,
Usage: "Don't cache ingest data",
},
true, true,
"Cache ingest data", "Cache ingest data",
`Specifies whether ingested data is cached or not, on a default or per-source `Specifies whether ingested data is cached or not, on a default or per-source
@ -43,8 +43,7 @@ ingested each time.
$ sq config set ingest.cache false $ sq config set ingest.cache false
# Set ingest caching behavior for a specific source # Set ingest caching behavior for a specific source
$ sq config set --src @sakila ingest.cache false $ sq config set --src @sakila ingest.cache false`,
`,
options.TagSource, options.TagSource,
) )
@ -52,8 +51,7 @@ ingested each time.
// should take to determine ingest data type. // should take to determine ingest data type.
var OptIngestSampleSize = options.NewInt( var OptIngestSampleSize = options.NewInt(
"ingest.sample-size", "ingest.sample-size",
"", nil,
0,
256, 256,
"Ingest data sample size for type detection", "Ingest data sample size for type detection",
`Specify the number of samples that a detector should take to determine type.`, `Specify the number of samples that a detector should take to determine type.`,
@ -64,8 +62,7 @@ var OptIngestSampleSize = options.NewInt(
// OptIngestColRename transforms a column name in ingested data. // OptIngestColRename transforms a column name in ingested data.
var OptIngestColRename = options.NewString( var OptIngestColRename = options.NewString(
"ingest.column.rename", "ingest.column.rename",
"", nil,
0,
"{{.Name}}{{with .Recurrence}}_{{.}}{{end}}", "{{.Name}}{{with .Recurrence}}_{{.}}{{end}}",
func(s string) error { func(s string) error {
return stringz.ValidTemplate("ingest.column.rename", s) return stringz.ValidTemplate("ingest.column.rename", s)

View File

@ -25,8 +25,7 @@ var (
// OptConnMaxOpen controls sql.DB.SetMaxOpenConn. // OptConnMaxOpen controls sql.DB.SetMaxOpenConn.
OptConnMaxOpen = options.NewInt( OptConnMaxOpen = options.NewInt(
"conn.max-open", "conn.max-open",
"", nil,
0,
0, 0,
"Max open connections to DB", "Max open connections to DB",
`Maximum number of open connections to the database. `Maximum number of open connections to the database.
@ -39,8 +38,7 @@ A value of zero indicates no limit.`,
// OptConnMaxIdle controls sql.DB.SetMaxIdleConns. // OptConnMaxIdle controls sql.DB.SetMaxIdleConns.
OptConnMaxIdle = options.NewInt( OptConnMaxIdle = options.NewInt(
"conn.max-idle", "conn.max-idle",
"", nil,
0,
2, 2,
"Max connections in idle connection pool", "Max connections in idle connection pool",
`Set the maximum number of connections in the idle connection pool. If `Set the maximum number of connections in the idle connection pool. If
@ -55,8 +53,7 @@ If n <= 0, no idle connections are retained.`,
// OptConnMaxIdleTime controls sql.DB.SetConnMaxIdleTime. // OptConnMaxIdleTime controls sql.DB.SetConnMaxIdleTime.
OptConnMaxIdleTime = options.NewDuration( OptConnMaxIdleTime = options.NewDuration(
"conn.max-idle-time", "conn.max-idle-time",
"", nil,
0,
time.Second*2, time.Second*2,
"Max connection idle time", "Max connection idle time",
`Sets the maximum amount of time a connection may be idle. Expired connections `Sets the maximum amount of time a connection may be idle. Expired connections
@ -70,8 +67,7 @@ If n <= 0, connections are not closed due to a connection's idle time.`,
// OptConnMaxLifetime controls sql.DB.SetConnMaxLifetime. // OptConnMaxLifetime controls sql.DB.SetConnMaxLifetime.
OptConnMaxLifetime = options.NewDuration( OptConnMaxLifetime = options.NewDuration(
"conn.max-lifetime", "conn.max-lifetime",
"", nil,
0,
time.Minute*10, time.Minute*10,
"Max connection lifetime", "Max connection lifetime",
` `
@ -86,8 +82,7 @@ If n <= 0, connections are not closed due to a connection's age.`,
// OptConnOpenTimeout controls connection open timeout. // OptConnOpenTimeout controls connection open timeout.
OptConnOpenTimeout = options.NewDuration( OptConnOpenTimeout = options.NewDuration(
"conn.open-timeout", "conn.open-timeout",
"", nil,
0,
time.Second*10, time.Second*10,
"Connection open timeout", "Connection open timeout",
"Max time to wait before a connection open timeout occurs.", "Max time to wait before a connection open timeout occurs.",
@ -99,8 +94,7 @@ If n <= 0, connections are not closed due to a connection's age.`,
// between retries. // between retries.
OptMaxRetryInterval = options.NewDuration( OptMaxRetryInterval = options.NewDuration(
"retry.max-interval", "retry.max-interval",
"", nil,
0,
time.Second*3, time.Second*3,
"Max interval between retries", "Max interval between retries",
`The maximum interval to wait between retries. If an operation is `The maximum interval to wait between retries. If an operation is
@ -113,8 +107,7 @@ operations back off, typically using a Fibonacci backoff.`,
// by an errgroup. // by an errgroup.
OptTuningErrgroupLimit = options.NewInt( OptTuningErrgroupLimit = options.NewInt(
"tuning.errgroup-limit", "tuning.errgroup-limit",
"", nil,
0,
16, 16,
"Max goroutines in any one errgroup", "Max goroutines in any one errgroup",
`Controls the maximum number of goroutines that can be spawned by an errgroup. `Controls the maximum number of goroutines that can be spawned by an errgroup.
@ -132,8 +125,7 @@ etc.`,
// insertion/writing. // insertion/writing.
OptTuningRecChanSize = options.NewInt( OptTuningRecChanSize = options.NewInt(
"tuning.record-buffer", "tuning.record-buffer",
"", nil,
0,
1024, 1024,
"Size of record buffer", "Size of record buffer",
`Controls the size of the buffer channel for record insertion/writing.`, `Controls the size of the buffer channel for record insertion/writing.`,

View File

@ -602,8 +602,7 @@ func mungeSetZeroValue(i int, rec []any, destMeta record.Meta) {
// OptResultColRename transforms a column name returned from the DB. // OptResultColRename transforms a column name returned from the DB.
var OptResultColRename = options.NewString( var OptResultColRename = options.NewString(
"result.column.rename", "result.column.rename",
"", nil,
0,
"{{.Name}}{{with .Recurrence}}_{{.}}{{end}}", "{{.Name}}{{with .Recurrence}}_{{.}}{{end}}",
func(s string) error { func(s string) error {
return stringz.ValidTemplate("result.column.rename", s) return stringz.ValidTemplate("result.column.rename", s)

View File

@ -30,8 +30,7 @@ import (
// See also: driver.OptIngestCache. // See also: driver.OptIngestCache.
var OptCacheLockTimeout = options.NewDuration( var OptCacheLockTimeout = options.NewDuration(
"cache.lock.timeout", "cache.lock.timeout",
"", nil,
0,
time.Second*5, time.Second*5,
"Wait timeout to acquire cache lock", "Wait timeout to acquire cache lock",
`Wait timeout to acquire cache lock. During this period, retry will occur `Wait timeout to acquire cache lock. During this period, retry will occur

View File

@ -19,8 +19,7 @@ import (
var ( var (
OptHTTPRequestTimeout = options.NewDuration( OptHTTPRequestTimeout = options.NewDuration(
"http.request.timeout", "http.request.timeout",
"", nil,
0,
time.Second*10, time.Second*10,
"HTTP/S request initial response timeout duration", "HTTP/S request initial response timeout duration",
`How long to wait for initial response from a HTTP/S endpoint before timeout `How long to wait for initial response from a HTTP/S endpoint before timeout
@ -32,8 +31,7 @@ Contrast with http.response.timeout.`,
) )
OptHTTPResponseTimeout = options.NewDuration( OptHTTPResponseTimeout = options.NewDuration(
"http.response.timeout", "http.response.timeout",
"", nil,
0,
0, 0,
"HTTP/S request completion timeout duration", "HTTP/S request completion timeout duration",
`How long to wait for the entire HTTP transaction to complete. This includes `How long to wait for the entire HTTP transaction to complete. This includes
@ -45,9 +43,7 @@ Contrast with http.request.timeout.`,
) )
OptHTTPSInsecureSkipVerify = options.NewBool( OptHTTPSInsecureSkipVerify = options.NewBool(
"https.insecure-skip-verify", "https.insecure-skip-verify",
"", nil,
false,
0,
false, false,
"Skip HTTPS TLS verification", "Skip HTTPS TLS verification",
"Skip HTTPS TLS verification. Useful when downloading against self-signed certs.", "Skip HTTPS TLS verification. Useful when downloading against self-signed certs.",

View File

@ -33,9 +33,7 @@ import (
var OptContinueOnError = options.NewBool( var OptContinueOnError = options.NewBool(
"download.refresh.ok-on-err", "download.refresh.ok-on-err",
"", nil,
false,
0,
true, true,
"Continue with stale download if refresh fails", "Continue with stale download if refresh fails",
`Continue with stale download if refresh fails. This option applies if a download `Continue with stale download if refresh fails. This option applies if a download
@ -48,9 +46,7 @@ download when the network is unavailable. If false, an error is returned instead
var OptCache = options.NewBool( var OptCache = options.NewBool(
"download.cache", "download.cache",
"", nil,
false,
0,
true, true,
"Cache downloads", "Cache downloads",
`Cache downloaded remote files. When false, the download cache is not used and `Cache downloaded remote files. When false, the download cache is not used and