1
2
3
4
5
6
7 package doc
8
9 import (
10 "errors"
11 "fmt"
12 "net"
13 "net/url"
14 "os"
15 "os/exec"
16 "os/signal"
17 "path/filepath"
18 "strings"
19 )
20
21
22
23
24
25 func pickUnusedPort() (int, error) {
26 l, err := net.Listen("tcp", "localhost:0")
27 if err != nil {
28 return 0, err
29 }
30 port := l.Addr().(*net.TCPAddr).Port
31 if err := l.Close(); err != nil {
32 return 0, err
33 }
34 return port, nil
35 }
36
37 func doPkgsite(urlPath string) error {
38 port, err := pickUnusedPort()
39 if err != nil {
40 return fmt.Errorf("failed to find port for documentation server: %v", err)
41 }
42 addr := fmt.Sprintf("localhost:%d", port)
43 path, err := url.JoinPath("http://"+addr, urlPath)
44 if err != nil {
45 return fmt.Errorf("internal error: failed to construct url: %v", err)
46 }
47
48
49
50
51 signal.Ignore(signalsToIgnore...)
52
53
54 env := os.Environ()
55 vars, err := runCmd(env, goCmd(), "env", "GOPROXY", "GOMODCACHE")
56 fields := strings.Fields(vars)
57 if err == nil && len(fields) == 2 {
58 goproxy, gomodcache := fields[0], fields[1]
59 gomodcache = filepath.Join(gomodcache, "cache", "download")
60
61
62
63 if strings.HasPrefix(gomodcache, "/") {
64 gomodcache = "file://" + gomodcache
65 } else {
66 gomodcache = "file:///" + filepath.ToSlash(gomodcache)
67 }
68 env = append(env, "GOPROXY="+gomodcache+","+goproxy)
69 }
70
71 const version = "v0.0.0-20250714212547-01b046e81fe7"
72 cmd := exec.Command(goCmd(), "run", "golang.org/x/pkgsite/cmd/internal/doc@"+version,
73 "-gorepo", buildCtx.GOROOT,
74 "-http", addr,
75 "-open", path)
76 cmd.Env = env
77 cmd.Stdout = os.Stderr
78 cmd.Stderr = os.Stderr
79
80 if err := cmd.Run(); err != nil {
81 var ee *exec.ExitError
82 if errors.As(err, &ee) {
83
84
85
86
87 os.Exit(ee.ExitCode())
88 }
89 return err
90 }
91
92 return nil
93 }
94
View as plain text