woj-server/internal/service/runner/compile.go

119 lines
3.5 KiB
Go
Raw Normal View History

package runner
import (
"fmt"
2023-07-14 21:47:11 +08:00
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/pkg/file"
2023-07-14 21:47:11 +08:00
"git.0x7f.app/WOJ/woj-server/pkg/utils"
2024-01-06 17:32:05 +08:00
"go.uber.org/zap"
"io"
"os"
"path/filepath"
2024-01-06 17:32:05 +08:00
"time"
)
func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
// 0. maybe we can skip compile
if v, ok := AllowedLanguages[meta.Cfg.Lang.Lang]; !ok || v.Interpreter != "" {
return &JudgeStatus{}, e.Success
}
// 1. prepare judge environment
workDir := filepath.Join(UserDir, meta.Run.User)
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang))
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.Run.User))
2024-01-06 17:32:05 +08:00
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", meta.Run.User))
2024-01-06 17:32:05 +08:00
log, err := os.Create(logFile)
if err != nil {
2024-01-06 19:47:16 +08:00
s.log.Error("[compile] create log file failed", zap.Error(err))
return &JudgeStatus{
Message: "System Error: Unable to create log file",
CompileMessage: "",
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "System Error"}},
2024-01-06 19:47:16 +08:00
}, e.RunnerUserCompileFailed
2024-01-06 17:32:05 +08:00
}
defer func(log *os.File) {
_ = log.Close()
}(log)
// 2. compile
2024-01-06 17:32:05 +08:00
err = utils.NewMust().
2024-01-06 19:21:37 +08:00
DoAny(func() error { return os.Remove(targetFile) }).
2024-01-06 17:32:05 +08:00
Do(func() error { return file.TouchErr(targetFile) }).
Do(func() error {
script := meta.Cfg.Lang.JudgeScript()
2024-01-06 17:32:05 +08:00
2024-01-27 17:37:27 +08:00
args := &RunArgs{
Program: ProgramArgs{
2024-03-13 22:38:52 +08:00
Args: []string{"/bin/sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script)},
Env: []string{fmt.Sprintf("USER_PROG=%s", meta.Run.User), fmt.Sprintf("LANG=%s", meta.Run.Lang)},
2024-01-27 17:37:27 +08:00
},
Runtime: RuntimeArgs{
2024-03-13 20:03:12 +08:00
Rootfs: RootfsFullDir,
2024-04-27 22:02:14 +08:00
Pid: int64(utils.If(meta.Cfg.Lang.Runtime.Compile.NProcLimit == 0, 0, meta.Cfg.Lang.Runtime.Compile.NProcLimit+2)), // bash + make
Memory: uint64(meta.Cfg.Lang.Runtime.Compile.MemoryLimit * 1024 * 1024),
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second,
2024-01-27 17:37:27 +08:00
},
IO: IOArgs{
Output: log,
Limit: 4 * 1024, // 4 KB
},
2024-01-06 17:32:05 +08:00
}
2024-03-13 20:03:12 +08:00
args.Runtime.Mount = []MountInfo{
2024-01-27 17:37:27 +08:00
{
Source: judgeDir,
Destination: "/woj/problem/judge",
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
2024-03-14 01:18:57 +08:00
{
// Rust will write intermediate files into source directory instead of /tmp
Source: "",
Destination: "/woj/user",
},
2024-01-27 17:37:27 +08:00
{
Source: sourceFile,
Destination: fmt.Sprintf("/woj/user/%s.%s", meta.Run.User, meta.Run.Lang),
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: targetFile,
Destination: fmt.Sprintf("/woj/user/%s.out", meta.Run.User),
2024-03-13 20:03:12 +08:00
Readonly: false,
2024-01-06 17:32:05 +08:00
},
}
2024-03-13 20:03:12 +08:00
id := s.JailRunPool(args)
ret := s.pool.WaitForTask(id)
return ret.Error
2024-01-06 17:32:05 +08:00
}).
Done()
status := e.Success
2024-01-06 17:32:05 +08:00
if err != nil {
s.log.Info("[compile] compile failed", zap.Error(err), zap.Any("meta", *meta))
2024-01-06 17:32:05 +08:00
status = e.RunnerUserCompileFailed
}
2024-01-06 17:32:05 +08:00
// 4. read log
_, _ = log.Seek(0, io.SeekStart)
msg, err := io.ReadAll(log)
2022-10-30 22:40:59 +08:00
msg = utils.If(err == nil, msg, nil)
msgText := string(msg)
if status != e.Success || !file.Exist(targetFile) || file.Empty(targetFile) {
return &JudgeStatus{
Message: "Compile Failed",
CompileMessage: msgText,
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
2022-10-30 22:40:59 +08:00
utils.If(status == e.Success, e.RunnerUserCompileFailed, status)
}
// 5. grant permission
_ = os.Chmod(targetFile, 0755)
return &JudgeStatus{CompileMessage: msgText}, status
}