github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/go/bug.go (about) 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. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "regexp" 16 "runtime" 17 "strings" 18 ) 19 20 var cmdBug = &Command{ 21 Run: runBug, 22 UsageLine: "bug", 23 Short: "start a bug report", 24 Long: ` 25 Bug opens the default browser and starts a new bug report. 26 The report includes useful system information. 27 `, 28 } 29 30 func init() { 31 cmdBug.Flag.BoolVar(&buildV, "v", false, "") 32 } 33 34 func runBug(cmd *Command, args []string) { 35 var buf bytes.Buffer 36 buf.WriteString(bugHeader) 37 inspectGoVersion(&buf) 38 fmt.Fprint(&buf, "#### System details\n\n") 39 fmt.Fprintln(&buf, "```") 40 fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) 41 env := newEnv 42 env = append(env, extraEnvVars()...) 43 for _, e := range env { 44 // Hide the TERM environment variable from "go bug". 45 // See issue #18128 46 if e.name != "TERM" { 47 fmt.Fprintf(&buf, "%s=\"%s\"\n", e.name, e.value) 48 } 49 } 50 printGoDetails(&buf) 51 printOSDetails(&buf) 52 printCDetails(&buf) 53 fmt.Fprintln(&buf, "```") 54 55 body := buf.String() 56 url := "https://github.com/golang/go/issues/new?body=" + queryEscape(body) 57 if !openBrowser(url) { 58 fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n") 59 fmt.Print(body) 60 } 61 } 62 63 const bugHeader = `Please answer these questions before submitting your issue. Thanks! 64 65 #### What did you do? 66 If possible, provide a recipe for reproducing the error. 67 A complete runnable program is good. 68 A link on play.golang.org is best. 69 70 71 #### What did you expect to see? 72 73 74 #### What did you see instead? 75 76 77 ` 78 79 func printGoDetails(w io.Writer) { 80 printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version") 81 printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V") 82 } 83 84 func printOSDetails(w io.Writer) { 85 switch runtime.GOOS { 86 case "darwin": 87 printCmdOut(w, "uname -v: ", "uname", "-v") 88 printCmdOut(w, "", "sw_vers") 89 case "linux": 90 printCmdOut(w, "uname -sr: ", "uname", "-sr") 91 printCmdOut(w, "", "lsb_release", "-a") 92 printGlibcVersion(w) 93 case "openbsd", "netbsd", "freebsd", "dragonfly": 94 printCmdOut(w, "uname -v: ", "uname", "-v") 95 case "solaris": 96 out, err := ioutil.ReadFile("/etc/release") 97 if err == nil { 98 fmt.Fprintf(w, "/etc/release: %s\n", out) 99 } else { 100 if buildV { 101 fmt.Printf("failed to read /etc/release: %v\n", err) 102 } 103 } 104 } 105 } 106 107 func printCDetails(w io.Writer) { 108 printCmdOut(w, "lldb --version: ", "lldb", "--version") 109 cmd := exec.Command("gdb", "--version") 110 out, err := cmd.Output() 111 if err == nil { 112 // There's apparently no combination of command line flags 113 // to get gdb to spit out its version without the license and warranty. 114 // Print up to the first newline. 115 fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out)) 116 } else { 117 if buildV { 118 fmt.Printf("failed to run gdb --version: %v\n", err) 119 } 120 } 121 } 122 123 func inspectGoVersion(w io.Writer) { 124 data, err := httpGET("https://golang.org/VERSION?m=text") 125 if err != nil { 126 if buildV { 127 fmt.Printf("failed to read from golang.org/VERSION: %v\n", err) 128 } 129 return 130 } 131 132 // golang.org/VERSION currently returns a whitespace-free string, 133 // but just in case, protect against that changing. 134 // Similarly so for runtime.Version. 135 release := string(bytes.TrimSpace(data)) 136 vers := strings.TrimSpace(runtime.Version()) 137 138 if vers == release { 139 // Up to date 140 return 141 } 142 143 // Devel version or outdated release. Either way, this request is apropos. 144 fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release) 145 } 146 147 // printCmdOut prints the output of running the given command. 148 // It ignores failures; 'go bug' is best effort. 149 func printCmdOut(w io.Writer, prefix, path string, args ...string) { 150 cmd := exec.Command(path, args...) 151 out, err := cmd.Output() 152 if err != nil { 153 if buildV { 154 fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err) 155 } 156 return 157 } 158 fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out)) 159 } 160 161 // firstLine returns the first line of a given byte slice. 162 func firstLine(buf []byte) []byte { 163 idx := bytes.IndexByte(buf, '\n') 164 if idx > 0 { 165 buf = buf[:idx] 166 } 167 return bytes.TrimSpace(buf) 168 } 169 170 // printGlibcVersion prints information about the glibc version. 171 // It ignores failures. 172 func printGlibcVersion(w io.Writer) { 173 tempdir := os.TempDir() 174 if tempdir == "" { 175 return 176 } 177 src := []byte(`int main() {}`) 178 srcfile := filepath.Join(tempdir, "go-bug.c") 179 outfile := filepath.Join(tempdir, "go-bug") 180 err := ioutil.WriteFile(srcfile, src, 0644) 181 if err != nil { 182 return 183 } 184 defer os.Remove(srcfile) 185 cmd := exec.Command("gcc", "-o", outfile, srcfile) 186 if _, err = cmd.CombinedOutput(); err != nil { 187 return 188 } 189 defer os.Remove(outfile) 190 191 cmd = exec.Command("ldd", outfile) 192 out, err := cmd.CombinedOutput() 193 if err != nil { 194 return 195 } 196 re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`) 197 m := re.FindStringSubmatch(string(out)) 198 if m == nil { 199 return 200 } 201 cmd = exec.Command(m[1]) 202 out, err = cmd.Output() 203 if err != nil { 204 return 205 } 206 fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out)) 207 208 // print another line (the one containing version string) in case of musl libc 209 if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 { 210 fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:])) 211 } 212 }