3
3
# pip requirements:
4
4
# python ^3.6
5
5
# inquirer (only for GUI)
6
- #
6
+ #
7
7
# system:
8
8
# docker
9
9
# docker-compose
15
15
# is prepared and should be upgraded or/and extended
16
16
# for any future needs.
17
17
18
- import sys
19
18
import os
20
-
19
+ import sys
20
+ from shlex import quote
21
21
22
22
BASE_DOCKER_COMMAND = "OIOIOI_UID=$(id -u) docker-compose" + \
23
23
" -f docker-compose-dev.yml"
29
29
("run" , "Run server" , "{exec} web python3 manage.py runserver 0.0.0.0:8000" ),
30
30
("stop" , "Stop all SIO2 containers" , "stop" ),
31
31
("bash" , "Open command prompt on web container." , "{exec} web bash" ),
32
+ ("exec" , "Run a command in the web container." , "{exec} web {extra_args}" ),
32
33
("bash-db" , "Open command prompt on database container." , "{exec} db bash" ),
33
34
# This one CLEARS the database. Use wisely.
34
35
("flush-db" , "Clear database." , "{exec} web python manage.py flush --noinput" , True ),
35
36
("add-superuser" , "Create admin_admin." ,
36
37
"{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}" ),
41
40
("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} " ),
43
42
("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"' ),
45
44
]
46
45
47
46
longest_command_arg = max ([len (command [0 ]) for command in RAW_COMMANDS ])
@@ -52,15 +51,19 @@ class Help(Exception):
52
51
53
52
54
53
class Option :
55
- def __init__ (self , _arg , _help , _command , _warn = False ):
54
+ def __init__ (self , _arg , _help , _command , _warn = False , extra_args = None ):
56
55
self .arg = _arg
56
+ self .extra_args = extra_args
57
57
self .help = _help
58
58
self .command = _command
59
59
self .warn = _warn
60
60
61
61
# 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
+ )
64
67
65
68
def long_str (self ) -> str :
66
69
return f"Option({ self .arg } , Description='{ self .help } ', Command='{ self .command } ')"
@@ -70,14 +73,10 @@ def __str__(self) -> str:
70
73
return f"[{ self .arg } ] { ' ' * spaces } { self .help } "
71
74
72
75
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 })
80
78
79
+ COMMANDS = {x [0 ]: Option (* x ) for x in RAW_COMMANDS }
81
80
NO_INPUT = False
82
81
83
82
@@ -86,26 +85,28 @@ def get_action_from_args() -> Option:
86
85
arguments = []
87
86
88
87
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" ]:
92
91
global NO_INPUT
93
92
NO_INPUT = True
94
93
else :
95
94
arguments .append (arg )
96
95
97
96
if len (arguments ) < 1 :
98
97
return None
99
- if len (arguments ) > 1 :
100
- raise Exception ("Too many arguments!" )
101
98
102
- candidates = list (filter (lambda opt : opt .arg == arguments [0 ], COMMANDS ))
103
- if len (candidates ) < 1 :
99
+ if arguments [0 ] not in COMMANDS :
104
100
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!" )
107
108
108
- return candidates [ 0 ]
109
+ return opt
109
110
110
111
111
112
def get_action_from_gui () -> Option :
@@ -114,18 +115,18 @@ def get_action_from_gui() -> Option:
114
115
inquirer .List (
115
116
"action" ,
116
117
message = "Select OIOIOI action" ,
117
- choices = COMMANDS
118
- )
118
+ choices = COMMANDS ,
119
+ ),
119
120
]
120
121
answers = inquirer .prompt (questions )
121
122
return answers ["action" ]
122
123
123
124
124
125
def run_command (command ) -> None :
125
- print (' Running command' , command )
126
+ print (" Running command" , command )
126
127
if not NO_INPUT :
127
128
width = os .get_terminal_size ().columns
128
- print ('=' * width )
129
+ print ("=" * width )
129
130
sys .exit (os .WEXITSTATUS (os .system (command )))
130
131
131
132
@@ -143,30 +144,34 @@ def warn_user(action: Option) -> bool:
143
144
144
145
def run () -> None :
145
146
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 )
147
148
if action .warn and not NO_INPUT :
148
149
if not warn_user (action ):
149
150
print ("Aborting." )
150
151
return
151
- run_command (f' { BASE_DOCKER_COMMAND } { action . command } ' )
152
+ run_command (f" { BASE_DOCKER_COMMAND } { command } " )
152
153
153
154
154
155
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
+ )
159
165
160
166
161
167
def main () -> None :
162
168
try :
163
- check_commands ()
164
169
run ()
165
170
except Help :
166
171
print_help ()
167
172
except Exception as e :
168
173
print (f"An error occurred during execution: { e } " , file = sys .stderr )
169
174
170
175
171
- if __name__ == ' __main__' :
176
+ if __name__ == " __main__" :
172
177
main ()
0 commit comments