Permalink
Browse files

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...
hyangah committed May 9, 2018
1 parent 392ff18 commit 3f89214940d1f922bc4fde923de658a2ec1e4ac3
Showing 304 changed files with 168,533 additions and 0 deletions.
@@ -33,6 +33,7 @@ func main() {
options := &driver.Options{
Fetch: new(fetcher),
Obj: new(objTool),
UI: newUI(),
}
if err := driver.PProf(options); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
@@ -369,3 +370,7 @@ func (f *file) Close() error {
f.file.Close()
return nil
}
// newUI will be set in readlineui.go in some platforms
// for interactive readline functionality.
var newUI = func() driver.UI { return nil }
@@ -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()
}
// SetAutoComplete instructs the UI to call complete(cmd) to obtain
// the auto-completion of cmd, if the UI supports auto-completion at all.
func (r *readlineUI) SetAutoComplete(complete func(string) string) {
// TODO: Implement auto-completion support.
}

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit 3f89214

Please sign in to comment.