structarg.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package structarg
  15. import (
  16. "bufio"
  17. "bytes"
  18. "fmt"
  19. "io"
  20. "io/ioutil"
  21. "os"
  22. "reflect"
  23. "strconv"
  24. "strings"
  25. "yunion.io/x/jsonutils"
  26. "yunion.io/x/log"
  27. "yunion.io/x/pkg/errors"
  28. "yunion.io/x/pkg/gotypes"
  29. "yunion.io/x/pkg/util/reflectutils"
  30. "yunion.io/x/pkg/utils"
  31. )
  32. type BaseOptions struct {
  33. PidFile string `help:"Pid file path"`
  34. Config string `help:"Configuration file"`
  35. Help bool `help:"Show help and exit"`
  36. Version bool `help:"Show version and exit"`
  37. }
  38. type Argument interface {
  39. NeedData() bool
  40. Token() string
  41. AliasToken() string
  42. ShortToken() string
  43. NegativeToken() string
  44. MetaVar() string
  45. IsPositional() bool
  46. IsRequired() bool
  47. IsMulti() bool
  48. IsSubcommand() bool
  49. HelpString(indent string) string
  50. String() string
  51. SetValue(val string) error
  52. Reset()
  53. DoAction(nega bool) error
  54. Validate() error
  55. SetDefault()
  56. IsSet() bool
  57. }
  58. type SingleArgument struct {
  59. token string
  60. aliasToken string
  61. shortToken string
  62. negaToken string
  63. metavar string
  64. positional bool
  65. required bool
  66. help string
  67. choices []string
  68. useDefault bool
  69. defValue reflect.Value
  70. value reflect.Value
  71. ovalue reflect.Value
  72. isSet bool
  73. parser *ArgumentParser
  74. }
  75. type MultiArgument struct {
  76. SingleArgument
  77. minCount int64
  78. maxCount int64
  79. }
  80. type SubcommandArgumentData struct {
  81. parser *ArgumentParser
  82. callback reflect.Value
  83. }
  84. type SubcommandArgument struct {
  85. SingleArgument
  86. subcommands map[string]SubcommandArgumentData
  87. }
  88. type ArgumentParser struct {
  89. target interface{}
  90. prog string
  91. description string
  92. epilog string
  93. help bool
  94. optArgs []Argument
  95. posArgs []Argument
  96. }
  97. type sHelpArg struct {
  98. }
  99. func (self *sHelpArg) AliasToken() string {
  100. return ""
  101. }
  102. func (self *sHelpArg) DoAction(nega bool) error {
  103. return nil
  104. }
  105. func (self *sHelpArg) HelpString(indent string) string {
  106. return indent + "Print usage and this help message and exit."
  107. }
  108. func (self *sHelpArg) NeedData() bool {
  109. return false
  110. }
  111. func (self *sHelpArg) Token() string {
  112. return "help"
  113. }
  114. func (self *sHelpArg) ShortToken() string {
  115. return ""
  116. }
  117. func (self *sHelpArg) NegativeToken() string {
  118. return ""
  119. }
  120. func (self *sHelpArg) MetaVar() string {
  121. return ""
  122. }
  123. func (self *sHelpArg) IsPositional() bool {
  124. return false
  125. }
  126. func (self *sHelpArg) IsRequired() bool {
  127. return false
  128. }
  129. func (self *sHelpArg) IsMulti() bool {
  130. return false
  131. }
  132. func (self *sHelpArg) IsSubcommand() bool {
  133. return false
  134. }
  135. func (self *sHelpArg) String() string {
  136. return "[--help]"
  137. }
  138. func (self *sHelpArg) SetValue(val string) error {
  139. return nil
  140. }
  141. func (self *sHelpArg) Reset() {
  142. return
  143. }
  144. func (self *sHelpArg) Validate() error {
  145. return nil
  146. }
  147. func (self *sHelpArg) SetDefault() {
  148. }
  149. func (self *sHelpArg) IsSet() bool {
  150. return false
  151. }
  152. func newArgumentParser(target interface{}, prog, desc, epilog string) (*ArgumentParser, error) {
  153. parser := ArgumentParser{prog: prog, description: desc,
  154. epilog: epilog, target: target}
  155. targetValue := reflect.ValueOf(target)
  156. if targetValue.Kind() != reflect.Ptr {
  157. return nil, fmt.Errorf("target must be a pointer")
  158. }
  159. targetValue = targetValue.Elem()
  160. e := parser.addStructArgument("", targetValue)
  161. if e != nil {
  162. return nil, e
  163. }
  164. // always add a help argument --help
  165. helpArg := &sHelpArg{}
  166. parser.AddArgument(helpArg)
  167. return &parser, nil
  168. }
  169. func NewArgumentParser(target interface{}, prog, desc, epilog string) (*ArgumentParser, error) {
  170. return newArgumentParser(target, prog, desc, epilog)
  171. }
  172. func NewArgumentParserWithHelp(target interface{}, prog, desc, epilog string) (*ArgumentParser, error) {
  173. return newArgumentParser(target, prog, desc, epilog)
  174. }
  175. const (
  176. /*
  177. help text of the argument
  178. the argument is optional.
  179. */
  180. TAG_HELP = "help"
  181. /*
  182. command-line token for the optional argument, e.g. token:"url"
  183. the command-line argument will be "--url http://127.0.0.1:3306"
  184. the tag is optional.
  185. if the tag is missing, the variable name will be used as token.
  186. If the variable name is CamelCase, the token will be transformed
  187. into kebab-case, e.g. if the variable is "AuthURL", the token will
  188. be "--auth-url"
  189. */
  190. TAG_TOKEN = "token"
  191. /*
  192. short form of command-line token, e.g. short-token:"u"
  193. the command-line argument will be "-u http://127.0.0.1:3306"
  194. the tag is optional
  195. */
  196. TAG_SHORT_TOKEN = "short-token"
  197. /*
  198. Metavar of the argument
  199. the tag is optional
  200. */
  201. TAG_METAVAR = "metavar"
  202. /*
  203. The default value of the argument.
  204. the tag is optional
  205. */
  206. TAG_DEFAULT = "default"
  207. /*
  208. The possible values of an arguments. All choices are are concatenatd by "|".
  209. e.g. `choices:"1|2|3"`
  210. the tag is optional
  211. */
  212. TAG_CHOICES = "choices"
  213. /*
  214. A boolean value explicitly declare whether the argument is optional,
  215. the tag is optional
  216. */
  217. TAG_POSITIONAL = "positional"
  218. /*
  219. A boolean value explicitly declare whether the argument is required.
  220. The tag is optional. This is for optional arguments. Positional
  221. arguments must be "required"
  222. */
  223. TAG_REQUIRED = "required"
  224. /*
  225. A boolean value explicitly decalre whther the argument is an subcommand
  226. A subcommand argument must be the last positional argument.
  227. the tag is optional, the default value is false
  228. */
  229. TAG_SUBCOMMAND = "subcommand"
  230. /*
  231. The attribute defines the possible number of argument. Possible values
  232. are:
  233. * positive integers, e.g. "1", "2"
  234. * "*" any number of arguments
  235. * "+" at lease one argument
  236. * "?" at most one argument
  237. the tag is optional, the default value is "1"
  238. */
  239. TAG_NARGS = "nargs"
  240. /*
  241. Alias name of argument
  242. */
  243. TAG_ALIAS = "alias"
  244. /*
  245. Token for negative value, applicable to boolean values
  246. */
  247. TAG_NEGATIVE_TOKEN = "negative"
  248. /*
  249. Token for ignore
  250. */
  251. TAG_IGNORE = "ignore"
  252. )
  253. func (this *ArgumentParser) addStructArgument(prefix string, tpVal reflect.Value) error {
  254. sets := reflectutils.FetchAllStructFieldValueSetForWrite(tpVal)
  255. for i := range sets {
  256. if sets[i].Value.Kind() == reflect.Struct && sets[i].Value.Type() != gotypes.TimeType {
  257. tagMap := sets[i].Info.Tags
  258. if _, ok := tagMap[reflectutils.TAG_DEPRECATED_BY]; ok {
  259. // deprecated field, ignore
  260. return nil
  261. }
  262. token, ok := tagMap[TAG_TOKEN]
  263. if !ok {
  264. token = sets[i].Info.MarshalName()
  265. }
  266. token = prefix + token + "-"
  267. err := this.addStructArgument(token, sets[i].Value)
  268. if err != nil {
  269. return errors.Wrap(err, "addStructArgument")
  270. }
  271. } else {
  272. err := this.addArgument(prefix, sets[i].Value, sets[i].Info)
  273. if err != nil {
  274. return errors.Wrap(err, "addArgument")
  275. }
  276. }
  277. }
  278. return nil
  279. }
  280. func (this *ArgumentParser) addArgument(prefix string, fv reflect.Value, info *reflectutils.SStructFieldInfo) error {
  281. tagMap := info.Tags
  282. if _, ok := tagMap[reflectutils.TAG_DEPRECATED_BY]; ok {
  283. // deprecated field, ignore
  284. return nil
  285. }
  286. if val, ok := tagMap[TAG_IGNORE]; ok && val == "true" {
  287. // ignore field
  288. return nil
  289. }
  290. help := tagMap[TAG_HELP]
  291. token, ok := tagMap[TAG_TOKEN]
  292. if !ok {
  293. token = info.MarshalName()
  294. }
  295. token = prefix + token
  296. shorttoken := tagMap[TAG_SHORT_TOKEN]
  297. alias := tagMap[TAG_ALIAS]
  298. negative := tagMap[TAG_NEGATIVE_TOKEN]
  299. metavar := tagMap[TAG_METAVAR]
  300. defval := tagMap[TAG_DEFAULT]
  301. if len(defval) > 0 {
  302. for _, dv := range strings.Split(defval, "|") {
  303. if dv[0] == '$' {
  304. dv = os.Getenv(strings.TrimLeft(dv, "$"))
  305. }
  306. defval = dv
  307. if len(defval) > 0 {
  308. break
  309. }
  310. }
  311. }
  312. if len(negative) > 0 && !valueIsBool(fv) {
  313. return fmt.Errorf("negative token is applicable to boolean option ONLY")
  314. }
  315. use_default := true
  316. if len(defval) == 0 {
  317. use_default = false
  318. }
  319. var choices []string
  320. if choices_str, ok := tagMap[TAG_CHOICES]; ok {
  321. choices = strings.Split(choices_str, "|")
  322. }
  323. // heuristic guessing "positional"
  324. var positional bool
  325. if info.FieldName == strings.ToUpper(info.FieldName) {
  326. positional = true
  327. } else {
  328. positional = false
  329. }
  330. if positionalTag := tagMap[TAG_POSITIONAL]; len(positionalTag) > 0 {
  331. switch positionalTag {
  332. case "true":
  333. positional = true
  334. case "false":
  335. positional = false
  336. default:
  337. return fmt.Errorf("Invalid positional tag %q, neither true nor false", positionalTag)
  338. }
  339. }
  340. required := positional
  341. if requiredTag := tagMap[TAG_REQUIRED]; len(requiredTag) > 0 {
  342. switch requiredTag {
  343. case "true":
  344. required = true
  345. case "false":
  346. required = false
  347. default:
  348. return fmt.Errorf("Invalid required tag %q, neither true nor false", requiredTag)
  349. }
  350. }
  351. if positional {
  352. if !required {
  353. return fmt.Errorf("positional %s must not have required:false", token)
  354. }
  355. if use_default {
  356. return fmt.Errorf("positional %s must not have default value", token)
  357. }
  358. }
  359. if !positional && use_default && required {
  360. return fmt.Errorf("non-positional argument with default value should not have required:true set")
  361. }
  362. subcommand, err := strconv.ParseBool(tagMap[TAG_SUBCOMMAND])
  363. if err != nil {
  364. subcommand = false
  365. }
  366. var defval_t reflect.Value
  367. if use_default {
  368. defval_t, err = gotypes.ParseValue(defval, fv.Type())
  369. if err != nil {
  370. return err
  371. }
  372. }
  373. if subcommand {
  374. positional = true
  375. }
  376. var arg Argument = nil
  377. ovalue := reflect.New(fv.Type()).Elem()
  378. ovalue.Set(fv)
  379. sarg := SingleArgument{
  380. token: token,
  381. shortToken: shorttoken,
  382. aliasToken: alias,
  383. negaToken: negative,
  384. positional: positional,
  385. required: required,
  386. metavar: metavar,
  387. help: help,
  388. choices: choices,
  389. useDefault: use_default,
  390. defValue: defval_t,
  391. value: fv,
  392. ovalue: ovalue,
  393. parser: this,
  394. }
  395. // fmt.Println(token, f.Type, f.Type.Kind())
  396. if subcommand {
  397. arg = &SubcommandArgument{SingleArgument: sarg,
  398. subcommands: make(map[string]SubcommandArgumentData)}
  399. } else if fv.Kind() == reflect.Array || fv.Kind() == reflect.Slice || fv.Kind() == reflect.Map {
  400. var min, max int64
  401. var err error
  402. nargs := tagMap[TAG_NARGS]
  403. if nargs == "*" {
  404. min = 0
  405. max = -1
  406. } else if nargs == "?" {
  407. min = 0
  408. max = 1
  409. } else if nargs == "+" {
  410. min = 1
  411. max = -1
  412. } else {
  413. min, err = strconv.ParseInt(nargs, 10, 64)
  414. if err == nil {
  415. max = min
  416. } else if positional {
  417. min = 1
  418. max = -1
  419. } else if !required {
  420. min = 0
  421. max = -1
  422. }
  423. }
  424. arg = &MultiArgument{SingleArgument: sarg,
  425. minCount: min, maxCount: max}
  426. } else {
  427. arg = &sarg
  428. }
  429. err = this.AddArgument(arg)
  430. if err != nil {
  431. return fmt.Errorf("AddArgument %s: %v", arg, err)
  432. }
  433. return nil
  434. }
  435. func (this *ArgumentParser) AddArgument(arg Argument) error {
  436. if arg.IsPositional() {
  437. if len(this.posArgs) > 0 {
  438. last_arg := this.posArgs[len(this.posArgs)-1]
  439. switch {
  440. case last_arg.IsMulti():
  441. return fmt.Errorf("Cannot append positional argument after an array positional argument")
  442. case last_arg.IsSubcommand():
  443. return fmt.Errorf("Cannot append positional argument after a subcommand argument")
  444. }
  445. }
  446. this.posArgs = append(this.posArgs, arg)
  447. } else {
  448. for _, argOld := range this.optArgs {
  449. if argOld.Token() == arg.Token() {
  450. if arg.Token() == "help" {
  451. // silently ignore help arguments
  452. return nil
  453. }
  454. rt := reflect.TypeOf(this.target)
  455. if rt.Kind() == reflect.Ptr || rt.Kind() == reflect.Interface {
  456. rt = rt.Elem()
  457. }
  458. return fmt.Errorf("%s: Duplicate argument %s", rt.Name(), argOld.Token())
  459. }
  460. }
  461. // Put required at the end and try to be stable
  462. if arg.IsRequired() {
  463. this.optArgs = append(this.optArgs, arg)
  464. } else {
  465. var i int
  466. var opt Argument
  467. for i, opt = range this.optArgs {
  468. if opt.IsRequired() {
  469. break
  470. }
  471. }
  472. this.optArgs = append(this.optArgs, nil)
  473. copy(this.optArgs[i+1:], this.optArgs[i:])
  474. this.optArgs[i] = arg
  475. }
  476. }
  477. return nil
  478. }
  479. func (this *ArgumentParser) SetDefault() {
  480. for _, arg := range this.posArgs {
  481. arg.SetDefault()
  482. }
  483. for _, arg := range this.optArgs {
  484. arg.SetDefault()
  485. }
  486. }
  487. func (this *ArgumentParser) Options() interface{} {
  488. return this.target
  489. }
  490. func valueIsBool(rv reflect.Value) bool {
  491. if rv.Kind() == reflect.Bool {
  492. return true
  493. }
  494. if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool {
  495. return true
  496. }
  497. return false
  498. }
  499. func valueIsMap(rv reflect.Value) bool {
  500. if rv.Kind() == reflect.Map {
  501. return true
  502. }
  503. return false
  504. }
  505. func (this *SingleArgument) defaultBoolValue() bool {
  506. rv := this.defValue
  507. if rv.Kind() == reflect.Bool {
  508. return rv.Bool()
  509. }
  510. if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool {
  511. return rv.Elem().Bool()
  512. }
  513. panic("expecting bool or *bool type: got " + rv.Type().String())
  514. }
  515. func (this *SingleArgument) NeedData() bool {
  516. if valueIsBool(this.value) {
  517. return false
  518. } else {
  519. return true
  520. }
  521. }
  522. func (this *SingleArgument) MetaVar() string {
  523. if len(this.metavar) > 0 {
  524. return this.metavar
  525. } else if len(this.choices) > 0 {
  526. return fmt.Sprintf("{%s}", strings.Join(this.choices, ","))
  527. } else {
  528. return strings.ToUpper(strings.Replace(this.Token(), "-", "_", -1))
  529. }
  530. }
  531. func splitCamelString(str string) string {
  532. return utils.CamelSplit(str, "-")
  533. }
  534. func (this *SingleArgument) AllToken() string {
  535. ret := this.Token()
  536. if len(this.AliasToken()) != 0 {
  537. ret = fmt.Sprintf("%s|--%s", ret, this.AliasToken())
  538. }
  539. if len(this.ShortToken()) != 0 {
  540. ret = fmt.Sprintf("%s|-%s", ret, this.ShortToken())
  541. }
  542. if len(this.NegativeToken()) != 0 {
  543. ret = fmt.Sprintf("%s/--%s", ret, this.NegativeToken())
  544. }
  545. return ret
  546. }
  547. func (this *SingleArgument) Token() string {
  548. return splitCamelString(this.token)
  549. }
  550. func (this *SingleArgument) AliasToken() string {
  551. return splitCamelString(this.aliasToken)
  552. }
  553. func (this *SingleArgument) ShortToken() string {
  554. return this.shortToken
  555. }
  556. func (this *SingleArgument) NegativeToken() string {
  557. return strings.ReplaceAll(this.negaToken, "_", "-")
  558. }
  559. func (this *SingleArgument) String() string {
  560. var start, end byte
  561. if this.IsRequired() {
  562. start = '<'
  563. end = '>'
  564. } else {
  565. start = '['
  566. end = ']'
  567. }
  568. if this.IsPositional() {
  569. return fmt.Sprintf("%c%s%c", start, this.MetaVar(), end)
  570. } else {
  571. if this.NeedData() {
  572. return fmt.Sprintf("%c--%s %s%c", start, this.AllToken(), this.MetaVar(), end)
  573. } else {
  574. return fmt.Sprintf("%c--%s%c", start, this.AllToken(), end)
  575. }
  576. }
  577. }
  578. func (this *SingleArgument) IsRequired() bool {
  579. return this.required
  580. }
  581. func (this *SingleArgument) IsPositional() bool {
  582. return this.positional
  583. }
  584. func (this *SingleArgument) IsMulti() bool {
  585. return false
  586. }
  587. func (this *SingleArgument) IsSubcommand() bool {
  588. return false
  589. }
  590. func (this *SingleArgument) HelpString(indent string) string {
  591. return indent + strings.Join(strings.Split(this.help, "\n"), "\n"+indent)
  592. }
  593. func (this *SingleArgument) InChoices(val string) bool {
  594. if len(this.choices) > 0 {
  595. for _, s := range this.choices {
  596. if s == val {
  597. return true
  598. }
  599. }
  600. return false
  601. } else {
  602. return true
  603. }
  604. }
  605. func (this *SingleArgument) Choices() []string {
  606. return this.choices
  607. }
  608. func (this *SingleArgument) SetValue(val string) error {
  609. if !this.InChoices(val) {
  610. return this.choicesErr(val)
  611. }
  612. e := gotypes.SetValue(this.value, val)
  613. if e != nil {
  614. return e
  615. }
  616. this.isSet = true
  617. return nil
  618. }
  619. func (this *SingleArgument) choicesErr(val string) error {
  620. cands := FindSimilar(val, this.choices, -1, 0.5)
  621. if len(cands) > 3 {
  622. cands = cands[:3]
  623. }
  624. msg := fmt.Sprintf("Unknown argument '%s' for %s", val, this.Token())
  625. if len(cands) > 0 {
  626. msg += fmt.Sprintf(", did you mean %s?", quotedChoicesString(cands))
  627. } else if len(this.choices) > 0 {
  628. msg += fmt.Sprintf(", accepts %s", quotedChoicesString(this.choices))
  629. }
  630. return fmt.Errorf("%s", msg)
  631. }
  632. func (this *SingleArgument) Reset() {
  633. this.value.Set(this.ovalue)
  634. this.isSet = false
  635. }
  636. func (this *SingleArgument) DoAction(nega bool) error {
  637. if valueIsBool(this.value) {
  638. var v bool
  639. if this.useDefault {
  640. v = !this.defaultBoolValue()
  641. } else if nega {
  642. v = false
  643. } else {
  644. v = true
  645. }
  646. gotypes.SetValue(this.value, fmt.Sprintf("%t", v))
  647. this.isSet = true
  648. }
  649. return nil
  650. }
  651. func (this *SingleArgument) SetDefault() {
  652. if !this.isSet && this.useDefault {
  653. this.value.Set(this.defValue)
  654. }
  655. }
  656. func (this *SingleArgument) Validate() error {
  657. if this.required && !this.isSet && !this.useDefault {
  658. return fmt.Errorf("Non-optional argument %s not set", this.token)
  659. }
  660. return nil
  661. }
  662. func (this *SingleArgument) IsSet() bool {
  663. return this.isSet
  664. }
  665. func (this *MultiArgument) IsMulti() bool {
  666. return true
  667. }
  668. func (this *MultiArgument) setKeyValue(val string) error {
  669. pos := strings.IndexByte(val, '=')
  670. var key, value string
  671. if pos >= 0 {
  672. key = val[:pos]
  673. value = val[pos+1:]
  674. } else {
  675. key = val
  676. }
  677. keyType := this.value.Type().Key()
  678. keyValue, err := gotypes.ParseValue(key, keyType)
  679. if err != nil {
  680. return errors.Wrapf(err, "ParseValue for key %s", key)
  681. }
  682. valType := this.value.Type().Elem()
  683. valValue, err := gotypes.ParseValue(value, valType)
  684. if err != nil {
  685. return errors.Wrapf(err, "ParseValue for value %s", value)
  686. }
  687. if this.value.Len() == 0 {
  688. this.value.Set(reflect.MakeMap(this.value.Type()))
  689. }
  690. this.value.SetMapIndex(keyValue, valValue)
  691. this.isSet = true
  692. return nil
  693. }
  694. func (this *MultiArgument) SetValue(val string) error {
  695. if valueIsMap(this.value) {
  696. return this.setKeyValue(val)
  697. }
  698. if !this.InChoices(val) {
  699. return this.choicesErr(val)
  700. }
  701. var e error = nil
  702. e = gotypes.AppendValue(this.value, val)
  703. if e != nil {
  704. return e
  705. }
  706. this.isSet = true
  707. return nil
  708. }
  709. func (this *MultiArgument) Validate() error {
  710. var e = this.SingleArgument.Validate()
  711. if e != nil {
  712. return e
  713. }
  714. var vallen int64 = int64(this.value.Len())
  715. if this.minCount >= 0 && vallen < this.minCount {
  716. return fmt.Errorf("Argument count requires at least %d", this.minCount)
  717. }
  718. if this.maxCount >= 0 && vallen > this.maxCount {
  719. return fmt.Errorf("Argument count requires at most %d", this.maxCount)
  720. }
  721. return nil
  722. }
  723. func (this *SubcommandArgument) IsSubcommand() bool {
  724. return true
  725. }
  726. func (this *SubcommandArgument) String() string {
  727. return fmt.Sprintf("<%s>", strings.ToUpper(this.token))
  728. }
  729. func (this *SubcommandArgument) AddSubParser(target interface{}, command string, desc string, callback interface{}) (*ArgumentParser, error) {
  730. return this.addSubParser(target, command, desc, callback)
  731. }
  732. func (this *SubcommandArgument) AddSubParserWithHelp(target interface{}, command string, desc string, callback interface{}) (*ArgumentParser, error) {
  733. return this.addSubParser(target, command, desc, callback)
  734. }
  735. func (this *SubcommandArgument) addSubParser(target interface{}, command string, desc string, callback interface{}) (*ArgumentParser, error) {
  736. prog := fmt.Sprintf("%s %s", this.parser.prog, command)
  737. parser, e := newArgumentParser(target, prog, desc, "")
  738. if e != nil {
  739. return nil, e
  740. }
  741. cbfunc := reflect.ValueOf(callback)
  742. this.subcommands[command] = SubcommandArgumentData{parser: parser,
  743. callback: cbfunc}
  744. this.choices = append(this.choices, command)
  745. return parser, nil
  746. }
  747. func (this *SubcommandArgument) HelpString(indent string) string {
  748. var buf bytes.Buffer
  749. for k, data := range this.subcommands {
  750. buf.WriteString(indent)
  751. buf.WriteString(k)
  752. buf.WriteByte('\n')
  753. buf.WriteString(indent)
  754. buf.WriteString(" ")
  755. buf.WriteString(data.parser.ShortDescription())
  756. buf.WriteByte('\n')
  757. }
  758. return buf.String()
  759. }
  760. func (this *SubcommandArgument) SubHelpString(cmd string) (string, error) {
  761. val, ok := this.subcommands[cmd]
  762. if ok {
  763. return val.parser.HelpString(), nil
  764. } else {
  765. return "", fmt.Errorf("No such command %s", cmd)
  766. }
  767. }
  768. func (this *SubcommandArgument) GetSubParser() *ArgumentParser {
  769. var cmd = this.value.String()
  770. val, ok := this.subcommands[cmd]
  771. if ok {
  772. return val.parser
  773. } else {
  774. return nil
  775. }
  776. }
  777. func (this *SubcommandArgument) Invoke(args ...interface{}) error {
  778. var inargs = make([]reflect.Value, 0)
  779. for _, arg := range args {
  780. inargs = append(inargs, reflect.ValueOf(arg))
  781. }
  782. var cmd = this.value.String()
  783. val, ok := this.subcommands[cmd]
  784. if !ok {
  785. return fmt.Errorf("Unknown subcommand %s", cmd)
  786. }
  787. out := val.callback.Call(inargs)
  788. if len(out) == 1 {
  789. if out[0].IsNil() {
  790. return nil
  791. } else {
  792. return out[0].Interface().(error)
  793. }
  794. } else {
  795. return fmt.Errorf("Callback return %d unknown outputs", len(out))
  796. }
  797. }
  798. func (this *ArgumentParser) ShortDescription() string {
  799. return strings.Split(this.description, "\n")[0]
  800. }
  801. func (this *ArgumentParser) Usage() string {
  802. var buf bytes.Buffer
  803. buf.WriteString("Usage: ")
  804. buf.WriteString(this.prog)
  805. for _, arg := range this.optArgs {
  806. buf.WriteByte(' ')
  807. buf.WriteString(arg.String())
  808. }
  809. for _, arg := range this.posArgs {
  810. buf.WriteByte(' ')
  811. buf.WriteString(arg.String())
  812. if arg.IsSubcommand() || arg.IsMulti() {
  813. buf.WriteString(" ...")
  814. }
  815. }
  816. buf.WriteByte('\n')
  817. buf.WriteByte('\n')
  818. return buf.String()
  819. }
  820. func (this *ArgumentParser) HelpString() string {
  821. var buf bytes.Buffer
  822. buf.WriteString(this.Usage())
  823. buf.WriteString(this.description)
  824. buf.WriteByte('\n')
  825. buf.WriteByte('\n')
  826. if len(this.posArgs) > 0 {
  827. buf.WriteString("Positional arguments:\n")
  828. for _, arg := range this.posArgs {
  829. buf.WriteString(" ")
  830. buf.WriteString(arg.String())
  831. buf.WriteByte('\n')
  832. buf.WriteString(arg.HelpString(" "))
  833. buf.WriteByte('\n')
  834. }
  835. buf.WriteByte('\n')
  836. }
  837. if len(this.optArgs) > 0 {
  838. buf.WriteString("Optional arguments:\n")
  839. for _, arg := range this.optArgs {
  840. buf.WriteString(" ")
  841. buf.WriteString(arg.String())
  842. buf.WriteByte('\n')
  843. buf.WriteString(arg.HelpString(" "))
  844. buf.WriteByte('\n')
  845. }
  846. buf.WriteByte('\n')
  847. }
  848. if len(this.epilog) > 0 {
  849. buf.WriteString(this.epilog)
  850. buf.WriteByte('\n')
  851. buf.WriteByte('\n')
  852. }
  853. return buf.String()
  854. }
  855. func tokenMatch(argToken, input string, exactMatch bool) bool {
  856. if exactMatch {
  857. return argToken == input
  858. } else {
  859. return strings.HasPrefix(argToken, input)
  860. }
  861. }
  862. func (this *ArgumentParser) findOptionalArgument(token string, exactMatch bool) (Argument, bool) {
  863. var match_arg Argument = nil
  864. match_len := -1
  865. negative := false
  866. for _, arg := range this.optArgs {
  867. if tokenMatch(arg.Token(), token, exactMatch) {
  868. if match_len < 0 || match_len > len(arg.Token()) {
  869. match_len = len(arg.Token())
  870. match_arg = arg
  871. negative = false
  872. }
  873. } else if tokenMatch(arg.ShortToken(), token, exactMatch) {
  874. if match_len < 0 || match_len > len(arg.ShortToken()) {
  875. match_len = len(arg.ShortToken())
  876. match_arg = arg
  877. negative = false
  878. }
  879. } else if tokenMatch(arg.AliasToken(), token, exactMatch) {
  880. if match_len < 0 || match_len > len(arg.AliasToken()) {
  881. match_len = len(arg.AliasToken())
  882. match_arg = arg
  883. negative = false
  884. }
  885. } else if tokenMatch(arg.NegativeToken(), token, exactMatch) {
  886. if match_len < 0 || match_len > len(arg.AliasToken()) {
  887. match_len = len(arg.AliasToken())
  888. match_arg = arg
  889. negative = true
  890. }
  891. }
  892. }
  893. return match_arg, negative
  894. }
  895. func validateArgs(args []Argument) error {
  896. for _, arg := range args {
  897. e := arg.Validate()
  898. if e != nil {
  899. return fmt.Errorf("%s error: %s", arg.Token(), e)
  900. }
  901. }
  902. return nil
  903. }
  904. func (this *ArgumentParser) Validate() error {
  905. var e error = nil
  906. e = validateArgs(this.posArgs)
  907. if e != nil {
  908. return e
  909. }
  910. e = validateArgs(this.optArgs)
  911. if e != nil {
  912. return e
  913. }
  914. return nil
  915. }
  916. func (this *ArgumentParser) reset() {
  917. for _, arg := range this.posArgs {
  918. arg.Reset()
  919. }
  920. for _, arg := range this.optArgs {
  921. arg.Reset()
  922. }
  923. this.help = false
  924. }
  925. func (this *ArgumentParser) ParseArgs(args []string, ignore_unknown bool) error {
  926. return this.ParseArgs2(args, ignore_unknown, true)
  927. }
  928. func (this *ArgumentParser) ParseArgs2(args []string, ignore_unknown bool, setDefaults bool) error {
  929. var pos_idx int
  930. var err error
  931. var argStr string
  932. this.reset()
  933. for i := 0; i < len(args) && err == nil; i++ {
  934. argStr = args[i]
  935. if argStr == "--help" {
  936. // shortcut to show help
  937. fmt.Println(this.HelpString())
  938. this.help = true
  939. continue
  940. }
  941. if strings.HasPrefix(argStr, "-") {
  942. arg, nega := this.findOptionalArgument(strings.TrimLeft(argStr, "-"), false)
  943. if arg != nil {
  944. if arg.NeedData() {
  945. if i+1 < len(args) {
  946. err = arg.SetValue(args[i+1])
  947. if err != nil {
  948. break
  949. }
  950. i++
  951. } else {
  952. err = fmt.Errorf("Missing arguments for %s", argStr)
  953. break
  954. }
  955. } else {
  956. err = arg.DoAction(nega)
  957. if err != nil {
  958. break
  959. }
  960. }
  961. } else if !ignore_unknown {
  962. err = fmt.Errorf("Unknown optional argument %s", argStr)
  963. break
  964. }
  965. } else {
  966. if pos_idx >= len(this.posArgs) {
  967. if len(this.posArgs) > 0 {
  968. last_arg := this.posArgs[len(this.posArgs)-1]
  969. if last_arg.IsMulti() {
  970. last_arg.SetValue(argStr)
  971. } else if !ignore_unknown {
  972. err = fmt.Errorf("Unknown positional argument %s", argStr)
  973. break
  974. }
  975. } else if !ignore_unknown {
  976. err = fmt.Errorf("Unknown positional argument %s", argStr)
  977. break
  978. }
  979. } else {
  980. arg := this.posArgs[pos_idx]
  981. pos_idx += 1
  982. err = arg.SetValue(argStr)
  983. if err != nil {
  984. break
  985. }
  986. if arg.IsSubcommand() {
  987. subarg := arg.(*SubcommandArgument)
  988. var subparser = subarg.GetSubParser()
  989. err = subparser.ParseArgs(args[i+1:], ignore_unknown)
  990. break
  991. }
  992. }
  993. }
  994. }
  995. if err == nil && pos_idx < len(this.posArgs) {
  996. err = &NotEnoughArgumentsError{argument: this.posArgs[pos_idx]}
  997. }
  998. if err == nil {
  999. err = this.Validate()
  1000. }
  1001. if setDefaults {
  1002. this.SetDefault()
  1003. }
  1004. return err
  1005. }
  1006. func isQuotedByChar(str string, quoteChar byte) bool {
  1007. return len(str) >= 2 && str[0] == quoteChar && str[len(str)-1] == quoteChar
  1008. }
  1009. func isQuoted(str string) bool {
  1010. return isQuotedByChar(str, '"') || isQuotedByChar(str, '\'')
  1011. }
  1012. func (this *ArgumentParser) parseKeyValue(key, value string) error {
  1013. arg, nega := this.findOptionalArgument(key, true)
  1014. if arg != nil {
  1015. if nega {
  1016. log.Warningf("Ignore negative token when parse %s=%v", key, value)
  1017. return nil
  1018. }
  1019. if arg.IsSet() {
  1020. return nil
  1021. }
  1022. if arg.IsMulti() {
  1023. if value[0] == '(' {
  1024. value = strings.Trim(value, "()")
  1025. } else {
  1026. value = strings.Trim(value, "[]")
  1027. }
  1028. values := utils.FindWords([]byte(value), 0)
  1029. for _, v := range values {
  1030. e := arg.SetValue(v)
  1031. if e != nil {
  1032. return e
  1033. }
  1034. }
  1035. } else {
  1036. if !isQuoted(value) {
  1037. value = fmt.Sprintf("\"%s\"", value)
  1038. }
  1039. values := utils.FindWords([]byte(value), 0)
  1040. if len(values) == 1 {
  1041. return arg.SetValue(values[0])
  1042. } else {
  1043. log.Warningf("too many arguments %#v for %s", values, key)
  1044. }
  1045. }
  1046. } else {
  1047. log.Warningf("Cannot find argument %s", key)
  1048. }
  1049. return nil
  1050. }
  1051. func removeComments(line string) string {
  1052. pos := strings.IndexByte(line, '#')
  1053. if pos >= 0 {
  1054. return line[:pos]
  1055. } else {
  1056. return line
  1057. }
  1058. }
  1059. func line2KeyValue(line string) (string, string, error) {
  1060. // first remove comments
  1061. pos := strings.IndexByte(line, '=')
  1062. if pos > 0 && pos < len(line) {
  1063. key := keyToToken(line[:pos])
  1064. val := strings.Trim(line[pos+1:], " ")
  1065. return key, val, nil
  1066. } else {
  1067. return "", "", fmt.Errorf("Misformated line: %s", line)
  1068. }
  1069. }
  1070. func removeCharacters(input, charSet string) string {
  1071. filter := func(r rune) rune {
  1072. if strings.IndexRune(charSet, r) < 0 {
  1073. return r
  1074. }
  1075. return -1
  1076. }
  1077. return strings.Map(filter, input)
  1078. }
  1079. func (this *ArgumentParser) ParseYAMLFile(filepath string) error {
  1080. content, err := ioutil.ReadFile(filepath)
  1081. if err != nil {
  1082. return fmt.Errorf("read file %s: %v", filepath, err)
  1083. }
  1084. obj, err := jsonutils.ParseYAML(string(content))
  1085. if err != nil {
  1086. return fmt.Errorf("parse yaml to json object: %v", err)
  1087. }
  1088. dict, ok := obj.(*jsonutils.JSONDict)
  1089. if !ok {
  1090. return fmt.Errorf("object %s is not JSONDict", obj.String())
  1091. }
  1092. return this.parseJSONDict(dict)
  1093. }
  1094. func (this *ArgumentParser) parseJSONDict(dict *jsonutils.JSONDict) error {
  1095. mapJson, err := dict.GetMap()
  1096. if err != nil {
  1097. return errors.Wrap(err, "GetMap")
  1098. }
  1099. for key, obj := range mapJson {
  1100. if err := this.parseJSONKeyValue(key, obj); err != nil {
  1101. return fmt.Errorf("parse json %s: %s: %v", key, obj.String(), err)
  1102. }
  1103. }
  1104. return nil
  1105. }
  1106. func keyToToken(key string) string {
  1107. return strings.Replace(strings.Trim(key, " "), "_", "-", -1)
  1108. }
  1109. func (this *ArgumentParser) parseJSONKeyValue(key string, obj jsonutils.JSONObject) error {
  1110. token := keyToToken(key)
  1111. arg, nega := this.findOptionalArgument(token, true)
  1112. if arg == nil {
  1113. log.Warningf("Cannot find argument %s", token)
  1114. return nil
  1115. }
  1116. if nega {
  1117. log.Warningf("Ignore negative token when parse JSONKeyValue %s", token)
  1118. return nil
  1119. }
  1120. if arg.IsSet() {
  1121. return nil
  1122. }
  1123. // process multi argument
  1124. if arg.IsMulti() {
  1125. array, err := obj.GetArray()
  1126. if err != nil {
  1127. return errors.Wrap(err, "GetArray")
  1128. }
  1129. for _, item := range array {
  1130. str, err := item.GetString()
  1131. if err != nil {
  1132. return err
  1133. }
  1134. if err := arg.SetValue(str); err != nil {
  1135. return err
  1136. }
  1137. }
  1138. return nil
  1139. }
  1140. // process single argument
  1141. str, err := obj.GetString()
  1142. if err != nil {
  1143. return err
  1144. }
  1145. return arg.SetValue(str)
  1146. }
  1147. func (this *ArgumentParser) ParseFile(filepath string) error {
  1148. if err := this.ParseYAMLFile(filepath); err == nil {
  1149. return nil
  1150. }
  1151. return this.ParseTornadoFile(filepath)
  1152. }
  1153. func (this *ArgumentParser) parseReader(r io.Reader) error {
  1154. scanner := bufio.NewScanner(r)
  1155. for scanner.Scan() {
  1156. line := scanner.Text()
  1157. line = strings.TrimSpace(removeComments(line))
  1158. // line = removeCharacters(line, `"'`)
  1159. if len(line) > 0 {
  1160. if line[0] == '[' {
  1161. continue
  1162. }
  1163. key, val, e := line2KeyValue(line)
  1164. if e == nil {
  1165. this.parseKeyValue(key, val)
  1166. } else {
  1167. return e
  1168. }
  1169. }
  1170. }
  1171. if err := scanner.Err(); err != nil {
  1172. return err
  1173. }
  1174. return nil
  1175. }
  1176. func (this *ArgumentParser) ParseTornadoFile(filepath string) error {
  1177. file, e := os.Open(filepath)
  1178. if e != nil {
  1179. return e
  1180. }
  1181. defer file.Close()
  1182. return this.parseReader(file)
  1183. }
  1184. func (this *ArgumentParser) GetSubcommand() *SubcommandArgument {
  1185. if len(this.posArgs) > 0 {
  1186. last_arg := this.posArgs[len(this.posArgs)-1]
  1187. if last_arg.IsSubcommand() {
  1188. return last_arg.(*SubcommandArgument)
  1189. }
  1190. }
  1191. return nil
  1192. }
  1193. func (this *ArgumentParser) ParseKnownArgs(args []string) error {
  1194. return this.ParseArgs(args, true)
  1195. }
  1196. func (this *ArgumentParser) GetOptArgs() []Argument {
  1197. return this.optArgs
  1198. }
  1199. func (this *ArgumentParser) GetPosArgs() []Argument {
  1200. return this.posArgs
  1201. }
  1202. func (this *ArgumentParser) IsHelpSet() bool {
  1203. return this.help
  1204. }