110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package runner
|
|
|
|
import (
|
|
"fmt"
|
|
"git.0x7f.app/WOJ/woj-server/internal/e"
|
|
"git.0x7f.app/WOJ/woj-server/pkg/file"
|
|
"git.0x7f.app/WOJ/woj-server/pkg/utils"
|
|
"go.uber.org/zap"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
func (s *service) Compile(version uint, user string, lang string) (JudgeStatus, e.Status) {
|
|
// 1. ensure problem/user exists
|
|
status := s.check(version, user, lang)
|
|
if status != e.Success {
|
|
return JudgeStatus{Message: "check failed"}, status
|
|
}
|
|
|
|
config, err := s.ParseConfig(version, true)
|
|
if err != nil {
|
|
s.log.Error("[compile] parse config failed", zap.Error(err))
|
|
return JudgeStatus{
|
|
Message: "parse config failed",
|
|
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "parse config failed"}},
|
|
}, e.RunnerProblemParseFailed
|
|
}
|
|
|
|
// 2. prepare judge environment
|
|
workDir := filepath.Join(UserDir, user)
|
|
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "judge")
|
|
|
|
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", user, lang))
|
|
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", user))
|
|
|
|
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", user))
|
|
log, err := os.Create(logFile)
|
|
if err != nil {
|
|
s.log.Error("[compile] create log file failed", zap.Error(err))
|
|
return JudgeStatus{
|
|
Message: "create log file failed",
|
|
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "create log file failed"}},
|
|
}, e.RunnerUserCompileFailed
|
|
}
|
|
defer func(log *os.File) {
|
|
_ = log.Close()
|
|
}(log)
|
|
|
|
// 3. compile
|
|
err = utils.NewMust().
|
|
DoAny(func() error { return os.Remove(targetFile) }).
|
|
Do(func() error { return file.TouchErr(targetFile) }).
|
|
Do(func() error {
|
|
l, ok := s.getLangInfo(&config, lang)
|
|
script := s.getLangScript(&l, lang)
|
|
if !ok {
|
|
return e.RunnerProblemParseFailed.AsError()
|
|
}
|
|
|
|
args := []string{
|
|
"-v", fmt.Sprintf("%s:/woj/problem/judge:ro", judgeDir),
|
|
"-v", fmt.Sprintf("%s:/woj/user/%s.%s:ro", sourceFile, user, lang),
|
|
"-v", fmt.Sprintf("%s:/woj/user/%s.out", targetFile, user),
|
|
"-e", fmt.Sprintf("USER_PROG=%s", user),
|
|
"-e", fmt.Sprintf("LANG=%s", lang),
|
|
"git.0x7f.app/woj/ubuntu-full:latest",
|
|
"sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script),
|
|
}
|
|
|
|
runArgs := &podmanArgs{
|
|
executeArgs: executeArgs{
|
|
args: args,
|
|
timeout: 60 * time.Second,
|
|
output: log,
|
|
},
|
|
memory: "256m",
|
|
}
|
|
|
|
return s.podmanRun(runArgs)
|
|
}).
|
|
Done()
|
|
|
|
if err != nil {
|
|
s.log.Info("[compile] compile failed",
|
|
zap.Error(err),
|
|
zap.Uint("version", version),
|
|
zap.String("user", user),
|
|
zap.String("lang", lang),
|
|
)
|
|
status = e.RunnerUserCompileFailed
|
|
}
|
|
|
|
// 4. read log
|
|
_, _ = log.Seek(0, io.SeekStart)
|
|
msg, err := io.ReadAll(log)
|
|
msg = utils.If(err == nil, msg, nil)
|
|
msgText := string(msg)
|
|
|
|
if !file.Exist(targetFile) || file.Empty(targetFile) {
|
|
return JudgeStatus{
|
|
Message: "compile failed",
|
|
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
|
utils.If(status == e.Success, e.RunnerUserCompileFailed, status)
|
|
}
|
|
|
|
return JudgeStatus{}, e.Success
|
|
}
|