mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Like GOOS=android which implies the "linux" build tag, GOOS=illumos implies the "solaris" build tag. This lets the existing ecosystem of packages still work on illumos, but still permits packages to start differentiating between solaris and illumos. Fixes #20603 Change-Id: I8f4eabf1a66060538dca15d7658c1fbc6c826622 Reviewed-on: https://go-review.googlesource.com/c/go/+/174457 Run-TryBot: Benny Siegert <bsiegert@gmail.com> Reviewed-by: Benny Siegert <bsiegert@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
229 lines
5.9 KiB
Go
229 lines
5.9 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package bug implements the ``go bug'' command.
|
|
package bug
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
urlpkg "net/url"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"cmd/go/internal/base"
|
|
"cmd/go/internal/cfg"
|
|
"cmd/go/internal/envcmd"
|
|
"cmd/go/internal/web"
|
|
)
|
|
|
|
var CmdBug = &base.Command{
|
|
Run: runBug,
|
|
UsageLine: "go bug",
|
|
Short: "start a bug report",
|
|
Long: `
|
|
Bug opens the default browser and starts a new bug report.
|
|
The report includes useful system information.
|
|
`,
|
|
}
|
|
|
|
func init() {
|
|
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
|
}
|
|
|
|
func runBug(cmd *base.Command, args []string) {
|
|
if len(args) > 0 {
|
|
base.Fatalf("go bug: bug takes no arguments")
|
|
}
|
|
var buf bytes.Buffer
|
|
buf.WriteString(bugHeader)
|
|
inspectGoVersion(&buf)
|
|
fmt.Fprint(&buf, "#### System details\n\n")
|
|
fmt.Fprintln(&buf, "```")
|
|
fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
|
env := cfg.CmdEnv
|
|
env = append(env, envcmd.ExtraEnvVars()...)
|
|
for _, e := range env {
|
|
// Hide the TERM environment variable from "go bug".
|
|
// See issue #18128
|
|
if e.Name != "TERM" {
|
|
fmt.Fprintf(&buf, "%s=\"%s\"\n", e.Name, e.Value)
|
|
}
|
|
}
|
|
printGoDetails(&buf)
|
|
printOSDetails(&buf)
|
|
printCDetails(&buf)
|
|
fmt.Fprintln(&buf, "```")
|
|
|
|
body := buf.String()
|
|
url := "https://github.com/golang/go/issues/new?body=" + urlpkg.QueryEscape(body)
|
|
if !web.OpenBrowser(url) {
|
|
fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
|
|
fmt.Print(body)
|
|
}
|
|
}
|
|
|
|
const bugHeader = `Please answer these questions before submitting your issue. Thanks!
|
|
|
|
#### What did you do?
|
|
If possible, provide a recipe for reproducing the error.
|
|
A complete runnable program is good.
|
|
A link on play.golang.org is best.
|
|
|
|
|
|
#### What did you expect to see?
|
|
|
|
|
|
#### What did you see instead?
|
|
|
|
|
|
`
|
|
|
|
func printGoDetails(w io.Writer) {
|
|
printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
|
|
printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
|
|
}
|
|
|
|
func printOSDetails(w io.Writer) {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
printCmdOut(w, "uname -v: ", "uname", "-v")
|
|
printCmdOut(w, "", "sw_vers")
|
|
case "linux":
|
|
printCmdOut(w, "uname -sr: ", "uname", "-sr")
|
|
printCmdOut(w, "", "lsb_release", "-a")
|
|
printGlibcVersion(w)
|
|
case "openbsd", "netbsd", "freebsd", "dragonfly":
|
|
printCmdOut(w, "uname -v: ", "uname", "-v")
|
|
case "illumos", "solaris":
|
|
// Be sure to use the OS-supplied uname, in "/usr/bin":
|
|
printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
|
|
out, err := ioutil.ReadFile("/etc/release")
|
|
if err == nil {
|
|
fmt.Fprintf(w, "/etc/release: %s\n", out)
|
|
} else {
|
|
if cfg.BuildV {
|
|
fmt.Printf("failed to read /etc/release: %v\n", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func printCDetails(w io.Writer) {
|
|
printCmdOut(w, "lldb --version: ", "lldb", "--version")
|
|
cmd := exec.Command("gdb", "--version")
|
|
out, err := cmd.Output()
|
|
if err == nil {
|
|
// There's apparently no combination of command line flags
|
|
// to get gdb to spit out its version without the license and warranty.
|
|
// Print up to the first newline.
|
|
fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
|
|
} else {
|
|
if cfg.BuildV {
|
|
fmt.Printf("failed to run gdb --version: %v\n", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func inspectGoVersion(w io.Writer) {
|
|
data, err := web.GetBytes(&urlpkg.URL{
|
|
Scheme: "https",
|
|
Host: "golang.org",
|
|
Path: "/VERSION",
|
|
RawQuery: "?m=text",
|
|
})
|
|
if err != nil {
|
|
if cfg.BuildV {
|
|
fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// golang.org/VERSION currently returns a whitespace-free string,
|
|
// but just in case, protect against that changing.
|
|
// Similarly so for runtime.Version.
|
|
release := string(bytes.TrimSpace(data))
|
|
vers := strings.TrimSpace(runtime.Version())
|
|
|
|
if vers == release {
|
|
// Up to date
|
|
return
|
|
}
|
|
|
|
// Devel version or outdated release. Either way, this request is apropos.
|
|
fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
|
|
}
|
|
|
|
// printCmdOut prints the output of running the given command.
|
|
// It ignores failures; 'go bug' is best effort.
|
|
func printCmdOut(w io.Writer, prefix, path string, args ...string) {
|
|
cmd := exec.Command(path, args...)
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
if cfg.BuildV {
|
|
fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
|
|
}
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
|
|
}
|
|
|
|
// firstLine returns the first line of a given byte slice.
|
|
func firstLine(buf []byte) []byte {
|
|
idx := bytes.IndexByte(buf, '\n')
|
|
if idx > 0 {
|
|
buf = buf[:idx]
|
|
}
|
|
return bytes.TrimSpace(buf)
|
|
}
|
|
|
|
// printGlibcVersion prints information about the glibc version.
|
|
// It ignores failures.
|
|
func printGlibcVersion(w io.Writer) {
|
|
tempdir := os.TempDir()
|
|
if tempdir == "" {
|
|
return
|
|
}
|
|
src := []byte(`int main() {}`)
|
|
srcfile := filepath.Join(tempdir, "go-bug.c")
|
|
outfile := filepath.Join(tempdir, "go-bug")
|
|
err := ioutil.WriteFile(srcfile, src, 0644)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer os.Remove(srcfile)
|
|
cmd := exec.Command("gcc", "-o", outfile, srcfile)
|
|
if _, err = cmd.CombinedOutput(); err != nil {
|
|
return
|
|
}
|
|
defer os.Remove(outfile)
|
|
|
|
cmd = exec.Command("ldd", outfile)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return
|
|
}
|
|
re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
|
|
m := re.FindStringSubmatch(string(out))
|
|
if m == nil {
|
|
return
|
|
}
|
|
cmd = exec.Command(m[1])
|
|
out, err = cmd.Output()
|
|
if err != nil {
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
|
|
|
|
// print another line (the one containing version string) in case of musl libc
|
|
if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
|
|
fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
|
|
}
|
|
}
|