diff --git a/cms/grading/Sandbox.py b/cms/grading/Sandbox.py index 8248eff302..5444d8fe85 100644 --- a/cms/grading/Sandbox.py +++ b/cms/grading/Sandbox.py @@ -743,17 +743,16 @@ def cleanup(self, delete: bool = False): # Delete the working directory. rmtree(self._outer_dir) - def archive(self) -> str | None: + def archive(self, file_cacher: FileCacher) -> str | None: """Archive the directory where the sandbox operated. Stores the archived sandbox in the file cacher and returns its digest. Returns None if archiving failed. + file_cacher: the FileCacher instance to use. """ logger.info("Archiving sandbox in %s.", self.get_root_path()) - assert self.file_cacher is not None - with tempfile.TemporaryFile(dir=self.temp_dir) as sandbox_archive: # Archive the working directory content_path = self.get_root_path() @@ -766,7 +765,7 @@ def archive(self) -> str | None: # Put archive to FS sandbox_archive.seek(0) - return self.file_cacher.put_file_from_fobj( + return file_cacher.put_file_from_fobj( sandbox_archive, "Sandbox %s" % self.get_root_path() ) diff --git a/cms/grading/tasktypes/Batch.py b/cms/grading/tasktypes/Batch.py index 9ccbd97539..9de82c823d 100644 --- a/cms/grading/tasktypes/Batch.py +++ b/cms/grading/tasktypes/Batch.py @@ -25,6 +25,8 @@ import os from cms.db import Executable +from cms.db.filecacher import FileCacher +from cms.grading.Job import CompilationJob, EvaluationJob from cms.grading.ParameterTypes import ParameterTypeCollection, \ ParameterTypeChoice, ParameterTypeString from cms.grading.language import Language @@ -196,15 +198,15 @@ def _executable_filename(codenames: Iterable[str], language: Language) -> str: for codename in codenames)) return name + language.executable_extension - def _do_compile(self, job, file_cacher): + def _do_compile(self, job: CompilationJob, file_cacher: FileCacher): language = get_language(job.language) source_ext = language.source_extension # Create the list of filenames to be passed to the compiler. If we use # a grader, it needs to be in first position in the command line, and # we check that it exists. - filenames_to_compile = [] - filenames_and_digests_to_get = {} + filenames_to_compile: list[str] = [] + filenames_and_digests_to_get: dict[str, str] = {} # The grader, that must have been provided (copy and add to # compilation). if self._uses_grader(): @@ -258,16 +260,16 @@ def _do_compile(self, job, file_cacher): Executable(executable_filename, digest) # Cleanup. - delete_sandbox(sandbox, job) + delete_sandbox(sandbox, job, file_cacher) - def compile(self, job, file_cacher): + def compile(self, job: CompilationJob, file_cacher: FileCacher): """See TaskType.compile.""" if not check_files_number(job, 1, or_more=True): return self._do_compile(job, file_cacher) - def _execution_step(self, job, file_cacher): + def _execution_step(self, job: EvaluationJob, file_cacher: FileCacher): # Prepare the execution executable_filename = next(iter(job.executables.keys())) language = get_language(job.language) @@ -385,7 +387,7 @@ def _evaluate_step(self, job, file_cacher, output_file_params, outcome, text, st job.admin_text = admin_text if sandbox is not None: - delete_sandbox(sandbox, job) + delete_sandbox(sandbox, job, file_cacher) def evaluate(self, job, file_cacher): """See TaskType.evaluate.""" diff --git a/cms/grading/tasktypes/Communication.py b/cms/grading/tasktypes/Communication.py index b2d3dd9a83..9f702c1ae4 100644 --- a/cms/grading/tasktypes/Communication.py +++ b/cms/grading/tasktypes/Communication.py @@ -30,6 +30,8 @@ from cms import config, rmtree from cms.db import Executable +from cms.db.filecacher import FileCacher +from cms.grading.Job import CompilationJob, EvaluationJob from cms.grading.ParameterTypes import ParameterTypeChoice, ParameterTypeInt from cms.grading.Sandbox import wait_without_std, Sandbox from cms.grading.language import Language @@ -181,7 +183,7 @@ def _executable_filename(codenames: Iterable[str], language: Language) -> str: for codename in codenames)) return name + language.executable_extension - def compile(self, job, file_cacher): + def compile(self, job: CompilationJob, file_cacher: FileCacher): """See TaskType.compile.""" language = get_language(job.language) source_ext = language.source_extension @@ -243,9 +245,9 @@ def compile(self, job, file_cacher): Executable(executable_filename, digest) # Cleanup. - delete_sandbox(sandbox, job) + delete_sandbox(sandbox, job, file_cacher) - def evaluate(self, job, file_cacher): + def evaluate(self, job: EvaluationJob, file_cacher: FileCacher): """See TaskType.evaluate.""" if not check_executables_number(job, 1): return @@ -439,9 +441,9 @@ def evaluate(self, job, file_cacher): job.plus = stats_user job.admin_text = admin_text - delete_sandbox(sandbox_mgr, job) + delete_sandbox(sandbox_mgr, job, file_cacher) for s in sandbox_user: - delete_sandbox(s, job) + delete_sandbox(s, job, file_cacher) if job.success and not config.worker.keep_sandbox and not job.keep_sandbox: for d in fifo_dir: rmtree(d) diff --git a/cms/grading/tasktypes/TwoSteps.py b/cms/grading/tasktypes/TwoSteps.py index b658d2e74f..720cae1e24 100644 --- a/cms/grading/tasktypes/TwoSteps.py +++ b/cms/grading/tasktypes/TwoSteps.py @@ -28,6 +28,8 @@ from cms import config from cms.db import Executable +from cms.db.filecacher import FileCacher +from cms.grading.Job import CompilationJob, EvaluationJob from cms.grading.ParameterTypes import ParameterTypeChoice from cms.grading.Sandbox import wait_without_std from cms.grading.languagemanager import LANGUAGES, get_language @@ -138,7 +140,7 @@ def get_auto_managers(self): def _uses_checker(self) -> bool: return self.output_eval == TwoSteps.OUTPUT_EVAL_CHECKER - def compile(self, job, file_cacher): + def compile(self, job: CompilationJob, file_cacher: FileCacher): """See TaskType.compile.""" language = get_language(job.language) source_ext = language.source_extension @@ -211,9 +213,9 @@ def compile(self, job, file_cacher): Executable(executable_filename, digest) # Cleanup - delete_sandbox(sandbox, job) + delete_sandbox(sandbox, job, file_cacher) - def evaluate(self, job, file_cacher): + def evaluate(self, job: EvaluationJob, file_cacher: FileCacher): """See TaskType.evaluate.""" if not check_executables_number(job, 1): return @@ -352,5 +354,5 @@ def evaluate(self, job, file_cacher): job.admin_text = admin_text job.plus = stats - delete_sandbox(first_sandbox, job) - delete_sandbox(second_sandbox, job) + delete_sandbox(first_sandbox, job, file_cacher) + delete_sandbox(second_sandbox, job, file_cacher) diff --git a/cms/grading/tasktypes/util.py b/cms/grading/tasktypes/util.py index e3825c6134..8244674ea8 100644 --- a/cms/grading/tasktypes/util.py +++ b/cms/grading/tasktypes/util.py @@ -71,7 +71,7 @@ def create_sandbox(box_index: int, file_cacher: FileCacher, name: str | None = N return sandbox -def delete_sandbox(sandbox: Sandbox, job: Job, success: bool | None = None): +def delete_sandbox(sandbox: Sandbox, job: Job, file_cacher: FileCacher, success: bool | None = None): """Delete the sandbox, if the configuration and job was ok. sandbox: the sandbox to delete. @@ -85,7 +85,7 @@ def delete_sandbox(sandbox: Sandbox, job: Job, success: bool | None = None): # Archive the sandbox if required if job.archive_sandbox: - sandbox_digest = sandbox.archive() + sandbox_digest = sandbox.archive(file_cacher) if sandbox_digest is not None: job.sandbox_digests[sandbox.get_root_path()] = sandbox_digest @@ -282,7 +282,7 @@ def eval_output( sandbox, file_cacher, checker_digest, job.input, job.output, EVAL_USER_OUTPUT_FILENAME, extra_args) - delete_sandbox(sandbox, job, success) + delete_sandbox(sandbox, job, file_cacher, success) return success, outcome, text, admin_text else: