119 lines
2.5 KiB
Go
119 lines
2.5 KiB
Go
package runner
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type logsWriter struct {
|
|
lock *sync.Mutex
|
|
logs *Logs
|
|
outfd int // 0(manual message) 1(stdout) or 2(stderr)
|
|
}
|
|
|
|
func (l *logsWriter) Write(data []byte) (written int, err error) {
|
|
datalen := len(data)
|
|
written = datalen
|
|
|
|
l.lock.Lock()
|
|
defer l.lock.Unlock()
|
|
|
|
for data[datalen-1] == byte('\n') {
|
|
datalen--
|
|
}
|
|
data = data[:datalen]
|
|
|
|
*l.logs = append(*l.logs, LogEntry{
|
|
Time: time.Now(),
|
|
Text: string(data),
|
|
OutFd: l.outfd,
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
// Run runs the profile on the target directory, preserving output.
|
|
func (p *Profile) Run(dir string, outfile string) (logs Logs, exitcode int, err error) {
|
|
|
|
// Try if the directory exists
|
|
_, err = os.ReadDir(dir)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Construct the env slice
|
|
env := make([]string, len(p.Environ))
|
|
{
|
|
i := 0
|
|
for key, val := range p.Environ {
|
|
env[i] = key + "=" + val
|
|
i++
|
|
}
|
|
}
|
|
|
|
loglock := &sync.Mutex{}
|
|
logman := &logsWriter{logs: &logs, lock: loglock, outfd: 0}
|
|
logout := &logsWriter{logs: &logs, lock: loglock, outfd: 1}
|
|
logerr := &logsWriter{logs: &logs, lock: loglock, outfd: 2}
|
|
|
|
var systime, usrtime time.Duration
|
|
|
|
fmt.Fprintf(logman, "building %s", p.Name)
|
|
|
|
// Run commands
|
|
runcmds:
|
|
for i, str := range p.Commands {
|
|
|
|
fmt.Fprintf(logman, "[%d/%d] running \"%s\"", i, len(p.Commands), str)
|
|
|
|
cmd := exec.Command("sh", "-c", "exec "+str)
|
|
cmd.Env = append(cmd.Env, env...)
|
|
cmd.Stdout = logout
|
|
cmd.Stderr = logerr
|
|
cmd.Dir = dir
|
|
|
|
err := cmd.Run()
|
|
|
|
systime += cmd.ProcessState.SystemTime()
|
|
usrtime += cmd.ProcessState.UserTime()
|
|
|
|
switch err.(type) {
|
|
case *exec.ExitError:
|
|
fmt.Fprintf(logman, "!!!!! command exit with code %d: %s", err.(*exec.ExitError).ExitCode(), err.Error())
|
|
break runcmds
|
|
}
|
|
}
|
|
|
|
fmt.Fprintf(logman, "system %.4f, user %.4f", systime.Seconds(), usrtime.Seconds())
|
|
|
|
// package the files
|
|
|
|
writer, err := os.OpenFile(outfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
defer writer.Close()
|
|
if err != nil {
|
|
fmt.Fprintf(logman, "!!!!! error opening output pack: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
packstr := "zip -r - " + strings.Join(p.Output, " ")
|
|
fmt.Fprintf(logman, "[fin] packing output: \"%s\"", packstr)
|
|
|
|
packcmd := exec.Command("sh", "-c", "exec "+packstr)
|
|
packcmd.Dir = p.OutputDir
|
|
packcmd.Stdout = writer
|
|
packcmd.Stderr = logerr
|
|
err = packcmd.Run()
|
|
if err != nil {
|
|
fmt.Fprintf(logman, "!!!!! pack subprocess return %d: %s", packcmd.ProcessState.ExitCode(), err.Error())
|
|
return
|
|
}
|
|
|
|
fmt.Fprintf(logman, "output is at %s", outfile)
|
|
|
|
return
|
|
}
|