github.com/MrKrisYu/mobile@v0.0.0-20230923092425-9be92a9aeacc/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 \"golang.org/x/mobile/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 golang.org/x/mobile/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  `))