sinol-make 1.7.0.dev1__tar.gz → 1.8.0__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.
- {sinol_make-1.7.0.dev1/src/sinol_make.egg-info → sinol_make-1.8.0}/PKG-INFO +35 -6
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/README.md +34 -5
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/setup.cfg +1 -1
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/__init__.py +28 -15
- sinol_make-1.8.0/src/sinol_make/commands/chkwer/__init__.py +137 -0
- sinol_make-1.8.0/src/sinol_make/commands/chkwer/chkwer_util.py +72 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/doc/__init__.py +6 -2
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/export/__init__.py +8 -2
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/gen/__init__.py +10 -4
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/ingen/ingen_util.py +2 -2
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/init/__init__.py +26 -10
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/inwer/__init__.py +8 -14
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/inwer/inwer_util.py +5 -1
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/outgen/__init__.py +3 -4
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/run/__init__.py +109 -93
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/verify/__init__.py +5 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/contest_types/__init__.py +2 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/contest_types/default.py +18 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/contest_types/icpc.py +6 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/contest_types/oi.py +6 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/contest_types/oij.py +3 -0
- sinol_make-1.8.0/src/sinol_make/executors/__init__.py +65 -0
- sinol_make-1.8.0/src/sinol_make/executors/detailed.py +91 -0
- sinol_make-1.8.0/src/sinol_make/executors/sio2jail.py +91 -0
- sinol_make-1.8.0/src/sinol_make/executors/time.py +113 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/cache.py +3 -3
- sinol_make-1.8.0/src/sinol_make/helpers/classinit.py +90 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/compile.py +22 -11
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/compiler.py +2 -2
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/package_util.py +21 -4
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/paths.py +8 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/interfaces/BaseCommand.py +7 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/interfaces/Errors.py +1 -1
- sinol_make-1.8.0/src/sinol_make/sio2jail/__init__.py +102 -0
- sinol_make-1.8.0/src/sinol_make/structs/chkwer_structs.py +68 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/run_structs.py +0 -2
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/status_structs.py +27 -6
- sinol_make-1.8.0/src/sinol_make/task_type/__init__.py +179 -0
- sinol_make-1.8.0/src/sinol_make/task_type/interactive.py +238 -0
- sinol_make-1.8.0/src/sinol_make/task_type/normal.py +37 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/util.py +1 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0/src/sinol_make.egg-info}/PKG-INFO +35 -6
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make.egg-info/SOURCES.txt +12 -6
- sinol_make-1.8.0/tests/test_sio2jail.py +104 -0
- sinol_make-1.7.0.dev1/src/sinol_make/oiejq/__init__.py +0 -128
- sinol_make-1.7.0.dev1/src/sinol_make/structs/package_structs.py +0 -7
- sinol_make-1.7.0.dev1/src/sinol_make/task_type/__init__.py +0 -17
- sinol_make-1.7.0.dev1/src/sinol_make/task_type/base.py +0 -273
- sinol_make-1.7.0.dev1/src/sinol_make/task_type/interactive_io.py +0 -219
- sinol_make-1.7.0.dev1/src/sinol_make/task_type/normal.py +0 -77
- sinol_make-1.7.0.dev1/tests/test_oiejq.py +0 -120
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/LICENSE +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/pyproject.toml +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/ingen/__init__.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/commands/outgen/outgen_util.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/__init__.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/func_cache.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/parsers.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/helpers/printer.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/interfaces/__init__.py +0 -0
- {sinol_make-1.7.0.dev1/src/sinol_make/oiejq → sinol_make-1.8.0/src/sinol_make/sio2jail}/perf_test.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/__init__.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/cache_structs.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/compiler_structs.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/gen_structs.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make/structs/inwer_structs.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make.egg-info/dependency_links.txt +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make.egg-info/entry_points.txt +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make.egg-info/requires.txt +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/src/sinol_make.egg-info/top_level.txt +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/tests/test_multiple_arguments.py +0 -0
- {sinol_make-1.7.0.dev1 → sinol_make-1.8.0}/tests/test_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sinol_make
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: CLI tool for creating sio2 task packages
|
|
5
5
|
Author: Mateusz Masiarz
|
|
6
6
|
Author-email: m.masiarz@fri.edu.pl
|
|
@@ -45,6 +45,7 @@ with features such as:
|
|
|
45
45
|
- [Why?](#why)
|
|
46
46
|
- [Installation](#installation)
|
|
47
47
|
- [Usage](#usage)
|
|
48
|
+
- [Contest types](#contest-types)
|
|
48
49
|
- [Reporting bugs and contributing code](#reporting-bugs-and-contributing-code)
|
|
49
50
|
|
|
50
51
|
### Why?
|
|
@@ -57,7 +58,7 @@ they lack some built-in mechanisms for verifying packages and finding mistakes
|
|
|
57
58
|
before uploading the package to the judge system.
|
|
58
59
|
As sinol-make was created specifically for the sio2 problem packages,
|
|
59
60
|
by default it downloads and uses sio2's deterministic mechanism of measuring
|
|
60
|
-
solutions' runtime, called `
|
|
61
|
+
solutions' runtime, called `sio2jail`.
|
|
61
62
|
|
|
62
63
|
### Installation
|
|
63
64
|
|
|
@@ -72,7 +73,7 @@ pip3 install sinol-make
|
|
|
72
73
|
so make sure this directory is in your `PATH`.
|
|
73
74
|
[Here's](https://gist.github.com/nex3/c395b2f8fd4b02068be37c961301caa7) how to add a directory to `PATH`.
|
|
74
75
|
|
|
75
|
-
As `
|
|
76
|
+
As `sio2jail` works only on Linux-based operating systems,
|
|
76
77
|
*we do not recommend* using operating systems such as Windows or macOS.
|
|
77
78
|
Nevertheless `sinol-make` supports those operating systems,
|
|
78
79
|
though there are additional installation steps required to use
|
|
@@ -93,11 +94,11 @@ activate-global-python-argcomplete
|
|
|
93
94
|
|
|
94
95
|
### Usage
|
|
95
96
|
|
|
96
|
-
The
|
|
97
|
+
The available commands (see `sinol-make --help`) are:
|
|
97
98
|
|
|
98
99
|
- `sinol-make run` -- Runs selected solutions (by default all solutions) on selected tests (by default all tests) with a given number
|
|
99
|
-
of CPUs. Measures the solutions' time with
|
|
100
|
-
compares the solutions' scores with the ones saved in config.yml. If you're using
|
|
100
|
+
of CPUs. Measures the solutions' time with sio2jail, unless specified otherwise. After running the solutions, it
|
|
101
|
+
compares the solutions' scores with the ones saved in config.yml. If you're using sio2jail, make sure you are not running on efficiency
|
|
101
102
|
cpu cores. You can check if you have them [like this](https://stackoverflow.com/a/71282744). To run on normal cpu cores, use
|
|
102
103
|
`taskset -c 8-15 sinol-make ...`, assuming that cpu cores 8-15 are not efficiency cores.
|
|
103
104
|
Run `sinol-make run --help` to see available flags.
|
|
@@ -116,6 +117,8 @@ program to use, what tests to check and how many CPUs to use. Run `sinol-make in
|
|
|
116
117
|
- `sinol-make verify` -- Verifies the package. This command runs stress tests (if available), verifies the config,
|
|
117
118
|
generates tests, generates problem statements, runs inwer and run all solutions. Ingen and inwer are compiled with
|
|
118
119
|
address and UB sanitizers. Run `sinol-make verify --help` to see all available flags.
|
|
120
|
+
- `sinol-make chkwer` -- Run checker with model solution and print results. Prints a table with points and checker's comments.
|
|
121
|
+
This command fails if the model solution didn't score maximum points. Run `sinol-make chkwer --help` to see all available flags.
|
|
119
122
|
- `sinol-make init [id]` -- Creates package from template [on github](https://github.com/sio2project/sinol-make/tree/main/example_package) and sets task id to provided `[id]`. Requires an internet connection to run.
|
|
120
123
|
|
|
121
124
|
You can also run multiple commands at once, for example:
|
|
@@ -124,6 +127,32 @@ You can also run multiple commands at once, for example:
|
|
|
124
127
|
sinol-make gen prog/abcingen2.cpp inwer --cpus 4 run --tests abc1*.in doc export --no-statement
|
|
125
128
|
```
|
|
126
129
|
|
|
130
|
+
There are also available short aliases for the commands:
|
|
131
|
+
- `sinol-make r` for `sinol-make run`
|
|
132
|
+
- `sinol-make g` for `sinol-make gen`
|
|
133
|
+
- `sinol-make i` for `sinol-make inwer`
|
|
134
|
+
- `sinol-make e` for `sinol-make export`
|
|
135
|
+
- `sinol-make d` for `sinol-make doc`
|
|
136
|
+
- `sinol-make v` for `sinol-make verify`
|
|
137
|
+
- `sinol-make c` for `sinol-make chkwer`
|
|
138
|
+
- `sm` for `sinol-make`
|
|
139
|
+
|
|
140
|
+
### Contest types
|
|
141
|
+
|
|
142
|
+
`sinol-make` changes its behavior depending on the contest type specified in `config.yml`. You can specify
|
|
143
|
+
the contest type with the `sinol_contest_type` key in config. Here is the table of available contest types and their
|
|
144
|
+
features:
|
|
145
|
+
|
|
146
|
+
| Feature | `default` | `oi` | `oij` | `icpc` |
|
|
147
|
+
|-----------------------------------------------------------------------------------------------------|-----------|----------|----------|--------|
|
|
148
|
+
| Max score | 100 | 100 | 100 | 1 |
|
|
149
|
+
| Default time tool | sio2jail | sio2jail | sio2jail | time |
|
|
150
|
+
| Full score if took less than half of the time limit, <br/>otherwise linearly decreasing to 1. | ❌ | ✔️ | ❌ | ❌ |
|
|
151
|
+
| Full score if took less than the time limit | ✔️ | ❌ | ✔️ | ✔️ |
|
|
152
|
+
| Scores must sum up to 100 | ❌ | ✔️ | ✔️ | ❌ |
|
|
153
|
+
| Limits can be set for individual tests | ✔️ | ❌ | ✔️ | ✔️ |
|
|
154
|
+
| Verifies if tests are named correctly<br/> (letters within groups increase, group numbers increase) | ❌ | ✔️ | ✔️ | ✔️ |
|
|
155
|
+
|
|
127
156
|
### Reporting bugs and contributing code
|
|
128
157
|
|
|
129
158
|
- Want to report a bug or request a feature? [Open an issue](https://github.com/sio2project/sinol-make/issues).
|
|
@@ -15,6 +15,7 @@ with features such as:
|
|
|
15
15
|
- [Why?](#why)
|
|
16
16
|
- [Installation](#installation)
|
|
17
17
|
- [Usage](#usage)
|
|
18
|
+
- [Contest types](#contest-types)
|
|
18
19
|
- [Reporting bugs and contributing code](#reporting-bugs-and-contributing-code)
|
|
19
20
|
|
|
20
21
|
### Why?
|
|
@@ -27,7 +28,7 @@ they lack some built-in mechanisms for verifying packages and finding mistakes
|
|
|
27
28
|
before uploading the package to the judge system.
|
|
28
29
|
As sinol-make was created specifically for the sio2 problem packages,
|
|
29
30
|
by default it downloads and uses sio2's deterministic mechanism of measuring
|
|
30
|
-
solutions' runtime, called `
|
|
31
|
+
solutions' runtime, called `sio2jail`.
|
|
31
32
|
|
|
32
33
|
### Installation
|
|
33
34
|
|
|
@@ -42,7 +43,7 @@ pip3 install sinol-make
|
|
|
42
43
|
so make sure this directory is in your `PATH`.
|
|
43
44
|
[Here's](https://gist.github.com/nex3/c395b2f8fd4b02068be37c961301caa7) how to add a directory to `PATH`.
|
|
44
45
|
|
|
45
|
-
As `
|
|
46
|
+
As `sio2jail` works only on Linux-based operating systems,
|
|
46
47
|
*we do not recommend* using operating systems such as Windows or macOS.
|
|
47
48
|
Nevertheless `sinol-make` supports those operating systems,
|
|
48
49
|
though there are additional installation steps required to use
|
|
@@ -63,11 +64,11 @@ activate-global-python-argcomplete
|
|
|
63
64
|
|
|
64
65
|
### Usage
|
|
65
66
|
|
|
66
|
-
The
|
|
67
|
+
The available commands (see `sinol-make --help`) are:
|
|
67
68
|
|
|
68
69
|
- `sinol-make run` -- Runs selected solutions (by default all solutions) on selected tests (by default all tests) with a given number
|
|
69
|
-
of CPUs. Measures the solutions' time with
|
|
70
|
-
compares the solutions' scores with the ones saved in config.yml. If you're using
|
|
70
|
+
of CPUs. Measures the solutions' time with sio2jail, unless specified otherwise. After running the solutions, it
|
|
71
|
+
compares the solutions' scores with the ones saved in config.yml. If you're using sio2jail, make sure you are not running on efficiency
|
|
71
72
|
cpu cores. You can check if you have them [like this](https://stackoverflow.com/a/71282744). To run on normal cpu cores, use
|
|
72
73
|
`taskset -c 8-15 sinol-make ...`, assuming that cpu cores 8-15 are not efficiency cores.
|
|
73
74
|
Run `sinol-make run --help` to see available flags.
|
|
@@ -86,6 +87,8 @@ program to use, what tests to check and how many CPUs to use. Run `sinol-make in
|
|
|
86
87
|
- `sinol-make verify` -- Verifies the package. This command runs stress tests (if available), verifies the config,
|
|
87
88
|
generates tests, generates problem statements, runs inwer and run all solutions. Ingen and inwer are compiled with
|
|
88
89
|
address and UB sanitizers. Run `sinol-make verify --help` to see all available flags.
|
|
90
|
+
- `sinol-make chkwer` -- Run checker with model solution and print results. Prints a table with points and checker's comments.
|
|
91
|
+
This command fails if the model solution didn't score maximum points. Run `sinol-make chkwer --help` to see all available flags.
|
|
89
92
|
- `sinol-make init [id]` -- Creates package from template [on github](https://github.com/sio2project/sinol-make/tree/main/example_package) and sets task id to provided `[id]`. Requires an internet connection to run.
|
|
90
93
|
|
|
91
94
|
You can also run multiple commands at once, for example:
|
|
@@ -94,6 +97,32 @@ You can also run multiple commands at once, for example:
|
|
|
94
97
|
sinol-make gen prog/abcingen2.cpp inwer --cpus 4 run --tests abc1*.in doc export --no-statement
|
|
95
98
|
```
|
|
96
99
|
|
|
100
|
+
There are also available short aliases for the commands:
|
|
101
|
+
- `sinol-make r` for `sinol-make run`
|
|
102
|
+
- `sinol-make g` for `sinol-make gen`
|
|
103
|
+
- `sinol-make i` for `sinol-make inwer`
|
|
104
|
+
- `sinol-make e` for `sinol-make export`
|
|
105
|
+
- `sinol-make d` for `sinol-make doc`
|
|
106
|
+
- `sinol-make v` for `sinol-make verify`
|
|
107
|
+
- `sinol-make c` for `sinol-make chkwer`
|
|
108
|
+
- `sm` for `sinol-make`
|
|
109
|
+
|
|
110
|
+
### Contest types
|
|
111
|
+
|
|
112
|
+
`sinol-make` changes its behavior depending on the contest type specified in `config.yml`. You can specify
|
|
113
|
+
the contest type with the `sinol_contest_type` key in config. Here is the table of available contest types and their
|
|
114
|
+
features:
|
|
115
|
+
|
|
116
|
+
| Feature | `default` | `oi` | `oij` | `icpc` |
|
|
117
|
+
|-----------------------------------------------------------------------------------------------------|-----------|----------|----------|--------|
|
|
118
|
+
| Max score | 100 | 100 | 100 | 1 |
|
|
119
|
+
| Default time tool | sio2jail | sio2jail | sio2jail | time |
|
|
120
|
+
| Full score if took less than half of the time limit, <br/>otherwise linearly decreasing to 1. | ❌ | ✔️ | ❌ | ❌ |
|
|
121
|
+
| Full score if took less than the time limit | ✔️ | ❌ | ✔️ | ✔️ |
|
|
122
|
+
| Scores must sum up to 100 | ❌ | ✔️ | ✔️ | ❌ |
|
|
123
|
+
| Limits can be set for individual tests | ✔️ | ❌ | ✔️ | ✔️ |
|
|
124
|
+
| Verifies if tests are named correctly<br/> (letters within groups increase, group numbers increase) | ❌ | ✔️ | ✔️ | ✔️ |
|
|
125
|
+
|
|
97
126
|
### Reporting bugs and contributing code
|
|
98
127
|
|
|
99
128
|
- Want to report a bug or request a feature? [Open an issue](https://github.com/sio2project/sinol-make/issues).
|
|
@@ -4,10 +4,14 @@ import argparse
|
|
|
4
4
|
import traceback
|
|
5
5
|
import argcomplete
|
|
6
6
|
|
|
7
|
-
from sinol_make import util,
|
|
7
|
+
from sinol_make import util, sio2jail
|
|
8
8
|
|
|
9
|
+
# Required for side effects
|
|
10
|
+
from sinol_make.task_type.normal import NormalTaskType # noqa
|
|
11
|
+
from sinol_make.task_type.interactive import InteractiveTaskType # noqa
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
__version__ = "1.8.0"
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
def configure_parsers():
|
|
@@ -32,19 +36,19 @@ def configure_parsers():
|
|
|
32
36
|
return parser
|
|
33
37
|
|
|
34
38
|
|
|
35
|
-
def
|
|
36
|
-
if util.is_linux() and not
|
|
37
|
-
print(util.warning('Up to date `
|
|
39
|
+
def check_sio2jail():
|
|
40
|
+
if util.is_linux() and not sio2jail.check_sio2jail():
|
|
41
|
+
print(util.warning('Up to date `sio2jail` in `~/.local/bin/` not found, installing new version...'))
|
|
38
42
|
try:
|
|
39
|
-
if
|
|
40
|
-
print(util.info('`
|
|
43
|
+
if sio2jail.install_sio2jail():
|
|
44
|
+
print(util.info('Newest `sio2jail` was successfully installed.'))
|
|
41
45
|
else:
|
|
42
|
-
util.exit_with_error('`
|
|
43
|
-
'You can download it from https://oij.edu.pl/zawodnik/srodowisko/oiejq.tar.gz
|
|
44
|
-
'unpack it to `~/.local/bin
|
|
45
|
-
'You can also use --
|
|
46
|
+
util.exit_with_error('`sio2jail` could not be installed.\n'
|
|
47
|
+
'You can download it from https://oij.edu.pl/zawodnik/srodowisko/oiejq.tar.gz '
|
|
48
|
+
'and unpack it to `~/.local/bin/`.\n'
|
|
49
|
+
'You can also use --sio2jail-path to specify path to your sio2jail.')
|
|
46
50
|
except Exception as err:
|
|
47
|
-
util.exit_with_error('`
|
|
51
|
+
util.exit_with_error('`sio2jail` could not be installed.\n' + str(err))
|
|
48
52
|
|
|
49
53
|
|
|
50
54
|
def main_exn():
|
|
@@ -53,11 +57,16 @@ def main_exn():
|
|
|
53
57
|
curr_args = []
|
|
54
58
|
commands = util.get_commands()
|
|
55
59
|
commands_dict = {command.get_name(): command for command in commands}
|
|
60
|
+
commands_short_dict = {command.get_short_name(): command for command in commands if command.get_short_name()}
|
|
56
61
|
for arg in sys.argv[1:]:
|
|
57
62
|
if arg in commands_dict.keys() and not (len(curr_args) > 0 and curr_args[0] == 'init'):
|
|
58
63
|
if curr_args:
|
|
59
64
|
arguments.append(curr_args)
|
|
60
65
|
curr_args = [arg]
|
|
66
|
+
elif arg in commands_short_dict.keys() and not (len(curr_args) > 0 and curr_args[0] == 'init'):
|
|
67
|
+
if curr_args:
|
|
68
|
+
arguments.append(curr_args)
|
|
69
|
+
curr_args = [commands_short_dict[arg].get_name()]
|
|
61
70
|
else:
|
|
62
71
|
curr_args.append(arg)
|
|
63
72
|
if curr_args:
|
|
@@ -65,7 +74,7 @@ def main_exn():
|
|
|
65
74
|
if not arguments:
|
|
66
75
|
parser.print_help()
|
|
67
76
|
exit(1)
|
|
68
|
-
|
|
77
|
+
check_sio2jail()
|
|
69
78
|
|
|
70
79
|
for curr_args in arguments:
|
|
71
80
|
args = parser.parse_args(curr_args)
|
|
@@ -101,9 +110,13 @@ def main():
|
|
|
101
110
|
if not util.is_dev(new_version):
|
|
102
111
|
print(util.warning(
|
|
103
112
|
f'New version of sinol-make is available (your version: {__version__}, available version: '
|
|
104
|
-
f'{new_version}).\
|
|
113
|
+
f'{new_version}).\n'
|
|
114
|
+
f'Changelog can be found at https://github.com/sio2project/sinol-make/releases.\n'
|
|
115
|
+
f'You can update sinol-make by running `pip install sinol-make --upgrade`.'))
|
|
105
116
|
elif util.is_dev(new_version):
|
|
106
117
|
print(util.warning(
|
|
107
118
|
f'New development version of sinol-make is available (your version: {__version__}, available '
|
|
108
|
-
f'version: {new_version}).\
|
|
119
|
+
f'version: {new_version}).\n'
|
|
120
|
+
f'Changelog can be found at https://github.com/sio2project/sinol-make/releases.\n'
|
|
121
|
+
f'You can update sinol-make by running `pip install sinol-make --pre --upgrade`.'
|
|
109
122
|
))
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import threading
|
|
4
|
+
from typing import Dict, List
|
|
5
|
+
import multiprocessing as mp
|
|
6
|
+
|
|
7
|
+
from sinol_make import util, contest_types
|
|
8
|
+
from sinol_make.commands.chkwer import chkwer_util
|
|
9
|
+
from sinol_make.commands.outgen import outgen_util
|
|
10
|
+
from sinol_make.helpers import package_util, parsers, compiler, compile, printer, paths
|
|
11
|
+
from sinol_make.interfaces.BaseCommand import BaseCommand
|
|
12
|
+
from sinol_make.structs.chkwer_structs import TestResult, ChkwerExecution, TableData, RunResult
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Command(BaseCommand):
|
|
16
|
+
"""
|
|
17
|
+
Class for `chkwer` command.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def get_name(self):
|
|
21
|
+
return "chkwer"
|
|
22
|
+
|
|
23
|
+
def get_short_name(self):
|
|
24
|
+
return "c"
|
|
25
|
+
|
|
26
|
+
def configure_subparser(self, subparser):
|
|
27
|
+
parser = subparser.add_parser(
|
|
28
|
+
self.get_name(),
|
|
29
|
+
help='Run checker with model solution and print results',
|
|
30
|
+
description='Run checker with model solution and print results. '
|
|
31
|
+
'Prints a table with points and checker\'s comments. '
|
|
32
|
+
'This command fails if the model solution didn\'t '
|
|
33
|
+
'score maximum points.'
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument('-t', '--tests', type=str, nargs='+',
|
|
36
|
+
help='test to run, for example in/abc{0,1}*')
|
|
37
|
+
parsers.add_cpus_argument(parser, 'number of cpus to use when verifying tests')
|
|
38
|
+
parsers.add_compilation_arguments(parser)
|
|
39
|
+
return parser
|
|
40
|
+
|
|
41
|
+
def compile(self, file_path, exe_path, args, name, compilation_flags):
|
|
42
|
+
print(f'Compiling {name}... ', end='')
|
|
43
|
+
compilers = compiler.verify_compilers(args, [file_path])
|
|
44
|
+
exe, compile_log_path = compile.compile_file(file_path, exe_path, compilers, compilation_flags,
|
|
45
|
+
use_fsanitize=False, use_extras=False)
|
|
46
|
+
if exe is None:
|
|
47
|
+
print(util.error('ERROR'))
|
|
48
|
+
compile.print_compile_log(compile_log_path)
|
|
49
|
+
util.exit_with_error(f'Failed {name} compilation.')
|
|
50
|
+
else:
|
|
51
|
+
print(util.info('OK'))
|
|
52
|
+
return exe
|
|
53
|
+
|
|
54
|
+
def run_test(self, execution: ChkwerExecution) -> RunResult:
|
|
55
|
+
"""
|
|
56
|
+
Verifies a test and returns the result of chkwer on this test.
|
|
57
|
+
"""
|
|
58
|
+
output_file = paths.get_chkwer_path(os.path.basename(execution.out_test_path))
|
|
59
|
+
with open(execution.in_test_path, 'r') as inf, open(output_file, 'w') as outf:
|
|
60
|
+
process = subprocess.Popen([execution.model_exe], stdin=inf, stdout=outf)
|
|
61
|
+
process.wait()
|
|
62
|
+
ok, points, comment = self.task_type.check_output(execution.in_test_path, output_file, execution.out_test_path)
|
|
63
|
+
|
|
64
|
+
return RunResult(execution.in_test_path, ok, int(points), comment)
|
|
65
|
+
|
|
66
|
+
def run_and_print_table(self) -> Dict[str, TestResult]:
|
|
67
|
+
os.makedirs(paths.get_chkwer_path(), exist_ok=True)
|
|
68
|
+
results = {}
|
|
69
|
+
sorted_tests = sorted(self.tests, key=lambda test: package_util.get_group(test, self.task_id))
|
|
70
|
+
executions: List[ChkwerExecution] = []
|
|
71
|
+
for test in sorted_tests:
|
|
72
|
+
results[test] = TestResult(test, self.task_id)
|
|
73
|
+
executions.append(ChkwerExecution(test, results[test].test_name, package_util.get_out_from_in(test),
|
|
74
|
+
self.checker_executable, self.model_executable))
|
|
75
|
+
|
|
76
|
+
has_terminal, terminal_width, terminal_height = util.get_terminal_size()
|
|
77
|
+
table_data = TableData(results, 0, self.task_id, self.contest_type.max_score_per_test())
|
|
78
|
+
if has_terminal:
|
|
79
|
+
run_event = threading.Event()
|
|
80
|
+
run_event.set()
|
|
81
|
+
thr = threading.Thread(target=printer.printer_thread, args=(run_event, chkwer_util.print_view, table_data))
|
|
82
|
+
thr.start()
|
|
83
|
+
|
|
84
|
+
keyboard_interrupt = False
|
|
85
|
+
try:
|
|
86
|
+
with mp.Pool(self.cpus) as pool:
|
|
87
|
+
for i, result in enumerate(pool.imap(self.run_test, executions)):
|
|
88
|
+
table_data.results[result.test_path].set_results(result.points, result.ok, result.comment)
|
|
89
|
+
table_data.i = i
|
|
90
|
+
except KeyboardInterrupt:
|
|
91
|
+
keyboard_interrupt = True
|
|
92
|
+
|
|
93
|
+
if has_terminal:
|
|
94
|
+
run_event.clear()
|
|
95
|
+
thr.join()
|
|
96
|
+
|
|
97
|
+
print("\n".join(chkwer_util.print_view(terminal_width, terminal_height, table_data)[0]))
|
|
98
|
+
if keyboard_interrupt:
|
|
99
|
+
util.exit_with_error("Keyboard interrupt.")
|
|
100
|
+
return results
|
|
101
|
+
|
|
102
|
+
def run(self, args):
|
|
103
|
+
args = util.init_package_command(args)
|
|
104
|
+
self.task_id = package_util.get_task_id()
|
|
105
|
+
self.task_type = package_util.get_task_type("time", None)
|
|
106
|
+
self.contest_type = contest_types.get_contest_type()
|
|
107
|
+
|
|
108
|
+
if self.task_type.name() != "normal":
|
|
109
|
+
util.exit_with_error("chkwer can be run only for normal tasks.")
|
|
110
|
+
|
|
111
|
+
self.cpus = args.cpus or util.default_cpu_count()
|
|
112
|
+
self.tests = package_util.get_tests(self.task_id, args.tests)
|
|
113
|
+
|
|
114
|
+
if len(self.tests) == 0:
|
|
115
|
+
util.exit_with_error("No tests found.")
|
|
116
|
+
else:
|
|
117
|
+
print('Will run on tests: ' + util.bold(', '.join(self.tests)))
|
|
118
|
+
util.change_stack_size_to_unlimited()
|
|
119
|
+
|
|
120
|
+
additional_files = self.task_type.additional_files_to_compile()
|
|
121
|
+
if len(additional_files) == 0:
|
|
122
|
+
util.exit_with_error("Checker not found.")
|
|
123
|
+
if len(additional_files) != 1:
|
|
124
|
+
util.exit_with_error("More than one file to compile found. How is that possible?")
|
|
125
|
+
checker_info = additional_files[0]
|
|
126
|
+
model_solution = outgen_util.get_correct_solution(self.task_id)
|
|
127
|
+
self.checker_executable = self.compile(checker_info[0], checker_info[1], args, "checker",
|
|
128
|
+
args.compile_mode)
|
|
129
|
+
self.model_executable = self.compile(model_solution, package_util.get_executable(model_solution), args,
|
|
130
|
+
"model solution", args.compile_mode)
|
|
131
|
+
print()
|
|
132
|
+
|
|
133
|
+
results = self.run_and_print_table()
|
|
134
|
+
for result in results.values():
|
|
135
|
+
if not result.ok or result.points != self.contest_type.max_score_per_test():
|
|
136
|
+
util.exit_with_error("Model solution didn't score maximum points.")
|
|
137
|
+
print(util.info("Checker verification successful."))
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from io import StringIO
|
|
3
|
+
|
|
4
|
+
from sinol_make import util
|
|
5
|
+
from sinol_make.commands.inwer.inwer_util import sort_tests
|
|
6
|
+
from sinol_make.structs.chkwer_structs import TableData
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def print_view(term_width, term_height, table_data: TableData):
|
|
10
|
+
"""
|
|
11
|
+
Prints current results of test verification.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
previous_stdout = sys.stdout
|
|
15
|
+
new_stdout = StringIO()
|
|
16
|
+
sys.stdout = new_stdout
|
|
17
|
+
|
|
18
|
+
results = table_data.results
|
|
19
|
+
column_lengths = [0, len('Points') + 1, 0]
|
|
20
|
+
tests = []
|
|
21
|
+
for result in results.values():
|
|
22
|
+
column_lengths[0] = max(column_lengths[0], len(result.test_name))
|
|
23
|
+
tests.append(result.test_path)
|
|
24
|
+
tests = sort_tests(tests, table_data.task_id)
|
|
25
|
+
|
|
26
|
+
# 6 is for " | " between columns, 3 for margin.
|
|
27
|
+
column_lengths[2] = max(10, term_width - column_lengths[0] - column_lengths[1] - 6 - 3)
|
|
28
|
+
margin = " "
|
|
29
|
+
|
|
30
|
+
def print_line_separator():
|
|
31
|
+
res = "-" * (column_lengths[0] + 3) + "+" + "-" * (column_lengths[1] + 1) + "+"
|
|
32
|
+
res += "-" * (term_width - len(res) - 1)
|
|
33
|
+
print(res)
|
|
34
|
+
|
|
35
|
+
print_line_separator()
|
|
36
|
+
|
|
37
|
+
print(margin + "Test".ljust(column_lengths[0]) + " | " + "Points" + " | " + "Comment")
|
|
38
|
+
print_line_separator()
|
|
39
|
+
|
|
40
|
+
last_group = None
|
|
41
|
+
for test_path in tests:
|
|
42
|
+
result = results[test_path]
|
|
43
|
+
if last_group is not None and last_group != result.test_group:
|
|
44
|
+
print_line_separator()
|
|
45
|
+
last_group = result.test_group
|
|
46
|
+
print(margin + result.test_name.ljust(column_lengths[0]) + " | ", end='')
|
|
47
|
+
|
|
48
|
+
if result.run:
|
|
49
|
+
if result.ok:
|
|
50
|
+
if result.points == table_data.max_score:
|
|
51
|
+
print(util.info(str(result.points).ljust(column_lengths[1] - 1)), end='')
|
|
52
|
+
else:
|
|
53
|
+
print(util.warning(str(result.points).ljust(column_lengths[1] - 1)), end='')
|
|
54
|
+
else:
|
|
55
|
+
print(util.error(str(result.points).ljust(column_lengths[1] - 1)), end='')
|
|
56
|
+
else:
|
|
57
|
+
print(util.warning("...".ljust(column_lengths[1] - 1)), end='')
|
|
58
|
+
print(" | ", end='')
|
|
59
|
+
|
|
60
|
+
output = []
|
|
61
|
+
if result.run:
|
|
62
|
+
if result.comment:
|
|
63
|
+
print(result.comment)
|
|
64
|
+
else:
|
|
65
|
+
print(util.color_gray("No comment"))
|
|
66
|
+
|
|
67
|
+
print_line_separator()
|
|
68
|
+
print()
|
|
69
|
+
print()
|
|
70
|
+
|
|
71
|
+
sys.stdout = previous_stdout
|
|
72
|
+
return new_stdout.getvalue().splitlines(), None, "Use arrows to move."
|
|
@@ -12,11 +12,14 @@ class Command(BaseCommand):
|
|
|
12
12
|
"""
|
|
13
13
|
Class for `doc` command.
|
|
14
14
|
"""
|
|
15
|
-
LOG_PATTERNS = ['*~', '*.aux', '*.log', '*.dvi', '*.err', '*.inf']
|
|
15
|
+
LOG_PATTERNS = ['*~', '*.aux', '*.log', '*.dvi', '*.err', '*.inf', '*.out']
|
|
16
16
|
|
|
17
17
|
def get_name(self):
|
|
18
18
|
return "doc"
|
|
19
19
|
|
|
20
|
+
def get_short_name(self):
|
|
21
|
+
return "d"
|
|
22
|
+
|
|
20
23
|
def compile_file_latex_div(self, file_path):
|
|
21
24
|
print(f'Compiling {os.path.basename(file_path)} (latex to dvi)...')
|
|
22
25
|
os.chdir(os.path.dirname(file_path))
|
|
@@ -37,7 +40,8 @@ class Command(BaseCommand):
|
|
|
37
40
|
def compile_pdf_latex(self, file_path):
|
|
38
41
|
print(f'Compiling {os.path.basename(file_path)} (pdflatex)...')
|
|
39
42
|
os.chdir(os.path.dirname(file_path))
|
|
40
|
-
|
|
43
|
+
for _ in range(3):
|
|
44
|
+
subprocess.run(['pdflatex', file_path])
|
|
41
45
|
pdf_file = os.path.splitext(file_path)[0] + '.pdf'
|
|
42
46
|
pdf_file_path = os.path.join(os.path.dirname(file_path), pdf_file)
|
|
43
47
|
if not os.path.exists(pdf_file_path):
|
|
@@ -23,6 +23,9 @@ class Command(BaseCommand):
|
|
|
23
23
|
def get_name(self):
|
|
24
24
|
return "export"
|
|
25
25
|
|
|
26
|
+
def get_short_name(self):
|
|
27
|
+
return "e"
|
|
28
|
+
|
|
26
29
|
def configure_subparser(self, subparser: argparse.ArgumentParser):
|
|
27
30
|
parser = subparser.add_parser(
|
|
28
31
|
self.get_name(),
|
|
@@ -215,12 +218,15 @@ class Command(BaseCommand):
|
|
|
215
218
|
if 'c' in config['extra_compilation_args']:
|
|
216
219
|
c_flags += ' ' + format_multiple_arguments(config['extra_compilation_args']['c'])
|
|
217
220
|
|
|
221
|
+
tl = config.get('time_limit', None)
|
|
222
|
+
if not tl:
|
|
223
|
+
tl = config['time_limits'][0]
|
|
218
224
|
f.write(f'MODE = wer\n'
|
|
219
225
|
f'ID = {self.task_id}\n'
|
|
220
226
|
f'SIG = sinolmake\n'
|
|
221
227
|
f'\n'
|
|
222
|
-
f'TIMELIMIT = {
|
|
223
|
-
f'SLOW_TIMELIMIT = {4 *
|
|
228
|
+
f'TIMELIMIT = {tl}\n'
|
|
229
|
+
f'SLOW_TIMELIMIT = {4 * tl}\n'
|
|
224
230
|
f'MEMLIMIT = {config["memory_limit"]}\n'
|
|
225
231
|
f'\n'
|
|
226
232
|
f'OI_TIME = oiejq\n'
|
|
@@ -3,9 +3,8 @@ import argparse
|
|
|
3
3
|
from sinol_make import util
|
|
4
4
|
from sinol_make.commands.ingen import Command as IngenCommand
|
|
5
5
|
from sinol_make.commands.outgen import Command as OutgenCommand
|
|
6
|
-
from sinol_make.helpers import parsers
|
|
6
|
+
from sinol_make.helpers import parsers, package_util
|
|
7
7
|
from sinol_make.interfaces.BaseCommand import BaseCommand
|
|
8
|
-
from sinol_make.task_type import get_task_type
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class Command(BaseCommand):
|
|
@@ -16,6 +15,9 @@ class Command(BaseCommand):
|
|
|
16
15
|
def get_name(self):
|
|
17
16
|
return "gen"
|
|
18
17
|
|
|
18
|
+
def get_short_name(self):
|
|
19
|
+
return "g"
|
|
20
|
+
|
|
19
21
|
def configure_subparser(self, subparser):
|
|
20
22
|
parser = subparser.add_parser(
|
|
21
23
|
self.get_name(),
|
|
@@ -41,11 +43,11 @@ class Command(BaseCommand):
|
|
|
41
43
|
|
|
42
44
|
def run(self, args: argparse.Namespace):
|
|
43
45
|
args = util.init_package_command(args)
|
|
44
|
-
task_type = get_task_type()
|
|
45
46
|
|
|
46
47
|
self.args = args
|
|
47
48
|
self.ins = args.only_inputs
|
|
48
49
|
self.outs = args.only_outputs
|
|
50
|
+
self.task_type = package_util.get_task_type_cls()
|
|
49
51
|
# If no arguments are specified, generate both input and output files.
|
|
50
52
|
if not self.ins and not self.outs:
|
|
51
53
|
self.ins = True
|
|
@@ -55,6 +57,10 @@ class Command(BaseCommand):
|
|
|
55
57
|
command = IngenCommand()
|
|
56
58
|
command.run(args)
|
|
57
59
|
|
|
58
|
-
if self.
|
|
60
|
+
if not self.task_type.run_outgen():
|
|
61
|
+
print(util.warning("Outgen is not supported for this task type."))
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
if self.outs:
|
|
59
65
|
command = OutgenCommand()
|
|
60
66
|
command.run(args)
|
|
@@ -58,7 +58,7 @@ def compile_ingen(ingen_path: str, args: argparse.Namespace, compilation_flags='
|
|
|
58
58
|
compilers = compiler.verify_compilers(args, [ingen_path])
|
|
59
59
|
ingen_exe, compile_log_path = compile.compile_file(ingen_path, package_util.get_executable(ingen_path),
|
|
60
60
|
compilers, compilation_flags, use_fsanitize=use_fsanitize,
|
|
61
|
-
additional_flags='-D_INGEN')
|
|
61
|
+
additional_flags='-D_INGEN', use_extras=False)
|
|
62
62
|
|
|
63
63
|
if ingen_exe is None:
|
|
64
64
|
compile.print_compile_log(compile_log_path)
|
|
@@ -100,7 +100,7 @@ def run_ingen(ingen_exe, working_dir=None):
|
|
|
100
100
|
|
|
101
101
|
if util.has_sanitizer_error(whole_output, exit_code):
|
|
102
102
|
print(util.warning('Warning: if ingen failed due to sanitizer errors, you can either run '
|
|
103
|
-
'`sudo sysctl vm.mmap_rnd_bits
|
|
103
|
+
'`sudo sysctl vm.mmap_rnd_bits=28` to fix this or disable sanitizers with the '
|
|
104
104
|
'--no-fsanitize flag.'))
|
|
105
105
|
|
|
106
106
|
return exit_code == 0
|