<commit_before>package cmd

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/justincarter/docker-workbench/machine"
	"github.com/urfave/cli"
)

// Commands config
var Commands = []cli.Command{
	{
		Name:   "create",
		Usage:  "Create a new workbench machine in the current directory",
		Action: Create,
	},
	{
		Name:   "up",
		Usage:  "Start the workbench machine and show details",
		Action: Up,
	},
	{
		Name:   "proxy",
		Usage:  "Start a reverse proxy to the app in the current directory",
		Action: Proxy,
	},
}

// FlightCheck helper checks for prerequisite commands
func FlightCheck() error {

	toolbox := []string{"docker", "docker-machine", "docker-compose"}
	missing := []string{}
	for _, c := range toolbox {
		if _, err := exec.LookPath(c); err != nil {
			missing = append(missing, c)
		}
	}
	if len(missing) > 0 {
		return fmt.Errorf("docker-workbench: %s was not found. Make sure you have installed Docker Toolbox", strings.Join(missing, ", "))
	}
	if _, err := exec.LookPath(machine.VBoxManagePath()); err != nil {
		return fmt.Errorf("docker-workbench: VBoxManage was not found. Make sure you have installed VirtualBox")
	}

	return nil
}

// NotFound command
func NotFound(c *cli.Context, command string) {
	fmt.Printf("docker-workbench: '%s' is not a docker-workbench command. See 'docker-workbench help'.", command)
	os.Exit(1)
}

// Version command
func Version(c *cli.Context) {
	fmt.Printf("v%s", c.App.Version)
}

// Create command
func Create(c *cli.Context) error {

	// get name from the current working directory
	workdir, _ := os.Getwd()
	name := filepath.Base(workdir)

	if !machine.Exists(name) {
		machine.Create(name)
		machine.EvalEnv(name)

		fmt.Println("Configuring bootsync.sh...")
		machine.SSH(name, "sudo echo 'sudo mkdir -p /workbench && sudo mount -t vboxsf -o uid=1000,gid=50 workbench /workbench' >  /tmp/bootsync.sh")
		machine.SSH(name, "sudo cp /tmp/bootsync.sh /var/lib/boot2docker/bootsync.sh")
		machine.SSH(name, "sudo chmod +x /var/lib/boot2docker/bootsync.sh")

		fmt.Println("Installing workbench apps...")
		machine.SSH(name, "docker run -d --restart=always --name=workbench_proxy -p 80:80 -v '/var/run/docker.sock:/tmp/docker.sock:ro' daemonite/workbench-proxy")
		machine.Stop(name)

		fmt.Println("Adding /workbench shared folder...")
		machine.ShareFolder(name, workdir)
	}

	machine.Start(name)
	machine.EvalEnv(name)
	machine.EvalHint(name, false)
	printWorkbenchInfo("*", name)

	return nil
}

// Up command
func Up(c *cli.Context) error {

	app, name, err := getWorkbenchContext()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	machine.Start(name)
	machine.EvalHint(name, true)
	if app != "*" {
		fmt.Println("\nStart the application:")
		fmt.Println("docker-compose up")
	}
	printWorkbenchInfo(app, name)

	return nil
}

// Proxy command
func Proxy(c *cli.Context) error {
	app, name, err := getWorkbenchContext()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if app == "*" {
		fmt.Printf("\nCould not find the app to proxy for Workbench machine '%s'. Try running from an app directory?\n", name)
		os.Exit(1)
	}

	ip, ok := machine.IP(name)
	if ok == true {
		fmt.Println("Starting reverse proxy on port 9999...")
		ips, err := getProxyIPs()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		fmt.Printf("Listening on:\n\n")
		for _, ip := range ips {
			fmt.Printf("http://%s.%s.nip.io:9999/\n", app, ip)
		}
		fmt.Println("\nPress Ctrl-C to terminate proxy")

		l, err := net.Listen("tcp4", ":9999")
		if err != nil {
			log.Fatal(err)
		}
		proxy := httputil.NewSingleHostReverseProxy(&url.URL{
			Scheme: "http",
			Host:   fmt.Sprintf("%s.%s.nip.io", app, ip),
		})
		log.Fatal(http.Serve(l, proxy))

	} else {
		fmt.Println("\nCould not find the IP address for this workbench. Have you run docker-workbench up?")
		os.Exit(1)
	}

	return nil
}

// getWorkbenchContext finds the application name and workbench machine name  from the current directory
func getWorkbenchContext() (app string, name string, err error) {
	err = nil
	app = "*"
	// get name from the current working directory
	workdir, _ := os.Getwd()
	name = filepath.Base(workdir)
	if !machine.Exists(name) {
		// get name from the parent of the current working directory
		app = name
		name = filepath.Base(filepath.Dir(workdir))

		if !machine.Exists(name) {
			err = fmt.Errorf("Workbench machine '%s' not found.", app)
		}
	}
	return
}

// printWorkbenchInfo prints the application URL using the given app name and workbench machine IP
func printWorkbenchInfo(app, name string) {
	ip, ok := machine.IP(name)
	if ok == true {
		fmt.Println("\nBrowse the workbench using:")
		fmt.Printf("http://%s.%s.nip.io/\n", app, ip)
	} else {
		fmt.Println("\nCould not find the IP address for this workbench")
		os.Exit(1)
	}
}

// getProxyIPs returns a slice of IP address strings that should be browsable when using the Proxy command
func getProxyIPs() ([]string, error) {
	var e error
	ips := []string{}

	ifaces, err := net.Interfaces()
	if err != nil {
		e = fmt.Errorf("\nCould not find local network interfaces")
	}

	for _, i := range ifaces {
		addrs, _ := i.Addrs()
		for _, addr := range addrs {
			var ip string
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP.String()
			case *net.IPAddr:
				ip = v.IP.String()
			}
			// output valid local IPv4 addresses, excluding loopbacks and docker machine default interface
			if machine.ValidIPv4(ip) && ip != "127.0.0.1" && ip != "192.168.99.1" && strings.Split(ip, ".")[0] != "169" {
				ips = append(ips, ip)
			}
		}
	}
	if len(ips) == 0 {
		e = fmt.Errorf("\nCould not find local network interfaces")
	}

	return ips, e
}
<commit_msg>refactor Proxy command proxy port lookup and proxy start<commit_after>package cmd

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/justincarter/docker-workbench/machine"
	"github.com/urfave/cli"
)

// Commands config
var Commands = []cli.Command{
	{
		Name:   "create",
		Usage:  "Create a new workbench machine in the current directory",
		Action: Create,
	},
	{
		Name:   "up",
		Usage:  "Start the workbench machine and show details",
		Action: Up,
	},
	{
		Name:   "proxy",
		Usage:  "Start a reverse proxy to the app in the current directory",
		Action: Proxy,
	},
}

// FlightCheck helper checks for prerequisite commands
func FlightCheck() error {

	toolbox := []string{"docker", "docker-machine", "docker-compose"}
	missing := []string{}
	for _, c := range toolbox {
		if _, err := exec.LookPath(c); err != nil {
			missing = append(missing, c)
		}
	}
	if len(missing) > 0 {
		return fmt.Errorf("docker-workbench: %s was not found. Make sure you have installed Docker Toolbox", strings.Join(missing, ", "))
	}
	if _, err := exec.LookPath(machine.VBoxManagePath()); err != nil {
		return fmt.Errorf("docker-workbench: VBoxManage was not found. Make sure you have installed VirtualBox")
	}

	return nil
}

// NotFound command
func NotFound(c *cli.Context, command string) {
	fmt.Printf("docker-workbench: '%s' is not a docker-workbench command. See 'docker-workbench help'.", command)
	os.Exit(1)
}

// Version command
func Version(c *cli.Context) {
	fmt.Printf("v%s", c.App.Version)
}

// Create command
func Create(c *cli.Context) error {

	// get name from the current working directory
	workdir, _ := os.Getwd()
	name := filepath.Base(workdir)

	if !machine.Exists(name) {
		machine.Create(name)
		machine.EvalEnv(name)

		fmt.Println("Configuring bootsync.sh...")
		machine.SSH(name, "sudo echo 'sudo mkdir -p /workbench && sudo mount -t vboxsf -o uid=1000,gid=50 workbench /workbench' >  /tmp/bootsync.sh")
		machine.SSH(name, "sudo cp /tmp/bootsync.sh /var/lib/boot2docker/bootsync.sh")
		machine.SSH(name, "sudo chmod +x /var/lib/boot2docker/bootsync.sh")

		fmt.Println("Installing workbench apps...")
		machine.SSH(name, "docker run -d --restart=always --name=workbench_proxy -p 80:80 -v '/var/run/docker.sock:/tmp/docker.sock:ro' daemonite/workbench-proxy")
		machine.Stop(name)

		fmt.Println("Adding /workbench shared folder...")
		machine.ShareFolder(name, workdir)
	}

	machine.Start(name)
	machine.EvalEnv(name)
	machine.EvalHint(name, false)
	printWorkbenchInfo("*", name)

	return nil
}

// Up command
func Up(c *cli.Context) error {

	app, name, err := getWorkbenchContext(false)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	machine.Start(name)
	machine.EvalHint(name, true)
	if app != "*" {
		fmt.Println("\nStart the application:")
		fmt.Println("docker-compose up")
	}
	printWorkbenchInfo(app, name)

	return nil
}

// Proxy command
func Proxy(c *cli.Context) error {
	app, name, err := getWorkbenchContext(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	port := getProxyPort(c)

	ip, ok := machine.IP(name)
	if ok == true {
		fmt.Printf("Starting reverse proxy on port %s...\n", port)
		ips, err := getProxyIPs()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Printf("Listening on:\n\n")
		for _, thisip := range ips {
			fmt.Printf("http://%s.%s.nip.io:%s/\n", app, thisip, port)
		}
		fmt.Println("\nPress Ctrl-C to terminate proxy")
		startProxy(app, name, ip, port)
	} else {
		fmt.Println("\nCould not find the IP address for this workbench. Have you run docker-workbench up?")
		os.Exit(1)
	}

	return nil
}

// getWorkbenchContext finds the application name and workbench machine name  from the current directory
func getWorkbenchContext(requireApp bool) (app string, name string, err error) {
	err = nil
	app = "*"
	// get name from the current working directory
	workdir, _ := os.Getwd()
	name = filepath.Base(workdir)
	if !machine.Exists(name) {
		// get name from the parent of the current working directory
		app = name
		name = filepath.Base(filepath.Dir(workdir))

		if !machine.Exists(name) {
			err = fmt.Errorf("Workbench machine '%s' not found.", app)
		}
	}
	if requireApp == true && app == "*" {
		err = fmt.Errorf("\nCould not find the app to proxy for Workbench machine '%s'. Try running from an app directory?", name)
	}
	return
}

// printWorkbenchInfo prints the application URL using the given app name and workbench machine IP
func printWorkbenchInfo(app, name string) {
	ip, ok := machine.IP(name)
	if ok == true {
		fmt.Println("\nBrowse the workbench using:")
		fmt.Printf("http://%s.%s.nip.io/\n", app, ip)
	} else {
		fmt.Println("\nCould not find the IP address for this workbench")
		os.Exit(1)
	}
}

// getProxyIPs returns a slice of IP address strings that should be browsable when using the Proxy command
func getProxyIPs() ([]string, error) {
	var e error
	ips := []string{}

	ifaces, err := net.Interfaces()
	if err != nil {
		e = fmt.Errorf("\nCould not find local network interfaces")
	}

	for _, i := range ifaces {
		addrs, _ := i.Addrs()
		for _, addr := range addrs {
			var ip string
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP.String()
			case *net.IPAddr:
				ip = v.IP.String()
			}
			// output valid local IPv4 addresses, excluding loopbacks and docker machine default interface
			if machine.ValidIPv4(ip) && ip != "127.0.0.1" && ip != "192.168.99.1" && strings.Split(ip, ".")[0] != "169" {
				ips = append(ips, ip)
			}
		}
	}
	if len(ips) == 0 {
		e = fmt.Errorf("\nCould not find local network interfaces")
	}

	return ips, e
}

func getProxyPort(c *cli.Context) string {
	return "9999"
}

func startProxy(app, name, ip, port string) {
	l, err := net.Listen("tcp4", fmt.Sprintf(":%s", port))
	if err != nil {
		log.Fatal(err)
	}
	proxy := httputil.NewSingleHostReverseProxy(&url.URL{
		Scheme: "http",
		Host:   fmt.Sprintf("%s.%s.nip.io", app, ip),
	})
	log.Fatal(http.Serve(l, proxy))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"

	sys "golang.org/x/sys/unix"

	"github.com/derekparker/delve/config"
	"github.com/derekparker/delve/service"
	"github.com/derekparker/delve/service/api"
	"github.com/derekparker/delve/service/rpc"
	"github.com/derekparker/delve/terminal"

	"github.com/spf13/cobra"
)

const version string = "0.10.0-alpha"

var (
	Log      bool
	Headless bool
	Addr     string
	InitFile string
)

func main() {
	// Config setup and load.
	conf := config.LoadConfig()

	// Main dlv root command.
	rootCommand := &cobra.Command{
		Use:   "dlv",
		Short: "Delve is a debugger for the Go programming language.",
		Long: `Delve is a source level debugger for Go programs.

Delve enables you to interact with your program by controlling the execution of the process,
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.

The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
`,
	}
	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{
		Use:   "version",
		Short: "Prints version.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Delve version: " + version)
		},
	}
	rootCommand.AddCommand(versionCommand)

	// Deprecated 'run' subcommand.
	runCommand := &cobra.Command{
		Use:   "run",
		Short: "Deprecated command. Use 'debug' instead.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("This command is deprecated, please use 'debug' instead.")
			os.Exit(0)
		},
	}
	rootCommand.AddCommand(runCommand)

	// 'debug' subcommand.
	debugCommand := &cobra.Command{
		Use:   "debug",
		Short: "Compile and begin debugging program.",
		Long: `Compiles your program with optimizations disabled,
starts and attaches to it, and enables you to immediately begin debugging your program.`,
		Run: func(cmd *cobra.Command, args []string) {
			status := func() int {
				const debugname = "debug"
				goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
				goBuild.Stderr = os.Stderr
				err := goBuild.Run()
				if err != nil {
					return 1
				}
				fp, err := filepath.Abs("./" + debugname)
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return 1
				}
				defer os.Remove(fp)

				processArgs := append([]string{"./" + debugname}, args...)
				return execute(0, processArgs, conf)
			}()
			os.Exit(status)
		},
	}
	rootCommand.AddCommand(debugCommand)

	// 'exec' subcommand.
	execCommand := &cobra.Command{
		Use:   "exec [./path/to/binary]",
		Short: "Runs precompiled binary, attaches and begins debug session.",
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return errors.New("you must provide a path to a binary")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			os.Exit(execute(0, args, conf))
		},
	}
	rootCommand.AddCommand(execCommand)

	// 'trace' subcommand.
	var traceAttachPid int
	traceCommand := &cobra.Command{
		Use:   "trace [regexp]",
		Short: "Compile and begin tracing program.",
		Long:  "Trace program execution. Will set a tracepoint on every function matching [regexp] and output information when tracepoint is hit.",
		Run: func(cmd *cobra.Command, args []string) {
			status := func() int {
				const debugname = "debug"
				var processArgs []string
				if traceAttachPid == 0 {
					goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
					goBuild.Stderr = os.Stderr
					err := goBuild.Run()
					if err != nil {
						return 1
					}
					fp, err := filepath.Abs("./" + debugname)
					if err != nil {
						fmt.Fprintf(os.Stderr, err.Error())
						return 1
					}
					defer os.Remove(fp)

					processArgs = append([]string{"./" + debugname}, args...)
				}
				// Make a TCP listener
				listener, err := net.Listen("tcp", Addr)
				if err != nil {
					fmt.Printf("couldn't start listener: %s\n", err)
					return 1
				}
				defer listener.Close()

				// Create and start a debugger server
				server := rpc.NewServer(&service.Config{
					Listener:    listener,
					ProcessArgs: processArgs,
					AttachPid:   traceAttachPid,
				}, Log)
				if err := server.Run(); err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 1
				}
				sigChan := make(chan os.Signal)
				signal.Notify(sigChan, sys.SIGINT)
				client := rpc.NewClient(listener.Addr().String())
				funcs, err := client.ListFunctions(args[0])
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 1
				}
				for i := range funcs {
					_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true})
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
						return 1
					}
				}
				stateChan := client.Continue()
				for {
					select {
					case state := <-stateChan:
						if state.Err != nil {
							fmt.Fprintln(os.Stderr, state.Err)
							return 0
						}
						var args []string
						var fname string
						if state.CurrentThread != nil && state.CurrentThread.Function != nil {
							fname = state.CurrentThread.Function.Name
						}
						if state.BreakpointInfo != nil {
							for _, arg := range state.BreakpointInfo.Arguments {
								args = append(args, arg.Value)
							}
						}
						fmt.Printf("%s(%s) %s:%d\n", fname, strings.Join(args, ", "), state.CurrentThread.File, state.CurrentThread.Line)
					case <-sigChan:
						server.Stop(traceAttachPid == 0)
						return 1
					}
				}
				return 0
			}()
			os.Exit(status)
		},
	}
	traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
	rootCommand.AddCommand(traceCommand)

	// '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) {
			status := func() int {
				wd, err := os.Getwd()
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return 1
				}
				base := filepath.Base(wd)
				goTest := exec.Command("go", "test", "-c", "-gcflags", "-N -l")
				goTest.Stderr = os.Stderr
				err = goTest.Run()
				if err != nil {
					return 1
				}
				debugname := "./" + base + ".test"
				defer os.Remove(debugname)
				processArgs := append([]string{debugname}, args...)

				return execute(0, processArgs, conf)
			}()
			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.",
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return errors.New("you must provide a PID")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			pid, err := strconv.Atoi(args[0])
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
				os.Exit(1)
			}
			os.Exit(execute(pid, nil, conf))
		},
	}
	rootCommand.AddCommand(attachCommand)

	// 'connect' subcommand.
	connectCommand := &cobra.Command{
		Use:   "connect [addr]",
		Short: "Connect to a headless debug server.",
		Long:  "Connect to a headless debug server.",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				fmt.Fprintf(os.Stderr, "An address was not provided. You must provide an address as the first argument.\n")
				os.Exit(1)
			}
			addr := args[0]
			if addr == "" {
				fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
				os.Exit(1)
			}
			os.Exit(connect(addr, conf))
		},
	}
	rootCommand.AddCommand(connectCommand)

	rootCommand.Execute()
}

func connect(addr string, conf *config.Config) int {
	// Create and start a terminal - attach to running instance
	var client service.Client
	client = rpc.NewClient(addr)
	term := terminal.New(client, conf)
	err, status := term.Run()
	if err != nil {
		fmt.Println(err)
	}
	return status
}

func execute(attachPid int, processArgs []string, conf *config.Config) int {
	// Make a TCP listener
	listener, err := net.Listen("tcp", Addr)
	if err != nil {
		fmt.Printf("couldn't start listener: %s\n", err)
		return 1
	}
	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,
		ProcessArgs: processArgs,
		AttachPid:   attachPid,
	}, Log)
	if err := server.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var status int
	if !Headless {
		// Create and start a terminal
		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)
		signal.Notify(ch, sys.SIGINT)
		<-ch
		err = server.Stop(true)
	}

	if err != nil {
		fmt.Println(err)
	}

	return status
}
<commit_msg>dlv: Add option to provide build flags<commit_after>package main

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"

	sys "golang.org/x/sys/unix"

	"github.com/derekparker/delve/config"
	"github.com/derekparker/delve/service"
	"github.com/derekparker/delve/service/api"
	"github.com/derekparker/delve/service/rpc"
	"github.com/derekparker/delve/terminal"

	"github.com/spf13/cobra"
)

const version string = "0.10.0-alpha"

var (
	Log        bool
	Headless   bool
	Addr       string
	InitFile   string
	BuildFlags string
)

func main() {
	// Config setup and load.
	conf := config.LoadConfig()

	// Main dlv root command.
	rootCommand := &cobra.Command{
		Use:   "dlv",
		Short: "Delve is a debugger for the Go programming language.",
		Long: `Delve is a source level debugger for Go programs.

Delve enables you to interact with your program by controlling the execution of the process,
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.

The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
`,
	}
	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.")
	rootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", "", "Build flags, to be passed to the compiler.")

	// 'version' subcommand.
	versionCommand := &cobra.Command{
		Use:   "version",
		Short: "Prints version.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Delve version: " + version)
		},
	}
	rootCommand.AddCommand(versionCommand)

	// Deprecated 'run' subcommand.
	runCommand := &cobra.Command{
		Use:   "run",
		Short: "Deprecated command. Use 'debug' instead.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("This command is deprecated, please use 'debug' instead.")
			os.Exit(0)
		},
	}
	rootCommand.AddCommand(runCommand)

	// 'debug' subcommand.
	debugCommand := &cobra.Command{
		Use:   "debug",
		Short: "Compile and begin debugging program.",
		Long: `Compiles your program with optimizations disabled,
starts and attaches to it, and enables you to immediately begin debugging your program.`,
		Run: func(cmd *cobra.Command, args []string) {
			status := func() int {
				const debugname = "debug"
				goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l", BuildFlags)
				goBuild.Stderr = os.Stderr
				err := goBuild.Run()
				if err != nil {
					return 1
				}
				fp, err := filepath.Abs("./" + debugname)
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return 1
				}
				defer os.Remove(fp)

				processArgs := append([]string{"./" + debugname}, args...)
				return execute(0, processArgs, conf)
			}()
			os.Exit(status)
		},
	}
	rootCommand.AddCommand(debugCommand)

	// 'exec' subcommand.
	execCommand := &cobra.Command{
		Use:   "exec [./path/to/binary]",
		Short: "Runs precompiled binary, attaches and begins debug session.",
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return errors.New("you must provide a path to a binary")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			os.Exit(execute(0, args, conf))
		},
	}
	rootCommand.AddCommand(execCommand)

	// 'trace' subcommand.
	var traceAttachPid int
	traceCommand := &cobra.Command{
		Use:   "trace [regexp]",
		Short: "Compile and begin tracing program.",
		Long:  "Trace program execution. Will set a tracepoint on every function matching [regexp] and output information when tracepoint is hit.",
		Run: func(cmd *cobra.Command, args []string) {
			status := func() int {
				const debugname = "debug"
				var processArgs []string
				if traceAttachPid == 0 {
					goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l", BuildFlags)
					goBuild.Stderr = os.Stderr
					err := goBuild.Run()
					if err != nil {
						return 1
					}
					fp, err := filepath.Abs("./" + debugname)
					if err != nil {
						fmt.Fprintf(os.Stderr, err.Error())
						return 1
					}
					defer os.Remove(fp)

					processArgs = append([]string{"./" + debugname}, args...)
				}
				// Make a TCP listener
				listener, err := net.Listen("tcp", Addr)
				if err != nil {
					fmt.Printf("couldn't start listener: %s\n", err)
					return 1
				}
				defer listener.Close()

				// Create and start a debugger server
				server := rpc.NewServer(&service.Config{
					Listener:    listener,
					ProcessArgs: processArgs,
					AttachPid:   traceAttachPid,
				}, Log)
				if err := server.Run(); err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 1
				}
				sigChan := make(chan os.Signal)
				signal.Notify(sigChan, sys.SIGINT)
				client := rpc.NewClient(listener.Addr().String())
				funcs, err := client.ListFunctions(args[0])
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 1
				}
				for i := range funcs {
					_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true})
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
						return 1
					}
				}
				stateChan := client.Continue()
				for {
					select {
					case state := <-stateChan:
						if state.Err != nil {
							fmt.Fprintln(os.Stderr, state.Err)
							return 0
						}
						var args []string
						var fname string
						if state.CurrentThread != nil && state.CurrentThread.Function != nil {
							fname = state.CurrentThread.Function.Name
						}
						if state.BreakpointInfo != nil {
							for _, arg := range state.BreakpointInfo.Arguments {
								args = append(args, arg.Value)
							}
						}
						fmt.Printf("%s(%s) %s:%d\n", fname, strings.Join(args, ", "), state.CurrentThread.File, state.CurrentThread.Line)
					case <-sigChan:
						server.Stop(traceAttachPid == 0)
						return 1
					}
				}
				return 0
			}()
			os.Exit(status)
		},
	}
	traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
	rootCommand.AddCommand(traceCommand)

	// '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) {
			status := func() int {
				wd, err := os.Getwd()
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return 1
				}
				base := filepath.Base(wd)
				goTest := exec.Command("go", "test", "-c", "-gcflags", "-N -l", BuildFlags)
				goTest.Stderr = os.Stderr
				err = goTest.Run()
				if err != nil {
					return 1
				}
				debugname := "./" + base + ".test"
				defer os.Remove(debugname)
				processArgs := append([]string{debugname}, args...)

				return execute(0, processArgs, conf)
			}()
			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.",
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return errors.New("you must provide a PID")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			pid, err := strconv.Atoi(args[0])
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
				os.Exit(1)
			}
			os.Exit(execute(pid, nil, conf))
		},
	}
	rootCommand.AddCommand(attachCommand)

	// 'connect' subcommand.
	connectCommand := &cobra.Command{
		Use:   "connect [addr]",
		Short: "Connect to a headless debug server.",
		Long:  "Connect to a headless debug server.",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				fmt.Fprintf(os.Stderr, "An address was not provided. You must provide an address as the first argument.\n")
				os.Exit(1)
			}
			addr := args[0]
			if addr == "" {
				fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
				os.Exit(1)
			}
			os.Exit(connect(addr, conf))
		},
	}
	rootCommand.AddCommand(connectCommand)

	rootCommand.Execute()
}

func connect(addr string, conf *config.Config) int {
	// Create and start a terminal - attach to running instance
	var client service.Client
	client = rpc.NewClient(addr)
	term := terminal.New(client, conf)
	err, status := term.Run()
	if err != nil {
		fmt.Println(err)
	}
	return status
}

func execute(attachPid int, processArgs []string, conf *config.Config) int {
	// Make a TCP listener
	listener, err := net.Listen("tcp", Addr)
	if err != nil {
		fmt.Printf("couldn't start listener: %s\n", err)
		return 1
	}
	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,
		ProcessArgs: processArgs,
		AttachPid:   attachPid,
	}, Log)
	if err := server.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var status int
	if !Headless {
		// Create and start a terminal
		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)
		signal.Notify(ch, sys.SIGINT)
		<-ch
		err = server.Stop(true)
	}

	if err != nil {
		fmt.Println(err)
	}

	return status
}
<|endoftext|>


<commit_before>// Package ez provides an easy but powerful way to define unit tests and benchmarks that are compatible with package `testing`.
package ez

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"
	"runtime"
	"runtime/debug"
	"strings"
	"testing"
)

type Unit struct {
	f  *reflect.Value
	rs []runner
	T  *testing.T
	B  *testing.B
	tr bool
	br bool
}

type Case struct {
	f   reflect.Value
	in  tuple
	out *tuple // nil means panic
}

type Step struct {
	fn func()
}

type runner interface {
	runTest(int, *testing.T)
	runBenchmark(int, *testing.B)
}

func NewUnit() *Unit {
	u := &Unit{}
	// FIXME: Sadly, finalizers are not guaranteed to run, so they're of little comfort.
	runtime.SetFinalizer(u, func(u *Unit) {
		if !u.tr && !u.br {
			panic("neither test nor benchmark ran")
		}
	})
	return u
}

func Test(fn interface{}, t *testing.T) *Unit {
	return NewUnit().setT(t).Of(fn)
}

func Benchmark(fn interface{}, b *testing.B) *Unit {
	return NewUnit().setB(b).Of(fn)
}

func (u *Unit) setT(t *testing.T) *Unit {
	u.T = t
	return u
}

func (u *Unit) setB(b *testing.B) *Unit {
	u.B = b
	return u
}

func (u *Unit) Of(fn interface{}) *Unit {
	f := reflect.ValueOf(fn)
	if !f.IsValid() || f.Kind() != reflect.Func {
		panic("not a valid function")
	}
	u.f = &f
	return u
}

func (u *Unit) Do(fn func(*Unit)) *Unit {
	fn(u)
	return u
}

func (u *Unit) Then(fn func()) *Unit { // TODO: Rename Step.
	u.rs = append(u.rs, Step{fn})
	return u
}

type CaseMap map[*tuple]*tuple

func (u *Unit) Cases(cs CaseMap) *Unit {
	for i, o := range cs {
		u = u.addCase(*i, o)
	}
	return u
}

func In(xs ...interface{}) *tuple  { return newTuple(xs) }
func Out(xs ...interface{}) *tuple { return newTuple(xs) }
func Panic() *tuple                { return nil }

type half struct {
	in tuple
	u  *Unit
}

func (u *Unit) In(xs ...interface{}) *half  { return &half{*newTuple(xs), u} }
func (h *half) Out(xs ...interface{}) *Unit { return h.u.addCase(h.in, newTuple(xs)) }
func (h *half) Panic() *Unit                { return h.u.addCase(h.in, nil) }

func (u *Unit) addCase(in tuple, out *tuple) *Unit {
	u.rs = append(u.rs, u.newCase(in, out))
	return u
}

func (u *Unit) newCase(in tuple, out *tuple) Case {
	if u.f == nil {
		panic("test has no function")
	}
	return Case{*u.f, in, out}
}

func (u *Unit) Run() {
	if u.B == nil && u.T == nil {
		panic("T and B are both nil")
	}
	if u.T != nil {
		u.RunTest(u.T)
	}
	if u.B != nil {
		u.RunBenchmark(u.B)
	}
}

func (u *Unit) RunTest(t *testing.T) {
	if u.tr {
		panic("test already ran")
	}
	u.tr = true

	for i, r := range u.rs {
		r.runTest(i, t)
	}
}

func (u *Unit) RunBenchmark(b *testing.B) {
	if u.br {
		panic("benchmark already ran")
	}
	u.br = true

	for i := 0; i < b.N; i++ {
		for j, r := range u.rs {
			r.runBenchmark(j, b)
		}
	}
}

func (s Step) runTest(int, *testing.T) {
	s.fn()
}

func (s Step) runBenchmark(_ int, b *testing.B) {
	b.StopTimer()
	s.fn()
	b.StartTimer()
}

func (c Case) runTest(i int, t *testing.T) {
	// TODO: Color i, n & c.in with default colors, so they can eventually be customized too.
	f := c.f
	n := runtime.FuncForPC(f.Pointer()).Name()
	defer func() {
		e := recover()
		if c.out == nil || e == nil {
			return
		}
		t.Errorf("case #%d %s - %s%v\n%s\n%s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want %#+v", *c.out),
			colorf(red, black, "have panic [%s]\n%s", e, string(debug.Stack())),
		)
	}()
	if out := apply(f, c.in.values(f)); c.out == nil {
		t.Errorf("case #%d %s - %s%v\n%s\n%s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want panic"), // TODO: Allow specifying the panic value or at least string.
			colorf(red, black, "have %#+v", out),
		)
	} else if !c.out.Equal(out) {
		t.Errorf("\b \b \b case #%d %s - %s%v\n%s\n%s\ndiff %s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want %#+v", *c.out),
			colorf(red, black, "have %#+v", out),
			Diff(fmt.Sprintf("%#+v", out), fmt.Sprintf("%#+v", *c.out)),
		)
	}
}

func (c Case) runBenchmark(i int, b *testing.B) {
	b.StopTimer()
	args := c.in.values(c.f)
	b.StartTimer()
	c.f.Call(args)
}

func apply(f reflect.Value, args []reflect.Value) tuple {
	var ys []interface{}
	for _, v := range f.Call(args) {
		ys = append(ys, v.Interface())
	}
	return tuple{ys, "", 0}
}

var Colorize = true

const (
	white     = 15
	black     = 232
	gray      = 59 // 7
	green     = 40
	purple    = 60
	cyan      = 80
	orange    = 214
	yellow    = 226
	red       = 160
	brightRed = 196
)

func colorf(fg, bg uint16, format string, xs ...interface{}) string {
	s := fmt.Sprintf(format, xs...)
	if !Colorize {
		return s
	}
	code := func(a, b, c uint16) string { return fmt.Sprintf("%d;%d;%d", a, b, c) }
	return fmt.Sprintf("\033[%s;%sm%s\033[0m", code(38, 5, fg), code(48, 5, bg), s)
}

var Diff = func(a, b string) (s string) {
	defer func() {
		if e := recover(); e != nil {
			s = "<unavailable: please install git>" + "\n" + fmt.Sprint(e) + "\n" + string(debug.Stack())
		}
	}()

	dir := os.TempDir()
	af, err := ioutil.TempFile(dir, "A-")
	if err != nil {
		panic(err)
	}
	defer af.Close()
	bf, err := ioutil.TempFile(dir, "B-")
	if err != nil {
		panic(err)
	}
	defer bf.Close()
	if _, err = af.WriteString(a); err != nil {
		panic(err)
	}
	if _, err = bf.WriteString(b); err != nil {
		panic(err)
	}
	bs, err := exec.Command("git", "diff", "--color-words", "--no-index", af.Name(), bf.Name()).Output()
	s = string(bs)
	if err != nil {
		// FIXME: Figure out how to make diff exit with 0 so that err is nil on
		//        success, otherwise we get "exit status 1".
		if len(s) == 0 {
			panic(err)
		}
	}

	if ss := strings.Split(s, "\n"); len(ss) >= 5 {
		// Skip the first five lines:
		// diff --git foo bar
		// index xyz
		// --- foo
		// +++ bar
		// @@
		return strings.Join(ss[5:], "\n")
	}
	return "<empty>"
}
<commit_msg>Rename {NewUnit,Of,Do,Then} to {New,Func,Thru,Step} and add Unit.Case<commit_after>// Package ez provides an easy but powerful way to define unit tests and benchmarks that are compatible with package `testing`.
package ez

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"
	"runtime"
	"runtime/debug"
	"strings"
	"testing"
)

type Unit struct {
	f  *reflect.Value
	rs []runner
	T  *testing.T
	B  *testing.B
	tr bool
	br bool
}

type Case struct {
	f   reflect.Value
	in  tuple
	out *tuple // nil means panic
}

type Step struct {
	fn func()
}

type runner interface {
	runTest(int, *testing.T)
	runBenchmark(int, *testing.B)
}

func New() *Unit {
	u := &Unit{}
	// FIXME: Sadly, finalizers are not guaranteed to run, so they're of little comfort.
	runtime.SetFinalizer(u, func(u *Unit) {
		if !u.tr && !u.br {
			panic("neither test nor benchmark ran")
		}
	})
	return u
}

func Test(fn interface{}, t *testing.T) *Unit {
	return NewUnit().setT(t).Of(fn)
}

func Benchmark(fn interface{}, b *testing.B) *Unit {
	return NewUnit().setB(b).Of(fn)
}

func (u *Unit) setT(t *testing.T) *Unit {
	u.T = t
	return u
}

func (u *Unit) setB(b *testing.B) *Unit {
	u.B = b
	return u
}

func (u *Unit) Func(fn interface{}) *Unit {
	f := reflect.ValueOf(fn)
	if !f.IsValid() || f.Kind() != reflect.Func {
		panic("not a valid function")
	}
	u.f = &f
	return u
}

func (u *Unit) Thru(fn func(*Unit)) *Unit {
	fn(u)
	return u
}

func (u *Unit) Step(fn func()) *Unit {
	u.rs = append(u.rs, Step{fn})
	return u
}

type CaseMap map[*tuple]*tuple

func (u *Unit) Case(in, out *tuple) *Unit {
	return u.addCase(*in, out)
}

func (u *Unit) Cases(cs CaseMap) *Unit {
	for in, out := range cs {
		u = u.addCase(*in, out)
	}
	return u
}

func In(xs ...interface{}) *tuple  { return newTuple(xs) }
func Out(xs ...interface{}) *tuple { return newTuple(xs) }
func Panic() *tuple                { return nil }

type half struct {
	in tuple
	u  *Unit
}

func (u *Unit) In(xs ...interface{}) *half  { return &half{*newTuple(xs), u} }
func (h *half) Out(xs ...interface{}) *Unit { return h.u.addCase(h.in, newTuple(xs)) }
func (h *half) Panic() *Unit                { return h.u.addCase(h.in, nil) }

func (u *Unit) addCase(in tuple, out *tuple) *Unit {
	u.rs = append(u.rs, u.newCase(in, out))
	return u
}

func (u *Unit) newCase(in tuple, out *tuple) Case {
	if u.f == nil {
		panic("test has no function")
	}
	return Case{*u.f, in, out}
}

func (u *Unit) Run() {
	if u.B == nil && u.T == nil {
		panic("T and B are both nil")
	}
	if u.T != nil {
		u.RunTest(u.T)
	}
	if u.B != nil {
		u.RunBenchmark(u.B)
	}
}

func (u *Unit) RunTest(t *testing.T) {
	if u.tr {
		panic("test already ran")
	}
	u.tr = true

	for i, r := range u.rs {
		r.runTest(i, t)
	}
}

func (u *Unit) RunBenchmark(b *testing.B) {
	if u.br {
		panic("benchmark already ran")
	}
	u.br = true

	for i := 0; i < b.N; i++ {
		for j, r := range u.rs {
			r.runBenchmark(j, b)
		}
	}
}

func (s Step) runTest(int, *testing.T) {
	s.fn()
}

func (s Step) runBenchmark(_ int, b *testing.B) {
	b.StopTimer()
	s.fn()
	b.StartTimer()
}

func (c Case) runTest(i int, t *testing.T) {
	// TODO: Color i, n & c.in with default colors, so they can eventually be customized too.
	f := c.f
	n := runtime.FuncForPC(f.Pointer()).Name()
	defer func() {
		e := recover()
		if c.out == nil || e == nil {
			return
		}
		t.Errorf("case #%d %s - %s%v\n%s\n%s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want %#+v", *c.out),
			colorf(red, black, "have panic [%s]\n%s", e, string(debug.Stack())),
		)
	}()
	if out := apply(f, c.in.values(f)); c.out == nil {
		t.Errorf("case #%d %s - %s%v\n%s\n%s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want panic"), // TODO: Allow specifying the panic value or at least string.
			colorf(red, black, "have %#+v", out),
		)
	} else if !c.out.Equal(out) {
		t.Errorf("\b \b \b case #%d %s - %s%v\n%s\n%s\ndiff %s",
			i,
			colorf(black, white, " %s:%d ", c.in.f, c.in.l),
			n,
			c.in,
			colorf(green, black, "want %#+v", *c.out),
			colorf(red, black, "have %#+v", out),
			Diff(fmt.Sprintf("%#+v", out), fmt.Sprintf("%#+v", *c.out)),
		)
	}
}

func (c Case) runBenchmark(i int, b *testing.B) {
	b.StopTimer()
	args := c.in.values(c.f)
	b.StartTimer()
	c.f.Call(args)
}

func apply(f reflect.Value, args []reflect.Value) tuple {
	var ys []interface{}
	for _, v := range f.Call(args) {
		ys = append(ys, v.Interface())
	}
	return tuple{ys, "", 0}
}

var Colorize = true

const (
	white     = 15
	black     = 232
	gray      = 59 // 7
	green     = 40
	purple    = 60
	cyan      = 80
	orange    = 214
	yellow    = 226
	red       = 160
	brightRed = 196
)

func colorf(fg, bg uint16, format string, xs ...interface{}) string {
	s := fmt.Sprintf(format, xs...)
	if !Colorize {
		return s
	}
	code := func(a, b, c uint16) string { return fmt.Sprintf("%d;%d;%d", a, b, c) }
	return fmt.Sprintf("\033[%s;%sm%s\033[0m", code(38, 5, fg), code(48, 5, bg), s)
}

var Diff = func(a, b string) (s string) {
	defer func() {
		if e := recover(); e != nil {
			s = "<unavailable: please install git>" + "\n" + fmt.Sprint(e) + "\n" + string(debug.Stack())
		}
	}()

	dir := os.TempDir()
	af, err := ioutil.TempFile(dir, "A-")
	if err != nil {
		panic(err)
	}
	defer af.Close()
	bf, err := ioutil.TempFile(dir, "B-")
	if err != nil {
		panic(err)
	}
	defer bf.Close()
	if _, err = af.WriteString(a); err != nil {
		panic(err)
	}
	if _, err = bf.WriteString(b); err != nil {
		panic(err)
	}
	bs, err := exec.Command("git", "diff", "--color-words", "--no-index", af.Name(), bf.Name()).Output()
	s = string(bs)
	if err != nil {
		// FIXME: Figure out how to make diff exit with 0 so that err is nil on
		//        success, otherwise we get "exit status 1".
		if len(s) == 0 {
			panic(err)
		}
	}

	if ss := strings.Split(s, "\n"); len(ss) >= 5 {
		// Skip the first five lines:
		// diff --git foo bar
		// index xyz
		// --- foo
		// +++ bar
		// @@
		return strings.Join(ss[5:], "\n")
	}
	return "<empty>"
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	"github.com/morikuni/mdq"
	"github.com/spf13/pflag"
)

var (
	Version string = "unknown"
)

func main() {
	os.Exit(Run(os.Args, os.Stdin, os.Stdout, os.Stderr))
}

func Run(args []string, in io.Reader, out io.Writer, errW io.Writer) int {
	home := os.Getenv("HOME")

	flag := pflag.NewFlagSet("mdq", pflag.ContinueOnError)
	tag := flag.String("tag", "", "database tag")
	format := flag.String("format", "", "golang template string")
	config := flag.String("config", home+"/.config/mdq/config.yaml", "path to config file")
	silent := flag.Bool("silent", false, "ignore errors from databases")
	help := flag.BoolP("help", "h", false, "print this help.")
	version := flag.Bool("version", false, "print version of mdq")

	flag.Usage = func() {
		fmt.Fprintln(errW)
		fmt.Fprintln(errW, "Usage: mdq [flags] <query>")
		fmt.Fprintln(errW)
		fmt.Fprintln(errW, flag.FlagUsages())
	}

	err := flag.Parse(args[1:])
	if err != nil {
		fmt.Fprintln(errW, err)
		return 1
	}

	if *help {
		flag.Usage()
		return 0
	}

	if *version {
		fmt.Fprintln(out, "mdq version", Version)
		return 0
	}

	as := flag.Args()
	if len(as) > 1 {
		fmt.Fprintln(errW, "too many args")
		return 1
	}
	var query string
	if len(as) == 1 {
		query = as[0]
	} else {
		bs, err := ioutil.ReadAll(in)
		if err != nil {
			fmt.Fprintln(errW, *config)
			return 1
		}
		query = string(bs)
	}

	reporter := mdq.DefaultReporter
	if *silent {
		reporter = mdq.SilentReporter
	}

	f, err := os.Open(*config)
	if err != nil {
		fmt.Fprintln(errW, "cannot open config file:", *config)
		return 1
	}
	defer f.Close()

	dbs, err := mdq.CreateDBsFromConfig(f, *tag)
	if err != nil {
		fmt.Fprintln(errW, err)
		return 1
	}

	cluster := mdq.NewCluster(dbs, reporter)

	results := cluster.Query(query)

	var printer mdq.Printer
	if *format != "" {
		printer, err = mdq.NewTemplatePrinter(os.Stdout, *format)
		if err != nil {
			fmt.Fprintln(errW, err)
			return 1
		}
	} else {
		printer = mdq.NewJsonPrinter(os.Stdout)
	}
	printer.Print(results)

	return 0
}
<commit_msg>Handele first argument as a tag<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	"github.com/morikuni/mdq"
	"github.com/spf13/pflag"
)

var (
	Version string = "unknown"
)

func main() {
	os.Exit(Run(os.Args, os.Stdin, os.Stdout, os.Stderr))
}

func Run(args []string, in io.Reader, out io.Writer, errW io.Writer) int {
	home := os.Getenv("HOME")

	flag := pflag.NewFlagSet("mdq", pflag.ContinueOnError)
	tag := flag.String("tag", "", "database tag")
	format := flag.String("format", "", "golang template string")
	config := flag.String("config", home+"/.config/mdq/config.yaml", "path to config file")
	silent := flag.Bool("silent", false, "ignore errors from databases")
	help := flag.BoolP("help", "h", false, "print this help.")
	version := flag.Bool("version", false, "print version of mdq")

	flag.Usage = func() {
		fmt.Fprintln(errW)
		fmt.Fprintln(errW, "Usage: mdq [flags] [<tag>] <query>")
		fmt.Fprintln(errW)
		fmt.Fprintln(errW, flag.FlagUsages())
	}

	err := flag.Parse(args[1:])
	if err != nil {
		fmt.Fprintln(errW, err)
		return 1
	}

	if *help {
		flag.Usage()
		return 0
	}

	if *version {
		fmt.Fprintln(out, "mdq version", Version)
		return 0
	}

	as := flag.Args()
	if len(as) > 2 {
		fmt.Fprintln(errW, "too many args")
		return 1
	}
	var query string
	switch len(as) {
	case 1:
		query = as[0]
	case 2:
		*tag = as[0]
		query = as[1]
	default:
		bs, err := ioutil.ReadAll(in)
		if err != nil {
			fmt.Fprintln(errW, *config)
			return 1
		}
		query = string(bs)
	}

	reporter := mdq.DefaultReporter
	if *silent {
		reporter = mdq.SilentReporter
	}

	f, err := os.Open(*config)
	if err != nil {
		fmt.Fprintln(errW, "cannot open config file:", *config)
		return 1
	}
	defer f.Close()

	dbs, err := mdq.CreateDBsFromConfig(f, *tag)
	if err != nil {
		fmt.Fprintln(errW, err)
		return 1
	}

	cluster := mdq.NewCluster(dbs, reporter)

	results := cluster.Query(query)

	var printer mdq.Printer
	if *format != "" {
		printer, err = mdq.NewTemplatePrinter(os.Stdout, *format)
		if err != nil {
			fmt.Fprintln(errW, err)
			return 1
		}
	} else {
		printer = mdq.NewJsonPrinter(os.Stdout)
	}
	printer.Print(results)

	return 0
}
<|endoftext|>


<commit_before>// Copyright 2017 phcurtis fn Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fn - includes APIs relating to function names (fn).
// Such as returning a given func name relative to its position on the
// call stack. Other APIs include returning all the func names on the
// call stack, and trace logging the entry and exiting of a func including
// its time duration.
package fn

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

// Version of package fn
const Version = 0.200

// Level genealogy values for exported Lvl functions
const (
	Lme     = 0       // me
	Lpar    = Lme + 1 // parent
	Lgpar   = Lme + 2 // grandparent
	Lggpar  = Lme + 3 // great-grandparent
	Lgggpar = Lme + 4 // great-great-grandparent
)

// nameform - contains form of func name to return
type nameform uint8

// list of forms of a func name to return
const (
	nfull nameform = 0 // full name form
	nbase nameform = 1 // filepath.Base form
)

//const cStkEndPfix = "<EndOfCallStack:lvlll-lvl="

// CStkEndPfix - sentinel prefix value denoting end of call stack
const CStkEndPfix = "<EndOfCallStack:"

// low level func getting a given 'lvl' func name
func lvlll(lvl int, nform nameform) string {
	const baselvl = 2
	pc := make([]uintptr, 10)
	runtime.Callers(baselvl+lvl, pc)
	name := runtime.FuncForPC(pc[0]).Name()
	if name == "" {
		name = fmt.Sprintf(CStkEndPfix+"%d>", lvl)
	} else {
		if nform == nbase {
			name = filepath.Base(name)
		}
	}
	return name
}

// Lvl - returns the func name relative to levels back on
// caller stack it was invoked from. Use lvl=Lpar for parent func,
// lvl=Lgpar or lvl=2 for GrandParent and so on.
func Lvl(lvl int) string {
	return lvlll(lvl+Lpar, nfull)
}

// flags used in funcs LvlInfoNNN.
const (
	Ifnbase = 1 << iota
	Ifnfull
	Ifileshort
	Ifilelong
	Ifuncnoparens
	Ifilenogps
	IflagsDef   = Ifnbase | Ifilenogps
	IflagsCmn   = Ifnbase | Ifilenogps
	IflagsShort = Ifnbase | Ifileshort
)

// LvlInfo - returns level info details, filename, linenum and func name
// adjusted according to flags value.
func LvlInfo(lvl int, flags int) (file string, line int, name string) {
	const baselvl = 2
	pc := make([]uintptr, 10)
	runtime.Callers(baselvl+lvl, pc)
	name = runtime.FuncForPC(pc[0]).Name()
	if name == "" {
		name = fmt.Sprintf(CStkEndPfix+"%d>", lvl)
	} else {
		if flags&Ifnbase > 0 {
			name = filepath.Base(name)
		}
		if flags&Ifuncnoparens == 0 {
			name += "()"
		}
	}
	var ok bool
	_, file, line, ok = runtime.Caller(baselvl + lvl - 1)
	if !ok {
		file = "???"
		line = 0
	}
	if flags&Ifileshort > 0 {
		file = filepath.Base(file)
	} else if flags&Ifilenogps > 0 {
		if strings.HasPrefix(file, gopathsrc) {
			file = file[len(gopathsrc):]
		}
	}
	return file, line, name
}

// LvlInfoStr - returns level one string containing info details,
// filename, linenum and func name adjusted according to flags value.
func LvlInfoStr(lvl int, flags int) string {
	file, line, name := LvlInfo(lvl+1, flags)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlInfoCmn - returns level one string containing info details,
// filename, linenum and func name adjusted to IflagsCmn flags value.
func LvlInfoCmn(lvl int) string {
	file, line, name := LvlInfo(lvl+1, IflagsCmn)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlInfoShort - returns level one string containing info details,
// filename, linenum and func name adjusted to IflagsShort flags value.
func LvlInfoShort(lvl int) string {
	file, line, name := LvlInfo(lvl+1, IflagsShort)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlBase - returns the filepath.Base form of func name relative to
// levels back on caller stack it was invoked from.
func LvlBase(lvl int) string {
	return lvlll(lvl+Lpar, nbase)
}

// Cur - returns the current func name relative to where it was invoked from.
func Cur() string {
	return lvlll(Lpar, nfull)
}

// CurBase - returns the filepath.Base form of func name relative to
// where it it was invoked from.
func CurBase() string {
	return lvlll(Lpar, nbase)
}

// LvlCStkMax -- max Level call stack depth that LvlCStk will search too.
const LvlCStkMax = 500

// LvlCStk returns func names in call stack for a given level relative
// to were it was invoked from; Typically one should use CStk instead.
// Use lvl=Lpar for parent func, lvl=LgPar for GrandParent and so on
func LvlCStk(lvl int) string {
	var name, sep string
	for i := lvl; i <= LvlCStkMax; i++ {
		cname := Lvl(i + Lpar)
		//fmt.Printf("cname(%d):%s\n", i, cname)
		if strings.HasPrefix(cname, CStkEndPfix) {
			break
		}
		name += sep + cname
		sep = "<--" // do not change - testing is dependent on this
	}
	return name
}

// CStk - returns func names in call stack relative to where it was invoked from.
func CStk() string {
	return LvlCStk(Lpar)
}
<commit_msg>end of callstk better msg and funcs named args<commit_after>// Copyright 2017 phcurtis fn Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fn - includes APIs relating to function names (fn).
// Such as returning a given func name relative to its position on the
// call stack. Other APIs include returning all the func names on the
// call stack, and trace logging the entry and exiting of a func including
// its time duration.
package fn

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

// Version of package fn
const Version = 0.201

// Level genealogy values for exported Lvl functions
const (
	Lme     = 0       // me
	Lpar    = Lme + 1 // parent
	Lgpar   = Lme + 2 // grandparent
	Lggpar  = Lme + 3 // great-grandparent
	Lgggpar = Lme + 4 // great-great-grandparent
)

// nameform - contains form of func name to return
type nameform uint8

// list of forms of a func name to return
const (
	nfull nameform = 0 // full name form
	nbase nameform = 1 // filepath.Base form
)

//const cStkEndPfix = "<EndOfCallStack:lvlll-lvl="

// CStkEndPfix - sentinel prefix value denoting end of call stack
const CStkEndPfix = "<EndOfCallStack:"

// low level func getting a given 'lvl' func name
func lvlll(lvl int, nform nameform) string {
	const baselvl = 2
	pc := make([]uintptr, 10)
	runtime.Callers(baselvl+lvl, pc)
	name := runtime.FuncForPC(pc[0]).Name()
	if name == "" {
		name = fmt.Sprintf(CStkEndPfix+"lvlll-lvl=%d>", lvl)
	} else {
		if nform == nbase {
			name = filepath.Base(name)
		}
	}
	return name
}

// Lvl - returns the func name relative to levels back on
// caller stack it was invoked from. Use lvl=Lpar for parent func,
// lvl=Lgpar or lvl=2 for GrandParent and so on.
func Lvl(lvl int) string {
	return lvlll(lvl+Lpar, nfull)
}

// flags used in funcs LvlInfoNNN.
const (
	Ifnbase = 1 << iota
	Ifnfull
	Ifileshort
	Ifilelong
	Ifuncnoparens
	Ifilenogps
	IflagsDef   = Ifnbase | Ifilenogps
	IflagsCmn   = Ifnbase | Ifilenogps
	IflagsShort = Ifnbase | Ifileshort
)

// LvlInfo - returns level info details, filename, linenum and func name
// adjusted according to flags value.
func LvlInfo(lvl int, flags int) (file string, line int, name string) {
	const baselvl = 2
	pc := make([]uintptr, 10)
	runtime.Callers(baselvl+lvl, pc)
	name = runtime.FuncForPC(pc[0]).Name()
	if name == "" {
		name = fmt.Sprintf(CStkEndPfix+"%d>", lvl)
	} else {
		if flags&Ifnbase > 0 {
			name = filepath.Base(name)
		}
		if flags&Ifuncnoparens == 0 {
			name += "()"
		}
	}
	var ok bool
	_, file, line, ok = runtime.Caller(baselvl + lvl - 1)
	if !ok {
		file = "???"
		line = 0
	}
	if flags&Ifileshort > 0 {
		file = filepath.Base(file)
	} else if flags&Ifilenogps > 0 {
		if strings.HasPrefix(file, gopathsrc) {
			file = file[len(gopathsrc):]
		}
	}
	return file, line, name
}

// LvlInfoStr - returns level one string containing info details,
// filename, linenum and func name adjusted according to flags value.
func LvlInfoStr(lvl int, flags int) (fileLineName string) {
	file, line, name := LvlInfo(lvl+1, flags)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlInfoCmn - returns level one string containing info details,
// filename, linenum and func name adjusted to IflagsCmn flags value.
func LvlInfoCmn(lvl int) (fileLineName string) {
	file, line, name := LvlInfo(lvl+1, IflagsCmn)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlInfoShort - returns level one string containing info details,
// filename, linenum and func name adjusted to IflagsShort flags value.
func LvlInfoShort(lvl int) (fileLineName string) {
	file, line, name := LvlInfo(lvl+1, IflagsShort)
	return fmt.Sprintf("%s:%d:%s", file, line, name)
}

// LvlBase - returns the filepath.Base form of func name relative to
// levels back on caller stack it was invoked from.
func LvlBase(lvl int) string {
	return lvlll(lvl+Lpar, nbase)
}

// Cur - returns the current func name relative to where it was invoked from.
func Cur() string {
	return lvlll(Lpar, nfull)
}

// CurBase - returns the filepath.Base form of func name relative to
// where it it was invoked from.
func CurBase() string {
	return lvlll(Lpar, nbase)
}

// LvlCStkMax -- max Level call stack depth that LvlCStk will search too.
const LvlCStkMax = 500

// LvlCStk returns func names in call stack for a given level relative
// to were it was invoked from; Typically one should use CStk instead.
// Use lvl=Lpar for parent func, lvl=LgPar for GrandParent and so on
func LvlCStk(lvl int) string {
	var name, sep string
	for i := lvl; i <= LvlCStkMax; i++ {
		cname := Lvl(i + Lpar)
		//fmt.Printf("cname(%d):%s\n", i, cname)
		if strings.HasPrefix(cname, CStkEndPfix) {
			break
		}
		name += sep + cname
		sep = "<--" // do not change - testing is dependent on this
	}
	return name
}

// CStk - returns func names in call stack relative to where it was invoked from.
func CStk() string {
	return LvlCStk(Lpar)
}
<|endoftext|>


<commit_before>package logentrus_test

import (
	"os"
	"testing"

	"github.com/puddingfactory/logentrus"
	"github.com/sirupsen/logrus"
)

func init() {
	logrus.SetLevel(logrus.DebugLevel)           // This will effect your stdout level, but not the level for LogentriesHook. You specify that priority on creation
	logrus.SetFormatter(&logrus.TextFormatter{}) // You an use any formatter; LogentriesHook will always format as JSON without interfering with your other hooks

	hook, err := logentrus.New(
		os.Getenv("TOKEN"), // fetching token from env vars here. You can make a token in your logentries account and are expected to have 1 token for each application
		"Jan 2 15:04:05",   // timeFormat could be an empty string instead; doing so will default to logrus's typically time format.
		logrus.InfoLevel,   // log level is inclusive. Setting to logrus.ErrorLevel, for example, would include errors, panics, and fatals, but not info or debug.
		nil,                // setting config to nil means that conn will use root certs already set up on local system
	)
	if err != nil {
		panic(err)
	}
	logrus.AddHook(hook)
}

func TestDebug(t *testing.T) {
	logrus.Debug("This is a debug entry that should *not* show in logentries") // This won't appear in logentries due to the priority we set
}

func TestInfo(t *testing.T) {
	logrus.WithField("anotherField", "hi there!").Info("This is an info entry that should show up in logentries")
}

func TestError(t *testing.T) {
	logrus.WithField("the rent", "is too dang high").Error("This is an error entry that should also appear in logentries")
}
<commit_msg>Update token env var to be less ambiguous<commit_after>package logentrus_test

import (
	"os"
	"testing"

	"github.com/puddingfactory/logentrus"
	"github.com/sirupsen/logrus"
)

func init() {
	logrus.SetLevel(logrus.DebugLevel)           // This will effect your stdout level, but not the level for LogentriesHook. You specify that priority on creation
	logrus.SetFormatter(&logrus.TextFormatter{}) // You an use any formatter; LogentriesHook will always format as JSON without interfering with your other hooks

	hook, err := logentrus.New(
		os.Getenv("LOGENTRIESTOKEN"), // fetching token from env vars here. You can make a token in your logentries account and are expected to have 1 token for each application
		"Jan 2 15:04:05",             // timeFormat could be an empty string instead; doing so will default to logrus's typically time format.
		logrus.InfoLevel,             // log level is inclusive. Setting to logrus.ErrorLevel, for example, would include errors, panics, and fatals, but not info or debug.
		nil,                          // setting config to nil means that conn will use root certs already set up on local system
	)
	if err != nil {
		panic(err)
	}
	logrus.AddHook(hook)
}

func TestDebug(t *testing.T) {
	logrus.Debug("This is a debug entry that should *not* show in logentries") // This won't appear in logentries due to the priority we set
}

func TestInfo(t *testing.T) {
	logrus.WithField("anotherField", "hi there!").Info("This is an info entry that should show up in logentries")
}

func TestError(t *testing.T) {
	logrus.WithField("the rent", "is too dang high").Error("This is an error entry that should also appear in logentries")
}
<|endoftext|>


<commit_before>package restpc

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type Request interface {
	RemoteIP() (string, error)
	URL() *url.URL
	Host() string

	Body() ([]byte, error)
	BodyMap() (map[string]interface{}, error)
	BodyTo(model interface{}) error

	GetHeader(string) string

	GetString(key string, flags ...ParamFlag) (*string, error)
	GetStringList(key string, flags ...ParamFlag) ([]string, error)
	GetInt(key string, flags ...ParamFlag) (*int, error)
	GetFloat(key string, flags ...ParamFlag) (*float64, error)
	GetBool(key string, flags ...ParamFlag) (*bool, error)
	GetTime(key string, flags ...ParamFlag) (*time.Time, error)
}

type requestImp struct {
	r       *http.Request
	body    []byte
	bodyErr error
	bodyMap map[string]interface{}
}

func (req *requestImp) RemoteIP() (string, error) {
	remoteIp, _, err := net.SplitHostPort(req.r.RemoteAddr)
	if err != nil {
		return "", NewError(
			Internal, "", err,
			"r.RemoteAddr", req.r.RemoteAddr,
		)
	}
	return remoteIp, nil
}

func (req *requestImp) URL() *url.URL {
	return req.r.URL
}

func (req *requestImp) Host() string {
	return req.r.Host
}

func (req *requestImp) Body() ([]byte, error) {
	if req.body != nil {
		return req.body, nil
	}
	if req.bodyErr != nil {
		return nil, req.bodyErr
	}
	if req.r.Body == nil {
		return nil, nil
	}
	body, err := ioutil.ReadAll(req.r.Body)
	if err != nil {
		req.bodyErr = err
		log.Println(err)
	}
	req.body = body
	req.r.Body.Close()
	req.r.Body = nil
	return body, nil
}

func (req *requestImp) BodyMap() (map[string]interface{}, error) {
	if req.bodyMap != nil {
		return req.bodyMap, nil
	}
	data := map[string]interface{}{}
	body, err := req.Body()
	if err != nil {
		return nil, err
	}
	if len(body) > 0 {
		json.Unmarshal(body, &data)
	}
	req.bodyMap = data
	return data, nil
}

func (req *requestImp) BodyTo(model interface{}) error {
	body, err := req.Body()
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, model)
	if err != nil {
		return NewError(InvalidArgument, "request body is not a valid json", err)
	}
	return nil
}

func (req *requestImp) GetHeader(key string) string {
	return req.r.Header.Get(key)
}

func (req *requestImp) GetString(key string, flags ...ParamFlag) (*string, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case string:
				valueStr := value // to copy
				return &valueStr, nil
			case []byte:
				valueStr := string(value)
				return &valueStr, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be string", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		value := req.r.FormValue(key)
		if value != "" {
			return &value, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetStringList(key string, flags ...ParamFlag) ([]string, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case []string:
				valueSlice := append([]string(nil), value...) // to copy
				return valueSlice, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be array of strings", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueSlice := strings.Split(valueStr, ",")
			return valueSlice, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetInt(key string, flags ...ParamFlag) (*int, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case float64:
				valueInt := int(value)
				return &valueInt, nil
			case int:
				valueInt := value // to copy
				return &valueInt, nil
			case int32:
				valueInt := int(value)
				return &valueInt, nil
			case int64:
				valueInt := int(value)
				return &valueInt, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be integer", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			value, err := strconv.ParseInt(valueStr, 10, 64)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be integer", key),
					err,
				)
			}
			valueInt := int(value)
			return &valueInt, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetFloat(key string, flags ...ParamFlag) (*float64, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case float64:
				valueF := value // to copy
				return &valueF, nil
			case float32:
				valueF := float64(value)
				return &valueF, nil
			case int:
				valueF := float64(value)
				return &valueF, nil
			case int64:
				valueF := float64(value)
				return &valueF, nil
			case int32:
				valueF := float64(value)
				return &valueF, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be float", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			value, err := strconv.ParseFloat(valueStr, 64)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be float", key),
					err,
				)
			}
			valueF := float64(value)
			return &valueF, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetBool(key string, flags ...ParamFlag) (*bool, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case bool:
				valueBool := value // to copy
				return &valueBool, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be true or false", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueStr = strings.ToLower(valueStr)
			switch valueStr {
			case "true":
				valueBool := true
				return &valueBool, nil
			case "false":
				valueBool := false
				return &valueBool, nil
			}
			return nil, NewError(
				InvalidArgument,
				fmt.Sprintf("invalid '%v', must be true or false", key),
				nil,
			)
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetTime(key string, flags ...ParamFlag) (*time.Time, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case string:
				valueTm, err := time.Parse(time.RFC3339, value)
				if err != nil {
					return nil, NewError(
						InvalidArgument,
						fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
						err,
					)
				}
				return &valueTm, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueTm, err := time.Parse(time.RFC3339, valueStr)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
					err,
				)
			}
			return &valueTm, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}
<commit_msg>req.BodyMap(): keep the error and return it next time if it's not nil<commit_after>package restpc

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type Request interface {
	RemoteIP() (string, error)
	URL() *url.URL
	Host() string

	Body() ([]byte, error)
	BodyMap() (map[string]interface{}, error)
	BodyTo(model interface{}) error

	GetHeader(string) string

	GetString(key string, flags ...ParamFlag) (*string, error)
	GetStringList(key string, flags ...ParamFlag) ([]string, error)
	GetInt(key string, flags ...ParamFlag) (*int, error)
	GetFloat(key string, flags ...ParamFlag) (*float64, error)
	GetBool(key string, flags ...ParamFlag) (*bool, error)
	GetTime(key string, flags ...ParamFlag) (*time.Time, error)
}

type requestImp struct {
	r          *http.Request
	body       []byte
	bodyErr    error
	bodyMap    map[string]interface{}
	bodyMapErr error
}

func (req *requestImp) RemoteIP() (string, error) {
	remoteIp, _, err := net.SplitHostPort(req.r.RemoteAddr)
	if err != nil {
		return "", NewError(
			Internal, "", err,
			"r.RemoteAddr", req.r.RemoteAddr,
		)
	}
	return remoteIp, nil
}

func (req *requestImp) URL() *url.URL {
	return req.r.URL
}

func (req *requestImp) Host() string {
	return req.r.Host
}

func (req *requestImp) Body() ([]byte, error) {
	if req.body != nil {
		return req.body, nil
	}
	if req.bodyErr != nil {
		return nil, req.bodyErr
	}
	if req.r.Body == nil {
		return nil, nil
	}
	body, err := ioutil.ReadAll(req.r.Body)
	if err != nil {
		req.bodyErr = err
		log.Println(err)
	}
	req.body = body
	req.r.Body.Close()
	req.r.Body = nil
	return body, nil
}

func (req *requestImp) BodyMap() (map[string]interface{}, error) {
	if req.bodyMap != nil {
		return req.bodyMap, nil
	}
	if req.bodyMapErr != nil {
		return nil, req.bodyMapErr
	}
	data := map[string]interface{}{}
	body, err := req.Body()
	if err != nil {
		req.bodyMapErr = err
		return nil, err
	}
	if len(body) > 0 {
		err = json.Unmarshal(body, &data)
		req.bodyMapErr = err
		log.Println(err)
		// return nil, err // FIXME
	}
	req.bodyMap = data
	return data, nil
}

func (req *requestImp) BodyTo(model interface{}) error {
	body, err := req.Body()
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, model)
	if err != nil {
		return NewError(InvalidArgument, "request body is not a valid json", err)
	}
	return nil
}

func (req *requestImp) GetHeader(key string) string {
	return req.r.Header.Get(key)
}

func (req *requestImp) GetString(key string, flags ...ParamFlag) (*string, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case string:
				valueStr := value // to copy
				return &valueStr, nil
			case []byte:
				valueStr := string(value)
				return &valueStr, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be string", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		value := req.r.FormValue(key)
		if value != "" {
			return &value, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetStringList(key string, flags ...ParamFlag) ([]string, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case []string:
				valueSlice := append([]string(nil), value...) // to copy
				return valueSlice, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be array of strings", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueSlice := strings.Split(valueStr, ",")
			return valueSlice, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetInt(key string, flags ...ParamFlag) (*int, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case float64:
				valueInt := int(value)
				return &valueInt, nil
			case int:
				valueInt := value // to copy
				return &valueInt, nil
			case int32:
				valueInt := int(value)
				return &valueInt, nil
			case int64:
				valueInt := int(value)
				return &valueInt, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be integer", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			value, err := strconv.ParseInt(valueStr, 10, 64)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be integer", key),
					err,
				)
			}
			valueInt := int(value)
			return &valueInt, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetFloat(key string, flags ...ParamFlag) (*float64, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case float64:
				valueF := value // to copy
				return &valueF, nil
			case float32:
				valueF := float64(value)
				return &valueF, nil
			case int:
				valueF := float64(value)
				return &valueF, nil
			case int64:
				valueF := float64(value)
				return &valueF, nil
			case int32:
				valueF := float64(value)
				return &valueF, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be float", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			value, err := strconv.ParseFloat(valueStr, 64)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be float", key),
					err,
				)
			}
			valueF := float64(value)
			return &valueF, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetBool(key string, flags ...ParamFlag) (*bool, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case bool:
				valueBool := value // to copy
				return &valueBool, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be true or false", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueStr = strings.ToLower(valueStr)
			switch valueStr {
			case "true":
				valueBool := true
				return &valueBool, nil
			case "false":
				valueBool := false
				return &valueBool, nil
			}
			return nil, NewError(
				InvalidArgument,
				fmt.Sprintf("invalid '%v', must be true or false", key),
				nil,
			)
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}

func (req *requestImp) GetTime(key string, flags ...ParamFlag) (*time.Time, error) {
	flag := mergeParamFlags(flags...)
	if flag.FromJSON() {
		data, err := req.BodyMap()
		if err != nil {
			return nil, err
		}
		valueIn := data[key]
		if valueIn != nil {
			switch value := valueIn.(type) {
			case string:
				valueTm, err := time.Parse(time.RFC3339, value)
				if err != nil {
					return nil, NewError(
						InvalidArgument,
						fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
						err,
					)
				}
				return &valueTm, nil
			default:
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
					nil,
				)
			}
		}
	}
	if flag.FromForm() {
		valueStr := req.r.FormValue(key)
		if valueStr != "" {
			valueTm, err := time.Parse(time.RFC3339, valueStr)
			if err != nil {
				return nil, NewError(
					InvalidArgument,
					fmt.Sprintf("invalid '%v', must be RFC3339 time string", key),
					err,
				)
			}
			return &valueTm, nil
		}
	}
	if flag.Mandatory() {
		return nil, NewError(
			InvalidArgument,
			fmt.Sprintf("missing '%v'", key),
			nil,
		)
	}
	return nil, nil
}
<|endoftext|>


<commit_before>// Copyright 2013, Cong Ding. All rights reserved.
// Use of this source code is governed by a GPLv2
// license that can be found in the LICENSE file.
//
// author: Cong Ding <dinggnu@gmail.com>
package logging

import (
	"runtime"
	"strconv"
	"sync/atomic"
	"time"
)

type field func(*logging) string

var fields = map[string]field{
	"seqid":           (*logging).seqid,
	"name":            (*logging).name,
	"levelno":         (*logging).levelno,
	"levelname":       (*logging).levelname,
	"pathname":        (*logging).pathname,
	"filename":        (*logging).filename,
	"module":          (*logging).module,
	"lineno":          (*logging).lineno,
	"funcName":        (*logging).funcName,
	"created":         (*logging).created,
	"asctime":         (*logging).asctime,
	"msecs":           (*logging).msecs,
	"relativeCreated": (*logging).relativeCreated,
	"thread":          (*logging).thread,
	"threadName":      (*logging).threadName,
	"process":         (*logging).process,
	"message":         (*logging).message,
}

func init() {
}

func (logger *logging) seqid() string {
	return strconv.FormatUint(atomic.AddUint64(&(logger.Seqid), 1), 10)
}

func (logger *logging) name() string {
	return logger.Name
}

func (logger *logging) levelno() string {
	return strconv.Itoa(int(logger.Level))
}

func (logger *logging) levelname() string {
	return levelNames[logger.Level]
}

func (logger *logging) pathname() string {
	return ""
}

func (logger *logging) filename() string {
	calldepth := 5
	_, file, _, ok := runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}
	return file
}

func (logger *logging) module() string {
	return ""
}

func (logger *logging) lineno() string {
	calldepth := 5
	_, _, line, ok := runtime.Caller(calldepth)
	if !ok {
		line = 0
	}
	return strconv.Itoa(line)
}

func (logger *logging) funcName() string {
	return ""
}

func (logger *logging) created() string {
	return strconv.FormatInt(logger.startTime, 10)
}

func (logger *logging) asctime() string {
	return time.Now().String()
}

func (logger *logging) msecs() string {
	return strconv.Itoa(int(logger.startTime % 1000))
}

func (logger *logging) timestamp() string {
	return strconv.FormatInt(time.Now().UnixNano(), 10)
}

func (logger *logging) relativeCreated() string {
	return strconv.FormatInt(time.Now().UnixNano()-logger.startTime, 10)
}

func (logger *logging) thread() string {
	return ""
}

func (logger *logging) threadName() string {
	return ""
}

func (logger *logging) process() string {
	return ""
}

func (logger *logging) message() string {
	return ""
}
<commit_msg>get funcName<commit_after>// Copyright 2013, Cong Ding. All rights reserved.
// Use of this source code is governed by a GPLv2
// license that can be found in the LICENSE file.
//
// author: Cong Ding <dinggnu@gmail.com>
package logging

import (
	"runtime"
	"strconv"
	"sync/atomic"
	"time"
)

type field func(*logging) string

var fields = map[string]field{
	"seqid":           (*logging).seqid,
	"name":            (*logging).name,
	"levelno":         (*logging).levelno,
	"levelname":       (*logging).levelname,
	"pathname":        (*logging).pathname,
	"filename":        (*logging).filename,
	"module":          (*logging).module,
	"lineno":          (*logging).lineno,
	"funcName":        (*logging).funcName,
	"created":         (*logging).created,
	"asctime":         (*logging).asctime,
	"msecs":           (*logging).msecs,
	"relativeCreated": (*logging).relativeCreated,
	"thread":          (*logging).thread,
	"threadName":      (*logging).threadName,
	"process":         (*logging).process,
	"message":         (*logging).message,
}

func init() {
}

func (logger *logging) seqid() string {
	return strconv.FormatUint(atomic.AddUint64(&(logger.Seqid), 1), 10)
}

func (logger *logging) name() string {
	return logger.Name
}

func (logger *logging) levelno() string {
	return strconv.Itoa(int(logger.Level))
}

func (logger *logging) levelname() string {
	return levelNames[logger.Level]
}

func (logger *logging) pathname() string {
	return ""
}

func (logger *logging) filename() string {
	calldepth := 5
	_, file, _, ok := runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}
	return file
}

func (logger *logging) module() string {
	return ""
}

func (logger *logging) lineno() string {
	calldepth := 5
	_, _, line, ok := runtime.Caller(calldepth)
	if !ok {
		line = 0
	}
	return strconv.Itoa(line)
}

func (logger *logging) funcName() string {
	calldepth := 5
	pc, _, _, ok := runtime.Caller(calldepth)
	if !ok {
		return "???"
	}
	return runtime.FuncForPC(pc).Name()
}

func (logger *logging) created() string {
	return strconv.FormatInt(logger.startTime, 10)
}

func (logger *logging) asctime() string {
	return time.Now().String()
}

func (logger *logging) msecs() string {
	return strconv.Itoa(int(logger.startTime % 1000))
}

func (logger *logging) timestamp() string {
	return strconv.FormatInt(time.Now().UnixNano(), 10)
}

func (logger *logging) relativeCreated() string {
	return strconv.FormatInt(time.Now().UnixNano()-logger.startTime, 10)
}

func (logger *logging) thread() string {
	return ""
}

func (logger *logging) threadName() string {
	return ""
}

func (logger *logging) process() string {
	return ""
}

func (logger *logging) message() string {
	return ""
}
<|endoftext|>


<commit_before>package gadget

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/redneckbeard/gadget/env"
	"io/ioutil"
	"net/http"
	"time"
)

type Request struct {
	*http.Request
	Path      string
	Payload   map[string]interface{}
	Method    string
	UrlParams map[string]string
	User      User
}

func NewRequest(raw *http.Request) *Request {
	r := &Request{Request: raw, Path: raw.URL.Path[1:], Method: raw.Method}
	r.setPayload()
	return r
}

func (r *Request) ContentType() string {
	accept := r.Request.Header.Get("Accept")
	if accept != "" {
		return accept
	}
	return r.Request.Header.Get("Content-Type")
}

func (r *Request) setPayload() {
	payload := make(map[string]interface{})
	switch r.Request.Header.Get("Content-Type") {
	case "":
		err := r.ParseForm()
		if err != nil {
			return
		}
		for k, v := range r.Form {
			if len(v) == 1 {
				payload[k] = v[0]
			} else {
				payload[k] = v
			}
		}
	case "application/json":
		if r.Request.Body != nil {
			raw, err := ioutil.ReadAll(r.Request.Body)
			if err != nil {
				return
			}
			err = json.Unmarshal(raw, payload)
			if err != nil {
				return
			}
		}
	}
	r.Payload = payload
}

func (r *Request) SetUser() error {
	if r.UrlParams == nil {
		return errors.New("UrlParams must be set prior to user identification")
	}
	if identifyUser != nil {
		r.User = identifyUser(r)
	} else {
		r.User = &AnonymousUser{}
	}
	return nil
}

func (r *Request) Log(status, contentLength int) {
	raw := r.Request
	env.Log(fmt.Sprintf(`[%s] "%s %s %s" %d %d`, time.Now().Format(time.RFC822), r.Method, raw.URL.Path, raw.Proto, status, contentLength))
}
<commit_msg>Scoop the poop.<commit_after>package gadget

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/redneckbeard/gadget/env"
	"io/ioutil"
	"net/http"
	"time"
)

type Request struct {
	*http.Request
	Path      string
	Payload   map[string]interface{}
	Method    string
	UrlParams map[string]string
	User      User
}

func NewRequest(raw *http.Request) *Request {
	r := &Request{Request: raw, Path: raw.URL.Path[1:], Method: raw.Method}
	r.setPayload()
	return r
}

func (r *Request) ContentType() string {
	accept := r.Request.Header.Get("Accept")
	if accept != "" {
		return accept
	}
	return r.Request.Header.Get("Content-Type")
}

func (r *Request) setPayload() {
	payload := make(map[string]interface{})
	switch r.Request.Header.Get("Content-Type") {
	case "":
		err := r.ParseForm()
		if err != nil {
			return
		}
		for k, v := range r.Form {
			if len(v) == 1 {
				payload[k] = v[0]
			} else {
				payload[k] = v
			}
		}
	case "application/json":
		if r.Request.Body != nil {
			raw, err := ioutil.ReadAll(r.Request.Body)
			defer r.Request.Body.Close()
			if err != nil {
				return
			}
			err = json.Unmarshal(raw, payload)
			if err != nil {
				return
			}
		}
	}
	r.Payload = payload
}

func (r *Request) SetUser() error {
	if r.UrlParams == nil {
		return errors.New("UrlParams must be set prior to user identification")
	}
	if identifyUser != nil {
		r.User = identifyUser(r)
	} else {
		r.User = &AnonymousUser{}
	}
	return nil
}

func (r *Request) Log(status, contentLength int) {
	raw := r.Request
	env.Log(fmt.Sprintf(`[%s] "%s %s %s" %d %d`, time.Now().Format(time.RFC822), r.Method, raw.URL.Path, raw.Proto, status, contentLength))
}
<|endoftext|>