From d75ac751950549c1c073a33635cc2f93dcd37246 Mon Sep 17 00:00:00 2001 From: Derek Parker Date: Sat, 11 Jul 2015 09:28:08 -0500 Subject: [PATCH] Replace hand-rolled cli interface with Cobra --- cmd/dlv/main.go | 208 +++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 109 deletions(-) diff --git a/cmd/dlv/main.go b/cmd/dlv/main.go index 4a2e124e..51c069c6 100644 --- a/cmd/dlv/main.go +++ b/cmd/dlv/main.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "net" "os" @@ -15,115 +14,116 @@ import ( "github.com/derekparker/delve/service" "github.com/derekparker/delve/service/rpc" "github.com/derekparker/delve/terminal" + "github.com/spf13/cobra" ) const version string = "0.5.0.beta" -var usage string = `Delve version %s -flags: -%s -Invoke with the path to a binary: - dlv ./path/to/prog -or use the following commands: - run - Build, run, and attach to program - test - Build test binary, run and attach to it - attach - Attach to running process -` - -func init() { - flag.Usage = help -} +var ( + Log bool + Headless bool + Addr string +) func main() { - var printv, printhelp bool - var addr string - var logEnabled bool - var headless bool - - flag.BoolVar(&printv, "version", false, "Print version number and exit.") - flag.StringVar(&addr, "addr", "localhost:0", "Debugging server listen address.") - flag.BoolVar(&logEnabled, "log", false, "Enable debugging server logging.") - flag.BoolVar(&headless, "headless", false, "Run in headless mode.") - flag.Parse() - - if flag.NFlag() == 0 && len(flag.Args()) == 0 { - help() - os.Exit(0) + // Main dlv root command. + rootCommand := &cobra.Command{ + Use: "dlv", + Short: "Delve is a debugger for the Go programming language.", } - - if printv { - fmt.Printf("Delve version: %s\n", version) - os.Exit(0) + rootCommand.Flags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.") + rootCommand.Flags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.") + rootCommand.Flags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.") + + // 'version' subcommand. + versionCommand := &cobra.Command{ + Use: "version", + Short: "Prints version.", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Delve version: " + version) + }, } - - if printhelp { - help() - os.Exit(0) + rootCommand.AddCommand(versionCommand) + + // 'run' subcommand. + runCommand := &cobra.Command{ + Use: "run", + Short: "Compile and begin debugging program.", + Long: `Compiles your program with optimizations disabled, +starts and attaches to it, and enable you to immediately begin debugging your program.`, + Run: func(cmd *cobra.Command, args []string) { + const debugname = "debug" + goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l") + goBuild.Stderr = os.Stderr + err := goBuild.Run() + if err != nil { + os.Exit(1) + } + fp, err := filepath.Abs("./" + debugname) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + + processArgs := append([]string{"./" + debugname}, args...) + status := execute(0, processArgs) + os.Remove(fp) + os.Exit(status) + }, } + rootCommand.AddCommand(runCommand) + + // 'test' subcommand. + testCommand := &cobra.Command{ + Use: "test", + Short: "Compile test binary and begin debugging program.", + Long: `Compiles a test binary with optimizations disabled, +starts and attaches to it, and enable you to immediately begin debugging your program.`, + Run: func(cmd *cobra.Command, args []string) { + wd, err := os.Getwd() + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + base := filepath.Base(wd) + goTest := exec.Command("go", "test", "-c", "-gcflags", "-N -l") + goTest.Stderr = os.Stderr + err = goTest.Run() + if err != nil { + os.Exit(1) + } + debugname := "./" + base + ".test" + processArgs := append([]string{debugname}, args...) + + status := execute(0, processArgs) + os.Remove(debugname) + os.Exit(status) + }, + } + rootCommand.AddCommand(testCommand) + + // 'attach' subcommand. + attachCommand := &cobra.Command{ + Use: "attach [pid]", + Short: "Attach to running process and begin debugging.", + Long: "Attach to running process and begin debugging.", + Run: func(cmd *cobra.Command, args []string) { + pid, err := strconv.Atoi(args[0]) + if err != nil { + fmt.Fprintf(os.Stderr, "Invalid pid: %d", args[0]) + os.Exit(1) + } + os.Exit(execute(pid, nil)) + }, + } + rootCommand.AddCommand(attachCommand) - defer func() { - if err := recover(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - }() - - status := run(addr, logEnabled, headless) - fmt.Println("[Hope I was of service hunting your bug!]") - os.Exit(status) + rootCommand.Execute() } -func run(addr string, logEnabled, headless bool) int { - // Collect launch arguments - var processArgs []string - var attachPid int - switch flag.Args()[0] { - case "run": - const debugname = "debug" - cmd := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l") - err := cmd.Run() - if err != nil { - fmt.Println("Could not compile program:", err) - return 1 - } - fp, err := filepath.Abs("./" + debugname) - if err != nil { - fmt.Println(err) - return 1 - } - defer os.Remove(fp) - - processArgs = append([]string{"./" + debugname}, flag.Args()[1:]...) - case "test": - wd, err := os.Getwd() - if err != nil { - fmt.Println(err) - return 1 - } - base := filepath.Base(wd) - cmd := exec.Command("go", "test", "-c", "-gcflags", "-N -l") - err = cmd.Run() - if err != nil { - fmt.Errorf("Could not compile program: %s\n", err) - return 1 - } - debugname := "./" + base + ".test" - defer os.Remove(debugname) - - processArgs = append([]string{debugname}, flag.Args()[1:]...) - case "attach": - pid, err := strconv.Atoi(flag.Args()[1]) - if err != nil { - fmt.Errorf("Invalid pid: %d", flag.Args()[1]) - return 1 - } - attachPid = pid - default: - processArgs = flag.Args() - } - +func execute(attachPid int, processArgs []string) int { // Make a TCP listener - listener, err := net.Listen("tcp", addr) + listener, err := net.Listen("tcp", Addr) if err != nil { fmt.Printf("couldn't start listener: %s\n", err) return 1 @@ -136,14 +136,14 @@ func run(addr string, logEnabled, headless bool) int { Listener: listener, ProcessArgs: processArgs, AttachPid: attachPid, - }, logEnabled) + }, Log) if err := server.Run(); err != nil { fmt.Fprintln(os.Stderr, err) return 1 } var status int - if !headless { + if !Headless { // Create and start a terminal var client service.Client client = rpc.NewClient(listener.Addr().String()) @@ -162,13 +162,3 @@ func run(addr string, logEnabled, headless bool) int { return status } - -// help prints help text to os.Stderr. -func help() { - flags := "" - flag.VisitAll(func(f *flag.Flag) { - doc := fmt.Sprintf(" -%s=%s: %s\n", f.Name, f.DefValue, f.Usage) - flags += doc - }) - fmt.Fprintf(os.Stderr, usage, version, flags) -} -- GitLab