rbx.cp 0.5.46__tar.gz → 0.5.48__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/PKG-INFO +1 -1
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/pyproject.toml +1 -1
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/checkers.py +81 -28
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/cli.py +12 -10
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/environment.py +1 -1
- rbx_cp-0.5.48/rbx/box/naming.py +22 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/boca/extension.py +1 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/boca/packager.py +54 -11
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/main.py +7 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/moj/packager.py +89 -19
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/packager.py +15 -3
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/polygon/packager.py +5 -4
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/solutions.py +2 -2
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/build_statements.py +2 -1
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/stresses.py +0 -1
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/tasks.py +6 -4
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/sandbox.py +29 -1
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/sandboxes/isolate.py +10 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/sandboxes/stupid_sandbox.py +16 -4
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/sandboxes/timeit.py +12 -3
- rbx_cp-0.5.48/rbx/grading/processing_context.py +48 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/steps.py +25 -14
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/checker.sh +8 -6
- rbx_cp-0.5.48/rbx/resources/packagers/boca/compare.sh +48 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/c +207 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/cc +207 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/cpp +207 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/java +240 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/kt +231 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/py2 +209 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactive/py3 +209 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/interactor_compile.sh +45 -0
- rbx_cp-0.5.48/rbx/resources/packagers/boca/run/bkp +163 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/c +19 -19
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/cc +19 -19
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/cpp +19 -19
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/java +51 -51
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/kt +30 -30
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/py2 +42 -42
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/run/py3 +42 -42
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/c/compile.sh +19 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/c/prep.sh +5 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/c/run.sh +16 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/moj/scripts/compare.sh +32 -6
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/cpp/compile.sh +19 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/cpp/prep.sh +5 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/cpp/run.sh +16 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/interactor_prep.sh +14 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/interactor_run.sh +38 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/java/compile.sh +12 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/java/prep.sh +8 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/java/run.sh +17 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py2/compile.sh +7 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py2/prep.sh +5 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py2/run.sh +16 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py3/compile.sh +7 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py3/prep.sh +5 -0
- rbx_cp-0.5.48/rbx/resources/packagers/moj/scripts/py3/run.sh +16 -0
- rbx_cp-0.5.46/rbx/resources/packagers/boca/compare +0 -53
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/LICENSE +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/README.md +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/annotations.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/autoenum.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/builder.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/cd.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/code.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/compile.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/build_contest_statements.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/contest/statements.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/creation.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/download.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/formatting.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/generators.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/lazy_importing_main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/lazy_importing_test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/package.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/retries.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/setter_config.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/state.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/testcase_extractors.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/testcase_utils.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/testcases/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/testcases/main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/ui/run.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/unit.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/validators.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/checker.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/clone.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/config.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/conftest.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/console.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/create.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/edit.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/caching.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/hydration.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/main.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/metadata.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/default_setter_config.mac.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/default_setter_config.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/pas +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/gen.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/random.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/random.txt +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/run.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/schema.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/submit.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/test.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/testcase.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/testing_utils.py +0 -0
- {rbx_cp-0.5.46 → rbx_cp-0.5.48}/rbx/utils.py +0 -0
@@ -1,4 +1,5 @@
|
|
1
1
|
import pathlib
|
2
|
+
import signal
|
2
3
|
from typing import Optional
|
3
4
|
|
4
5
|
import typer
|
@@ -108,23 +109,31 @@ def _convert_tle(result: CheckerResult, run_log: Optional[RunLog]) -> CheckerRes
|
|
108
109
|
return result
|
109
110
|
|
110
111
|
|
112
|
+
def _is_checker_exitcode(exitcode: int) -> bool:
|
113
|
+
return exitcode in [0, 1, 2, 3]
|
114
|
+
|
115
|
+
|
111
116
|
def process_checker_run_log(
|
112
117
|
checker_run_log: Optional[RunLog], message: str
|
113
|
-
) ->
|
118
|
+
) -> CheckerResult:
|
114
119
|
if (
|
115
120
|
checker_run_log is not None
|
116
|
-
and checker_run_log.
|
117
|
-
and (
|
118
|
-
checker_run_log.exitstatus != SandboxBase.EXIT_NONZERO_RETURN
|
119
|
-
or checker_run_log.exitcode not in [0, 1, 2, 3]
|
120
|
-
)
|
121
|
+
and checker_run_log.exitstatus == SandboxBase.EXIT_SANDBOX_ERROR
|
121
122
|
):
|
122
|
-
|
123
|
+
# When the sandbox fails, it means the checker failed to run.
|
124
|
+
# We don't know what happened.
|
125
|
+
return CheckerResult(
|
126
|
+
outcome=Outcome.INTERNAL_ERROR,
|
127
|
+
message='sandbox failed to run checker',
|
128
|
+
)
|
123
129
|
|
124
130
|
if checker_run_log is None:
|
125
131
|
return CheckerResult(outcome=Outcome.INTERNAL_ERROR)
|
126
|
-
if checker_run_log.exitcode
|
127
|
-
return
|
132
|
+
if not _is_checker_exitcode(checker_run_log.exitcode):
|
133
|
+
return CheckerResult(
|
134
|
+
outcome=Outcome.JUDGE_FAILED,
|
135
|
+
message=f'checker failed with unknown exit code {checker_run_log.exitcode}: {message}',
|
136
|
+
)
|
128
137
|
|
129
138
|
result = CheckerResult(outcome=Outcome.ACCEPTED, message=message)
|
130
139
|
|
@@ -185,7 +194,7 @@ async def _check(
|
|
185
194
|
message = package.get_digest_as_string(error.value or '') or ''
|
186
195
|
|
187
196
|
processed_checker_result = process_checker_run_log(checker_run_log, message)
|
188
|
-
if processed_checker_result
|
197
|
+
if processed_checker_result.outcome == Outcome.INTERNAL_ERROR:
|
189
198
|
console.console.print(
|
190
199
|
f'[error]Checker [item]{package.get_checker().path}[/item] failed unexpectedly.[/error]'
|
191
200
|
)
|
@@ -240,33 +249,77 @@ async def check_communication(
|
|
240
249
|
program_output: pathlib.Path,
|
241
250
|
skip_run_log: bool = False,
|
242
251
|
) -> CheckerResult:
|
243
|
-
|
252
|
+
def _extra_check_and_sanitize(result: CheckerResult) -> CheckerResult:
|
253
|
+
result.sanitizer_warnings = _check_sanitizer_warnings(run_log)
|
254
|
+
return result
|
255
|
+
|
256
|
+
def _check_interactor(reinterpret_rte: bool = True) -> Optional[CheckerResult]:
|
257
|
+
result = process_checker_run_log(
|
258
|
+
interactor_run_log, interactor_stderr.read_text()
|
259
|
+
)
|
260
|
+
if result.outcome in [Outcome.JUDGE_FAILED, Outcome.WRONG_ANSWER]:
|
261
|
+
# Only return testlib errors (exit code 2 and 3), skip other types of RTEs and verdicts.
|
262
|
+
if (
|
263
|
+
interactor_run_log is not None
|
264
|
+
and _is_checker_exitcode(interactor_run_log.exitcode)
|
265
|
+
and interactor_run_log.exitstatus == SandboxBase.EXIT_NONZERO_RETURN
|
266
|
+
):
|
267
|
+
return _extra_check_and_sanitize(result)
|
268
|
+
else:
|
269
|
+
# Check for other verdicts, but potentially reinterpret RTEs as JUDGE_FAILED.
|
270
|
+
result = check_with_no_output(interactor_run_log)
|
271
|
+
if result.outcome == Outcome.RUNTIME_ERROR and reinterpret_rte:
|
272
|
+
result.outcome = Outcome.JUDGE_FAILED
|
273
|
+
if result.outcome != Outcome.ACCEPTED:
|
274
|
+
return _extra_check_and_sanitize(result)
|
275
|
+
else:
|
276
|
+
# Return any other checker/interactor errors, such as INTERNAL_ERRORs.
|
277
|
+
return _extra_check_and_sanitize(result)
|
278
|
+
|
279
|
+
# No relevant error was found.
|
280
|
+
return None
|
244
281
|
|
282
|
+
# 1. If the solution received SIGPIPE or was terminated, it means the
|
283
|
+
# interactor exited before it. Thus, check the interactor, as it might have
|
284
|
+
# returned a checker verdict.
|
285
|
+
#
|
286
|
+
# Also, do the same if the solution returned a non-zero exit code. Checker verdict
|
287
|
+
# should usually supersede a solution's RTE verdict.
|
288
|
+
if (
|
289
|
+
interactor_run_log is not None
|
290
|
+
and run_log is not None
|
291
|
+
and (
|
292
|
+
run_log.exitcode == -signal.SIGPIPE
|
293
|
+
or run_log.exitstatus == SandboxBase.EXIT_TERMINATED
|
294
|
+
or run_log.exitstatus == SandboxBase.EXIT_NONZERO_RETURN
|
295
|
+
)
|
296
|
+
):
|
297
|
+
result = _check_interactor()
|
298
|
+
if result is not None and result.outcome != Outcome.ACCEPTED:
|
299
|
+
return _extra_check_and_sanitize(result)
|
300
|
+
|
301
|
+
# 2. Check if the solution failed without looking at its output (TLE, MLE, RTE, etc).
|
245
302
|
result = check_with_no_output(run_log)
|
246
|
-
result.sanitizer_warnings = sanitizer_warnings
|
247
303
|
if result.outcome != Outcome.ACCEPTED:
|
248
|
-
return result
|
304
|
+
return _extra_check_and_sanitize(result)
|
249
305
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if result is None:
|
256
|
-
result = check_with_no_output(interactor_run_log)
|
257
|
-
result.sanitizer_warnings = sanitizer_warnings
|
258
|
-
if result.outcome != Outcome.ACCEPTED:
|
259
|
-
result.outcome = Outcome.JUDGE_FAILED
|
260
|
-
return result
|
306
|
+
# 3. Now check interactor return code regardless of what happened to the
|
307
|
+
# solution.
|
308
|
+
result = _check_interactor()
|
309
|
+
if result is not None and result.outcome != Outcome.ACCEPTED:
|
310
|
+
return _extra_check_and_sanitize(result)
|
261
311
|
|
262
|
-
result
|
312
|
+
# Just a defensive pattern to ensure result is not None, should never happen.
|
313
|
+
result = check_with_no_output(interactor_run_log)
|
263
314
|
if result.outcome != Outcome.ACCEPTED:
|
264
|
-
|
315
|
+
if result.outcome == Outcome.RUNTIME_ERROR:
|
316
|
+
result.outcome = Outcome.JUDGE_FAILED
|
317
|
+
return _extra_check_and_sanitize(result)
|
265
318
|
|
319
|
+
# 4. Now actually check the output with a checker.
|
266
320
|
if checker_digest is not None:
|
267
321
|
result = await check(
|
268
322
|
checker_digest, run_log, testcase, program_output, skip_run_log
|
269
323
|
)
|
270
|
-
result.sanitizer_warnings = sanitizer_warnings
|
271
324
|
|
272
|
-
return result
|
325
|
+
return _extra_check_and_sanitize(result)
|
@@ -222,7 +222,7 @@ async def run(
|
|
222
222
|
tracked_solutions = {solution}
|
223
223
|
|
224
224
|
if choice:
|
225
|
-
tracked_solutions = set(pick_solutions(tracked_solutions))
|
225
|
+
tracked_solutions = set(await pick_solutions(tracked_solutions))
|
226
226
|
if not tracked_solutions:
|
227
227
|
console.console.print('[error]No solutions selected. Exiting.[/error]')
|
228
228
|
raise typer.Exit(1)
|
@@ -453,7 +453,7 @@ async def irun(
|
|
453
453
|
tracked_solutions = {solution}
|
454
454
|
|
455
455
|
if choice:
|
456
|
-
tracked_solutions = set(pick_solutions(tracked_solutions))
|
456
|
+
tracked_solutions = set(await pick_solutions(tracked_solutions))
|
457
457
|
if not tracked_solutions:
|
458
458
|
console.console.print('[error]No solutions selected. Exiting.[/error]')
|
459
459
|
raise typer.Exit(1)
|
@@ -515,7 +515,8 @@ def create(
|
|
515
515
|
help='Run a stress test.',
|
516
516
|
)
|
517
517
|
@package.within_problem
|
518
|
-
|
518
|
+
@syncer.sync
|
519
|
+
async def stress(
|
519
520
|
name: Annotated[
|
520
521
|
str,
|
521
522
|
typer.Argument(
|
@@ -574,7 +575,7 @@ def stress(
|
|
574
575
|
from rbx.box import stresses
|
575
576
|
|
576
577
|
with utils.StatusProgress('Running stress...') as s:
|
577
|
-
report = stresses.run_stress(
|
578
|
+
report = await stresses.run_stress(
|
578
579
|
name,
|
579
580
|
timeout,
|
580
581
|
args=generator_args,
|
@@ -608,15 +609,15 @@ def stress(
|
|
608
609
|
|
609
610
|
import questionary
|
610
611
|
|
611
|
-
testgroup = questionary.select(
|
612
|
+
testgroup = await questionary.select(
|
612
613
|
'Choose the testgroup to add the tests to.\nOnly test groups that have a .txt generatorScript are shown below: ',
|
613
614
|
choices=list(groups_by_name) + ['(create new script)', '(skip)'],
|
614
|
-
).
|
615
|
+
).ask_async()
|
615
616
|
|
616
617
|
if testgroup == '(create new script)':
|
617
|
-
new_script_name = questionary.text(
|
618
|
+
new_script_name = await questionary.text(
|
618
619
|
'Enter the name of the new .txt generatorScript file: '
|
619
|
-
).
|
620
|
+
).ask_async()
|
620
621
|
new_script_path = pathlib.Path(new_script_name).with_suffix('.txt')
|
621
622
|
new_script_path.parent.mkdir(parents=True, exist_ok=True)
|
622
623
|
new_script_path.touch()
|
@@ -673,7 +674,8 @@ def stress(
|
|
673
674
|
help='Compile an asset given its path.',
|
674
675
|
)
|
675
676
|
@package.within_problem
|
676
|
-
|
677
|
+
@syncer.sync
|
678
|
+
async def compile_command(
|
677
679
|
path: Annotated[
|
678
680
|
Optional[str],
|
679
681
|
typer.Argument(help='Path to the asset to compile.'),
|
@@ -694,7 +696,7 @@ def compile_command(
|
|
694
696
|
if path is None:
|
695
697
|
import questionary
|
696
698
|
|
697
|
-
path = questionary.path("What's the path to your asset?").
|
699
|
+
path = await questionary.path("What's the path to your asset?").ask_async()
|
698
700
|
if path is None:
|
699
701
|
console.console.print('[error]No path specified.[/error]')
|
700
702
|
raise typer.Exit(1)
|
@@ -343,7 +343,7 @@ def get_extension(name: str, _: Type[T]) -> Optional[T]:
|
|
343
343
|
pkg = get_environment()
|
344
344
|
if pkg.extensions is None:
|
345
345
|
return None
|
346
|
-
if hasattr(pkg.extensions, name):
|
346
|
+
if not hasattr(pkg.extensions, name):
|
347
347
|
return None
|
348
348
|
return getattr(pkg.extensions, name)
|
349
349
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from rbx.box import package
|
4
|
+
from rbx.box.contest import contest_package
|
5
|
+
|
6
|
+
|
7
|
+
def get_problem_shortname() -> Optional[str]:
|
8
|
+
contest = contest_package.find_contest_package()
|
9
|
+
if contest is None:
|
10
|
+
return None
|
11
|
+
problem_path = package.find_problem()
|
12
|
+
contest_path = contest_package.find_contest()
|
13
|
+
|
14
|
+
for problem in contest.problems:
|
15
|
+
if problem.path is None:
|
16
|
+
continue
|
17
|
+
if (problem_path / 'problem.rbx.yml').samefile(
|
18
|
+
contest_path / problem.path / 'problem.rbx.yml'
|
19
|
+
):
|
20
|
+
return problem.short_name
|
21
|
+
|
22
|
+
return None
|
@@ -11,6 +11,7 @@ class BocaExtension(BaseModel):
|
|
11
11
|
languages: typing.List[BocaLanguage] = list(typing.get_args(BocaLanguage))
|
12
12
|
flags: typing.Dict[BocaLanguage, str] = {}
|
13
13
|
maximumTimeError: float = _MAX_REP_ERROR
|
14
|
+
preferContestLetter: bool = False
|
14
15
|
|
15
16
|
def flags_with_defaults(self) -> typing.Dict[BocaLanguage, str]:
|
16
17
|
res: typing.Dict[BocaLanguage, str] = {
|
@@ -6,10 +6,11 @@ from typing import List
|
|
6
6
|
import typer
|
7
7
|
|
8
8
|
from rbx import console
|
9
|
-
from rbx.box import package
|
9
|
+
from rbx.box import naming, package
|
10
10
|
from rbx.box.environment import get_extension_or_default
|
11
11
|
from rbx.box.packaging.boca.extension import BocaExtension, BocaLanguage
|
12
12
|
from rbx.box.packaging.packager import BasePackager, BuiltStatement
|
13
|
+
from rbx.box.schema import TaskType
|
13
14
|
from rbx.box.statements.schema import Statement
|
14
15
|
from rbx.config import get_default_app_path, get_testlib
|
15
16
|
|
@@ -24,6 +25,10 @@ def test_time(time):
|
|
24
25
|
|
25
26
|
|
26
27
|
class BocaPackager(BasePackager):
|
28
|
+
@classmethod
|
29
|
+
def task_types(cls) -> List[TaskType]:
|
30
|
+
return [TaskType.BATCH, TaskType.COMMUNICATION]
|
31
|
+
|
27
32
|
def _get_main_statement(self) -> Statement:
|
28
33
|
pkg = package.find_problem_package_or_die()
|
29
34
|
|
@@ -47,14 +52,20 @@ class BocaPackager(BasePackager):
|
|
47
52
|
raise typer.Exit(1)
|
48
53
|
|
49
54
|
def _get_problem_name(self) -> str:
|
50
|
-
pkg = package.find_problem_package_or_die()
|
51
55
|
# BOCA forces Java class names to be the name of the problem.
|
52
|
-
return
|
56
|
+
return self.package_basename().replace('-', '_')
|
57
|
+
|
58
|
+
def _get_problem_basename(self) -> str:
|
59
|
+
extension = get_extension_or_default('boca', BocaExtension)
|
60
|
+
shortname = naming.get_problem_shortname()
|
61
|
+
if extension.preferContestLetter and shortname is not None:
|
62
|
+
return shortname
|
63
|
+
return self._get_problem_name()
|
53
64
|
|
54
65
|
def _get_problem_info(self) -> str:
|
55
66
|
statement = self._get_main_statement()
|
56
67
|
return (
|
57
|
-
f'basename={self.
|
68
|
+
f'basename={self._get_problem_basename()}\n'
|
58
69
|
f'fullname={statement.title}\n'
|
59
70
|
f'descfile={self._get_problem_name()}.pdf\n'
|
60
71
|
)
|
@@ -119,7 +130,7 @@ class BocaPackager(BasePackager):
|
|
119
130
|
)
|
120
131
|
|
121
132
|
def _get_compare(self) -> str:
|
122
|
-
compare_path = get_default_app_path() / 'packagers' / 'boca' / 'compare'
|
133
|
+
compare_path = get_default_app_path() / 'packagers' / 'boca' / 'compare.sh'
|
123
134
|
if not compare_path.exists():
|
124
135
|
console.console.print(
|
125
136
|
'[error]BOCA template compare script not found.[/error]'
|
@@ -145,7 +156,26 @@ class BocaPackager(BasePackager):
|
|
145
156
|
.replace('{{checker_content}}', checker)
|
146
157
|
)
|
147
158
|
|
159
|
+
def _get_interactor(self) -> str:
|
160
|
+
extension = get_extension_or_default('boca', BocaExtension)
|
161
|
+
|
162
|
+
interactor_path = (
|
163
|
+
get_default_app_path() / 'packagers' / 'boca' / 'interactor_compile.sh'
|
164
|
+
)
|
165
|
+
if not interactor_path.exists():
|
166
|
+
console.console.print(
|
167
|
+
'[error]BOCA template interactor compile script not found.[/error]'
|
168
|
+
)
|
169
|
+
raise typer.Exit(1)
|
170
|
+
|
171
|
+
interactor_text = interactor_path.read_text()
|
172
|
+
interactor = package.get_interactor().path.read_text()
|
173
|
+
return interactor_text.replace(
|
174
|
+
'{{rbxFlags}}', extension.flags_with_defaults()['cc']
|
175
|
+
).replace('{{interactor_content}}', interactor)
|
176
|
+
|
148
177
|
def _get_compile(self, language: BocaLanguage) -> str:
|
178
|
+
pkg = package.find_problem_package_or_die()
|
149
179
|
extension = get_extension_or_default('boca', BocaExtension)
|
150
180
|
|
151
181
|
compile_path = (
|
@@ -160,6 +190,10 @@ class BocaPackager(BasePackager):
|
|
160
190
|
compile_text = compile_path.read_text()
|
161
191
|
|
162
192
|
assert 'umask 0022' in compile_text
|
193
|
+
if pkg.type == TaskType.COMMUNICATION:
|
194
|
+
compile_text = compile_text.replace(
|
195
|
+
'umask 0022', 'umask 0022\n\n' + self._get_interactor()
|
196
|
+
)
|
163
197
|
compile_text = compile_text.replace(
|
164
198
|
'umask 0022', 'umask 0022\n\n' + self._get_checker()
|
165
199
|
)
|
@@ -197,7 +231,8 @@ class BocaPackager(BasePackager):
|
|
197
231
|
)
|
198
232
|
)
|
199
233
|
|
200
|
-
|
234
|
+
@classmethod
|
235
|
+
def name(cls) -> str:
|
201
236
|
return 'boca'
|
202
237
|
|
203
238
|
def package(
|
@@ -207,7 +242,7 @@ class BocaPackager(BasePackager):
|
|
207
242
|
built_statements: List[BuiltStatement],
|
208
243
|
) -> pathlib.Path:
|
209
244
|
extension = get_extension_or_default('boca', BocaExtension)
|
210
|
-
|
245
|
+
pkg = package.find_problem_package_or_die()
|
211
246
|
# Prepare limits
|
212
247
|
limits_path = into_path / 'limits'
|
213
248
|
limits_path.mkdir(parents=True, exist_ok=True)
|
@@ -227,9 +262,17 @@ class BocaPackager(BasePackager):
|
|
227
262
|
run_orig_path = (
|
228
263
|
get_default_app_path() / 'packagers' / 'boca' / 'run' / language
|
229
264
|
)
|
265
|
+
if pkg.type == TaskType.COMMUNICATION:
|
266
|
+
run_orig_path = (
|
267
|
+
get_default_app_path()
|
268
|
+
/ 'packagers'
|
269
|
+
/ 'boca'
|
270
|
+
/ 'interactive'
|
271
|
+
/ language
|
272
|
+
)
|
230
273
|
if not run_orig_path.is_file():
|
231
274
|
console.console.print(
|
232
|
-
f'[error]Run script for language [item]{language}[/item] not found.[/error]'
|
275
|
+
f'[error]Run script for language [item]{language}[/item] not found for task of type [item]{pkg.type}[/item].[/error]'
|
233
276
|
)
|
234
277
|
raise typer.Exit(1)
|
235
278
|
shutil.copyfile(run_orig_path, run_path / language)
|
@@ -268,11 +311,11 @@ class BocaPackager(BasePackager):
|
|
268
311
|
|
269
312
|
testcases = self.get_flattened_built_testcases()
|
270
313
|
for i, testcase in enumerate(testcases):
|
271
|
-
shutil.copyfile(testcase.inputPath, inputs_path / f'{i+1:03d}')
|
314
|
+
shutil.copyfile(testcase.inputPath, inputs_path / f'{i + 1:03d}')
|
272
315
|
if testcase.outputPath is not None:
|
273
|
-
shutil.copyfile(testcase.outputPath, outputs_path / f'{i+1:03d}')
|
316
|
+
shutil.copyfile(testcase.outputPath, outputs_path / f'{i + 1:03d}')
|
274
317
|
else:
|
275
|
-
(outputs_path / f'{i+1:03d}').touch()
|
318
|
+
(outputs_path / f'{i + 1:03d}').touch()
|
276
319
|
|
277
320
|
# Zip all.
|
278
321
|
shutil.make_archive(
|
@@ -28,6 +28,13 @@ async def run_packager(
|
|
28
28
|
raise typer.Exit(1)
|
29
29
|
|
30
30
|
pkg = package.find_problem_package_or_die()
|
31
|
+
|
32
|
+
if pkg.type not in packager_cls.task_types():
|
33
|
+
console.console.print(
|
34
|
+
f'[error]Packager [item]{packager_cls.name()}[/item] does not support task type [item]{pkg.type}[/item].[/error]'
|
35
|
+
)
|
36
|
+
raise typer.Exit(1)
|
37
|
+
|
31
38
|
packager = packager_cls(**kwargs)
|
32
39
|
|
33
40
|
statement_types = packager.statement_types()
|
@@ -7,10 +7,10 @@ import typer
|
|
7
7
|
from rbx import console
|
8
8
|
from rbx.box import package
|
9
9
|
from rbx.box.environment import get_extension_or_default
|
10
|
-
from rbx.box.packaging.boca.extension import BocaExtension
|
10
|
+
from rbx.box.packaging.boca.extension import BocaExtension, BocaLanguage
|
11
11
|
from rbx.box.packaging.boca.packager import BocaPackager
|
12
12
|
from rbx.box.packaging.packager import BuiltStatement
|
13
|
-
from rbx.box.schema import ExpectedOutcome
|
13
|
+
from rbx.box.schema import ExpectedOutcome, TaskType
|
14
14
|
from rbx.config import get_default_app_path, get_testlib
|
15
15
|
from rbx.grading.judge.digester import digest_cooperatively
|
16
16
|
|
@@ -20,13 +20,9 @@ class MojPackager(BocaPackager):
|
|
20
20
|
super().__init__()
|
21
21
|
self.for_boca = for_boca
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
return
|
26
|
-
f'basename={self._get_problem_name()}\n'
|
27
|
-
f'fullname={statement.title}\n'
|
28
|
-
f'descfile={self._get_problem_name()}.pdf\n'
|
29
|
-
)
|
23
|
+
@classmethod
|
24
|
+
def task_types(cls) -> List[TaskType]:
|
25
|
+
return [TaskType.COMMUNICATION, TaskType.BATCH]
|
30
26
|
|
31
27
|
def _get_tl(self) -> str:
|
32
28
|
extension = get_extension_or_default('boca', BocaExtension)
|
@@ -40,8 +36,12 @@ class MojPackager(BocaPackager):
|
|
40
36
|
def _get_limits(self) -> str:
|
41
37
|
pkg = package.find_problem_package_or_die()
|
42
38
|
ml = pkg.memoryLimit
|
43
|
-
ol = pkg.outputLimit
|
44
|
-
|
39
|
+
# ol = pkg.outputLimit
|
40
|
+
limits = [
|
41
|
+
f'ULIMITS[-v]={ml * 1024}',
|
42
|
+
# f'ULIMITS[-f]={ol}',
|
43
|
+
]
|
44
|
+
return '\n'.join(limits) + '\n'
|
45
45
|
|
46
46
|
def _get_compare(self) -> str:
|
47
47
|
extension = get_extension_or_default('boca', BocaExtension)
|
@@ -65,6 +65,33 @@ class MojPackager(BocaPackager):
|
|
65
65
|
def _get_checker(self) -> str:
|
66
66
|
return package.get_checker().path.read_text()
|
67
67
|
|
68
|
+
def _get_interactor(self) -> str:
|
69
|
+
return package.get_interactor().path.read_text()
|
70
|
+
|
71
|
+
def _expand_language_vars(self, language: BocaLanguage, dir: pathlib.Path):
|
72
|
+
extension = get_extension_or_default('boca', BocaExtension)
|
73
|
+
|
74
|
+
for path in dir.glob('**/*'):
|
75
|
+
if not path.is_file():
|
76
|
+
continue
|
77
|
+
|
78
|
+
replaced = path.read_text()
|
79
|
+
replaced = replaced.replace(
|
80
|
+
'{{rbxMaxMemory}}', f'{self._get_pkg_memorylimit(language)}'
|
81
|
+
).replace(
|
82
|
+
'{{rbxInitialMemory}}',
|
83
|
+
f'{min(512, int(self._get_pkg_memorylimit(language) * 0.9))}',
|
84
|
+
)
|
85
|
+
|
86
|
+
flags = extension.flags_with_defaults()
|
87
|
+
if language in flags:
|
88
|
+
replaced = replaced.replace('{{rbxFlags}}', flags[language])
|
89
|
+
|
90
|
+
path.write_text(replaced)
|
91
|
+
|
92
|
+
if path.suffix == '.sh':
|
93
|
+
path.chmod(0o755)
|
94
|
+
|
68
95
|
def _copy_solutions_moj(self, into_path: pathlib.Path):
|
69
96
|
into_path = into_path / 'sols'
|
70
97
|
has_good = False
|
@@ -83,7 +110,8 @@ class MojPackager(BocaPackager):
|
|
83
110
|
console.console.print('[error]No good solution found.[/error]')
|
84
111
|
raise typer.Exit(1)
|
85
112
|
|
86
|
-
|
113
|
+
@classmethod
|
114
|
+
def name(cls) -> str:
|
87
115
|
return 'moj'
|
88
116
|
|
89
117
|
def package(
|
@@ -92,6 +120,8 @@ class MojPackager(BocaPackager):
|
|
92
120
|
into_path: pathlib.Path,
|
93
121
|
built_statements: List[BuiltStatement],
|
94
122
|
) -> pathlib.Path:
|
123
|
+
pkg = package.find_problem_package_or_die()
|
124
|
+
|
95
125
|
# Prepare dummy files
|
96
126
|
author_path = into_path / 'author'
|
97
127
|
author_path.parent.mkdir(parents=True, exist_ok=True)
|
@@ -128,6 +158,48 @@ class MojPackager(BocaPackager):
|
|
128
158
|
checker_path.parent.mkdir(parents=True, exist_ok=True)
|
129
159
|
checker_path.write_text(self._get_checker())
|
130
160
|
|
161
|
+
# Prepare interactor
|
162
|
+
if pkg.type == TaskType.COMMUNICATION:
|
163
|
+
interactor_path = into_path / 'scripts' / 'interactor.cpp'
|
164
|
+
interactor_path.parent.mkdir(parents=True, exist_ok=True)
|
165
|
+
interactor_path.write_text(self._get_interactor())
|
166
|
+
|
167
|
+
interactor_prep_path = into_path / 'scripts' / 'interactor_prep.sh'
|
168
|
+
interactor_prep_path.parent.mkdir(parents=True, exist_ok=True)
|
169
|
+
shutil.copy(
|
170
|
+
get_default_app_path()
|
171
|
+
/ 'packagers'
|
172
|
+
/ 'moj'
|
173
|
+
/ 'scripts'
|
174
|
+
/ 'interactor_prep.sh',
|
175
|
+
interactor_prep_path,
|
176
|
+
)
|
177
|
+
interactor_prep_path.chmod(0o755)
|
178
|
+
|
179
|
+
interactor_run_path = into_path / 'scripts' / 'interactor_run.sh'
|
180
|
+
interactor_run_path.parent.mkdir(parents=True, exist_ok=True)
|
181
|
+
shutil.copy(
|
182
|
+
get_default_app_path()
|
183
|
+
/ 'packagers'
|
184
|
+
/ 'moj'
|
185
|
+
/ 'scripts'
|
186
|
+
/ 'interactor_run.sh',
|
187
|
+
interactor_run_path,
|
188
|
+
)
|
189
|
+
interactor_run_path.chmod(0o755)
|
190
|
+
|
191
|
+
# Prepare language scripts
|
192
|
+
extension = get_extension_or_default('boca', BocaExtension)
|
193
|
+
for language in extension.languages:
|
194
|
+
language_path = into_path / 'scripts' / language
|
195
|
+
language_path.parent.mkdir(parents=True, exist_ok=True)
|
196
|
+
src_path = (
|
197
|
+
get_default_app_path() / 'packagers' / 'moj' / 'scripts' / language
|
198
|
+
)
|
199
|
+
if src_path.exists():
|
200
|
+
shutil.copytree(src_path, language_path)
|
201
|
+
self._expand_language_vars(language, language_path)
|
202
|
+
|
131
203
|
# Problem statement
|
132
204
|
enunciado_path = into_path / 'docs' / 'enunciado.pdf'
|
133
205
|
enunciado_path.parent.mkdir(parents=True, exist_ok=True)
|
@@ -150,15 +222,13 @@ class MojPackager(BocaPackager):
|
|
150
222
|
|
151
223
|
testcases = self.get_flattened_built_testcases()
|
152
224
|
for i, testcase in enumerate(testcases):
|
153
|
-
shutil.copyfile(testcase.inputPath, inputs_path / f'{i+1:03d}')
|
225
|
+
shutil.copyfile(testcase.inputPath, inputs_path / f'{i + 1:03d}')
|
154
226
|
if testcase.outputPath is not None:
|
155
|
-
shutil.copyfile(testcase.outputPath, outputs_path / f'{i+1:03d}')
|
227
|
+
shutil.copyfile(testcase.outputPath, outputs_path / f'{i + 1:03d}')
|
156
228
|
else:
|
157
|
-
(outputs_path / f'{i+1:03d}').touch()
|
229
|
+
(outputs_path / f'{i + 1:03d}').touch()
|
158
230
|
|
159
231
|
# Zip all.
|
160
|
-
shutil.make_archive(
|
161
|
-
str(build_path / self._get_problem_name()), 'zip', into_path
|
162
|
-
)
|
232
|
+
shutil.make_archive(str(build_path / self.package_basename()), 'zip', into_path)
|
163
233
|
|
164
|
-
return (build_path / self.
|
234
|
+
return (build_path / self.package_basename()).with_suffix('.zip')
|
@@ -3,11 +3,11 @@ import pathlib
|
|
3
3
|
from abc import ABC, abstractmethod
|
4
4
|
from typing import List, Tuple
|
5
5
|
|
6
|
-
from rbx.box import package
|
6
|
+
from rbx.box import naming, package
|
7
7
|
from rbx.box.contest import contest_package
|
8
8
|
from rbx.box.contest.schema import ContestProblem, ContestStatement
|
9
9
|
from rbx.box.generators import get_all_built_testcases
|
10
|
-
from rbx.box.schema import Package, Testcase, TestcaseGroup
|
10
|
+
from rbx.box.schema import Package, TaskType, Testcase, TestcaseGroup
|
11
11
|
from rbx.box.statements.schema import Statement, StatementType
|
12
12
|
|
13
13
|
|
@@ -33,10 +33,15 @@ class BuiltProblemPackage:
|
|
33
33
|
|
34
34
|
|
35
35
|
class BasePackager(ABC):
|
36
|
+
@classmethod
|
36
37
|
@abstractmethod
|
37
|
-
def name(
|
38
|
+
def name(cls) -> str:
|
38
39
|
pass
|
39
40
|
|
41
|
+
@classmethod
|
42
|
+
def task_types(cls) -> List[TaskType]:
|
43
|
+
return [TaskType.BATCH]
|
44
|
+
|
40
45
|
def languages(self):
|
41
46
|
pkg = package.find_problem_package_or_die()
|
42
47
|
|
@@ -45,6 +50,13 @@ class BasePackager(ABC):
|
|
45
50
|
res.add(statement.language)
|
46
51
|
return list(res)
|
47
52
|
|
53
|
+
def package_basename(self):
|
54
|
+
pkg = package.find_problem_package_or_die()
|
55
|
+
shortname = naming.get_problem_shortname()
|
56
|
+
if shortname is not None:
|
57
|
+
return f'{shortname}-{pkg.name}'
|
58
|
+
return pkg.name
|
59
|
+
|
48
60
|
def statement_types(self) -> List[StatementType]:
|
49
61
|
return [StatementType.PDF]
|
50
62
|
|