| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| // 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.3" |
| |
| // 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", "--device=/dev/bus/usb", "--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) |
| } |
| } |