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