Repository: incubator-mynewt-newt Updated Branches: refs/heads/master 8a61764b4 -> acd9c3337
Move newtvm so that it is a sibling of newt. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/52e1f4c9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/52e1f4c9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/52e1f4c9 Branch: refs/heads/master Commit: 52e1f4c9fdc856b044e4fcebe9dafb67d12ae2e5 Parents: 8a61764 Author: Christopher Collins <ccollins47...@gmail.com> Authored: Thu Dec 3 16:33:13 2015 -0800 Committer: Christopher Collins <ccollins47...@gmail.com> Committed: Thu Dec 3 16:33:13 2015 -0800 ---------------------------------------------------------------------- newtvm/newtvm.go | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/52e1f4c9/newtvm/newtvm.go ---------------------------------------------------------------------- diff --git a/newtvm/newtvm.go b/newtvm/newtvm.go new file mode 100644 index 0000000..09274ce --- /dev/null +++ b/newtvm/newtvm.go @@ -0,0 +1,174 @@ +// newtvm is a Windows wrapper for the newt tool. It runs the specified +// commands within a Linux docker instance, giving access to newt and the +// utilities that it depends on. + +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "os/exec" + "regexp" + "strings" +) + +const debug bool = false +const dockerMachineName string = "default" +const newtvmImage = "mynewt/mynewt" +const newtvmVersion = "0.0.2" + +// Sets the necessary environment variables to allow docker to run. +func configEnv() error { + re, err := regexp.Compile("^SET ([^ ]+)=(.+)") + if err != nil { + return err + } + + cmd := exec.Command("docker-machine", "env", "--shell", "cmd", "default") + outputBytes, err := cmd.CombinedOutput() + if err != nil { + return err + } + + output := string(outputBytes[:]) + lines := strings.Split(output, "\n") + + for _, line := range lines { + matches := re.FindStringSubmatch(line) + if matches != nil { + if debug { + fmt.Fprintf(os.Stderr, "os.Setenv(\"%s\", \"%s\")\n", + matches[1], matches[2]) + } + err = os.Setenv(matches[1], matches[2]) + if err != nil { + return err + } + } + } + + return nil +} + +// Calculates a virtualbox-compatible representation of the present working +// directory. +// +// E.g., +// C:\Users\me\Documents +// +// becomes: +// /c/Users/me/documents +func fixedPwd() (string, error) { + var pwd string + var err error + + if pwd, err = os.Getwd(); err != nil { + return "", err + } + + // Begin with a slash; convert drive letter to lowercase. + pwd = "/" + strings.ToLower(pwd[0:1]) + pwd[2:] + + // Replace backslashes with slashes. + pwd = strings.Replace(pwd, "\\", "/", -1) + + return pwd, nil +} + +// Constructs a command that will run the specified shell tokens in the +// docker environment. +// +// E.g., the args parameter might be: { "echo", "'hello", "world'" } +func buildCmd(args []string) (*exec.Cmd, error) { + pwd, err := fixedPwd() + if err != nil { + return nil, err + } + + fullArgs := []string{ + "run", "--rm=true", "-v", fmt.Sprintf("%s:/larva", pwd), + "-w", "/larva", fmt.Sprintf("%s:%s", newtvmImage, newtvmVersion), + "script", "-qc", + strings.Join(args, " "), "/dev/null"} + + return exec.Command("docker", fullArgs...), nil +} + +// Executes the specified command, displaying output as it is generated. +func execCmd(cmd *exec.Cmd) error { + // Reader / scanner pair for printing stdout output. + stdoutReader, err := cmd.StdoutPipe() + if err != nil { + return err + } + + stdoutScanner := bufio.NewScanner(stdoutReader) + go func() { + for stdoutScanner.Scan() { + fmt.Println(stdoutScanner.Text()) + } + }() + + // Reader / scanner pair for printing stderr output. + stderrReader, err := cmd.StderrPipe() + if err != nil { + return err + } + + stderrScanner := bufio.NewScanner(stderrReader) + go func() { + for stderrScanner.Scan() { + fmt.Fprintln(os.Stderr, stderrScanner.Text()) + } + }() + + // Execute command. + err = cmd.Start() + if err != nil { + return err + } + + err = cmd.Wait() + if err != nil { + return err + } + + return nil +} + +func printUsage(w io.Writer) { + fmt.Fprintf(w, "usage: newtvm <command> [arg-1] [arg-2] [...]\n") +} + +func usageErr(msg string, rc int) { + if msg != "" { + fmt.Fprintf(os.Stderr, "* error: %s\n", msg) + } + + printUsage(os.Stderr) + + os.Exit(rc) +} + +func main() { + if len(os.Args) < 2 { + usageErr("", 1) + } + + cmd, err := buildCmd(os.Args[1:]) + if err != nil { + usageErr(err.Error(), 1) + } + + err = configEnv() + if err != nil { + usageErr(err.Error(), 1) + } + + err = execCmd(cmd) + if err != nil { + usageErr(err.Error(), 1) + } +}