github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/bug/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 bug implements the ``go bug'' command. 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 "github.com/gagliardetto/golang-go/cmd/go/not-internal/base" 22 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg" 23 "github.com/gagliardetto/golang-go/cmd/go/not-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 // Be sure to use the OS-supplied uname, in "/usr/bin": 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 // There's apparently no combination of command line flags 136 // to get gdb to spit out its version without the license and warranty. 137 // Print up to the first newline. 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 // printCmdOut prints the output of running the given command. 147 // It ignores failures; 'go bug' is best effort. 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 // firstLine returns the first line of a given byte slice. 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 // printGlibcVersion prints information about the glibc version. 170 // It ignores failures. 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 // print another line (the one containing version string) in case of musl libc 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 }