Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "exec" |
Andrew Gerrand | b3601a5 | 2010-10-21 15:33:31 +1100 | [diff] [blame] | 6 | "io" |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 7 | "os" |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 8 | "strings" |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 9 | ) |
| 10 | |
| 11 | // run is a simple wrapper for exec.Run/Close |
| 12 | func run(envv []string, dir string, argv ...string) os.Error { |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 13 | bin, err := pathLookup(argv[0]) |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 14 | if err != nil { |
| 15 | return err |
| 16 | } |
| 17 | p, err := exec.Run(bin, argv, envv, dir, |
| 18 | exec.DevNull, exec.DevNull, exec.PassThrough) |
| 19 | if err != nil { |
| 20 | return err |
| 21 | } |
| 22 | return p.Close() |
| 23 | } |
| 24 | |
Andrew Gerrand | b3601a5 | 2010-10-21 15:33:31 +1100 | [diff] [blame] | 25 | // runLog runs a process and returns the combined stdout/stderr, |
| 26 | // as well as writing it to logfile (if specified). |
| 27 | func runLog(envv []string, logfile, dir string, argv ...string) (output string, exitStatus int, err os.Error) { |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 28 | bin, err := pathLookup(argv[0]) |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 29 | if err != nil { |
| 30 | return |
| 31 | } |
| 32 | p, err := exec.Run(bin, argv, envv, dir, |
| 33 | exec.DevNull, exec.Pipe, exec.MergeWithStdout) |
| 34 | if err != nil { |
| 35 | return |
| 36 | } |
| 37 | defer p.Close() |
| 38 | b := new(bytes.Buffer) |
Andrew Gerrand | b3601a5 | 2010-10-21 15:33:31 +1100 | [diff] [blame] | 39 | var w io.Writer = b |
| 40 | if logfile != "" { |
| 41 | f, err := os.Open(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) |
| 42 | if err != nil { |
| 43 | return |
| 44 | } |
| 45 | defer f.Close() |
| 46 | w = io.MultiWriter(f, b) |
| 47 | } |
| 48 | _, err = io.Copy(w, p.Stdout) |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 49 | if err != nil { |
| 50 | return |
| 51 | } |
Andrew Gerrand | b3601a5 | 2010-10-21 15:33:31 +1100 | [diff] [blame] | 52 | wait, err := p.Wait(0) |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 53 | if err != nil { |
| 54 | return |
| 55 | } |
Andrew Gerrand | b3601a5 | 2010-10-21 15:33:31 +1100 | [diff] [blame] | 56 | return b.String(), wait.WaitStatus.ExitStatus(), nil |
Andrew Gerrand | 3e8cc7f | 2010-09-13 10:46:17 +1000 | [diff] [blame] | 57 | } |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 58 | |
| 59 | // Find bin in PATH if a relative or absolute path hasn't been specified |
| 60 | func pathLookup(s string) (string, os.Error) { |
Robert Griesemer | 3478891 | 2010-10-22 10:06:33 -0700 | [diff] [blame] | 61 | if strings.HasPrefix(s, "/") || strings.HasPrefix(s, "./") || strings.HasPrefix(s, "../") { |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 62 | return s, nil |
Robert Griesemer | 3478891 | 2010-10-22 10:06:33 -0700 | [diff] [blame] | 63 | } |
Andrew Gerrand | 96d6f9d | 2010-09-22 15:18:41 +1000 | [diff] [blame] | 64 | return exec.LookPath(s) |
| 65 | } |