1
0
mirror of https://github.com/golang/go synced 2024-10-01 16:28:33 -06:00

cmd/go: split out cmd/go/internal/help

This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

Change-Id: I4cf05b076d81b780c87a31378523929b5da8964b
Reviewed-on: https://go-review.googlesource.com/36194
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Russ Cox 2017-01-13 14:51:57 -05:00
parent 6dc9e31f5e
commit 2cab41d5cb
4 changed files with 205 additions and 189 deletions

View File

@ -43,6 +43,10 @@ type Command struct {
CustomFlags bool CustomFlags bool
} }
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var Commands []*Command
// Name returns the command's name: the first word in the usage line. // Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string { func (c *Command) Name() string {
name := c.UsageLine name := c.UsageLine

View File

@ -0,0 +1,178 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package help implements "go help".
package help
import (
"bufio"
"bytes"
"fmt"
"html/template"
"io"
"os"
"strings"
"unicode"
"unicode/utf8"
"cmd/go/internal/base"
)
// Help implements the 'help' command.
func Help(args []string) {
if len(args) == 0 {
PrintUsage(os.Stdout)
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'go help'
}
arg := args[0]
// 'go help documentation' generates doc.go.
if arg == "documentation" {
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
PrintUsage(buf)
usage := &base.Command{Long: buf.String()}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...))
fmt.Println("package main")
return
}
for _, cmd := range base.Commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
os.Exit(2) // failed at 'go help cmd'
}
var usageTemplate = `Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
go {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
type commentWriter struct {
W io.Writer
wroteSlashes bool // Wrote "//" at the beginning of the current line.
}
func (c *commentWriter) Write(p []byte) (int, error) {
var n int
for i, b := range p {
if !c.wroteSlashes {
s := "//"
if b != '\n' {
s = "// "
}
if _, err := io.WriteString(c.W, s); err != nil {
return n, err
}
c.wroteSlashes = true
}
n0, err := c.W.Write(p[i : i+1])
n += n0
if err != nil {
return n, err
}
if b == '\n' {
c.wroteSlashes = false
}
}
return len(p), nil
}
// An errWriter wraps a writer, recording whether a write error occurred.
type errWriter struct {
w io.Writer
err error
}
func (w *errWriter) Write(b []byte) (int, error) {
n, err := w.w.Write(b)
if err != nil {
w.err = err
}
return n, err
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
ew := &errWriter{w: w}
err := t.Execute(ew, data)
if ew.err != nil {
// I/O error writing. Ignore write on closed pipe.
if strings.Contains(ew.err.Error(), "pipe") {
os.Exit(1)
}
base.Fatalf("writing output: %v", ew.err)
}
if err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func PrintUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, base.Commands)
bw.Flush()
}

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package help
import "cmd/go/internal/base" import "cmd/go/internal/base"
var helpC = &base.Command{ var HelpC = &base.Command{
UsageLine: "c", UsageLine: "c",
Short: "calling between Go and C", Short: "calling between Go and C",
Long: ` Long: `
@ -28,7 +28,7 @@ the C or C++ compiler, respectively, to use.
`, `,
} }
var helpPackages = &base.Command{ var HelpPackages = &base.Command{
UsageLine: "packages", UsageLine: "packages",
Short: "description of package lists", Short: "description of package lists",
Long: ` Long: `
@ -102,7 +102,7 @@ by the go tool, as are directories named "testdata".
`, `,
} }
var helpImportPath = &base.Command{ var HelpImportPath = &base.Command{
UsageLine: "importpath", UsageLine: "importpath",
Short: "import path syntax", Short: "import path syntax",
Long: ` Long: `
@ -279,7 +279,7 @@ See https://golang.org/s/go14customimport for details.
`, `,
} }
var helpGopath = &base.Command{ var HelpGopath = &base.Command{
UsageLine: "gopath", UsageLine: "gopath",
Short: "GOPATH environment variable", Short: "GOPATH environment variable",
Long: ` Long: `
@ -431,7 +431,7 @@ See https://golang.org/s/go15vendor for details.
`, `,
} }
var helpEnvironment = &base.Command{ var HelpEnvironment = &base.Command{
UsageLine: "environment", UsageLine: "environment",
Short: "environment variables", Short: "environment variables",
Long: ` Long: `
@ -513,7 +513,7 @@ Special-purpose environment variables:
`, `,
} }
var helpFileType = &base.Command{ var HelpFileType = &base.Command{
UsageLine: "filetype", UsageLine: "filetype",
Short: "file types", Short: "file types",
Long: ` Long: `
@ -559,7 +559,7 @@ for more details.
`, `,
} }
var helpBuildmode = &base.Command{ var HelpBuildmode = &base.Command{
UsageLine: "buildmode", UsageLine: "buildmode",
Short: "description of build modes", Short: "description of build modes",
Long: ` Long: `

View File

@ -5,14 +5,9 @@
package main package main
import ( import (
"bufio"
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"flag" "flag"
"fmt" "fmt"
"go/build" "go/build"
"io"
"log" "log"
"os" "os"
"path" "path"
@ -20,17 +15,14 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"text/template"
"unicode" "cmd/go/internal/base"
"unicode/utf8" "cmd/go/internal/cfg"
"cmd/go/internal/help"
) )
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands []*base.Command
func init() { func init() {
commands = []*base.Command{ base.Commands = []*base.Command{
cmdBuild, cmdBuild,
cmdClean, cmdClean,
cmdDoc, cmdDoc,
@ -48,13 +40,13 @@ func init() {
cmdVersion, cmdVersion,
cmdVet, cmdVet,
helpC, help.HelpC,
helpBuildmode, help.HelpBuildmode,
helpFileType, help.HelpFileType,
helpGopath, help.HelpGopath,
helpEnvironment, help.HelpEnvironment,
helpImportPath, help.HelpImportPath,
helpPackages, help.HelpPackages,
helpTestflag, helpTestflag,
helpTestfunc, helpTestfunc,
} }
@ -72,7 +64,7 @@ func main() {
} }
if args[0] == "help" { if args[0] == "help" {
help(args[1:]) help.Help(args[1:])
return return
} }
@ -115,7 +107,7 @@ func main() {
} }
} }
for _, cmd := range commands { for _, cmd := range base.Commands {
if cmd.Name() == args[0] && cmd.Runnable() { if cmd.Name() == args[0] && cmd.Runnable() {
cmd.Flag.Usage = func() { cmd.Usage() } cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags { if cmd.CustomFlags {
@ -135,121 +127,6 @@ func main() {
base.Exit() base.Exit()
} }
var usageTemplate = `Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
go {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
type commentWriter struct {
W io.Writer
wroteSlashes bool // Wrote "//" at the beginning of the current line.
}
func (c *commentWriter) Write(p []byte) (int, error) {
var n int
for i, b := range p {
if !c.wroteSlashes {
s := "//"
if b != '\n' {
s = "// "
}
if _, err := io.WriteString(c.W, s); err != nil {
return n, err
}
c.wroteSlashes = true
}
n0, err := c.W.Write(p[i : i+1])
n += n0
if err != nil {
return n, err
}
if b == '\n' {
c.wroteSlashes = false
}
}
return len(p), nil
}
// An errWriter wraps a writer, recording whether a write error occurred.
type errWriter struct {
w io.Writer
err error
}
func (w *errWriter) Write(b []byte) (int, error) {
n, err := w.w.Write(b)
if err != nil {
w.err = err
}
return n, err
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
ew := &errWriter{w: w}
err := t.Execute(ew, data)
if ew.err != nil {
// I/O error writing. Ignore write on closed pipe.
if strings.Contains(ew.err.Error(), "pipe") {
os.Exit(1)
}
base.Fatalf("writing output: %v", ew.err)
}
if err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func printUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, commands)
bw.Flush()
}
var usage func() var usage func()
func init() { func init() {
@ -264,53 +141,10 @@ func mainUsage() {
strings.TrimSpace(testFlag2) + "\n") strings.TrimSpace(testFlag2) + "\n")
os.Exit(2) os.Exit(2)
} }
printUsage(os.Stderr) help.PrintUsage(os.Stderr)
os.Exit(2) os.Exit(2)
} }
// help implements the 'help' command.
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'go help'
}
arg := args[0]
// 'go help documentation' generates doc.go.
if arg == "documentation" {
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
printUsage(buf)
usage := &base.Command{Long: buf.String()}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, commands...))
fmt.Println("package main")
return
}
for _, cmd := range commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
os.Exit(2) // failed at 'go help cmd'
}
// importPathsNoDotExpansion returns the import paths to use for the given // importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion. // command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string { func importPathsNoDotExpansion(args []string) []string {