From 2a5ac1a993efc463efdce7996efd356dabf03a25 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 21 May 2025 12:18:03 -0400 Subject: [PATCH] cmd/doc: allow go doc -http without package in current directory go doc tries to find a package to display documentation for. In the case that no package is provided, it uses "." just like go list does. So if go doc -http is run without any arguments, it tries to show the documentation for the package in the current directory. As a special case, if no arguments are provided, allow no package to match the current directory and just open the root pkgsite page. For #68106 Change-Id: I6d65b160a838591db953fac630eced6b09106877 Reviewed-on: https://go-review.googlesource.com/c/go/+/675075 Reviewed-by: Alan Donovan Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI --- src/cmd/doc/main.go | 60 ++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index 4c47b4bcfc..03654e5824 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -122,8 +122,21 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { } } if serveHTTP { - // We want to run the logic below to determine a match for a symbol, method, - // or field, but not actually print the documentation to the output. + // Special case: if there are no arguments to go doc -http, allow + // there to be no package in the current directory. We'll still try + // to open the page for the documentation of the package in the current + // directory, but if one doesn't exist, fall back to opening the home page. + if len(flagSet.Args()) == 0 { + var path string + if importPath, err := runCmd("go", "list"); err == nil { + path = importPath + } + return doPkgsite(path) + } + + // If args are provided, we need to figure out which page to open on the pkgsite + // instance. Run the logic below to determine a match for a symbol, method, + // or field, but don't actually print the documentation to the output. writer = io.Discard } var paths []string @@ -179,44 +192,41 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { } if found { if serveHTTP { - return doPkgsite(userPath, pkg, symbol, method) + path, err := objectPath(userPath, pkg, symbol, method) + if err != nil { + return err + } + return doPkgsite(path) } return nil } } } -func listUserPath(userPath string) (string, error) { +func runCmd(cmdline ...string) (string, error) { var stdout, stderr strings.Builder - cmd := exec.Command("go", "list", userPath) + cmd := exec.Command(cmdline[0], cmdline[1:]...) cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - return "", fmt.Errorf("go doc: go list %s: %v\n%s\n", userPath, err, stderr.String()) + return "", fmt.Errorf("go doc: %s: %v\n%s\n", strings.Join(cmdline, " "), err, stderr.String()) } return strings.TrimSpace(stdout.String()), nil } -func doPkgsite(userPath string, pkg *Package, symbol, method string) error { - port, err := pickUnusedPort() - if err != nil { - return fmt.Errorf("failed to find port for documentation server: %v", err) - } - addr := fmt.Sprintf("localhost:%d", port) - - // Assemble url to open on the browser, to point to documentation of - // the requested object. - importPath := pkg.build.ImportPath - if importPath == "." { +func objectPath(userPath string, pkg *Package, symbol, method string) (string, error) { + var err error + path := pkg.build.ImportPath + if path == "." { // go/build couldn't determine the import path, probably // because this was a relative path into a module. Use // go list to get the import path. - importPath, err = listUserPath(userPath) + path, err = runCmd("go", "list", userPath) if err != nil { - return err + return "", err } } - path := path.Join("http://"+addr, importPath) + object := symbol if symbol != "" && method != "" { object = symbol + "." + method @@ -224,6 +234,16 @@ func doPkgsite(userPath string, pkg *Package, symbol, method string) error { if object != "" { path = path + "#" + object } + return path, nil +} + +func doPkgsite(urlPath string) error { + port, err := pickUnusedPort() + if err != nil { + return fmt.Errorf("failed to find port for documentation server: %v", err) + } + addr := fmt.Sprintf("localhost:%d", port) + path := path.Join("http://"+addr, urlPath) // Turn off the default signal handler for SIGINT (and SIGQUIT on Unix) // and instead wait for the child process to handle the signal and -- 2.50.0