feat: #6 [7] Rewrite run_judge
This commit is contained in:
parent
8dee13af85
commit
bb105d1451
@ -56,14 +56,8 @@ func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
||||
return e.Success, 0, compileResult
|
||||
}
|
||||
|
||||
// 4. config
|
||||
config, err := h.runnerService.ParseConfig(p.ProblemVersionID, true)
|
||||
if err != nil {
|
||||
return e.InternalError, 0, systemError
|
||||
}
|
||||
|
||||
// 5. run and judge
|
||||
result, point, status := h.runnerService.RunAndJudge(p.ProblemVersionID, user, p.Submission.Language, &config)
|
||||
// 4. run and judge
|
||||
result, point, status := h.runnerService.RunAndJudge(p.ProblemVersionID, user, p.Submission.Language)
|
||||
return utils.If(status != e.Success, e.InternalError, e.Success), point, result
|
||||
}()
|
||||
|
||||
|
@ -30,31 +30,6 @@ func init() {
|
||||
TmpDir = path.Join(Prefix, TmpDir)
|
||||
}
|
||||
|
||||
func (s *service) checkAndExecute(version uint, user string, lang string, script string, fail e.Status) 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
|
||||
}
|
||||
|
||||
err := s.execute(script, fmt.Sprintf("%d", version), user, lang)
|
||||
|
||||
if err != nil {
|
||||
s.log.Info("execute failed",
|
||||
zap.Error(err),
|
||||
zap.Uint("version", version),
|
||||
zap.String("user", user),
|
||||
zap.String("lang", lang))
|
||||
return fail
|
||||
}
|
||||
|
||||
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))
|
||||
@ -78,3 +53,20 @@ func (s *service) userExists(user string, name string) bool {
|
||||
userPath := filepath.Join(UserDir, user, name)
|
||||
return file.Exist(userPath)
|
||||
}
|
||||
|
||||
func (s *service) getLangInfo(config *Config, lang string) (configLanguage, bool) {
|
||||
for _, l := range config.Languages {
|
||||
if l.Lang == lang {
|
||||
return l, true
|
||||
}
|
||||
}
|
||||
return configLanguage{}, false
|
||||
}
|
||||
|
||||
func (s *service) getLangScript(l *configLanguage, lang string) string {
|
||||
if l.Type == "default" {
|
||||
return "/woj/framework/template/default/" + lang + ".Makefile"
|
||||
} else {
|
||||
return "/woj/problem/judge/" + l.Script
|
||||
}
|
||||
}
|
||||
|
@ -12,30 +12,6 @@ import (
|
||||
"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)
|
||||
@ -43,15 +19,17 @@ func (s *service) Compile(version uint, user string, lang string) (JudgeStatus,
|
||||
return JudgeStatus{Message: "check failed"}, status
|
||||
}
|
||||
|
||||
config, err := s.ParseConfig(version, true)
|
||||
if err != nil {
|
||||
return JudgeStatus{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))
|
||||
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)
|
||||
@ -64,25 +42,23 @@ func (s *service) Compile(version uint, user string, lang string) (JudgeStatus,
|
||||
|
||||
// 3. compile
|
||||
err = utils.NewMust().
|
||||
Do(func() error {
|
||||
_ = os.Remove(targetFile)
|
||||
return nil
|
||||
}).
|
||||
DoAny(func() error { return os.Remove(targetFile) }).
|
||||
Do(func() error { return file.TouchErr(targetFile) }).
|
||||
Do(func() error {
|
||||
script, err := s.getProblemScript(version, lang)
|
||||
if err != e.Success {
|
||||
return err.AsError()
|
||||
l, ok := s.getLangInfo(&config, lang)
|
||||
script := s.getLangScript(&l, lang)
|
||||
if !ok {
|
||||
return e.RunnerProblemParseFailed.AsError()
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-v", judgeDir + ":/woj/problem/judge:ro",
|
||||
"-v", sourceFile + ":" + boxSourceFile + ":ro",
|
||||
"-v", targetFile + ":" + boxTargetFile,
|
||||
"-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/problem/user && make -f %s compile", script),
|
||||
"sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script),
|
||||
}
|
||||
|
||||
runArgs := &podmanArgs{
|
||||
|
@ -8,18 +8,20 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type configLanguage struct {
|
||||
Lang string `json:"Lang"`
|
||||
Type string `json:"Type,omitempty"`
|
||||
Script string `json:"Script,omitempty"`
|
||||
Cmp string `json:"Cmp,omitempty"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Runtime struct {
|
||||
TimeLimit int `json:"TimeLimit"`
|
||||
MemoryLimit int `json:"MemoryLimit"`
|
||||
NProcLimit int `json:"NProcLimit"`
|
||||
} `json:"Runtime"`
|
||||
Languages []struct {
|
||||
Lang string `json:"Lang"`
|
||||
Type string `json:"Type,omitempty"`
|
||||
Script string `json:"Script,omitempty"`
|
||||
Cmp string `json:"Cmp,omitempty"`
|
||||
} `json:"Languages"`
|
||||
Languages []configLanguage `json:"Languages"`
|
||||
Tasks []struct {
|
||||
Id int `json:"Id"`
|
||||
Points int32 `json:"Points"`
|
||||
|
@ -53,8 +53,8 @@ func (s *service) prebuild(version uint, force bool) e.Status {
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "judge")
|
||||
|
||||
args := []string{
|
||||
"-v", dataDir + ":/woj/problem/data",
|
||||
"-v", judgeDir + ":/woj/problem/judge",
|
||||
"-v", fmt.Sprintf("%s:/woj/problem/data", dataDir),
|
||||
"-v", fmt.Sprintf("%s:/woj/problem/judge", judgeDir),
|
||||
"-e", "PREFIX=/woj/problem",
|
||||
"git.0x7f.app/woj/ubuntu-full:latest",
|
||||
"sh", "-c", "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild",
|
||||
|
@ -1,22 +0,0 @@
|
||||
package runner
|
||||
|
||||
import "git.0x7f.app/WOJ/woj-server/internal/e"
|
||||
|
||||
func (s *service) RunAndJudge(version uint, user string, lang string, config *Config) (JudgeStatus, int32, e.Status) {
|
||||
// run user program
|
||||
status := s.checkAndExecute(version, user, lang, "problem_run.sh", e.RunnerRunFailed)
|
||||
if status != e.Success {
|
||||
return JudgeStatus{Message: "run failed"}, 0, status
|
||||
}
|
||||
|
||||
// run judger
|
||||
status = s.checkAndExecute(version, user, lang, "problem_judge.sh", e.RunnerJudgeFailed)
|
||||
if status != e.Success {
|
||||
return JudgeStatus{Message: "judge failed"}, 0, status
|
||||
}
|
||||
|
||||
// check result
|
||||
result, pts := s.checkResults(user, config)
|
||||
|
||||
return result, pts, e.Success
|
||||
}
|
183
internal/service/runner/run_judge.go
Normal file
183
internal/service/runner/run_judge.go
Normal file
@ -0,0 +1,183 @@
|
||||
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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *service) problemRun(version uint, user string, lang string, config *Config) {
|
||||
workDir := filepath.Join(UserDir, user)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "data", "input")
|
||||
|
||||
// woj-sandbox killer will add 2 more seconds, here we add 2 more seconds
|
||||
timeout := time.Duration((config.Runtime.TimeLimit+1000)/1000+2+2) * time.Second
|
||||
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
f := func(id int) func() {
|
||||
return func() {
|
||||
testCase := filepath.Join(dataDir, fmt.Sprintf("%d.input", id))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", user))
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
ifoFile := filepath.Join(workDir, fmt.Sprintf("%d.info", id))
|
||||
|
||||
err := utils.NewMust().
|
||||
DoAny(func() error { return os.Remove(ansFile) }).
|
||||
DoAny(func() error { return os.Remove(ifoFile) }).
|
||||
Do(func() error { return file.TouchErr(ansFile) }).
|
||||
Do(func() error { return file.TouchErr(ifoFile) }).
|
||||
Do(func() error {
|
||||
args := []string{
|
||||
"--cpus", "1",
|
||||
"--network", "none",
|
||||
"-v", fmt.Sprintf("%s:/woj/problem/data/input/%d.input:ro", testCase, id),
|
||||
"-v", fmt.Sprintf("%s:/woj/user/%s.out:ro", targetFile, user),
|
||||
"-v", fmt.Sprintf("%s:/woj/user/%d.out.usr", ansFile, id),
|
||||
"-v", fmt.Sprintf("%s:/woj/user/%d.info", ifoFile, id),
|
||||
"git.0x7f.app/woj/ubuntu-run:latest",
|
||||
"sh", "-c",
|
||||
fmt.Sprintf("cd /woj/user && /woj/framework/scripts/woj_launcher "+
|
||||
"--memory_limit=%d "+
|
||||
"--nproc_limit=%d "+
|
||||
"--time_limit=%d "+
|
||||
"--sandbox_template=%s "+
|
||||
"--sandbox_action=ret "+
|
||||
"--uid=1000 "+
|
||||
"--gid=1000 "+
|
||||
"--file_input=/woj/problem/data/input/%d.input "+
|
||||
"--file_output=/woj/user/%d.out.usr "+
|
||||
"--file_info=/woj/user/%d.info "+
|
||||
"-program=/woj/user/%s.out",
|
||||
config.Runtime.MemoryLimit,
|
||||
config.Runtime.NProcLimit,
|
||||
config.Runtime.TimeLimit,
|
||||
lang,
|
||||
id, id, id,
|
||||
user,
|
||||
),
|
||||
}
|
||||
|
||||
runArgs := &podmanArgs{
|
||||
executeArgs: executeArgs{
|
||||
args: args,
|
||||
timeout: timeout,
|
||||
},
|
||||
}
|
||||
|
||||
return s.podmanRun(runArgs)
|
||||
}).
|
||||
Done()
|
||||
|
||||
if err != nil {
|
||||
s.log.Info("run failed",
|
||||
zap.Error(err),
|
||||
zap.Uint("version", version),
|
||||
zap.String("user", user),
|
||||
zap.String("lang", lang),
|
||||
)
|
||||
}
|
||||
}
|
||||
}(task.Id)
|
||||
|
||||
id := s.pool.AddTask(f)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
s.pool.WaitForTask(id)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) problemJudge(version uint, user string, lang string, config *Config) {
|
||||
workDir := filepath.Join(UserDir, user)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", version), "judge")
|
||||
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
f := func(id int) func() {
|
||||
return func() {
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
jdgFile := filepath.Join(workDir, fmt.Sprintf("%d.judge", id))
|
||||
|
||||
c, ok := s.getLangInfo(config, lang)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err := utils.NewMust().
|
||||
DoAny(func() error { return os.Remove(jdgFile) }).
|
||||
Do(func() error { return file.TouchErr(jdgFile) }).
|
||||
Do(func() error {
|
||||
args := []string{
|
||||
"-v", fmt.Sprintf("%s:/woj/problem/judge:ro", judgeDir),
|
||||
"-v", fmt.Sprintf("%s:/woj/problem/data:ro", dataDir),
|
||||
"-v", fmt.Sprintf("%s:/woj/user/%d.out.usr", ansFile, id),
|
||||
"-v", fmt.Sprintf("%s:/woj/user/%d.judge", jdgFile, id),
|
||||
"-e", fmt.Sprintf("TEST_NUM=%d", id),
|
||||
"-e", fmt.Sprintf("CMP=%s", c.Cmp),
|
||||
"git.0x7f.app/woj/ubuntu-full:latest",
|
||||
"sh", "-c",
|
||||
fmt.Sprintf("cd /woj/user && make -f %s judge", s.getLangScript(&c, lang)),
|
||||
}
|
||||
|
||||
runArgs := &podmanArgs{
|
||||
executeArgs: executeArgs{
|
||||
args: args,
|
||||
},
|
||||
}
|
||||
|
||||
return s.podmanRun(runArgs)
|
||||
}).
|
||||
Done()
|
||||
|
||||
if err != nil {
|
||||
s.log.Info("judge failed",
|
||||
zap.Error(err),
|
||||
zap.Uint("version", version),
|
||||
zap.String("user", user),
|
||||
zap.String("lang", lang),
|
||||
)
|
||||
}
|
||||
}
|
||||
}(task.Id)
|
||||
|
||||
id := s.pool.AddTask(f)
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
s.pool.WaitForTask(id)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) RunAndJudge(version uint, user string, lang string) (JudgeStatus, int32, e.Status) {
|
||||
// 1. ensure problem/user exists
|
||||
status := s.check(version, user, lang)
|
||||
if status != e.Success {
|
||||
return JudgeStatus{Message: "check failed"}, 0, status
|
||||
}
|
||||
|
||||
// 2. config
|
||||
config, err := s.ParseConfig(version, false)
|
||||
if err != nil {
|
||||
return JudgeStatus{Message: "parse config failed"}, 0, e.RunnerProblemParseFailed
|
||||
}
|
||||
|
||||
// 3. run user program
|
||||
s.problemRun(version, user, lang, &config)
|
||||
|
||||
// 4. run judger
|
||||
s.problemJudge(version, user, lang, &config)
|
||||
|
||||
// 5. check result
|
||||
result, pts := s.checkResults(user, &config)
|
||||
|
||||
return result, pts, e.Success
|
||||
}
|
@ -22,7 +22,7 @@ type Service interface {
|
||||
// Compile compile user submission
|
||||
Compile(version uint, user string, lang string) (JudgeStatus, e.Status)
|
||||
// RunAndJudge execute user program
|
||||
RunAndJudge(version uint, user string, lang string, config *Config) (JudgeStatus, int32, e.Status)
|
||||
RunAndJudge(version uint, user string, lang string) (JudgeStatus, int32, e.Status)
|
||||
|
||||
// ParseConfig parse config file
|
||||
ParseConfig(version uint, skipCheck bool) (Config, error)
|
||||
@ -30,16 +30,20 @@ type Service interface {
|
||||
ProblemExists(version uint) bool
|
||||
|
||||
HealthCheck() error
|
||||
Shutdown() error
|
||||
}
|
||||
|
||||
func NewService(i *do.Injector) (Service, error) {
|
||||
concurrency := utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1)
|
||||
|
||||
return &service{
|
||||
srv := &service{
|
||||
log: do.MustInvoke[log.Service](i).GetLogger("runner"),
|
||||
pool: pool.NewTaskPool(concurrency, concurrency),
|
||||
verbose: do.MustInvoke[config.Service](i).GetConfig().Development,
|
||||
}, nil
|
||||
}
|
||||
srv.pool.Start()
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
type service struct {
|
||||
@ -51,3 +55,8 @@ type service struct {
|
||||
func (s *service) HealthCheck() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Shutdown() error {
|
||||
s.pool.Stop()
|
||||
return nil
|
||||
}
|
||||
|
@ -15,6 +15,11 @@ func (c *MustChain) Do(callback func() error) *MustChain {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *MustChain) DoAny(callback func() error) *MustChain {
|
||||
_ = callback()
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *MustChain) Done() error {
|
||||
return c.err
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_PATH=$(cd "$(dirname "$0")" && pwd)
|
||||
. "$SCRIPT_PATH/common.sh"
|
||||
|
||||
function docker_run() {
|
||||
local timeout=${TIMEOUT:-10}
|
||||
local memory=${MEMORY:-"256m"}
|
||||
local log_file=${LOG_FILE:-"/dev/stderr"}
|
||||
local log_limit=${LOG_LIMIT:-4K}
|
||||
log_info "$DOCKER run with timeout $timeout"
|
||||
CONTAINER_NAME=$(uuidgen)
|
||||
(
|
||||
sleep "$timeout"
|
||||
$DOCKER kill "$CONTAINER_NAME"
|
||||
) &
|
||||
$DOCKER run --rm --name "$CONTAINER_NAME" --memory "$memory" "$@" 2>&1 | head -c "$log_limit" >"$log_file"
|
||||
pkill -P $$
|
||||
$DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1
|
||||
return 0
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_PATH=$(cd "$(dirname "$0")" && pwd)
|
||||
. "$SCRIPT_PATH/common.sh"
|
||||
|
||||
# get_problem_info
|
||||
# extract language info and limits
|
||||
# $1: workspace
|
||||
# $2: problem name
|
||||
# $3: language
|
||||
# exports: Info_Script, Info_Cmp, Info_Num, Info_Limit_Time, Info_Limit_Memory, Info_Limit_NProc
|
||||
function get_problem_info() {
|
||||
local err
|
||||
|
||||
if [ ! -f "$1/problem/$2/config.json" ]; then
|
||||
log_error "problem $2 not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
parse_language_info "$1" "$2" "$3"
|
||||
err=$?
|
||||
if [ "$err" -ne 0 ]; then
|
||||
return "$err"
|
||||
fi
|
||||
|
||||
parse_limits "$1" "$2"
|
||||
err=$?
|
||||
if [ "$err" -ne 0 ]; then
|
||||
return "$err"
|
||||
fi
|
||||
}
|
||||
|
||||
function parse_language_info() {
|
||||
export Info_Script
|
||||
export Info_Cmp
|
||||
|
||||
local lang_config
|
||||
local lang_type
|
||||
local lang_script
|
||||
|
||||
lang_config=$(jq ".Languages[] | select(.Lang == \"$3\")" "$1/problem/$2/config.json")
|
||||
if [ -z "$lang_config" ]; then
|
||||
log_error "language $3 is not supported"
|
||||
return 1
|
||||
fi
|
||||
|
||||
Info_Cmp=$(echo "$lang_config" | jq -r ".Cmp")
|
||||
|
||||
lang_type=$(echo "$lang_config" | jq -r ".Type")
|
||||
lang_script=$(echo "$lang_config" | jq -r ".Script")
|
||||
|
||||
if [ "$lang_type" == "custom" ]; then
|
||||
Info_Script="/woj/problem/judge/$lang_script"
|
||||
elif [ "$lang_type" == "default" ]; then
|
||||
Info_Script="/woj/framework/template/default/$3.Makefile"
|
||||
else
|
||||
log_warn "Config file might be corrupted!"
|
||||
log_error "Unknown language type: $lang_type"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function parse_limits() {
|
||||
export Info_Limit_Time
|
||||
export Info_Limit_Memory
|
||||
export Info_Limit_NProc
|
||||
export Info_Num
|
||||
|
||||
local cfg
|
||||
cfg="$1/problem/$2/config.json"
|
||||
|
||||
Info_Limit_Time=$(jq ".Runtime.TimeLimit" "$cfg")
|
||||
Info_Limit_Memory=$(jq ".Runtime.MemoryLimit" "$cfg")
|
||||
Info_Limit_NProc=$(jq ".Runtime.NProcLimit" "$cfg")
|
||||
Info_Num=$(jq ".Tasks | length" "$1/problem/$2/config.json")
|
||||
}
|
@ -1,40 +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"
|
||||
|
||||
export TIMEOUT=${4:-60}
|
||||
for test_num in $(seq "$Info_Num"); do
|
||||
std_file="$WORKSPACE/problem/$1/data/output/$test_num.output"
|
||||
ans_file="$WORKSPACE/user/$2/$test_num.out.usr"
|
||||
jdg_file="$WORKSPACE/user/$2/$test_num.judge"
|
||||
|
||||
if [ ! -f "$std_file" ] || [ ! -f "$ans_file" ]; then
|
||||
log_error "Missing test case $test_num"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Judging test case $test_num"
|
||||
|
||||
touch "$jdg_file"
|
||||
|
||||
docker_run \
|
||||
-v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \
|
||||
-v "$WORKSPACE"/problem/"$1"/data:/woj/problem/data:ro \
|
||||
-v "$ans_file":/woj/problem/user/"$test_num".out.usr \
|
||||
-v "$jdg_file":/woj/problem/user/"$test_num".judge \
|
||||
-e TEST_NUM="$test_num" \
|
||||
-e CMP="$Info_Cmp" \
|
||||
git.0x7f.app/woj/ubuntu-full \
|
||||
sh -c \
|
||||
"cd /woj/problem/user && make -f $Info_Script judge"
|
||||
done
|
@ -1,72 +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>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then
|
||||
log_warn "Problem $1 has not been prebuilt"
|
||||
log_warn "Please run 'problem_prebuild.sh $1' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$WORKSPACE/user/$2/$2.out" ]; then
|
||||
log_warn "User $2 has not been compiled"
|
||||
log_warn "Please run 'problem_compile.sh ...' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
parse_limits "$WORKSPACE" "$1"
|
||||
|
||||
log_info "Running problem $1 for user $2"
|
||||
log_info "TimeLimit: $Info_Limit_Time"
|
||||
log_info "MemoryLimit: $Info_Limit_Memory"
|
||||
log_info "NProcLimit: $Info_Limit_NProc"
|
||||
|
||||
# launcher will add 2 more seconds
|
||||
# here add 3 more seconds
|
||||
TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 4))
|
||||
log_info "Timeout: $TIMEOUT"
|
||||
|
||||
for test_num in $(seq "$Info_Num"); do
|
||||
test_case="$WORKSPACE/problem/$1/data/input/$test_num.input"
|
||||
exe_file="$WORKSPACE/user/$2/$2.out"
|
||||
ans_file="$WORKSPACE/user/$2/$test_num.out.usr"
|
||||
ifo_file="$WORKSPACE/user/$2/$test_num.info"
|
||||
|
||||
if [ ! -f "$test_case" ]; then
|
||||
log_error "Test case $test_num does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Running test case $test_num"
|
||||
rm -f "$ans_file" && touch "$ans_file"
|
||||
rm -f "$ifo_file" && touch "$ifo_file"
|
||||
docker_run \
|
||||
--cpus 1 \
|
||||
--network none \
|
||||
-v "$test_case":/woj/problem/data/input/"$test_num".input:ro \
|
||||
-v "$exe_file":/woj/user/"$2".out:ro \
|
||||
-v "$ans_file":/woj/user/"$test_num".out.usr \
|
||||
-v "$ifo_file":/woj/user/"$test_num".info \
|
||||
git.0x7f.app/woj/ubuntu-run \
|
||||
sh -c \
|
||||
"cd /woj/user && /woj/framework/scripts/woj_launcher \
|
||||
--memory_limit=$Info_Limit_Memory \
|
||||
--nproc_limit=$Info_Limit_NProc \
|
||||
--time_limit=$Info_Limit_Time \
|
||||
--sandbox_template=$3 \
|
||||
--sandbox_action=ret \
|
||||
--uid=1000 \
|
||||
--gid=1000 \
|
||||
--file_input=/woj/problem/data/input/$test_num.input \
|
||||
--file_output=/woj/user/$test_num.out.usr \
|
||||
--file_info=/woj/user/$test_num.info \
|
||||
--program=/woj/user/$2.out"
|
||||
done
|
Loading…
Reference in New Issue
Block a user