Compare commits
	
		
			3 Commits
		
	
	
		
			master
			...
			docs/READM
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 139eafa644 | |||
| 8ebc432999 | |||
| 2a6428feec | 
|  | @ -23,9 +23,9 @@ jobs: | |||
|       - name: PDM install dependencies | ||||
|         run: | | ||||
|           pdm install | ||||
|       - name: All | ||||
|       - name: Lint | ||||
|         run: | | ||||
|           pdm run all | ||||
|           pdm run lint | ||||
|       - name: Run | ||||
|         run: | | ||||
|           pdm run app --help | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ repos: | |||
|       - id: yamlfmt | ||||
|         exclude: '^tests/' | ||||
|   - repo: https://github.com/pdm-project/pdm | ||||
|     rev: 2.25.9 | ||||
|     rev: 2.19.2 | ||||
|     hooks: | ||||
|       - id: pdm-lock-check | ||||
|   - repo: https://github.com/pre-commit/mirrors-mypy | ||||
|  |  | |||
							
								
								
									
										66
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								README.md
									
									
									
									
									
								
							|  | @ -1,8 +1,12 @@ | |||
| # JOJ3-config-generator | ||||
| # JOJ3-forge | ||||
| 
 | ||||
| [](https://app.codacy.com/gh/joint-online-judge/JOJ3-config-generator/dashboard) | ||||
| [](https://app.codacy.com/gh/joint-online-judge/JOJ3-config-generator/dashboard) | ||||
| 
 | ||||
| ## Introduction | ||||
| 
 | ||||
| JOJ3-forge is a CLI tool that generates configuration files for [JOJ3](https://github.com/joint-online-judge/JOJ3). | ||||
| 
 | ||||
| ## Getting Started | ||||
| 
 | ||||
| ### For users | ||||
|  | @ -10,7 +14,7 @@ | |||
| 1. Install [Python>=3.9](https://www.python.org/) and [pip](https://pip.pypa.io/) | ||||
| 2. (Optional) Create a virtual environment, check [here](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/). | ||||
| 3. Install/Upgrade the project by `pip install --force-reinstall --upgrade git+ssh://git@focs.ji.sjtu.edu.cn:2222/JOJ/JOJ3-config-generator.git` | ||||
| 4. Run it by `joj3-config-generator --help` | ||||
| 4. Run it by `joj3-forge --help` | ||||
| 
 | ||||
| ### For developers | ||||
| 
 | ||||
|  | @ -23,22 +27,62 @@ | |||
| 
 | ||||
| ## 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` | ||||
| Run `joj3-forge --help` to get basic CLI usage information. | ||||
| 
 | ||||
| ### `convert` | ||||
| 
 | ||||
| - `joj3-forge convert` function is now supported, currently support one argument as input, it indicates the **convert root* | ||||
|   - default value on the server should 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 | ||||
|   - a sample directory tree as follows | ||||
| 
 | ||||
| ```shell | ||||
| $ tree . | ||||
| . | ||||
| |- immutable_files | ||||
| | |-- push.yaml | ||||
| | |-- release.yaml | ||||
| |-- repo.toml | ||||
| $ tree -a | ||||
| home | ||||
| `-- tt | ||||
|     |-- .cache | ||||
|     `-- .config | ||||
|         `-- joj | ||||
|             |-- hidden | ||||
|             |   |-- ex1 | ||||
|             |   |   |-- case1.in | ||||
|             |   |   |-- case1.out | ||||
|             |   |   |-- conf.json | ||||
|             |   |   `-- conf.toml | ||||
|             |   |-- immutable_files | ||||
|             |   |   |-- push.yaml | ||||
|             |   |   `-- release.yaml | ||||
|             |   |-- p1 | ||||
|             |   |   |-- case1.in | ||||
|             |   |   |-- case1.out | ||||
|             |   |   |-- conf.json | ||||
|             |   |   `-- conf.toml | ||||
|             |   `-- repo.toml | ||||
|             |-- students | ||||
|             |   |-- ex1 | ||||
|             |   |   |-- case1.in | ||||
|             |   |   |-- case1.out | ||||
|             |   |   |-- conf.json | ||||
|             |   |   `-- conf.toml | ||||
|             |   |-- immutable_files | ||||
|             |   |   |-- push.yaml | ||||
|             |   |   `-- release.yaml | ||||
|             |   |-- p1 | ||||
|             |   |   |-- case1.in | ||||
|             |   |   |-- case1.out | ||||
|             |   |   |-- conf.json | ||||
|             |   |   `-- conf.toml | ||||
|             |   `-- repo.toml | ||||
|             |-- students.csv | ||||
|             `-- tools | ||||
|                 |-- .clang-tidy | ||||
|                 |-- compile | ||||
|                 `-- helper.sh | ||||
| ``` | ||||
| 
 | ||||
| - sample command on the server | ||||
| 
 | ||||
| ```shell | ||||
| joj3-config-generator convert /home/tt/.config/joj | ||||
| joj3-forge convert /home/tt/.config/joj | ||||
| ``` | ||||
|  |  | |||
|  | @ -2,11 +2,7 @@ import os | |||
| from typing import Dict | ||||
| 
 | ||||
| from joj3_config_generator.models import answer, joj1, repo, result, task | ||||
| from joj3_config_generator.models.const import ( | ||||
|     ACTOR_CSV_PATH, | ||||
|     JOJ3_LOG_BASE_PATH, | ||||
|     JOJ3_LOG_FILENAME, | ||||
| ) | ||||
| from joj3_config_generator.models.const import ACTOR_CSV_PATH, JOJ3_LOG_PATH | ||||
| from joj3_config_generator.transformers.answer import get_task_conf_from_answers | ||||
| from joj3_config_generator.transformers.joj1 import get_task_conf_from_joj1 | ||||
| from joj3_config_generator.transformers.repo import ( | ||||
|  | @ -27,22 +23,31 @@ def convert_joj1_conf(joj1_conf: joj1.Config) -> task.Config: | |||
| def convert_joj3_conf(repo_conf: repo.Config, task_conf: task.Config) -> result.Config: | ||||
|     # Create the base ResultConf object | ||||
|     result_conf = result.Config( | ||||
|         name=task_conf.name, | ||||
|         name=task_conf.task.name, | ||||
|         # exact folder difference specified by type | ||||
|         log_path=str(JOJ3_LOG_BASE_PATH / task_conf.suffix / JOJ3_LOG_FILENAME), | ||||
|         log_path=str(JOJ3_LOG_PATH), | ||||
|         expire_unix_timestamp=int(task_conf.release.end_time.timestamp()), | ||||
|         effective_unix_timestamp=int(task_conf.release.begin_time.timestamp()), | ||||
|         actor_csv_path=str(ACTOR_CSV_PATH),  # students.csv position | ||||
|         sandbox_token=repo_conf.sandbox_token, | ||||
|         max_total_score=( | ||||
|             repo_conf.max_total_score | ||||
|             if not task_conf.max_total_score | ||||
|             else task_conf.max_total_score | ||||
|         ), | ||||
|         stage=result.Stage(sandbox_token=repo_conf.sandbox_token), | ||||
|     ) | ||||
| 
 | ||||
|     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.stages.append(get_health_check_stage(repo_conf, task_conf)) | ||||
|         result_conf.stage.stages.append(get_health_check_stage(repo_conf, task_conf)) | ||||
|     cached: Dict[str, None] = {} | ||||
|     # Convert each stage in the task configuration | ||||
|     for task_stage in task_conf.stages: | ||||
|         result_conf.stages.append(get_conf_stage(task_conf, task_stage, cached)) | ||||
|         result_conf.stage.stages.append(get_conf_stage(task_conf, task_stage, cached)) | ||||
|     if not repo_conf.force_skip_teapot_on_test or not current_test: | ||||
|         result_conf.post_stages.append(get_teapot_post_stage(repo_conf, task_conf)) | ||||
|         result_conf.stage.post_stages.append( | ||||
|             get_teapot_post_stage(repo_conf, task_conf) | ||||
|         ) | ||||
| 
 | ||||
|     return result_conf | ||||
|  |  | |||
|  | @ -5,23 +5,13 @@ from typing import Any, Dict, Tuple, Type, cast | |||
| import inquirer | ||||
| import tomli | ||||
| import yaml | ||||
| from pydantic import AliasChoices, BaseModel, ValidationError | ||||
| from pydantic import BaseModel | ||||
| 
 | ||||
| from joj3_config_generator.models import answer, joj1, repo, task | ||||
| from joj3_config_generator.models.common import Memory, Time | ||||
| from joj3_config_generator.utils.logger import logger | ||||
| 
 | ||||
| 
 | ||||
| def is_toml_empty(toml_path: Path) -> bool: | ||||
|     if toml_path.stat().st_size == 0: | ||||
|         return True | ||||
|     try: | ||||
|         data = tomli.loads(toml_path.read_text()) | ||||
|         return not data | ||||
|     except tomli.TOMLDecodeError: | ||||
|         return False | ||||
| 
 | ||||
| 
 | ||||
| def load_joj3_task_toml_answers() -> answer.Answers: | ||||
|     name = inquirer.text("What's the task name?", default="hw0") | ||||
|     language = inquirer.list_input( | ||||
|  | @ -93,16 +83,8 @@ def load_joj3_toml( | |||
|                 f"{current_path}.{field_name}" if current_path else field_name | ||||
|             ) | ||||
|             toml_field_name = field_name | ||||
|             if field_info.validation_alias: | ||||
|                 if isinstance(field_info.validation_alias, str): | ||||
|                     if field_info.validation_alias in input_dict: | ||||
|                         toml_field_name = field_info.validation_alias | ||||
|                 elif isinstance(field_info.validation_alias, AliasChoices): | ||||
|                     for choice in field_info.validation_alias.choices: | ||||
|                         if choice in input_dict: | ||||
|                             if isinstance(choice, str): | ||||
|                                 toml_field_name = choice | ||||
|                                 break | ||||
|             if field_info.alias in input_dict: | ||||
|                 toml_field_name = field_info.alias | ||||
|             if toml_field_name not in input_dict: | ||||
|                 continue | ||||
|             toml_value = input_dict[toml_field_name] | ||||
|  | @ -176,22 +158,10 @@ def load_joj3_toml( | |||
| 
 | ||||
|     repo_obj = tomli.loads(repo_toml_path.read_text()) | ||||
|     task_obj = tomli.loads(task_toml_path.read_text()) | ||||
|     try: | ||||
|     repo_conf = repo.Config(**repo_obj) | ||||
|     except ValidationError as e: | ||||
|         logger.error( | ||||
|             f"Error parsing {repo_toml_path}, most likely to be unknown fields, check the latest sample toml carefully:\n{e}" | ||||
|         ) | ||||
|         raise | ||||
|     repo_conf.root = root_path | ||||
|     repo_conf.path = repo_toml_path.relative_to(root_path) | ||||
|     try: | ||||
|     task_conf = task.Config(**task_obj) | ||||
|     except ValidationError as e: | ||||
|         logger.error( | ||||
|             f"Error parsing {task_toml_path}, most likely to be unknown fields, check the latest sample toml carefully:\n{e}" | ||||
|         ) | ||||
|         raise | ||||
|     task_conf.root = root_path | ||||
|     task_conf.path = task_toml_path.relative_to(root_path) | ||||
|     check_unnecessary_fields(repo.Config, repo_obj, repo_toml_path) | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ from joj3_config_generator.generator import ( | |||
|     create_joj3_task_conf, | ||||
| ) | ||||
| from joj3_config_generator.loader import ( | ||||
|     is_toml_empty, | ||||
|     load_joj1_yaml, | ||||
|     load_joj3_task_toml_answers, | ||||
|     load_joj3_toml, | ||||
|  | @ -95,33 +94,16 @@ def convert( | |||
|     """ | ||||
|     app.pretty_exceptions_enable = False | ||||
|     logger.info(f"Converting files in {root.absolute()}") | ||||
|     error_json_paths = [] | ||||
|     is_json_generated = False | ||||
|     for repo_toml_path in root.glob("**/repo.toml"): | ||||
|         if not any(p != repo_toml_path for p in repo_toml_path.parent.glob("*.toml")): | ||||
|             fallback_toml_path = repo_toml_path.parent / "conf.toml" | ||||
|             if not fallback_toml_path.exists(): | ||||
|                 fallback_toml_path.write_text( | ||||
|                     'name = "health check"\nmax-total-score = 0\n' | ||||
|                 ) | ||||
|         for task_toml_path in repo_toml_path.parent.glob("**/*.toml"): | ||||
|             if repo_toml_path == task_toml_path: | ||||
|                 continue | ||||
|             if is_toml_empty(task_toml_path): | ||||
|                 logger.info(f"Skipping empty task toml file {task_toml_path}") | ||||
|                 continue | ||||
|             toml_name = task_toml_path.name.removesuffix(".toml") | ||||
|             result_json_path = task_toml_path.parent / f"{toml_name}.json" | ||||
|             logger.info( | ||||
|                 f"Converting {repo_toml_path} & {task_toml_path} to {result_json_path}" | ||||
|             ) | ||||
|             try: | ||||
|                 repo_conf, task_conf = load_joj3_toml( | ||||
|                     root, repo_toml_path, task_toml_path | ||||
|                 ) | ||||
|             except Exception: | ||||
|                 error_json_paths.append(result_json_path) | ||||
|                 continue | ||||
|             repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path) | ||||
|             result_model = convert_joj3_conf(repo_conf, task_conf) | ||||
|             result_dict = result_model.model_dump( | ||||
|                 mode="json", by_alias=True, exclude_none=True | ||||
|  | @ -129,12 +111,3 @@ def convert( | |||
|             with result_json_path.open("w", newline="") as result_file: | ||||
|                 json.dump(result_dict, result_file, ensure_ascii=False, indent=4) | ||||
|                 result_file.write("\n") | ||||
|             is_json_generated = True | ||||
|     if error_json_paths: | ||||
|         logger.error( | ||||
|             f"Failed to convert {len(error_json_paths)} file(s): {', '.join(str(json_path) for json_path in error_json_paths)}. Check previous errors for details." | ||||
|         ) | ||||
|         raise typer.Exit(code=1) | ||||
|     if not is_json_generated: | ||||
|         logger.error("No repo.toml files found to convert.") | ||||
|         raise typer.Exit(code=1) | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| from typing import Union | ||||
| 
 | ||||
| import humanfriendly | ||||
| from pydantic import BaseModel, ConfigDict | ||||
| 
 | ||||
| 
 | ||||
| class Memory(int): | ||||
|  | @ -18,7 +17,3 @@ class Time(int): | |||
|             parsed = humanfriendly.parse_timespan(value) * 1_000_000_000  # ns | ||||
|             return super().__new__(cls, round(parsed)) | ||||
|         return super().__new__(cls, value) | ||||
| 
 | ||||
| 
 | ||||
| class StrictBaseModel(BaseModel): | ||||
|     model_config = ConfigDict(extra="forbid") | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ DEFAULT_PATH_ENV = "PATH=/usr/bin:/bin:/usr/local/bin" | |||
| JOJ3_CONFIG_ROOT = PurePosixPath("/home/tt/.config/joj") | ||||
| TEAPOT_CONFIG_ROOT = PurePosixPath("/home/tt/.config/teapot") | ||||
| CACHE_ROOT = PurePosixPath("/home/tt/.cache") | ||||
| JOJ3_LOG_BASE_PATH = CACHE_ROOT / "joj3" | ||||
| JOJ3_LOG_FILENAME = "joj3.log" | ||||
| JOJ3_LOG_PATH = CACHE_ROOT / "joj3" / "joj3.log" | ||||
| TEAPOT_LOG_PATH = CACHE_ROOT / "joint-teapot-debug.log" | ||||
| ACTOR_CSV_PATH = JOJ3_CONFIG_ROOT / "students.csv" | ||||
|  |  | |||
|  | @ -1,18 +1,16 @@ | |||
| import os | ||||
| import socket | ||||
| from pathlib import Path | ||||
| from typing import Any, List | ||||
| from typing import List | ||||
| 
 | ||||
| from pydantic import AliasChoices, Field, field_validator, model_validator | ||||
| 
 | ||||
| from joj3_config_generator.models.common import Memory, StrictBaseModel | ||||
| from pydantic import AliasChoices, BaseModel, Field | ||||
| 
 | ||||
| 
 | ||||
| class Files(StrictBaseModel): | ||||
| class Files(BaseModel): | ||||
|     required: List[str] = [] | ||||
|     immutable: List[str] = [] | ||||
| 
 | ||||
| 
 | ||||
| class Groups(StrictBaseModel): | ||||
| class Groups(BaseModel): | ||||
|     name: List[str] = [] | ||||
|     max_count: List[int] = Field( | ||||
|         [], validation_alias=AliasChoices("max-count", "max_count") | ||||
|  | @ -22,81 +20,42 @@ class Groups(StrictBaseModel): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class Label(StrictBaseModel): | ||||
|     name: str = "Kind/Testing" | ||||
|     color: str = "#795548" | ||||
|     exclusive: bool = False | ||||
| 
 | ||||
| 
 | ||||
| class Issue(StrictBaseModel): | ||||
|     label: Label = Label() | ||||
|     show_submitter: bool = Field( | ||||
|         True, validation_alias=AliasChoices("show-submitter", "show_submitter") | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class HealthCheck(StrictBaseModel): | ||||
|     score: int = 0 | ||||
|     max_size: int = Field( | ||||
|         Memory("10m"), validation_alias=AliasChoices("max-size", "max_size") | ||||
|     ) | ||||
|     immutable_path: Path = Field( | ||||
|         Path("immutable"), | ||||
|         validation_alias=AliasChoices("immutable-path", "immutable_path"), | ||||
|     ) | ||||
|     required_files: List[str] = Field( | ||||
|         [], validation_alias=AliasChoices("required-files", "required_files") | ||||
|     ) | ||||
| 
 | ||||
|     @field_validator("max_size", mode="before") | ||||
|     @classmethod | ||||
|     def ensure_mem_type(cls, v: Any) -> Memory: | ||||
|         if isinstance(v, str): | ||||
|             return Memory(v) | ||||
|         raise ValueError(f'Must be a string, e.g., "256m" or "1g", but got {v}') | ||||
| 
 | ||||
| 
 | ||||
| class Config(StrictBaseModel): | ||||
|     root: Path = Field(Path("."), exclude=True) | ||||
|     path: Path = Field(Path("repo.toml"), exclude=True) | ||||
| 
 | ||||
|     force_skip_health_check_on_test: bool = Field( | ||||
|         False, | ||||
|         validation_alias=AliasChoices( | ||||
|             "force-skip-health-check-on-test", "force_skip_health_check_on_test" | ||||
|         ), | ||||
|         exclude=True, | ||||
|     ) | ||||
|     force_skip_teapot_on_test: bool = Field( | ||||
|         False, | ||||
|         validation_alias=AliasChoices( | ||||
|             "force-skip-teapot-on-test", "force_skip_teapot_on_test" | ||||
|         ), | ||||
|         exclude=True, | ||||
|     ) | ||||
|     grading_repo_name: str = Field( | ||||
|         "", | ||||
|         validation_alias=AliasChoices("grading-repo-name", "grading_repo_name"), | ||||
| class Config(BaseModel): | ||||
|     max_size: float = Field( | ||||
|         10, ge=0, validation_alias=AliasChoices("max-size", "max_size") | ||||
|     ) | ||||
|     files: Files = Files() | ||||
|     sandbox_token: str = Field( | ||||
|         "", validation_alias=AliasChoices("sandbox-token", "sandbox_token") | ||||
|     ) | ||||
|     max_total_score: int = Field( | ||||
|         100, validation_alias=AliasChoices("max-total-score", "max_total_score") | ||||
|     ) | ||||
|     groups: Groups = Groups() | ||||
|     issue: Issue = Issue() | ||||
| 
 | ||||
|     health_check: HealthCheck = Field( | ||||
|         HealthCheck(), validation_alias=AliasChoices("health-check", "health_check") | ||||
|     force_skip_health_check_on_test: bool = Field( | ||||
|         False, | ||||
|         validation_alias=AliasChoices( | ||||
|             "force-skip-health-check-on-test", "force_skip_health_check_on_test" | ||||
|         ), | ||||
|     ) | ||||
|     force_skip_teapot_on_test: bool = Field( | ||||
|         False, | ||||
|         validation_alias=AliasChoices( | ||||
|             "force-skip-teapot-on-test", "force_skip_teapot_on_test" | ||||
|         ), | ||||
|     ) | ||||
|     groups: Groups = Groups() | ||||
|     root: Path = Path(".") | ||||
|     path: Path = Path("repo.toml") | ||||
|     grading_repo_name: str = Field( | ||||
|         f"{socket.gethostname().split('-')[0]}-joj", | ||||
|         validation_alias=AliasChoices("grading-repo-name", "grading_repo_name"), | ||||
|     ) | ||||
|     health_check_score: int = Field( | ||||
|         0, validation_alias=AliasChoices("health-check-score", "health_check_score") | ||||
|     ) | ||||
|     submitter_in_issue_title: bool = Field( | ||||
|         True, | ||||
|         validation_alias=AliasChoices( | ||||
|             "submitter-in-issue-title", "submitter_in_issue_title" | ||||
|         ), | ||||
|     ) | ||||
| 
 | ||||
|     @model_validator(mode="after") | ||||
|     def set_grading_repo_name_from_cwd(self) -> "Config": | ||||
|         if not self.grading_repo_name: | ||||
|             course_env = os.getenv("COURSE") | ||||
|             if course_env: | ||||
|                 self.grading_repo_name = f"{course_env}-joj" | ||||
|             else: | ||||
|                 self.grading_repo_name = Path.cwd().name | ||||
|         return self | ||||
|  |  | |||
|  | @ -146,15 +146,12 @@ class Parser(BaseModel): | |||
| 
 | ||||
| class StageDetail(BaseModel): | ||||
|     name: str | ||||
|     groups: List[str] = [] | ||||
|     group: str = "" | ||||
|     executor: Executor | ||||
|     parsers: List[Parser] | ||||
| 
 | ||||
| 
 | ||||
| class Config(BaseModel): | ||||
|     name: str = "" | ||||
|     log_path: str = Field("", serialization_alias="logPath") | ||||
|     actor_csv_path: str = Field("", serialization_alias="actorCsvPath") | ||||
| class Stage(BaseModel): | ||||
|     sandbox_exec_server: str = Field( | ||||
|         "172.17.0.1:5051", serialization_alias="sandboxExecServer" | ||||
|     ) | ||||
|  | @ -162,18 +159,24 @@ class Config(BaseModel): | |||
|     output_path: str = Field( | ||||
|         "/tmp/joj3_result.json", serialization_alias="outputPath" | ||||
|     )  # nosec: B108 | ||||
|     pre_stages: List[StageDetail] = Field([], serialization_alias="preStages") | ||||
|     stages: List[StageDetail] = [] | ||||
|     pre_stages: List[StageDetail] = Field([], serialization_alias="preStages") | ||||
|     post_stages: List[StageDetail] = Field([], serialization_alias="postStages") | ||||
| 
 | ||||
| 
 | ||||
| class Config(BaseModel): | ||||
|     name: str = "" | ||||
|     log_path: str = Field("", serialization_alias="logPath") | ||||
|     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 | ||||
| 
 | ||||
| 
 | ||||
| class DummyConfig(BaseModel): | ||||
|     score: int = 0 | ||||
|     comment: Optional[str] = None | ||||
|     force_quit: Optional[bool] = Field(False, serialization_alias="forceQuit") | ||||
| 
 | ||||
| 
 | ||||
| class ResultStatusConfig(BaseModel): | ||||
|     score: int = 0 | ||||
|     comment: Optional[str] = None | ||||
|     force_quit_on_not_accepted: Optional[bool] = Field( | ||||
|  | @ -183,7 +186,7 @@ class ResultStatusConfig(BaseModel): | |||
| 
 | ||||
| class DiffOutputConfig(BaseModel): | ||||
|     score: int = 100 | ||||
|     filename: str = Field("", serialization_alias="filename") | ||||
|     file_name: str = Field("", serialization_alias="fileName") | ||||
|     answer_path: str = Field("", serialization_alias="answerPath") | ||||
|     compare_space: bool = Field(False, serialization_alias="compareSpace") | ||||
|     always_hide: bool = Field(False, serialization_alias="alwaysHide") | ||||
|  | @ -214,7 +217,6 @@ class KeywordConfig(BaseModel): | |||
| 
 | ||||
| 
 | ||||
| class KeywordMatchConfig(BaseModel): | ||||
|     score: int = 0 | ||||
|     matches: List[KeywordConfig] = [] | ||||
| 
 | ||||
| 
 | ||||
|  | @ -232,9 +234,7 @@ class DiffConfig(BaseModel): | |||
| 
 | ||||
| 
 | ||||
| class MsgConfig(BaseModel): | ||||
|     filename: str = "stdout" | ||||
|     msg: str = "" | ||||
|     level: int = 0 | ||||
| 
 | ||||
| 
 | ||||
| class ScoreConfig(BaseModel): | ||||
|  |  | |||
|  | @ -1,15 +1,20 @@ | |||
| import re | ||||
| from datetime import datetime, timezone | ||||
| from enum import Enum | ||||
| from pathlib import Path | ||||
| from typing import Any, Dict, List, Optional, Type | ||||
| from typing import Any, Dict, List, Type | ||||
| 
 | ||||
| from pydantic import AliasChoices, ConfigDict, Field, field_validator, model_validator | ||||
| from pydantic import ( | ||||
|     AliasChoices, | ||||
|     BaseModel, | ||||
|     ConfigDict, | ||||
|     Field, | ||||
|     field_validator, | ||||
|     model_validator, | ||||
| ) | ||||
| 
 | ||||
| from joj3_config_generator.models.common import Memory, StrictBaseModel, Time | ||||
| from joj3_config_generator.models.common import Memory, Time | ||||
| from joj3_config_generator.models.const import ( | ||||
|     DEFAULT_CASE_SCORE, | ||||
|     DEFAULT_CLOCK_LIMIT_MULTIPLIER, | ||||
|     DEFAULT_CPU_LIMIT, | ||||
|     DEFAULT_FILE_LIMIT, | ||||
|     DEFAULT_MEMORY_LIMIT, | ||||
|  | @ -18,11 +23,11 @@ from joj3_config_generator.models.const import ( | |||
| from joj3_config_generator.models.repo import Groups | ||||
| 
 | ||||
| 
 | ||||
| class ParserResultDetail(StrictBaseModel): | ||||
| class ParserResultDetail(BaseModel): | ||||
|     cpu_time: bool = Field( | ||||
|         True, validation_alias=AliasChoices("cpu-time", "cpu_time", "cpu") | ||||
|         True, validation_alias=AliasChoices("cpu-time", "cpu_time") | ||||
|     )  # Display CPU time | ||||
|     time: bool = True  # Display wall-clock time | ||||
|     time: bool = True  # Display run time | ||||
|     mem: bool = True  # Display memory usage | ||||
|     stdout: bool = False  # Display stdout messages | ||||
|     stderr: bool = False  # Display stderr messages | ||||
|  | @ -33,25 +38,19 @@ class ParserResultDetail(StrictBaseModel): | |||
|         False, validation_alias=AliasChoices("proc-peak", "proc_peak") | ||||
|     )  # Display peak process count | ||||
|     error: bool = False  # Display error messages | ||||
|     code_block: bool = Field( | ||||
|         True, validation_alias=AliasChoices("code-block", "code_block") | ||||
|     )  # Display file in code block | ||||
|     max_length: int = Field( | ||||
|         2048, validation_alias=AliasChoices("max-length", "max_length") | ||||
|     )  # Max output length of each file | ||||
| 
 | ||||
| 
 | ||||
| class ParserFile(StrictBaseModel): | ||||
| class ParserFile(BaseModel): | ||||
|     name: str = "" | ||||
| 
 | ||||
| 
 | ||||
| class ParserLog(StrictBaseModel): | ||||
| class ParserLog(BaseModel): | ||||
|     filename: str | ||||
|     msg: str = "" | ||||
|     level: str = "" | ||||
| 
 | ||||
| 
 | ||||
| class ParserDummy(StrictBaseModel): | ||||
| class ParserDummy(BaseModel): | ||||
|     comment: str = "" | ||||
|     score: int = 0 | ||||
|     force_quit: bool = Field( | ||||
|  | @ -59,21 +58,12 @@ class ParserDummy(StrictBaseModel): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class ParserResultStatus(StrictBaseModel): | ||||
|     comment: str = "" | ||||
|     score: int = 0 | ||||
|     force_quit: bool = Field( | ||||
|         True, validation_alias=AliasChoices("force-quit", "force_quit") | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class ParserKeyword(StrictBaseModel): | ||||
|     score: int = 0 | ||||
| class ParserKeyword(BaseModel): | ||||
|     keyword: List[str] = [] | ||||
|     weight: List[int] = [] | ||||
| 
 | ||||
| 
 | ||||
| class ParserDiffOutputs(StrictBaseModel): | ||||
| class ParserDiffOutputs(BaseModel): | ||||
|     score: int = 0 | ||||
|     ignore_spaces: bool = Field( | ||||
|         True, validation_alias=AliasChoices("ignore-spaces", "ignore_spaces") | ||||
|  | @ -91,79 +81,41 @@ class ParserDiffOutputs(StrictBaseModel): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class ParserDiff(StrictBaseModel): | ||||
|     score: int = DEFAULT_CASE_SCORE | ||||
|     ignore_spaces: bool = Field( | ||||
|         True, validation_alias=AliasChoices("ignore-spaces", "ignore_spaces") | ||||
|     ) | ||||
|     hide: bool = False | ||||
|     force_quit: bool = Field( | ||||
|         False, validation_alias=AliasChoices("force-quit", "force_quit") | ||||
|     ) | ||||
|     max_length: int = Field( | ||||
|         2048, validation_alias=AliasChoices("max-length", "max_length") | ||||
|     ) | ||||
|     max_lines: int = Field(50, validation_alias=AliasChoices("max-lines", "max_lines")) | ||||
|     hide_common_prefix: bool = Field( | ||||
|         False, validation_alias=AliasChoices("hide-common-prefix", "hide_common_prefix") | ||||
|     ) | ||||
|     # remove below codes when migration is complete | ||||
| class ParserDiff(BaseModel): | ||||
|     output: ParserDiffOutputs = ParserDiffOutputs() | ||||
|     default_score: int = Field( | ||||
|         DEFAULT_CASE_SCORE, | ||||
|         validation_alias=AliasChoices("default-score", "default_score"), | ||||
|     ) | ||||
| 
 | ||||
|     @model_validator(mode="after") | ||||
|     def copy_output_fields(self) -> "ParserDiff": | ||||
|         if "default_score" in self.model_fields_set: | ||||
|             self.score = self.default_score | ||||
|         if not isinstance(self.output, ParserDiffOutputs): | ||||
|             return self | ||||
|         for field_name, field_value in self.output.model_dump().items(): | ||||
|             if field_name in self.output.model_fields_set and hasattr(self, field_name): | ||||
|                 setattr(self, field_name, field_value) | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
| class StageFiles(StrictBaseModel): | ||||
| class StageFiles(BaseModel): | ||||
|     import_: List[str] = Field([], validation_alias="import") | ||||
|     export: List[str] = [] | ||||
|     import_map: Dict[str, str] = Field( | ||||
|         {}, validation_alias=AliasChoices("import-map", "import_map") | ||||
|     ) | ||||
|     no_auto_import: List[str] = Field( | ||||
|         [], validation_alias=AliasChoices("no-auto-import", "no_auto_import") | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class Limit(StrictBaseModel): | ||||
| class Limit(BaseModel): | ||||
|     mem: int = DEFAULT_MEMORY_LIMIT | ||||
|     cpu: int = DEFAULT_CPU_LIMIT | ||||
|     time: int = 0 | ||||
|     stdout: int = DEFAULT_FILE_LIMIT | ||||
|     stderr: int = DEFAULT_FILE_LIMIT | ||||
|     proc: int = DEFAULT_PROC_LIMIT | ||||
| 
 | ||||
|     @field_validator("cpu", "time", mode="before") | ||||
|     model_config = ConfigDict(validate_assignment=True) | ||||
| 
 | ||||
|     @field_validator("cpu", mode="before") | ||||
|     @classmethod | ||||
|     def ensure_time_type(cls, v: Any) -> Time: | ||||
|     def ensure_time(cls, v: Any) -> Time: | ||||
|         if isinstance(v, str): | ||||
|             return Time(v) | ||||
|         raise ValueError(f'Must be a string, e.g., "1s" or "100ms", but got {v}') | ||||
|         raise ValueError("Must be a string") | ||||
| 
 | ||||
|     @field_validator("mem", "stdout", "stderr", mode="before") | ||||
|     @classmethod | ||||
|     def ensure_mem_type(cls, v: Any) -> Memory: | ||||
|     def ensure_mem(cls, v: Any) -> Memory: | ||||
|         if isinstance(v, str): | ||||
|             return Memory(v) | ||||
|         raise ValueError(f'Must be a string, e.g., "256m" or "1g", but got {v}') | ||||
| 
 | ||||
|     @model_validator(mode="after") | ||||
|     def set_time_if_not_set(self) -> "Limit": | ||||
|         if self.time == 0: | ||||
|             self.time = DEFAULT_CLOCK_LIMIT_MULTIPLIER * self.cpu | ||||
|         return self | ||||
|         raise ValueError("Must be a string") | ||||
| 
 | ||||
| 
 | ||||
| class Parser(str, Enum): | ||||
|  | @ -173,14 +125,13 @@ class Parser(str, Enum): | |||
|     KEYWORD = "keyword" | ||||
|     RESULT_STATUS = "result-status" | ||||
|     RESULT_DETAIL = "result-detail" | ||||
|     DEBUG = "debug" | ||||
|     DUMMY = "dummy" | ||||
|     FILE = "file" | ||||
|     DIFF = "diff" | ||||
|     ELF = "elf" | ||||
| 
 | ||||
| 
 | ||||
| class Case(StrictBaseModel): | ||||
| class Case(BaseModel): | ||||
|     env: List[str] = [] | ||||
|     command: str = ""  # Command to run | ||||
|     files: StageFiles = StageFiles() | ||||
|  | @ -190,21 +141,18 @@ class Case(StrictBaseModel): | |||
|         True, validation_alias=AliasChoices("copy-in-cwd", "copy_in_cwd") | ||||
|     ) | ||||
|     limit: Limit = Limit() | ||||
|     score: int = 0 | ||||
|     diff: ParserDiff = ParserDiff() | ||||
| 
 | ||||
| 
 | ||||
| class Stage(Case): | ||||
|     name: str = ""  # stage name | ||||
|     groups: List[str] = []  # list of groups | ||||
|     base_case_dir: str = Field( | ||||
|         ".", validation_alias=AliasChoices("base-case-dir", "base_case_dir") | ||||
|     )  # base directory for finding cases | ||||
|     skip: List[str] = [] | ||||
| 
 | ||||
|     parsers: List[Parser] = []  # list of parsers | ||||
|     dummy: ParserDummy = ParserDummy() | ||||
|     result_status: ParserResultStatus = Field( | ||||
|         ParserResultStatus(), | ||||
|         validation_alias=AliasChoices("result-status", "result_status"), | ||||
|     result_status: ParserDummy = Field( | ||||
|         ParserDummy(), validation_alias=AliasChoices("result-status", "result_status") | ||||
|     ) | ||||
|     keyword: ParserKeyword = ParserKeyword() | ||||
|     clangtidy: ParserKeyword = ParserKeyword() | ||||
|  | @ -216,7 +164,6 @@ class Stage(Case): | |||
|         validation_alias=AliasChoices("result-detail", "result_detail"), | ||||
|     ) | ||||
|     file: ParserFile = ParserFile() | ||||
|     # diff: ParserDiff = ParserDiff() # inherited from Case | ||||
| 
 | ||||
|     cases: Dict[str, Case] = {} | ||||
| 
 | ||||
|  | @ -237,7 +184,7 @@ class Stage(Case): | |||
|         return values | ||||
| 
 | ||||
| 
 | ||||
| class Release(StrictBaseModel): | ||||
| class Release(BaseModel): | ||||
|     end_time: datetime = Field( | ||||
|         datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc), | ||||
|         validation_alias=AliasChoices("end-time", "end_time"), | ||||
|  | @ -248,61 +195,17 @@ class Release(StrictBaseModel): | |||
|     )  # timestamp = 0, no begin time | ||||
| 
 | ||||
| 
 | ||||
| class SubmissionTime(StrictBaseModel): | ||||
|     begin: Optional[datetime] = None | ||||
|     end: Optional[datetime] = None | ||||
| class Task(BaseModel): | ||||
|     name: str = "unknown" | ||||
| 
 | ||||
| 
 | ||||
| class Penalties(StrictBaseModel): | ||||
|     hours: List[float] = [] | ||||
|     factors: List[float] = [] | ||||
| 
 | ||||
| 
 | ||||
| class Issue(StrictBaseModel): | ||||
|     skip: bool = False | ||||
| 
 | ||||
| 
 | ||||
| class Grading(StrictBaseModel): | ||||
|     skip_scoreboard: bool = Field( | ||||
|         False, validation_alias=AliasChoices("skip-scoreboard", "skip_scoreboard") | ||||
|     ) | ||||
|     skip_failed_table: bool = Field( | ||||
|         False, validation_alias=AliasChoices("skip-failed-table", "skip_failed_table") | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class Config(StrictBaseModel): | ||||
|     root: Path = Field(Path("."), exclude=True) | ||||
|     path: Path = Field(Path("task.toml"), exclude=True) | ||||
|     suffix: str = Field("", exclude=True) | ||||
| 
 | ||||
|     name: str = "unknown"  # Task name (e.g., hw3 ex5) | ||||
|     max_total_score: Optional[int] = Field( | ||||
|         None, validation_alias=AliasChoices("max-total-score", "max_total_score") | ||||
|     ) | ||||
|     issue: Issue = Issue() | ||||
|     grading: Grading = Grading() | ||||
|     scoreboard: str = "scoreboard.csv" | ||||
|     scoreboard_column_by_ref: bool = Field( | ||||
|         False, | ||||
|         validation_alias=AliasChoices( | ||||
|             "scoreboard-column-by-ref", "scoreboard_column_by_ref" | ||||
|         ), | ||||
|     ) | ||||
|     time: SubmissionTime = SubmissionTime()  # Valid time configuration | ||||
| class Config(BaseModel): | ||||
|     root: Path = Path(".") | ||||
|     path: Path = Path("task.toml") | ||||
|     task: Task = Task()  # Task name (e.g., hw3 ex5) | ||||
|     release: Release = Release()  # Release configuration | ||||
|     groups: Groups = Groups() | ||||
|     penalties: Penalties = Penalties() | ||||
|     stages: List[Stage] = []  # list of stage configurations | ||||
| 
 | ||||
|     @model_validator(mode="after") | ||||
|     def set_suffix(self) -> "Config": | ||||
|         if not self.suffix: | ||||
|             self.suffix = re.split(r"[-_/\s]+", self.name)[0] | ||||
|         return self | ||||
| 
 | ||||
|     @model_validator(mode="after") | ||||
|     def set_scoreboard(self) -> "Config": | ||||
|         if self.scoreboard == "auto": | ||||
|             self.scoreboard = f"scoreboard-{self.suffix}.csv" | ||||
|         return self | ||||
|     groups: Groups = Groups() | ||||
|     max_total_score: int = Field( | ||||
|         100, validation_alias=AliasChoices("max-total-score", "max_total_score") | ||||
|     ) | ||||
|  |  | |||
|  | @ -9,16 +9,16 @@ def get_task_conf_from_answers(answers: answer.Answers) -> task.Config: | |||
|     if answers.template_file_content: | ||||
|         toml_dict = tomli.loads(answers.template_file_content) | ||||
|         return task.Config( | ||||
|             name=answers.name, | ||||
|             task=task.Task(name=answers.name), | ||||
|             stages=toml_dict["stages"], | ||||
|         ) | ||||
|     language = answers.language | ||||
|     transformer_dict = get_transformer_dict() | ||||
|     if language not in transformer_dict: | ||||
|         return task.Config(name=answers.name, stages=[]) | ||||
|         return task.Config(task=task.Task(name=answers.name), stages=[]) | ||||
|     transformer = transformer_dict[language] | ||||
|     stages = transformer(language) | ||||
|     return task.Config(name=answers.name, stages=stages) | ||||
|     return task.Config(task=task.Task(name=answers.name), stages=stages) | ||||
| 
 | ||||
| 
 | ||||
| def get_transformer_dict() -> Dict[ | ||||
|  |  | |||
|  | @ -1,21 +1,9 @@ | |||
| import hashlib | ||||
| from pathlib import Path | ||||
| from typing import List, Tuple | ||||
| from typing import List | ||||
| 
 | ||||
| from joj3_config_generator.models import common, repo, result, task | ||||
| from joj3_config_generator.models.const import ( | ||||
|     CACHE_ROOT, | ||||
|     TEAPOT_CONFIG_ROOT, | ||||
|     TEAPOT_LOG_PATH, | ||||
| ) | ||||
| from joj3_config_generator.utils.logger import logger | ||||
| 
 | ||||
| 
 | ||||
| def get_teapot_env() -> List[str]: | ||||
|     return [ | ||||
|         f"REPOS_DIR={CACHE_ROOT}", | ||||
|         f"LOG_FILE_PATH={TEAPOT_LOG_PATH}", | ||||
|     ] | ||||
| from joj3_config_generator.models.const import TEAPOT_CONFIG_ROOT, TEAPOT_LOG_PATH | ||||
| 
 | ||||
| 
 | ||||
| def get_teapot_post_stage( | ||||
|  | @ -29,44 +17,13 @@ def get_teapot_post_stage( | |||
|         repo_conf.grading_repo_name, | ||||
|         "--max-total-score", | ||||
|         ( | ||||
|             str(task_conf.max_total_score) | ||||
|             if task_conf.max_total_score is not None | ||||
|             else str(repo_conf.max_total_score) | ||||
|             str(repo_conf.max_total_score) | ||||
|             if not task_conf.max_total_score | ||||
|             else str(task_conf.max_total_score) | ||||
|         ), | ||||
|         "--issue-label-name", | ||||
|         repo_conf.issue.label.name, | ||||
|         "--issue-label-color", | ||||
|         repo_conf.issue.label.color, | ||||
|         "--scoreboard-filename", | ||||
|         task_conf.scoreboard, | ||||
|     ] | ||||
|     if task_conf.scoreboard_column_by_ref: | ||||
|         args.append("--scoreboard-column-by-ref") | ||||
|     if task_conf.issue.skip: | ||||
|         args.append("--skip-result-issue") | ||||
|     if task_conf.grading.skip_scoreboard: | ||||
|         args.append("--skip-scoreboard") | ||||
|     if task_conf.grading.skip_failed_table: | ||||
|         args.append("--skip-failed-table") | ||||
|     if repo_conf.issue.label.exclusive: | ||||
|         args.append("--issue-label-exclusive") | ||||
|     if not repo_conf.issue.show_submitter: | ||||
|     if not repo_conf.submitter_in_issue_title: | ||||
|         args.append("--no-submitter-in-issue-title") | ||||
|     if task_conf.time.end: | ||||
|         args.extend( | ||||
|             [ | ||||
|                 "--end-time", | ||||
|                 task_conf.time.end.strftime("%Y-%m-%dT%H:%M:%S"), | ||||
|             ] | ||||
|         ) | ||||
|     if task_conf.penalties.hours: | ||||
|         penalty_config = ",".join( | ||||
|             f"{hour}={factor}" | ||||
|             for hour, factor in zip( | ||||
|                 task_conf.penalties.hours, task_conf.penalties.factors | ||||
|             ) | ||||
|         ) | ||||
|         args.extend(["--penalty-config", penalty_config]) | ||||
| 
 | ||||
|     stage_conf = result.StageDetail( | ||||
|         name="teapot", | ||||
|  | @ -75,7 +32,7 @@ def get_teapot_post_stage( | |||
|             with_=result.ExecutorWith( | ||||
|                 default=result.Cmd( | ||||
|                     args=args, | ||||
|                     env=get_teapot_env(), | ||||
|                     env=[f"LOG_FILE_PATH={TEAPOT_LOG_PATH}"], | ||||
|                     cpu_limit=common.Time("30s"), | ||||
|                     clock_limit=common.Time("60s"), | ||||
|                 ), | ||||
|  | @ -83,40 +40,21 @@ def get_teapot_post_stage( | |||
|             ), | ||||
|         ), | ||||
|         parsers=[ | ||||
|             result.Parser( | ||||
|                 name="log", with_=result.MsgConfig(msg="joj3 summary", level=-4) | ||||
|             ), | ||||
|             result.Parser(name="log", with_=result.MsgConfig(msg="joj3 summary")), | ||||
|             result.Parser(name="debug"), | ||||
|         ], | ||||
|     ) | ||||
|     return stage_conf | ||||
| 
 | ||||
| 
 | ||||
| def get_check_lists(repo_conf: repo.Config) -> Tuple[List[str], List[str]]: | ||||
|     base_dir = (repo_conf.root / repo_conf.path).parent | ||||
|     immutable_dir = base_dir / repo_conf.health_check.immutable_path | ||||
|     file_sums = [] | ||||
|     file_paths = [] | ||||
|     for file_path in sorted(immutable_dir.glob("**/*")): | ||||
|         if file_path.is_dir(): | ||||
|             continue | ||||
|         if not file_path.exists(): | ||||
|             logger.warning(f"Immutable file not found: {file_path}") | ||||
|             continue | ||||
|         file_sums.append(calc_sha256sum(file_path)) | ||||
|         file_paths.append(file_path.relative_to(immutable_dir).as_posix()) | ||||
|     return file_sums, file_paths | ||||
| 
 | ||||
| 
 | ||||
| def get_health_check_args(repo_conf: repo.Config) -> List[str]: | ||||
|     file_sums, file_paths = get_check_lists(repo_conf) | ||||
|     return [ | ||||
|         "/usr/local/bin/repo-health-checker", | ||||
|         "-root=.", | ||||
|         f"-repoSize={str(repo_conf.health_check.max_size / 1024 / 1024)}",  # B -> MB | ||||
|         *[f"-meta={meta}" for meta in repo_conf.health_check.required_files], | ||||
|         f"-checkFileSumList={','.join(file_sums)}", | ||||
|         f"-checkFileNameList={','.join(file_paths)}", | ||||
|         f"-repoSize={str(repo_conf.max_size)}", | ||||
|         *[f"-meta={meta}" for meta in repo_conf.files.required], | ||||
|         f"-checkFileSumList={','.join(get_hashes(repo_conf))}", | ||||
|         f"-checkFileNameList={','.join(repo_conf.files.immutable)}", | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
|  | @ -127,32 +65,28 @@ def get_teapot_check_args(repo_conf: repo.Config, task_conf: task.Config) -> Lis | |||
|         str(TEAPOT_CONFIG_ROOT / "teapot.env"), | ||||
|         "--grading-repo-name", | ||||
|         repo_conf.grading_repo_name, | ||||
|         "--scoreboard-filename", | ||||
|         task_conf.scoreboard, | ||||
|     ] | ||||
|     if repo_conf.groups.name or task_conf.groups.name: | ||||
|         groups = task_conf.groups if task_conf.groups.name else repo_conf.groups | ||||
|         group_config = ",".join( | ||||
|     if repo_conf.groups.name: | ||||
|         group_config_str = ",".join( | ||||
|             f"{name}={max_count}:{time_period}" | ||||
|             for name, max_count, time_period in zip( | ||||
|                 groups.name, | ||||
|                 groups.max_count, | ||||
|                 groups.time_period_hour, | ||||
|                 repo_conf.groups.name, | ||||
|                 repo_conf.groups.max_count, | ||||
|                 repo_conf.groups.time_period_hour, | ||||
|             ) | ||||
|         ) | ||||
|         res.extend(["--group-config", group_config]) | ||||
|     if task_conf.time.begin: | ||||
|         res.extend(["--begin-time", task_conf.time.begin.strftime("%Y-%m-%dT%H:%M:%S")]) | ||||
|     if task_conf.time.end: | ||||
|         res.extend(["--end-time", task_conf.time.end.strftime("%Y-%m-%dT%H:%M:%S")]) | ||||
|     if task_conf.penalties.hours: | ||||
|         penalty_config = ",".join( | ||||
|             f"{hour}={factor}" | ||||
|             for hour, factor in zip( | ||||
|                 task_conf.penalties.hours, task_conf.penalties.factors | ||||
|         if task_conf.groups.name: | ||||
|             overwrite_group_config_str = ",".join( | ||||
|                 f"{name}={max_count}:{time_period}" | ||||
|                 for name, max_count, time_period in zip( | ||||
|                     task_conf.groups.name, | ||||
|                     task_conf.groups.max_count, | ||||
|                     task_conf.groups.time_period_hour, | ||||
|                 ) | ||||
|             ) | ||||
|         res.extend(["--penalty-config", penalty_config]) | ||||
|             res.extend(["--group-config", overwrite_group_config_str]) | ||||
|         else: | ||||
|             res.extend(["--group-config", group_config_str]) | ||||
|     return res | ||||
| 
 | ||||
| 
 | ||||
|  | @ -161,13 +95,12 @@ def get_health_check_stage( | |||
| ) -> result.StageDetail: | ||||
|     health_check_stage = result.StageDetail( | ||||
|         name="Health Check", | ||||
|         groups=[], | ||||
|         group="", | ||||
|         executor=result.Executor( | ||||
|             name="local", | ||||
|             with_=result.ExecutorWith( | ||||
|                 default=result.Cmd( | ||||
|                     cpu_limit=common.Time("10s"), | ||||
|                     clock_limit=common.Time("20s"), | ||||
|                     cpu_limit=common.Time("10s"), clock_limit=common.Time("20s") | ||||
|                 ), | ||||
|                 cases=[ | ||||
|                     result.OptionalCmd( | ||||
|  | @ -175,7 +108,7 @@ def get_health_check_stage( | |||
|                     ), | ||||
|                     result.OptionalCmd( | ||||
|                         args=get_teapot_check_args(repo_conf, task_conf), | ||||
|                         env=get_teapot_env(), | ||||
|                         env=[f"LOG_FILE_PATH={TEAPOT_LOG_PATH}"], | ||||
|                     ), | ||||
|                 ], | ||||
|             ), | ||||
|  | @ -183,7 +116,7 @@ def get_health_check_stage( | |||
|         parsers=[ | ||||
|             result.Parser( | ||||
|                 name="healthcheck", | ||||
|                 with_=result.ScoreConfig(score=repo_conf.health_check.score), | ||||
|                 with_=result.ScoreConfig(score=repo_conf.health_check_score), | ||||
|             ), | ||||
|             result.Parser(name="debug"), | ||||
|         ], | ||||
|  | @ -197,3 +130,12 @@ def calc_sha256sum(file_path: Path) -> str: | |||
|         for byte_block in iter(lambda: f.read(64 * 1024), b""): | ||||
|             sha256_hash.update(byte_block) | ||||
|     return sha256_hash.hexdigest() | ||||
| 
 | ||||
| 
 | ||||
| def get_hashes(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] | ||||
|  |  | |||
|  | @ -2,11 +2,15 @@ import re | |||
| import shlex | ||||
| from functools import partial | ||||
| from pathlib import Path, PurePosixPath | ||||
| from typing import Any, Callable, Dict, List, Optional, Tuple, Union | ||||
| from typing import Any, Callable, Dict, List, Optional, Tuple | ||||
| 
 | ||||
| from joj3_config_generator.models import result, task | ||||
| from joj3_config_generator.models.common import StrictBaseModel | ||||
| from joj3_config_generator.models.const import DEFAULT_PATH_ENV, JOJ3_CONFIG_ROOT | ||||
| from joj3_config_generator.models.common import Memory, Time | ||||
| from joj3_config_generator.models.const import ( | ||||
|     DEFAULT_CLOCK_LIMIT_MULTIPLIER, | ||||
|     DEFAULT_PATH_ENV, | ||||
|     JOJ3_CONFIG_ROOT, | ||||
| ) | ||||
| from joj3_config_generator.utils.logger import logger | ||||
| 
 | ||||
| 
 | ||||
|  | @ -15,18 +19,14 @@ def get_conf_stage( | |||
|     task_stage: task.Stage, | ||||
|     cached: Dict[str, None], | ||||
| ) -> result.StageDetail: | ||||
|     if task_stage.groups: | ||||
|         groups = task_stage.groups | ||||
|     else: | ||||
|         # TODO: remove group matching | ||||
|         # single group is determined by adding between "[]" in the name of the task | ||||
|         if match := re.search(r"\[([^\[\]]+)\]", task_stage.name): | ||||
|             groups = [match.group(1)] | ||||
|         else: | ||||
|             groups = [] | ||||
|     conf_stage = result.StageDetail( | ||||
|         name=task_stage.name, | ||||
|         groups=groups, | ||||
|         # 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), | ||||
|  | @ -60,9 +60,8 @@ def get_parser_handler_map( | |||
|         task.Parser.CPPCHECK: (fix_keyword, task_stage.cppcheck), | ||||
|         task.Parser.CPPLINT: (fix_keyword, task_stage.cpplint), | ||||
|         task.Parser.RESULT_DETAIL: (fix_result_detail, task_stage.result_detail), | ||||
|         task.Parser.DEBUG: (fix_debug, None), | ||||
|         task.Parser.DUMMY: (fix_dummy, task_stage.dummy), | ||||
|         task.Parser.RESULT_STATUS: (fix_result_status, task_stage.result_status), | ||||
|         task.Parser.RESULT_STATUS: (fix_dummy, task_stage.result_status), | ||||
|         task.Parser.FILE: (fix_file, task_stage.file), | ||||
|         task.Parser.DIFF: ( | ||||
|             partial( | ||||
|  | @ -80,46 +79,33 @@ def get_parser_handler_map( | |||
| def get_executor_with( | ||||
|     task_stage: task.Stage, cached: Dict[str, None] | ||||
| ) -> result.ExecutorWith: | ||||
|     copy_in: dict[ | ||||
|         str, | ||||
|         Union[result.LocalFile, result.MemoryFile, result.PreparedFile, result.Symlink], | ||||
|     ] = { | ||||
|         file: result.LocalFile(src=str(JOJ3_CONFIG_ROOT / file)) | ||||
|         for file in task_stage.files.import_ | ||||
|         if file not in cached | ||||
|     } | ||||
|     for src, dst in task_stage.files.import_map.items(): | ||||
|         if dst in cached: | ||||
|             continue | ||||
|         if dst in task_stage.files.import_: | ||||
|             logger.warning( | ||||
|                 f"file {dst} imported multiple times. from files.import: {dst} and files.import-map: {src}" | ||||
|             ) | ||||
|         copy_in[dst] = result.LocalFile(src=str(JOJ3_CONFIG_ROOT / src)) | ||||
|     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), | ||||
|             env=[DEFAULT_PATH_ENV, *task_stage.env], | ||||
|             copy_in=copy_in, | ||||
|             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_in_dir="." if task_stage.copy_in_cwd else "", | ||||
|             copy_out=copy_out_files, | ||||
|             copy_in_cached={ | ||||
|                 file: file | ||||
|                 for file in cached | ||||
|                 if file not in task_stage.files.no_auto_import | ||||
|             }, | ||||
|             copy_in_cached={file: file for file in cached}, | ||||
|             copy_out_cached=file_export, | ||||
|             cpu_limit=task_stage.limit.cpu, | ||||
|             clock_limit=task_stage.limit.time, | ||||
|             memory_limit=task_stage.limit.mem, | ||||
|             cpu_limit=Time(task_stage.limit.cpu), | ||||
|             clock_limit=DEFAULT_CLOCK_LIMIT_MULTIPLIER * Time(task_stage.limit.cpu), | ||||
|             memory_limit=Memory(task_stage.limit.mem), | ||||
|             proc_limit=task_stage.limit.proc, | ||||
|             stderr=result.Collector( | ||||
|                 name="stderr", pipe=True, max=task_stage.limit.stderr | ||||
|                 name="stderr", pipe=True, max=Memory(task_stage.limit.stderr) | ||||
|             ), | ||||
|             stdout=result.Collector( | ||||
|                 name="stdout", pipe=True, max=task_stage.limit.stdout | ||||
|                 name="stdout", pipe=True, max=Memory(task_stage.limit.stdout) | ||||
|             ), | ||||
|         ), | ||||
|         cases=[], | ||||
|  | @ -138,11 +124,10 @@ def fix_keyword( | |||
|     for keyword, score in zip(keyword_config.keyword, keyword_config.weight): | ||||
|         score_groups.setdefault(score, []).append(keyword) | ||||
|     keyword_parser.with_ = result.KeywordMatchConfig( | ||||
|         score=keyword_config.score, | ||||
|         matches=[ | ||||
|             result.KeywordConfig(keywords=keywords, score=score) | ||||
|             for score, keywords in score_groups.items() | ||||
|         ], | ||||
|         ] | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -165,35 +150,17 @@ def fix_result_detail( | |||
|         show_memory=result_detail_parser_config.mem, | ||||
|         show_error=result_detail_parser_config.error, | ||||
|         show_proc_peak=result_detail_parser_config.proc_peak, | ||||
|         files_in_code_block=result_detail_parser_config.code_block, | ||||
|         max_file_length=result_detail_parser_config.max_length, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| 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=dummy_parser_config.force_quit, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def fix_debug(parser_config: StrictBaseModel, parser: result.Parser) -> None: | ||||
|     logger.warning( | ||||
|         "debug parser enabled, should be disabled as soon as possible after issue is fixed" | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def fix_result_status( | ||||
|     result_status_parser_config: task.ParserResultStatus, | ||||
|     result_status_parser: result.Parser, | ||||
| ) -> None: | ||||
|     result_status_parser.with_ = result.ResultStatusConfig( | ||||
|         score=result_status_parser_config.score, | ||||
|         comment=result_status_parser_config.comment, | ||||
|         force_quit_on_not_accepted=result_status_parser_config.force_quit, | ||||
|         force_quit_on_not_accepted=dummy_parser_config.force_quit, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -210,19 +177,18 @@ def fix_diff( | |||
|     task_path: Path, | ||||
| ) -> None: | ||||
|     base_dir = JOJ3_CONFIG_ROOT / task_path.parent | ||||
|     case_base_dir = Path(task_stage.base_case_dir) | ||||
|     # cases not specified in the toml config (auto-detected) | ||||
|     unspecified_cases = get_unspecified_cases( | ||||
|         task_root, task_path, case_base_dir, task_stage.cases | ||||
|     ) | ||||
|     unspecified_cases = get_unspecified_cases(task_root, task_path, task_stage.cases) | ||||
|     # cases specified in toml config but not skipped | ||||
|     specified_cases = [(case, task_stage.cases[case]) for case in task_stage.cases] | ||||
|     specified_cases = [ | ||||
|         (case, task_stage.cases[case]) | ||||
|         for case in task_stage.cases | ||||
|         if case not in task_stage.skip | ||||
|     ] | ||||
|     stage_cases = [] | ||||
|     parser_cases = [] | ||||
|     for case_name, case in specified_cases: | ||||
|         stdin, stdout = get_stdin_stdout( | ||||
|             task_root, task_path, case_base_dir, case_name, case | ||||
|         ) | ||||
|         stdin, stdout = get_stdin_stdout(task_root, task_path, case_name, case) | ||||
|         if stdout is None: | ||||
|             logger.warning( | ||||
|                 f"In file {task_root / task_path}, " | ||||
|  | @ -234,7 +200,7 @@ def fix_diff( | |||
|             stdin=stdin, | ||||
|             args=shlex.split(case.command) if case.command else None, | ||||
|             cpu_limit=case.limit.cpu, | ||||
|             clock_limit=case.limit.time, | ||||
|             clock_limit=DEFAULT_CLOCK_LIMIT_MULTIPLIER * case.limit.cpu, | ||||
|             memory_limit=case.limit.mem, | ||||
|             proc_limit=task_stage.limit.proc, | ||||
|         ) | ||||
|  | @ -249,24 +215,18 @@ def fix_diff( | |||
|         if cmd.proc_limit == executor.with_.default.proc_limit: | ||||
|             cmd.proc_limit = None | ||||
|         stage_cases.append(cmd) | ||||
| 
 | ||||
|         def get_diff_attribute(attribute_name: str) -> Any: | ||||
|             if case.diff and attribute_name in case.diff.model_fields_set: | ||||
|                 return getattr(case.diff, attribute_name) | ||||
|             return getattr(task_stage.diff, attribute_name) | ||||
| 
 | ||||
|         parser_case = result.DiffCasesConfig( | ||||
|             outputs=[ | ||||
|                 result.DiffOutputConfig( | ||||
|                     score=get_diff_attribute("score"), | ||||
|                     filename="stdout", | ||||
|                     score=case.diff.output.score, | ||||
|                     file_name="stdout", | ||||
|                     answer_path=stdout, | ||||
|                     compare_space=not get_diff_attribute("ignore_spaces"), | ||||
|                     always_hide=get_diff_attribute("hide"), | ||||
|                     force_quit_on_diff=get_diff_attribute("force_quit"), | ||||
|                     max_diff_length=get_diff_attribute("max_length"), | ||||
|                     max_diff_lines=get_diff_attribute("max_lines"), | ||||
|                     hide_common_prefix=get_diff_attribute("hide_common_prefix"), | ||||
|                     force_quit_on_diff=case.diff.output.force_quit, | ||||
|                     always_hide=case.diff.output.hide, | ||||
|                     compare_space=not case.diff.output.ignore_spaces, | ||||
|                     max_diff_length=case.diff.output.max_length, | ||||
|                     max_diff_lines=case.diff.output.max_lines, | ||||
|                     hide_common_prefix=case.diff.output.hide_common_prefix, | ||||
|                 ) | ||||
|             ] | ||||
|         ) | ||||
|  | @ -274,20 +234,18 @@ def fix_diff( | |||
|     for case_name in unspecified_cases: | ||||
|         cmd = result.OptionalCmd( | ||||
|             stdin=result.LocalFile(src=str(base_dir / f"{case_name}.in")), | ||||
|             cpu_limit=None, | ||||
|             clock_limit=None, | ||||
|             memory_limit=None, | ||||
|             proc_limit=None, | ||||
|         ) | ||||
|         stage_cases.append(cmd) | ||||
|         parser_case = result.DiffCasesConfig( | ||||
|             outputs=[ | ||||
|                 result.DiffOutputConfig( | ||||
|                     score=task_stage.diff.score, | ||||
|                     filename="stdout", | ||||
|                     score=task_stage.diff.default_score, | ||||
|                     file_name="stdout", | ||||
|                     answer_path=str(base_dir / f"{case_name}.out"), | ||||
|                     compare_space=not task_stage.diff.ignore_spaces, | ||||
|                     always_hide=task_stage.diff.hide, | ||||
|                     force_quit_on_diff=task_stage.diff.force_quit, | ||||
|                     max_diff_length=task_stage.diff.max_length, | ||||
|                     max_diff_lines=task_stage.diff.max_lines, | ||||
|                     hide_common_prefix=task_stage.diff.hide_common_prefix, | ||||
|                 ) | ||||
|             ] | ||||
|         ) | ||||
|  | @ -297,12 +255,10 @@ def fix_diff( | |||
| 
 | ||||
| 
 | ||||
| def get_unspecified_cases( | ||||
|     task_root: Path, task_path: Path, case_base_dir: Path, cases: Dict[str, task.Case] | ||||
|     task_root: Path, task_path: Path, cases: Dict[str, task.Case] | ||||
| ) -> List[str]: | ||||
|     testcases = set() | ||||
|     for testcases_path in ((task_root / task_path).parent / case_base_dir).glob( | ||||
|         "**/*.in" | ||||
|     ): | ||||
|     for testcases_path in (task_root / task_path).parent.glob("**/*.in"): | ||||
|         if not testcases_path.with_suffix(".out").exists(): | ||||
|             logger.warning( | ||||
|                 f"In file {task_root / task_path}, " | ||||
|  | @ -329,28 +285,18 @@ def get_unspecified_cases( | |||
| 
 | ||||
| 
 | ||||
| def get_stdin_stdout( | ||||
|     task_root: Path, | ||||
|     task_path: Path, | ||||
|     case_base_dir: Path, | ||||
|     case_name: str, | ||||
|     case: task.Case, | ||||
|     task_root: Path, task_path: Path, case_name: str, case: task.Case | ||||
| ) -> Tuple[result.Stdin, Optional[str]]: | ||||
|     base_dir = (task_root / task_path).parent / case_base_dir | ||||
|     case_stdout_name = case.out_ if case.out_ else f"{case_name}.out" | ||||
|     stdin: result.Stdin = result.MemoryFile(content="") | ||||
|     stdout = None | ||||
|     for case_stdout_path in base_dir.glob("**/*.out"): | ||||
|         if not case.out_:  # if not set, look for .out files with case name | ||||
|             if case_stdout_path.name != f"{case_name}.out": | ||||
|                 continue | ||||
|         else:  # if set, look for .out files with the same relative path | ||||
|             if PurePosixPath(case.out_) != PurePosixPath(case_stdout_path).relative_to( | ||||
|                 base_dir | ||||
|             ): | ||||
|     for case_stdout_path in (task_root / task_path).parent.glob("**/*.out"): | ||||
|         if case_stdout_path.name != case_stdout_name: | ||||
|             continue | ||||
|         stdout = str(JOJ3_CONFIG_ROOT / case_stdout_path.relative_to(task_root)) | ||||
|         case_stdin_path = case_stdout_path.with_suffix(".in") | ||||
|         if case.in_: | ||||
|             case_stdin_path = Path(base_dir / case.in_) | ||||
|             case_stdin_path = Path((task_root / task_path).parent / case.in_) | ||||
|         if not case_stdin_path.exists(): | ||||
|             logger.warning( | ||||
|                 f"In file {task_root / task_path}, " | ||||
|  |  | |||
							
								
								
									
										32
									
								
								pdm.lock
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								pdm.lock
									
									
									
									
									
								
							|  | @ -5,7 +5,7 @@ | |||
| groups = ["default", "dev", "lint", "test"] | ||||
| strategy = ["inherit_metadata"] | ||||
| lock_version = "4.5.0" | ||||
| content_hash = "sha256:0d342f3006bcf50ba9bf77ee49f2b03705b001e9e558d401ef66d24f74610b92" | ||||
| content_hash = "sha256:871844bf136123c9677a605fce706c5ea8f86734f29eefcba10513c082531657" | ||||
| 
 | ||||
| [[metadata.targets]] | ||||
| requires_python = ">=3.9" | ||||
|  | @ -510,7 +510,7 @@ name = "packaging" | |||
| version = "24.2" | ||||
| requires_python = ">=3.8" | ||||
| summary = "Core utilities for Python packages" | ||||
| groups = ["default", "lint", "test"] | ||||
| groups = ["lint", "test"] | ||||
| files = [ | ||||
|     {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, | ||||
|     {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, | ||||
|  | @ -835,34 +835,6 @@ files = [ | |||
|     {file = "runs-1.2.2.tar.gz", hash = "sha256:9dc1815e2895cfb3a48317b173b9f1eac9ba5549b36a847b5cc60c3bf82ecef1"}, | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "setuptools" | ||||
| version = "80.9.0" | ||||
| requires_python = ">=3.9" | ||||
| summary = "Easily download, build, install, upgrade, and uninstall Python packages" | ||||
| groups = ["default"] | ||||
| files = [ | ||||
|     {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, | ||||
|     {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "setuptools-scm" | ||||
| version = "9.2.0" | ||||
| requires_python = ">=3.8" | ||||
| summary = "the blessed package to manage your versions by scm tags" | ||||
| groups = ["default"] | ||||
| dependencies = [ | ||||
|     "packaging>=20", | ||||
|     "setuptools", | ||||
|     "tomli>=1; python_version < \"3.11\"", | ||||
|     "typing-extensions; python_version < \"3.10\"", | ||||
| ] | ||||
| files = [ | ||||
|     {file = "setuptools_scm-9.2.0-py3-none-any.whl", hash = "sha256:c551ef54e2270727ee17067881c9687ca2aedf179fa5b8f3fab9e8d73bdc421f"}, | ||||
|     {file = "setuptools_scm-9.2.0.tar.gz", hash = "sha256:6662c9b9497b6c9bf13bead9d7a9084756f68238302c5ed089fb4dbd29d102d7"}, | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "shellingham" | ||||
| version = "1.5.4" | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| [build-system] | ||||
| requires = ["pdm-backend", "setuptools>=80", "setuptools-scm>=8"] | ||||
| requires = ["pdm-backend", "setuptools>=64", "setuptools-scm>=8"] | ||||
| build-backend = "setuptools.build_meta" | ||||
| 
 | ||||
| [project] | ||||
| name = "JOJ3-config-generator" | ||||
| dynamic = ["version"] | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|     "pyyaml>=6.0.2", | ||||
|     "typer>=0.12.5", | ||||
|  | @ -14,7 +14,6 @@ dependencies = [ | |||
|     "humanfriendly>=10.0", | ||||
|     "tomlkit>=0.13.2", | ||||
|     "tomli>=2.2.1", | ||||
|     "setuptools-scm>=9.2.0", | ||||
| ] | ||||
| requires-python = ">=3.9" | ||||
| authors = [{ name = "JOJ3-dev", email = "joj3@focs.ji.sjtu.edu.cn" }] | ||||
|  | @ -70,6 +69,7 @@ disallow_untyped_defs = true | |||
| [tool.pydantic-mypy] | ||||
| init_forbid_extra = true | ||||
| init_typed = true | ||||
| warn_required_dynamic_aliases = true | ||||
| warn_untyped_fields = true | ||||
| 
 | ||||
| [tool.setuptools_scm] | ||||
|  |  | |||
|  | @ -3,13 +3,14 @@ grading-repo-name = "ece280-joj" | |||
| sandbox-token = "test" | ||||
| # reconfigure later | ||||
| max-total-score = 1000 | ||||
| 
 | ||||
| health-check.max-size = "50.5m" | ||||
| health-check.immutable-path = "immutable" | ||||
| health-check.required-files = ["README.md", "Changelog.md"] | ||||
| max-size = 50.5 | ||||
| 
 | ||||
| # for tests | ||||
| [groups] | ||||
| name = ["joj", "run"] | ||||
| max-count = [1000, 1000] | ||||
| time-period-hour = [24, 24] | ||||
| 
 | ||||
| [files] | ||||
| required = ["README.md", "Changelog.md"] | ||||
| immutable = [".gitignore", ".gitattributes",".gitea/workflows/push.yaml", ".gitea/workflows/release.yaml"] | ||||
|  |  | |||
|  | @ -1,15 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.log", | ||||
|     "expireUnixTimestamp": 1735574399, | ||||
|     "effectiveUnixTimestamp": 1735487999, | ||||
|     "actorCsvPath": "/home/tt/.config/joj/students.csv", | ||||
|     "maxTotalScore": 10245871, | ||||
|     "stage": { | ||||
|         "sandboxExecServer": "172.17.0.1:5051", | ||||
|         "sandboxToken": "test", | ||||
|         "outputPath": "/tmp/joj3_result.json", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "Health Check", | ||||
|             "groups": [], | ||||
|                 "group": "", | ||||
|                 "executor": { | ||||
|                     "name": "local", | ||||
|                     "with": { | ||||
|  | @ -61,8 +64,8 @@ | |||
|                                     "-repoSize=50.5", | ||||
|                                     "-meta=README.md", | ||||
|                                     "-meta=Changelog.md", | ||||
|                                 "-checkFileSumList=b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,2ba059f3977e2e3dee6cacbfbf0ba2578baa1b8e04b4977aec400868b6e49856,3db23f7fb2ca9814617e767ddc41b77073180b3b0b73e87b5f2a6d3129f88f3a,a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc", | ||||
|                                 "-checkFileNameList=.gitattributes,.gitea/workflows/push.yaml,.gitea/workflows/release.yaml,.gitignore" | ||||
|                                     "-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,2ba059f3977e2e3dee6cacbfbf0ba2578baa1b8e04b4977aec400868b6e49856,3db23f7fb2ca9814617e767ddc41b77073180b3b0b73e87b5f2a6d3129f88f3a", | ||||
|                                     "-checkFileNameList=.gitignore,.gitattributes,.gitea/workflows/push.yaml,.gitea/workflows/release.yaml" | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|  | @ -72,19 +75,10 @@ | |||
|                                     "/home/tt/.config/teapot/teapot.env", | ||||
|                                     "--grading-repo-name", | ||||
|                                     "ece280-joj", | ||||
|                                 "--scoreboard-filename", | ||||
|                                 "scoreboard-hw7.csv", | ||||
|                                     "--group-config", | ||||
|                                 "Manuel=500:24,Boming=501:48,Nuvole=502:72", | ||||
|                                 "--begin-time", | ||||
|                                 "2024-12-29T23:59:59", | ||||
|                                 "--end-time", | ||||
|                                 "2024-12-30T23:59:59", | ||||
|                                 "--penalty-config", | ||||
|                                 "24.0=0.5,48.0=0.25,72.0=0.1" | ||||
|                                     "Manuel=500:24,Boming=501:48,Nuvole=502:72" | ||||
|                                 ], | ||||
|                                 "env": [ | ||||
|                                 "REPOS_DIR=/home/tt/.cache", | ||||
|                                     "LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log" | ||||
|                                 ] | ||||
|                             } | ||||
|  | @ -106,7 +100,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "Compilation", | ||||
|             "groups": [], | ||||
|                 "group": "", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -142,9 +136,6 @@ | |||
|                             "copyIn": { | ||||
|                                 "tools/compile": { | ||||
|                                     "src": "/home/tt/.config/joj/tools/compile" | ||||
|                             }, | ||||
|                             "h7/Makefile": { | ||||
|                                 "src": "/home/tt/.config/joj/tools/Makefile" | ||||
|                                 } | ||||
|                             }, | ||||
|                             "copyInCached": {}, | ||||
|  | @ -202,9 +193,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "[cq] Filelength", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -271,7 +260,6 @@ | |||
|                     { | ||||
|                         "name": "keyword", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -311,9 +299,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "[cq] Clang-tidy", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -382,7 +368,6 @@ | |||
|                     { | ||||
|                         "name": "clangtidy", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -448,9 +433,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "[cq] Cppcheck", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -515,14 +498,12 @@ | |||
|                     { | ||||
|                         "name": "keyword", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [] | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         "name": "cppcheck", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -545,7 +526,6 @@ | |||
|                     { | ||||
|                         "name": "clangtidy", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [] | ||||
|                         } | ||||
|                     }, | ||||
|  | @ -571,7 +551,6 @@ | |||
|                     { | ||||
|                         "name": "cpplint", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [] | ||||
|                         } | ||||
|                     }, | ||||
|  | @ -580,7 +559,7 @@ | |||
|                         "with": { | ||||
|                             "score": 0, | ||||
|                             "comment": "", | ||||
|                         "forceQuitOnNotAccepted": true | ||||
|                             "forceQuitOnNotAccepted": false | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|  | @ -594,7 +573,7 @@ | |||
|                         "with": { | ||||
|                             "score": 0, | ||||
|                             "comment": "", | ||||
|                         "forceQuit": false | ||||
|                             "forceQuitOnNotAccepted": false | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|  | @ -608,9 +587,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "[cq] Cpplint", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -674,7 +651,6 @@ | |||
|                     { | ||||
|                         "name": "cpplint", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -720,9 +696,7 @@ | |||
|             }, | ||||
|             { | ||||
|                 "name": "[joj] ex2-asan", | ||||
|             "groups": [ | ||||
|                 "joj" | ||||
|             ], | ||||
|                 "group": "joj", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -748,7 +722,7 @@ | |||
|                                 "pipe": true | ||||
|                             }, | ||||
|                             "cpuLimit": 1000000000, | ||||
|                         "clockLimit": 100000000000, | ||||
|                             "clockLimit": 2000000000, | ||||
|                             "memoryLimit": 134217728, | ||||
|                             "stackLimit": 0, | ||||
|                             "procLimit": 50, | ||||
|  | @ -775,27 +749,7 @@ | |||
|                             "dataSegmentLimit": false, | ||||
|                             "addressSpaceLimit": false | ||||
|                         }, | ||||
|                     "cases": [ | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "content": "" | ||||
|                             }, | ||||
|                             "cpuLimit": 500000000, | ||||
|                             "clockLimit": 1000000000, | ||||
|                             "memoryLimit": 5242880 | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "content": "" | ||||
|                             }, | ||||
|                             "memoryLimit": 5242880 | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "content": "" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                         "cases": [] | ||||
|                     } | ||||
|                 }, | ||||
|                 "parsers": [ | ||||
|  | @ -803,53 +757,7 @@ | |||
|                         "name": "diff", | ||||
|                         "with": { | ||||
|                             "name": "diff", | ||||
|                         "cases": [ | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 10, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/basic/cases/case0.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/basic/cases/case1.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 10, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/basic/cases/case2.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": true, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                             "cases": [] | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|  | @ -874,10 +782,11 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [ | ||||
|             { | ||||
|                 "name": "teapot", | ||||
|             "groups": [], | ||||
|                 "group": "", | ||||
|                 "executor": { | ||||
|                     "name": "local", | ||||
|                     "with": { | ||||
|  | @ -889,20 +798,9 @@ | |||
|                                 "--grading-repo-name", | ||||
|                                 "ece280-joj", | ||||
|                                 "--max-total-score", | ||||
|                             "10245871", | ||||
|                             "--issue-label-name", | ||||
|                             "Kind/Testing", | ||||
|                             "--issue-label-color", | ||||
|                             "#795548", | ||||
|                             "--scoreboard-filename", | ||||
|                             "scoreboard-hw7.csv", | ||||
|                             "--end-time", | ||||
|                             "2024-12-30T23:59:59", | ||||
|                             "--penalty-config", | ||||
|                             "24.0=0.5,48.0=0.25,72.0=0.1" | ||||
|                                 "10245871" | ||||
|                             ], | ||||
|                             "env": [ | ||||
|                             "REPOS_DIR=/home/tt/.cache", | ||||
|                                 "LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log" | ||||
|                             ], | ||||
|                             "stdin": { | ||||
|  | @ -947,9 +845,7 @@ | |||
|                     { | ||||
|                         "name": "log", | ||||
|                         "with": { | ||||
|                         "filename": "stdout", | ||||
|                         "msg": "joj3 summary", | ||||
|                         "level": -4 | ||||
|                             "msg": "joj3 summary" | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|  | @ -960,3 +856,4 @@ | |||
|             } | ||||
|         ] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,14 +1,9 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| max-total-score = 10245871 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| scoreboard = "auto" | ||||
| 
 | ||||
| [penalties] | ||||
| hours = [ 24, 48, 72 ] | ||||
| factors = [ 0.5, 0.25, 0.1 ] | ||||
| release.end-time = 2024-12-30 23:59:59+08:00 | ||||
| release.begin-time = 2024-12-29 23:59:59+08:00 | ||||
| 
 | ||||
| [groups] | ||||
| name = ["Manuel", "Boming", "Nuvole"] | ||||
|  | @ -20,8 +15,8 @@ name = "Compilation" | |||
| env = [ "CC=clang", "CXX=clang++" ] | ||||
| command = "./tools/compile" # eg. script running cmake commands | ||||
| files.import = [ "tools/compile" ] | ||||
| files.import-map = { "tools/Makefile" = "h7/Makefile" } | ||||
| files.export = [ "h7/build/ex2", "h7/build/ex2-asan", "h7/build/ex2-ubsan", "h7/build/ex2-msan", "h7/build/compile_commands.json" ] | ||||
| score = 1 | ||||
| 
 | ||||
| # compile parsers | ||||
| parsers = [ "result-detail", "result-status" ] | ||||
|  | @ -91,29 +86,24 @@ command="./h7/build/ex2-asan -a" | |||
| copy-in-cwd = false | ||||
| files.import = [ "h7/build/ex2-asan" ] | ||||
| limit.mem = "128m" | ||||
| limit.time = "100s" | ||||
| 
 | ||||
| diff.score = 10 | ||||
| 
 | ||||
| parsers = [ "diff", "result-detail" ] | ||||
| result-detail.exit-status = 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.time = "1s" | ||||
| case0.limit.mem = "5m" | ||||
| case0.diff.ignore-spaces = true | ||||
| case0.diff.output.ignore-spaces = true | ||||
| #case0.limit.stdout = 8 | ||||
| #case0.command = "./h7/build/ex2" | ||||
| case0.in = "case0.in" | ||||
| 
 | ||||
| case1.diff.score = 5 | ||||
| case1.diff.output.score = 5 | ||||
| case1.limit.cpu = "1s" | ||||
| case1.limit.mem = "5m" | ||||
| case1.diff.ignore-spaces = true | ||||
| case1.diff.output.ignore-spaces = true | ||||
| #case1.limit.stdout = 8 | ||||
| #case1.command = "./h7/build/ex2" | ||||
| case1.in = "case1.in" | ||||
| 
 | ||||
| case2.diff.hide = true | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Clang-tidy", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -77,7 +78,6 @@ | |||
|                     { | ||||
|                         "name": "clangtidy", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -142,5 +142,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Cppcheck", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -70,7 +71,6 @@ | |||
|                     { | ||||
|                         "name": "cppcheck", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -112,5 +112,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Cpplint", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -69,7 +70,6 @@ | |||
|                     { | ||||
|                         "name": "cpplint", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -114,5 +114,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[joj] ex2-asan", | ||||
|             "groups": [ | ||||
|                 "joj" | ||||
|             ], | ||||
|                 "group": "joj", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -143,7 +144,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/case0.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -158,7 +159,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 123214122421, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/case1.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -173,7 +174,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 1232131, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/case9.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -188,7 +189,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 92321, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task1/subtask1/case11.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -203,7 +204,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 823131, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task1/subtask1/case10.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -218,7 +219,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 2590, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task1/case5.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -233,7 +234,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/case2.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -248,7 +249,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task1/case4.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -263,7 +264,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task2/case6.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -278,7 +279,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task2/case7.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -293,365 +294,7 @@ | |||
|                                     "outputs": [ | ||||
|                                         { | ||||
|                                             "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task2/case8.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "result-detail", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "comment": "", | ||||
|                         "showExxecutorStatus": true, | ||||
|                         "showExitStatus": true, | ||||
|                         "showError": false, | ||||
|                         "showTime": true, | ||||
|                         "showMemory": true, | ||||
|                         "showRuntime": true, | ||||
|                         "showProcPeak": false, | ||||
|                         "showFiles": [ | ||||
|                             "stderr" | ||||
|                         ], | ||||
|                         "filesInCodeBlock": true, | ||||
|                         "maxFileLength": 2048 | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "[joj] ex2-asan base dir task1", | ||||
|             "groups": [ | ||||
|                 "joj" | ||||
|             ], | ||||
|             "executor": { | ||||
|                 "name": "sandbox", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [ | ||||
|                             "./h7/build/ex2-asan", | ||||
|                             "-a" | ||||
|                         ], | ||||
|                         "env": [ | ||||
|                             "PATH=/usr/bin:/bin:/usr/local/bin" | ||||
|                         ], | ||||
|                         "stdin": { | ||||
|                             "content": "" | ||||
|                         }, | ||||
|                         "stdout": { | ||||
|                             "name": "stdout", | ||||
|                             "max": 10485760, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "stderr": { | ||||
|                             "name": "stderr", | ||||
|                             "max": 10485760, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "cpuLimit": 3000000000, | ||||
|                         "clockLimit": 6000000000, | ||||
|                         "memoryLimit": 10485760, | ||||
|                         "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/task1/case5.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task1/case9.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task1/case4.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task1/subtask1/case10.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task1/subtask1/case11.in" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "parsers": [ | ||||
|                 { | ||||
|                     "name": "diff", | ||||
|                     "with": { | ||||
|                         "name": "diff", | ||||
|                         "cases": [ | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 2590, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task1/case5.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 99999, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task1/case9.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task1/case4.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task1/subtask1/case10.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task1/subtask1/case11.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "result-detail", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "comment": "", | ||||
|                         "showExxecutorStatus": true, | ||||
|                         "showExitStatus": true, | ||||
|                         "showError": false, | ||||
|                         "showTime": true, | ||||
|                         "showMemory": true, | ||||
|                         "showRuntime": true, | ||||
|                         "showProcPeak": false, | ||||
|                         "showFiles": [ | ||||
|                             "stderr" | ||||
|                         ], | ||||
|                         "filesInCodeBlock": true, | ||||
|                         "maxFileLength": 2048 | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "[joj] ex2-asan base dir task2", | ||||
|             "groups": [ | ||||
|                 "joj" | ||||
|             ], | ||||
|             "executor": { | ||||
|                 "name": "sandbox", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [ | ||||
|                             "./h7/build/ex2-asan", | ||||
|                             "-a" | ||||
|                         ], | ||||
|                         "env": [ | ||||
|                             "PATH=/usr/bin:/bin:/usr/local/bin" | ||||
|                         ], | ||||
|                         "stdin": { | ||||
|                             "content": "" | ||||
|                         }, | ||||
|                         "stdout": { | ||||
|                             "name": "stdout", | ||||
|                             "max": 10485760, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "stderr": { | ||||
|                             "name": "stderr", | ||||
|                             "max": 10485760, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "cpuLimit": 3000000000, | ||||
|                         "clockLimit": 6000000000, | ||||
|                         "memoryLimit": 10485760, | ||||
|                         "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/task2/case9.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task2/case6.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task2/case7.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/diff/task2/case8.in" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "parsers": [ | ||||
|                 { | ||||
|                     "name": "diff", | ||||
|                     "with": { | ||||
|                         "name": "diff", | ||||
|                         "cases": [ | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 99999, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task2/case9.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task2/case6.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/diff/task2/case7.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 100, | ||||
|                                         "filename": "stdout", | ||||
|                                             "fileName": "stdout", | ||||
|                                             "answerPath": "/home/tt/.config/joj/diff/task2/case8.out", | ||||
|                                             "compareSpace": false, | ||||
|                                             "alwaysHide": false, | ||||
|  | @ -687,5 +330,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  | @ -17,63 +17,26 @@ parsers = ["diff", "result-detail"] | |||
| result-detail.exit-status = true | ||||
| result-detail.stderr = true | ||||
| 
 | ||||
| diff.score = 100 | ||||
| diff.default-score = 100 | ||||
| 
 | ||||
| case0.diff.score = 5 | ||||
| case0.diff.output.score = 5 | ||||
| case0.limit.cpu = "1s" | ||||
| case0.limit.mem = "2m" | ||||
| case0.diff.ignore-spaces = true | ||||
| case0.diff.output.ignore-spaces = true | ||||
| case0.command = "./h7/build/ex2" | ||||
| case0.in = "case0.in" | ||||
| 
 | ||||
| case1.diff.score = 123214122421 | ||||
| case1.diff.output.score = 123214122421 | ||||
| case1.limit.cpu = "2s" | ||||
| case1.limit.mem = "4m" | ||||
| case1.diff.ignore-spaces = true | ||||
| case1.diff.output.ignore-spaces = true | ||||
| case1.command = "./h7/build/ex2" | ||||
| 
 | ||||
| case9.diff.score = 1232131 | ||||
| case9.diff.output.score = 1232131 | ||||
| case9.limit.mem = "10m" | ||||
| 
 | ||||
| case11.diff.score = 92321 | ||||
| case11.diff.output.score = 92321 | ||||
| 
 | ||||
| case10.diff.score = 823131 | ||||
| case10.diff.output.score = 823131 | ||||
| 
 | ||||
| case5.diff.score = 2590 | ||||
| 
 | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[joj] ex2-asan base dir task1" | ||||
| command = "./h7/build/ex2-asan -a" | ||||
| base-case-dir = "task1" | ||||
| files.import = ["h7/build/ex2-asan"] | ||||
| limit.cpu = "3s" | ||||
| limit.mem = "10m" | ||||
| limit.stdout = "10m" | ||||
| limit.stderr = "10m" | ||||
| 
 | ||||
| parsers = ["diff", "result-detail"] | ||||
| result-detail.exit-status = true | ||||
| result-detail.stderr = true | ||||
| 
 | ||||
| diff.score = 100 | ||||
| 
 | ||||
| case5.diff.score = 2590 | ||||
| case9.diff.score = 99999 | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[joj] ex2-asan base dir task2" | ||||
| command = "./h7/build/ex2-asan -a" | ||||
| base-case-dir = "task2" | ||||
| files.import = ["h7/build/ex2-asan"] | ||||
| limit.cpu = "3s" | ||||
| limit.mem = "10m" | ||||
| limit.stdout = "10m" | ||||
| limit.stderr = "10m" | ||||
| 
 | ||||
| parsers = ["diff", "result-detail"] | ||||
| result-detail.exit-status = true | ||||
| result-detail.stderr = true | ||||
| 
 | ||||
| diff.score = 100 | ||||
| case9.diff.score = 99999 | ||||
| case5.diff.output.score = 2590 | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] elf", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -73,7 +74,6 @@ | |||
|                     { | ||||
|                         "name": "elf", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -122,5 +122,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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] elf" | ||||
|  |  | |||
|  | @ -1,179 +0,0 @@ | |||
| { | ||||
|     "name": "health check", | ||||
|     "logPath": "/home/tt/.cache/joj3/health/joj3.log", | ||||
|     "actorCsvPath": "/home/tt/.config/joj/students.csv", | ||||
|     "sandboxExecServer": "172.17.0.1:5051", | ||||
|     "sandboxToken": "", | ||||
|     "outputPath": "/tmp/joj3_result.json", | ||||
|     "preStages": [], | ||||
|     "stages": [ | ||||
|         { | ||||
|             "name": "Health Check", | ||||
|             "groups": [], | ||||
|             "executor": { | ||||
|                 "name": "local", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [], | ||||
|                         "env": [ | ||||
|                             "PATH=/usr/bin:/bin:/usr/local/bin" | ||||
|                         ], | ||||
|                         "stdin": { | ||||
|                             "content": "" | ||||
|                         }, | ||||
|                         "stdout": { | ||||
|                             "name": "stdout", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "stderr": { | ||||
|                             "name": "stderr", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "cpuLimit": 10000000000, | ||||
|                         "clockLimit": 20000000000, | ||||
|                         "memoryLimit": 268435456, | ||||
|                         "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": [ | ||||
|                         { | ||||
|                             "args": [ | ||||
|                                 "/usr/local/bin/repo-health-checker", | ||||
|                                 "-root=.", | ||||
|                                 "-repoSize=10.0", | ||||
|                                 "-checkFileSumList=", | ||||
|                                 "-checkFileNameList=" | ||||
|                             ] | ||||
|                         }, | ||||
|                         { | ||||
|                             "args": [ | ||||
|                                 "/usr/local/bin/joint-teapot", | ||||
|                                 "joj3-check-env", | ||||
|                                 "/home/tt/.config/teapot/teapot.env", | ||||
|                                 "--grading-repo-name", | ||||
|                                 "JOJ3-config-generator", | ||||
|                                 "--scoreboard-filename", | ||||
|                                 "scoreboard.csv" | ||||
|                             ], | ||||
|                             "env": [ | ||||
|                                 "REPOS_DIR=/home/tt/.cache", | ||||
|                                 "LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log" | ||||
|                             ] | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "parsers": [ | ||||
|                 { | ||||
|                     "name": "healthcheck", | ||||
|                     "with": { | ||||
|                         "score": 0 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "debug", | ||||
|                     "with": {} | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     ], | ||||
|     "postStages": [ | ||||
|         { | ||||
|             "name": "teapot", | ||||
|             "groups": [], | ||||
|             "executor": { | ||||
|                 "name": "local", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [ | ||||
|                             "/usr/local/bin/joint-teapot", | ||||
|                             "joj3-all-env", | ||||
|                             "/home/tt/.config/teapot/teapot.env", | ||||
|                             "--grading-repo-name", | ||||
|                             "JOJ3-config-generator", | ||||
|                             "--max-total-score", | ||||
|                             "0", | ||||
|                             "--issue-label-name", | ||||
|                             "Kind/Testing", | ||||
|                             "--issue-label-color", | ||||
|                             "#795548", | ||||
|                             "--scoreboard-filename", | ||||
|                             "scoreboard.csv" | ||||
|                         ], | ||||
|                         "env": [ | ||||
|                             "REPOS_DIR=/home/tt/.cache", | ||||
|                             "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": 30000000000, | ||||
|                         "clockLimit": 60000000000, | ||||
|                         "memoryLimit": 268435456, | ||||
|                         "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": { | ||||
|                         "filename": "stdout", | ||||
|                         "msg": "joj3 summary", | ||||
|                         "level": -4 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "debug", | ||||
|                     "with": {} | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     ] | ||||
| } | ||||
|  | @ -1,2 +0,0 @@ | |||
| name = "health check" | ||||
| max-total-score = 0 | ||||
|  | @ -1,4 +0,0 @@ | |||
| name = "extra-field" | ||||
| extra-field = "extra-field value" | ||||
| extra-dict.extra-field = "extra-dict.extra-field value" | ||||
| limit.extra-field = "limit.extra-field value" | ||||
							
								
								
									
										33
									
								
								tests/convert/full/immutable/.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								tests/convert/full/immutable/.gitattributes
									
									
									
									
										vendored
									
									
								
							|  | @ -1,33 +0,0 @@ | |||
| *.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 | ||||
|  | @ -1,19 +0,0 @@ | |||
| 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 | ||||
|  | @ -1,21 +0,0 @@ | |||
| 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 "${{ gitea.ref_name }}" | ||||
							
								
								
									
										23
									
								
								tests/convert/full/immutable/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								tests/convert/full/immutable/.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -1,23 +0,0 @@ | |||
| ################################ | ||||
| ## 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 | ||||
|  | @ -1,23 +0,0 @@ | |||
| sandbox-token = "" # sandbox token | ||||
| 
 | ||||
| health-check.score = 0 # score for health check stage | ||||
| health-check.max-size = "10m" # max size of the repository | ||||
| health-check.immutable-path = "immutable" # path for immutable files, relative to the path of repo.toml | ||||
| health-check.required-files = ["README.md", "Changelog.md"] # required files name, case insensitive | ||||
| 
 | ||||
| issue.label.name = "Kind/Testing" # label for issues | ||||
| issue.label.color = "#795548" # color for the label | ||||
| issue.label.exclusive = false # whether the label is exclusive | ||||
| issue.show-submitter = true # whether to show submitter in the issue title | ||||
| 
 | ||||
| 
 | ||||
| # fields below can be overridden by task.toml | ||||
| max-total-score = 100 # maximum total score for the task | ||||
| # submission count limit groups | ||||
| # explanation of the following config: | ||||
| # in last 1 hour, total submission <= 50 times | ||||
| # in last 24 hours, submission includes group "joj" <= 1000 times | ||||
| # in last 2 hours, submission includes group "run" <= 100 times | ||||
| groups.name = ["", "joj", "run"] # names of the groups | ||||
| groups.max-count = [50, 1000, 100] # maximum submission count for each group | ||||
| groups.time-period-hour = [1, 24, 2] # time period in hour for each group | ||||
|  | @ -1,516 +0,0 @@ | |||
| { | ||||
|     "name": "hw7 ex3", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "actorCsvPath": "/home/tt/.config/joj/students.csv", | ||||
|     "sandboxExecServer": "172.17.0.1:5051", | ||||
|     "sandboxToken": "", | ||||
|     "outputPath": "/tmp/joj3_result.json", | ||||
|     "preStages": [], | ||||
|     "stages": [ | ||||
|         { | ||||
|             "name": "Health Check", | ||||
|             "groups": [], | ||||
|             "executor": { | ||||
|                 "name": "local", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [], | ||||
|                         "env": [ | ||||
|                             "PATH=/usr/bin:/bin:/usr/local/bin" | ||||
|                         ], | ||||
|                         "stdin": { | ||||
|                             "content": "" | ||||
|                         }, | ||||
|                         "stdout": { | ||||
|                             "name": "stdout", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "stderr": { | ||||
|                             "name": "stderr", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "cpuLimit": 10000000000, | ||||
|                         "clockLimit": 20000000000, | ||||
|                         "memoryLimit": 268435456, | ||||
|                         "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": [ | ||||
|                         { | ||||
|                             "args": [ | ||||
|                                 "/usr/local/bin/repo-health-checker", | ||||
|                                 "-root=.", | ||||
|                                 "-repoSize=10.0", | ||||
|                                 "-meta=README.md", | ||||
|                                 "-meta=Changelog.md", | ||||
|                                 "-checkFileSumList=b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,2ba059f3977e2e3dee6cacbfbf0ba2578baa1b8e04b4977aec400868b6e49856,3db23f7fb2ca9814617e767ddc41b77073180b3b0b73e87b5f2a6d3129f88f3a,a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc", | ||||
|                                 "-checkFileNameList=.gitattributes,.gitea/workflows/push.yaml,.gitea/workflows/release.yaml,.gitignore" | ||||
|                             ] | ||||
|                         }, | ||||
|                         { | ||||
|                             "args": [ | ||||
|                                 "/usr/local/bin/joint-teapot", | ||||
|                                 "joj3-check-env", | ||||
|                                 "/home/tt/.config/teapot/teapot.env", | ||||
|                                 "--grading-repo-name", | ||||
|                                 "JOJ3-config-generator", | ||||
|                                 "--scoreboard-filename", | ||||
|                                 "scoreboard-hw7.csv", | ||||
|                                 "--group-config", | ||||
|                                 "joj=1000:24,run=100:1", | ||||
|                                 "--begin-time", | ||||
|                                 "2024-12-29T23:59:59", | ||||
|                                 "--end-time", | ||||
|                                 "2024-12-30T23:59:59", | ||||
|                                 "--penalty-config", | ||||
|                                 "24.0=0.75,48.0=0.5,72.0=0.25" | ||||
|                             ], | ||||
|                             "env": [ | ||||
|                                 "REPOS_DIR=/home/tt/.cache", | ||||
|                                 "LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log" | ||||
|                             ] | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "parsers": [ | ||||
|                 { | ||||
|                     "name": "healthcheck", | ||||
|                     "with": { | ||||
|                         "score": 0 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "debug", | ||||
|                     "with": {} | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "Generate yes.txt [no]", | ||||
|             "groups": [ | ||||
|                 "run", | ||||
|                 "no" | ||||
|             ], | ||||
|             "executor": { | ||||
|                 "name": "sandbox", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [ | ||||
|                             "sh", | ||||
|                             "-c", | ||||
|                             "yes | head -n 10 > yes.txt" | ||||
|                         ], | ||||
|                         "env": [ | ||||
|                             "PATH=/usr/bin:/bin:/usr/local/bin", | ||||
|                             "THE_ANSWER=42" | ||||
|                         ], | ||||
|                         "stdin": { | ||||
|                             "content": "" | ||||
|                         }, | ||||
|                         "stdout": { | ||||
|                             "name": "stdout", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "stderr": { | ||||
|                             "name": "stderr", | ||||
|                             "max": 33554432, | ||||
|                             "pipe": true | ||||
|                         }, | ||||
|                         "cpuLimit": 1000000000, | ||||
|                         "clockLimit": 2000000000, | ||||
|                         "memoryLimit": 268435456, | ||||
|                         "stackLimit": 0, | ||||
|                         "procLimit": 50, | ||||
|                         "cpuRateLimit": 0, | ||||
|                         "cpuSetLimit": "", | ||||
|                         "copyIn": { | ||||
|                             "tools/filelength": { | ||||
|                                 "src": "/home/tt/.config/joj/tools/filelength" | ||||
|                             }, | ||||
|                             "h7/Makefile": { | ||||
|                                 "src": "/home/tt/.config/joj/tools/Makefile" | ||||
|                             } | ||||
|                         }, | ||||
|                         "copyInCached": {}, | ||||
|                         "copyInDir": ".", | ||||
|                         "copyOut": [ | ||||
|                             "stdout", | ||||
|                             "stderr" | ||||
|                         ], | ||||
|                         "copyOutCached": [ | ||||
|                             "yes.txt" | ||||
|                         ], | ||||
|                         "copyOutMax": 0, | ||||
|                         "copyOutDir": "", | ||||
|                         "tty": false, | ||||
|                         "strictMemoryLimit": false, | ||||
|                         "dataSegmentLimit": false, | ||||
|                         "addressSpaceLimit": false | ||||
|                     }, | ||||
|                     "cases": [ | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/full/cases/case0.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/full/cases/case2.in" | ||||
|                             }, | ||||
|                             "cpuLimit": 2000000000, | ||||
|                             "memoryLimit": 536870912 | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/full/cases/case1.in" | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             "stdin": { | ||||
|                                 "src": "/home/tt/.config/joj/full/other/cases/case3.in" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             }, | ||||
|             "parsers": [ | ||||
|                 { | ||||
|                     "name": "result-status", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "comment": "Congrats! There is a yes.txt file generated!", | ||||
|                         "forceQuitOnNotAccepted": true | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "result-detail", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "comment": "", | ||||
|                         "showExxecutorStatus": true, | ||||
|                         "showExitStatus": true, | ||||
|                         "showError": false, | ||||
|                         "showTime": true, | ||||
|                         "showMemory": true, | ||||
|                         "showRuntime": true, | ||||
|                         "showProcPeak": false, | ||||
|                         "showFiles": [], | ||||
|                         "filesInCodeBlock": true, | ||||
|                         "maxFileLength": 2048 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "keyword", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "matches": [ | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "aaa" | ||||
|                                 ], | ||||
|                                 "score": 20 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "bbb" | ||||
|                                 ], | ||||
|                                 "score": 10 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "ccc" | ||||
|                                 ], | ||||
|                                 "score": 5 | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "clangtidy", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "matches": [ | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "clang-diagnostic", | ||||
|                                     "clang-analyzer", | ||||
|                                     "misc", | ||||
|                                     "performance", | ||||
|                                     "portability" | ||||
|                                 ], | ||||
|                                 "score": 5 | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "cppcheck", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "matches": [ | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "error" | ||||
|                                 ], | ||||
|                                 "score": 15 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "warning", | ||||
|                                     "portability", | ||||
|                                     "performance", | ||||
|                                     "style" | ||||
|                                 ], | ||||
|                                 "score": 5 | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "cpplint", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "matches": [ | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "runtime" | ||||
|                                 ], | ||||
|                                 "score": 5 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "readability" | ||||
|                                 ], | ||||
|                                 "score": 20 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "build" | ||||
|                                 ], | ||||
|                                 "score": 10 | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "elf", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "matches": [ | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "Parentheses" | ||||
|                                 ], | ||||
|                                 "score": 100 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "Length" | ||||
|                                 ], | ||||
|                                 "score": 300 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "Arity" | ||||
|                                 ], | ||||
|                                 "score": 50 | ||||
|                             }, | ||||
|                             { | ||||
|                                 "keywords": [ | ||||
|                                     "Repetitive" | ||||
|                                 ], | ||||
|                                 "score": 80 | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "diff", | ||||
|                     "with": { | ||||
|                         "name": "diff", | ||||
|                         "cases": [ | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/full/cases/case0.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/full/cases/case2.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/full/cases/case1.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             { | ||||
|                                 "outputs": [ | ||||
|                                     { | ||||
|                                         "score": 5, | ||||
|                                         "filename": "stdout", | ||||
|                                         "answerPath": "/home/tt/.config/joj/full/other/cases/case3.out", | ||||
|                                         "compareSpace": false, | ||||
|                                         "alwaysHide": false, | ||||
|                                         "forceQuitOnDiff": false, | ||||
|                                         "maxDiffLength": 2048, | ||||
|                                         "maxDiffLines": 50, | ||||
|                                         "hideCommonPrefix": false | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "dummy", | ||||
|                     "with": { | ||||
|                         "score": 0, | ||||
|                         "comment": "", | ||||
|                         "forceQuit": false | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "debug", | ||||
|                     "with": {} | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     ], | ||||
|     "postStages": [ | ||||
|         { | ||||
|             "name": "teapot", | ||||
|             "groups": [], | ||||
|             "executor": { | ||||
|                 "name": "local", | ||||
|                 "with": { | ||||
|                     "default": { | ||||
|                         "args": [ | ||||
|                             "/usr/local/bin/joint-teapot", | ||||
|                             "joj3-all-env", | ||||
|                             "/home/tt/.config/teapot/teapot.env", | ||||
|                             "--grading-repo-name", | ||||
|                             "JOJ3-config-generator", | ||||
|                             "--max-total-score", | ||||
|                             "100", | ||||
|                             "--issue-label-name", | ||||
|                             "Kind/Testing", | ||||
|                             "--issue-label-color", | ||||
|                             "#795548", | ||||
|                             "--scoreboard-filename", | ||||
|                             "scoreboard-hw7.csv", | ||||
|                             "--scoreboard-column-by-ref", | ||||
|                             "--end-time", | ||||
|                             "2024-12-30T23:59:59", | ||||
|                             "--penalty-config", | ||||
|                             "24.0=0.75,48.0=0.5,72.0=0.25" | ||||
|                         ], | ||||
|                         "env": [ | ||||
|                             "REPOS_DIR=/home/tt/.cache", | ||||
|                             "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": 30000000000, | ||||
|                         "clockLimit": 60000000000, | ||||
|                         "memoryLimit": 268435456, | ||||
|                         "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": { | ||||
|                         "filename": "stdout", | ||||
|                         "msg": "joj3 summary", | ||||
|                         "level": -4 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "debug", | ||||
|                     "with": {} | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     ] | ||||
| } | ||||
|  | @ -1,222 +0,0 @@ | |||
| name = "hw7 ex3" # task name, will be shown in the issue title | ||||
| 
 | ||||
| # scoreboard file name in grading repo, "auto" for automatic generation, default: scoreboard.csv | ||||
| scoreboard = "auto" | ||||
| # scoreboard = "scoreboard-42.csv" # use this if you want to specify a custom scoreboard | ||||
| 
 | ||||
| # whether to use gitea ref as scoreboard column, instead of the task name, default: false | ||||
| scoreboard-column-by-ref = true | ||||
| 
 | ||||
| # skip creating issue after job done, default: false | ||||
| issue.skip = false | ||||
| 
 | ||||
| # skip updating scoreboard in grading branch in course-joj repo after job done, default: false | ||||
| grading.skip-scoreboard = false | ||||
| # skip updating failed table in grading branch in course-joj repo after job done, default: false | ||||
| grading.skip-failed-table = false | ||||
| 
 | ||||
| # task triggered not in this time period will not pass the health check | ||||
| time.begin = 2024-12-29 23:59:59 # begin time, default: no start time, do not check | ||||
| time.end = 2024-12-30 23:59:59 # end time, default: no end time, do not check | ||||
| 
 | ||||
| # explanation of the following config: | ||||
| # if the submission is within 0-24 hours late from time.end, | ||||
| # the final score will be multiplied by 0.75 | ||||
| # if the submission is within 24-48 hours, multiplied by 0.5 | ||||
| # if the submission is within 48-72 hours, multiplied by 0.25 | ||||
| penalties.hours = [24, 48, 72] # penalty hours for late submissions | ||||
| penalties.factors = [0.75, 0.5, 0.25] # penalty factors for late submissions | ||||
| 
 | ||||
| # check repo.toml, fields below can override repo.toml | ||||
| max-total-score = 100 | ||||
| groups.name = ["joj", "run"] | ||||
| groups.max-count = [1000, 100] | ||||
| groups.time-period-hour = [24, 1] | ||||
| 
 | ||||
| # list of stages | ||||
| [[stages]] | ||||
| # stage name, content in the `[]` set the group | ||||
| # conventional commit message needs to contain the group name to run it | ||||
| # group can be omitted so that every commit will run this stage | ||||
| # e.g. commit msg "test(hw7): run yes" will not run this stage | ||||
| # commit msg "test(hw7): run yes [no]" will run this stage | ||||
| name = "Generate yes.txt [no]" | ||||
| # you can also use this fields to override the above groups | ||||
| groups = ["run", "no"] | ||||
| # default dir to automatically searching for cases | ||||
| base-case-dir = "." | ||||
| 
 | ||||
| # =================================================== | ||||
| # ========== executor related config start ========== | ||||
| # =================================================== | ||||
| 
 | ||||
| # executor runs the command in a limited sandbox, each stage uses a unique new sandbox | ||||
| # by default the sandbox does not share files and env vars with the host | ||||
| # so we need to set env vars and import files to it, and export files for later stages | ||||
| # limits can be applied on time, memory, file size, process count | ||||
| 
 | ||||
| # environment variables, will be set in the sandbox | ||||
| # by default, "PATH=/usr/bin:/bin:/usr/local/bin" will be inserted in the front | ||||
| env = ["THE_ANSWER=42"] | ||||
| command = "sh -c 'yes | head -n 10 > yes.txt'" # command to run in the sandbox, use `sh -c` to run shell commands | ||||
| # files to import into the sandbox, relative to `/home/tt/.config/joj/` | ||||
| # e.g. this will copy `/home/tt/.config/joj/tools/filelength` in host | ||||
| # to `/w/tools/filelength` in the sandbox as work dir in sandbox is `/w` | ||||
| files.import = [ "tools/filelength" ] | ||||
| # files to import into the sandbox | ||||
| # key is the path in the host, value is the path in the sandbox | ||||
| # e.g. this will copy `/home/tt/.config/joj/tools/Makefile` in host | ||||
| # to `/w/h7/Makefile` in the sandbox | ||||
| files.import-map = { "tools/Makefile" = "h7/Makefile" } | ||||
| # files to export from the sandbox, relative to `/w`, will be imported to later | ||||
| # stages automatically | ||||
| files.export = [ "yes.txt" ] | ||||
| # files that should not be imported from the `export` field in previous stages | ||||
| files.no-auto-import = [ "yes.txt" ] | ||||
| # whether to copy all files from the current working directory from host (i.e. the whole repo) | ||||
| # you can set it as false if you are in the run stage of a compiled language, as the binary is all you need | ||||
| copy-in-cwd = true # default: true | ||||
| 
 | ||||
| # normally, you DO NOT need to change these default limits | ||||
| limit.cpu = "1s" # CPU time limit, default: "1s" | ||||
| limit.mem = "256m" # memory limit, default: "256m" | ||||
| limit.time = "2s" # wall-clock time limit, if not set, will be 2x CPU time | ||||
| limit.stdout = "32m" # stdout size limit, default: "32m" | ||||
| limit.stderr = "32m" # stderr size limit, default: "32m" | ||||
| limit.proc = 50 # process limit, default: 50 | ||||
| 
 | ||||
| # ================================================= | ||||
| # ========== executor related config end ========== | ||||
| # ================================================= | ||||
| 
 | ||||
| # ================================================= | ||||
| # ========== parser related config start ========== | ||||
| # ================================================= | ||||
| 
 | ||||
| # parser parses the output of the executor and generates comments | ||||
| 
 | ||||
| # parsers to use for this stage | ||||
| # parsers will be run in the order they are listed, | ||||
| # which defines the order of the output comment | ||||
| # all possible parsers are listed here | ||||
| # usually, only one of the match keywords style parsers should be used in one stage | ||||
| parsers = [ | ||||
|     "result-status", # check if result status is Accepted | ||||
|     "result-detail", # show result details (CPU time, memory, etc.) | ||||
|     # ========== match keywords style parsers start ======== | ||||
|     "keyword", # match keywords in the output and score them | ||||
|     "clangtidy", # parse clang-tidy output, and match keywords | ||||
|     "cppcheck", # parse cppcheck output, and match keywords | ||||
|     "cpplint", # parse cpplint output, and match keywords | ||||
|     "elf", # parse elf (static analyzer for elm) output, and match keywords | ||||
|     # ========== match keywords style parsers end ========== | ||||
|     "diff", # diff the output with the expected output | ||||
|     # ====================================================== | ||||
|     "dummy", # dummy parser, used to show a comment | ||||
|     "debug", # debug parser, will log executor output files | ||||
| ] | ||||
| 
 | ||||
| result-status.score = 0 # score added if result status is Accepted, default: 0 | ||||
| result-status.comment = "Congrats! There is a yes.txt file generated!" # comment to show if result status is Accepted, default: "" | ||||
| result-status.force-quit = true # whether to force quit the stage if result status is not Accepted, default: true | ||||
| 
 | ||||
| result-detail.cpu-time = true # show CPU time, default: true | ||||
| result-detail.mem = true # show memory usage, default: true | ||||
| result-detail.time = true # show wall-clock time, default: true | ||||
| result-detail.stdout = false # show stdout content, default: false | ||||
| result-detail.stderr = false # show stderr content, default: false | ||||
| result-detail.exit-status = true # show exit status, default: true | ||||
| result-detail.proc-peak = false # show peak process count, default: false | ||||
| result-detail.error = false # show error message, default: false | ||||
| result-detail.code-block = true # show result in a code block, default: true | ||||
| result-detail.max-length = 2048 # maximum length of the stdout/stderr content to show, longer content will be truncated, default: 2048 | ||||
| 
 | ||||
| # explanation of the following config: | ||||
| # if the output is "aaa bbb ccc aaa", then the score will be: 0 - 20 - 10 - 5 - 20 = -55 | ||||
| keyword.score = 0 # base score, default: 0 | ||||
| keyword.keyword = [ "aaa", "bbb", "ccc" ] # list of keywords to match in stdout & stderr | ||||
| keyword.weight = [ 20, 10, 5 ] # weight for each keyword, will be deducted for each keyword found | ||||
| 
 | ||||
| # similar to keyword, but will only match check name in clang-tidy | ||||
| clangtidy.score = 0 | ||||
| clangtidy.keyword = [ "clang-diagnostic", "clang-analyzer", "misc", "performance", "portability" ] | ||||
| clangtidy.weight = [ 5, 5, 5, 5, 5 ] | ||||
| 
 | ||||
| # similar to keyword, but will only match record ID & severity in cppcheck | ||||
| cppcheck.score = 0 | ||||
| cppcheck.keyword = [ "error", "warning", "portability", "performance", "style" ] | ||||
| cppcheck.weight = [ 15, 5, 5, 5, 5 ] | ||||
| 
 | ||||
| # similar to keyword, but will only match category in cpplint | ||||
| cpplint.score = 0 | ||||
| cpplint.keyword = [ "runtime", "readability", "build" ] | ||||
| cpplint.weight = [ 5, 20, 10 ] | ||||
| 
 | ||||
| # similar to keyword, but will only match kind in elf | ||||
| elf.score = 0 | ||||
| elf.keyword = [ "Parentheses", "Length", "Arity", "Repetitive" ] | ||||
| elf.weight = [ 100, 300, 50, 80 ] | ||||
| 
 | ||||
| # dummy parser, it will not parse the result from the command, always give the same output | ||||
| dummy.score = 0 # score to add, default: 0 | ||||
| dummy.comment = "" # comment to show, default: "" | ||||
| dummy.force-quit = false # whether to force quit the stage, default: false | ||||
| 
 | ||||
| diff.score = 5 # default score for each case, default: 5 | ||||
| diff.ignore-spaces = true # ignore spaces in diff, default: true | ||||
| diff.hide = false # whether to hide the diff output, default: false | ||||
| diff.force-quit = false # whether to force quit the stage if there is a difference, default: false | ||||
| diff.max-length = 2048 # maximum length of the diff output, longer content will be truncated, default: 2048 | ||||
| diff.max-lines = 50 # maximum number of lines to show in the diff output, longer content will be truncated, default: 50 | ||||
| diff.hide-common-prefix = false # whether to hide the common prefix in the diff output, thus the first different line will be shown, default: false | ||||
| 
 | ||||
| # override when there are more than 1 cases in this stage | ||||
| # for quality check stages, there is only 1 case so this is not needed | ||||
| # previous fields without `case0.` prefix will be used as default for all cases | ||||
| # and for run stages, multiple cases will be run with different inputs and outputs | ||||
| # specific cases can be overridden here with these `case<x>.` prefix | ||||
| # if no `case<x>.in` and `case<x>.out` is specified here, | ||||
| # it will look for files with name `case<x>.in` and `case<x>.out` | ||||
| # recursively in the directory of this toml file, and set them as corresponding | ||||
| # `case<x>.in` and `case<x>.out` automatically, use the default value defined above | ||||
| case0.in = "cases/case0.in" # file will be used as stdin, relative to this toml file | ||||
| case0.out = "cases/case0.out" # file will be used to run diff with stdout, relative to this toml file | ||||
| # the following fields just show the default values | ||||
| case0.env = [] | ||||
| case0.command = "" | ||||
| case0.files.import = [] | ||||
| case0.files.import-map = {} | ||||
| case0.files.export = [] | ||||
| case0.copy-in-cwd = true | ||||
| case0.limit.cpu = "1s" | ||||
| case0.limit.mem = "256m" | ||||
| case0.limit.time = "2s" | ||||
| case0.limit.stdout = "32m" | ||||
| case0.limit.stderr = "32m" | ||||
| case0.limit.proc = 50 | ||||
| case0.diff.score = 5 | ||||
| case0.diff.ignore-spaces = true | ||||
| case0.diff.hide = false | ||||
| case0.diff.force-quit = false | ||||
| case0.diff.max-length = 2048 | ||||
| case0.diff.max-lines = 50 | ||||
| case0.diff.hide-common-prefix = false | ||||
| 
 | ||||
| # the following 2 lines can be omitted as they can be detected automatically | ||||
| # case1.in = "cases/case1.in" | ||||
| # case1.out = "cases/case1.out" | ||||
| 
 | ||||
| # and you can only override part of the fields | ||||
| case2.limit.cpu = "2s" # override CPU time limit for case2 | ||||
| case2.limit.mem = "512m" # override memory limit for case2 | ||||
| 
 | ||||
| # also, you can put .in and .out files in other directories | ||||
| # case3.in = "other/cases/case3.in" | ||||
| # case3.out = "other/cases/case3.out" | ||||
| 
 | ||||
| # =============================================== | ||||
| # ========== parser related config end ========== | ||||
| # =============================================== | ||||
| 
 | ||||
| # all supported fields are listed here in 1 stage, but usually you need multiple stages | ||||
| # for a real world example, please refer to playground repo | ||||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Filelength", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -72,7 +73,6 @@ | |||
|                     { | ||||
|                         "name": "keyword", | ||||
|                         "with": { | ||||
|                         "score": 0, | ||||
|                             "matches": [ | ||||
|                                 { | ||||
|                                     "keywords": [ | ||||
|  | @ -111,5 +111,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.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", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Filelength", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -92,5 +93,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| time.end = 2024-12-30 23:59:59+08:00 | ||||
| time.begin = 2024-12-29 23:59:59+08:00 | ||||
| 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" | ||||
|  |  | |||
|  | @ -1,6 +1,3 @@ | |||
| import pytest | ||||
| from pydantic import ValidationError | ||||
| 
 | ||||
| from tests.convert.utils import load_case | ||||
| 
 | ||||
| 
 | ||||
|  | @ -24,23 +21,6 @@ def test_diff() -> None: | |||
|     load_case("diff") | ||||
| 
 | ||||
| 
 | ||||
| def test_elf() -> None: | ||||
|     load_case("elf") | ||||
| 
 | ||||
| 
 | ||||
| def test_empty() -> None: | ||||
|     load_case("empty") | ||||
| 
 | ||||
| 
 | ||||
| def test_extra_field() -> None: | ||||
|     with pytest.raises(ValidationError): | ||||
|         load_case("extra-field") | ||||
| 
 | ||||
| 
 | ||||
| def test_full() -> None: | ||||
|     load_case("full") | ||||
| 
 | ||||
| 
 | ||||
| def test_keyword() -> None: | ||||
|     load_case("keyword") | ||||
| 
 | ||||
|  | @ -49,5 +29,5 @@ def test_result_detail() -> None: | |||
|     load_case("result-detail") | ||||
| 
 | ||||
| 
 | ||||
| def test_unnecessary() -> None: | ||||
|     load_case("unnecessary") | ||||
| def test_elf() -> None: | ||||
|     load_case("elf") | ||||
|  |  | |||
|  | @ -1,17 +1,18 @@ | |||
| { | ||||
|     "name": "hw7 ex2", | ||||
|     "logPath": "/home/tt/.cache/joj3/hw7/joj3.log", | ||||
|     "logPath": "/home/tt/.cache/joj3/joj3.log", | ||||
|     "expireUnixTimestamp": 0, | ||||
|     "effectiveUnixTimestamp": 0, | ||||
|     "actorCsvPath": "/home/tt/.config/joj/students.csv", | ||||
|     "maxTotalScore": 100, | ||||
|     "stage": { | ||||
|         "sandboxExecServer": "172.17.0.1:5051", | ||||
|         "sandboxToken": "", | ||||
|         "outputPath": "/tmp/joj3_result.json", | ||||
|     "preStages": [], | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "[cq] Filelength", | ||||
|             "groups": [ | ||||
|                 "cq" | ||||
|             ], | ||||
|                 "group": "cq", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|  | @ -89,5 +90,7 @@ | |||
|                 ] | ||||
|             } | ||||
|         ], | ||||
|         "preStages": [], | ||||
|         "postStages": [] | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| # general task configuration | ||||
| name = "hw7 ex2" # task name | ||||
| task.name = "hw7 ex2" # task name | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[cq] Filelength" | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| [task] | ||||
| name = "hw7 ex2" | ||||
| 
 | ||||
| [[stages]] | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user