cmd/uplink: hide advanced flags from output
Change-Id: I536af267c38e153aeea682fca4a74dc0ea2c42f0
This commit is contained in:
parent
c6f94ce9e4
commit
fab58e9c12
@ -57,7 +57,7 @@ type Config struct {
|
||||
// AccessConfig holds information about which accesses exist and are selected.
|
||||
type AccessConfig struct {
|
||||
Accesses map[string]string `internal:"true"`
|
||||
Access string `help:"the serialized access, or name of the access to use" default:""`
|
||||
Access string `help:"the serialized access, or name of the access to use" default:"" basic-help:"true"`
|
||||
|
||||
// used for backward compatibility
|
||||
Scopes map[string]string `internal:"true"` // deprecated
|
||||
|
@ -38,6 +38,8 @@ func init() {
|
||||
progress = cpCmd.Flags().Bool("progress", true, "if true, show progress")
|
||||
expires = cpCmd.Flags().String("expires", "", "optional expiration date of an object. Please use format (yyyy-mm-ddThh:mm:ssZhh:mm)")
|
||||
metadata = cpCmd.Flags().String("metadata", "", "optional metadata for the object. Please use a single level JSON object of string to string only")
|
||||
|
||||
setBasicFlags(cpCmd.Flags(), "progress", "expires", "metadata")
|
||||
}
|
||||
|
||||
// upload transfers src from local machine to s3 compatible object dst
|
||||
|
@ -39,6 +39,9 @@ func init() {
|
||||
// flags.
|
||||
// TODO: revisit after the configuration/flag code is refactored.
|
||||
process.Bind(importCmd, &importCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
|
||||
// NB: access is not supported by `setup` or `import`
|
||||
cfgstruct.SetBoolAnnotation(importCmd.Flags(), "access", cfgstruct.BasicHelpAnnotationName, false)
|
||||
}
|
||||
|
||||
// importMain is the function executed when importCmd is called
|
||||
|
@ -29,6 +29,8 @@ func init() {
|
||||
}, RootCmd)
|
||||
lsRecursiveFlag = lsCmd.Flags().Bool("recursive", false, "if true, list recursively")
|
||||
lsEncryptedFlag = lsCmd.Flags().Bool("encrypted", false, "if true, show paths as base64-encoded encrypted paths")
|
||||
|
||||
setBasicFlags(lsCmd.Flags(), "recursive", "encrypted")
|
||||
}
|
||||
|
||||
func list(cmd *cobra.Command, args []string) error {
|
||||
|
@ -25,6 +25,7 @@ func init() {
|
||||
RunE: deleteObject,
|
||||
}, RootCmd)
|
||||
rmEncryptedFlag = rmCmd.Flags().Bool("encrypted", false, "if true, treat paths as base64-encoded encrypted paths")
|
||||
setBasicFlags(rmCmd.Flags(), "encrypted")
|
||||
}
|
||||
|
||||
func deleteObject(cmd *cobra.Command, args []string) error {
|
||||
|
@ -4,15 +4,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/zeebo/errs"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@ -26,6 +30,8 @@ import (
|
||||
"storj.io/storj/private/version/checker"
|
||||
)
|
||||
|
||||
const advancedFlagName = "advanced"
|
||||
|
||||
// UplinkFlags configuration flags
|
||||
type UplinkFlags struct {
|
||||
NonInteractive bool `help:"disable interactive mode" default:"false" setup:"true"`
|
||||
@ -51,6 +57,12 @@ var (
|
||||
func init() {
|
||||
defaultConfDir := fpath.ApplicationDir("storj", "uplink")
|
||||
cfgstruct.SetupFlag(zap.L(), RootCmd, &confDir, "config-dir", defaultConfDir, "main directory for uplink configuration")
|
||||
|
||||
// NB: more-help flag is always retrieved using `findBoolFlagEarly()`
|
||||
RootCmd.PersistentFlags().BoolVar(new(bool), advancedFlagName, false, "if used in with -h, print advanced flags help")
|
||||
|
||||
setBasicFlags(RootCmd.PersistentFlags(), "config-dir", advancedFlagName)
|
||||
setUsageFunc(RootCmd)
|
||||
}
|
||||
|
||||
var cpuProfile = flag.String("profile.cpu", "", "file path of the cpu profile to be created")
|
||||
@ -244,3 +256,98 @@ func combineCobraFuncs(funcs ...func(*cobra.Command, []string) error) func(*cobr
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
/* `setUsageFunc` is a bit unconventional but cobra didn't leave much room for
|
||||
extensibility here. `cmd.SetUsageTemplate` is fairly useless for our case without
|
||||
the ability to add to the template's function map (see: https://golang.org/pkg/text/template/#hdr-Functions).
|
||||
|
||||
Because we can't alter what `cmd.Usage` generates, we have to edit it afterwards.
|
||||
In order to hook this function *and* get the usage string, we have to juggle the
|
||||
`cmd.usageFunc` between our hook and `nil`, so that we can get the usage string
|
||||
from the default usage func.
|
||||
*/
|
||||
func setUsageFunc(cmd *cobra.Command) {
|
||||
if findBoolFlagEarly(advancedFlagName) {
|
||||
return
|
||||
}
|
||||
|
||||
reset := func() (set func()) {
|
||||
original := cmd.UsageFunc()
|
||||
cmd.SetUsageFunc(nil)
|
||||
|
||||
return func() {
|
||||
cmd.SetUsageFunc(original)
|
||||
}
|
||||
}
|
||||
|
||||
cmd.SetUsageFunc(func(cmd *cobra.Command) error {
|
||||
set := reset()
|
||||
usageStr := cmd.UsageString()
|
||||
defer set()
|
||||
|
||||
usageScanner := bufio.NewScanner(bytes.NewBufferString(usageStr))
|
||||
|
||||
var basicFlags []string
|
||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||
basic, ok := flag.Annotations[cfgstruct.BasicHelpAnnotationName]
|
||||
if ok && len(basic) == 1 && basic[0] == "true" {
|
||||
basicFlags = append(basicFlags, flag.Name)
|
||||
}
|
||||
})
|
||||
|
||||
for usageScanner.Scan() {
|
||||
line := usageScanner.Text()
|
||||
trimmedLine := strings.TrimSpace(line)
|
||||
|
||||
var flagName string
|
||||
if _, err := fmt.Sscanf(trimmedLine, "--%s", &flagName); err != nil {
|
||||
fmt.Println(line)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: properly filter flags with short names
|
||||
if !strings.HasPrefix(trimmedLine, "--") {
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
for _, basicFlag := range basicFlags {
|
||||
if basicFlag == flagName {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func findBoolFlagEarly(flagName string) bool {
|
||||
for i, arg := range os.Args {
|
||||
arg := arg
|
||||
argHasPrefix := func(format string, args ...interface{}) bool {
|
||||
return strings.HasPrefix(arg, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
if !argHasPrefix("--%s", flagName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// NB: covers `--<flagName> false` usage
|
||||
if i+1 != len(os.Args) {
|
||||
next := os.Args[i+1]
|
||||
if next == "false" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if !argHasPrefix("--%s=false", flagName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setBasicFlags(flagset interface{}, flagNames ...string) {
|
||||
for _, name := range flagNames {
|
||||
cfgstruct.SetBoolAnnotation(flagset, name, cfgstruct.BasicHelpAnnotationName, true)
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ var (
|
||||
func init() {
|
||||
RootCmd.AddCommand(setupCmd)
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.SetupMode())
|
||||
|
||||
// NB: access is not supported by `setup` or `import`
|
||||
cfgstruct.SetBoolAnnotation(setupCmd.Flags(), "access", cfgstruct.BasicHelpAnnotationName, false)
|
||||
}
|
||||
|
||||
func cmdSetup(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -21,16 +21,16 @@ import (
|
||||
)
|
||||
|
||||
var shareCfg struct {
|
||||
DisallowReads bool `default:"false" help:"if true, disallow reads"`
|
||||
DisallowWrites bool `default:"false" help:"if true, disallow writes"`
|
||||
DisallowLists bool `default:"false" help:"if true, disallow lists"`
|
||||
DisallowDeletes bool `default:"false" help:"if true, disallow deletes"`
|
||||
Readonly bool `default:"false" help:"implies disallow_writes and disallow_deletes"`
|
||||
Writeonly bool `default:"false" help:"implies disallow_reads and disallow_lists"`
|
||||
NotBefore string `help:"disallow access before this time"`
|
||||
NotAfter string `help:"disallow access after this time"`
|
||||
DisallowReads bool `default:"false" help:"if true, disallow reads" basic-help:"true"`
|
||||
DisallowWrites bool `default:"false" help:"if true, disallow writes" basic-help:"true"`
|
||||
DisallowLists bool `default:"false" help:"if true, disallow lists" basic-help:"true"`
|
||||
DisallowDeletes bool `default:"false" help:"if true, disallow deletes" basic-help:"true"`
|
||||
Readonly bool `default:"false" help:"implies disallow_writes and disallow_deletes" basic-help:"true"`
|
||||
Writeonly bool `default:"false" help:"implies disallow_reads and disallow_lists" basic-help:"true"`
|
||||
NotBefore string `help:"disallow access before this time" basic-help:"true"`
|
||||
NotAfter string `help:"disallow access after this time" basic-help:"true"`
|
||||
AllowedPathPrefix []string `help:"whitelist of path prefixes to require, overrides the [allowed-path-prefix] arguments"`
|
||||
ExportTo string `default:"" help:"path to export the shared access to"`
|
||||
ExportTo string `default:"" help:"path to export the shared access to" basic-help:"true"`
|
||||
|
||||
// Share requires information about the current access
|
||||
AccessConfig
|
||||
|
@ -27,6 +27,10 @@ const (
|
||||
// FlagSource is a source annotation for config values that just come from
|
||||
// flags (i.e. are never persisted to file)
|
||||
FlagSource = "flag"
|
||||
|
||||
// BasicHelpAnnotationName is the name of the annotation used to indicate
|
||||
// a flag should be included in basic usage/help.
|
||||
BasicHelpAnnotationName = "basic-help"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -182,18 +186,18 @@ func bindConfig(flags FlagSet, prefix string, val reflect.Value, vars map[string
|
||||
|
||||
markHidden := false
|
||||
if onlyForSetup {
|
||||
setBoolAnnotation(flags, flagname, "setup")
|
||||
SetBoolAnnotation(flags, flagname, "setup", true)
|
||||
}
|
||||
if field.Tag.Get("user") == "true" {
|
||||
setBoolAnnotation(flags, flagname, "user")
|
||||
SetBoolAnnotation(flags, flagname, "user", true)
|
||||
}
|
||||
if field.Tag.Get("hidden") == "true" {
|
||||
markHidden = true
|
||||
setBoolAnnotation(flags, flagname, "hidden")
|
||||
SetBoolAnnotation(flags, flagname, "hidden", true)
|
||||
}
|
||||
if field.Tag.Get("deprecated") == "true" {
|
||||
markHidden = true
|
||||
setBoolAnnotation(flags, flagname, "deprecated")
|
||||
SetBoolAnnotation(flags, flagname, "deprecated", true)
|
||||
}
|
||||
if source := field.Tag.Get("source"); source != "" {
|
||||
setSourceAnnotation(flags, flagname, source)
|
||||
@ -276,20 +280,23 @@ func bindConfig(flags FlagSet, prefix string, val reflect.Value, vars map[string
|
||||
panic(fmt.Sprintf("invalid field type: %s", field.Type.String()))
|
||||
}
|
||||
if onlyForSetup {
|
||||
setBoolAnnotation(flags, flagname, "setup")
|
||||
SetBoolAnnotation(flags, flagname, "setup", true)
|
||||
}
|
||||
if field.Tag.Get("user") == "true" {
|
||||
setBoolAnnotation(flags, flagname, "user")
|
||||
SetBoolAnnotation(flags, flagname, "user", true)
|
||||
}
|
||||
if field.Tag.Get(BasicHelpAnnotationName) == "true" {
|
||||
SetBoolAnnotation(flags, flagname, BasicHelpAnnotationName, true)
|
||||
}
|
||||
|
||||
markHidden := false
|
||||
if field.Tag.Get("hidden") == "true" {
|
||||
markHidden = true
|
||||
setBoolAnnotation(flags, flagname, "hidden")
|
||||
SetBoolAnnotation(flags, flagname, "hidden", true)
|
||||
}
|
||||
if field.Tag.Get("deprecated") == "true" {
|
||||
markHidden = true
|
||||
setBoolAnnotation(flags, flagname, "deprecated")
|
||||
SetBoolAnnotation(flags, flagname, "deprecated", true)
|
||||
}
|
||||
if source := field.Tag.Get("source"); source != "" {
|
||||
setSourceAnnotation(flags, flagname, source)
|
||||
@ -343,13 +350,14 @@ func setStringAnnotation(flagset interface{}, name, key, value string) {
|
||||
}
|
||||
}
|
||||
|
||||
func setBoolAnnotation(flagset interface{}, name, key string) {
|
||||
// SetBoolAnnotation sets an annotation (if it can) on flagset with a value of []string{"true|false"}.
|
||||
func SetBoolAnnotation(flagset interface{}, name, key string, value bool) {
|
||||
flags, ok := flagset.(*pflag.FlagSet)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err := flags.SetAnnotation(name, key, []string{"true"})
|
||||
err := flags.SetAnnotation(name, key, []string{strconv.FormatBool(value)})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to set %s annotation for %s: %v", key, name, err))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user