Source file src/pkg/cmd/go/internal/bug/bug.go
1
2
3
4
5
6 package bug
7
8 import (
9 "bytes"
10 "fmt"
11 "io"
12 "io/ioutil"
13 urlpkg "net/url"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "regexp"
18 "runtime"
19 "strings"
20
21 "cmd/go/internal/base"
22 "cmd/go/internal/cfg"
23 "cmd/go/internal/web"
24 )
25
26 var CmdBug = &base.Command{
27 Run: runBug,
28 UsageLine: "go bug",
29 Short: "start a bug report",
30 Long: `
31 Bug opens the default browser and starts a new bug report.
32 The report includes useful system information.
33 `,
34 }
35
36 func init() {
37 CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
38 }
39
40 func runBug(cmd *base.Command, args []string) {
41 if len(args) > 0 {
42 base.Fatalf("go bug: bug takes no arguments")
43 }
44 var buf bytes.Buffer
45 buf.WriteString(bugHeader)
46 printGoVersion(&buf)
47 buf.WriteString("### Does this issue reproduce with the latest release?\n\n\n")
48 printEnvDetails(&buf)
49 buf.WriteString(bugFooter)
50
51 body := buf.String()
52 url := "https://github.com/golang/go/issues/new?body=" + urlpkg.QueryEscape(body)
53 if !web.OpenBrowser(url) {
54 fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
55 fmt.Print(body)
56 }
57 }
58
59 const bugHeader = `<!-- Please answer these questions before submitting your issue. Thanks! -->
60
61 `
62 const bugFooter = `### What did you do?
63
64 <!--
65 If possible, provide a recipe for reproducing the error.
66 A complete runnable program is good.
67 A link on play.golang.org is best.
68 -->
69
70
71
72 ### What did you expect to see?
73
74
75
76 ### What did you see instead?
77
78 `
79
80 func printGoVersion(w io.Writer) {
81 fmt.Fprintf(w, "### What version of Go are you using (`go version`)?\n\n")
82 fmt.Fprintf(w, "<pre>\n")
83 fmt.Fprintf(w, "$ go version\n")
84 printCmdOut(w, "", "go", "version")
85 fmt.Fprintf(w, "</pre>\n")
86 fmt.Fprintf(w, "\n")
87 }
88
89 func printEnvDetails(w io.Writer) {
90 fmt.Fprintf(w, "### What operating system and processor architecture are you using (`go env`)?\n\n")
91 fmt.Fprintf(w, "<details><summary><code>go env</code> Output</summary><br><pre>\n")
92 fmt.Fprintf(w, "$ go env\n")
93 printCmdOut(w, "", "go", "env")
94 printGoDetails(w)
95 printOSDetails(w)
96 printCDetails(w)
97 fmt.Fprintf(w, "</pre></details>\n\n")
98 }
99
100 func printGoDetails(w io.Writer) {
101 printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
102 printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
103 }
104
105 func printOSDetails(w io.Writer) {
106 switch runtime.GOOS {
107 case "darwin":
108 printCmdOut(w, "uname -v: ", "uname", "-v")
109 printCmdOut(w, "", "sw_vers")
110 case "linux":
111 printCmdOut(w, "uname -sr: ", "uname", "-sr")
112 printCmdOut(w, "", "lsb_release", "-a")
113 printGlibcVersion(w)
114 case "openbsd", "netbsd", "freebsd", "dragonfly":
115 printCmdOut(w, "uname -v: ", "uname", "-v")
116 case "illumos", "solaris":
117
118 printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
119 out, err := ioutil.ReadFile("/etc/release")
120 if err == nil {
121 fmt.Fprintf(w, "/etc/release: %s\n", out)
122 } else {
123 if cfg.BuildV {
124 fmt.Printf("failed to read /etc/release: %v\n", err)
125 }
126 }
127 }
128 }
129
130 func printCDetails(w io.Writer) {
131 printCmdOut(w, "lldb --version: ", "lldb", "--version")
132 cmd := exec.Command("gdb", "--version")
133 out, err := cmd.Output()
134 if err == nil {
135
136
137
138 fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
139 } else {
140 if cfg.BuildV {
141 fmt.Printf("failed to run gdb --version: %v\n", err)
142 }
143 }
144 }
145
146
147
148 func printCmdOut(w io.Writer, prefix, path string, args ...string) {
149 cmd := exec.Command(path, args...)
150 out, err := cmd.Output()
151 if err != nil {
152 if cfg.BuildV {
153 fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
154 }
155 return
156 }
157 fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
158 }
159
160
161 func firstLine(buf []byte) []byte {
162 idx := bytes.IndexByte(buf, '\n')
163 if idx > 0 {
164 buf = buf[:idx]
165 }
166 return bytes.TrimSpace(buf)
167 }
168
169
170
171 func printGlibcVersion(w io.Writer) {
172 tempdir := os.TempDir()
173 if tempdir == "" {
174 return
175 }
176 src := []byte(`int main() {}`)
177 srcfile := filepath.Join(tempdir, "go-bug.c")
178 outfile := filepath.Join(tempdir, "go-bug")
179 err := ioutil.WriteFile(srcfile, src, 0644)
180 if err != nil {
181 return
182 }
183 defer os.Remove(srcfile)
184 cmd := exec.Command("gcc", "-o", outfile, srcfile)
185 if _, err = cmd.CombinedOutput(); err != nil {
186 return
187 }
188 defer os.Remove(outfile)
189
190 cmd = exec.Command("ldd", outfile)
191 out, err := cmd.CombinedOutput()
192 if err != nil {
193 return
194 }
195 re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
196 m := re.FindStringSubmatch(string(out))
197 if m == nil {
198 return
199 }
200 cmd = exec.Command(m[1])
201 out, err = cmd.Output()
202 if err != nil {
203 return
204 }
205 fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
206
207
208 if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
209 fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
210 }
211 }
212
View as plain text