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