main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. //go:generate gomobile help documentation doc.go
  6. import (
  7. "bufio"
  8. "bytes"
  9. "errors"
  10. "flag"
  11. "fmt"
  12. "html/template"
  13. "io"
  14. "io/ioutil"
  15. "log"
  16. "os"
  17. "os/exec"
  18. "unicode"
  19. "unicode/utf8"
  20. )
  21. var (
  22. gomobileName = "gomobile"
  23. goVersionOut = []byte(nil)
  24. )
  25. func printUsage(w io.Writer) {
  26. bufw := bufio.NewWriter(w)
  27. if err := usageTmpl.Execute(bufw, commands); err != nil {
  28. panic(err)
  29. }
  30. bufw.Flush()
  31. }
  32. func main() {
  33. gomobileName = os.Args[0]
  34. flag.Usage = func() {
  35. printUsage(os.Stderr)
  36. os.Exit(2)
  37. }
  38. flag.Parse()
  39. log.SetFlags(0)
  40. args := flag.Args()
  41. if len(args) < 1 {
  42. flag.Usage()
  43. }
  44. if args[0] == "help" {
  45. if len(args) == 3 && args[1] == "documentation" {
  46. helpDocumentation(args[2])
  47. return
  48. }
  49. help(args[1:])
  50. return
  51. }
  52. if err := determineGoVersion(); err != nil {
  53. fmt.Fprintf(os.Stderr, "%s: %v\n", gomobileName, err)
  54. os.Exit(1)
  55. }
  56. for _, cmd := range commands {
  57. if cmd.Name == args[0] {
  58. cmd.flag.Usage = func() {
  59. cmd.usage()
  60. os.Exit(1)
  61. }
  62. cmd.flag.Parse(args[1:])
  63. if err := cmd.run(cmd); err != nil {
  64. msg := err.Error()
  65. if msg != "" {
  66. fmt.Fprintf(os.Stderr, "%s: %v\n", os.Args[0], err)
  67. }
  68. os.Exit(1)
  69. }
  70. return
  71. }
  72. }
  73. fmt.Fprintf(os.Stderr, "%s: unknown subcommand %q\nRun 'gomobile help' for usage.\n", os.Args[0], args[0])
  74. os.Exit(2)
  75. }
  76. func determineGoVersion() error {
  77. goVersionOut, err := exec.Command("go", "version").CombinedOutput()
  78. if err != nil {
  79. return fmt.Errorf("'go version' failed: %v, %s", err, goVersionOut)
  80. }
  81. var minor int
  82. if _, err := fmt.Sscanf(string(goVersionOut), "go version go1.%d", &minor); err != nil {
  83. // Ignore unknown versions; it's probably a devel version.
  84. return nil
  85. }
  86. if minor < 16 {
  87. return errors.New("Go 1.16 or newer is required")
  88. }
  89. return nil
  90. }
  91. func help(args []string) {
  92. if len(args) == 0 {
  93. printUsage(os.Stdout)
  94. return // succeeded at helping
  95. }
  96. if len(args) != 1 {
  97. fmt.Fprintf(os.Stderr, "usage: %s help command\n\nToo many arguments given.\n", gomobileName)
  98. os.Exit(2) // failed to help
  99. }
  100. arg := args[0]
  101. for _, cmd := range commands {
  102. if cmd.Name == arg {
  103. cmd.usage()
  104. return // succeeded at helping
  105. }
  106. }
  107. fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run '%s help'.\n", arg, gomobileName)
  108. os.Exit(2)
  109. }
  110. const documentationHeader = `// Copyright 2015 The Go Authors. All rights reserved.
  111. // Use of this source code is governed by a BSD-style
  112. // license that can be found in the LICENSE file.
  113. // Code generated by 'gomobile help documentation doc.go'. DO NOT EDIT.
  114. `
  115. func helpDocumentation(path string) {
  116. w := new(bytes.Buffer)
  117. w.WriteString(documentationHeader)
  118. w.WriteString("\n/*\n")
  119. if err := usageTmpl.Execute(w, commands); err != nil {
  120. log.Fatal(err)
  121. }
  122. for _, cmd := range commands {
  123. r, rlen := utf8.DecodeRuneInString(cmd.Short)
  124. w.WriteString("\n\n")
  125. w.WriteRune(unicode.ToUpper(r))
  126. w.WriteString(cmd.Short[rlen:])
  127. w.WriteString("\n\nUsage:\n\n\tgomobile " + cmd.Name)
  128. if cmd.Usage != "" {
  129. w.WriteRune(' ')
  130. w.WriteString(cmd.Usage)
  131. }
  132. w.WriteRune('\n')
  133. w.WriteString(cmd.Long)
  134. }
  135. w.WriteString("*/\npackage main // import \"golang.org/x/mobile/cmd/gomobile\"\n")
  136. if err := ioutil.WriteFile(path, w.Bytes(), 0666); err != nil {
  137. log.Fatal(err)
  138. }
  139. }
  140. var commands = []*command{
  141. // TODO(crawshaw): cmdRun
  142. cmdBind,
  143. cmdBuild,
  144. cmdClean,
  145. cmdInit,
  146. cmdInstall,
  147. cmdVersion,
  148. }
  149. type command struct {
  150. run func(*command) error
  151. flag flag.FlagSet
  152. Name string
  153. Usage string
  154. Short string
  155. Long string
  156. }
  157. func (cmd *command) usage() {
  158. fmt.Fprintf(os.Stdout, "usage: %s %s %s\n%s", gomobileName, cmd.Name, cmd.Usage, cmd.Long)
  159. }
  160. var usageTmpl = template.Must(template.New("usage").Parse(
  161. `Gomobile is a tool for building and running mobile apps written in Go.
  162. To install:
  163. $ go install golang.org/x/mobile/cmd/gomobile@latest
  164. $ gomobile init
  165. At least Go 1.16 is required.
  166. For detailed instructions, see https://golang.org/wiki/Mobile.
  167. Usage:
  168. gomobile command [arguments]
  169. Commands:
  170. {{range .}}
  171. {{.Name | printf "%-11s"}} {{.Short}}{{end}}
  172. Use 'gomobile help [command]' for more information about that command.
  173. `))