-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/pprof: add readline support similar to upstream
The upstream pprof implements the readline feature using the github.com/chzyer/readline package in its pprof.go main. It would be ideal to use the same readline support package as the upstream for better user experience and code maintenance. However, bringing in third-party packages requires more work than I envisioned (e.g. clean up the vendored code to meet the expected standard - iow don't break builders). As a result, this change implements the similar feature for the pprof command included in the go distribution (cmd/pprof/pprof.go) using golang.org/x/crypto/ssh/terminal for now. Auto-completion is not yet supported (same in the upstream). The feature is enabled only in linux, windows, darwin, and only when terminal support is available. This change brings in new vendored packages, golang.org/x/crypto/ssh/terminal and golang.org/x/sys/{unix,windows}. For #14041 Change-Id: If4a790796acf2ab20f7e81268b9d9354c5a5cd2b Reviewed-on: https://go-review.googlesource.com/112436 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
- Loading branch information
Showing
304 changed files
with
168,533 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright 2018 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. | ||
|
||
// This file contains an driver.UI implementation | ||
// that provides the readline functionality if possible. | ||
|
||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows | ||
// +build !appengine | ||
// +build !android | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
"github.com/google/pprof/driver" | ||
"golang.org/x/crypto/ssh/terminal" | ||
) | ||
|
||
func init() { | ||
newUI = newReadlineUI | ||
} | ||
|
||
// readlineUI implements driver.UI interface using the | ||
// golang.org/x/crypto/ssh/terminal package. | ||
// The upstream pprof command implements the same functionality | ||
// using the github.com/chzyer/readline package. | ||
type readlineUI struct { | ||
term *terminal.Terminal | ||
} | ||
|
||
func newReadlineUI() driver.UI { | ||
// test if we can use terminal.ReadLine | ||
// that assumes operation in the raw mode. | ||
oldState, err := terminal.MakeRaw(0) | ||
if err != nil { | ||
return nil | ||
} | ||
terminal.Restore(0, oldState) | ||
|
||
rw := struct { | ||
io.Reader | ||
io.Writer | ||
}{os.Stdin, os.Stderr} | ||
return &readlineUI{term: terminal.NewTerminal(rw, "")} | ||
} | ||
|
||
// Read returns a line of text (a command) read from the user. | ||
// prompt is printed before reading the command. | ||
func (r *readlineUI) ReadLine(prompt string) (string, error) { | ||
r.term.SetPrompt(prompt) | ||
|
||
// skip error checking because we tested it | ||
// when creating this readlineUI initially. | ||
oldState, _ := terminal.MakeRaw(0) | ||
defer terminal.Restore(0, oldState) | ||
|
||
s, err := r.term.ReadLine() | ||
return s, err | ||
} | ||
|
||
// Print shows a message to the user. | ||
// It formats the text as fmt.Print would and adds a final \n if not already present. | ||
// For line-based UI, Print writes to standard error. | ||
// (Standard output is reserved for report data.) | ||
func (r *readlineUI) Print(args ...interface{}) { | ||
r.print(false, args...) | ||
} | ||
|
||
// PrintErr shows an error message to the user. | ||
// It formats the text as fmt.Print would and adds a final \n if not already present. | ||
// For line-based UI, PrintErr writes to standard error. | ||
func (r *readlineUI) PrintErr(args ...interface{}) { | ||
r.print(true, args...) | ||
} | ||
|
||
func (r *readlineUI) print(withColor bool, args ...interface{}) { | ||
text := fmt.Sprint(args...) | ||
if !strings.HasSuffix(text, "\n") { | ||
text += "\n" | ||
} | ||
if withColor { | ||
text = colorize(text) | ||
} | ||
fmt.Fprintf(r.term, text) | ||
} | ||
|
||
// colorize prints the msg in red using ANSI color escapes. | ||
func colorize(msg string) string { | ||
const red = 31 | ||
var colorEscape = fmt.Sprintf("\033[0;%dm", red) | ||
var colorResetEscape = "\033[0m" | ||
return colorEscape + msg + colorResetEscape | ||
} | ||
|
||
// IsTerminal returns whether the UI is known to be tied to an | ||
// interactive terminal (as opposed to being redirected to a file). | ||
func (r *readlineUI) IsTerminal() bool { | ||
const stdout = 1 | ||
return terminal.IsTerminal(stdout) | ||
} | ||
|
||
// WantBrowser indicates whether browser should be opened with the -http option. | ||
func (r *readlineUI) WantBrowser() bool { | ||
return r.IsTerminal() | ||
} | ||
|
||