zrb 0.18.0__py3-none-any.whl → 0.22.0__py3-none-any.whl
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.
- zrb/__init__.py +2 -0
- zrb/builtin/project/add/app/generator/generator.py +1 -0
- zrb/builtin/project/add/app/generator/template/src/kebab-zrb-package-name/src/snake_zrb_package_name/snake_zrb_generator_name/_input.py +7 -4
- zrb/builtin/project/add/app/generator/template/src/kebab-zrb-package-name/src/snake_zrb_package_name/snake_zrb_generator_name/snake_zrb_generator_name.py +1 -0
- zrb/builtin/project/add/app/python/python.py +1 -0
- zrb/builtin/project/add/fastapp/app/_input.py +8 -4
- zrb/builtin/project/add/fastapp/app/app.py +1 -0
- zrb/builtin/project/add/fastapp/crud/_input.py +2 -1
- zrb/builtin/project/add/fastapp/crud/crud.py +1 -0
- zrb/builtin/project/add/fastapp/crud/nodejs/codemod/package-lock.json +33 -24
- zrb/builtin/project/add/fastapp/field/field.py +1 -0
- zrb/builtin/project/add/plugin/plugin.py +5 -1
- zrb/builtin/project/add/task/cmd/add.py +1 -0
- zrb/builtin/project/add/task/docker_compose/add.py +1 -0
- zrb/builtin/project/add/task/python/add.py +1 -0
- zrb/config/config.py +1 -0
- zrb/helper/multiline.py +13 -0
- zrb/task/any_task.py +7 -0
- zrb/task/base_task/base_task.py +1 -2
- zrb/task/base_task/component/common_task_model.py +34 -3
- zrb/task/cmd_task.py +21 -8
- zrb/task_input/base_input.py +51 -6
- zrb/task_input/bool_input.py +9 -6
- zrb/task_input/choice_input.py +8 -5
- zrb/task_input/float_input.py +8 -5
- zrb/task_input/int_input.py +8 -5
- zrb/task_input/multiline_input.py +125 -0
- zrb/task_input/password_input.py +9 -6
- zrb/task_input/str_input.py +18 -15
- zrb/task_input/task_input.py +3 -2
- {zrb-0.18.0.dist-info → zrb-0.22.0.dist-info}/METADATA +1 -1
- {zrb-0.18.0.dist-info → zrb-0.22.0.dist-info}/RECORD +35 -33
- {zrb-0.18.0.dist-info → zrb-0.22.0.dist-info}/LICENSE +0 -0
- {zrb-0.18.0.dist-info → zrb-0.22.0.dist-info}/WHEEL +0 -0
- {zrb-0.18.0.dist-info → zrb-0.22.0.dist-info}/entry_points.txt +0 -0
zrb/__init__.py
CHANGED
@@ -45,6 +45,7 @@ from zrb.task_input.bool_input import BoolInput
|
|
45
45
|
from zrb.task_input.choice_input import ChoiceInput
|
46
46
|
from zrb.task_input.float_input import FloatInput
|
47
47
|
from zrb.task_input.int_input import IntInput
|
48
|
+
from zrb.task_input.multiline_input import MultilineInput
|
48
49
|
from zrb.task_input.password_input import PasswordInput
|
49
50
|
from zrb.task_input.str_input import StrInput
|
50
51
|
from zrb.task_input.task_input import Input
|
@@ -93,6 +94,7 @@ assert BoolInput
|
|
93
94
|
assert ChoiceInput
|
94
95
|
assert FloatInput
|
95
96
|
assert IntInput
|
97
|
+
assert MultilineInput
|
96
98
|
assert PasswordInput
|
97
99
|
assert StrInput
|
98
100
|
assert Env
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
+
from zrb.helper.util import coalesce, to_kebab_case, to_snake_case
|
3
4
|
from zrb.task_input.int_input import IntInput
|
4
5
|
from zrb.task_input.str_input import StrInput
|
5
6
|
|
@@ -41,9 +42,9 @@ app_image_name_input = StrInput(
|
|
41
42
|
name="app-image-name",
|
42
43
|
description="App image name",
|
43
44
|
prompt="App image name",
|
44
|
-
default=
|
45
|
-
|
46
|
-
|
45
|
+
default=lambda m: "/".join(
|
46
|
+
[app_image_default_namespace, to_kebab_case(m.get("app_name"))]
|
47
|
+
),
|
47
48
|
)
|
48
49
|
|
49
50
|
http_port_input = IntInput(
|
@@ -58,5 +59,7 @@ env_prefix_input = StrInput(
|
|
58
59
|
name="env-prefix",
|
59
60
|
description="OS environment prefix",
|
60
61
|
prompt="OS environment prefix",
|
61
|
-
default=
|
62
|
+
default=lambda m: to_snake_case(
|
63
|
+
coalesce(m.get("app_name"), m.get("task_name"), "MY")
|
64
|
+
).upper(),
|
62
65
|
)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
+
from zrb.helper.util import coalesce, to_kebab_case, to_snake_case
|
3
4
|
from zrb.task_input.int_input import IntInput
|
4
5
|
from zrb.task_input.str_input import StrInput
|
5
6
|
|
@@ -37,13 +38,14 @@ app_description_input = StrInput(
|
|
37
38
|
app_image_default_namespace = os.getenv(
|
38
39
|
"PROJECT_IMAGE_DEFAULT_NAMESPACE", "docker.io/" + SYSTEM_USER
|
39
40
|
)
|
41
|
+
|
40
42
|
app_image_name_input = StrInput(
|
41
43
|
name="app-image-name",
|
42
44
|
description="App image name",
|
43
45
|
prompt="App image name",
|
44
|
-
default=
|
45
|
-
|
46
|
-
|
46
|
+
default=lambda m: "/".join(
|
47
|
+
[app_image_default_namespace, to_kebab_case(m.get("app_name"))]
|
48
|
+
),
|
47
49
|
)
|
48
50
|
|
49
51
|
http_port_input = IntInput(
|
@@ -58,5 +60,7 @@ env_prefix_input = StrInput(
|
|
58
60
|
name="env-prefix",
|
59
61
|
description="OS environment prefix",
|
60
62
|
prompt="OS environment prefix",
|
61
|
-
default=
|
63
|
+
default=lambda m: to_snake_case(
|
64
|
+
coalesce(m.get("app_name"), m.get("task_name"), "MY")
|
65
|
+
).upper(),
|
62
66
|
)
|
@@ -10,9 +10,10 @@ entity_name_input = StrInput(
|
|
10
10
|
|
11
11
|
plural_entity_name_input = StrInput(
|
12
12
|
name="plural-entity-name",
|
13
|
+
shortcut="p",
|
13
14
|
description="Plural entity name",
|
14
15
|
prompt="Plural entity name",
|
15
|
-
default="
|
16
|
+
default=lambda m: m.get("entity_name", "") + "s",
|
16
17
|
)
|
17
18
|
|
18
19
|
main_column_name_input = StrInput(
|
@@ -35,6 +35,7 @@ _CODEMOD_DIR = os.path.join(_CURRENT_DIR, "nodejs", "codemod")
|
|
35
35
|
@python_task(
|
36
36
|
name="validate",
|
37
37
|
inputs=[project_dir_input, app_name_input, module_name_input, entity_name_input],
|
38
|
+
retry=0,
|
38
39
|
)
|
39
40
|
async def validate(*args: Any, **kwargs: Any):
|
40
41
|
project_dir = kwargs.get("project_dir")
|
@@ -60,10 +60,13 @@
|
|
60
60
|
}
|
61
61
|
},
|
62
62
|
"node_modules/@types/node": {
|
63
|
-
"version": "20.
|
64
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.
|
65
|
-
"integrity": "sha512-
|
66
|
-
"dev": true
|
63
|
+
"version": "20.14.2",
|
64
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
|
65
|
+
"integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
|
66
|
+
"dev": true,
|
67
|
+
"dependencies": {
|
68
|
+
"undici-types": "~5.26.4"
|
69
|
+
}
|
67
70
|
},
|
68
71
|
"node_modules/balanced-match": {
|
69
72
|
"version": "1.0.2",
|
@@ -79,11 +82,11 @@
|
|
79
82
|
}
|
80
83
|
},
|
81
84
|
"node_modules/braces": {
|
82
|
-
"version": "3.0.
|
83
|
-
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.
|
84
|
-
"integrity": "sha512-
|
85
|
+
"version": "3.0.3",
|
86
|
+
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
87
|
+
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
85
88
|
"dependencies": {
|
86
|
-
"fill-range": "^7.
|
89
|
+
"fill-range": "^7.1.1"
|
87
90
|
},
|
88
91
|
"engines": {
|
89
92
|
"node": ">=8"
|
@@ -95,9 +98,9 @@
|
|
95
98
|
"integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w=="
|
96
99
|
},
|
97
100
|
"node_modules/fast-glob": {
|
98
|
-
"version": "3.3.
|
99
|
-
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.
|
100
|
-
"integrity": "sha512-
|
101
|
+
"version": "3.3.2",
|
102
|
+
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
103
|
+
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
101
104
|
"dependencies": {
|
102
105
|
"@nodelib/fs.stat": "^2.0.2",
|
103
106
|
"@nodelib/fs.walk": "^1.2.3",
|
@@ -110,17 +113,17 @@
|
|
110
113
|
}
|
111
114
|
},
|
112
115
|
"node_modules/fastq": {
|
113
|
-
"version": "1.
|
114
|
-
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.
|
115
|
-
"integrity": "sha512-
|
116
|
+
"version": "1.17.1",
|
117
|
+
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
118
|
+
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
|
116
119
|
"dependencies": {
|
117
120
|
"reusify": "^1.0.4"
|
118
121
|
}
|
119
122
|
},
|
120
123
|
"node_modules/fill-range": {
|
121
|
-
"version": "7.
|
122
|
-
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.
|
123
|
-
"integrity": "sha512-
|
124
|
+
"version": "7.1.1",
|
125
|
+
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
126
|
+
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
124
127
|
"dependencies": {
|
125
128
|
"to-regex-range": "^5.0.1"
|
126
129
|
},
|
@@ -175,11 +178,11 @@
|
|
175
178
|
}
|
176
179
|
},
|
177
180
|
"node_modules/micromatch": {
|
178
|
-
"version": "4.0.
|
179
|
-
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.
|
180
|
-
"integrity": "sha512-
|
181
|
+
"version": "4.0.7",
|
182
|
+
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
183
|
+
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
181
184
|
"dependencies": {
|
182
|
-
"braces": "^3.0.
|
185
|
+
"braces": "^3.0.3",
|
183
186
|
"picomatch": "^2.3.1"
|
184
187
|
},
|
185
188
|
"engines": {
|
@@ -301,9 +304,9 @@
|
|
301
304
|
}
|
302
305
|
},
|
303
306
|
"node_modules/typescript": {
|
304
|
-
"version": "5.
|
305
|
-
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.
|
306
|
-
"integrity": "sha512-
|
307
|
+
"version": "5.4.5",
|
308
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
309
|
+
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
307
310
|
"dev": true,
|
308
311
|
"bin": {
|
309
312
|
"tsc": "bin/tsc",
|
@@ -312,6 +315,12 @@
|
|
312
315
|
"engines": {
|
313
316
|
"node": ">=14.17"
|
314
317
|
}
|
318
|
+
},
|
319
|
+
"node_modules/undici-types": {
|
320
|
+
"version": "5.26.5",
|
321
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
322
|
+
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
323
|
+
"dev": true
|
315
324
|
}
|
316
325
|
}
|
317
326
|
}
|
@@ -32,6 +32,7 @@ from zrb.task.task import Task
|
|
32
32
|
@python_task(
|
33
33
|
name="validate",
|
34
34
|
inputs=[project_dir_input, app_name_input, module_name_input, entity_name_input],
|
35
|
+
retry=0,
|
35
36
|
)
|
36
37
|
async def validate(*args: Any, **kwargs: Any):
|
37
38
|
project_dir = kwargs.get("project_dir")
|
@@ -28,7 +28,11 @@ from zrb.task.task import Task
|
|
28
28
|
_CURRENT_DIR = os.path.dirname(__file__)
|
29
29
|
|
30
30
|
|
31
|
-
@python_task(
|
31
|
+
@python_task(
|
32
|
+
name="validate",
|
33
|
+
inputs=[project_dir_input, package_name_input],
|
34
|
+
retry=0,
|
35
|
+
)
|
32
36
|
async def validate(*args: Any, **kwargs: Any):
|
33
37
|
project_dir = kwargs.get("project_dir")
|
34
38
|
validate_existing_project_dir(project_dir)
|
zrb/config/config.py
CHANGED
@@ -32,6 +32,7 @@ def _get_default_tmp_dir() -> str:
|
|
32
32
|
|
33
33
|
tmp_dir = os.getenv("ZRB_TMP_DIR", _get_default_tmp_dir())
|
34
34
|
default_shell = os.getenv("ZRB_SHELL", _get_current_shell())
|
35
|
+
default_editor = os.getenv("ZRB_EDITOR", "nano")
|
35
36
|
init_script_str = os.getenv("ZRB_INIT_SCRIPTS", "")
|
36
37
|
init_scripts = init_script_str.split(":") if init_script_str != "" else []
|
37
38
|
logging_level = untyped_to_logging_level(os.getenv("ZRB_LOGGING_LEVEL", "WARNING"))
|
zrb/helper/multiline.py
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from zrb.helper.typecheck import typechecked
|
4
|
+
|
5
|
+
|
6
|
+
@typechecked
|
7
|
+
def edit(editor: str, mark_comment: str, text: str, extension: str = "txt") -> str:
|
8
|
+
result = click.edit(
|
9
|
+
text="\n".join([mark_comment, text]), editor=editor, extension=f".{extension}"
|
10
|
+
)
|
11
|
+
if result is None:
|
12
|
+
result = text
|
13
|
+
return "\n".join(result.split(mark_comment)).strip()
|
zrb/task/any_task.py
CHANGED
zrb/task/base_task/base_task.py
CHANGED
@@ -467,10 +467,9 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
|
|
467
467
|
)
|
468
468
|
)
|
469
469
|
# set checker keyval
|
470
|
+
self._lock_checkers()
|
470
471
|
checker_coroutines = []
|
471
472
|
for checker_task in self._get_checkers():
|
472
|
-
checker_task.add_input(*self._get_inputs())
|
473
|
-
checker_task.add_env(*self._get_envs())
|
474
473
|
checker_coroutines.append(
|
475
474
|
asyncio.create_task(
|
476
475
|
checker_task._set_keyval(kwargs=new_kwargs, env_prefix=env_prefix)
|
@@ -65,6 +65,11 @@ class CommonTaskModel:
|
|
65
65
|
self._group = group
|
66
66
|
if group is not None:
|
67
67
|
group._add_task(self)
|
68
|
+
checkers_cp: List[AnyTask] = [checker.copy() for checker in checkers]
|
69
|
+
for checker in checkers_cp:
|
70
|
+
checker.add_env(*envs)
|
71
|
+
checker.add_env_file(*env_files)
|
72
|
+
checker.add_input(*inputs)
|
68
73
|
self._description = coalesce_str(description, name)
|
69
74
|
self._inputs = inputs
|
70
75
|
self._envs = envs
|
@@ -75,7 +80,7 @@ class CommonTaskModel:
|
|
75
80
|
self._retry_interval = retry_interval
|
76
81
|
self._upstreams = upstreams
|
77
82
|
self._fallbacks = fallbacks
|
78
|
-
self._checkers =
|
83
|
+
self._checkers = checkers_cp
|
79
84
|
self._checking_interval = checking_interval
|
80
85
|
self._run_function: Optional[Callable[..., Any]] = run
|
81
86
|
self._on_triggered = on_triggered
|
@@ -101,6 +106,9 @@ class CommonTaskModel:
|
|
101
106
|
self.__has_already_inject_fallbacks: bool = False
|
102
107
|
self.__all_inputs: Optional[List[AnyInput]] = None
|
103
108
|
|
109
|
+
def _lock_checkers(self):
|
110
|
+
self.__allow_add_checkers = False
|
111
|
+
|
104
112
|
def _lock_upstreams(self):
|
105
113
|
self.__allow_add_upstreams = False
|
106
114
|
|
@@ -164,11 +172,15 @@ class CommonTaskModel:
|
|
164
172
|
if not self.__allow_add_inputs:
|
165
173
|
raise Exception(f"Cannot insert inputs for `{self.get_name()}`")
|
166
174
|
self._inputs = list(inputs) + list(self._inputs)
|
175
|
+
for checker in self._get_checkers():
|
176
|
+
checker.insert_input(*inputs)
|
167
177
|
|
168
178
|
def add_input(self, *inputs: AnyInput):
|
169
179
|
if not self.__allow_add_inputs:
|
170
180
|
raise Exception(f"Cannot add inputs for `{self.get_name()}`")
|
171
181
|
self._inputs = list(self._inputs) + list(inputs)
|
182
|
+
for checker in self._get_checkers():
|
183
|
+
checker.add_input(*inputs)
|
172
184
|
|
173
185
|
def inject_inputs(self):
|
174
186
|
pass
|
@@ -219,11 +231,15 @@ class CommonTaskModel:
|
|
219
231
|
if not self.__allow_add_envs:
|
220
232
|
raise Exception(f"Cannot insert envs to `{self.get_name()}`")
|
221
233
|
self._envs = list(envs) + list(self._envs)
|
234
|
+
for checker in self._get_checkers():
|
235
|
+
checker.insert_env(*envs)
|
222
236
|
|
223
237
|
def add_env(self, *envs: Env):
|
224
238
|
if not self.__allow_add_envs:
|
225
239
|
raise Exception(f"Cannot add envs to `{self.get_name()}`")
|
226
240
|
self._envs = list(self._envs) + list(envs)
|
241
|
+
for checker in self._get_checkers():
|
242
|
+
checker.add_env(*envs)
|
227
243
|
|
228
244
|
def inject_envs(self):
|
229
245
|
pass
|
@@ -255,11 +271,15 @@ class CommonTaskModel:
|
|
255
271
|
if not self.__allow_add_env_files:
|
256
272
|
raise Exception(f"Cannot insert env_files to `{self.get_name()}`")
|
257
273
|
self._env_files = list(env_files) + list(self._env_files)
|
274
|
+
for checker in self._get_checkers():
|
275
|
+
checker.insert_env_file(*env_files)
|
258
276
|
|
259
277
|
def add_env_file(self, *env_files: EnvFile):
|
260
278
|
if not self.__allow_add_env_files:
|
261
279
|
raise Exception(f"Cannot add env_files to `{self.get_name()}`")
|
262
280
|
self._env_files = list(self._env_files) + list(env_files)
|
281
|
+
for checker in self._get_checkers():
|
282
|
+
checker.add_env_file(*env_files)
|
263
283
|
|
264
284
|
def inject_env_files(self):
|
265
285
|
pass
|
@@ -317,15 +337,26 @@ class CommonTaskModel:
|
|
317
337
|
def insert_checker(self, *checkers: AnyTask):
|
318
338
|
if not self.__allow_add_checkers:
|
319
339
|
raise Exception(f"Cannot insert checkers to `{self.get_name()}`")
|
320
|
-
additional_checkers =
|
340
|
+
additional_checkers = self.__complete_new_checkers(checkers)
|
321
341
|
self._checkers = additional_checkers + self._checkers
|
322
342
|
|
323
343
|
def add_checker(self, *checkers: AnyTask):
|
324
344
|
if not self.__allow_add_checkers:
|
325
345
|
raise Exception(f"Cannot add checkers to `{self.get_name()}`")
|
326
|
-
additional_checkers =
|
346
|
+
additional_checkers = self.__complete_new_checkers(checkers)
|
327
347
|
self._checkers = self._checkers + additional_checkers
|
328
348
|
|
349
|
+
def __complete_new_checkers(self, new_checkers: List[AnyTask]) -> List[AnyTask]:
|
350
|
+
"""
|
351
|
+
For internal use: copy and completing new checkers
|
352
|
+
"""
|
353
|
+
checkers: List[AnyTask] = [checker.copy() for checker in new_checkers]
|
354
|
+
for checker in checkers:
|
355
|
+
checker.add_input(*self._get_inputs())
|
356
|
+
checker.add_env(*self._get_envs())
|
357
|
+
checker.add_env_file(*self._get_env_files())
|
358
|
+
return checkers
|
359
|
+
|
329
360
|
def inject_checkers(self):
|
330
361
|
pass
|
331
362
|
|
zrb/task/cmd_task.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import asyncio
|
2
2
|
import atexit
|
3
|
+
import logging
|
3
4
|
import os
|
4
5
|
import pathlib
|
5
6
|
import signal
|
@@ -7,7 +8,7 @@ import subprocess
|
|
7
8
|
import sys
|
8
9
|
import time
|
9
10
|
|
10
|
-
from zrb.config.config import default_shell
|
11
|
+
from zrb.config.config import default_shell, logging_level
|
11
12
|
from zrb.helper.accessories.color import colored
|
12
13
|
from zrb.helper.log import logger
|
13
14
|
from zrb.helper.typecheck import typechecked
|
@@ -55,6 +56,18 @@ def _reset_stty():
|
|
55
56
|
_has_stty = False
|
56
57
|
|
57
58
|
|
59
|
+
def _log_error(message: Any):
|
60
|
+
if logging_level > logging.ERROR:
|
61
|
+
return
|
62
|
+
colored_message = colored(f"{message}", color="red", attrs=["bold"])
|
63
|
+
logger.error(colored_message, exc_info=True)
|
64
|
+
|
65
|
+
|
66
|
+
def _print_out_dark(message: Any):
|
67
|
+
message_str = f"{message}"
|
68
|
+
print(colored(message_str, attrs=["dark"]), file=sys.stderr)
|
69
|
+
|
70
|
+
|
58
71
|
CmdVal = Union[
|
59
72
|
JinjaTemplate,
|
60
73
|
Iterable[JinjaTemplate],
|
@@ -272,7 +285,7 @@ class CmdTask(BaseTask):
|
|
272
285
|
def __on_kill(self, signum: Any, frame: Any):
|
273
286
|
self._global_state.no_more_attempt = True
|
274
287
|
self._global_state.is_killed_by_signal = True
|
275
|
-
|
288
|
+
_print_out_dark(f"Getting signal {signum}")
|
276
289
|
for pid in self._pids:
|
277
290
|
self.__kill_by_pid(pid)
|
278
291
|
tasks = asyncio.all_tasks()
|
@@ -282,7 +295,7 @@ class CmdTask(BaseTask):
|
|
282
295
|
except Exception as e:
|
283
296
|
self.print_err(e)
|
284
297
|
time.sleep(0.3)
|
285
|
-
|
298
|
+
_print_out_dark(f"Exiting with signal {signum}")
|
286
299
|
sys.exit(signum)
|
287
300
|
|
288
301
|
def __on_exit(self):
|
@@ -297,20 +310,20 @@ class CmdTask(BaseTask):
|
|
297
310
|
process_ever_exists = False
|
298
311
|
if self.__is_process_exist(pid):
|
299
312
|
process_ever_exists = True
|
300
|
-
|
313
|
+
_print_out_dark(f"Send SIGTERM to process {pid}")
|
301
314
|
os.killpg(os.getpgid(pid), signal.SIGTERM)
|
302
315
|
time.sleep(0.3)
|
303
316
|
if self.__is_process_exist(pid):
|
304
|
-
|
317
|
+
_print_out_dark(f"Send SIGINT to process {pid}")
|
305
318
|
os.killpg(os.getpgid(pid), signal.SIGINT)
|
306
319
|
time.sleep(0.3)
|
307
320
|
if self.__is_process_exist(pid):
|
308
|
-
|
321
|
+
_print_out_dark(f"Send SIGKILL to process {pid}")
|
309
322
|
os.killpg(os.getpgid(pid), signal.SIGKILL)
|
310
323
|
if process_ever_exists:
|
311
|
-
|
324
|
+
_print_out_dark(f"Process {pid} is killed successfully")
|
312
325
|
except Exception:
|
313
|
-
|
326
|
+
_log_error(f"Cannot kill process {pid}")
|
314
327
|
|
315
328
|
def __is_process_exist(self, pid: int) -> bool:
|
316
329
|
try:
|
zrb/task_input/base_input.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
from zrb.config.config import show_prompt
|
2
2
|
from zrb.helper.accessories.color import colored
|
3
3
|
from zrb.helper.log import logger
|
4
|
+
from zrb.helper.string.conversion import to_variable_name
|
5
|
+
from zrb.helper.string.jinja import is_probably_jinja
|
4
6
|
from zrb.helper.typecheck import typechecked
|
5
|
-
from zrb.helper.typing import Any, List, Mapping, Optional, Union
|
7
|
+
from zrb.helper.typing import Any, Callable, List, Mapping, Optional, Union
|
6
8
|
from zrb.task_input.any_input import AnyInput
|
7
9
|
from zrb.task_input.constant import RESERVED_INPUT_NAMES
|
8
10
|
|
@@ -10,6 +12,9 @@ logger.debug(colored("Loading zrb.task_input.base_input", attrs=["dark"]))
|
|
10
12
|
|
11
13
|
# flake8: noqa E501
|
12
14
|
|
15
|
+
InputCallback = Callable[[Mapping[str, Any], Any], Any]
|
16
|
+
InputDefault = Callable[[Mapping[str, Any]], Any]
|
17
|
+
|
13
18
|
|
14
19
|
@typechecked
|
15
20
|
class BaseInput(AnyInput):
|
@@ -22,8 +27,9 @@ class BaseInput(AnyInput):
|
|
22
27
|
name (str): The name of the input, used as a unique identifier.
|
23
28
|
shortcut (Optional[str]): An optional single-character shortcut for the input.
|
24
29
|
default (Optional[Any]): The default value of the input.
|
30
|
+
callback (Optional[Any]): The default value of the input.
|
25
31
|
description (Optional[str]): A brief description of what the input is for.
|
26
|
-
show_default (Union[bool, JinjaTemplate, None]): Determines
|
32
|
+
show_default (Union[bool, JinjaTemplate, None]): Determines the default value to be shown.
|
27
33
|
prompt (Union[bool, str]): The prompt text to be displayed when asking for the input.
|
28
34
|
confirmation_prompt (Union[bool, str]): A prompt for confirmation if required.
|
29
35
|
prompt_required (bool): Indicates whether a prompt is required.
|
@@ -50,13 +56,17 @@ class BaseInput(AnyInput):
|
|
50
56
|
>>> )
|
51
57
|
"""
|
52
58
|
|
59
|
+
__value_cache: Mapping[str, Any] = {}
|
60
|
+
__default_cache: Mapping[str, Any] = {}
|
61
|
+
|
53
62
|
def __init__(
|
54
63
|
self,
|
55
64
|
name: str,
|
56
65
|
shortcut: Optional[str] = None,
|
57
|
-
default: Optional[Any] = None,
|
66
|
+
default: Optional[Union[Any, InputDefault]] = None,
|
67
|
+
callback: Optional[InputCallback] = None,
|
58
68
|
description: Optional[str] = None,
|
59
|
-
show_default: Union[bool, str
|
69
|
+
show_default: Union[bool, str] = True,
|
60
70
|
prompt: Union[bool, str] = True,
|
61
71
|
confirmation_prompt: Union[bool, str] = False,
|
62
72
|
prompt_required: bool = True,
|
@@ -79,6 +89,7 @@ class BaseInput(AnyInput):
|
|
79
89
|
self._shortcut = shortcut
|
80
90
|
self._prompt = prompt
|
81
91
|
self._default = default
|
92
|
+
self._callback = callback
|
82
93
|
self._help = description if description is not None else name
|
83
94
|
self._type = type
|
84
95
|
self._show_default = show_default
|
@@ -100,6 +111,8 @@ class BaseInput(AnyInput):
|
|
100
111
|
return self._name
|
101
112
|
|
102
113
|
def get_default(self) -> Any:
|
114
|
+
if callable(self._default):
|
115
|
+
return self._default(self.__value_cache)
|
103
116
|
return self._default
|
104
117
|
|
105
118
|
def get_param_decl(self) -> List[str]:
|
@@ -110,10 +123,9 @@ class BaseInput(AnyInput):
|
|
110
123
|
|
111
124
|
def get_options(self) -> Mapping[str, Any]:
|
112
125
|
options: Mapping[str, Any] = {
|
113
|
-
"default": self._default,
|
114
126
|
"help": self._help,
|
115
127
|
"type": self._type,
|
116
|
-
"show_default": self.
|
128
|
+
"show_default": self._get_calculated_show_default(),
|
117
129
|
"confirmation_prompt": self._confirmation_prompt,
|
118
130
|
"prompt_required": self._prompt_required,
|
119
131
|
"hide_input": self._hide_input,
|
@@ -126,11 +138,44 @@ class BaseInput(AnyInput):
|
|
126
138
|
"show_choices": self._show_choices,
|
127
139
|
"show_envvar": self._show_envvar,
|
128
140
|
"nargs": self._nargs,
|
141
|
+
"callback": self._wrapped_callback,
|
142
|
+
"default": self._wrapped_default,
|
129
143
|
}
|
130
144
|
if show_prompt:
|
131
145
|
options["prompt"] = self._prompt
|
132
146
|
return options
|
133
147
|
|
148
|
+
def _wrapped_callback(self, ctx, param, value) -> Any:
|
149
|
+
var_name = to_variable_name(self.get_name())
|
150
|
+
if var_name not in self.__value_cache:
|
151
|
+
if callable(self._callback):
|
152
|
+
result = self._callback(self.__value_cache, value)
|
153
|
+
self.__value_cache[var_name] = result
|
154
|
+
return result
|
155
|
+
self.__value_cache[var_name] = value
|
156
|
+
return value
|
157
|
+
return self.__value_cache[var_name]
|
158
|
+
|
159
|
+
def _wrapped_default(self) -> Any:
|
160
|
+
var_name = to_variable_name(self.get_name())
|
161
|
+
if var_name not in self.__default_cache:
|
162
|
+
if callable(self._default):
|
163
|
+
default = self._default(self.__value_cache)
|
164
|
+
self.__default_cache[var_name] = default
|
165
|
+
return default
|
166
|
+
self.__default_cache[var_name] = self._default
|
167
|
+
return self._default
|
168
|
+
return self.__default_cache[var_name]
|
169
|
+
|
170
|
+
def _get_calculated_show_default(self) -> str:
|
171
|
+
if self._show_default != True:
|
172
|
+
return self._show_default
|
173
|
+
if callable(self._default) or (
|
174
|
+
self.__should_render and is_probably_jinja(self._default)
|
175
|
+
):
|
176
|
+
return colored("Autogenerated", color="yellow")
|
177
|
+
return f"{self._default}"
|
178
|
+
|
134
179
|
def should_render(self) -> bool:
|
135
180
|
return self.__should_render
|
136
181
|
|