github.com/wtfutil/wtf@v0.43.0/flags/flags.go (about) 1 package flags 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "runtime/debug" 8 "strings" 9 10 "github.com/chzyer/readline" 11 goFlags "github.com/jessevdk/go-flags" 12 "github.com/olebedev/config" 13 "github.com/wtfutil/wtf/cfg" 14 "github.com/wtfutil/wtf/help" 15 ) 16 17 // Flags is the container for command line flag data 18 type Flags struct { 19 Config string `short:"c" long:"config" optional:"yes" description:"Path to config file"` 20 Module string `short:"m" long:"module" optional:"yes" description:"Display info about a specific module, i.e.: 'wtfutil -m=todo'"` 21 Profile bool `short:"p" long:"profile" optional:"yes" description:"Profile application memory usage"` 22 Version bool `short:"v" long:"version" description:"Show version info"` 23 // Work-around go-flags misfeatures. If any sub-command is defined 24 // then `wtf` (no sub-commands, the common usage), is warned about. 25 Opt struct { 26 Cmd string `positional-arg-name:"command"` 27 Args []string `positional-arg-name:"args"` 28 } `positional-args:"yes"` 29 30 hasCustom bool 31 } 32 33 var EXTRA = ` 34 Commands: 35 save-secret <service> 36 service Service URL or module name of secret. 37 Save a secret into the secret store. The secret will be prompted for. 38 Requires wtf.secretStore to be configured. See individual modules for 39 information on what service and secret means for their configuration, 40 not all modules use secrets. 41 ` 42 43 // NewFlags creates an instance of Flags 44 func NewFlags() *Flags { 45 flags := Flags{} 46 return &flags 47 } 48 49 /* -------------------- Exported Functions -------------------- */ 50 51 // ConfigFilePath returns the path to the currently-loaded config file 52 func (flags *Flags) ConfigFilePath() string { 53 return flags.Config 54 } 55 56 // RenderIf displays special-case information based on the flags passed 57 // in, if any flags were passed in 58 func (flags *Flags) RenderIf(config *config.Config) { 59 if flags.HasModule() { 60 help.Display(flags.Module, config) 61 os.Exit(0) 62 } 63 64 if flags.HasVersion() { 65 info, _ := debug.ReadBuildInfo() 66 version := "dev" 67 date := "now" 68 for _, setting := range info.Settings { 69 if setting.Key == "vcs.revision" { 70 version = setting.Value 71 } else if setting.Key == "vcs.time" { 72 date = setting.Value 73 } 74 } 75 fmt.Printf("%s (%s)\n", version, date) 76 os.Exit(0) 77 } 78 79 if flags.Opt.Cmd == "" { 80 return 81 } 82 83 switch cmd := flags.Opt.Cmd; cmd { 84 case "save-secret": 85 var service, secret string 86 args := flags.Opt.Args 87 88 if len(args) < 1 || args[0] == "" { 89 fmt.Fprintf(os.Stderr, "save-secret: service required, see `%s --help`\n", os.Args[0]) 90 os.Exit(1) 91 } 92 93 service = args[0] 94 95 if len(args) > 1 { 96 fmt.Fprintf(os.Stderr, "save-secret: too many arguments, see `%s --help`\n", os.Args[0]) 97 os.Exit(1) 98 } 99 100 b, err := readline.Password("Secret: ") 101 if err != nil { 102 fmt.Fprintf(os.Stderr, "Error: %v\n", err) 103 os.Exit(1) 104 } 105 secret = string(b) 106 secret = strings.TrimSpace(secret) 107 108 if secret == "" { 109 fmt.Fprintf(os.Stderr, "save-secret: secret required, see `%s --help`\n", os.Args[0]) 110 os.Exit(1) 111 } 112 113 err = cfg.StoreSecret(config, &cfg.Secret{ 114 Service: service, 115 Secret: secret, 116 Username: "default", 117 }) 118 119 if err != nil { 120 fmt.Fprintf(os.Stderr, "Saving secret for service %q: %s\n", service, err.Error()) 121 os.Exit(1) 122 } 123 124 fmt.Printf("Saved secret for service %q\n", service) 125 os.Exit(0) 126 default: 127 fmt.Fprintf(os.Stderr, "Command `%s` is not supported, try `%s --help`\n", cmd, os.Args[0]) 128 os.Exit(1) 129 } 130 } 131 132 // HasCustomConfig returns TRUE if a config path was passed in, FALSE if one was not 133 func (flags *Flags) HasCustomConfig() bool { 134 return flags.hasCustom 135 } 136 137 // HasModule returns TRUE if a module name was passed in, FALSE if one was not 138 func (flags *Flags) HasModule() bool { 139 return len(flags.Module) > 0 140 } 141 142 // HasVersion returns TRUE if the version flag was passed in, FALSE if it was not 143 func (flags *Flags) HasVersion() bool { 144 return flags.Version 145 } 146 147 // Parse parses the incoming flags 148 func (flags *Flags) Parse() { 149 parser := goFlags.NewParser(flags, goFlags.Default) 150 if _, err := parser.Parse(); err != nil { 151 if flagsErr, ok := err.(*goFlags.Error); ok && flagsErr.Type == goFlags.ErrHelp { 152 fmt.Println(EXTRA) 153 os.Exit(0) 154 } 155 } 156 157 // If we have a custom config, then we're done parsing parameters, we don't need to 158 // generate the default value 159 flags.hasCustom = (len(flags.Config) > 0) 160 if flags.hasCustom { 161 return 162 } 163 164 // If no config file is explicitly passed in as a param then set the flag to the default config file 165 configDir, err := cfg.WtfConfigDir() 166 if err != nil { 167 fmt.Printf("Error: %v\n", err) 168 os.Exit(1) 169 } 170 flags.Config = filepath.Join(configDir, "config.yml") 171 }