github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/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  	gobin, err := exec.LookPath("go")
    89  	if err != nil {
    90  		return errors.New("go not found")
    91  	}
    92  	goVersionOut, err = exec.Command(gobin, "version").CombinedOutput()
    93  	if err != nil {
    94  		return fmt.Errorf("'go version' failed: %v, %s", err, goVersionOut)
    95  	}
    96  	var minor int
    97  	if _, err := fmt.Sscanf(string(goVersionOut), "go version go1.%d", &minor); err != nil {
    98  		// Ignore unknown versions; it's probably a devel version.
    99  		return nil
   100  	}
   101  	if minor < 10 {
   102  		return errors.New("Go 1.10 or newer is required")
   103  	}
   104  	return nil
   105  }
   106  
   107  func help(args []string) {
   108  	if len(args) == 0 {
   109  		printUsage(os.Stdout)
   110  		return // succeeded at helping
   111  	}
   112  	if len(args) != 1 {
   113  		fmt.Fprintf(os.Stderr, "usage: %s help command\n\nToo many arguments given.\n", gomobileName)
   114  		os.Exit(2) // failed to help
   115  	}
   116  
   117  	arg := args[0]
   118  	for _, cmd := range commands {
   119  		if cmd.Name == arg {
   120  			cmd.usage()
   121  			return // succeeded at helping
   122  		}
   123  	}
   124  
   125  	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run '%s help'.\n", arg, gomobileName)
   126  	os.Exit(2)
   127  }
   128  
   129  const documentationHeader = `// Copyright 2015 The Go Authors.  All rights reserved.
   130  // Use of this source code is governed by a BSD-style
   131  // license that can be found in the LICENSE file.
   132  
   133  // Code generated by 'gomobile help documentation doc.go'. DO NOT EDIT.
   134  `
   135  
   136  func helpDocumentation(path string) {
   137  	w := new(bytes.Buffer)
   138  	w.WriteString(documentationHeader)
   139  	w.WriteString("\n/*\n")
   140  	if err := usageTmpl.Execute(w, commands); err != nil {
   141  		log.Fatal(err)
   142  	}
   143  
   144  	for _, cmd := range commands {
   145  		r, rlen := utf8.DecodeRuneInString(cmd.Short)
   146  		w.WriteString("\n\n")
   147  		w.WriteRune(unicode.ToUpper(r))
   148  		w.WriteString(cmd.Short[rlen:])
   149  		w.WriteString("\n\nUsage:\n\n\tgomobile " + cmd.Name)
   150  		if cmd.Usage != "" {
   151  			w.WriteRune(' ')
   152  			w.WriteString(cmd.Usage)
   153  		}
   154  		w.WriteRune('\n')
   155  		w.WriteString(cmd.Long)
   156  	}
   157  
   158  	w.WriteString("*/\npackage main // import \"golang.org/x/mobile/cmd/gomobile\"\n")
   159  
   160  	if err := ioutil.WriteFile(path, w.Bytes(), 0666); err != nil {
   161  		log.Fatal(err)
   162  	}
   163  }
   164  
   165  var commands = []*command{
   166  	// TODO(crawshaw): cmdRun
   167  	cmdBind,
   168  	cmdBuild,
   169  	cmdClean,
   170  	cmdInit,
   171  	cmdInstall,
   172  	cmdVersion,
   173  }
   174  
   175  type command struct {
   176  	run   func(*command) error
   177  	flag  flag.FlagSet
   178  	Name  string
   179  	Usage string
   180  	Short string
   181  	Long  string
   182  }
   183  
   184  func (cmd *command) usage() {
   185  	fmt.Fprintf(os.Stdout, "usage: %s %s %s\n%s", gomobileName, cmd.Name, cmd.Usage, cmd.Long)
   186  }
   187  
   188  var usageTmpl = template.Must(template.New("usage").Parse(
   189  	`Gomobile is a tool for building and running mobile apps written in Go.
   190  
   191  To install:
   192  
   193  	$ go get golang.org/x/mobile/cmd/gomobile
   194  	$ gomobile init
   195  
   196  At least Go 1.10 is required.
   197  For detailed instructions, see https://golang.org/wiki/Mobile.
   198  
   199  Usage:
   200  
   201  	gomobile command [arguments]
   202  
   203  Commands:
   204  {{range .}}
   205  	{{.Name | printf "%-11s"}} {{.Short}}{{end}}
   206  
   207  Use 'gomobile help [command]' for more information about that command.
   208  `))