Coverage for src/cli/main.py: 100.00%
86 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 10:53 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 10:53 +0000
1#!/usr/bin/env python3
3# Standard libraries
4from argparse import (
5 _ArgumentGroup,
6 ArgumentParser,
7 Namespace,
8 RawTextHelpFormatter,
9)
10from os import environ
11from shutil import get_terminal_size
12from sys import exit as sys_exit
14# Components
15from ..features.actions import ActionsFeature
16from ..lib.executor import Executor
17from ..package.bundle import Bundle
18from ..package.settings import Settings
19from ..package.updates import Updates
20from ..package.version import Version
21from ..prints.colors import Colors
22from ..system.platform import Platform
23from .entrypoint import Entrypoint
25# Constants
26HELP_POSITION: int = 23
28# Main, pylint: disable=too-many-branches,too-many-statements
29def main() -> None:
31 # Variables
32 group: _ArgumentGroup
33 result: Entrypoint.Result
35 # Arguments creation
36 parser: ArgumentParser = ArgumentParser(
37 prog=Bundle.NAME,
38 description=f'{Bundle.NAME}: {Bundle.DESCRIPTION}',
39 add_help=False,
40 formatter_class=lambda prog: RawTextHelpFormatter(
41 prog,
42 max_help_position=HELP_POSITION,
43 width=min(
44 120,
45 get_terminal_size().columns - 2,
46 ),
47 ),
48 )
50 # Arguments internal definitions
51 group = parser.add_argument_group('internal arguments')
52 group.add_argument(
53 '-h',
54 '--help',
55 dest='help',
56 action='store_true',
57 help='Show this help message',
58 )
59 group.add_argument(
60 '--version',
61 dest='version',
62 action='store_true',
63 help='Show the current version',
64 )
65 group.add_argument(
66 '--no-color',
67 dest='no_color',
68 action='store_true',
69 help=f'Disable colors outputs with \'{Bundle.ENV_NO_COLOR}=1\'\n'
70 '(or default settings: [themes] > no_color)',
71 )
72 group.add_argument(
73 '--update-check',
74 dest='update_check',
75 action='store_true',
76 help='Check for newer package updates',
77 )
78 group.add_argument(
79 '--settings',
80 dest='settings',
81 action='store_true',
82 help='Show the current settings path and contents',
83 )
84 group.add_argument(
85 '--set',
86 dest='set',
87 action='store',
88 metavar=('GROUP', 'KEY', 'VAL'),
89 nargs=3,
90 help='Set settings specific \'VAL\' value to [GROUP] > KEY\n' \
91 'or unset by using \'UNSET\' as \'VAL\'',
92 )
94 # Arguments configuration definitions
95 group = parser.add_argument_group('configuration arguments')
96 group.add_argument(
97 '--delay-init',
98 dest='delay_init',
99 type=float,
100 default=Executor.DELAY_INIT,
101 help='Delay the initial action execution (in s, default: %(default)s)',
102 metavar='SECS',
103 )
104 group.add_argument(
105 '--delay-press',
106 dest='delay_press',
107 type=float,
108 default=Executor.DELAY_PRESS,
109 help='Delay the press actions execution (in s, default: %(default)s)',
110 metavar='SECS',
111 )
112 group.add_argument(
113 '--delay-prompt',
114 dest='delay_prompt',
115 type=float,
116 default=Executor.DELAY_PROMPT,
117 help='Delay the prompt actions execution (in s, default: %(default)s)',
118 metavar='SECS',
119 )
120 group.add_argument(
121 '--hold-prompt',
122 dest='hold_prompt',
123 action='store_true',
124 help='Hold the prompt execution without a new line',
125 )
126 group.add_argument(
127 '--host',
128 dest='host',
129 action='store',
130 default=Executor.LABEL_HOST,
131 help='Configure the host name (default: %(default)s' + ', env: ' +
132 Bundle.ENV_HOST + ')',
133 )
134 group.add_argument(
135 '--tool',
136 dest='tool',
137 action='store',
138 default=Executor.LABEL_TOOL,
139 help='Configure the tool name (default: %(default)s' + ', env: ' +
140 Bundle.ENV_TOOL + ')',
141 )
142 group.add_argument(
143 '--mask',
144 dest='masks',
145 action='append',
146 help='Mask specific strings from console outputs (credentials for example)',
147 metavar='STRINGS',
148 )
149 group.add_argument(
150 '--workdir',
151 dest='workdir',
152 action='store',
153 help='Use a specific working directory path',
154 )
156 # Arguments actions definitions
157 group = parser.add_argument_group('actions arguments')
158 group.add_argument(
159 '--up',
160 dest='actions',
161 action='append_const',
162 const=ActionsFeature.ActionKey(Executor.KEY_UP),
163 help='Press the <UP> key',
164 )
165 group.add_argument(
166 '--down',
167 dest='actions',
168 action='append_const',
169 const=ActionsFeature.ActionKey(Executor.KEY_DOWN),
170 help='Press the <DOWN> key',
171 )
172 group.add_argument(
173 '--left',
174 dest='actions',
175 action='append_const',
176 const=ActionsFeature.ActionKey(Executor.KEY_LEFT),
177 help='Press the <LEFT> key',
178 )
179 group.add_argument(
180 '--right',
181 dest='actions',
182 action='append_const',
183 const=ActionsFeature.ActionKey(Executor.KEY_RIGHT),
184 help='Press the <RIGHT> key',
185 )
186 group.add_argument(
187 '--enter',
188 dest='actions',
189 action='append_const',
190 const=ActionsFeature.ActionKey(Executor.KEY_ENTER),
191 help='Press the <ENTER> key',
192 )
193 group.add_argument(
194 '--space',
195 dest='actions',
196 action='append_const',
197 const=ActionsFeature.ActionKey(Executor.KEY_SPACE),
198 help='Press the <SPACE> key',
199 )
200 group.add_argument(
201 '--press',
202 dest='actions',
203 action='append',
204 type=ActionsFeature.ActionKey,
205 help='Press the specified <KEY>',
206 metavar='KEY',
207 )
208 group.add_argument(
209 '--ctrl',
210 dest='actions',
211 action='append',
212 type=ActionsFeature.ActionKeyControl,
213 help='Press the specified Ctrl+<KEY>',
214 metavar='KEY',
215 )
216 group.add_argument(
217 '--read',
218 dest='actions',
219 action='append_const',
220 const=ActionsFeature.ActionRead(),
221 help='Read the buffered data output (forced)',
222 )
223 group.add_argument(
224 '--wait',
225 dest='actions',
226 action='append',
227 type=ActionsFeature.ActionWait,
228 help='Wait the specified time (in s, example: 1.0)',
229 metavar='SECS',
230 )
231 group.add_argument(
232 '--finish',
233 dest='actions',
234 action='append_const',
235 const=ActionsFeature.ActionFinish(),
236 help='Finish the execution (forced)',
237 )
239 # Arguments positional definitions
240 group = parser.add_argument_group('positional arguments')
241 group.add_argument(
242 '--',
243 dest='double_dash',
244 action='store_true',
245 help='Positional arguments separator (recommended)',
246 )
247 group.add_argument(
248 dest='command',
249 nargs='*',
250 help='Command arguments to execute (use -- to separate)',
251 )
253 # Arguments parser
254 options: Namespace = parser.parse_args()
256 # Help informations
257 if options.help:
258 print(' ')
259 parser.print_help()
260 print(' ')
261 Platform.flush()
262 sys_exit(0)
264 # Instantiate settings
265 settings: Settings = Settings(name=Bundle.NAME)
267 # Prepare no_color
268 if not options.no_color:
269 if settings.has('themes', 'no_color'):
270 options.no_color = settings.get_bool('themes', 'no_color')
271 else:
272 options.no_color = False
273 settings.set_bool('themes', 'no_color', options.no_color)
275 # Configure no_color
276 if options.no_color:
277 environ[Bundle.ENV_FORCE_COLOR] = '0'
278 environ[Bundle.ENV_NO_COLOR] = '1'
280 # Prepare colors
281 Colors.prepare()
283 # Settings setter
284 if options.set:
285 settings.set(options.set[0], options.set[1], options.set[2])
286 settings.show()
287 sys_exit(0)
289 # Settings informations
290 if options.settings:
291 settings.show()
292 sys_exit(0)
294 # Instantiate updates
295 updates: Updates = Updates(
296 name=Bundle.PACKAGE,
297 settings=settings,
298 )
300 # Version informations
301 if options.version:
302 print(
303 f'{Bundle.NAME} {Version.get()} from {Version.path()} (python {Version.python()})'
304 )
305 Platform.flush()
306 sys_exit(0)
308 # Check for current updates
309 if options.update_check:
310 if not updates.check():
311 updates.check(older=True)
312 sys_exit(0)
314 # CLI entrypoint
315 result = Entrypoint.cli(options)
317 # Check for daily updates
318 if updates.enabled and updates.daily:
319 updates.check()
321 # Result
322 if result in [
323 Entrypoint.Result.SUCCESS,
324 Entrypoint.Result.FINALIZE,
325 ]:
326 sys_exit(0)
327 else:
328 sys_exit(1)
330# Entrypoint
331if __name__ == '__main__': # pragma: no cover
332 main()