summaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/help/help.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2018-07-28 20:25:06 -0400
committerRuss Cox <rsc@golang.org>2018-08-01 00:35:17 +0000
commit6121987a10b2c54bc4c48473353205753d91f807 (patch)
treefcbb2090efe8a86daea4408d875adfe60d112238 /src/cmd/go/internal/help/help.go
parent16962faf998a2f84793c5ca8481f6686ae9e3024 (diff)
downloadgo-git-6121987a10b2c54bc4c48473353205753d91f807.tar.gz
cmd/go: split go mod into multiple subcommands
The current "go mod" command does too many things. The design is unclear. It looks like "everything you might want to do with modules" which causes people to think all module operations go through "go mod", which is the opposite of the seamless integration we're going for. In particular too many people think "go mod -require" and "go get" are the same. It does make sense to put the module-specific functionality under "go mod", but not as flags. Instead, split "go mod" into multiple subcommands: go mod edit # old go mod -require ... go mod fix # old go mod -fix go mod graph # old go mod -graph go mod init # old go mod -init go mod tidy # old go mod -sync go mod vendor # old go mod -vendor go mod verify # old go mod -verify Splitting out the individual commands makes both the docs and the implementations dramatically easier to read. It simplifies the command lines (go mod -init -module m is now 'go mod init m') and allows command-specific flags. We've avoided subcommands in the go command to date, and we should continue to avoid adding them unless it really makes the experience significantly better. In this case, it does. Creating subcommands required some changes in the core command-parsing and help logic to generalize from one level to multiple levels. As part of having "go mod init" be a separate command, this CL changes the failure behavior during module initialization to be delayed until modules are actually needed. Initialization can still happen early, but the base.Fatalf is delayed until something needs to use modules. This fixes a bunch of commands like 'go env' that were unhelpfully failing with GO111MODULE=on when not in a module directory. Fixes #26432. Fixes #26581. Fixes #26596. Fixes #26639. Change-Id: I868db0babe8c288e8af684b29d4a5ae4825d6407 Reviewed-on: https://go-review.googlesource.com/126655 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
Diffstat (limited to 'src/cmd/go/internal/help/help.go')
-rw-r--r--src/cmd/go/internal/help/help.go77
1 files changed, 41 insertions, 36 deletions
diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go
index 14cfb6d747..a80afe36c4 100644
--- a/src/cmd/go/internal/help/help.go
+++ b/src/cmd/go/internal/help/help.go
@@ -21,20 +21,8 @@ import (
// 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" {
+ if len(args) == 1 && args[0] == "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.")
@@ -43,68 +31,85 @@ func Help(args []string) {
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
- PrintUsage(buf)
+ PrintUsage(buf, base.Go)
usage := &base.Command{Long: buf.String()}
cmds := []*base.Command{usage}
- for _, cmd := range base.Commands {
+ for _, cmd := range base.Go.Commands {
if cmd.UsageLine == "gopath-get" {
// Avoid duplication of the "get" documentation.
continue
}
cmds = append(cmds, cmd)
+ cmds = append(cmds, cmd.Commands...)
}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, cmds)
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
+ cmd := base.Go
+Args:
+ for i, arg := range args {
+ for _, sub := range cmd.Commands {
+ if sub.Name() == arg {
+ cmd = sub
+ continue Args
+ }
}
+
+ // helpSuccess is the help command using as many args as possible that would succeed.
+ helpSuccess := "go help"
+ if i > 0 {
+ helpSuccess = " " + strings.Join(args[:i], " ")
+ }
+ fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess)
+ os.Exit(2) // failed at 'go help cmd'
}
- fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
- os.Exit(2) // failed at 'go help cmd'
+ if len(cmd.Commands) > 0 {
+ PrintUsage(os.Stdout, cmd)
+ } else {
+ tmpl(os.Stdout, helpTemplate, cmd)
+ }
+ // not exit 2: succeeded at 'go help cmd'.
+ return
}
-var usageTemplate = `Go is a tool for managing Go source code.
+var usageTemplate = `{{.Long | trim}}
Usage:
- go command [arguments]
+ {{.UsageLine}} <command> [arguments]
The commands are:
-{{range .}}{{if .Runnable}}
+{{range .Commands}}{{if or (.Runnable) .Commands}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-Use "go help [command]" for more information about a command.
-
+Use "go help{{with .LongName}} {{.}}{{end}} <command>" for more information about a command.
+{{if eq (.UsageLine) "go"}}
Additional help topics:
-{{range .}}{{if not .Runnable}}
+{{range .Commands}}{{if and (not .Runnable) (not .Commands)}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-Use "go help [topic]" for more information about that topic.
-
+Use "go help{{with .LongName}} {{.}}{{end}} <topic>" for more information about that topic.
+{{end}}
`
-var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
+var helpTemplate = `{{if .Runnable}}usage: {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
-{{end}}{{if .Runnable}}Usage:
+{{end}}{{if .Commands}}` + usageTemplate + `{{else}}{{if .Runnable}}Usage:
- go {{.UsageLine}}
+ {{.UsageLine}}
{{end}}{{.Long | trim}}
-{{end}}`
+{{end}}{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
@@ -179,8 +184,8 @@ func capitalize(s string) string {
return string(unicode.ToTitle(r)) + s[n:]
}
-func PrintUsage(w io.Writer) {
+func PrintUsage(w io.Writer, cmd *base.Command) {
bw := bufio.NewWriter(w)
- tmpl(bw, usageTemplate, base.Commands)
+ tmpl(bw, usageTemplate, cmd)
bw.Flush()
}