cmd/go: check for another GCC error message
[official-gcc.git] / libgo / go / cmd / go / internal / bug / bug.go
blob963da94c493c10cb4b47015dbc4a536424e8097c
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package bug implements the ``go bug'' command.
6 package bug
8 import (
9 "bytes"
10 "fmt"
11 "io"
12 "io/ioutil"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "regexp"
17 "runtime"
18 "strings"
20 "cmd/go/internal/base"
21 "cmd/go/internal/cfg"
22 "cmd/go/internal/envcmd"
23 "cmd/go/internal/web"
26 var CmdBug = &base.Command{
27 Run: runBug,
28 UsageLine: "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.
36 func init() {
37 CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
40 func runBug(cmd *base.Command, args []string) {
41 var buf bytes.Buffer
42 buf.WriteString(bugHeader)
43 inspectGoVersion(&buf)
44 fmt.Fprint(&buf, "#### System details\n\n")
45 fmt.Fprintln(&buf, "```")
46 fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
47 env := cfg.CmdEnv
48 env = append(env, envcmd.ExtraEnvVars()...)
49 for _, e := range env {
50 // Hide the TERM environment variable from "go bug".
51 // See issue #18128
52 if e.Name != "TERM" {
53 fmt.Fprintf(&buf, "%s=\"%s\"\n", e.Name, e.Value)
56 printGoDetails(&buf)
57 printOSDetails(&buf)
58 printCDetails(&buf)
59 fmt.Fprintln(&buf, "```")
61 body := buf.String()
62 url := "https://github.com/golang/go/issues/new?body=" + web.QueryEscape(body)
63 if !web.OpenBrowser(url) {
64 fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
65 fmt.Print(body)
69 const bugHeader = `Please answer these questions before submitting your issue. Thanks!
71 #### What did you do?
72 If possible, provide a recipe for reproducing the error.
73 A complete runnable program is good.
74 A link on play.golang.org is best.
77 #### What did you expect to see?
80 #### What did you see instead?
85 func printGoDetails(w io.Writer) {
86 printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
87 printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
90 func printOSDetails(w io.Writer) {
91 switch runtime.GOOS {
92 case "darwin":
93 printCmdOut(w, "uname -v: ", "uname", "-v")
94 printCmdOut(w, "", "sw_vers")
95 case "linux":
96 printCmdOut(w, "uname -sr: ", "uname", "-sr")
97 printCmdOut(w, "", "lsb_release", "-a")
98 printGlibcVersion(w)
99 case "openbsd", "netbsd", "freebsd", "dragonfly":
100 printCmdOut(w, "uname -v: ", "uname", "-v")
101 case "solaris":
102 out, err := ioutil.ReadFile("/etc/release")
103 if err == nil {
104 fmt.Fprintf(w, "/etc/release: %s\n", out)
105 } else {
106 if cfg.BuildV {
107 fmt.Printf("failed to read /etc/release: %v\n", err)
113 func printCDetails(w io.Writer) {
114 printCmdOut(w, "lldb --version: ", "lldb", "--version")
115 cmd := exec.Command("gdb", "--version")
116 out, err := cmd.Output()
117 if err == nil {
118 // There's apparently no combination of command line flags
119 // to get gdb to spit out its version without the license and warranty.
120 // Print up to the first newline.
121 fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
122 } else {
123 if cfg.BuildV {
124 fmt.Printf("failed to run gdb --version: %v\n", err)
129 func inspectGoVersion(w io.Writer) {
130 data, err := web.Get("https://golang.org/VERSION?m=text")
131 if err != nil {
132 if cfg.BuildV {
133 fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
135 return
138 // golang.org/VERSION currently returns a whitespace-free string,
139 // but just in case, protect against that changing.
140 // Similarly so for runtime.Version.
141 release := string(bytes.TrimSpace(data))
142 vers := strings.TrimSpace(runtime.Version())
144 if vers == release {
145 // Up to date
146 return
149 // Devel version or outdated release. Either way, this request is apropos.
150 fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
153 // printCmdOut prints the output of running the given command.
154 // It ignores failures; 'go bug' is best effort.
155 func printCmdOut(w io.Writer, prefix, path string, args ...string) {
156 cmd := exec.Command(path, args...)
157 out, err := cmd.Output()
158 if err != nil {
159 if cfg.BuildV {
160 fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
162 return
164 fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
167 // firstLine returns the first line of a given byte slice.
168 func firstLine(buf []byte) []byte {
169 idx := bytes.IndexByte(buf, '\n')
170 if idx > 0 {
171 buf = buf[:idx]
173 return bytes.TrimSpace(buf)
176 // printGlibcVersion prints information about the glibc version.
177 // It ignores failures.
178 func printGlibcVersion(w io.Writer) {
179 tempdir := os.TempDir()
180 if tempdir == "" {
181 return
183 src := []byte(`int main() {}`)
184 srcfile := filepath.Join(tempdir, "go-bug.c")
185 outfile := filepath.Join(tempdir, "go-bug")
186 err := ioutil.WriteFile(srcfile, src, 0644)
187 if err != nil {
188 return
190 defer os.Remove(srcfile)
191 cmd := exec.Command("gcc", "-o", outfile, srcfile)
192 if _, err = cmd.CombinedOutput(); err != nil {
193 return
195 defer os.Remove(outfile)
197 cmd = exec.Command("ldd", outfile)
198 out, err := cmd.CombinedOutput()
199 if err != nil {
200 return
202 re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
203 m := re.FindStringSubmatch(string(out))
204 if m == nil {
205 return
207 cmd = exec.Command(m[1])
208 out, err = cmd.Output()
209 if err != nil {
210 return
212 fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
214 // print another line (the one containing version string) in case of musl libc
215 if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
216 fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))