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  }