feat: #6 [6] Rewrite compile
This commit is contained in:
parent
7f0f897181
commit
8dee13af85
@ -1,5 +1,7 @@
|
||||
package e
|
||||
|
||||
import "errors"
|
||||
|
||||
type Status int
|
||||
|
||||
func (code Status) String() string {
|
||||
@ -9,3 +11,7 @@ func (code Status) String() string {
|
||||
}
|
||||
return msgText[InternalError]
|
||||
}
|
||||
|
||||
func (code Status) AsError() error {
|
||||
return errors.New(code.String())
|
||||
}
|
||||
|
@ -55,6 +55,20 @@ func (s *service) checkAndExecute(version uint, user string, lang string, script
|
||||
return e.Success
|
||||
}
|
||||
|
||||
func (s *service) check(version uint, user string, lang string) e.Status {
|
||||
if !s.ProblemExists(version) {
|
||||
s.log.Info("problem not exists", zap.Uint("version", version))
|
||||
return e.RunnerProblemNotExist
|
||||
}
|
||||
|
||||
if !s.userExists(user, fmt.Sprintf("%s.%s", user, lang)) {
|
||||
s.log.Info("user program not exists", zap.String("user", user), zap.String("lang", lang))
|
||||
return e.RunnerUserNotExist
|
||||
}
|
||||
|
||||
return e.Success
|
||||
}
|
||||
|
||||
func (s *service) ProblemExists(version uint) bool {
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", version))
|
||||
return file.Exist(problemPath)
|
||||
|
@ -5,18 +5,112 @@ import (
|
||||
"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) {
|
||||
target := filepath.Join(UserDir, user, fmt.Sprintf("%s.out", user))
|
||||
// 1. ensure problem/user exists
|
||||
status := s.check(version, user, lang)
|
||||
if status != e.Success {
|
||||
return JudgeStatus{Message: "check failed"}, status
|
||||
}
|
||||
|
||||
_ = os.Remove(target)
|
||||
status := s.checkAndExecute(version, user, lang, "problem_compile.sh", e.RunnerUserCompileFailed)
|
||||
// 2. prepare judge environment
|
||||
workDir := filepath.Join(UserDir, user)
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "judge")
|
||||
|
||||
log := filepath.Join(UserDir, user, fmt.Sprintf("%s.compile.log", user))
|
||||
msg, err := file.FileRead(log)
|
||||
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)
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
|
||||
. "$WORKSPACE"/scripts/common.sh
|
||||
. "$WORKSPACE"/scripts/docker_run.sh
|
||||
. "$WORKSPACE"/scripts/problem.sh
|
||||
|
||||
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then
|
||||
log_warn "Usage: $0 <problem> <user_dir> <language> <timeout>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
get_problem_info "$WORKSPACE" "$1" "$3"
|
||||
|
||||
SRC_FILE="$WORKSPACE"/user/"$2"/"$2"."$3"
|
||||
EXE_FILE="$WORKSPACE"/user/"$2"/"$2".out
|
||||
export LOG_FILE="$WORKSPACE"/user/"$2"/"$2".compile.log
|
||||
|
||||
rm -f "$EXE_FILE" && touch "$EXE_FILE"
|
||||
|
||||
export TIMEOUT=${4:-60}
|
||||
docker_run \
|
||||
-v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \
|
||||
-v "$SRC_FILE":/woj/problem/user/"$2"."$3":ro \
|
||||
-v "$EXE_FILE":/woj/problem/user/"$2".out \
|
||||
-e USER_PROG="$2" \
|
||||
-e LANG="$3" \
|
||||
git.0x7f.app/woj/ubuntu-full \
|
||||
sh -c \
|
||||
"cd /woj/problem/user && make -f $Info_Script compile"
|
Loading…
Reference in New Issue
Block a user