github.com/gsquire/gb@v0.4.4-0.20161112235727-3982dc872064/cmd/gb/help.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"sort"
    10  	"strings"
    11  	"text/template"
    12  	"unicode"
    13  	"unicode/utf8"
    14  
    15  	"github.com/constabulary/gb/cmd"
    16  )
    17  
    18  func init() {
    19  	registerCommand(helpProject)
    20  }
    21  
    22  var helpProject = &cmd.Command{
    23  	Name:  "project",
    24  	Short: "gb project layout",
    25  	Long: `A gb project is defined as any directory that contains a src/ subdirectory.
    26  gb automatically detects the root of the project by looking at the current
    27  working directory and walking backwards until it finds a directory that
    28  contains a src/ subdirectory.
    29  
    30  In the event you wish to override this auto detection mechanism, the -R flag
    31  can be used to supply a project root.
    32  
    33  See http://getgb.io/docs/project for details`,
    34  }
    35  
    36  var helpTemplate = `{{if .Runnable}}usage: gb {{.UsageLine}}
    37  
    38  {{end}}{{.Long | trim}}
    39  `
    40  
    41  // help implements the 'help' command.
    42  func help(args []string) {
    43  	if len(args) == 0 {
    44  		printUsage(os.Stdout)
    45  		// not exit 2: succeeded at 'gb help'.
    46  		return
    47  	}
    48  	if len(args) != 1 {
    49  		fmt.Fprintf(os.Stderr, "usage: gb help command\n\nToo many arguments given.\n")
    50  		exit(2) // failed at 'gb help'
    51  	}
    52  
    53  	arg := args[0]
    54  
    55  	// 'gb help documentation' generates alldocs.go.
    56  	if arg == "documentation" {
    57  		var buf bytes.Buffer
    58  		printUsage(&buf)
    59  		usage := &cmd.Command{Long: buf.String()}
    60  		f, _ := os.Create("alldocs.go")
    61  		tmpl(f, documentationTemplate, append([]*cmd.Command{usage}, sortedCommands()...))
    62  		f.Close()
    63  		return
    64  	}
    65  
    66  	for _, cmd := range commands {
    67  		if cmd.Name == arg {
    68  			tmpl(os.Stdout, helpTemplate, cmd)
    69  			// not exit 2: succeeded at 'gb help cmd'.
    70  			return
    71  		}
    72  	}
    73  
    74  	fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'gb help'.\n", arg)
    75  	exit(2) // failed at 'gb help cmd'
    76  }
    77  
    78  var usageTemplate = `gb, a project based build tool for the Go programming language.
    79  
    80  Usage:
    81  
    82          gb command [arguments]
    83  
    84  The commands are:
    85  {{range .}}{{if .Runnable}}
    86          {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
    87  
    88  Use "gb help [command]" for more information about a command.
    89  
    90  Additional help topics:
    91  {{range .}}{{if not .Runnable}}
    92          {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
    93  
    94  Use "gb help [topic]" for more information about that topic.
    95  `
    96  
    97  var documentationTemplate = `// DO NOT EDIT THIS FILE.
    98  //go:generate gb help documentation
    99  
   100  /*
   101  {{range .}}{{if .Short}}{{.Short | capitalize}}
   102  
   103  {{end}}{{if .Runnable}}Usage:
   104  
   105          gb {{.UsageLine}}
   106  
   107  {{end}}{{.Long | trim}}
   108  
   109  
   110  {{end}}*/
   111  package main
   112  `
   113  
   114  // tmpl executes the given template text on data, writing the result to w.
   115  func tmpl(w io.Writer, text string, data interface{}) {
   116  	t := template.New("top")
   117  	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
   118  	template.Must(t.Parse(text))
   119  	if err := t.Execute(w, data); err != nil {
   120  		panic(err)
   121  	}
   122  }
   123  
   124  func capitalize(s string) string {
   125  	if s == "" {
   126  		return s
   127  	}
   128  	r, n := utf8.DecodeRuneInString(s)
   129  	return string(unicode.ToTitle(r)) + s[n:]
   130  }
   131  
   132  func printUsage(w io.Writer) {
   133  	bw := bufio.NewWriter(w)
   134  	tmpl(bw, usageTemplate, sortedCommands())
   135  	bw.Flush()
   136  }
   137  
   138  func sortedCommands() []*cmd.Command {
   139  	// TODO(dfc) drop this and make main.commands a []*cmd.Command
   140  	var sortedKeys []string
   141  	for k := range commands {
   142  		sortedKeys = append(sortedKeys, k)
   143  	}
   144  
   145  	sort.Strings(sortedKeys)
   146  	var cmds []*cmd.Command
   147  	for _, c := range sortedKeys {
   148  
   149  		// skip hidden commands
   150  		if commands[c].Hidden() {
   151  			continue
   152  		}
   153  
   154  		cmds = append(cmds, commands[c])
   155  	}
   156  	return cmds
   157  }
   158  
   159  func usage() {
   160  	printUsage(os.Stderr)
   161  	exit(2)
   162  }