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.
20 "cmd/go/internal/base"
22 "cmd/go/internal/envcmd"
26 var CmdBug
= &base
.Command
{
29 Short
: "start a bug report",
31 Bug opens the default browser and starts a new bug report.
32 The report includes useful system information.
37 CmdBug
.Flag
.BoolVar(&cfg
.BuildV
, "v", false, "")
40 func runBug(cmd
*base
.Command
, args
[]string) {
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
)
48 env
= append(env
, envcmd
.ExtraEnvVars()...)
49 for _
, e
:= range env
{
50 // Hide the TERM environment variable from "go bug".
53 fmt
.Fprintf(&buf
, "%s=\"%s\"\n", e
.Name
, e
.Value
)
59 fmt
.Fprintln(&buf
, "```")
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")
69 const bugHeader
= `Please answer these questions before submitting your issue. Thanks!
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
) {
93 printCmdOut(w
, "uname -v: ", "uname", "-v")
94 printCmdOut(w
, "", "sw_vers")
96 printCmdOut(w
, "uname -sr: ", "uname", "-sr")
97 printCmdOut(w
, "", "lsb_release", "-a")
99 case "openbsd", "netbsd", "freebsd", "dragonfly":
100 printCmdOut(w
, "uname -v: ", "uname", "-v")
102 out
, err
:= ioutil
.ReadFile("/etc/release")
104 fmt
.Fprintf(w
, "/etc/release: %s\n", out
)
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()
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
))
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")
133 fmt
.Printf("failed to read from golang.org/VERSION: %v\n", err
)
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())
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()
160 fmt
.Printf("%s %s: %v\n", path
, strings
.Join(args
, " "), err
)
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')
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()
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)
190 defer os
.Remove(srcfile
)
191 cmd
:= exec
.Command("gcc", "-o", outfile
, srcfile
)
192 if _
, err
= cmd
.CombinedOutput(); err
!= nil {
195 defer os
.Remove(outfile
)
197 cmd
= exec
.Command("ldd", outfile
)
198 out
, err
:= cmd
.CombinedOutput()
202 re
:= regexp
.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
203 m
:= re
.FindStringSubmatch(string(out
))
207 cmd
= exec
.Command(m
[1])
208 out
, err
= cmd
.Output()
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:]))