项目作者: moshenahmias

项目描述 :
Command-Line parser for Go
高级语言: Go
项目地址: git://github.com/moshenahmias/funcv.git
创建时间: 2020-05-29T13:31:19Z
项目社区:https://github.com/moshenahmias/funcv

开源协议:MIT License

下载


funcv GoDoc

funcv helps you create CLI tools with Go.

funcv offers a different approach for dealing with command line arguments and flags.

funcv supplies an easy to use command builder, you use that builder to build your set of commands, each such command can be tested against a slice of string arguments, if the arguments are compatible with the command, a given action function is called, the parameters for that function are the extracted and parsed variables and flags.

Let’s see how it works with a simple example:

  1. func main() {
  2. cmd := funcv.NewCommand("delete a file").
  3. AddConstant("delete", false).
  4. AddVariable("filename", "file to delete", new(funcv.StringConverter)).
  5. MustCompile()
  6. if _, err := cmd.Execute(os.Args[1:], func(name string) {
  7. fmt.Println("deleting", name, "...")
  8. // ...
  9. }); err != nil {
  10. fmt.Fprintln(os.Stderr, "invalid command:", strings.Join(os.Args[1:], " "))
  11. }
  12. }
  1. $ example delete song.mp3
  2. deleting song.mp3 ...

First, we called the funcv.NewCommand function with a command description, then, we used the returned builder (funcv.Builder) to add our command components, a constant text (“delete”) and a string variable (“filename”). The call for MustCompile() finished the building process and returned the new command (failure.Command).

Next, we called the command’s Execute method with a slice of string arguments (os.Args[1:]) and an action function (func(name string){...}).

The Execute method tests the given arguments slice ([]string{"delete", "song.mp3"}) and finds that it contains two arguments, the first argument equals “delete”, therefore, the action function is called with the second argument as a parameter (name string).

Arguments

Currently supported list of arguments:

Comment
Constant Static word (allowed characters: 0-9, A-Z, a-z, _, -).
Variable With default value or without.
Flag -x or -x..x, with parameter or without.
Variadic Closing the list of arguments.

The list of supported arguments is extendable via the funcv.Argument interface.

Converters

Arguments that translates to function parameters (ex: not constant) require a func.Converter.

The package includes converters for Strings, Integers, Floats and Booleans.

Groups

It is possible to group different commands together using a funcv.Group:

  1. func main() {
  2. var grp funcv.Group
  3. err := funcv.NewCommand("delete a file").
  4. AddConstant("example", false).
  5. AddConstant("delete", false).
  6. AddParameterlessFlag("r", "move to recycle bin", new(funcv.BooleanConverter), false, true).
  7. AddVariable("filename", "file to delete", new(funcv.StringConverter)).
  8. ToGroup(&grp, func(recycle bool, name string) {
  9. // the count, order and type of params must match the count, order
  10. // and type of flags and variables in the command (excluding constants)
  11. if recycle {
  12. fmt.Println("recycling", name, "...")
  13. } else {
  14. fmt.Println("deleting", name, "...")
  15. }
  16. // ...
  17. })
  18. if err != nil {
  19. panic(err)
  20. }
  21. err = funcv.NewCommand("print this help").
  22. AddConstant("example", false).
  23. AddConstant("help", false).
  24. ToGroup(&grp, func() {
  25. // groups, commands and arguments implement io.WriterTo
  26. // and will write their informative usage text into the
  27. // writer given to WriteTo(io.Writer)
  28. w := new(tabwriter.Writer)
  29. w.Init(os.Stdout, 18, 8, 0, '\t', 0)
  30. defer w.Flush()
  31. if _, err := grp.WriteTo(w); err != nil {
  32. panic(err)
  33. }
  34. })
  35. if err != nil {
  36. panic(err)
  37. }
  38. // test against all commands in grp
  39. // returns the number of executed commands
  40. if grp.ExecuteAll(append([]string{"example"}, os.Args[1:]...)) == 0 {
  41. fmt.Fprintln(os.Stderr, "invalid command:", strings.Join(os.Args[1:], " "))
  42. }
  43. }
  1. $ example delete song.mp3
  2. deleting song.mp3 ...
  3. $ example delete -r song.mp3
  4. recycling song.mp3 ...
  5. $ example delete -r false song.mp3
  6. deleting song.mp3 ...
  7. $ example delete -r true song.mp3
  8. recycling song.mp3 ...
  9. $ example help
  10. delete a file: > example delete [-r] <filename>
  11. -r move to recycle bin (default: false)
  12. filename file to delete
  13. print this help: > example help
  14. $ example typo
  15. invalid command: typo

Variadic Functions

Variadic action functions support is available. Example:

  1. func main() {
  2. var grp funcv.Group
  3. converter := new(funcv.IntegerConverter)
  4. if err := funcv.NewCommand("add two numbers").
  5. AddConstant("calc", false).
  6. AddConstant("add", false).
  7. AddVariable("1st", "first operand", converter).
  8. AddVariable("2nd", "second operand", converter).
  9. ToGroup(&grp, func(x, y int) {
  10. fmt.Println(x, "+", y, "=", x+y, "(I)")
  11. }); err != nil {
  12. panic(err)
  13. }
  14. if err := funcv.NewCommand("add two or more numbers").
  15. AddConstant("calc", false).
  16. AddConstant("add", false).
  17. AddVariable("1st", "first operand", converter).
  18. AddVariable("2nd", "second operand", converter).
  19. AddVariadic("operands", "list of operands", converter).
  20. ToGroup(&grp, func(operands ...int) {
  21. var sb strings.Builder
  22. var sum int
  23. for i, op := range operands {
  24. sum += op
  25. sb.WriteString(fmt.Sprint(op))
  26. if i+1 < len(operands) {
  27. sb.WriteString(" + ")
  28. }
  29. }
  30. sb.WriteString(fmt.Sprintf(" = %d (II)", sum))
  31. fmt.Println(sb.String())
  32. }); err != nil {
  33. panic(err)
  34. }
  35. if grp.ExecuteAll(append([]string{"calc"}, os.Args[1:]...)) == 0 {
  36. fmt.Fprintln(os.Stderr, "invalid command:", strings.Join(os.Args[1:], " "))
  37. }
  38. }
  1. $ calc add 1
  2. invalid command: add 1
  3. $ calc add 1 2
  4. 1 + 2 = 3 (I)
  5. 1 + 2 = 3 (II)
  6. $ calc add 1 2 3
  7. 1 + 2 + 3 = 6 (II)

Use ExecuteFirst if you want to stop executing commands after the first successful executed command, the method returns the index of the executed command within the group, [0, len(group)), or a negative value if no command was found:

  1. func main() {
  2. // ... same commands as before ...
  3. if grp.ExecuteFirst(append([]string{"calc"}, os.Args[1:]...)) < 0 {
  4. fmt.Fprintln(os.Stderr, "invalid command:", strings.Join(os.Args[1:], " "))
  5. }
  6. }
  1. $ calc add 1 2
  2. 1 + 2 = 3 (I)

Action Function Returned Error

If an action function returns an error (non-nil), that error will propagate through the command’s Execute method:

  1. func main() {
  2. var grp funcv.Group
  3. if err := funcv.NewCommand("...").
  4. AddConstant("run", false).
  5. AddConstant("me", false).
  6. ToGroup(&grp, func() error {
  7. fmt.Println("1nd command")
  8. return errors.New("...")
  9. }); err != nil {
  10. panic(err)
  11. }
  12. if err := funcv.NewCommand("...").
  13. AddConstant("run", false).
  14. AddConstant("me", false).
  15. ToGroup(&grp, func() {
  16. fmt.Println("2nd command")
  17. }); err != nil {
  18. panic(err)
  19. }
  20. if grp.ExecuteFirst(append([]string{"run"}, os.Args[1:]...)) < 0 {
  21. fmt.Fprintln(os.Stderr, "invalid command:", strings.Join(os.Args[1:], " "))
  22. }
  23. }
  1. $ run me
  2. 1nd command
  3. 2nd command

ExecuteFirst stops after the first successful command, if an action function returns an error, the execution is considered to be unsuccessful.

Download

  1. $ go get -u github.com/moshenahmias/funcv