package runner import ( "context" "errors" "fmt" "git.0x7f.app/WOJ/woj-server/pkg/file" "git.0x7f.app/WOJ/woj-server/pkg/utils" "os" "os/exec" "time" ) func (s *service) execute(exe string, args ...string) error { cmd := exec.Command(exe, args...) cmd.Dir = Prefix if s.verbose { cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr } return cmd.Run() } type executeArgs struct { exe string args []string timeout time.Duration kill func() error output *os.File limit int64 } func (s *service) executeTimeout(arg *executeArgs) error { ctx, cancel := context.WithTimeout(context.Background(), arg.timeout) defer cancel() cmd := exec.CommandContext(ctx, arg.exe, arg.args...) cmd.Dir = Prefix if arg.kill != nil { cmd.Cancel = arg.kill } if s.verbose && arg.output == nil { cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr } else if arg.output != nil { if arg.limit == 0 { cmd.Stdout = arg.output cmd.Stderr = arg.output } else { lw := &file.LimitedWriter{ File: arg.output, Limit: arg.limit, } cmd.Stdout = lw cmd.Stderr = lw } } err := cmd.Start() if err != nil { return err } err = cmd.Wait() // make sure the process is killed _ = cmd.Process.Kill() if errors.Is(ctx.Err(), context.DeadlineExceeded) { return fmt.Errorf("command timed out") } return err } type podmanArgs struct { executeArgs memory string } func (s *service) podmanRun(arg *podmanArgs) error { name := fmt.Sprintf("woj-%d-%s", time.Now().UnixNano(), utils.RandomString(8)) execArgs := &executeArgs{ exe: "podman", output: utils.If(arg.output == nil, os.Stderr, arg.output), limit: utils.If(arg.limit == 0, 4*1024, arg.limit), timeout: utils.If(arg.timeout == 0, 10*time.Second, arg.timeout), kill: func() error { if arg.kill != nil { _ = arg.kill() } return s.execute("podman", "kill", name) }, } args := []string{ "run", "--rm", "--name", name, "--memory", utils.If(arg.memory == "", "256m", arg.memory), } args = append(args, arg.args...) execArgs.args = args return s.executeTimeout(execArgs) }