github.com/kekek/gb@v0.4.5-0.20170222120241-d4ba64b0b297/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 }