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