提交 eb2bc2a7 编写于 作者: A aarzilli 提交者: Derek Parker

terminal: Implements init file and source command

The 'source' command reads the file specified as argument and executes
it as a list of delve commands.
Additionally a flag '--init' can be passed to delve specifying a file
containing a list of commands to execute on startup.

Issue #96
上级 bc9ac0ec
# comment line
trace main.main
break main.sayhi
#
# comment line
#
......@@ -27,6 +27,7 @@ var (
Log bool
Headless bool
Addr string
InitFile string
)
func main() {
......@@ -48,6 +49,7 @@ The goal of this tool is to provide a simple yet powerful interface for debuggin
rootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
rootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.")
rootCommand.PersistentFlags().StringVar(&InitFile, "init", "", "Init file, executed by the terminal client")
// 'version' subcommand.
versionCommand := &cobra.Command{
......@@ -292,6 +294,10 @@ func execute(attachPid int, processArgs []string, conf *config.Config) int {
}
defer listener.Close()
if Headless && (InitFile != "") {
fmt.Fprintf(os.Stderr, "Warning: init file ignored\n")
}
// Create and start a debugger server
server := rpc.NewServer(&service.Config{
Listener: listener,
......@@ -309,6 +315,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config) int {
var client service.Client
client = rpc.NewClient(listener.Addr().String())
term := terminal.New(client, conf)
term.InitFile = InitFile
err, status = term.Run()
} else {
ch := make(chan os.Signal)
......
......@@ -23,10 +23,7 @@ type Fixture struct {
// Fixtures is a map of Fixture.Name to Fixture.
var Fixtures map[string]Fixture = make(map[string]Fixture)
func BuildFixture(name string) Fixture {
if f, ok := Fixtures[name]; ok {
return f
}
func FindFixturesDir() string {
parent := ".."
fixturesDir := "_fixtures"
for depth := 0; depth < 10; depth++ {
......@@ -35,6 +32,15 @@ func BuildFixture(name string) Fixture {
}
fixturesDir = filepath.Join(parent, fixturesDir)
}
return fixturesDir
}
func BuildFixture(name string) Fixture {
if f, ok := Fixtures[name]; ok {
return f
}
fixturesDir := FindFixturesDir()
// Make a (good enough) random temporary file name
r := make([]byte, 4)
......
......@@ -41,9 +41,9 @@ func (c command) match(cmdstr string) bool {
}
type Commands struct {
cmds []command
lastCmd cmdfunc
client service.Client
cmds []command
lastCmd cmdfunc
client service.Client
}
// Returns a Commands struct with default commands defined.
......@@ -77,6 +77,7 @@ func DebugCommands(client service.Client) *Commands {
{aliases: []string{"list", "ls"}, cmdFn: listCommand, helpMsg: "list <linespec>. Show source around current point or provided linespec."},
{aliases: []string{"stack", "bt"}, cmdFn: stackCommand, helpMsg: "stack [<depth>] [-full]. Prints stack."},
{aliases: []string{"frame"}, cmdFn: frame, helpMsg: "Sets current stack frame (0 is the top of the stack)"},
{aliases: []string{"source"}, cmdFn: c.sourceCommand, helpMsg: "Executes a file containing a list of delve commands"},
}
return c
......@@ -699,6 +700,14 @@ func listCommand(t *Term, args ...string) error {
return nil
}
func (cmds *Commands) sourceCommand(t *Term, args ...string) error {
if len(args) != 1 {
return fmt.Errorf("wrong number of arguments: source <filename>")
}
return cmds.executeFile(t, args[0])
}
func digits(n int) int {
return int(math.Floor(math.Log10(float64(n)))) + 1
}
......@@ -826,3 +835,32 @@ func shortenFilePath(fullPath string) string {
workingDir, _ := os.Getwd()
return strings.Replace(fullPath, workingDir, ".", 1)
}
func (cmds *Commands) executeFile(t *Term, name string) error {
fh, err := os.Open(name)
if err != nil {
return err
}
defer fh.Close()
scanner := bufio.NewScanner(fh)
lineno := 0
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
lineno++
if line == "" || line[0] == '#' {
continue
}
cmdstr, args := parseCommand(line)
cmd := cmds.Find(cmdstr)
err := cmd(t, args...)
if err != nil {
fmt.Printf("%s:%d: %v\n", name, lineno, err)
}
}
return scanner.Err()
}
......@@ -2,7 +2,10 @@ package terminal
import (
"fmt"
"path/filepath"
"testing"
"github.com/derekparker/delve/proc/test"
)
func TestCommandDefault(t *testing.T) {
......@@ -65,3 +68,33 @@ func TestCommandThread(t *testing.T) {
t.Fatal("wrong command output: ", err.Error())
}
}
func TestExecuteFile(t *testing.T) {
breakCount := 0
traceCount := 0
c := &Commands{
client: nil,
cmds: []command{
{aliases: []string{"trace"}, cmdFn: func(t *Term, args ...string) error {
traceCount++
return nil
}},
{aliases: []string{"break"}, cmdFn: func(t *Term, args ...string) error {
breakCount++
return nil
}},
},
}
fixturesDir := test.FindFixturesDir()
err := c.executeFile(nil, filepath.Join(fixturesDir, "bpfile"))
if err != nil {
t.Fatalf("executeFile: %v", err)
}
if breakCount != 1 || traceCount != 1 {
t.Fatalf("Wrong counts break: %d trace: %d\n", breakCount, traceCount)
}
}
......@@ -26,6 +26,7 @@ type Term struct {
line *liner.State
conf *config.Config
dumb bool
InitFile string
}
func New(client service.Client, conf *config.Config) *Term {
......@@ -85,6 +86,13 @@ func (t *Term) Run() (error, int) {
f.Close()
fmt.Println("Type 'help' for list of commands.")
if t.InitFile != "" {
err := cmds.executeFile(t, t.InitFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error executing init file: %s\n", err)
}
}
var status int
for {
cmdstr, err := t.promptForInput()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册