cmd/guru: clean ups to command-line interface

-pos is now a positional argument; -scope is now a flag.
Tidy up usage message.
Update Vim and Emacs scripts and test
Remove call to GOMAXPROCS.
Use log.{SetPrefix,SetFlags} and Fatalf

Change-Id: I3786ed83aecb17d622b29d2a538a374f813f0adc
Reviewed-on: https://go-review.googlesource.com/19438
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Alan Donovan 2016-02-12 00:04:56 -05:00 committed by Alan Donovan
parent 789265387f
commit 00b8b1eb95
4 changed files with 55 additions and 78 deletions

View File

@ -26,15 +26,14 @@ mv -f $GOPATH/bin/guru $GOROOT/bin/
$GOROOT/bin/guru >$log 2>&1 || true # (prints usage and exits 1)
grep -q "Run.*help" $log || die "$GOROOT/bin/guru not installed"
# Run Emacs, set the scope to the guru tool itself,
# load ./main.go, and describe the "fmt" import.
emacs --batch --no-splash --no-window-system --no-init \
--load $GOROOT/misc/emacs/go-mode.el \
--load $GOPATH/src/github.com/dominikh/go-mode.el/go-mode.el \
--load $thisdir/guru.el \
--eval '
(progn
(setq go-guru-scope "golang.org/x/tools/cmd/guru")
(princ (emacs-version)) ; requires Emacs v23
(find-file "'$thisdir'/main.go")
(search-forward "\"fmt\"")
(backward-char)

View File

@ -2,20 +2,16 @@
;;; Integration of the Go 'guru' analysis tool into Emacs.
;;;
;;; To install the Go guru, run:
;;; % export GOROOT=... GOPATH=...
;;; % go get golang.org/x/tools/cmd/guru
;;; % mv $GOPATH/bin/guru $GOROOT/bin/
;;; $ go get golang.org/x/tools/cmd/guru
;;;
;;; Load this file into Emacs and set go-guru-scope to your
;;; configuration. Then, find a file of Go source code, enable
;;; go-guru-mode, select an expression of interest, and press `C-c C-o d'
;;; (for "describe") or run one of the other go-guru-xxx commands.
;;;
;;; TODO(adonovan): simplify installation and configuration by making
;;; guru a subcommand of 'go tool'.
(require 'compile)
(require 'go-mode)
(require 'simple)
(require 'cl)
(defgroup go-guru nil
@ -99,14 +95,14 @@ file name with a small hyperlink. Display the result."
(string-equal "" go-guru-scope)
(go-guru-set-scope))
(let* ((filename (file-truename buffer-file-name))
(posflag (if (use-region-p)
(format "-pos=%s:#%d,#%d"
filename
(1- (go--position-bytes (region-beginning)))
(1- (go--position-bytes (region-end))))
(format "-pos=%s:#%d"
filename
(1- (position-bytes (point))))))
(posn (if (use-region-p)
(format "%s:#%d,#%d"
filename
(1- (go--position-bytes (region-beginning)))
(1- (go--position-bytes (region-end))))
(format "%s:#%d"
filename
(1- (position-bytes (point))))))
(env-vars (go-root-and-paths))
(goroot-env (concat "GOROOT=" (car env-vars)))
(gopath-env (concat "GOPATH=" (mapconcat #'identity (cdr env-vars) ":"))))
@ -114,8 +110,8 @@ file name with a small hyperlink. Display the result."
(setq buffer-read-only nil)
(erase-buffer)
(insert "Go Guru\n")
(let ((args (append (list go-guru-command nil t nil posflag mode)
(split-string go-guru-scope " " t))))
(let ((args (list go-guru-command nil t nil
"-scope" go-guru-scope mode posn)))
;; Log the command to *Messages*, for debugging.
(message "Command: %s:" args)
(message nil) ; clears/shrinks minibuffer

View File

@ -68,14 +68,14 @@ func! s:RunGuru(mode, selected) range abort
if a:selected != -1
let pos1 = s:getpos(line("'<"), col("'<"))
let pos2 = s:getpos(line("'>"), col("'>"))
let cmd = printf('%s -pos=%s:#%d,#%d %s %s',
let cmd = printf('%s -scope=\'%s\' %s %s:#%d,#%d',
\ s:go_guru,
\ shellescape(fname), pos1, pos2, a:mode, shellescape(sname))
\ shellescape(fname), shellescape(sname), a:mode, pos1, pos2)
else
let pos = s:getpos(line('.'), col('.'))
let cmd = printf('%s -pos=%s:#%d %s %s',
let cmd = printf('%s -scope=\'%s\' %s %s:#%d',
\ s:go_guru,
\ shellescape(fname), pos, a:mode, shellescape(sname))
\ shellescape(fname), shellescape(sname), a:mode, pos)
endif
call s:qflist(system(cmd))
endfun

View File

@ -21,23 +21,20 @@ import (
"io"
"log"
"os"
"runtime"
"runtime/pprof"
"strings"
"golang.org/x/tools/go/buildutil"
"golang.org/x/tools/go/loader"
)
var posFlag = flag.String("pos", "",
"Filename and byte offset or extent of a syntax element about which to query, "+
"e.g. foo.go:#123,#456, bar.go:#123.")
var ptalogFlag = flag.String("ptalog", "",
"Location of the points-to analysis log file, or empty to disable logging.")
var formatFlag = flag.String("format", "plain", "Output format. One of {plain,json,xml}.")
var reflectFlag = flag.Bool("reflect", false, "Analyze reflection soundly (slow).")
// flags
var (
scopeFlag = flag.String("scope", "", "comma-separated list of `packages` to which the analysis should be limited (default=all)")
ptalogFlag = flag.String("ptalog", "", "write points-to analysis log to `file`")
formatFlag = flag.String("format", "plain", "output `format`; one of {plain,json,xml}")
reflectFlag = flag.Bool("reflect", false, "analyze reflection soundly (slow)")
cpuprofileFlag = flag.String("cpuprofile", "", "write CPU profile to `file`")
)
func init() {
flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
@ -46,15 +43,7 @@ func init() {
const useHelp = "Run 'guru -help' for more information.\n"
const helpMessage = `Go source code guru.
Usage: guru [<flag> ...] <mode> <args> ...
The -format flag controls the output format:
plain an editor-friendly format in which every line of output
is of the form "pos: text", where pos is "-" if unknown.
json structured data in JSON syntax.
xml structured data in XML syntax.
The -pos flag is required in all modes.
Usage: guru [flags] <mode> <position>
The mode argument determines the query to perform:
@ -71,29 +60,24 @@ The mode argument determines the query to perform:
what show basic information about the selected syntax node
whicherrs show possible values of the selected error variable
The user manual is available here: http://golang.org/s/guru-user-manual
The position argument specifies the filename and byte offset (or range)
of the syntax element to query. For example:
Examples:
foo.go:#123,#128
bar.go:#123
Describe the syntax at offset 530 in this file (an import spec):
% guru -pos=src/golang.org/x/tools/cmd/guru/main.go:#530 describe \
golang.org/x/tools/cmd/guru
The -format flag controls the output format:
plain an editor-friendly format in which every line of output
is of the form "pos: text", where pos is "-" if unknown.
json structured data in JSON syntax.
xml structured data in XML syntax.
` + loader.FromArgsUsage
User manual: http://golang.org/s/oracle-user-manual
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
Example: describe syntax at offset 530 in this file (an import spec):
func init() {
// If $GOMAXPROCS isn't set, use the full capacity of the machine.
// For small machines, use at least 4 threads.
if os.Getenv("GOMAXPROCS") == "" {
n := runtime.NumCPU()
if n < 4 {
n = 4
}
runtime.GOMAXPROCS(n)
}
}
$ guru describe src/golang.org/x/tools/cmd/guru/main.go:#530
`
func printHelp() {
fmt.Fprintln(os.Stderr, helpMessage)
@ -102,6 +86,9 @@ func printHelp() {
}
func main() {
log.SetPrefix("guru: ")
log.SetFlags(0)
// Don't print full help unless -help was requested.
// Just gently remind users that it's there.
flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
@ -115,13 +102,12 @@ func main() {
}
args := flag.Args()
if len(args) == 0 || args[0] == "" {
fmt.Fprint(os.Stderr, "guru: a mode argument is required.\n"+useHelp)
if len(args) != 2 {
flag.Usage()
os.Exit(2)
}
mode, posn := args[0], args[1]
mode := args[0]
args = args[1:]
if mode == "help" {
printHelp()
os.Exit(2)
@ -147,8 +133,8 @@ func main() {
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if *cpuprofileFlag != "" {
f, err := os.Create(*cpuprofileFlag)
if err != nil {
log.Fatal(err)
}
@ -161,23 +147,21 @@ func main() {
case "json", "plain", "xml":
// ok
default:
fmt.Fprintf(os.Stderr, "guru: illegal -format value: %q.\n"+useHelp, *formatFlag)
os.Exit(2)
log.Fatalf("illegal -format value: %q.\n"+useHelp, *formatFlag)
}
// Ask the guru.
query := Query{
Mode: mode,
Pos: *posFlag,
Pos: posn,
Build: &build.Default,
Scope: args,
Scope: strings.Split(*scopeFlag, ","),
PTALog: ptalog,
Reflection: *reflectFlag,
}
if err := Run(&query); err != nil {
fmt.Fprintf(os.Stderr, "guru: %s\n", err)
os.Exit(1)
log.Fatal(err)
}
// Print the result.
@ -185,16 +169,14 @@ func main() {
case "json":
b, err := json.MarshalIndent(query.Serial(), "", "\t")
if err != nil {
fmt.Fprintf(os.Stderr, "guru: JSON error: %s\n", err)
os.Exit(1)
log.Fatalf("JSON error: %s", err)
}
os.Stdout.Write(b)
case "xml":
b, err := xml.MarshalIndent(query.Serial(), "", "\t")
if err != nil {
fmt.Fprintf(os.Stderr, "guru: XML error: %s\n", err)
os.Exit(1)
log.Fatalf("XML error: %s", err)
}
os.Stdout.Write(b)