dev #10
22
README.md
|
@ -16,3 +16,25 @@
|
||||||
4. Install deps by `pdm install && pdm run pre-commit install`
|
4. Install deps by `pdm install && pdm run pre-commit install`
|
||||||
5. Run the cli app by `pdm run app --help`
|
5. Run the cli app by `pdm run app --help`
|
||||||
6. Check other commands or scripts with `pdm run --list`
|
6. Check other commands or scripts with `pdm run --list`
|
||||||
|
|
||||||
|
## How to use?
|
||||||
|
|
||||||
|
- `joj3-config-generator convert` function is now supported, currently support one argument as input, it indicates the **convert root**
|
||||||
|
- default value on the server can be given as `/home/tt/.config/joj`
|
||||||
|
- **NOTE:** the user should ensure that the ideal `repo.toml` file is in the sub-directory of the **convert root**
|
||||||
|
- the intended immutable files should be placed at a sub-directory named `immutable_files` at same position as the `repo.toml` file
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ tree .
|
||||||
|
.
|
||||||
|
|- immutable_files
|
||||||
|
| |-- push.yaml
|
||||||
|
| |-- release.yaml
|
||||||
|
|-- repo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
- sample command on the server
|
||||||
|
|
||||||
|
```shell
|
||||||
|
joj3-config-generator convert /home/tt/.config/joj
|
||||||
|
```
|
||||||
|
|
|
@ -1,93 +1,41 @@
|
||||||
from typing import List
|
import os
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from joj3_config_generator.models import joj1, repo, result, task
|
from joj3_config_generator.models import joj1, repo, result, task
|
||||||
|
from joj3_config_generator.models.const import CACHE_ROOT, JOJ3_CONFIG_ROOT
|
||||||
|
from joj3_config_generator.processers.repo import (
|
||||||
|
get_health_check_stage,
|
||||||
|
get_teapot_stage,
|
||||||
|
)
|
||||||
|
from joj3_config_generator.processers.task import get_conf_stage
|
||||||
|
|
||||||
|
|
||||||
# FIXME: LLM generated convert function, only for demostration
|
|
||||||
def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
|
def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
|
||||||
# Create the base ResultConf object
|
# Create the base ResultConf object
|
||||||
result_conf = result.Config(
|
result_conf = result.Config(
|
||||||
name=task_conf.task,
|
name=task_conf.task.name,
|
||||||
log_path=f"{task_conf.task.replace(' ', '_')}.log",
|
# exact folder difference specified by type
|
||||||
expire_unix_timestamp=(
|
log_path=str(CACHE_ROOT / "joj3" / f"{task_conf.task.type_}.log"),
|
||||||
int(task_conf.release.deadline.timestamp())
|
expire_unix_timestamp=int(task_conf.release.end_time.timestamp()),
|
||||||
if task_conf.release.deadline
|
effective_unix_timestamp=int(task_conf.release.begin_time.timestamp()),
|
||||||
else -1
|
actor_csv_path=str(JOJ3_CONFIG_ROOT / "students.csv"), # students.csv position
|
||||||
),
|
max_total_score=repo_conf.max_total_score,
|
||||||
stage=result.Stage(stages=[], sandbox_token=repo_conf.sandbox_token),
|
stage=result.Stage(sandbox_token=repo_conf.sandbox_token),
|
||||||
teapot=result.Teapot(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
current_test = os.environ.get("PYTEST_CURRENT_TEST") is not None
|
||||||
|
# Construct health check stage
|
||||||
|
if not repo_conf.force_skip_health_check_on_test or not current_test:
|
||||||
|
result_conf.stage.stages.append(get_health_check_stage(repo_conf))
|
||||||
|
cached: Dict[str, None] = {}
|
||||||
# Convert each stage in the task configuration
|
# Convert each stage in the task configuration
|
||||||
for task_stage in task_conf.stages:
|
for task_stage in task_conf.stages:
|
||||||
executor_with_config = result.ExecutorWith(
|
result_conf.stage.stages.append(get_conf_stage(task_conf, task_stage, cached))
|
||||||
default=result.Cmd(
|
if not repo_conf.force_skip_teapot_on_test or not current_test:
|
||||||
args=task_stage.command.split(),
|
result_conf.stage.post_stages.append(get_teapot_stage(repo_conf))
|
||||||
copy_in={
|
|
||||||
file: result.LocalFile(src=file)
|
|
||||||
for file in task_stage.files.import_
|
|
||||||
},
|
|
||||||
copy_out_cached=task_stage.files.export,
|
|
||||||
),
|
|
||||||
cases=[], # You can add cases if needed
|
|
||||||
)
|
|
||||||
conf_stage = result.StageDetail(
|
|
||||||
name=task_stage.name,
|
|
||||||
group=task_conf.task,
|
|
||||||
executor=result.Executor(
|
|
||||||
name="sandbox",
|
|
||||||
with_=executor_with_config,
|
|
||||||
),
|
|
||||||
parsers=[
|
|
||||||
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)
|
|
||||||
|
|
||||||
result_conf.stage.stages.append(conf_stage)
|
|
||||||
|
|
||||||
return result_conf
|
return result_conf
|
||||||
|
|
||||||
|
|
||||||
# FIXME: LLM generated convert function, only for demostration
|
|
||||||
def convert_joj1(joj1_conf: joj1.Config) -> task.Config:
|
def convert_joj1(joj1_conf: joj1.Config) -> task.Config:
|
||||||
stages = []
|
return task.Config()
|
||||||
for language in joj1_conf.languages:
|
|
||||||
# Here you might want to create a stage for each language
|
|
||||||
# You can define a command based on language properties
|
|
||||||
command = f"run {language.language}"
|
|
||||||
# Assuming we don't have explicit files, we will set empty ones or default behavior
|
|
||||||
files = task.Files(import_=[], export=[])
|
|
||||||
# Score can be derived from the first case or set to a default
|
|
||||||
score = 0
|
|
||||||
parsers: List[str] = [] # Define parsers if applicable
|
|
||||||
if joj1_conf.cases:
|
|
||||||
score = sum(
|
|
||||||
case.score for case in joj1_conf.cases
|
|
||||||
) # Sum scores for all cases
|
|
||||||
# Creating a stage for each language
|
|
||||||
stages.append(
|
|
||||||
task.Stage(
|
|
||||||
name=language.language,
|
|
||||||
command=command,
|
|
||||||
files=files,
|
|
||||||
score=score,
|
|
||||||
parsers=parsers,
|
|
||||||
result_detail=task.ParserResultDetail(), # You can customize this further if needed
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# Assuming no deadline is provided in `joj1`, you can set it accordingly
|
|
||||||
release_deadline = (
|
|
||||||
None # Placeholder for future implementation if deadlines are defined
|
|
||||||
)
|
|
||||||
|
|
||||||
return task.Config(
|
|
||||||
task=joj1_conf.languages[0].language if joj1_conf.languages else "Unnamed Task",
|
|
||||||
release=task.Release(deadline=release_deadline),
|
|
||||||
stages=stages,
|
|
||||||
)
|
|
||||||
|
|
39
joj3_config_generator/load.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
|
import inquirer
|
||||||
|
import rtoml
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from joj3_config_generator.models import joj1, repo, task
|
||||||
|
|
||||||
|
|
||||||
|
def load_joj3_toml_answers() -> Dict[str, str]:
|
||||||
|
questions = [
|
||||||
|
inquirer.List(
|
||||||
|
"size",
|
||||||
|
message="What size do you need?",
|
||||||
|
choices=["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
answers = inquirer.prompt(questions)
|
||||||
|
return answers
|
||||||
|
|
||||||
|
|
||||||
|
def load_joj1_yaml(yaml_path: Path) -> joj1.Config:
|
||||||
|
joj1_obj = yaml.safe_load(yaml_path.read_text())
|
||||||
|
return joj1.Config(**joj1_obj)
|
||||||
|
|
||||||
|
|
||||||
|
def load_joj3_toml(
|
||||||
|
root_path: Path, repo_toml_path: Path, task_toml_path: Path
|
||||||
|
) -> Tuple[repo.Config, task.Config]:
|
||||||
|
repo_obj = rtoml.loads(repo_toml_path.read_text())
|
||||||
|
task_obj = rtoml.loads(task_toml_path.read_text())
|
||||||
|
repo_conf = repo.Config(**repo_obj)
|
||||||
|
repo_conf.root = root_path
|
||||||
|
repo_conf.path = repo_toml_path.relative_to(root_path)
|
||||||
|
task_conf = task.Config(**task_obj)
|
||||||
|
task_conf.root = root_path
|
||||||
|
task_conf.path = task_toml_path.relative_to(root_path)
|
||||||
|
return repo_conf, task_conf
|
|
@ -1,48 +1,44 @@
|
||||||
import json
|
import json
|
||||||
jon-lee marked this conversation as resolved
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import inquirer
|
|
||||||
import rtoml
|
import rtoml
|
||||||
import typer
|
import typer
|
||||||
import yaml
|
|
||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
from joj3_config_generator.convert import convert as convert_conf
|
from joj3_config_generator.convert import convert as convert_conf
|
||||||
from joj3_config_generator.convert import convert_joj1 as convert_joj1_conf
|
from joj3_config_generator.convert import convert_joj1 as convert_joj1_conf
|
||||||
from joj3_config_generator.models import joj1, repo, task
|
from joj3_config_generator.load import (
|
||||||
|
load_joj1_yaml,
|
||||||
|
load_joj3_toml,
|
||||||
|
load_joj3_toml_answers,
|
||||||
|
)
|
||||||
|
from joj3_config_generator.models.const import JOJ3_CONFIG_ROOT
|
||||||
from joj3_config_generator.utils.logger import logger
|
from joj3_config_generator.utils.logger import logger
|
||||||
|
|
||||||
app = typer.Typer(add_completion=False)
|
app = typer.Typer(add_completion=False)
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def create(toml: typer.FileTextWrite) -> None:
|
def create(toml_path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Create a new JOJ3 toml config file
|
Create a new JOJ3 toml config file
|
||||||
"""
|
"""
|
||||||
logger.info("Creating")
|
logger.info(f"Creating toml file {toml_path}")
|
||||||
questions = [
|
answers = load_joj3_toml_answers()
|
||||||
inquirer.List(
|
logger.debug(f"Got answers: {answers}")
|
||||||
"size",
|
toml_path.write_text(rtoml.dumps({}))
|
||||||
message="What size do you need?",
|
|
||||||
choices=["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
answers = inquirer.prompt(questions)
|
|
||||||
logger.info(answers)
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def convert_joj1(yaml_file: typer.FileText, toml_file: typer.FileTextWrite) -> None:
|
def convert_joj1(yaml_path: Path, toml_path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Convert a JOJ1 yaml config file to JOJ3 toml config file
|
Convert a JOJ1 yaml config file to JOJ3 toml config file
|
||||||
"""
|
"""
|
||||||
logger.info(f"Converting yaml file {yaml_file}")
|
logger.info(f"Converting yaml file {yaml_path}")
|
||||||
joj1_obj = yaml.safe_load(yaml_file.read())
|
joj1_model = load_joj1_yaml(yaml_path)
|
||||||
joj1_model = joj1.Config(**joj1_obj)
|
|
||||||
task_model = convert_joj1_conf(joj1_model)
|
task_model = convert_joj1_conf(joj1_model)
|
||||||
result_dict = task_model.model_dump(by_alias=True)
|
result_dict = task_model.model_dump(mode="json", by_alias=True, exclude_none=True)
|
||||||
toml_file.write(rtoml.dumps(result_dict))
|
toml_path.write_text(rtoml.dumps(result_dict))
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
|
@ -50,8 +46,7 @@ def convert(
|
||||||
root: Annotated[
|
root: Annotated[
|
||||||
Path,
|
Path,
|
||||||
typer.Argument(
|
typer.Argument(
|
||||||
help="root directory of config files, "
|
help=f"root directory of config files, located at {JOJ3_CONFIG_ROOT} in JTC"
|
||||||
"located at /home/tt/.config/joj in JTC"
|
|
||||||
),
|
),
|
||||||
] = Path(".")
|
] = Path(".")
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -60,9 +55,7 @@ def convert(
|
||||||
"""
|
"""
|
||||||
logger.info(f"Converting files in {root.absolute()}")
|
logger.info(f"Converting files in {root.absolute()}")
|
||||||
for repo_toml_path in root.glob("**/repo.toml"):
|
for repo_toml_path in root.glob("**/repo.toml"):
|
||||||
repo_path = repo_toml_path.parent
|
for task_toml_path in repo_toml_path.parent.glob("**/*.toml"):
|
||||||
repo_obj = rtoml.loads(repo_toml_path.read_text())
|
|
||||||
for task_toml_path in repo_path.glob("**/*.toml"):
|
|
||||||
if repo_toml_path == task_toml_path:
|
if repo_toml_path == task_toml_path:
|
||||||
continue
|
continue
|
||||||
toml_name = task_toml_path.name.removesuffix(".toml")
|
toml_name = task_toml_path.name.removesuffix(".toml")
|
||||||
|
@ -70,15 +63,11 @@ def convert(
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Converting {repo_toml_path} & {task_toml_path} to {result_json_path}"
|
f"Converting {repo_toml_path} & {task_toml_path} to {result_json_path}"
|
||||||
)
|
)
|
||||||
task_obj = rtoml.loads(task_toml_path.read_text())
|
repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path)
|
||||||
repo_conf = repo.Config(**repo_obj)
|
|
||||||
repo_conf.root = root
|
|
||||||
repo_conf.path = repo_toml_path.relative_to(root)
|
|
||||||
task_conf = task.Config(**task_obj)
|
|
||||||
task_conf.root = root
|
|
||||||
task_conf.path = task_toml_path.relative_to(root)
|
|
||||||
result_model = convert_conf(repo_conf, task_conf)
|
result_model = convert_conf(repo_conf, task_conf)
|
||||||
result_dict = result_model.model_dump(by_alias=True, exclude_none=True)
|
result_dict = result_model.model_dump(
|
||||||
|
mode="json", by_alias=True, exclude_none=True
|
||||||
|
)
|
||||||
with result_json_path.open("w") as result_file:
|
with result_json_path.open("w") as result_file:
|
||||||
json.dump(result_dict, result_file, ensure_ascii=False, indent=4)
|
json.dump(result_dict, result_file, ensure_ascii=False, indent=4)
|
||||||
result_file.write("\n")
|
result_file.write("\n")
|
||||||
|
|
19
joj3_config_generator/models/common.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
import humanfriendly
|
||||||
|
|
||||||
|
|
||||||
|
class Memory(int):
|
||||||
|
def __new__(cls, value: Union[str, int]) -> "Memory":
|
||||||
|
if isinstance(value, str):
|
||||||
|
parsed = humanfriendly.parse_size(value, binary=True)
|
||||||
|
return super().__new__(cls, parsed)
|
||||||
|
return super().__new__(cls, value)
|
||||||
|
|
||||||
|
|
||||||
|
class Time(int):
|
||||||
|
def __new__(cls, value: Union[str, int]) -> "Time":
|
||||||
|
if isinstance(value, str):
|
||||||
|
parsed = humanfriendly.parse_timespan(value) * 1_000_000_000 # ns
|
||||||
|
return super().__new__(cls, round(parsed))
|
||||||
|
return super().__new__(cls, value)
|
11
joj3_config_generator/models/const.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from joj3_config_generator.models.common import Memory, Time
|
||||||
|
|
||||||
|
DEFAULT_CPU_LIMIT = Time("1s")
|
||||||
|
DEFAULT_MEMORY_LIMIT = Memory("128m")
|
||||||
|
DEFAULT_FILE_LIMIT = Memory("32m")
|
||||||
|
|
||||||
|
JOJ3_CONFIG_ROOT = Path("/home/tt/.config/joj")
|
||||||
|
TEAPOT_CONFIG_ROOT = Path("/home/tt/.config/teapot")
|
||||||
|
CACHE_ROOT = Path("/home/tt/.cache")
|
|
@ -1,21 +1,29 @@
|
||||||
|
import socket
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class Files(BaseModel):
|
class Files(BaseModel):
|
||||||
whitelist_patterns: List[str]
|
required: List[str] = []
|
||||||
whitelist_file: Optional[str]
|
immutable: List[str] = []
|
||||||
required: List[str]
|
|
||||||
immutable: List[str]
|
|
||||||
|
class Groups(BaseModel):
|
||||||
|
name: List[str] = []
|
||||||
|
max_count: List[int] = []
|
||||||
|
time_period_hour: List[int] = []
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
|
max_size: float = Field(10, ge=0)
|
||||||
|
files: Files = Files()
|
||||||
|
sandbox_token: str = Field("")
|
||||||
|
max_total_score: int = Field(100)
|
||||||
|
force_skip_health_check_on_test: bool = False
|
||||||
|
force_skip_teapot_on_test: bool = False
|
||||||
|
groups: Groups = Groups()
|
||||||
root: Path = Path(".")
|
root: Path = Path(".")
|
||||||
path: Path = Path("repo.toml")
|
path: Path = Path("repo.toml")
|
||||||
teaching_team: List[str]
|
grading_repo_name: str = f"{socket.gethostname().split('-')[0]}-joj"
|
||||||
max_size: float = Field(..., ge=0)
|
|
||||||
release_tags: List[str]
|
|
||||||
files: Files
|
|
||||||
sandbox_token: str
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||||
|
|
||||||
|
from joj3_config_generator.models.const import (
|
||||||
|
DEFAULT_CPU_LIMIT,
|
||||||
|
DEFAULT_FILE_LIMIT,
|
||||||
|
DEFAULT_MEMORY_LIMIT,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LocalFile(BaseModel):
|
class LocalFile(BaseModel):
|
||||||
|
@ -17,7 +23,7 @@ class PreparedFile(BaseModel):
|
||||||
|
|
||||||
class Collector(BaseModel):
|
class Collector(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
max: int
|
max: int = DEFAULT_FILE_LIMIT
|
||||||
pipe: bool = True
|
pipe: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,27 +39,26 @@ class StreamOut(BaseModel):
|
||||||
stream_out: bool = Field(..., alias="streamOut")
|
stream_out: bool = Field(..., alias="streamOut")
|
||||||
|
|
||||||
|
|
||||||
InputFile = Union[LocalFile | MemoryFile | PreparedFile | Symlink]
|
InputFile = Union[LocalFile, MemoryFile, PreparedFile, Symlink]
|
||||||
|
|
||||||
|
|
||||||
class Cmd(BaseModel):
|
class Cmd(BaseModel):
|
||||||
args: List[str]
|
args: List[str] = []
|
||||||
env: List[str] = []
|
env: List[str] = []
|
||||||
stdin: Optional[Union[InputFile | StreamIn]] = None
|
stdin: Union[InputFile, StreamIn] = MemoryFile(content="")
|
||||||
stdout: Optional[Union[Collector | StreamOut]] = None
|
stdout: Union[Collector, StreamOut] = Collector(name="stdout")
|
||||||
stderr: Optional[Union[Collector | StreamOut]] = None
|
stderr: Union[Collector, StreamOut] = Collector(name="stderr")
|
||||||
cpu_limit: int = Field(0, serialization_alias="cpuLimit")
|
cpu_limit: int = Field(DEFAULT_CPU_LIMIT, serialization_alias="cpuLimit")
|
||||||
real_cpu_limit: int = Field(0, serialization_alias="realCpuLimit")
|
clock_limit: int = Field(2 * DEFAULT_CPU_LIMIT, serialization_alias="clockLimit")
|
||||||
clock_limit: int = Field(0, serialization_alias="clockLimit")
|
memory_limit: int = Field(DEFAULT_MEMORY_LIMIT, serialization_alias="memoryLimit")
|
||||||
memory_limit: int = Field(0, serialization_alias="memoryLimit")
|
|
||||||
stack_limit: int = Field(0, serialization_alias="stackLimit")
|
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_rate_limit: int = Field(0, serialization_alias="cpuRateLimit")
|
||||||
cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit")
|
cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit")
|
||||||
copy_in: Dict[str, InputFile] = Field({}, serialization_alias="copyIn")
|
copy_in: Dict[str, InputFile] = Field({}, serialization_alias="copyIn")
|
||||||
copy_in_cached: Dict[str, str] = Field({}, serialization_alias="copyInCached")
|
copy_in_cached: Dict[str, str] = Field({}, serialization_alias="copyInCached")
|
||||||
copy_in_dir: str = Field(".", serialization_alias="copyInDir")
|
copy_in_dir: str = Field(".", serialization_alias="copyInDir")
|
||||||
copy_out: List[str] = Field([], serialization_alias="copyOut")
|
copy_out: List[str] = Field(["stdout", "stderr"], serialization_alias="copyOut")
|
||||||
copy_out_cached: List[str] = Field([], serialization_alias="copyOutCached")
|
copy_out_cached: List[str] = Field([], serialization_alias="copyOutCached")
|
||||||
copy_out_max: int = Field(0, serialization_alias="copyOutMax")
|
copy_out_max: int = Field(0, serialization_alias="copyOutMax")
|
||||||
copy_out_dir: str = Field("", serialization_alias="copyOutDir")
|
copy_out_dir: str = Field("", serialization_alias="copyOutDir")
|
||||||
|
@ -66,11 +71,10 @@ class Cmd(BaseModel):
|
||||||
class OptionalCmd(BaseModel):
|
class OptionalCmd(BaseModel):
|
||||||
args: Optional[List[str]] = None
|
args: Optional[List[str]] = None
|
||||||
env: Optional[List[str]] = None
|
env: Optional[List[str]] = None
|
||||||
stdin: Optional[Union[InputFile | StreamIn]] = None
|
stdin: Optional[Union[InputFile, StreamIn]] = None
|
||||||
stdout: Optional[Union[Collector | StreamOut]] = None
|
stdout: Optional[Union[Collector, StreamOut]] = None
|
||||||
stderr: Optional[Union[Collector | StreamOut]] = None
|
stderr: Optional[Union[Collector, StreamOut]] = None
|
||||||
cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit")
|
cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit")
|
||||||
real_cpu_limit: Optional[int] = Field(None, serialization_alias="realCpuLimit")
|
|
||||||
clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit")
|
clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit")
|
||||||
memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit")
|
memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit")
|
||||||
stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit")
|
stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit")
|
||||||
|
@ -101,23 +105,39 @@ class OptionalCmd(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class ExecutorWith(BaseModel):
|
class ExecutorWith(BaseModel):
|
||||||
default: Cmd
|
default: Cmd = Cmd()
|
||||||
cases: List[OptionalCmd]
|
cases: List[OptionalCmd] = []
|
||||||
|
|
||||||
|
|
||||||
class Executor(BaseModel):
|
class Executor(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
with_: ExecutorWith = Field(..., serialization_alias="with")
|
with_: ExecutorWith = Field(ExecutorWith(), serialization_alias="with")
|
||||||
|
|
||||||
|
|
||||||
class Parser(BaseModel):
|
class Parser(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
with_: Dict[str, Any] = Field(..., serialization_alias="with")
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
class Empty(BaseModel):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with_: BaseModel = Field(Empty(), serialization_alias="with")
|
||||||
|
else:
|
||||||
|
with_: Dict[str, Any] = Field({}, serialization_alias="with")
|
||||||
|
|
||||||
|
model_config = ConfigDict(validate_assignment=True)
|
||||||
|
|
||||||
|
@field_validator("with_", mode="before")
|
||||||
|
@classmethod
|
||||||
|
def validate_with(cls, v: Any) -> Dict[str, Any]:
|
||||||
|
if isinstance(v, BaseModel):
|
||||||
|
return v.model_dump(by_alias=True)
|
||||||
|
raise ValueError("Must be a BaseModel instance")
|
||||||
|
|
||||||
|
|
||||||
class StageDetail(BaseModel):
|
class StageDetail(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
group: str
|
group: str = ""
|
||||||
executor: Executor
|
executor: Executor
|
||||||
parsers: List[Parser]
|
parsers: List[Parser]
|
||||||
|
|
||||||
|
@ -130,26 +150,74 @@ class Stage(BaseModel):
|
||||||
output_path: str = Field(
|
output_path: str = Field(
|
||||||
"/tmp/joj3_result.json", serialization_alias="outputPath"
|
"/tmp/joj3_result.json", serialization_alias="outputPath"
|
||||||
) # nosec: B108
|
) # nosec: B108
|
||||||
stages: List[StageDetail]
|
stages: List[StageDetail] = []
|
||||||
|
pre_stages: List[StageDetail] = Field([], serialization_alias="preStages")
|
||||||
|
post_stages: List[StageDetail] = Field([], serialization_alias="postStages")
|
||||||
class Teapot(BaseModel):
|
|
||||||
log_path: str = Field(
|
|
||||||
"/home/tt/.cache/joint-teapot-debug.log", serialization_alias="logPath"
|
|
||||||
)
|
|
||||||
scoreboard_path: str = Field("scoreboard.csv", serialization_alias="scoreboardPath")
|
|
||||||
failed_table_path: str = Field(
|
|
||||||
"failed-table.md", serialization_alias="failedTablePath"
|
|
||||||
)
|
|
||||||
grading_repo_name: str = Field("", serialization_alias="gradingRepoName")
|
|
||||||
skip_issue: bool = Field(False, serialization_alias="skipIssue")
|
|
||||||
skip_scoreboard: bool = Field(False, serialization_alias="skipScoreboard")
|
|
||||||
skip_failed_table: bool = Field(False, serialization_alias="skipFailedTable")
|
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
name: str = "unknown"
|
name: str = ""
|
||||||
log_path: str = Field("", serialization_alias="logPath")
|
log_path: str = Field("", serialization_alias="logPath")
|
||||||
expire_unix_timestamp: int = Field(-1, serialization_alias="expireUnixTimestamp")
|
expire_unix_timestamp: int = Field(-1, serialization_alias="expireUnixTimestamp")
|
||||||
|
effective_unix_timestamp: int = Field(
|
||||||
|
-1, serialization_alias="effectiveUnixTimestamp"
|
||||||
|
)
|
||||||
|
actor_csv_path: str = Field("", serialization_alias="actorCsvPath")
|
||||||
|
max_total_score: int = Field(100, serialization_alias="maxTotalScore")
|
||||||
stage: Stage
|
stage: Stage
|
||||||
teapot: Teapot
|
|
||||||
|
|
||||||
|
class DummyConfig(BaseModel):
|
||||||
|
score: int = 0
|
||||||
|
comment: Optional[str] = None
|
||||||
|
force_quit_on_not_accepted: Optional[bool] = Field(
|
||||||
|
False, serialization_alias="forceQuitOnNotAccepted"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DiffOutputConfig(BaseModel):
|
||||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
also these also these `Optional`?
李衍志523370910113
commented
I guess some of the field have default within JOJ3, so I choose optional just to reduce the length of json previously I guess some of the field have default within JOJ3, so I choose optional just to reduce the length of json previously
张泊明518370910136
commented
better put all defaults here then we only need to check the code here better put all defaults here then we only need to check the code here
李衍志523370910113
commented
indeed. indeed.
|
|||||||
|
score: int = 100
|
||||||
|
file_name: str = Field("", serialization_alias="fileName")
|
||||||
|
answer_path: str = Field("", serialization_alias="answerPath")
|
||||||
|
force_quit_on_diff: bool = Field(False, serialization_alias="forceQuitOnDiff")
|
||||||
|
always_hide: bool = Field(False, serialization_alias="alwaysHide")
|
||||||
|
compare_space: bool = Field(False, serialization_alias="compareSpace")
|
||||||
|
|
||||||
|
|
||||||
|
class ResultDetailConfig(BaseModel):
|
||||||
|
score: int = 0
|
||||||
|
comment: str = ""
|
||||||
|
show_files: List[str] = Field([], serialization_alias="showFiles")
|
||||||
|
show_exit_status: bool = Field(True, serialization_alias="showExitStatus")
|
||||||
|
show_runtime: bool = Field(True, serialization_alias="showRuntime")
|
||||||
|
show_memory: bool = Field(False, serialization_alias="showMemory")
|
||||||
|
|
||||||
|
|
||||||
|
class KeywordConfig(BaseModel):
|
||||||
|
keywords: List[str] = []
|
||||||
|
score: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class KeywordMatchConfig(BaseModel):
|
||||||
|
matches: List[KeywordConfig] = []
|
||||||
|
|
||||||
|
|
||||||
|
class FileConfig(BaseModel):
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
class DiffCasesConfig(BaseModel):
|
||||||
|
outputs: List[DiffOutputConfig] = []
|
||||||
|
|
||||||
|
|
||||||
|
class DiffConfig(BaseModel):
|
||||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
what needs to be refined? what needs to be refined?
李衍志523370910113
commented
just feels bit waste since this outputs only have one field before I coded the logic, I wrote that comment without checking the details of diff parser. But it should be the best strategy to show the structures as well as give flexiblity for extension now. just feels bit waste since this outputs only have one field before I coded the logic, I wrote that comment without checking the details of diff parser. But it should be the best strategy to show the structures as well as give flexiblity for extension now.
|
|||||||
|
name: str = "diff"
|
||||||
|
cases: List[DiffCasesConfig] = []
|
||||||
|
|
||||||
|
|
||||||
|
class MsgConfig(BaseModel):
|
||||||
|
msg: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreConfig(BaseModel):
|
||||||
|
score: int = 0
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import Any, Dict, List, Type
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||||
|
|
||||||
|
from joj3_config_generator.models.common import Memory, Time
|
||||||
|
from joj3_config_generator.models.const import (
|
||||||
|
DEFAULT_CPU_LIMIT,
|
||||||
|
DEFAULT_FILE_LIMIT,
|
||||||
|
DEFAULT_MEMORY_LIMIT,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ParserResultDetail(BaseModel):
|
class ParserResultDetail(BaseModel):
|
||||||
|
@ -10,31 +18,136 @@ class ParserResultDetail(BaseModel):
|
||||||
mem: bool = True # Display memory usage
|
mem: bool = True # Display memory usage
|
||||||
stdout: bool = False # Display stdout messages
|
stdout: bool = False # Display stdout messages
|
||||||
stderr: bool = False # Display stderr messages
|
stderr: bool = False # Display stderr messages
|
||||||
|
exit_status: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
class ParserFile(BaseModel):
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ParserLog(BaseModel):
|
||||||
|
filename: str
|
||||||
|
msg: str = ""
|
||||||
|
level: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ParserDummy(BaseModel):
|
||||||
|
comment: str = ""
|
||||||
|
score: int = 0
|
||||||
|
force_quit: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class ParserKeyword(BaseModel):
|
||||||
|
keyword: List[str] = []
|
||||||
|
weight: List[int] = []
|
||||||
|
|
||||||
|
|
||||||
|
class Outputs(BaseModel):
|
||||||
|
score: int = 0
|
||||||
|
ignore_spaces: bool = True
|
||||||
|
hide: bool = False
|
||||||
|
force_quit: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class ParserDiff(BaseModel):
|
||||||
|
output: Outputs = Outputs()
|
||||||
|
|
||||||
|
|
||||||
class Files(BaseModel):
|
class Files(BaseModel):
|
||||||
import_: List[str] = Field(serialization_alias="import", validation_alias="import")
|
import_: List[str] = Field([], alias="import")
|
||||||
export: List[str]
|
export: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
|
class Limit(BaseModel):
|
||||||
|
mem: int = DEFAULT_MEMORY_LIMIT
|
||||||
|
cpu: int = DEFAULT_CPU_LIMIT
|
||||||
|
stdout: int = DEFAULT_FILE_LIMIT
|
||||||
|
stderr: int = DEFAULT_FILE_LIMIT
|
||||||
|
|
||||||
|
model_config = ConfigDict(validate_assignment=True)
|
||||||
|
|
||||||
|
@field_validator("cpu", mode="before")
|
||||||
|
@classmethod
|
||||||
|
def ensure_time(cls, v: Any) -> Time:
|
||||||
|
if isinstance(v, str):
|
||||||
|
return Time(v)
|
||||||
|
raise ValueError("Must be a string")
|
||||||
|
|
||||||
|
@field_validator("mem", "stdout", "stderr", mode="before")
|
||||||
|
@classmethod
|
||||||
|
def ensure_mem(cls, v: Any) -> Memory:
|
||||||
|
if isinstance(v, str):
|
||||||
|
return Memory(v)
|
||||||
|
raise ValueError("Must be a string")
|
||||||
|
|
||||||
|
|
||||||
|
class Parser(str, Enum):
|
||||||
|
CLANG_TIDY = "clangtidy"
|
||||||
|
CPPCHECK = "cppcheck"
|
||||||
|
CPPLINT = "cpplint"
|
||||||
|
KEYWORD = "keyword"
|
||||||
|
RESULT_STATUS = "result-status"
|
||||||
|
RESULT_DETAIL = "result-detail"
|
||||||
|
DUMMY = "dummy"
|
||||||
|
FILE = "file"
|
||||||
|
DIFF = "diff"
|
||||||
|
|
||||||
|
|
||||||
class Stage(BaseModel):
|
class Stage(BaseModel):
|
||||||
name: str # Stage name
|
name: str = "" # Stage name
|
||||||
command: str # Command to run
|
env: List[str] = []
|
||||||
files: Files # Files to import and export
|
command: str = "" # Command to run
|
||||||
score: int # Score for the task
|
files: Files = Files()
|
||||||
parsers: List[str] # list of parsers
|
in_: str = Field("", alias="in")
|
||||||
result_detail: ParserResultDetail = (
|
out_: str = Field("", alias="out")
|
||||||
ParserResultDetail()
|
score: int = 0
|
||||||
) # for result-detail parser
|
parsers: List[Parser] = [] # list of parsers
|
||||||
|
limit: Limit = Limit()
|
||||||
|
dummy: ParserDummy = ParserDummy()
|
||||||
|
result_status: ParserDummy = Field(ParserDummy(), alias="result-status")
|
||||||
|
keyword: ParserKeyword = ParserKeyword()
|
||||||
|
clangtidy: ParserKeyword = ParserKeyword()
|
||||||
|
cppcheck: ParserKeyword = ParserKeyword()
|
||||||
|
cpplint: ParserKeyword = ParserKeyword()
|
||||||
|
result_detail: ParserResultDetail = Field(
|
||||||
|
ParserResultDetail(), alias="result-detail"
|
||||||
|
)
|
||||||
|
file: ParserFile = ParserFile()
|
||||||
|
skip: List[str] = []
|
||||||
|
|
||||||
|
# cases related
|
||||||
|
cases: Dict[str, "Stage"] = {}
|
||||||
|
diff: ParserDiff = ParserDiff()
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
@model_validator(mode="before")
|
||||||
|
@classmethod
|
||||||
|
def gather_cases(cls: Type["Stage"], values: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
cases = {k: v for k, v in values.items() if k.startswith("case")}
|
||||||
|
for key in cases:
|
||||||
|
values.pop(key)
|
||||||
|
values["cases"] = {k: v for k, v in cases.items()}
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
class Release(BaseModel):
|
class Release(BaseModel):
|
||||||
deadline: Optional[datetime] # RFC 3339 formatted date-time with offset
|
end_time: datetime = datetime.now() + timedelta(
|
||||||
|
days=365
|
||||||
|
) # RFC 3339 formatted date-time with offset
|
||||||
|
begin_time: datetime = datetime.fromtimestamp(
|
||||||
|
0
|
||||||
|
) # RFC 3339 formatted date-time with offset
|
||||||
|
|
||||||
|
|
||||||
|
class Task(BaseModel):
|
||||||
|
type_: str = Field("unknown", serialization_alias="type", validation_alias="type")
|
||||||
|
name: str = "unknown"
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
root: Path = Path(".")
|
root: Path = Path(".")
|
||||||
path: Path = Path("task.toml")
|
path: Path = Path("task.toml")
|
||||||
task: str # Task name (e.g., hw3 ex5)
|
task: Task = Task() # Task name (e.g., hw3 ex5)
|
||||||
release: Release # Release configuration
|
release: Release = Release() # Release configuration
|
||||||
stages: List[Stage] # list of stage configurations
|
stages: List[Stage] = [] # list of stage configurations
|
||||||
|
|
0
joj3_config_generator/processers/__init__.py
Normal file
108
joj3_config_generator/processers/repo.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from joj3_config_generator.models import repo, result
|
||||||
|
from joj3_config_generator.models.const import CACHE_ROOT, TEAPOT_CONFIG_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
def get_teapot_stage(repo_conf: repo.Config) -> result.StageDetail:
|
||||||
|
args = [
|
||||||
|
"/usr/local/bin/joint-teapot",
|
||||||
|
"joj3-all-env",
|
||||||
|
str(TEAPOT_CONFIG_ROOT / "teapot.env"),
|
||||||
|
"--grading-repo-name",
|
||||||
|
repo_conf.grading_repo_name,
|
||||||
|
"--max-total-score",
|
||||||
|
str(repo_conf.max_total_score),
|
||||||
|
]
|
||||||
|
|
||||||
|
stage_conf = result.StageDetail(
|
||||||
|
name="teapot",
|
||||||
|
executor=result.Executor(
|
||||||
|
name="local",
|
||||||
|
with_=result.ExecutorWith(
|
||||||
|
default=result.Cmd(
|
||||||
|
args=args,
|
||||||
|
env=[f"LOG_FILE_PATH={CACHE_ROOT}/joint-teapot-debug.log"],
|
||||||
|
),
|
||||||
|
cases=[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
parsers=[result.Parser(name="log", with_=result.MsgConfig(msg="joj3 summary"))],
|
||||||
|
)
|
||||||
|
return stage_conf
|
||||||
|
|
||||||
|
|
||||||
|
def get_health_check_args(repo_conf: repo.Config) -> List[str]:
|
||||||
|
return [
|
||||||
|
"/usr/local/bin/repo-health-checker",
|
||||||
|
"-root=.",
|
||||||
|
f"-repoSize={str(repo_conf.max_size)}",
|
||||||
|
*[f"-meta={meta}" for meta in repo_conf.files.required],
|
||||||
|
f"-checkFileSumList={','.join(get_hashs(repo_conf))}",
|
||||||
|
f"-checkFileNameList={','.join(repo_conf.files.immutable)}",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_teapot_check_args(repo_conf: repo.Config) -> List[str]:
|
||||||
|
return [
|
||||||
|
"/usr/local/bin/joint-teapot",
|
||||||
|
"joj3-check-env",
|
||||||
|
str(TEAPOT_CONFIG_ROOT / "teapot.env"),
|
||||||
|
"--grading-repo-name",
|
||||||
|
repo_conf.grading_repo_name,
|
||||||
|
"--group-config",
|
||||||
|
",".join(
|
||||||
|
f"{name}={max_count}:{time_period}"
|
||||||
|
for name, max_count, time_period in zip(
|
||||||
|
repo_conf.groups.name,
|
||||||
|
repo_conf.groups.max_count,
|
||||||
|
repo_conf.groups.time_period_hour,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_health_check_stage(repo_conf: repo.Config) -> result.StageDetail:
|
||||||
|
health_check_stage = result.StageDetail(
|
||||||
|
name="Health Check",
|
||||||
|
group="",
|
||||||
|
executor=result.Executor(
|
||||||
|
name="local",
|
||||||
|
with_=result.ExecutorWith(
|
||||||
|
default=result.Cmd(),
|
||||||
|
cases=[
|
||||||
|
result.OptionalCmd(
|
||||||
|
args=get_health_check_args(repo_conf),
|
||||||
|
),
|
||||||
|
result.OptionalCmd(
|
||||||
|
args=get_teapot_check_args(repo_conf),
|
||||||
|
env=[f"LOG_FILE_PATH={CACHE_ROOT}/joint-teapot-debug.log"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
parsers=[
|
||||||
|
result.Parser(name="healthcheck", with_=result.ScoreConfig(score=1)),
|
||||||
|
result.Parser(name="debug", with_=result.ScoreConfig(score=0)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return health_check_stage
|
||||||
|
|
||||||
|
|
||||||
|
def calc_sha256sum(file_path: Path) -> str:
|
||||||
|
sha256_hash = hashlib.sha256()
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
for byte_block in iter(lambda: f.read(64 * 1024), b""):
|
||||||
|
sha256_hash.update(byte_block)
|
||||||
|
return sha256_hash.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def get_hashs(repo_conf: repo.Config) -> List[str]:
|
||||||
|
base_dir = (repo_conf.root / repo_conf.path).parent
|
||||||
|
immutable_dir = base_dir / "immutable_files"
|
||||||
|
immutable_files = [
|
||||||
|
immutable_dir / Path(file).name for file in repo_conf.files.immutable
|
||||||
|
]
|
||||||
|
return [calc_sha256sum(file) for file in immutable_files]
|
206
joj3_config_generator/processers/task.py
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
import re
|
||||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
Path should not be relative to Path should not be relative to `JOJ3_CONFIG_ROOT` in this file, should be relative to `task.toml` dir
李衍志523370910113
commented
I reckon you said things is relative to I reckon you said things is relative to `JOJ3_CONFIG_ROOT` in JTC before. we have a `task.type` in `task.toml` to mend the path
张泊明518370910136
commented
`config.path` is relative to `JOJ3_CONFIG_ROOT`.
李衍志523370910113
commented
could you explain further? I m not quite sure my understanding is clear. could you explain further? I m not quite sure my understanding is clear.
张泊明518370910136
commented
In In `joj3_config_generator/models/task.py`, `Config.path` is relative to `JOJ3_CONFIG_ROOT`, so `task.toml` will located at `JOJ3_CONFIG_ROOT / task_conf.path` in JTC.
|
|||||||
|
import shlex
|
||||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
Some Some `with_.update` is still using raw dict, not model with `model_dump`.
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Callable, Dict, List, Tuple
|
||||||
|
|
||||||
|
from joj3_config_generator.models import result, task
|
||||||
|
from joj3_config_generator.models.common import Memory, Time
|
||||||
|
from joj3_config_generator.models.const import JOJ3_CONFIG_ROOT
|
||||||
|
from joj3_config_generator.models.task import Parser as ParserEnum
|
||||||
|
|
||||||
|
|
||||||
|
def get_conf_stage(
|
||||||
|
task_conf: task.Config,
|
||||||
|
task_stage: task.Stage,
|
||||||
|
cached: Dict[str, None],
|
||||||
|
) -> result.StageDetail:
|
||||||
|
conf_stage = result.StageDetail(
|
||||||
|
name=task_stage.name,
|
||||||
|
# group is determined by adding between "[]" in the name of the task
|
||||||
|
group=(
|
||||||
|
match.group(1)
|
||||||
|
if (match := re.search(r"\[([^\[\]]+)\]", task_stage.name or ""))
|
||||||
|
else ""
|
||||||
|
),
|
||||||
|
executor=result.Executor(
|
||||||
|
name="sandbox",
|
||||||
|
with_=get_executor_with(task_stage, cached),
|
||||||
|
),
|
||||||
|
parsers=([result.Parser(name=parser) for parser in task_stage.parsers]),
|
||||||
|
)
|
||||||
|
processed_dict = get_processed_dict(task_stage)
|
||||||
|
for idx, parser in enumerate(task_stage.parsers):
|
||||||
|
if parser in processed_dict:
|
||||||
|
fn, parser_model = processed_dict[parser]
|
||||||
|
fn(parser_model, conf_stage.parsers[idx])
|
||||||
|
elif parser == ParserEnum.DIFF:
|
||||||
|
fix_diff(
|
||||||
|
task_stage,
|
||||||
|
conf_stage.parsers[idx],
|
||||||
|
conf_stage.executor,
|
||||||
|
JOJ3_CONFIG_ROOT / task_conf.path.parent,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
return conf_stage
|
||||||
|
|
||||||
|
|
||||||
|
def get_processed_dict(
|
||||||
|
task_stage: task.Stage,
|
||||||
|
) -> Dict[ParserEnum, Tuple[Callable[[Any, result.Parser], None], Any]]:
|
||||||
|
processed_dict: Dict[
|
||||||
|
ParserEnum, Tuple[Callable[[Any, result.Parser], None], Any]
|
||||||
|
] = {
|
||||||
|
ParserEnum.CLANG_TIDY: (fix_keyword, task_stage.clangtidy),
|
||||||
|
ParserEnum.KEYWORD: (fix_keyword, task_stage.keyword),
|
||||||
|
ParserEnum.CPPCHECK: (fix_keyword, task_stage.cppcheck),
|
||||||
|
ParserEnum.CPPLINT: (fix_keyword, task_stage.cpplint),
|
||||||
|
ParserEnum.RESULT_DETAIL: (fix_result_detail, task_stage.result_detail),
|
||||||
|
ParserEnum.DUMMY: (fix_dummy, task_stage.dummy),
|
||||||
|
ParserEnum.RESULT_STATUS: (fix_dummy, task_stage.result_status),
|
||||||
|
ParserEnum.FILE: (fix_file, task_stage.file),
|
||||||
|
}
|
||||||
|
return processed_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_executor_with(
|
||||||
|
task_stage: task.Stage, cached: Dict[str, None]
|
||||||
|
) -> result.ExecutorWith:
|
||||||
|
file_import = task_stage.files.import_
|
||||||
|
copy_in_files = (file for file in file_import if file not in cached)
|
||||||
|
file_export = task_stage.files.export
|
||||||
|
copy_out_files = ["stdout", "stderr"]
|
||||||
|
executor_with_config = result.ExecutorWith(
|
||||||
|
default=result.Cmd(
|
||||||
|
args=shlex.split(task_stage.command),
|
||||||
|
copy_in={
|
||||||
|
file: result.LocalFile(src=str(JOJ3_CONFIG_ROOT / file))
|
||||||
|
# all copyin files store in this tools folder
|
||||||
|
# TODO: are there any corner cases?
|
||||||
|
for file in copy_in_files
|
||||||
|
},
|
||||||
|
copy_out=copy_out_files,
|
||||||
|
copy_in_cached={file: file for file in cached},
|
||||||
|
copy_out_cached=file_export,
|
||||||
|
cpu_limit=Time(task_stage.limit.cpu),
|
||||||
|
clock_limit=2 * Time(task_stage.limit.cpu),
|
||||||
|
memory_limit=Memory(task_stage.limit.mem),
|
||||||
|
stderr=result.Collector(
|
||||||
|
name="stderr", pipe=True, max=Memory(task_stage.limit.stderr)
|
||||||
|
),
|
||||||
|
stdout=result.Collector(
|
||||||
|
name="stdout", pipe=True, max=Memory(task_stage.limit.stdout)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
cases=[],
|
||||||
|
)
|
||||||
|
for file in file_export:
|
||||||
|
cached[file] = None
|
||||||
|
return executor_with_config
|
||||||
|
|
||||||
|
|
||||||
|
def fix_keyword(
|
||||||
|
keyword_config: task.ParserKeyword, keyword_parser: result.Parser
|
||||||
|
) -> None:
|
||||||
|
if len(keyword_config.keyword) != len(keyword_config.weight):
|
||||||
|
raise ValueError("Keywords and weights must have the same length")
|
||||||
|
score_groups: Dict[int, List[str]] = {}
|
||||||
|
for keyword, score in zip(keyword_config.keyword, keyword_config.weight):
|
||||||
|
score_groups.setdefault(score, []).append(keyword)
|
||||||
|
keyword_parser.with_ = result.KeywordMatchConfig(
|
||||||
|
matches=[
|
||||||
|
result.KeywordConfig(keywords=keywords, score=score)
|
||||||
|
for score, keywords in score_groups.items()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_result_detail(
|
||||||
|
result_detail_parser_config: task.ParserResultDetail,
|
||||||
|
result_detail_parser: result.Parser,
|
||||||
|
) -> None:
|
||||||
|
show_files = []
|
||||||
|
if result_detail_parser_config.stdout:
|
||||||
|
show_files.append("stdout")
|
||||||
|
if result_detail_parser_config.stderr:
|
||||||
|
show_files.append("stderr")
|
||||||
|
result_detail_parser.with_ = result.ResultDetailConfig(
|
||||||
|
score=0,
|
||||||
|
comment="",
|
||||||
|
show_files=show_files,
|
||||||
|
show_exit_status=result_detail_parser_config.exit_status,
|
||||||
|
show_runtime=result_detail_parser_config.time,
|
||||||
|
show_memory=result_detail_parser_config.mem,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_dummy(
|
||||||
|
dummy_parser_config: task.ParserDummy, dummy_parser: result.Parser
|
||||||
|
) -> None:
|
||||||
|
# we don't use dummy parser in real application
|
||||||
|
dummy_parser.with_ = result.DummyConfig(
|
||||||
|
score=dummy_parser_config.score,
|
||||||
|
comment=dummy_parser_config.comment,
|
||||||
|
force_quit_on_not_accepted=dummy_parser_config.force_quit,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_file(file_parser_config: task.ParserFile, file_parser: result.Parser) -> None:
|
||||||
|
file_parser.with_ = result.FileConfig(name=file_parser_config.name)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_diff(
|
||||||
|
task_stage: task.Stage,
|
||||||
|
diff_parser_config: result.Parser,
|
||||||
|
diff_executor: result.Executor,
|
||||||
|
base_dir: Path,
|
||||||
|
) -> None:
|
||||||
|
skip = task_stage.skip
|
||||||
|
cases = task_stage.cases
|
||||||
|
finalized_cases = [case for case in cases if case not in skip]
|
||||||
|
|
||||||
|
stage_cases = []
|
||||||
|
parser_cases = []
|
||||||
|
|
||||||
|
for case in finalized_cases:
|
||||||
|
case_stage = task_stage.cases.get(case) if task_stage.cases else None
|
||||||
|
if not case_stage:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cpu_limit = case_stage.limit.cpu
|
||||||
|
clock_limit = 2 * case_stage.limit.cpu
|
||||||
|
memory_limit = case_stage.limit.mem
|
||||||
|
command = case_stage.command
|
||||||
|
stdin = case_stage.in_ if case_stage.in_ != "" else f"{case}.in"
|
||||||
|
stdout = case_stage.out_ if case_stage.out_ != "" else f"{case}.out"
|
||||||
|
|
||||||
|
stage_cases.append(
|
||||||
|
result.OptionalCmd(
|
||||||
|
stdin=result.LocalFile(
|
||||||
|
src=str(base_dir / stdin),
|
||||||
|
),
|
||||||
|
args=shlex.split(command) if command else None,
|
||||||
|
cpu_limit=cpu_limit,
|
||||||
|
clock_limit=clock_limit,
|
||||||
|
memory_limit=memory_limit,
|
||||||
|
proc_limit=50,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
diff_output = case_stage.diff.output
|
||||||
|
parser_cases.append(
|
||||||
|
result.DiffCasesConfig(
|
||||||
|
outputs=[
|
||||||
|
result.DiffOutputConfig(
|
||||||
|
score=diff_output.score,
|
||||||
|
file_name="stdout",
|
||||||
|
answer_path=str(base_dir / stdout),
|
||||||
|
force_quit_on_diff=diff_output.force_quit,
|
||||||
|
always_hide=diff_output.hide,
|
||||||
|
compare_space=not diff_output.ignore_spaces,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
diff_executor.with_.cases = stage_cases
|
||||||
|
diff_parser_config.with_ = result.DiffConfig(name="diff", cases=parser_cases)
|
|
@ -2,7 +2,7 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
from sys import stderr
|
from sys import stderr
|
||||||
from types import FrameType
|
from types import FrameType
|
||||||
from typing import Optional
|
from typing import Optional, Union
|
||||||
|
|
||||||
from loguru import logger as logger
|
from loguru import logger as logger
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from loguru import logger as logger
|
||||||
# recipe from https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging
|
# recipe from https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging
|
||||||
class InterceptHandler(logging.Handler):
|
class InterceptHandler(logging.Handler):
|
||||||
def emit(self, record: logging.LogRecord) -> None:
|
def emit(self, record: logging.LogRecord) -> None:
|
||||||
level: str | int
|
level: Union[str, int]
|
||||||
try:
|
try:
|
||||||
level = logger.level(record.levelname).name
|
level = logger.level(record.levelname).name
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -12,6 +12,7 @@ dependencies = [
|
||||||
"pydantic>=2.9.2",
|
"pydantic>=2.9.2",
|
||||||
"inquirer>=3.4.0",
|
"inquirer>=3.4.0",
|
||||||
"rtoml>=0.11.0",
|
"rtoml>=0.11.0",
|
||||||
|
"humanfriendly>=10.0",
|
||||||
]
|
]
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
authors = [{ name = "JOJ3-dev", email = "joj3@focs.ji.sjtu.edu.cn" }]
|
authors = [{ name = "JOJ3-dev", email = "joj3@focs.ji.sjtu.edu.cn" }]
|
||||||
|
|
33
tests/convert/basic/immutable_files/.gitattributes
vendored
Normal 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/convert/basic/immutable_files/.gitignore
vendored
Normal 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
|
19
tests/convert/basic/immutable_files/push.yaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
name: Run JOJ3 on Push
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
container:
|
||||||
|
runs-on: focs-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: actions/checkout@focs
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run joj3
|
||||||
|
run: |
|
||||||
|
sudo -E -u tt joj3 -conf-root /home/tt/.config/joj/tests/homework
|
21
tests/convert/basic/immutable_files/release.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: Run JOJ3 on Release
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
runs-on: focs-latest-slim
|
||||||
|
container:
|
||||||
|
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: actions/checkout@focs
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run joj3
|
||||||
|
run: |
|
||||||
|
sudo -E -u tt joj3 -conf-root "/home/tt/.config/joj/tests/homework" -conf-name "conf-release.json" -tag "${{ github.ref_name }}"
|
|
@ -1,10 +1,16 @@
|
||||||
teaching_team = ["prof_john", "ta_alice", "ta_bob"]
|
grading_repo_name = "ece280-joj"
|
||||||
max_size = 50.5
|
|
||||||
release_tags = ["v1.0", "v2.0", "final"]
|
|
||||||
sandbox_token = "test"
|
sandbox_token = "test"
|
||||||
|
# reconfigure later
|
||||||
|
max_total_score = 100
|
||||||
|
max_size = 50.5
|
||||||
|
|
||||||
|
# for tests
|
||||||
|
[groups]
|
||||||
|
name = ["joj", "run"]
|
||||||
|
max_count = [1000, 1000]
|
||||||
|
time_period_hour = [24, 24]
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
whitelist_patterns = ["*.py", "*.txt", "*.md"]
|
required = ["README.md", "Changelog.md"]
|
||||||
whitelist_file = ".whitelist"
|
immutable = [".gitignore", ".gitattributes",".gitea/workflows/push.yaml", ".gitea/workflows/release.yaml"]
|
||||||
required = ["main.py", "README.md"]
|
|
||||||
immutable = ["config.yaml", "setup.py"]
|
|
||||||
|
|
|
@ -1,47 +1,52 @@
|
||||||
{
|
{
|
||||||
"name": "hw3 ex5",
|
"name": "hw7 ex2",
|
||||||
"logPath": "hw3_ex5.log",
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
"expireUnixTimestamp": 1729267140,
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
"stage": {
|
"stage": {
|
||||||
"sandboxExecServer": "172.17.0.1:5051",
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
"sandboxToken": "test",
|
"sandboxToken": "test",
|
||||||
"outputPath": "/tmp/joj3_result.json",
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
"stages": [
|
"stages": [
|
||||||
{
|
{
|
||||||
"name": "judge_base",
|
"name": "Health Check",
|
||||||
"group": "hw3 ex5",
|
"group": "",
|
||||||
"executor": {
|
"executor": {
|
||||||
"name": "sandbox",
|
"name": "local",
|
||||||
"with": {
|
"with": {
|
||||||
"default": {
|
"default": {
|
||||||
"args": [
|
"args": [],
|
||||||
"./matlab-joj",
|
|
||||||
"./h3/ex5.m"
|
|
||||||
],
|
|
||||||
"env": [],
|
"env": [],
|
||||||
"cpuLimit": 0,
|
"stdin": {
|
||||||
"realCpuLimit": 0,
|
"content": ""
|
||||||
"clockLimit": 0,
|
},
|
||||||
"memoryLimit": 0,
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
"stackLimit": 0,
|
"stackLimit": 0,
|
||||||
"procLimit": 0,
|
"procLimit": 50,
|
||||||
"cpuRateLimit": 0,
|
"cpuRateLimit": 0,
|
||||||
"cpuSetLimit": "",
|
"cpuSetLimit": "",
|
||||||
"copyIn": {
|
"copyIn": {},
|
||||||
"tools/matlab-joj": {
|
|
||||||
"src": "tools/matlab-joj"
|
|
||||||
},
|
|
||||||
"tools/matlab_formatter.py": {
|
|
||||||
"src": "tools/matlab_formatter.py"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"copyInCached": {},
|
"copyInCached": {},
|
||||||
"copyInDir": ".",
|
"copyInDir": ".",
|
||||||
"copyOut": [],
|
"copyOut": [
|
||||||
"copyOutCached": [
|
"stdout",
|
||||||
"output/ex5_results.txt",
|
"stderr"
|
||||||
"output/ex5_logs.txt"
|
|
||||||
],
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
"copyOutMax": 0,
|
"copyOutMax": 0,
|
||||||
"copyOutDir": "",
|
"copyOutDir": "",
|
||||||
"tty": false,
|
"tty": false,
|
||||||
|
@ -49,59 +54,98 @@
|
||||||
"dataSegmentLimit": false,
|
"dataSegmentLimit": false,
|
||||||
"addressSpaceLimit": false
|
"addressSpaceLimit": false
|
||||||
},
|
},
|
||||||
"cases": []
|
"cases": [
|
||||||
|
{
|
||||||
|
"args": [
|
||||||
|
"/usr/local/bin/repo-health-checker",
|
||||||
|
"-root=.",
|
||||||
|
"-repoSize=50.5",
|
||||||
|
"-meta=README.md",
|
||||||
|
"-meta=Changelog.md",
|
||||||
|
"-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,2ba059f3977e2e3dee6cacbfbf0ba2578baa1b8e04b4977aec400868b6e49856,bf7d181362affdcc72aac33f3520e4e6371adc48ea62a6f24524b4a3e76724c5",
|
||||||
|
"-checkFileNameList=.gitignore,.gitattributes,.gitea/workflows/push.yaml,.gitea/workflows/release.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": [
|
||||||
|
"/usr/local/bin/joint-teapot",
|
||||||
|
"joj3-check-env",
|
||||||
|
"/home/tt/.config/teapot/teapot.env",
|
||||||
|
"--grading-repo-name",
|
||||||
|
"ece280-joj",
|
||||||
|
"--group-config",
|
||||||
|
"joj=1000:24,run=1000:24"
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
"LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"parsers": [
|
"parsers": [
|
||||||
{
|
{
|
||||||
"name": "diff",
|
"name": "healthcheck",
|
||||||
"with": {}
|
"with": {
|
||||||
|
"score": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "result-detail",
|
"name": "debug",
|
||||||
"with": {
|
"with": {
|
||||||
"time": false,
|
"score": 0
|
||||||
"mem": false,
|
|
||||||
"stdout": false,
|
|
||||||
"stderr": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "judge_base2",
|
"name": "Compilation",
|
||||||
"group": "hw3 ex5",
|
"group": "",
|
||||||
"executor": {
|
"executor": {
|
||||||
"name": "sandbox",
|
"name": "sandbox",
|
||||||
"with": {
|
"with": {
|
||||||
"default": {
|
"default": {
|
||||||
"args": [
|
"args": [
|
||||||
"./matlab-joj",
|
"./tools/compile"
|
||||||
"./h3/ex5.m"
|
|
||||||
],
|
],
|
||||||
"env": [],
|
"env": [],
|
||||||
"cpuLimit": 0,
|
"stdin": {
|
||||||
"realCpuLimit": 0,
|
"content": ""
|
||||||
"clockLimit": 0,
|
},
|
||||||
"memoryLimit": 0,
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
"stackLimit": 0,
|
"stackLimit": 0,
|
||||||
"procLimit": 0,
|
"procLimit": 50,
|
||||||
"cpuRateLimit": 0,
|
"cpuRateLimit": 0,
|
||||||
"cpuSetLimit": "",
|
"cpuSetLimit": "",
|
||||||
"copyIn": {
|
"copyIn": {
|
||||||
"tools/matlab-joj": {
|
"tools/compile": {
|
||||||
"src": "tools/matlab-joj"
|
"src": "/home/tt/.config/joj/tools/compile"
|
||||||
},
|
|
||||||
"tools/matlab_formatter.py": {
|
|
||||||
"src": "tools/matlab_formatter.py"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"copyInCached": {},
|
"copyInCached": {},
|
||||||
"copyInDir": ".",
|
"copyInDir": ".",
|
||||||
"copyOut": [],
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
"copyOutCached": [
|
"copyOutCached": [
|
||||||
"output/ex5_results2.txt",
|
"h7/build/ex2",
|
||||||
"output/ex5_logs2.txt"
|
"h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json"
|
||||||
],
|
],
|
||||||
"copyOutMax": 0,
|
"copyOutMax": 0,
|
||||||
"copyOutDir": "",
|
"copyOutDir": "",
|
||||||
|
@ -115,29 +159,691 @@
|
||||||
},
|
},
|
||||||
"parsers": [
|
"parsers": [
|
||||||
{
|
{
|
||||||
"name": "diff",
|
"name": "result-detail",
|
||||||
"with": {}
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-status",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "Congratulations! Your code compiled successfully.",
|
||||||
|
"forceQuitOnNotAccepted": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[cq] Filelength",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"./tools/filelength",
|
||||||
|
"400",
|
||||||
|
"300",
|
||||||
|
"*.cpp",
|
||||||
|
"*.h"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"tools/filelength": {
|
||||||
|
"src": "/home/tt/.config/joj/tools/filelength"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {
|
||||||
|
"h7/build/ex2": "h7/build/ex2",
|
||||||
|
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||||
|
},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "keyword",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"max"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"recommended"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "result-detail",
|
"name": "result-detail",
|
||||||
"with": {
|
"with": {
|
||||||
"time": true,
|
"score": 0,
|
||||||
"mem": true,
|
"comment": "",
|
||||||
"stdout": false,
|
"showFiles": [
|
||||||
"stderr": false
|
"stdout"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[cq] Clang-tidy",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"run-clang-tidy-18",
|
||||||
|
"-header-filter=.*",
|
||||||
|
"-quiet",
|
||||||
|
"-load=/usr/local/lib/libcodequality.so",
|
||||||
|
"-p",
|
||||||
|
"h7/build",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 4194304,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"tests/homework/h7/.clang-tidy": {
|
||||||
|
"src": "/home/tt/.config/joj/tests/homework/h7/.clang-tidy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {
|
||||||
|
"h7/build/ex2": "h7/build/ex2",
|
||||||
|
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||||
|
},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "clangtidy",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"codequality-unchecked-malloc-result",
|
||||||
|
"readability-duplicate-include",
|
||||||
|
"readability-identifier-naming",
|
||||||
|
"readability-redundant",
|
||||||
|
"readability-misplaced-array-index",
|
||||||
|
"cppcoreguidelines-init-variables",
|
||||||
|
"bugprone-suspicious-string-compare",
|
||||||
|
"google-global-names-in-headers",
|
||||||
|
"clang-diagnostic",
|
||||||
|
"clang-analyzer",
|
||||||
|
"misc",
|
||||||
|
"performance",
|
||||||
|
"portability"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"codequality-no-global-variables",
|
||||||
|
"codequality-no-header-guard",
|
||||||
|
"codequality-no-fflush-stdin"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability-function-size"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability-misleading-indentation"
|
||||||
|
],
|
||||||
|
"score": 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stdout"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[cq] Cppcheck",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"cppcheck",
|
||||||
|
"--template={\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}",
|
||||||
|
"--force",
|
||||||
|
"--enable=all",
|
||||||
|
"--suppress=missingIncludeSystem",
|
||||||
|
"--quiet",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 8388608,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {
|
||||||
|
"h7/build/ex2": "h7/build/ex2",
|
||||||
|
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||||
|
},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "keyword",
|
||||||
|
"with": {
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cppcheck",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"error"
|
||||||
|
],
|
||||||
|
"score": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"warning",
|
||||||
|
"portability",
|
||||||
|
"performance",
|
||||||
|
"style"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clangtidy",
|
||||||
|
"with": {
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpplint",
|
||||||
|
"with": {
|
||||||
|
"matches": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-status",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"forceQuitOnNotAccepted": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file",
|
||||||
|
"with": {
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dummy",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"forceQuitOnNotAccepted": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "diff",
|
||||||
|
"with": {
|
||||||
|
"name": "diff",
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[cq] Cpplint",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"cpplint",
|
||||||
|
"--linelength=120",
|
||||||
|
"--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use",
|
||||||
|
"--recursive",
|
||||||
|
"--exclude=build",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 68157440,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {
|
||||||
|
"h7/build/ex2": "h7/build/ex2",
|
||||||
|
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||||
|
},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "cpplint",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"runtime"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"build"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "[joj] ex2-asan",
|
||||||
|
"group": "joj",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"./h7/build/ex2-asan",
|
||||||
|
"-a"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {
|
||||||
|
"h7/build/ex2": "h7/build/ex2",
|
||||||
|
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||||
|
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||||
|
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||||
|
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||||
|
},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"stdin": {
|
||||||
|
"src": "/home/tt/.config/joj/basic/case0.in"
|
||||||
|
},
|
||||||
|
"cpuLimit": 500000000,
|
||||||
|
"clockLimit": 1000000000,
|
||||||
|
"memoryLimit": 5242880,
|
||||||
|
"procLimit": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stdin": {
|
||||||
|
"src": "/home/tt/.config/joj/basic/case1.in"
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 5242880,
|
||||||
|
"procLimit": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "diff",
|
||||||
|
"with": {
|
||||||
|
"name": "diff",
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"score": 5,
|
||||||
|
"fileName": "stdout",
|
||||||
|
"answerPath": "/home/tt/.config/joj/basic/case0.out",
|
||||||
|
"forceQuitOnDiff": false,
|
||||||
|
"alwaysHide": false,
|
||||||
|
"compareSpace": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"score": 5,
|
||||||
|
"fileName": "stdout",
|
||||||
|
"answerPath": "/home/tt/.config/joj/basic/case1.out",
|
||||||
|
"forceQuitOnDiff": false,
|
||||||
|
"alwaysHide": false,
|
||||||
|
"compareSpace": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": true,
|
||||||
|
"showMemory": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": [
|
||||||
|
{
|
||||||
|
"name": "teapot",
|
||||||
|
"group": "",
|
||||||
|
"executor": {
|
||||||
|
"name": "local",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"/usr/local/bin/joint-teapot",
|
||||||
|
"joj3-all-env",
|
||||||
|
"/home/tt/.config/teapot/teapot.env",
|
||||||
|
"--grading-repo-name",
|
||||||
|
"ece280-joj",
|
||||||
|
"--max-total-score",
|
||||||
|
"100"
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
"LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log"
|
||||||
|
],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "log",
|
||||||
|
"with": {
|
||||||
|
"msg": "joj3 summary"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"teapot": {
|
|
||||||
"logPath": "/home/tt/.cache/joint-teapot-debug.log",
|
|
||||||
"scoreboardPath": "scoreboard.csv",
|
|
||||||
"failedTablePath": "failed-table.md",
|
|
||||||
"gradingRepoName": "",
|
|
||||||
"skipIssue": false,
|
|
||||||
"skipScoreboard": false,
|
|
||||||
"skipFailedTable": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,102 @@
|
||||||
task = "hw3 ex5"
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
[release]
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
deadline = "2024-10-18T23:59:00+08:00"
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
[[stages]]
|
[[stages]]
|
||||||
name = "judge_base"
|
name = "Compilation"
|
||||||
command = "./matlab-joj ./h3/ex5.m"
|
command = "./tools/compile" # eg. script running cmake commands
|
||||||
score = 100
|
files.import = [ "tools/compile" ]
|
||||||
parsers = ["diff", "result-detail"]
|
files.export = [ "h7/build/ex2", "h7/build/ex2-asan", "h7/build/ex2-ubsan", "h7/build/ex2-msan", "h7/build/compile_commands.json" ]
|
||||||
|
score = 1
|
||||||
|
|
||||||
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
|
# compile parsers
|
||||||
files.export = ["output/ex5_results.txt", "output/ex5_logs.txt"]
|
parsers = [ "result-detail", "result-status" ]
|
||||||
|
result-status.comment = "Congratulations! Your code compiled successfully."
|
||||||
result_detail.time = false
|
result-detail.exitstatus = true
|
||||||
result_detail.mem = false
|
result-detail.stderr = true
|
||||||
result_detail.stderr = true
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
||||||
|
result-status.force_quit = true
|
||||||
|
|
||||||
[[stages]]
|
[[stages]]
|
||||||
name = "judge_base2"
|
name = "[cq] Filelength"
|
||||||
command = "./matlab-joj ./h3/ex5.m"
|
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||||
score = 80
|
files.import = [ "tools/filelength" ]
|
||||||
parsers = ["diff", "result-detail"]
|
|
||||||
|
|
||||||
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
|
parsers = [ "keyword", "result-detail" ]
|
||||||
files.export = ["output/ex5_results2.txt", "output/ex5_logs2.txt"]
|
keyword.keyword = [ "max", "recommended"]
|
||||||
|
keyword.weight = [ 20, 10 ]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stdout = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
||||||
|
|
||||||
result_detail.time = true
|
[[stages]]
|
||||||
result_detail.mem = true
|
name = "[cq] Clang-tidy"
|
||||||
result_detail.stderr = false
|
command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p h7/build h7/ex2.cpp"
|
||||||
|
files.import = [ "tests/homework/h7/.clang-tidy", "h7/build/compile_commands.json" ]
|
||||||
|
limit.stdout = "4m"
|
||||||
|
|
||||||
|
parsers = [ "clangtidy", "result-detail" ]
|
||||||
|
clangtidy.keyword = [ "codequality-unchecked-malloc-result", "codequality-no-global-variables", "codequality-no-header-guard", "codequality-no-fflush-stdin", "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", "portability" ]
|
||||||
|
clangtidy.weight = [ 5, 20, 20, 20, 10, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stdout = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Cppcheck"
|
||||||
|
command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --suppress=missingIncludeSystem --quiet h7/ex2.cpp"
|
||||||
|
limit.stderr = "8m"
|
||||||
|
|
||||||
|
parsers = [ "keyword", "cppcheck", "clangtidy", "result-detail", "cpplint", "result-status", "file", "dummy", "diff" ]
|
||||||
|
cppcheck.keyword = ["error", "warning", "portability", "performance", "style"]
|
||||||
|
cppcheck.weight = [15, 5, 5, 5, 5]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Cpplint"
|
||||||
|
command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use --recursive --exclude=build h7/ex2.cpp"
|
||||||
|
limit.stdout = "65m"
|
||||||
|
|
||||||
|
parsers = [ "cpplint", "result-detail" ]
|
||||||
|
cpplint.keyword = [ "runtime", "readability", "build" ]
|
||||||
|
cpplint.weight = [ 5, 20, 10]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[joj] ex2-asan"
|
||||||
|
command="./h7/build/ex2-asan -a"
|
||||||
|
files.import = [ "h7/build/ex2-asan" ]
|
||||||
|
limit.mem = "128m"
|
||||||
|
|
||||||
|
parsers = [ "diff", "result-detail" ]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
|
||||||
|
# will be removed as long as the name is fixed
|
||||||
|
case0.diff.output.score = 5
|
||||||
|
case0.limit.cpu = "0.5s"
|
||||||
|
case0.limit.mem = "5m"
|
||||||
|
case0.diff.output.ignore_spaces = true
|
||||||
|
#case0.limit.stdout = 8
|
||||||
|
#case0.command = "./h7/build/ex2"
|
||||||
|
case0.in = "case0.in"
|
||||||
|
|
||||||
|
case1.diff.output.score = 5
|
||||||
|
case1.limit.cpu = "1s"
|
||||||
|
case1.limit.mem = "5m"
|
||||||
|
case1.diff.output.ignore_spaces = true
|
||||||
|
#case1.limit.stdout = 8
|
||||||
|
#case1.command = "./h7/build/ex2"
|
||||||
|
case1.in = "case1.in"
|
||||||
|
|
2
tests/convert/clang-tidy/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
140
tests/convert/clang-tidy/task.json
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[cq] Clang-tidy",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"run-clang-tidy-18",
|
||||||
|
"-header-filter=.*",
|
||||||
|
"-quiet",
|
||||||
|
"-load=/usr/local/lib/libcodequality.so",
|
||||||
|
"-p",
|
||||||
|
"h7/build",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 68157440,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"tests/homework/h7/.clang-tidy": {
|
||||||
|
"src": "/home/tt/.config/joj/tests/homework/h7/.clang-tidy"
|
||||||
|
},
|
||||||
|
"h7/build/compile_commands.json": {
|
||||||
|
"src": "/home/tt/.config/joj/h7/build/compile_commands.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "clangtidy",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"codequality-unchecked-malloc-result",
|
||||||
|
"readability-duplicate-include",
|
||||||
|
"readability-identifier-naming",
|
||||||
|
"readability-redundant",
|
||||||
|
"readability-misplaced-array-index",
|
||||||
|
"cppcoreguidelines-init-variables",
|
||||||
|
"bugprone-suspicious-string-compare",
|
||||||
|
"google-global-names-in-headers",
|
||||||
|
"clang-diagnostic",
|
||||||
|
"clang-analyzer",
|
||||||
|
"misc",
|
||||||
|
"performance",
|
||||||
|
"portability"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"codequality-no-global-variables",
|
||||||
|
"codequality-no-header-guard",
|
||||||
|
"codequality-no-fflush-stdin"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability-function-size"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability-misleading-indentation"
|
||||||
|
],
|
||||||
|
"score": 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stdout"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
20
tests/convert/clang-tidy/task.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Clang-tidy"
|
||||||
|
command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p h7/build h7/ex2.cpp"
|
||||||
|
files.import = [ "tests/homework/h7/.clang-tidy", "h7/build/compile_commands.json" ]
|
||||||
|
limit.stdout = "65m"
|
||||||
|
|
||||||
|
parsers = [ "clangtidy", "result-detail" ]
|
||||||
|
clangtidy.keyword = [ "codequality-unchecked-malloc-result", "codequality-no-global-variables", "codequality-no-header-guard", "codequality-no-fflush-stdin", "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", "portability" ]
|
||||||
|
clangtidy.weight = [ 5, 20, 20, 20, 10, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stdout = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
2
tests/convert/cppcheck/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
110
tests/convert/cppcheck/task.json
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[cq] Cppcheck",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"cppcheck",
|
||||||
|
"--template={\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}",
|
||||||
|
"--force",
|
||||||
|
"--enable=all",
|
||||||
|
"--suppress=missingIncludeSystem",
|
||||||
|
"--quiet",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 68157440,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "cppcheck",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"error"
|
||||||
|
],
|
||||||
|
"score": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"warning",
|
||||||
|
"portability",
|
||||||
|
"performance",
|
||||||
|
"style"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
19
tests/convert/cppcheck/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Cppcheck"
|
||||||
|
command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --suppress=missingIncludeSystem --quiet h7/ex2.cpp"
|
||||||
|
limit.stderr = "65m"
|
||||||
|
|
||||||
|
parsers = [ "cppcheck", "result-detail" ]
|
||||||
|
cppcheck.keyword = ["error", "warning", "portability", "performance", "style"]
|
||||||
|
cppcheck.weight = [15, 5, 5, 5, 5]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
2
tests/convert/cpplint/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
112
tests/convert/cpplint/task.json
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[cq] Cpplint",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"cpplint",
|
||||||
|
"--linelength=120",
|
||||||
|
"--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use",
|
||||||
|
"--recursive",
|
||||||
|
"--exclude=build",
|
||||||
|
"h7/ex2.cpp"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 68157440,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "cpplint",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"runtime"
|
||||||
|
],
|
||||||
|
"score": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"readability"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"build"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
19
tests/convert/cpplint/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Cpplint"
|
||||||
|
command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use --recursive --exclude=build h7/ex2.cpp"
|
||||||
|
limit.stdout = "65m"
|
||||||
|
|
||||||
|
parsers = [ "cpplint", "result-detail" ]
|
||||||
|
cpplint.keyword = [ "runtime", "readability", "build" ]
|
||||||
|
cpplint.weight = [ 5, 20, 10]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
2
tests/convert/diff/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
138
tests/convert/diff/task.json
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[joj] ex2-asan",
|
||||||
|
"group": "joj",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"./h7/build/ex2-asan",
|
||||||
|
"-a"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 68157440,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"h7/build/ex2-asan": {
|
||||||
|
"src": "/home/tt/.config/joj/h7/build/ex2-asan"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"stdin": {
|
||||||
|
"src": "/home/tt/.config/joj/diff/case0.in"
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 2097152,
|
||||||
|
"procLimit": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stdin": {
|
||||||
|
"src": "/home/tt/.config/joj/diff/case1.in"
|
||||||
|
},
|
||||||
|
"cpuLimit": 2000000000,
|
||||||
|
"clockLimit": 4000000000,
|
||||||
|
"memoryLimit": 4194304,
|
||||||
|
"procLimit": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "diff",
|
||||||
|
"with": {
|
||||||
|
"name": "diff",
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"score": 5,
|
||||||
|
"fileName": "stdout",
|
||||||
|
"answerPath": "/home/tt/.config/joj/diff/case0.out",
|
||||||
|
"forceQuitOnDiff": false,
|
||||||
|
"alwaysHide": false,
|
||||||
|
"compareSpace": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"score": 5,
|
||||||
|
"fileName": "stdout",
|
||||||
|
"answerPath": "/home/tt/.config/joj/diff/case1.out",
|
||||||
|
"forceQuitOnDiff": false,
|
||||||
|
"alwaysHide": false,
|
||||||
|
"compareSpace": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": true,
|
||||||
|
"showMemory": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
33
tests/convert/diff/task.toml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[joj] ex2-asan"
|
||||||
|
command="./h7/build/ex2-asan -a"
|
||||||
|
files.import = [ "h7/build/ex2-asan" ]
|
||||||
|
limit.mem = "65m"
|
||||||
|
|
||||||
|
parsers = [ "diff", "result-detail" ]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
|
||||||
|
# will be removed as long as the name is fixed
|
||||||
|
case0.diff.output.score = 5
|
||||||
|
case0.limit.cpu = "1s"
|
||||||
|
case0.limit.mem = "2m"
|
||||||
|
case0.diff.output.ignore_spaces = true
|
||||||
|
#case0.limit.stdout = 8
|
||||||
|
#case0.command = "./h7/build/ex2"
|
||||||
|
case0.in = "case0.in"
|
||||||
|
|
||||||
|
case1.diff.output.score = 5
|
||||||
|
case1.limit.cpu = "2s"
|
||||||
|
case1.limit.mem = "4m"
|
||||||
|
case1.diff.output.ignore_spaces = true
|
||||||
|
#case1.limit.stdout = 8
|
||||||
|
#case1.command = "./h7/build/ex2"
|
||||||
|
case1.in = "case1.in"
|
2
tests/convert/keyword/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
109
tests/convert/keyword/task.json
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[cq] Filelength",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"./tools/filelength",
|
||||||
|
"400",
|
||||||
|
"300",
|
||||||
|
"*.cpp",
|
||||||
|
"*.h"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"tools/filelength": {
|
||||||
|
"src": "/home/tt/.config/joj/tools/filelength"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "keyword",
|
||||||
|
"with": {
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"max"
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"recommended"
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stdout"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
19
tests/convert/keyword/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Filelength"
|
||||||
|
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||||
|
files.import = [ "tools/filelength" ]
|
||||||
|
|
||||||
|
parsers = [ "keyword", "result-detail" ]
|
||||||
|
keyword.keyword = [ "max", "recommended"]
|
||||||
|
keyword.weight = [ 20, 10 ]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stdout = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
2
tests/convert/result-detail/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
force_skip_health_check_on_test = true
|
||||||
|
force_skip_teapot_on_test = true
|
91
tests/convert/result-detail/task.json
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"name": "hw7 ex2",
|
||||||
|
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||||
|
"expireUnixTimestamp": 1735574399,
|
||||||
|
"effectiveUnixTimestamp": 1735487999,
|
||||||
|
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||||
|
"maxTotalScore": 100,
|
||||||
|
"stage": {
|
||||||
|
"sandboxExecServer": "172.17.0.1:5051",
|
||||||
|
"sandboxToken": "",
|
||||||
|
"outputPath": "/tmp/joj3_result.json",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "[cq] Filelength",
|
||||||
|
"group": "cq",
|
||||||
|
"executor": {
|
||||||
|
"name": "sandbox",
|
||||||
|
"with": {
|
||||||
|
"default": {
|
||||||
|
"args": [
|
||||||
|
"./tools/filelength",
|
||||||
|
"400",
|
||||||
|
"300",
|
||||||
|
"*.cpp",
|
||||||
|
"*.h"
|
||||||
|
],
|
||||||
|
"env": [],
|
||||||
|
"stdin": {
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"name": "stdout",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"name": "stderr",
|
||||||
|
"max": 33554432,
|
||||||
|
"pipe": true
|
||||||
|
},
|
||||||
|
"cpuLimit": 1000000000,
|
||||||
|
"clockLimit": 2000000000,
|
||||||
|
"memoryLimit": 134217728,
|
||||||
|
"stackLimit": 0,
|
||||||
|
"procLimit": 50,
|
||||||
|
"cpuRateLimit": 0,
|
||||||
|
"cpuSetLimit": "",
|
||||||
|
"copyIn": {
|
||||||
|
"tools/filelength": {
|
||||||
|
"src": "/home/tt/.config/joj/tools/filelength"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copyInCached": {},
|
||||||
|
"copyInDir": ".",
|
||||||
|
"copyOut": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"copyOutCached": [],
|
||||||
|
"copyOutMax": 0,
|
||||||
|
"copyOutDir": "",
|
||||||
|
"tty": false,
|
||||||
|
"strictMemoryLimit": false,
|
||||||
|
"dataSegmentLimit": false,
|
||||||
|
"addressSpaceLimit": false
|
||||||
|
},
|
||||||
|
"cases": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parsers": [
|
||||||
|
{
|
||||||
|
"name": "result-detail",
|
||||||
|
"with": {
|
||||||
|
"score": 0,
|
||||||
|
"comment": "",
|
||||||
|
"showFiles": [
|
||||||
|
"stdout",
|
||||||
|
"stderr"
|
||||||
|
],
|
||||||
|
"showExitStatus": true,
|
||||||
|
"showRuntime": false,
|
||||||
|
"showMemory": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preStages": [],
|
||||||
|
"postStages": []
|
||||||
|
}
|
||||||
|
}
|
18
tests/convert/result-detail/task.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# general task configuration
|
||||||
|
task.name = "hw7 ex2" # task name
|
||||||
|
task.type = "homework/h7/e2" # remove this task type later
|
||||||
|
|
||||||
|
release.end_time = 2024-12-30 23:59:59+08:00
|
||||||
|
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||||
|
|
||||||
|
[[stages]]
|
||||||
|
name = "[cq] Filelength"
|
||||||
|
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||||
|
files.import = [ "tools/filelength" ]
|
||||||
|
|
||||||
|
parsers = [ "result-detail" ]
|
||||||
|
result-detail.exitstatus = true
|
||||||
|
result-detail.stdout = true
|
||||||
|
result-detail.stderr = true
|
||||||
|
result-detail.time = false
|
||||||
|
result-detail.mem = false
|
|
@ -3,3 +3,27 @@ from tests.convert.utils import load_case
|
||||||
|
|
||||||
def test_basic() -> None:
|
def test_basic() -> None:
|
||||||
load_case("basic")
|
load_case("basic")
|
||||||
|
|
||||||
|
|
||||||
|
def test_clang_tidy() -> None:
|
||||||
|
load_case("clang-tidy")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cppcheck() -> None:
|
||||||
|
load_case("cppcheck")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cpplint() -> None:
|
||||||
|
load_case("cpplint")
|
||||||
|
|
||||||
|
|
||||||
|
def test_diff() -> None:
|
||||||
|
load_case("diff")
|
||||||
|
|
||||||
|
|
||||||
|
def test_keyword() -> None:
|
||||||
|
load_case("keyword")
|
||||||
|
|
||||||
|
|
||||||
|
def test_result_detail() -> None:
|
||||||
|
load_case("result-detail")
|
||||||
|
|
|
@ -1,32 +1,18 @@
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Tuple
|
|
||||||
|
|
||||||
import rtoml
|
|
||||||
|
|
||||||
from joj3_config_generator.convert import convert
|
from joj3_config_generator.convert import convert
|
||||||
from joj3_config_generator.models import repo, task
|
from joj3_config_generator.load import load_joj3_toml
|
||||||
|
|
||||||
|
|
||||||
def read_convert_files(
|
|
||||||
case_name: str,
|
|
||||||
) -> Tuple[repo.Config, task.Config, Dict[str, Any]]:
|
|
||||||
root = Path(__file__).resolve().parent / case_name
|
|
||||||
repo_toml_path = root / "repo.toml"
|
|
||||||
repo_toml = repo_toml_path.read_text() if repo_toml_path.exists() else ""
|
|
||||||
task_toml_path = root / "task.toml"
|
|
||||||
task_toml = task_toml_path.read_text() if task_toml_path.exists() else ""
|
|
||||||
result = json.loads((root / "task.json").read_text())
|
|
||||||
return (
|
|
||||||
repo.Config(root=root, **rtoml.loads(repo_toml)),
|
|
||||||
task.Config(root=root, **rtoml.loads(task_toml)),
|
|
||||||
result,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_case(case_name: str) -> None:
|
def load_case(case_name: str) -> None:
|
||||||
repo, task, expected_result = read_convert_files(case_name)
|
root = Path(__file__).resolve().parent
|
||||||
result = convert(repo, task).model_dump(
|
repo_toml_path = root / case_name / "repo.toml"
|
||||||
|
task_toml_path = root / case_name / "task.toml"
|
||||||
|
repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path)
|
||||||
|
result_json_path = root / case_name / "task.json"
|
||||||
|
expected_result = json.loads(result_json_path.read_text())
|
||||||
|
result = convert(repo_conf, task_conf).model_dump(
|
||||||
mode="json", by_alias=True, exclude_none=True
|
mode="json", by_alias=True, exclude_none=True
|
||||||
)
|
)
|
||||||
assert result == expected_result
|
assert result == expected_result
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Tuple
|
|
||||||
|
|
||||||
import rtoml
|
import rtoml
|
||||||
import yaml
|
|
||||||
|
|
||||||
from joj3_config_generator.convert import convert_joj1
|
from joj3_config_generator.convert import convert_joj1
|
||||||
from joj3_config_generator.models import joj1
|
from joj3_config_generator.load import load_joj1_yaml
|
||||||
|
|
||||||
|
|
||||||
def read_convert_joj1_files(case_name: str) -> Tuple[joj1.Config, Dict[str, Any]]:
|
|
||||||
root = Path(__file__).resolve().parent
|
|
||||||
task_yaml_path = root / case_name / "task.yaml"
|
|
||||||
task_yaml = task_yaml_path.read_text()
|
|
||||||
task_toml_path = root / case_name / "task.toml"
|
|
||||||
task_toml = task_toml_path.read_text()
|
|
||||||
return joj1.Config(**yaml.safe_load(task_yaml)), rtoml.loads(task_toml)
|
|
||||||
|
|
||||||
|
|
||||||
def load_case(case_name: str) -> None:
|
def load_case(case_name: str) -> None:
|
||||||
joj1, expected_result = read_convert_joj1_files(case_name)
|
root = Path(__file__).resolve().parent
|
||||||
result = convert_joj1(joj1).model_dump(by_alias=True, exclude_none=True)
|
task_yaml_path = root / case_name / "task.yaml"
|
||||||
|
task_yaml = load_joj1_yaml(task_yaml_path)
|
||||||
|
task_toml_path = root / case_name / "task.toml"
|
||||||
|
task_toml = task_toml_path.read_text()
|
||||||
|
expected_result = rtoml.loads(task_toml)
|
||||||
|
result = convert_joj1(task_yaml).model_dump(
|
||||||
|
mode="json", by_alias=True, exclude_none=True
|
||||||
|
)
|
||||||
assert result == expected_result
|
assert result == expected_result
|
||||||
|
|
this file should not be changed