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) getProblemScript(version uint, lang string) (string, e.Status) { config, err := s.ParseConfig(version, true) if err != nil { return "", e.RunnerProblemParseFailed } var script string for _, l := range config.Languages { if l.Lang == lang { if l.Type == "default" { script = "/woj/framework/template/default/" + lang + ".Makefile" } else { script = "/woj/problem/judge/" + l.Script } break } } if script == "" { return "", e.RunnerProblemParseFailed } return script, e.Success } 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 } // 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)) boxSourceFile := filepath.Join("/woj/problem/user", fmt.Sprintf("%s.%s", user, lang)) targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", user)) boxTargetFile := filepath.Join("/woj/problem/user", fmt.Sprintf("%s.out", user)) logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", user)) log, err := os.Create(logFile) if err != nil { return JudgeStatus{Message: "create log file failed"}, e.RunnerUserCompileFailed } defer func(log *os.File) { _ = log.Close() }(log) // 3. compile err = utils.NewMust(). Do(func() error { _ = os.Remove(targetFile) return nil }). Do(func() error { return file.TouchErr(targetFile) }). Do(func() error { script, err := s.getProblemScript(version, lang) if err != e.Success { return err.AsError() } args := []string{ "-v", judgeDir + ":/woj/problem/judge:ro", "-v", sourceFile + ":" + boxSourceFile + ":ro", "-v", targetFile + ":" + boxTargetFile, "-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/problem/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 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 }