diff --git a/src/cmd/doc/doc.go b/src/cmd/doc/doc.go new file mode 100644 index 00000000000..ac15ad9c7d3 --- /dev/null +++ b/src/cmd/doc/doc.go @@ -0,0 +1,55 @@ +// Copyright 2015 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. + +// Doc (usually run as go doc) accepts zero, one or two arguments. +// +// Zero arguments: +// +// go doc +// +// Show the documentation for the package in the current directory. +// +// One argument: +// +// go doc +// go doc [.] +// go doc [.][.] +// go doc [.][.] +// +// The first item in this list that succeeds is the one whose documentation +// is printed. If there is a symbol but no package, the package in the current +// directory is chosen. However, if the argument begins with a capital +// letter it is always assumed to be a symbol in the current directory. +// +// Two arguments: +// +// go doc [.] +// +// Show the documentation for the package, symbol, and method or field. The +// first argument must be a full package path. This is similar to the +// command-line usage for the godoc command. +// +// For commands, unless the -cmd flag is present "go doc command" +// shows only the package-level docs for the package. +// +// The -src flag causes doc to print the full source code for the symbol, such +// as the body of a struct, function or method. +// +// The -all flag causes doc to print all documentation for the package and +// all its visible symbols. The argument must identify a package. +// +// For complete documentation, run "go help doc". +package main + +import ( + "cmd/internal/doc" + "cmd/internal/telemetry/counter" + "os" +) + +func main() { + counter.Open() + counter.Inc("doc/invocations") + doc.Main(os.Args[1:]) +} diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 83323aeaad0..3e691abe41f 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1093,10 +1093,10 @@ func TestGoListTest(t *testing.T) { tg.grepStdoutNot(`^testing \[bytes.test\]$`, "unexpected test copy of testing") tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing") - tg.run("list", "-test", "cmd/buildid", "cmd/doc") + tg.run("list", "-test", "cmd/buildid", "cmd/gofmt") tg.grepStdout(`^cmd/buildid$`, "missing cmd/buildid") - tg.grepStdout(`^cmd/doc$`, "missing cmd/doc") - tg.grepStdout(`^cmd/doc\.test$`, "missing cmd/doc test") + tg.grepStdout(`^cmd/gofmt$`, "missing cmd/gofmt") + tg.grepStdout(`^cmd/gofmt\.test$`, "missing cmd/gofmt test") tg.grepStdoutNot(`^cmd/buildid\.test$`, "unexpected cmd/buildid test") tg.grepStdoutNot(`^testing`, "unexpected testing") diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go index 7dfa652e155..131da814951 100644 --- a/src/cmd/go/internal/doc/doc.go +++ b/src/cmd/go/internal/doc/doc.go @@ -2,17 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !cmd_go_bootstrap + // Package doc implements the “go doc” command. package doc import ( "cmd/go/internal/base" - "cmd/go/internal/cfg" + "cmd/internal/doc" "context" - "errors" - "os" - "os/exec" - "path/filepath" ) var CmdDoc = &base.Command{ @@ -134,13 +132,5 @@ Flags: } func runDoc(ctx context.Context, cmd *base.Command, args []string) { - base.StartSigHandlers() - err := base.RunErr(cfg.BuildToolexec, filepath.Join(cfg.GOROOTbin, "go"), "tool", "doc", args) - if err != nil { - var ee *exec.ExitError - if errors.As(err, &ee) { - os.Exit(ee.ExitCode()) - } - base.Error(err) - } + doc.Main(args) } diff --git a/src/cmd/go/internal/doc/doc_bootstrap.go b/src/cmd/go/internal/doc/doc_bootstrap.go new file mode 100644 index 00000000000..8be95dc9a60 --- /dev/null +++ b/src/cmd/go/internal/doc/doc_bootstrap.go @@ -0,0 +1,13 @@ +// Copyright 2025 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. + +//go:build cmd_go_bootstrap + +// Don't build cmd/doc into go_bootstrap because it depends on net. + +package doc + +import "cmd/go/internal/base" + +var CmdDoc = &base.Command{} diff --git a/src/cmd/doc/dirs.go b/src/cmd/internal/doc/dirs.go similarity index 99% rename from src/cmd/doc/dirs.go rename to src/cmd/internal/doc/dirs.go index 60ad6d30e6a..8b1670f61c2 100644 --- a/src/cmd/doc/dirs.go +++ b/src/cmd/internal/doc/dirs.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package doc import ( "bytes" diff --git a/src/cmd/doc/doc_test.go b/src/cmd/internal/doc/doc_test.go similarity index 99% rename from src/cmd/doc/doc_test.go rename to src/cmd/internal/doc/doc_test.go index 3b383bdd78e..bccace40c0f 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/internal/doc/doc_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package doc import ( "bytes" @@ -90,7 +90,7 @@ type test struct { no []string // Regular expressions that should not match. } -const p = "cmd/doc/testdata" +const p = "cmd/internal/doc/testdata" var tests = []test{ // Sanity check. @@ -105,7 +105,7 @@ var tests = []test{ { "package clause", []string{p}, - []string{`package pkg.*cmd/doc/testdata`}, + []string{`package pkg.*cmd/internal/doc/testdata`}, nil, }, diff --git a/src/cmd/doc/main.go b/src/cmd/internal/doc/main.go similarity index 89% rename from src/cmd/doc/main.go rename to src/cmd/internal/doc/main.go index 490337a0b49..a19f36e1bd5 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/internal/doc/main.go @@ -2,45 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Doc (usually run as go doc) accepts zero, one or two arguments. -// -// Zero arguments: -// -// go doc -// -// Show the documentation for the package in the current directory. -// -// One argument: -// -// go doc -// go doc [.] -// go doc [.][.] -// go doc [.][.] -// -// The first item in this list that succeeds is the one whose documentation -// is printed. If there is a symbol but no package, the package in the current -// directory is chosen. However, if the argument begins with a capital -// letter it is always assumed to be a symbol in the current directory. -// -// Two arguments: -// -// go doc [.] -// -// Show the documentation for the package, symbol, and method or field. The -// first argument must be a full package path. This is similar to the -// command-line usage for the godoc command. -// -// For commands, unless the -cmd flag is present "go doc command" -// shows only the package-level docs for the package. -// -// The -src flag causes doc to print the full source code for the symbol, such -// as the body of a struct, function or method. -// -// The -all flag causes doc to print all documentation for the package and -// all its visible symbols. The argument must identify a package. -// -// For complete documentation, run "go help doc". -package main +// Package doc provides the implementation of the "go doc" subcommand and cmd/doc. +package doc import ( "bytes" @@ -74,7 +37,7 @@ var ( ) // usage is a replacement usage function for the flags package. -func usage() { +func usage(flagSet *flag.FlagSet) { fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n") fmt.Fprintf(os.Stderr, "\tgo doc\n") fmt.Fprintf(os.Stderr, "\tgo doc \n") @@ -85,16 +48,17 @@ func usage() { fmt.Fprintf(os.Stderr, "For more information run\n") fmt.Fprintf(os.Stderr, "\tgo help doc\n\n") fmt.Fprintf(os.Stderr, "Flags:\n") - flag.PrintDefaults() + flagSet.PrintDefaults() os.Exit(2) } -func main() { +// Main is the entry point, invoked both by go doc and cmd/doc. +func Main(args []string) { log.SetFlags(0) log.SetPrefix("doc: ") - counter.Open() dirsInit() - err := do(os.Stdout, flag.CommandLine, os.Args[1:]) + var flagSet flag.FlagSet + err := do(os.Stdout, &flagSet, args) if err != nil { log.Fatal(err) } @@ -102,7 +66,7 @@ func main() { // do is the workhorse, broken out of main to make testing easier. func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { - flagSet.Usage = usage + flagSet.Usage = func() { usage(flagSet) } unexported = false matchCase = false flagSet.StringVar(&chdir, "C", "", "change to `dir` before running command") @@ -114,7 +78,6 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { flagSet.BoolVar(&short, "short", false, "one-line representation for each symbol") flagSet.BoolVar(&serveHTTP, "http", false, "serve HTML docs over HTTP") flagSet.Parse(args) - counter.Inc("doc/invocations") counter.CountFlags("doc/flag:", *flag.CommandLine) if chdir != "" { if err := os.Chdir(chdir); err != nil { @@ -151,7 +114,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { // Loop until something is printed. dirs.Reset() for i := 0; ; i++ { - buildPackage, userPath, sym, more := parseArgs(flagSet.Args()) + buildPackage, userPath, sym, more := parseArgs(flagSet, flagSet.Args()) if i > 0 && !more { // Ignore the "more" bit on the first iteration. return failMessage(paths, symbol, method) } @@ -165,7 +128,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { unexported = true } - symbol, method = parseSymbol(sym) + symbol, method = parseSymbol(flagSet, sym) pkg := parsePackage(writer, buildPackage, userPath) paths = append(paths, pkg.prettyPath()) @@ -338,7 +301,7 @@ func failMessage(paths []string, symbol, method string) error { // and there may be more matches. For example, if the argument // is rand.Float64, we must scan both crypto/rand and math/rand // to find the symbol, and the first call will return crypto/rand, true. -func parseArgs(args []string) (pkg *build.Package, path, symbol string, more bool) { +func parseArgs(flagSet *flag.FlagSet, args []string) (pkg *build.Package, path, symbol string, more bool) { wd, err := os.Getwd() if err != nil { log.Fatal(err) @@ -356,7 +319,7 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo } switch len(args) { default: - usage() + usage(flagSet) case 1: // Done below. case 2: @@ -499,7 +462,7 @@ func importDir(dir string) *build.Package { // parseSymbol breaks str apart into a symbol and method. // Both may be missing or the method may be missing. // If present, each must be a valid Go identifier. -func parseSymbol(str string) (symbol, method string) { +func parseSymbol(flagSet *flag.FlagSet, str string) (symbol, method string) { if str == "" { return } @@ -510,7 +473,7 @@ func parseSymbol(str string) (symbol, method string) { method = elem[1] default: log.Printf("too many periods in symbol specification") - usage() + usage(flagSet) } symbol = elem[0] return diff --git a/src/cmd/doc/pkg.go b/src/cmd/internal/doc/pkg.go similarity index 99% rename from src/cmd/doc/pkg.go rename to src/cmd/internal/doc/pkg.go index a21d8a46882..953b0d9a284 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/internal/doc/pkg.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package doc import ( "bufio" diff --git a/src/cmd/doc/signal_notunix.go b/src/cmd/internal/doc/signal_notunix.go similarity index 95% rename from src/cmd/doc/signal_notunix.go rename to src/cmd/internal/doc/signal_notunix.go index 3b8fa9e0803..b91a67eb5fb 100644 --- a/src/cmd/doc/signal_notunix.go +++ b/src/cmd/internal/doc/signal_notunix.go @@ -4,7 +4,7 @@ //go:build plan9 || windows -package main +package doc import ( "os" diff --git a/src/cmd/doc/signal_unix.go b/src/cmd/internal/doc/signal_unix.go similarity index 95% rename from src/cmd/doc/signal_unix.go rename to src/cmd/internal/doc/signal_unix.go index 52431c221b5..f30612ce9dc 100644 --- a/src/cmd/doc/signal_unix.go +++ b/src/cmd/internal/doc/signal_unix.go @@ -4,7 +4,7 @@ //go:build unix || js || wasip1 -package main +package doc import ( "os" diff --git a/src/cmd/doc/testdata/merge/aa.go b/src/cmd/internal/doc/testdata/merge/aa.go similarity index 100% rename from src/cmd/doc/testdata/merge/aa.go rename to src/cmd/internal/doc/testdata/merge/aa.go diff --git a/src/cmd/doc/testdata/merge/bb.go b/src/cmd/internal/doc/testdata/merge/bb.go similarity index 100% rename from src/cmd/doc/testdata/merge/bb.go rename to src/cmd/internal/doc/testdata/merge/bb.go diff --git a/src/cmd/doc/testdata/nested/empty/empty.go b/src/cmd/internal/doc/testdata/nested/empty/empty.go similarity index 100% rename from src/cmd/doc/testdata/nested/empty/empty.go rename to src/cmd/internal/doc/testdata/nested/empty/empty.go diff --git a/src/cmd/doc/testdata/nested/ignore.go b/src/cmd/internal/doc/testdata/nested/ignore.go similarity index 100% rename from src/cmd/doc/testdata/nested/ignore.go rename to src/cmd/internal/doc/testdata/nested/ignore.go diff --git a/src/cmd/doc/testdata/nested/nested/real.go b/src/cmd/internal/doc/testdata/nested/nested/real.go similarity index 100% rename from src/cmd/doc/testdata/nested/nested/real.go rename to src/cmd/internal/doc/testdata/nested/nested/real.go diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/internal/doc/testdata/pkg.go similarity index 100% rename from src/cmd/doc/testdata/pkg.go rename to src/cmd/internal/doc/testdata/pkg.go