types.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package rcli
  2. import (
  3. "fmt"
  4. "io"
  5. "reflect"
  6. "flag"
  7. "log"
  8. "strings"
  9. "errors"
  10. )
  11. type Service interface {
  12. Name() string
  13. Help() string
  14. }
  15. type Cmd func(io.ReadCloser, io.Writer, ...string) error
  16. type CmdMethod func(Service, io.ReadCloser, io.Writer, ...string) error
  17. func call(service Service, stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  18. flags := flag.NewFlagSet("main", flag.ContinueOnError)
  19. flags.SetOutput(stdout)
  20. flags.Usage = func() { stdout.Write([]byte(service.Help())) }
  21. if err := flags.Parse(args); err != nil {
  22. return err
  23. }
  24. cmd := flags.Arg(0)
  25. log.Printf("%s\n", strings.Join(append(append([]string{service.Name()}, cmd), flags.Args()[1:]...), " "))
  26. if cmd == "" {
  27. cmd = "help"
  28. }
  29. method := getMethod(service, cmd)
  30. if method != nil {
  31. return method(stdin, stdout, args[1:]...)
  32. }
  33. return errors.New("No such command: " + cmd)
  34. }
  35. func getMethod(service Service, name string) Cmd {
  36. if name == "help" {
  37. return func(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  38. if len(args) == 0 {
  39. stdout.Write([]byte(service.Help()))
  40. } else {
  41. if method := getMethod(service, args[0]); method == nil {
  42. return errors.New("No such command: " + args[0])
  43. } else {
  44. method(stdin, stdout, "--help")
  45. }
  46. }
  47. return nil
  48. }
  49. }
  50. methodName := "Cmd"+strings.ToUpper(name[:1])+strings.ToLower(name[1:])
  51. method, exists := reflect.TypeOf(service).MethodByName(methodName)
  52. if !exists {
  53. return nil
  54. }
  55. return func(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  56. ret := method.Func.CallSlice([]reflect.Value{
  57. reflect.ValueOf(service),
  58. reflect.ValueOf(stdin),
  59. reflect.ValueOf(stdout),
  60. reflect.ValueOf(args),
  61. })[0].Interface()
  62. if ret == nil {
  63. return nil
  64. }
  65. return ret.(error)
  66. }
  67. }
  68. func Subcmd(output io.Writer, name, signature, description string) *flag.FlagSet {
  69. flags := flag.NewFlagSet(name, flag.ContinueOnError)
  70. flags.SetOutput(output)
  71. flags.Usage = func() {
  72. fmt.Fprintf(output, "\nUsage: docker %s %s\n\n%s\n\n", name, signature, description)
  73. flags.PrintDefaults()
  74. }
  75. return flags
  76. }