WIP: dev #6

Closed
李衍志523370910113 wants to merge 131 commits from dev into master
13 changed files with 1156 additions and 132 deletions
Showing only changes of commit fe620d710e - Show all commits

2
.gitignore vendored
View File

@ -15,7 +15,7 @@ dist/
downloads/
eggs/
.eggs/
lib/
# lib/
lib64/
parts/
sdist/

View File

@ -1,6 +1,20 @@
from typing import List
from joj3_config_generator.models import joj1, repo, result, task
from joj3_config_generator.lib.repo import getHealthcheckConfig, getTeapotConfig
from joj3_config_generator.models import (
Cmd,
CmdFile,
ExecutorConfig,
ExecutorWithConfig,
ParserConfig,
Repo,
ResultConfig,
Stage,
StageConfig,
Task,
TeapotConfig,
)
# FIXME: LLM generated convert function, only for demostration
@ -8,7 +22,8 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
# Create the base ResultConf object
result_conf = result.Config(
name=task_conf.task,
log_path=f"{task_conf.task.replace(' ', '_')}.log",
# TODO: specify the exact folder difference
log_path=f"{task_conf.task.replace(' ', '-')}.log",
expire_unix_timestamp=(
int(task_conf.release.deadline.timestamp())
if task_conf.release.deadline
@ -16,8 +31,14 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
),
stage=result.Stage(stages=[], sandbox_token=repo_conf.sandbox_token),
teapot=result.Teapot(),
stage=StageConfig(stages=[], sandbox_token=repo_conf.sandbox_token),
teapot=getTeapotConfig(repo_conf, task_conf),
)
# Construct healthcheck stage
healthcheck_stage = getHealthcheckConfig(repo_conf, task_conf)
result_conf.stage.stages.append(healthcheck_stage)
cached = []
# Convert each stage in the task configuration
for task_stage in task_conf.stages:
executor_with_config = result.ExecutorWith(
@ -41,12 +62,12 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
result.Parser(name=parser, with_={}) for parser in task_stage.parsers
],
)
if "result-detail" in task_stage.parsers:
result_detail_parser = next(
p for p in conf_stage.parsers if p.name == "result-detail"
)
result_detail_parser.with_.update(task_stage.result_detail)
if task_stage.result_detail is not None:
result_detail_parser.with_.update(task_stage.result_detail)
result_conf.stage.stages.append(conf_stage)

View File

@ -0,0 +1,11 @@
from joj3_config_generator.models.repo import Repo as Repo
from joj3_config_generator.models.result import Cmd as Cmd
from joj3_config_generator.models.result import CmdFile as CmdFile
from joj3_config_generator.models.result import ExecutorConfig as ExecutorConfig
from joj3_config_generator.models.result import ExecutorWithConfig as ExecutorWithConfig
from joj3_config_generator.models.result import ParserConfig as ParserConfig
from joj3_config_generator.models.result import ResultConfig as ResultConfig
from joj3_config_generator.models.result import Stage as Stage
from joj3_config_generator.models.result import StageConfig as StageConfig
from joj3_config_generator.models.result import TeapotConfig as TeapotConfig
from joj3_config_generator.models.task import Task as Task

View File

@ -0,0 +1,123 @@
import hashlib
import os
import tempfile
from dotenv import load_dotenv
from joj3_config_generator.models import (
Cmd,
CmdFile,
ExecutorConfig,
ExecutorWithConfig,
ParserConfig,
Repo,
ResultConfig,
Stage,
StageConfig,
Task,
TeapotConfig,
)
def get_temp_directory() -> str:
return tempfile.mkdtemp(prefix="repo-checker-")
def getGradingRepoName() -> str:
path = os.path.expanduser("~/.config/teapot/teapot.env")
if os.path.exists(path):
load_dotenv(path)
repo_name = os.environ.get("GITEA_ORG_NAME")
if repo_name is not None:
return f"{repo_name.split('-')[0]}-joj"
return "ece482-joj"
def getTeapotConfig(repo_conf: Repo, task_conf: Task) -> TeapotConfig:
teapot = TeapotConfig(
# TODO: fix the log path
log_path=f"{task_conf.task.replace(' ', '-')}-joint-teapot-debug.log",
scoreboard_path=f"{task_conf.task.replace(' ', '-')}-scoreboard.csv",
failed_table_path=f"{task_conf.task.replace(' ', '-')}-failed-table.md",
grading_repo_name=getGradingRepoName(),
)
return teapot
def getHealthcheckCmd(repo_conf: Repo) -> Cmd:
repoSize = repo_conf.max_size
immutable = repo_conf.files.immutable
repo_size = f"-repoSize={str(repoSize)} "
required_files = repo_conf.files.required
for i, meta in enumerate(required_files):
required_files[i] = f"-meta={meta} "
immutable_files = f"-checkFileNameList="
for i, name in enumerate(immutable):
if i == len(immutable) - 1:
immutable_files = immutable_files + name + " "
else:
immutable_files = immutable_files + name + ","
# FIXME: need to make solution and make things easier to edit with global scope
chore = f"/{get_temp_directory}/repo-health-checker -root=. "
args = ""
args = args + chore
args = args + repo_size
for meta in required_files:
args = args + meta
args = args + get_hash(immutable)
args = args + immutable_files
cmd = Cmd(
args=args.split(),
# FIXME: easier to edit within global scope
copy_in={
f"/{get_temp_directory()}/repo-health-checker": CmdFile(
src=f"/{get_temp_directory()}/repo-health-checker"
)
},
)
return cmd
def getHealthcheckConfig(repo_conf: Repo, task_conf: Task) -> Stage:
healthcheck_stage = Stage(

hard coded path not acceptable

hard coded path not acceptable

thats what I wanted to discuss, in what form would be better? @manuel @bomingzh
my suggestions is to add more fields related to this in repo.toml or task.toml, I think store it globally in some *.py file is still hardcoded

thats what I wanted to discuss, in what form would be better? @manuel @bomingzh my suggestions is to add more fields related to this in `repo.toml` or `task.toml`, I think store it globally in some `*.py` file is still hardcoded

just let them enter path relative to project root for immutable files

just let them enter path relative to project root for immutable files

giving prompt? Wouldn't it be better to export field in *.toml file? they may accidnetally input wrong things I guess

giving prompt? Wouldn't it be better to export field in `*.toml` file? they may accidnetally input wrong things I guess

just throw error on wrong input

just throw error on wrong input

I mean, they input \home\tt\.config\ instead of \home\tt\.config\joj such things may happen, but will cost time to figure out what happened? So I think better put them in *.toml.

I mean, they input `\home\tt\.config\` instead of `\home\tt\.config\joj` such things may happen, but will cost time to figure out what happened? So I think better put them in `*.toml`.

just make the dir relative to git repo root, if the file does not exist, throw error

just make the dir relative to git repo root, if the file does not exist, throw error

any path in toml should probably be defined relative to /home/tt/.config/joj and be in a subdirectory. this is where all config must be.
then they can specify projects/p2/.cang-tidy or tool/compile

using project_root as too tricky as it could mean going up (../../) which is hard to read/figure out quickly.

as all JOJ config files must be in $HOME/.config/joj taking it as root makes sense, is general, and consistent with the approach we have used so far

any path in toml should probably be defined relative to `/home/tt/.config/joj` and be in a subdirectory. this is where all config must be. then they can specify `projects/p2/.cang-tidy` or `tool/compile` using `project_root` as too tricky as it could mean going up (`../../`) which is hard to read/figure out quickly. as all JOJ config files must be in `$HOME/.config/joj` taking it as root makes sense, is general, and consistent with the approach we have used so far

bit mixed here, if fixed, can I hardcode it?

bit mixed here, if fixed, can I hardcode it?
name="healthcheck",
group="",
executor=ExecutorConfig(
name="sandbox",
with_=ExecutorWithConfig(default=getHealthcheckCmd(repo_conf), cases=[]),
),
parsers=[ParserConfig(name="healthcheck", with_={"score": 0, "comment": ""})],
)
return healthcheck_stage
def calc_sha256sum(file_path: str) -> str:
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(65536 * 2), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
def get_hash(immutable_files: list[str]) -> str: # input should be a list
file_path = "../immutable_file/" # TODO: change this when things are on the server
immutable_hash = []
for i, file in enumerate(immutable_files):
immutable_files[i] = file_path + file.rsplit("/", 1)[-1]
for i, file in enumerate(immutable_files):
immutable_hash.append(calc_sha256sum(file))
hash_check = "-checkFileSumList="
for i, file in enumerate(immutable_hash):
if i == len(immutable_hash) - 1:
hash_check = hash_check + file + " "
else:
hash_check = hash_check + file + ","
return hash_check

View File

@ -8,7 +8,7 @@ class CmdFile(BaseModel):
content: Optional[str] = None
file_id: Optional[str] = Field(None, serialization_alias="fileId")
name: Optional[str] = None
max: Optional[int] = None
max: Optional[int] = 4 * 1024 * 1024
symlink: Optional[str] = None
stream_in: bool = Field(False, serialization_alias="streamIn")
stream_out: bool = Field(False, serialization_alias="streamOut")
@ -16,17 +16,17 @@ class CmdFile(BaseModel):
class Cmd(BaseModel):
args: List[str]
env: List[str] = []
stdin: Optional[CmdFile] = None
stdout: Optional[CmdFile] = None
stderr: Optional[CmdFile] = None
cpu_limit: int = Field(0, serialization_alias="cpuLimit")
args: list[str]
env: list[str] = ["PATH=/usr/bin:/bin:/usr/local/bin"]

Unify the use of list or List everywhere as we only support Python >=3.9 now.

Unify the use of `list` or `List` everywhere as we only support Python >=3.9 now.
stdin: Optional[CmdFile] = CmdFile(content="")
stdout: Optional[CmdFile] = CmdFile(name="stdout", max=4 * 1024)
stderr: Optional[CmdFile] = CmdFile(name="stderr", max=4 * 1024)
cpu_limit: int = Field(4 * 1000000000, serialization_alias="cpuLimit")
real_cpu_limit: int = Field(0, serialization_alias="realCpuLimit")
clock_limit: int = Field(0, serialization_alias="clockLimit")
memory_limit: int = Field(0, serialization_alias="memoryLimit")
clock_limit: int = Field(8 * 1000000000, serialization_alias="clockLimit")
memory_limit: int = Field(4 * 1024 * 1024, serialization_alias="memoryLimit")
stack_limit: int = Field(0, serialization_alias="stackLimit")
proc_limit: int = Field(0, serialization_alias="procLimit")
proc_limit: int = Field(50, serialization_alias="procLimit")
cpu_rate_limit: int = Field(0, serialization_alias="cpuRateLimit")
cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit")
copy_in: Dict[str, CmdFile] = Field({}, serialization_alias="copyIn")
@ -43,17 +43,19 @@ class Cmd(BaseModel):
class OptionalCmd(BaseModel):
args: Optional[List[str]] = None
env: Optional[List[str]] = None
args: Optional[list[str]] = None
env: Optional[list[str]] = ["PATH=/usr/bin:/bin:/usr/local/bin"]
stdin: Optional[CmdFile] = None
stdout: Optional[CmdFile] = None
stderr: Optional[CmdFile] = None
cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit")
cpu_limit: Optional[int] = Field(4 * 1000000000, serialization_alias="cpuLimit")
real_cpu_limit: Optional[int] = Field(None, serialization_alias="realCpuLimit")
clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit")
memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit")
clock_limit: Optional[int] = Field(8 * 1000000000, serialization_alias="clockLimit")
memory_limit: Optional[int] = Field(
4 * 1024 * 1024, serialization_alias="memoryLimit"
)
stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit")
proc_limit: Optional[int] = Field(None, serialization_alias="procLimit")
proc_limit: Optional[int] = Field(50, serialization_alias="procLimit")
cpu_rate_limit: Optional[int] = Field(None, serialization_alias="cpuRateLimit")
cpu_set_limit: Optional[str] = Field(None, serialization_alias="cpuSetLimit")
copy_in: Optional[Dict[str, CmdFile]] = Field(None, serialization_alias="copyIn")

View File

@ -5,26 +5,50 @@ from pydantic import BaseModel, Field
class ParserResultDetail(BaseModel):
time: bool = True # Display run time
mem: bool = True # Display memory usage
stdout: bool = False # Display stdout messages
stderr: bool = False # Display stderr messages
time: Optional[bool] = True # Display run time
mem: Optional[bool] = True # Display memory usage
stdout: Optional[bool] = False # Display stdout messages
stderr: Optional[bool] = False # Display stderr messages
exitstatus: Optional[bool] = False
class ParserDummy(BaseModel):
comment: Optional[str] = ""
class ParserKeyword(BaseModel):
keyword: Optional[list[str]] = None
weight: Optional[list[int]] = None
class Files(BaseModel):
import_: List[str] = Field(serialization_alias="import", validation_alias="import")
export: List[str]
import_: Optional[List[str]] = Field(serialization_alias="import", validation_alias="import")
export: Optional[List[str]]
class Limit(BaseModel):
mem: Optional[int] = 4
cpu: Optional[int] = 4
stderr: Optional[int] = 4
stdout: Optional[int] = 4
class Stage(BaseModel):
name: str # Stage name
command: str # Command to run
files: Files # Files to import and export
score: int # Score for the task
parsers: List[str] # list of parsers
result_detail: ParserResultDetail = (
ParserResultDetail()
) # for result-detail parser
files: Optional[Files] = None
score: Optional[int] = 0
parsers: list[str] # list of parsers
limit: Optional[Limit] = None
dummy: Optional[ParserDummy] = ParserDummy()
keyword: Optional[ParserKeyword] = ParserKeyword()
clangtidy: Optional[ParserKeyword] = ParserKeyword()
cppcheck: Optional[ParserKeyword] = ParserKeyword()
cpplint: Optional[ParserKeyword] = ParserKeyword()
result_detail: Optional[ParserResultDetail] = Field(
ParserResultDetail(), alias="result-detail"
)
class Release(BaseModel):

View File

@ -7,4 +7,4 @@ sandbox_token = "test"
whitelist_patterns = ["*.py", "*.txt", "*.md"]
whitelist_file = ".whitelist"
required = ["main.py", "README.md"]
immutable = ["config.yaml", "setup.py"]
immutable = [".gitignore", ".gitattributes", "push.yaml", "release.yaml"]

View File

@ -1,53 +1,79 @@
{
"name": "hw3 ex5",
"logPath": "hw3_ex5.log",
"expireUnixTimestamp": 1729267140,
"name": "Homework 1 exercise 2",
"logPath": "Homework-1-exercise-2.log",
"expireUnixTimestamp": 1728748740,
"stage": {
"sandboxExecServer": "172.17.0.1:5051",
"sandboxToken": "test",
"outputPath": "/tmp/joj3_result.json",
"stages": [
{
"name": "judge_base",
"group": "hw3 ex5",
"name": "healthcheck",
"group": "",
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"./matlab-joj",
"./h3/ex5.m"
"/tmp/repo-health-checker",
"-root=.",
"-repoSize=50.5",
"-meta=main.py",
"-meta=README.md",
"-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,8d1229900c6fc6711b5cc141d1ab5ea7f5b7b7a4b921d9cfa3957408b43ae723,eb857bcd94857cedc4045cb2d6ba04cb5bbb3daf188abc95fb9478db823ef47e",
"-checkFileNameList=.gitignore,.gitattributes,push.yaml,release.yaml"
],
"env": [],
"stdin": null,
"stdout": null,
"stderr": null,
"cpuLimit": 0,
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,

yes, remove_null function need a small adjustment

yes, `remove_null` function need a small adjustment

default value problem in pydantic model

default value problem in pydantic model
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 0,
"memoryLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {
"tools/matlab-joj": {
"src": "tools/matlab-joj",
"/tmp/repo-health-checker": {
"src": "/tmp/repo-health-checker",
"content": null,
"fileId": null,
"name": null,
"max": null,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"tools/matlab_formatter.py": {
"src": "tools/matlab_formatter.py",
"content": null,
"fileId": null,
"name": null,
"max": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
@ -57,9 +83,139 @@
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "healthcheck",
"with": {
"score": 0,
"comment": ""
}
}
]
},
{
"name": "Compilation",
"group": null,
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"make.sh"
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {
"tools/make.sh": {
"src": "/home/tt/.config/joj/tools/make.sh",
"content": null,
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"src/main.c": {
"src": "/home/tt/.config/joj/src/main.c",
"content": null,
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"src/task.h": {
"src": "/home/tt/.config/joj/src/task.h",
"content": null,
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"srcCMakelist.txt": {
"src": "/home/tt/.config/joj/srcCMakelist.txt",
"content": null,
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
}
},
"copyInCached": {
"tools/make.sh": "tools/make.sh",
"src/main.c": "src/main.c",
"src/task.h": "src/task.h",
"srcCMakelist.txt": "srcCMakelist.txt"
},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [
"output/ex5_results.txt",
"output/ex5_logs.txt"
"driver",
"p2",
"p2-msan"
],
"copyOutMax": 0,
"copyOutDir": "",
@ -73,7 +229,119 @@
},
"parsers": [
{
"name": "diff",
"name": "result-detail",
"with": {
"time": false,
"mem": false,
"stdout": false,
"stderr": true,
"exitstatus": true
}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-status",
"with": {}
}
]
},
{
"name": "File length check",
"group": null,
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"./file-length",
"500",
"400",
"*.c",
"*.h"
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {
"tools/file-length": {
"src": "/home/tt/.config/joj/tools/file-length",
"content": null,
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
}
},
"copyInCached": {
"tools/file-length": "tools/file-length"
},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "keyword",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
@ -82,65 +350,361 @@
"time": false,
"mem": false,
"stdout": false,
"stderr": true
"stderr": true,
"exitstatus": false
}
}
]
},
{
"name": "judge_base2",
"group": "hw3 ex5",
"name": "Clang-tidy checks",
"group": null,
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"./matlab-joj",
"./h3/ex5.m"
"run-clang-tidy-18",
"-header-filter=.*",
"-quiet",
"-load=/usr/local/lib/libcodequality.so",
"-p",
"build"
],
"env": [],
"stdin": null,
"stdout": null,
"stderr": null,
"cpuLimit": 0,
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 0,
"memoryLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {
"tools/matlab-joj": {
"src": "tools/matlab-joj",
"content": null,
"fileId": null,
"name": null,
"max": null,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"tools/matlab_formatter.py": {
"src": "tools/matlab_formatter.py",
"content": null,
"fileId": null,
"name": null,
"max": null,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
}
},
"copyIn": {},
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [
"output/ex5_results2.txt",
"output/ex5_logs2.txt"
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "clangtidy",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-detail",
"with": {
"time": false,
"mem": false,
"stdout": true,
"stderr": false,
"exitstatus": true
}
}
]
},
{
"name": "Cppcheck check",
"group": null,
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"cppcheck",
"--template='{\"file\":\"{file}\",\"line\":{line},",
"\"column\":{column},",
"\"severity\":\"{severity}\",",
"\"message\":\"{message}\",",
"\"id\":\"{id}\"}'",
"--force",
"--enable=all",
"--quiet",
"./"
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {},
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "cppcheck",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-detail",
"with": {
"time": false,
"mem": false,
"stdout": false,
"stderr": true,
"exitstatus": true
}
}
]
},
{
"name": "Cpplint check",
"group": null,
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"cpplint",
"--linelength=120",
"--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard",
"--recursive",
"--exclude=build",
"."
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {},
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "cpplint",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-detail",
"with": {
"time": false,
"mem": false,
"stdout": true,
"stderr": false,
"exitstatus": true
}
}
]
},
{
"name": "judge-base",
"group": "joj",
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"./driver",
"./mumsh"
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {},
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
@ -156,13 +720,109 @@
"name": "diff",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-detail",
"with": {
"time": true,
"mem": true,
"stdout": false,
"stderr": false
"stderr": true,
"exitstatus": true
}
}
]
},
{
"name": "judge-msan",
"group": "joj",
"executor": {
"name": "sandbox",
"with": {
"default": {
"args": [
"./driver",
"./mumsh-msan"
],
"env": [
"PATH=/usr/bin:/bin:/usr/local/bin"
],
"stdin": {
"src": null,
"content": "",
"fileId": null,
"name": null,
"max": 4194304,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stdout": {
"src": null,
"content": null,
"fileId": null,
"name": "stdout",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"stderr": {
"src": null,
"content": null,
"fileId": null,
"name": "stderr",
"max": 4096,
"symlink": null,
"streamIn": false,
"streamOut": false,
"pipe": false
},
"cpuLimit": 4000000000,
"realCpuLimit": 0,
"clockLimit": 8000000000,
"memoryLimit": 4194304,
"stackLimit": 0,
"procLimit": 50,
"cpuRateLimit": 0,
"cpuSetLimit": "",
"copyIn": {},
"copyInCached": {},
"copyInDir": ".",
"copyOut": [],
"copyOutCached": [],
"copyOutMax": 0,
"copyOutDir": "",
"tty": false,
"strictMemoryLimit": false,
"dataSegmentLimit": false,
"addressSpaceLimit": false
},
"cases": []
}
},
"parsers": [
{
"name": "diff",
"with": {}
},
{
"name": "dummy",
"with": {}
},
{
"name": "result-detail",
"with": {
"time": true,
"mem": true,
"stdout": false,
"stderr": true,
"exitstatus": true
}
}
]
@ -170,10 +830,10 @@
]
},
"teapot": {
"logPath": "/home/tt/.cache/joint-teapot-debug.log",
"scoreboardPath": "scoreboard.csv",
"failedTablePath": "failed-table.md",
"gradingRepoName": "",
"logPath": "Homework-1-exercise-2-joint-teapot-debug.log",
"scoreboardPath": "Homework-1-exercise-2-scoreboard.csv",
"failedTablePath": "Homework-1-exercise-2-failed-table.md",
"gradingRepoName": "engr151-joj",
"skipIssue": false,
"skipScoreboard": false,
"skipFailedTable": false

View File

@ -1,30 +1,119 @@
task = "hw3 ex5"
# general task configuration

make this basic test as simple as possible, and create new test cases for each kind of stage

make this basic test as simple as possible, and create new test cases for each kind of stage
task="Homework 1 exercise 2" # task name
[release]
deadline = "2024-10-18T23:59:00+08:00"
release.deadline = 2024-10-12 23:59:00+08:00
release.stages = [ "compile" ]
[[stages]]
name = "judge_base"
command = "./matlab-joj ./h3/ex5.m"
score = 100
parsers = ["diff", "result-detail"]
name = "Compilation"
command = "make.sh" # eg. script running cmake commands
files.import = [ "tools/make.sh", "src/main.c", "src/task.h", "srcCMakelist.txt" ]
files.export = [ "driver", "p2", "p2-msan" ]
limit.cpu = 180 # p2 takes long to compile
limit.stderr = 128
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
files.export = ["output/ex5_results.txt", "output/ex5_logs.txt"]
result_detail.time = false
result_detail.mem = false
result_detail.stderr = true
# compile parsers
parsers = [ "result-detail", "dummy", "result-status" ]
result-status.comment = "Congratulations! Your code compiled successfully."
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stderr = true
result-detail.time = false
result-detail.mem = false
[[stages]]
name = "judge_base2"
command = "./matlab-joj ./h3/ex5.m"
score = 80
parsers = ["diff", "result-detail"]
name = "File length check"
command = "./file-length 500 400 *.c *.h" # command to run
files.import = [ "tools/file-length" ]
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
files.export = ["output/ex5_results2.txt", "output/ex5_logs2.txt"]
parsers = [ "keyword", "dummy", "result-detail" ]
keyword.keyword = [ "max", "recommend"] # keywords caught by corresponding JOJ plugin
keyword.weight = [ 50, 20 ] # weight of each keyword
result-detail.exitstatus = false
result-detail.stderr = true
result-detail.time = false
result-detail.mem = false
result_detail.time = true
result_detail.mem = true
result_detail.stderr = false
[[stages]]
name = "Clang-tidy checks"
command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p build"
limit.stdout = 65
parsers = [ "clangtidy", "dummy", "result-detail" ]
clangtidy.keyword = [ "codequality-no-global-variables", "codequality-no-header-guard", "readability-function-size", "readability-duplicate-include", "readability-identifier-naming", "readability-redundant", "readability-misleading-indentation", "readability-misplaced-array-index", "cppcoreguidelines-init-variables", "bugprone-suspicious-string-compare", "google-global-names-in-headers", "clang-diagnostic", "clang-analyzer", "misc performance" ]
clangtidy.weight = [10, 10, 50, 10, 5, 5, 10, 5, 5, 8, 5, 5, 5, 5, 8]
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stdout = true
result-detail.time = false
result-detail.mem = false
[[stages]]
name = "Cppcheck check"
command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --quiet ./"
limit.stderr = 65
parsers = [ "cppcheck", "dummy", "result-detail" ]
cppcheck.keyword = ["error", "warning", "portability", "performance", "style"]
cppcheck.weight = [20, 10, 15, 15, 10]
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stderr = true
result-detail.time = false
result-detail.mem = false
[[stages]]
name = "Cpplint check"
command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard --recursive --exclude=build ."
limit.stdout = 65
parsers = [ "cpplint", "dummy", "result-detail" ]
cpplint.keyword = [ "runtime", "readability", "build" ]
cpplint.weight = [ 10, 20, 15]
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stdout = true
result-detail.time = false
result-detail.mem = false
[[stages]]
name = "judge-base"
command="./driver ./mumsh"
limit.cpu = 3
limit.mem = 75
score = 10
parsers = ["diff", "dummy", "result-detail"]
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stderr = true
case4.score = 15
case4.limit.cpu = 30
case4.limit.mem = 10
case4.limit.stdout = 8
case5.score = 25
case8.limit.stderr = 128
[[stages]]
name = "judge-msan"
command="./driver ./mumsh-msan"
limit.cpu = 10 # default cpu limit (in sec) for each test case
limit.mem = 500 # set default mem limit (in MB) for all OJ test cases
score = 10
skip = ["case0", "case11"]
parsers = ["diff", "dummy", "result-detail"]
dummy.comment = "\n\n### Details\n"
result-detail.exitstatus = true
result-detail.stderr = true
case4.score = 15
case4.limit.cpu = 30
case4.limit.mem = 10
case5.diff.output.ignorespaces = false
case6.diff.output.hide = true

33
tests/immutable_file/.gitattributes vendored Normal file
View File

@ -0,0 +1,33 @@
*.avi filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.djvu filter=lfs diff=lfs merge=lfs -text
*.doc filter=lfs diff=lfs merge=lfs -text
*.docx filter=lfs diff=lfs merge=lfs -text
*.epub filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.ipynb filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.JPEG filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.JPG filter=lfs diff=lfs merge=lfs -text
*.mkv filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.ods filter=lfs diff=lfs merge=lfs -text
*.odt filter=lfs diff=lfs merge=lfs -text
*.otf filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.PDF filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.PNG filter=lfs diff=lfs merge=lfs -text
*.ppt filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text
*.ps filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
*.xls filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text

23
tests/immutable_file/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
################################
## White list based gitignore ##
################################
# forbidden
*
.*
# allowed
!.gitignore
!.gitattributes
!.gitea/
!.gitea/issue_template/
!.gitea/workflows/
!*.yaml
!Makefile
!CMakeLists.txt
!h[0-8]/
!*.m
!*.c
!*.cpp
!*.h
!*.md

View File

@ -0,0 +1,18 @@
name: Run JOJ3 on Push
on: [push]
jobs:
run:
container:
image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim
volumes:
- /home/tt/.config:/home/tt/.config
- /home/tt/.cache:/home/tt/.cache
- /home/tt/.ssh:/home/tt/.ssh
steps:
- name: Check out repository code
uses: https://gitea.com/BoYanZh/checkout@focs
with:
fetch-depth: 0
- name: run joj3
run: |
sudo -E -u tt joj3 -conf-root /home/tt/.config/joj

View File

@ -0,0 +1,20 @@
name: Run JOJ3 on Release
on:
release:
types: [published]
jobs:
run:
container:
image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim
volumes:
- /home/tt/.config:/home/tt/.config
- /home/tt/.cache:/home/tt/.cache
- /home/tt/.ssh:/home/tt/.ssh
steps:
- name: Check out repository code
uses: https://gitea.com/BoYanZh/checkout@focs
with:
fetch-depth: 0
- name: run joj3
run: |
sudo -E -u tt joj3 -conf-root /home/tt/.config/joj -msg "feat(h1-release): joj on ${{ github.ref }}"