From 4d294648bfa82e0fa113b76647988964af12f560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Czech?= <58006957+adespawn@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:48:21 +0100 Subject: [PATCH 1/3] Compile statement on export (#186) --- src/sinol_make/commands/export/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sinol_make/commands/export/__init__.py b/src/sinol_make/commands/export/__init__.py index b5d02405..83d3e08f 100644 --- a/src/sinol_make/commands/export/__init__.py +++ b/src/sinol_make/commands/export/__init__.py @@ -12,6 +12,7 @@ from sinol_make.helpers import package_util, parsers, paths from sinol_make.interfaces.BaseCommand import BaseCommand from sinol_make.commands.outgen import Command as OutgenCommand, compile_correct_solution, get_correct_solution +from sinol_make.commands.doc import Command as DocCommand class Command(BaseCommand): @@ -31,6 +32,8 @@ def configure_subparser(self, subparser: argparse.ArgumentParser): help=f'number of cpus to use to generate output files ' f'(default: {util.default_cpu_count()})', default=util.default_cpu_count()) + parser.add_argument('--no-statement', dest='no_statement', action='store_true', + help='allow export without statement') parsers.add_compilation_arguments(parser) def generate_input_tests(self): @@ -111,6 +114,15 @@ def create_ocen(self, target_dir: str): shutil.make_archive(os.path.join(attachments_dir, f'{self.task_id}ocen'), 'zip', tmpdir) + def compile_statement(self): + command = DocCommand() + doc_args = argparse.Namespace() + doc_args.files = [f'./doc/{self.task_id}zad.tex'] + command.run(doc_args) + if not os.path.isfile(f'./doc/{self.task_id}zad.pdf') and not self.args.no_statement: + util.exit_with_error('There is no pdf statements. If this intentional, export with flag "--no-statement". ' + 'Otherwise create pdf before continuing.') + def copy_package_required_files(self, target_dir: str): """ Copies package files and directories from @@ -228,6 +240,7 @@ def run(self, args: argparse.Namespace): util.change_stack_size_to_unlimited() self.generate_input_tests() + self.compile_statement() self.copy_package_required_files(export_package_path) self.clear_files(export_package_path) self.create_makefile_in(export_package_path, config) From c340475d31b6e35a36fc93944e888eea3e7403ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Czech?= <58006957+adespawn@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:52:17 +0100 Subject: [PATCH 2/3] Move config loading to package_util (#184) * Fix get_group to comply with oioioi standards * Update compilation error logs * Move config loading and surround with error checks * fix regex for finding solutions --- src/sinol_make/commands/export/__init__.py | 3 +-- src/sinol_make/commands/run/__init__.py | 7 +----- src/sinol_make/contest_types/__init__.py | 9 +++---- src/sinol_make/helpers/compile.py | 10 ++++---- src/sinol_make/helpers/package_util.py | 28 ++++++++++++++++------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/sinol_make/commands/export/__init__.py b/src/sinol_make/commands/export/__init__.py index 83d3e08f..2ff67203 100644 --- a/src/sinol_make/commands/export/__init__.py +++ b/src/sinol_make/commands/export/__init__.py @@ -230,8 +230,7 @@ def run(self, args: argparse.Namespace): self.task_id = package_util.get_task_id() package_util.validate_test_names(self.task_id) - with open(os.path.join(os.getcwd(), 'config.yml'), 'r') as config_file: - config = yaml.load(config_file, Loader=yaml.FullLoader) + config = package_util.get_config() export_package_path = paths.get_cache_path('export', self.task_id) if os.path.exists(export_package_path): diff --git a/src/sinol_make/commands/run/__init__.py b/src/sinol_make/commands/run/__init__.py index 0bf5c623..0796f6d7 100644 --- a/src/sinol_make/commands/run/__init__.py +++ b/src/sinol_make/commands/run/__init__.py @@ -1148,12 +1148,7 @@ def run(self, args): self.set_constants() package_util.validate_test_names(self.ID) self.args = args - with open(os.path.join(os.getcwd(), "config.yml"), 'r') as config: - try: - self.config = yaml.load(config, Loader=yaml.FullLoader) - except AttributeError: - self.config = yaml.load(config) - + self.config = package_util.get_config() try: self.contest = contest_types.get_contest_type() except UnknownContestType as e: diff --git a/src/sinol_make/contest_types/__init__.py b/src/sinol_make/contest_types/__init__.py index 309198df..98887606 100644 --- a/src/sinol_make/contest_types/__init__.py +++ b/src/sinol_make/contest_types/__init__.py @@ -1,16 +1,13 @@ -import os -import yaml - from sinol_make.contest_types.default import DefaultContest from sinol_make.contest_types.icpc import ICPCContest from sinol_make.contest_types.oi import OIContest +from sinol_make.helpers.package_util import get_config from sinol_make.interfaces.Errors import UnknownContestType def get_contest_type(): - with open(os.path.join(os.getcwd(), "config.yml"), "r") as config_file: - config = yaml.load(config_file, Loader=yaml.FullLoader) - contest_type = config.get("sinol_contest_type", "default").lower() + config = get_config() + contest_type = config.get("sinol_contest_type", "default").lower() if contest_type == "default": return DefaultContest() diff --git a/src/sinol_make/helpers/compile.py b/src/sinol_make/helpers/compile.py index b4435b8f..5c1c9375 100644 --- a/src/sinol_make/helpers/compile.py +++ b/src/sinol_make/helpers/compile.py @@ -9,7 +9,7 @@ import sinol_make.helpers.compiler as compiler from sinol_make import util from sinol_make.helpers import paths -from sinol_make.helpers.cache import check_compiled, save_compiled +from sinol_make.helpers.cache import check_compiled, save_compiled, package_util from sinol_make.interfaces.Errors import CompilationError from sinol_make.structs.compiler_structs import Compilers @@ -120,8 +120,7 @@ def compile_file(file_path: str, name: str, compilers: Compilers, weak_compilati os.makedirs(paths.get_executables_path(), exist_ok=True) os.makedirs(paths.get_compilation_log_path(), exist_ok=True) - with open(os.path.join(os.getcwd(), "config.yml"), "r") as config_file: - config = yaml.load(config_file, Loader=yaml.FullLoader) + config = package_util.get_config() extra_compilation_files = [os.path.join(os.getcwd(), "prog", file) for file in config.get("extra_compilation_files", [])] @@ -148,8 +147,11 @@ def print_compile_log(compile_log_path: str): Print the first 500 lines of compilation log :param compile_log_path: path to the compilation log """ + lines_to_print = 500 with open(compile_log_path, 'r') as compile_log: lines = compile_log.readlines() - for line in lines[:500]: + for line in lines[:lines_to_print]: print(line, end='') + if len(lines) > lines_to_print: + print(util.error(f"Compilation log too long. Whole log file at: {compile_log_path}")) diff --git a/src/sinol_make/helpers/package_util.py b/src/sinol_make/helpers/package_util.py index 86cdc53b..2a69d52d 100644 --- a/src/sinol_make/helpers/package_util.py +++ b/src/sinol_make/helpers/package_util.py @@ -11,8 +11,7 @@ def get_task_id() -> str: - with open(os.path.join(os.getcwd(), "config.yml")) as config_file: - config = yaml.load(config_file, Loader=yaml.FullLoader) + config = get_config() if "sinol_task_id" in config: return config["sinol_task_id"] else: @@ -38,7 +37,7 @@ def extract_test_id(test_path, task_id): def get_group(test_path, task_id): if extract_test_id(test_path, task_id).endswith("ocen"): return 0 - return int("".join(re.search(r'\d+',extract_test_id(test_path, task_id)).group())) + return int("".join(re.search(r'\d+', extract_test_id(test_path, task_id)).group())) def get_groups(tests, task_id): @@ -49,12 +48,23 @@ def get_test_key(test, task_id): return get_group(test, task_id), test +def get_config(): + try: + with open(os.path.join(os.getcwd(), "config.yml"), "r") as config_file: + return yaml.load(config_file, Loader=yaml.FullLoader) + except FileNotFoundError: + # Potentially redundant with util:exit_if_not_package + util.exit_with_error("You are not in a package directory (couldn't find config.yml in current directory).") + except yaml.YAMLError as e: + util.exit_with_error("config.yml is not a valid YAML. Fix it before continuing:\n" + str(e)) + + def get_solutions_re(task_id: str) -> re.Pattern: """ Returns regex pattern matching all solutions for given task. :param task_id: Task id. """ - return re.compile(r"^%s[bs]?[0-9]*(_.*)?\.(cpp|cc|java|py|pas)$" % task_id) + return re.compile(r"^%s[bs]?[0-9]*(_.*)?\.(c|cpp|cc|py)$" % task_id) def get_executable_key(executable, task_id): @@ -202,7 +212,8 @@ def _get_limit_from_dict(dict: Dict[str, Any], limit_type: LimitTypes, test_id: if allow_test_limit: return dict[plural_limit_name][test_id] else: - util.exit_with_error(f'{os.path.basename(test_path)}: Specifying limit for a single test is not allowed in sinol-make.') + util.exit_with_error( + f'{os.path.basename(test_path)}: Specifying limit for a single test is not allowed in sinol-make.') elif test_group in dict[plural_limit_name]: return dict[plural_limit_name][test_group] if limit_name in dict: @@ -226,9 +237,11 @@ def _get_limit(limit_type: LimitTypes, test_path: str, config: Dict[str, Any], l return global_limit else: if limit_type == LimitTypes.TIME_LIMIT: - util.exit_with_error(f'Time limit was not defined for test {os.path.basename(test_path)} in config.yml.') + util.exit_with_error( + f'Time limit was not defined for test {os.path.basename(test_path)} in config.yml.') elif limit_type == LimitTypes.MEMORY_LIMIT: - util.exit_with_error(f'Memory limit was not defined for test {os.path.basename(test_path)} in config.yml.') + util.exit_with_error( + f'Memory limit was not defined for test {os.path.basename(test_path)} in config.yml.') def get_time_limit(test_path, config, lang, task_id, args=None): @@ -257,6 +270,7 @@ def validate_test_names(task_id): """ Checks if all files in the package have valid names. """ + def get_invalid_files(path, pattern): invalid_files = [] for file in glob.glob(os.path.join(os.getcwd(), path)): From 6ed52cf030d8f5782b2bfc3d70aa3466e9939db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Czech?= Date: Fri, 16 Feb 2024 16:39:41 +0100 Subject: [PATCH 3/3] Fix tests from Compile statement on export --- tests/commands/export/test_integration.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/commands/export/test_integration.py b/tests/commands/export/test_integration.py index ba2dfd56..b59b8dc5 100644 --- a/tests/commands/export/test_integration.py +++ b/tests/commands/export/test_integration.py @@ -53,7 +53,7 @@ def test_simple(create_package, capsys): """ package_path = create_package parser = configure_parsers() - args = parser.parse_args(["export"]) + args = parser.parse_args(["export", "--no-statement"]) command = Command() command.run(args) @@ -95,7 +95,7 @@ def test_correct_permissions(create_package, capsys): os.chmod(shell_ingen, st.st_mode & ~stat.S_IEXEC) parser = configure_parsers() - args = parser.parse_args(["export"]) + args = parser.parse_args(["export", "--no-statement"]) command = Command() command.run(args) task_id = package_util.get_task_id() @@ -116,7 +116,7 @@ def test_handwritten_tests(create_package): Test if handwritten tests are correctly copied. """ parser = configure_parsers() - args = parser.parse_args(["export"]) + args = parser.parse_args(["export", "--no-statement"]) command = Command() command.run(args) task_id = package_util.get_task_id() @@ -136,7 +136,7 @@ def test_ocen_archive(create_package): Test creation of ocen archive. """ parser = configure_parsers() - args = parser.parse_args(["export"]) + args = parser.parse_args(["export", "--no-statement"]) command = Command() command.run(args) task_id = package_util.get_task_id()