pbuild/internal/runner/run.go
2023-08-15 21:42:18 +08:00

106 lines
2.3 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) (len int, err error) {
l.lock.Lock()
defer l.lock.Unlock()
*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
// 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", 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", 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
}
return
}