|
| 1 | +// Copyright (C) 2023-2024 Takayuki Sato. All Rights Reserved. |
| 2 | +// This program is free software under MIT License. |
| 3 | +// See the file LICENSE in this distribution for more details. |
| 4 | + |
| 5 | +/* |
| 6 | +Package github.com/sttk/cliargs is a library to parse command line arguments. |
| 7 | +
|
| 8 | +# Parse without configurations |
| 9 | +
|
| 10 | +The Cmd struct has the method which parses command line arguments without configurations. |
| 11 | +This method automatically divides command line arguments to options and command arguments. |
| 12 | +
|
| 13 | +Command line arguments starts with - or -- are options, and others are command arguments. |
| 14 | +If you want to specify a value to an option, follows "=" and the value after the option, like |
| 15 | +foo=123. |
| 16 | +
|
| 17 | +All command line arguments after `--` are command arguments, even they starts with `-` or `--`. |
| 18 | +
|
| 19 | + // os.Args = []string{"path/to/app", "--foo-bar", "hoge", "--baz", "1", "-z=2", "-xyz=3", "fuga"} |
| 20 | + cmd := cliargs.NewCmd() |
| 21 | + err := cmd.Parse() |
| 22 | +
|
| 23 | + cmd.Name // app |
| 24 | + cmd.Args // [hoge fuga] |
| 25 | + cmd.HasOpt("foo-bar") // true |
| 26 | + cmd.HasOpt("baz") // true |
| 27 | + cmd.HasOpt("x") // true |
| 28 | + cmd.HasOpt("y") // true |
| 29 | + cmd.HasOpt("z") // true |
| 30 | + cmd.OptArg("foo-bar") // |
| 31 | + cmd.OptArg("baz") // 1 |
| 32 | + cmd.OptArg("x") // |
| 33 | + cmd.OptArg("y") // |
| 34 | + cmd.OptArg("z") // 2 |
| 35 | + cmd.OptArgs("foo-bar") // [] |
| 36 | + cmd.OptArgs("baz") // [1] |
| 37 | + cmd.OptArgs("x") // [] |
| 38 | + cmd.OptArgs("y") // [] |
| 39 | + cmd.OptArgs("z") // [2 3] |
| 40 | +
|
| 41 | +## Parses with configurations |
| 42 | +
|
| 43 | +The Cmd struct has the method ParseWith which parses command line arguments with configurations. |
| 44 | +
|
| 45 | +This method takes an array of option configurations: OptCfg, and divides command line arguments to |
| 46 | +options and command arguments according to this configurations. |
| 47 | +
|
| 48 | +An option configuration has fields: StoreKey, Names, HasArg, IsArray, Defaults, Desc, ArgInHelp, |
| 49 | +and Validator. |
| 50 | +
|
| 51 | +StoreKey field is specified the key name to store the option value to the option map in the Cmd |
| 52 | +instance. |
| 53 | +If this field is not specified, the first element of Names field is used instead. |
| 54 | +
|
| 55 | +Names field is a string array and specified the option names, that are both long options and short |
| 56 | +options. |
| 57 | +The order of elements in this field is used in a help text. |
| 58 | +If you want to prioritize the output of short option name first in the help text, |
| 59 | +like `-f, --foo-bar`, but use the long option name as the key in the option map, write StoreKey |
| 60 | +and Names fields as follows: |
| 61 | +OptCfg{StoreKey: "foo-bar", Names: []string{"f", "foo-bar"}}. |
| 62 | +
|
| 63 | +HasArg field indicates the option requires one or more values. |
| 64 | +IsArray field indicates the option can have multiple values. |
| 65 | +Defaults field is an array of string which is used as default one or more option arguments if the |
| 66 | +option is not specified. |
| 67 | +Desc is a description of the option for help text. |
| 68 | +ArgInHelp field is a text which is output after option name and aliases as an option value in help |
| 69 | +text. |
| 70 | +
|
| 71 | +Validator field is to set a function pointer which validates an option argument. |
| 72 | +This module provides several validators that validate whether an option argument is in a valid |
| 73 | +numeric format. |
| 74 | +
|
| 75 | +In addition,the help printing for an array of OptCfg is generated with Help. |
| 76 | +
|
| 77 | + // os.Args = []string{"app", "--foo-bar", "hoge", "--baz", "1", "-z=2", "-x" "fuga"} |
| 78 | +
|
| 79 | + optCfgs := []cliargs.OptCfg{ |
| 80 | + cliargs.OptCfg{ |
| 81 | + StoreKey: "FooBar", |
| 82 | + Names: []string{"foo-bar"}, |
| 83 | + Desc: "This is description of foo-bar.", |
| 84 | + }, |
| 85 | + cliargs.OptCfg{ |
| 86 | + Names: []string{"baz", "z"}, |
| 87 | + HasArg:true, |
| 88 | + IsArray: true, |
| 89 | + Defaults: [9,8,7], |
| 90 | + Desc:"This is description of baz.", |
| 91 | + ArgHelp:"<text>", |
| 92 | + }, |
| 93 | + cliargs.OptCfg{ |
| 94 | + Names: []string{"*"}, |
| 95 | + Desc: "(Any options are accepted)", |
| 96 | + }, |
| 97 | + } |
| 98 | +
|
| 99 | + cmd := cliars.NewCmd() |
| 100 | + err := cmd.ParseWith(optCfgs) |
| 101 | + cmd.Name // app |
| 102 | + cmd.Args // [hoge fuga] |
| 103 | + cmd.HasOpt("FooBar") // true |
| 104 | + cmd.HasOpt("baz") // true |
| 105 | + cmd.HasOpt("x") // true, due to "*" config |
| 106 | + cmd.OptArg("FooBar") // true |
| 107 | + cmd.OptArg("baz") // 1 |
| 108 | + cmd.OptArg("x") // true |
| 109 | + cmd.OptArgs("FooBar") // [] |
| 110 | + cmd.OptArgs("baz") // [1 2] |
| 111 | + cmd.OptArgs("x") // [] |
| 112 | +
|
| 113 | + help := cliargs.NewHelp() |
| 114 | + help.AddText("This is the usage description.") |
| 115 | + help.AddOptsWithMargins(optCfgs, 2, 0) |
| 116 | + help.Print() |
| 117 | +
|
| 118 | + // (stdout) |
| 119 | + // This is the usage description. |
| 120 | + // --foo-bar, -f This is description of foo-bar. |
| 121 | + // --baz, -z <text> This is description of baz. |
| 122 | +
|
| 123 | +## Parse for a OptStore struct |
| 124 | +
|
| 125 | +The Cmd struct has the method ParseFor which parses command line arguments and set their option |
| 126 | +values to the option store which is passed as an argument. |
| 127 | +
|
| 128 | +This method divides command line arguments to command arguments and options, then sets each option |
| 129 | +value to a curresponding field of the option store. |
| 130 | +
|
| 131 | +Within this method, a array of OptCfg is made from the fields of the option store. This OptCfg |
| 132 | +array is set to the public field: OptCfgs of the Cmd instance. |
| 133 | +If you want to access this option configurations, get them from this field. |
| 134 | +
|
| 135 | +An option configuration corresponding to each field of an option store is determined by its type |
| 136 | +and its struct tags. |
| 137 | +If the type is bool, the option takes no argument. |
| 138 | +If the type is integer, floating point number or string, the option can takes single option |
| 139 | +argument, therefore it can appear once in command line arguments. |
| 140 | +If the type is an array, the option can takes multiple option arguments, therefore it can appear |
| 141 | +multiple times in command line arguments. |
| 142 | +
|
| 143 | +The struct tags used in a option store struct are optcfg, optdesc, and optarg. |
| 144 | +optcfg is what to specify option configurations other than Desc and AtgInHelp. |
| 145 | +The format of optcfg is as follows: |
| 146 | +
|
| 147 | + `optcfg:"name"` // only name |
| 148 | + `optcfg:"name,alias1,alias2"` // with two aliases |
| 149 | + `optcfg:"name=value"` // with a default value |
| 150 | + `optcfg:"name=[value1,value2]"` // with defalt values for array |
| 151 | + `optcfg:"name=:[value1:value2]"` // with default values and separator is : |
| 152 | +
|
| 153 | +optdesc is what to specify a option description. |
| 154 | +And optarg is what to specify a text for an option argument value in help text. |
| 155 | +
|
| 156 | +NOTE: A default value of empty string array option in the struct tag is `[]`, |
| 157 | +like: `optcfg:"name=[]"`, |
| 158 | +but it doesn't represent an array which contains only one empty string. |
| 159 | +If you want to specify an array which contains only one emtpy string, write nothing after `=` |
| 160 | +symbol, |
| 161 | +like `optcfg:"name="`. |
| 162 | +
|
| 163 | + // os.Args = []string{"app", "--foo-bar", "hoge", "--baz", "1", "-z=2", "-x", "fuga"} |
| 164 | +
|
| 165 | + type MyOptions struct { |
| 166 | + FooBar bool `optcfg:"foo-bar" optdesc:"This is description of foo-bar."` |
| 167 | + Baz []int `optcfg:"baz,z=[9,8,7]" optdesc:"This is description of baz." optarg:"<num>"` |
| 168 | + Qux bool `optcfg:"qux,x" optdesc:"This is description of qux"` |
| 169 | + } |
| 170 | +
|
| 171 | + options := MyOptions{} |
| 172 | +
|
| 173 | + cmd := cliargs.NewCmd() |
| 174 | + err := cliargs.ParseFor(&options) |
| 175 | + cmd.Name // app |
| 176 | + cmd.Args // [hoge fuga] |
| 177 | + cmd.HasOpt("FooBar") // true |
| 178 | + cmd.HasOpt("Baz") // true |
| 179 | + cmd.HasOpt("Qux") // true |
| 180 | + cmd.OptArg("FooBar") // true |
| 181 | + cmd.OptArg("Baz") // 1 |
| 182 | + cmd.OptArg("Qux") // true |
| 183 | + cmd.OptArgs("FooBar") // [] |
| 184 | + cmd.OptArgs("Baz") // [1 2] |
| 185 | + cmd.OptArgs("Qux") // [] |
| 186 | +
|
| 187 | + options.FooBar // true |
| 188 | + options.Baz // [1 2] |
| 189 | + options.Qux // true |
| 190 | +
|
| 191 | + optCfgs // []OptCfg{ |
| 192 | + // OptCfg{ |
| 193 | + // StoreKey: "FooBar", |
| 194 | + // Names: []string{"foo-bar"}, |
| 195 | + // Desc: "This is description of foo-bar.", |
| 196 | + // HasArg: false, |
| 197 | + // IsArray: false, |
| 198 | + // Defaults: []string(nil), |
| 199 | + // ArgInHelp: "", |
| 200 | + // }, |
| 201 | + // OptCfg{ |
| 202 | + // StoreKey: "Baz", |
| 203 | + // Aliases: []string{"baz", "z"}, |
| 204 | + // Desc: "This is description of baz.", |
| 205 | + // HasArg: true, |
| 206 | + // IsArray: true, |
| 207 | + // Defaults: []string{"9","8","7"}, |
| 208 | + // ArgInHelp: "<num>", |
| 209 | + // }, |
| 210 | + // OptCfg{ |
| 211 | + // StoreKey: "Qux", |
| 212 | + // Aliases: []string{"qux", "x"}, |
| 213 | + // Desc: "This is description of qux.", |
| 214 | + // HasArg: false, |
| 215 | + // IsArray: false, |
| 216 | + // Defaults: []string(nil), |
| 217 | + // ArgInHelp: "", |
| 218 | + // }, |
| 219 | + // } |
| 220 | +
|
| 221 | + help := cliargs.NewHelp() |
| 222 | + help.AddText("This is the usage description.") |
| 223 | + help.AddOptsWithIndentAndMargins(optCfgs, 12, 1, 0) |
| 224 | + iter := help.Iter() |
| 225 | + for { |
| 226 | + line, exists := iter.Next() { |
| 227 | + if !exists { break } |
| 228 | + fmt.Println(line) |
| 229 | + } |
| 230 | +
|
| 231 | + // (stdout) |
| 232 | + // This is the usage description. |
| 233 | + // --foo-bar This is description of foo-bar. |
| 234 | + // --baz, -z <num> |
| 235 | + // This is description of baz. |
| 236 | + // --qux This is description of qux. |
| 237 | +
|
| 238 | +
|
| 239 | +## Parse command line arguments including sub command |
| 240 | +
|
| 241 | +This module provides methods Cmd#parseUntilSubCmd, Cmd#parseUntilSubCmdWith, and |
| 242 | +Cmd#parseUntilSubCmdFor for parsing command line arguments including sub commands. |
| 243 | +
|
| 244 | +These methods correspond to Cmd#parse, Cmd#parseWith, and Cmd#parseFor, respectively, |
| 245 | +and behave the same except that they stop parsing before the first command argument |
| 246 | +(= sub command) and return a Cmd instance containing the arguments starting from the the sub |
| 247 | +command. |
| 248 | +
|
| 249 | +The folowing is an example code using Cmd#parse_until_sub_cmd: |
| 250 | +
|
| 251 | + // os.Args = []string{"path/to/app", "--foo-bar", "hoge", "--baz", "1", "-z=2", "-xyz=3", "fuga"} |
| 252 | + cmd := cliargs.NewCmd() |
| 253 | + subCmd, err := cmd.ParseUntilSubCmd() |
| 254 | + errSub := subCmd.Parse() |
| 255 | +
|
| 256 | + cmd.Name // app |
| 257 | + cmd.Args // [] |
| 258 | + cmd.HasOpt("foo-bar") // true |
| 259 | + cmd.HasOpt("baz") // false |
| 260 | + cmd.HasOpt("x") // false |
| 261 | + cmd.HasOpt("y") // false |
| 262 | + cmd.HasOpt("z") // false |
| 263 | + cmd.OptArg("foo-bar") // |
| 264 | + cmd.OptArg("baz") // |
| 265 | + cmd.OptArg("x") // |
| 266 | + cmd.OptArg("y") // |
| 267 | + cmd.OptArg("z") // |
| 268 | + cmd.OptArgs("foo-bar") // [] |
| 269 | + cmd.OptArgs("baz") // [] |
| 270 | + cmd.OptArgs("x") // [] |
| 271 | + cmd.OptArgs("y") // [] |
| 272 | + cmd.OptArgs("z") // [] |
| 273 | +
|
| 274 | + subCmd.Name // hoge |
| 275 | + subCmd.Args // [fuga] |
| 276 | + subCmd.HasOpt("foo-bar") // false |
| 277 | + subCmd.HasOpt("baz") // true |
| 278 | + subCmd.HasOpt("x") // true |
| 279 | + subCmd.HasOpt("y") // true |
| 280 | + subCmd.HasOpt("z") // true |
| 281 | + subCmd.OptArg("foo-bar") // |
| 282 | + subCmd.OptArg("baz") // 1 |
| 283 | + subCmd.OptArg("x") // |
| 284 | + subCmd.OptArg("y") // |
| 285 | + subCmd.OptArg("z") // 2 |
| 286 | + subCmd.OptArgs("foo-bar") // [] |
| 287 | + subCmd.OptArgs("baz") // [1] |
| 288 | + subCmd.OptArgs("x") // [] |
| 289 | + subCmd.OptArgs("y") // [] |
| 290 | + subCmd.OptArgs("z") // [2 3] |
| 291 | +*/ |
| 292 | +package cliargs |
0 commit comments