feat: add support for python3(pypy3) and rust

This commit is contained in:
Paul Pan 2024-01-30 20:56:07 +08:00
parent 204b61a867
commit 864696c70c
Signed by: Paul
GPG Key ID: D639BDF5BA578AF4
12 changed files with 122 additions and 21 deletions

View File

@ -14,6 +14,11 @@ import (
)
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")
@ -104,5 +109,8 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
utils.If(status == e.Success, e.RunnerUserCompileFailed, status)
}
// 5. grant permission
_ = os.Chmod(targetFile, 0755)
return &JudgeStatus{CompileMessage: msgText}, e.Success
}

View File

@ -9,6 +9,18 @@ import (
"path/filepath"
)
var (
AllowedLanguages = map[string]struct {
Interpreter string
}{
"c": {""},
"cpp": {""},
"rust": {""},
"python3": {"/usr/bin/python3"},
"pypy3": {"/usr/bin/pypy3"},
}
)
type ConfigRuntime struct {
TimeLimit int `json:"TimeLimit"`
MemoryLimit int `json:"MemoryLimit"`
@ -19,17 +31,17 @@ var (
DefaultPrebuildRuntime = ConfigRuntime{
TimeLimit: 300000,
MemoryLimit: 256,
NProcLimit: 64,
NProcLimit: 128,
}
DefaultCompileRuntime = ConfigRuntime{
TimeLimit: 60000,
MemoryLimit: 256,
NProcLimit: 64,
NProcLimit: 128,
}
DefaultCheckRuntime = ConfigRuntime{
TimeLimit: 60000,
MemoryLimit: 128,
NProcLimit: 64,
NProcLimit: 128,
}
)
@ -96,6 +108,10 @@ func (l *ConfigLanguage) JudgeScript() string {
}
}
func (l *ConfigLanguage) JudgeInterpreter() string {
return AllowedLanguages[l.Lang].Interpreter
}
type Config struct {
Languages []ConfigLanguage `json:"Languages"`
Prebuild ConfigRuntime `json:"Prebuild,omitempty"`
@ -106,18 +122,9 @@ type Config struct {
}
func (c *Config) Validate(base string) error {
allowedLang := map[string]struct{}{
"c": {},
"cpp": {},
"go": {},
"rust": {},
"python3": {},
"pypy3": {},
}
// check per language config
for _, lang := range c.Languages {
if _, ok := allowedLang[lang.Lang]; !ok {
if _, ok := AllowedLanguages[lang.Lang]; !ok {
return fmt.Errorf("language %s is not allowed", lang.Lang)
}

View File

@ -20,13 +20,23 @@ func (s *service) SandboxArgsBuilder(meta *JudgeMeta, id int) string {
args = append(args, fmt.Sprintf("--nproc_limit=%d", meta.Cfg.Lang.Runtime.Run.NProcLimit))
args = append(args, fmt.Sprintf("--time_limit=%d", meta.Cfg.Lang.Runtime.Run.TimeLimit))
args = append(args, fmt.Sprintf("--sandbox_template=%s", meta.Cfg.Lang.Lang))
args = append(args, fmt.Sprintf("--sandbox_action=ret"))
args = append(args, fmt.Sprintf("--uid=1000"))
args = append(args, fmt.Sprintf("--gid=1000"))
args = append(args, fmt.Sprintf("--sandbox_action=%s", "ret"))
args = append(args, fmt.Sprintf("--uid=%d", 1000))
args = append(args, fmt.Sprintf("--gid=%d", 1000))
args = append(args, fmt.Sprintf("--file_input=/woj/problem/data/input/%d.input", id))
args = append(args, fmt.Sprintf("--file_output=/woj/user/%d.out.usr", id))
args = append(args, fmt.Sprintf("--file_info=/woj/user/%d.info", id))
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.Run.User))
if meta.Cfg.Lang.JudgeInterpreter() != "" {
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
args = append(args, fmt.Sprintf("--program=%s", meta.Cfg.Lang.JudgeInterpreter()))
args = append(args, fmt.Sprintf("--program_arg=/woj/user/%s", sourceFile))
} else {
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.Run.User))
}
s.log.Debug("[run] sandbox args", zap.Strings("args", args))
return strings.Join(args, " ")
}
@ -49,10 +59,14 @@ func (s *service) ProblemRun(meta *JudgeMeta) {
f := func(id int) func() error {
return func() error {
testCase := filepath.Join(dataDir, fmt.Sprintf("%d.input", id))
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.Run.User))
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
ifoFile := filepath.Join(workDir, fmt.Sprintf("%d.info", id))
targetFile := fmt.Sprintf("%s.out", meta.Run.User)
targetPath := filepath.Join(workDir, targetFile)
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
sourcePath := filepath.Join(workDir, sourceFile)
args := &RunArgs{
Program: ProgramArgs{
Args: []string{
@ -71,8 +85,8 @@ func (s *service) ProblemRun(meta *JudgeMeta) {
Options: []string{"rbind", "ro"},
},
{
Source: targetFile,
Destination: fmt.Sprintf("/woj/user/%s.out", meta.Run.User),
Source: utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourcePath, targetPath),
Destination: fmt.Sprintf("/woj/user/%s", utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourceFile, targetFile)),
Type: "bind",
Options: []string{"rbind", "ro"},
},

View File

@ -0,0 +1,7 @@
include ${TEMPLATE}/pypy3.mk ${TEMPLATE}/Judger.mk
compile:
@echo no need to compile
judge:
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes

View File

@ -0,0 +1,7 @@
include ${TEMPLATE}/python3.mk ${TEMPLATE}/Judger.mk
compile:
@echo no need to compile
judge:
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes

View File

@ -0,0 +1,7 @@
include ${TEMPLATE}/rust.mk ${TEMPLATE}/Judger.mk
compile:
@$(RUSTC) $(RUSTFLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG)
judge:
$($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes

View File

@ -0,0 +1 @@
PYTHON=/usr/bin/pypy3

View File

@ -0,0 +1 @@
PYTHON=/usr/bin/python3

View File

@ -0,0 +1,2 @@
RUSTC = /root/.cargo/bin/rustc
RUSTFLAGS = -C opt-level=2 -W warnings

View File

@ -51,6 +51,28 @@
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
},
{
"Lang" : "python3",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
},
{
"Lang" : "pypy3",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
// pypy3 运行时内存常数开销大A+B 问题内存至少给到 80 MB
"Run": {"TimeLimit": 1000, "MemoryLimit": 80, "NProcLimit": 1}
}
},
{
"Lang" : "rust",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
}
],
// 题目构建阶段,用于生成测试数据等,可选,默认值见下
@ -69,7 +91,7 @@
### 评测脚本
1. 默认评测脚本目前只支持 `c` 语言和 `cpp`,参见 `../../framework/template/default/{c,cpp}.Makefile`
2. 自定义评测脚本参见 `./judge/XYZ.Makefile`
2. 自定义评测脚本参见 `./judge/custom.Makefile`
3. `prebuild.Makefile`: 题目初始化脚本,用于编译辅助程序、生成数据等。如果存在该文件,系统会在题目分发到判机后自动执行,否则跳过该步骤
## 注意事项

View File

@ -15,6 +15,27 @@
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
},
{
"Lang" : "python3",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
},
{
"Lang" : "pypy3",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 80, "NProcLimit": 1}
}
},
{
"Lang" : "rust",
"Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"},
"Runtime": {
"Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}
}
}
],
"Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64},

View File

@ -1,6 +1,10 @@
FROM git.0x7f.app/woj/ubuntu-full:latest AS builder
FROM docker.io/library/ubuntu:22.04
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y python3 pypy3 \
&& apt-get clean && rm -rf /var/lib/apt/lists
WORKDIR /woj
RUN mkdir -p /woj/framework/scripts