PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/cmd/xs/main.go

https://bitbucket.org/go2clouds/goxs
Go | 212 lines | 160 code | 34 blank | 18 comment | 26 complexity | 0d10225472fd3d83d745ed05e65e8d7a MD5 | raw file
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "io"
  6. "log"
  7. "os"
  8. "strings"
  9. "sync"
  10. "text/template"
  11. "unicode"
  12. "unicode/utf8"
  13. )
  14. // A Command is an implementation of a xs command
  15. // like xs read or xs write.
  16. type Command struct {
  17. // Run runs the command.
  18. // The args are the arguments after the command name.
  19. Run func(cmd *Command, args []string)
  20. // UsageLine is the one-line usage message.
  21. // The first word in the line is taken to be the command name.
  22. UsageLine string
  23. // Short is the short description shown in the 'xs help' output.
  24. Short string
  25. // Long is the long message shown in the 'xs help <this-command>' output.
  26. Long string
  27. // Flag is a set of flags specific to this command.
  28. Flag flag.FlagSet
  29. // CustomFlags indicates that the command will do its own
  30. // flag parsing.
  31. CustomFlags bool
  32. }
  33. // Name returns the command's name: the first word in the usage line.
  34. func (c *Command) Name() string {
  35. name := c.UsageLine
  36. i := strings.Index(name, " ")
  37. if i >= 0 {
  38. name = name[:i]
  39. }
  40. return name
  41. }
  42. func (c *Command) Usage() {
  43. fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
  44. fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
  45. os.Exit(2)
  46. }
  47. // Commands lists the available commands and help topics.
  48. // The order here is the order in which they are printed by 'yapm help'.
  49. var commands = []*Command{
  50. cmdRead,
  51. cmdWrite,
  52. cmdWatch,
  53. }
  54. var exitStatus = 0
  55. var exitMu sync.Mutex
  56. func setExitStatus(n int) {
  57. exitMu.Lock()
  58. if exitStatus < n {
  59. exitStatus = n
  60. }
  61. exitMu.Unlock()
  62. }
  63. func main() {
  64. flag.Usage = usage
  65. flag.Parse()
  66. log.SetFlags(0)
  67. args := flag.Args()
  68. if len(args) < 1 {
  69. usage()
  70. }
  71. if args[0] == "help" {
  72. help(args[1:])
  73. return
  74. }
  75. for _, cmd := range commands {
  76. if cmd.Name() == args[0] && cmd.Run != nil {
  77. cmd.Flag.Usage = func() { cmd.Usage() }
  78. if cmd.CustomFlags {
  79. args = args[1:]
  80. } else {
  81. cmd.Flag.Parse(args[1:])
  82. args = cmd.Flag.Args()
  83. }
  84. cmd.Run(cmd, args)
  85. exit()
  86. return
  87. }
  88. }
  89. fmt.Fprintf(os.Stderr, "xs: unknown subcommand %q\nRun 'xs help' for usage.\n", args[0])
  90. setExitStatus(2)
  91. exit()
  92. }
  93. var usageTemplate = `xs is a tool for comunication with xenstore.
  94. Usage:
  95. xs command [arguments]
  96. The commands are:
  97. {{range .}}
  98. {{.Name | printf "%-11s"}} {{.Short}}{{end}}
  99. Use "xs help [command]" for more information about a command.
  100. `
  101. var helpTemplate = `usage: xs {{.UsageLine}}
  102. {{.Long | trim}}
  103. `
  104. // tmpl executes the given template text on data, writing the result to w.
  105. func tmpl(w io.Writer, text string, data interface{}) {
  106. t := template.New("top")
  107. t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
  108. template.Must(t.Parse(text))
  109. if err := t.Execute(w, data); err != nil {
  110. panic(err)
  111. }
  112. }
  113. func capitalize(s string) string {
  114. if s == "" {
  115. return s
  116. }
  117. r, n := utf8.DecodeRuneInString(s)
  118. return string(unicode.ToTitle(r)) + s[n:]
  119. }
  120. func printUsage(w io.Writer) {
  121. tmpl(w, usageTemplate, commands)
  122. }
  123. func usage() {
  124. printUsage(os.Stderr)
  125. os.Exit(2)
  126. }
  127. // help implements the 'help' command.
  128. func help(args []string) {
  129. if len(args) == 0 {
  130. printUsage(os.Stdout)
  131. // not exit 2: succeeded at 'go help'.
  132. return
  133. }
  134. if len(args) != 1 {
  135. fmt.Fprintf(os.Stderr, "usage: xs help command\n\nToo many arguments given.\n")
  136. os.Exit(2) // failed at 'xs help'
  137. }
  138. arg := args[0]
  139. for _, cmd := range commands {
  140. if cmd.Name() == arg {
  141. tmpl(os.Stdout, helpTemplate, cmd)
  142. // not exit 2: succeeded at 'go help cmd'.
  143. return
  144. }
  145. }
  146. fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'xs help'.\n", arg)
  147. os.Exit(2) // failed at 'go help cmd'
  148. }
  149. var atexitFuncs []func()
  150. func atexit(f func()) {
  151. atexitFuncs = append(atexitFuncs, f)
  152. }
  153. func exit() {
  154. for _, f := range atexitFuncs {
  155. f()
  156. }
  157. os.Exit(exitStatus)
  158. }
  159. func fatalf(format string, args ...interface{}) {
  160. errorf(format, args...)
  161. exit()
  162. }
  163. func errorf(format string, args ...interface{}) {
  164. log.Printf(format, args...)
  165. setExitStatus(1)
  166. }
  167. var logf = log.Printf
  168. func exitIfErrors() {
  169. if exitStatus != 0 {
  170. exit()
  171. }
  172. }