Skip to content

Commit ef75347

Browse files
authored
Merge branch 'sio2project:master' into issue288
2 parents c53fce6 + 9c60b54 commit ef75347

File tree

174 files changed

+5425
-3380
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

174 files changed

+5425
-3380
lines changed

.readthedocs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ sphinx:
3030

3131
python:
3232
install:
33-
- requirements: rst/requirements.txt
3433
- requirements: requirements.txt
34+
- requirements: rst/requirements.txt

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ RUN apt-get update && \
2222
sudo \
2323
libstdc++6 \
2424
zlib1g \
25+
sox \
26+
flite \
2527
locales \
2628
python3-pip && \
2729
apt-get clean

easy_toolbox.py

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# pip requirements:
44
# python ^3.6
55
# inquirer (only for GUI)
6-
#
6+
#
77
# system:
88
# docker
99
# docker-compose
@@ -15,9 +15,9 @@
1515
# is prepared and should be upgraded or/and extended
1616
# for any future needs.
1717

18-
import sys
1918
import os
20-
19+
import sys
20+
from shlex import quote
2121

2222
BASE_DOCKER_COMMAND = "OIOIOI_UID=$(id -u) docker-compose" + \
2323
" -f docker-compose-dev.yml"
@@ -29,19 +29,18 @@
2929
("run", "Run server", "{exec} web python3 manage.py runserver 0.0.0.0:8000"),
3030
("stop", "Stop all SIO2 containers", "stop"),
3131
("bash", "Open command prompt on web container.", "{exec} web bash"),
32+
("exec", "Run a command in the web container.", "{exec} web {extra_args}"),
3233
("bash-db", "Open command prompt on database container.", "{exec} db bash"),
3334
# This one CLEARS the database. Use wisely.
3435
("flush-db", "Clear database.", "{exec} web python manage.py flush --noinput", True),
3536
("add-superuser", "Create admin_admin.",
3637
"{exec} web python manage.py loaddata ../oioioi/oioioi_cypress/cypress/fixtures/admin_admin.json"),
37-
("test", "Run unit tests.", "{exec} web ../oioioi/test.sh"),
38-
("test-slow", "Run unit tests. (--runslow)", "{exec} web ../oioioi/test.sh --runslow"),
39-
("test-abc", "Run specific test file. (edit the toolbox)",
40-
"{exec} web ../oioioi/test.sh -v oioioi/problems/tests/test_task_archive.py"),
38+
("test", "Run unit tests.", "{exec} web ../oioioi/test.sh {extra_args}"),
39+
("test-slow", "Run unit tests. (--runslow)", "{exec} web ../oioioi/test.sh --runslow {extra_args}"),
4140
("test-coverage", "Run coverage tests.",
42-
"{exec} 'web' ../oioioi/test.sh oioioi/problems --cov-report term --cov-report xml:coverage.xml --cov=oioioi"),
41+
"{exec} 'web' ../oioioi/test.sh oioioi/problems --cov-report term --cov-report xml:coverage.xml --cov=oioioi {extra_args}"),
4342
("cypress-apply-settings", "Apply settings for CyPress.",
44-
"{exec} web bash -c \"echo CAPTCHA_TEST_MODE=True >> settings.py\""),
43+
'{exec} web bash -c "echo CAPTCHA_TEST_MODE=True >> settings.py"'),
4544
]
4645

4746
longest_command_arg = max([len(command[0]) for command in RAW_COMMANDS])
@@ -52,15 +51,19 @@ class Help(Exception):
5251

5352

5453
class Option:
55-
def __init__(self, _arg, _help, _command, _warn=False):
54+
def __init__(self, _arg, _help, _command, _warn=False, extra_args=None):
5655
self.arg = _arg
56+
self.extra_args = extra_args
5757
self.help = _help
5858
self.command = _command
5959
self.warn = _warn
6060

6161
# If we use exec we should add -T for GitHub actions (disable tty).
62-
def fill_tty(self, disable=False):
63-
self.command = self.command.format(exec="exec -T" if disable else "exec")
62+
def gen_full_command(self, disable=False):
63+
return self.command.format(
64+
exec="exec -T" if disable else "exec",
65+
extra_args=self.extra_args or "",
66+
)
6467

6568
def long_str(self) -> str:
6669
return f"Option({self.arg}, Description='{self.help}', Command='{self.command}')"
@@ -70,14 +73,10 @@ def __str__(self) -> str:
7073
return f"[{self.arg}] {' ' * spaces} {self.help}"
7174

7275

73-
COMMANDS = [Option(*x) for x in RAW_COMMANDS]
74-
75-
76-
def check_commands() -> None:
77-
if len(set([opt.arg for opt in COMMANDS])) != len(COMMANDS):
78-
raise Exception("Error in COMMANDS. Same name was declared for more then one command.")
79-
76+
# command names are unique
77+
assert len(RAW_COMMANDS) == len({x[0] for x in RAW_COMMANDS})
8078

79+
COMMANDS = {x[0]: Option(*x) for x in RAW_COMMANDS}
8180
NO_INPUT = False
8281

8382

@@ -86,26 +85,28 @@ def get_action_from_args() -> Option:
8685
arguments = []
8786

8887
for arg in sys.argv[1:]:
89-
if arg in ['--help', '-h']:
90-
raise Help()
91-
elif arg in ['--no-input', '-i']:
88+
if arg in ["--help", "-h"]:
89+
raise Help
90+
elif arg in ["--no-input", "-i"]:
9291
global NO_INPUT
9392
NO_INPUT = True
9493
else:
9594
arguments.append(arg)
9695

9796
if len(arguments) < 1:
9897
return None
99-
if len(arguments) > 1:
100-
raise Exception("Too many arguments!")
10198

102-
candidates = list(filter(lambda opt: opt.arg == arguments[0], COMMANDS))
103-
if len(candidates) < 1:
99+
if arguments[0] not in COMMANDS:
104100
raise Exception("No argument was found!")
105-
if len(candidates) > 1:
106-
raise Exception("More then one matching argument was found!")
101+
opt = COMMANDS[arguments[0]]
102+
103+
if len(arguments) > 1:
104+
if r"{extra_args}" in opt.command:
105+
opt.extra_args = " ".join(map(quote, arguments[1:]))
106+
else:
107+
raise Exception("Too many arguments!")
107108

108-
return candidates[0]
109+
return opt
109110

110111

111112
def get_action_from_gui() -> Option:
@@ -114,18 +115,18 @@ def get_action_from_gui() -> Option:
114115
inquirer.List(
115116
"action",
116117
message="Select OIOIOI action",
117-
choices=COMMANDS
118-
)
118+
choices=COMMANDS,
119+
),
119120
]
120121
answers = inquirer.prompt(questions)
121122
return answers["action"]
122123

123124

124125
def run_command(command) -> None:
125-
print('Running command', command)
126+
print("Running command", command)
126127
if not NO_INPUT:
127128
width = os.get_terminal_size().columns
128-
print('=' * width)
129+
print("=" * width)
129130
sys.exit(os.WEXITSTATUS(os.system(command)))
130131

131132

@@ -143,30 +144,34 @@ def warn_user(action: Option) -> bool:
143144

144145
def run() -> None:
145146
action = get_action_from_args() or get_action_from_gui()
146-
action.fill_tty(disable=NO_INPUT)
147+
command = action.gen_full_command(disable=NO_INPUT)
147148
if action.warn and not NO_INPUT:
148149
if not warn_user(action):
149150
print("Aborting.")
150151
return
151-
run_command(f'{BASE_DOCKER_COMMAND} {action.command}')
152+
run_command(f"{BASE_DOCKER_COMMAND} {command}")
152153

153154

154155
def print_help() -> None:
155-
print("OIOIOI helper toolbox", "", "This script allows to control OIOIOI with Docker commands.",
156-
f"Commands are always being run with '{BASE_DOCKER_COMMAND}' prefix.",
157-
f"Aveliable commands are: ", "",
158-
*COMMANDS, "", "Example `build`:", f"{sys.argv[0]} build", sep="\n")
156+
print(
157+
"OIOIOI helper toolbox", "", "This script allows to control OIOIOI with Docker commands.",
158+
f"Commands are always being run with '{BASE_DOCKER_COMMAND}' prefix.",
159+
"Available commands are: ", "",
160+
*COMMANDS.values(), "",
161+
"Example `build`:",
162+
f"{sys.argv[0]} build",
163+
sep="\n",
164+
)
159165

160166

161167
def main() -> None:
162168
try:
163-
check_commands()
164169
run()
165170
except Help:
166171
print_help()
167172
except Exception as e:
168173
print(f"An error occurred during execution: {e}", file=sys.stderr)
169174

170175

171-
if __name__ == '__main__':
176+
if __name__ == "__main__":
172177
main()

jsconfig.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "https://json.schemastore.org/jsconfig",
3+
"compilerOptions": {
4+
"target": "ES2022",
5+
"moduleResolution": "NodeNext",
6+
"module": "NodeNext",
7+
"lib": [
8+
"ES2022",
9+
"DOM",
10+
"DOM.Iterable"
11+
],
12+
"allowJs": true,
13+
"checkJs": true,
14+
"noEmit": true,
15+
"strict": true,
16+
"exactOptionalPropertyTypes": true,
17+
// "resolveJsonModule": true,
18+
// "noUncheckedIndexedAccess": true, // Broken
19+
"skipLibCheck": false // Poorly documented, doesn't check own project files if true (default)
20+
},
21+
// Files we wish to typecheck
22+
"include": [
23+
"oioioi/notifications/**/*"
24+
],
25+
"typeAcquisition": {
26+
"include": [
27+
"jquery"
28+
]
29+
}
30+
}

0 commit comments

Comments
 (0)