diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/go/doc.go | 28 | ||||
-rw-r--r-- | src/cmd/go/generate.go | 75 | ||||
-rw-r--r-- | src/cmd/go/generate_test.go | 2 | ||||
-rw-r--r-- | src/cmd/pprof/internal/commands/commands.go | 26 | ||||
-rw-r--r-- | src/cmd/pprof/internal/symbolizer/symbolizer.go | 4 |
5 files changed, 105 insertions, 30 deletions
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 43a315944..65640fb48 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -234,17 +234,24 @@ create or update Go source files, for instance by running yacc. Go generate is never run automatically by go build, go get, go test, and so on. It must be run explicitly. -Directives are written as a whole-line comment of the form +Go generate scans the file for directives, which are lines of +the form, //go:generate command argument... -(note: no space in "//go") where command is the generator to be -run, corresponding to an executable file that can be run locally. -It must either be in the shell path (gofmt), a fully qualified path -(/usr/you/bin/mytool), or a command alias, described below. +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +that can be run locally. It must either be in the shell path +(gofmt), a fully qualified path (/usr/you/bin/mytool), or a +command alias, described below. -The arguments are space-separated tokens or double-quoted strings -passed to the generator as individual arguments when it is run. +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. Quoted strings use Go syntax and are evaluated before execution; a quoted string appears as a single argument to the generator. @@ -317,7 +324,7 @@ Download and install packages and dependencies Usage: - go get [-d] [-fix] [-t] [-u] [build flags] [packages] + go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages] Get downloads and installs the packages named by the import paths, along with their dependencies. @@ -325,6 +332,11 @@ along with their dependencies. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index a83cce8f7..baf4d2b55 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -32,20 +32,27 @@ create or update Go source files, for instance by running yacc. Go generate is never run automatically by go build, go get, go test, and so on. It must be run explicitly. -Directives are written as a whole-line comment of the form +Go generate scans the file for directives, which are lines of +the form, //go:generate command argument... -(note: no space in "//go") where command is the generator to be -run, corresponding to an executable file that can be run locally. -It must either be in the shell path (gofmt), a fully qualified path -(/usr/you/bin/mytool), or a command alias, described below. +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +that can be run locally. It must either be in the shell path +(gofmt), a fully qualified path (/usr/you/bin/mytool), or a +command alias, described below. -The arguments are space-separated tokens or double-quoted strings -passed to the generator as individual arguments when it is run. +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. Quoted strings use Go syntax and are evaluated before execution; a -quoted string appears a single argument to the generator. +quoted string appears as a single argument to the generator. Go generate sets several variables when it runs the generator: @@ -178,13 +185,43 @@ func (g *Generator) run() (ok bool) { fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path)) } - s := bufio.NewScanner(g.r) - for s.Scan() { - g.lineNum++ - if !bytes.HasPrefix(s.Bytes(), []byte("//go:generate ")) && !bytes.HasPrefix(s.Bytes(), []byte("//go:generate\t")) { + // Scan for lines that start "//go:generate". + // Can't use bufio.Scanner because it can't handle long lines, + // which are likely to appear when using generate. + input := bufio.NewReader(g.r) + var err error + // One line per loop. + for { + g.lineNum++ // 1-indexed. + var buf []byte + buf, err = input.ReadSlice('\n') + if err == bufio.ErrBufferFull { + // Line too long - consume and ignore. + if isGoGenerate(buf) { + g.errorf("directive too long") + } + for err == bufio.ErrBufferFull { + _, err = input.ReadSlice('\n') + } + if err != nil { + break + } + continue + } + + if err != nil { + // Check for marker at EOF without final \n. + if err == io.EOF && isGoGenerate(buf) { + err = io.ErrUnexpectedEOF + } + break + } + + if !isGoGenerate(buf) { continue } - words := g.split(s.Text()) + + words := g.split(string(buf)) if len(words) == 0 { g.errorf("no arguments to directive") } @@ -201,19 +238,23 @@ func (g *Generator) run() (ok bool) { } g.exec(words) } - if s.Err() != nil { - g.errorf("error reading %s: %s", shortPath(g.path), s.Err()) + if err != nil && err != io.EOF { + g.errorf("error reading %s: %s", shortPath(g.path), err) } return true } +func isGoGenerate(buf []byte) bool { + return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t")) +} + // split breaks the line into words, evaluating quoted // strings and evaluating environment variables. -// The initial //go:generate element is dropped. +// The initial //go:generate element is present in line. func (g *Generator) split(line string) []string { // Parse line, obeying quoted strings. var words []string - line = line[len("//go:generate "):] + line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline. // One (possibly quoted) word per iteration. Words: for { diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go index 93c0ae66e..660ebabbe 100644 --- a/src/cmd/go/generate_test.go +++ b/src/cmd/go/generate_test.go @@ -40,7 +40,7 @@ func TestGenerateCommandParse(t *testing.T) { } g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) for _, test := range splitTests { - got := g.split("//go:generate " + test.in) + got := g.split("//go:generate " + test.in + "\n") if !reflect.DeepEqual(got, test.out) { t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) } diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go index 6d3582018..51397a3c6 100644 --- a/src/cmd/pprof/internal/commands/commands.go +++ b/src/cmd/pprof/internal/commands/commands.go @@ -11,6 +11,7 @@ import ( "io" "os" "os/exec" + "runtime" "strings" "cmd/pprof/internal/plugin" @@ -71,15 +72,27 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands { "eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"}, "evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"}, "gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"}, - "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers), false, "Visualize graph through web browser"}, + "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"}, // Visualize HTML directly generated by report. - "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers), true, "Output annotated source in HTML for functions matching regexp or address"}, + "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"}, } } -// List of web browsers to attempt for web visualization -var browsers = []string{"chrome", "google-chrome", "firefox", "/usr/bin/open"} +// browsers returns a list of commands to attempt for web visualization +// on the current platform +func browsers() []string { + cmds := []string{"chrome", "google-chrome", "firefox"} + switch runtime.GOOS { + case "darwin": + cmds = append(cmds, "/usr/bin/open") + case "windows": + cmds = append(cmds, "cmd /c start") + default: + cmds = append(cmds, "xdg-open") + } + return cmds +} // NewCompleter creates an autocompletion function for a set of commands. func NewCompleter(cs Commands) Completer { @@ -142,6 +155,10 @@ func awayFromTTY(format string) PostProcessor { func invokeDot(format string) PostProcessor { divert := awayFromTTY(format) return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error { + if _, err := exec.LookPath("dot"); err != nil { + ui.PrintErr("Cannot find dot, have you installed Graphviz?") + return err + } cmd := exec.Command("dot", "-T"+format) var buf bytes.Buffer cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr @@ -174,6 +191,7 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v if err = format(input, tempFile, ui); err != nil { return err } + tempFile.Close() // on windows, if the file is Open, start cannot access it. // Try visualizers until one is successful for _, v := range visualizers { // Separate command and arguments for exec.Command. diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go index cabddaa76..86de5640d 100644 --- a/src/cmd/pprof/internal/symbolizer/symbolizer.go +++ b/src/cmd/pprof/internal/symbolizer/symbolizer.go @@ -32,6 +32,10 @@ func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin } } + if len(prof.Mapping) == 0 { + return fmt.Errorf("no known mappings") + } + mt, err := newMapping(prof, obj, ui, force) if err != nil { return err |