zrb 0.0.45__py3-none-any.whl → 0.0.47__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.
Files changed (57) hide show
  1. zrb/__init__.py +1 -1
  2. zrb/action/runner.py +2 -3
  3. zrb/builtin/__init__.py +2 -0
  4. zrb/builtin/_group.py +1 -1
  5. zrb/builtin/env.py +0 -2
  6. zrb/builtin/generator/_common.py +15 -16
  7. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/docker-compose.yml +7 -1
  8. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/image/Dockerfile +3 -1
  9. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/image/main.py +0 -5
  10. zrb/builtin/generator/fastapp/add.py +3 -3
  11. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/_common.py +17 -7
  12. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/config/docker-compose.env +3 -0
  13. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/container.py +14 -5
  14. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/image.py +1 -1
  15. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/local.py +1 -2
  16. zrb/builtin/generator/fastapp/template/src/kebab-app-name/docker-compose.yml +24 -6
  17. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/Dockerfile +3 -1
  18. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/template.env +1 -1
  19. zrb/builtin/generator/fastapp_module/add.py +266 -83
  20. zrb/builtin/generator/project/template/README.md +19 -3
  21. zrb/builtin/generator/project_task/add.py +12 -13
  22. zrb/builtin/generator/project_task/task_factory.py +12 -14
  23. zrb/builtin/generator/simple_python_app/add.py +3 -3
  24. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/docker-compose.yml +7 -1
  25. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/src/Dockerfile +3 -1
  26. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/src/main.py +0 -5
  27. zrb/builtin/md5.py +5 -4
  28. zrb/builtin/project.py +32 -0
  29. zrb/helper/docker_compose/file.py +22 -0
  30. zrb/helper/env_map/fetch.py +68 -0
  31. zrb/helper/file/copy_tree.py +6 -7
  32. zrb/helper/file/text.py +20 -0
  33. zrb/helper/string/jinja.py +11 -0
  34. zrb/task/base_task.py +457 -4
  35. zrb/task/cmd_task.py +1 -2
  36. zrb/task/decorator.py +1 -1
  37. zrb/task/docker_compose_task.py +3 -4
  38. zrb/task/http_checker.py +1 -2
  39. zrb/task/installer/factory.py +6 -4
  40. zrb/task/path_checker.py +3 -4
  41. zrb/task/port_checker.py +1 -2
  42. zrb/task/resource_maker.py +2 -3
  43. zrb/task_env/env.py +4 -3
  44. {zrb-0.0.45.dist-info → zrb-0.0.47.dist-info}/METADATA +3 -1
  45. {zrb-0.0.45.dist-info → zrb-0.0.47.dist-info}/RECORD +52 -51
  46. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module_disabled.env +0 -0
  47. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module_enabled.env +0 -0
  48. zrb/helper/dockercompose/read.py +0 -9
  49. zrb/task/base_model.py +0 -456
  50. zrb/task_group/group.py +0 -36
  51. /zrb/builtin/generator/fastapp/template/{_automate/snake_app_name/config/module_disabled.env → src/kebab-app-name/all-module-disabled.env} +0 -0
  52. /zrb/builtin/generator/fastapp/template/{_automate/snake_app_name/config/module_enabled.env → src/kebab-app-name/all-module-enabled.env} +0 -0
  53. /zrb/helper/{dockercompose → docker_compose}/fetch_external_env.py +0 -0
  54. /zrb/{task_group → helper/env_map}/__init__.py +0 -0
  55. {zrb-0.0.45.dist-info → zrb-0.0.47.dist-info}/LICENSE +0 -0
  56. {zrb-0.0.45.dist-info → zrb-0.0.47.dist-info}/WHEEL +0 -0
  57. {zrb-0.0.45.dist-info → zrb-0.0.47.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  from typing import Any, List
2
+ from dotenv import dotenv_values
2
3
  from ..._group import project_add_group
3
4
  from ....task.task import Task
4
5
  from ....task.decorator import python_task
@@ -12,11 +13,15 @@ from .._common import (
12
13
  from ....helper import util
13
14
  from ....helper.codemod.add_import_module import add_import_module
14
15
  from ....helper.codemod.add_function_call import add_function_call
16
+ from ....helper.docker_compose.file import add_services
17
+ from ....helper.file.text import (
18
+ read_text_file_async, write_text_file_async, append_text_file_async
19
+ )
15
20
 
21
+ import asyncio
16
22
  import os
17
23
  import jsons
18
24
 
19
-
20
25
  current_dir = os.path.dirname(__file__)
21
26
 
22
27
 
@@ -66,120 +71,298 @@ copy_resource = ResourceMaker(
66
71
 
67
72
 
68
73
  @python_task(
69
- name='register-module',
70
- inputs=[project_dir_input, app_name_input, module_name_input],
71
- upstreams=[copy_resource]
74
+ name='fastapp-module',
75
+ group=project_add_group,
76
+ upstreams=[copy_resource],
77
+ runner=runner
72
78
  )
73
- def register_module(*args: Any, **kwargs: Any):
79
+ async def add_fastapp_module(*args: Any, **kwargs: Any):
74
80
  task: Task = kwargs.get('_task')
75
81
  project_dir = kwargs.get('project_dir', '.')
76
82
  app_name = kwargs.get('app_name')
77
83
  module_name = kwargs.get('module_name')
78
84
  kebab_app_name = util.to_kebab_case(app_name)
85
+ snake_app_name = util.to_snake_case(app_name)
86
+ kebab_module_name = util.to_kebab_case(module_name)
79
87
  snake_module_name = util.to_snake_case(module_name)
80
- import_module_path = '.'.join([
81
- 'module', snake_module_name
88
+ upper_snake_module_name = snake_module_name.upper()
89
+ app_main_file = get_app_main_file(project_dir, kebab_app_name)
90
+ app_config_file = get_app_config_file(project_dir, kebab_app_name)
91
+ json_modules_file = get_json_modules_file(project_dir, snake_app_name)
92
+ enabled_env_file = get_all_enabled_env_file(project_dir, kebab_app_name)
93
+ disabled_env_file = get_all_disabled_env_file(project_dir, kebab_app_name)
94
+ docker_compose_file = get_docker_compose_file(project_dir, kebab_app_name)
95
+ results = await asyncio.gather(*[
96
+ asyncio.create_task(create_automation_json_config(
97
+ task, json_modules_file, snake_module_name
98
+ )),
99
+ asyncio.create_task(register_module(
100
+ task, app_main_file, snake_module_name
101
+ )),
102
+ asyncio.create_task(create_app_config(
103
+ task, app_config_file, snake_module_name, upper_snake_module_name
104
+ )),
105
+ asyncio.create_task(append_all_enabled_env(
106
+ task, enabled_env_file, upper_snake_module_name
107
+ )),
108
+ asyncio.create_task(append_all_disabled_env(
109
+ task, disabled_env_file, upper_snake_module_name
110
+ )),
82
111
  ])
83
- function_name = f'register_{snake_module_name}'
84
- main_file_path = os.path.join(
85
- project_dir, 'src', kebab_app_name, 'src', 'main.py'
112
+ modules = results[0] # return value of `create_automation_json_config`
113
+ module_port = 8080 + len(modules)
114
+ src_template_env_path = get_src_template_env_file(
115
+ project_dir, kebab_app_name
86
116
  )
87
- task.print_out(f'Read code from: {main_file_path}')
88
- with open(main_file_path, 'r') as f:
89
- code = f.read()
90
- task.print_out(
91
- f'Add import "{function_name}" from "{import_module_path}" to the code'
117
+ src_template_env_map = dotenv_values(src_template_env_path)
118
+ app_port = int(src_template_env_map.get('APP_PORT', '8080'))
119
+ module_app_port = app_port + len(modules)
120
+ compose_env_path = get_compose_env_file(
121
+ project_dir, snake_app_name
92
122
  )
93
- code = add_import_module(
94
- code=code,
95
- module_path=import_module_path,
96
- resource=function_name
123
+ compose_env_map = dotenv_values(compose_env_path)
124
+ host_port = int(compose_env_map.get('APP_GATEWAY_HOST_PORT', '8080'))
125
+ module_host_port = host_port + len(modules)
126
+ await asyncio.gather(*[
127
+ asyncio.create_task(add_docker_compose_service(
128
+ task, module_port, docker_compose_file, kebab_app_name,
129
+ snake_app_name, kebab_module_name, snake_module_name,
130
+ upper_snake_module_name
131
+ )),
132
+ asyncio.create_task(append_src_template_env(
133
+ task, module_app_port, src_template_env_path,
134
+ upper_snake_module_name
135
+ )),
136
+ asyncio.create_task(append_compose_env(
137
+ task, module_host_port, compose_env_path,
138
+ upper_snake_module_name
139
+ ))
140
+ ])
141
+ # TODO: create runner for local microservices
142
+ # TODO: create deployment for local microservices
143
+ task.print_out('Success')
144
+
145
+
146
+ async def add_docker_compose_service(
147
+ task: Task,
148
+ module_app_port: int,
149
+ docker_compose_file_path: str,
150
+ kebab_app_name: str,
151
+ snake_app_name: str,
152
+ kebab_module_name: str,
153
+ snake_module_name: str,
154
+ upper_snake_module_name: str
155
+ ):
156
+ module_app_port_str = str(module_app_port)
157
+ app_container_port_env_name = f'APP_{upper_snake_module_name}_MODULE_PORT'
158
+ app_container_port_env = '${' + app_container_port_env_name + ':-' + module_app_port_str + '}' # noqa
159
+ app_host_port_env_name = f'APP_{upper_snake_module_name}_HOST_MODULE_PORT'
160
+ app_host_port_env = '${' + app_host_port_env_name + ':-' + module_app_port_str + '}' # noqa
161
+ task.print_out(f'Add service at: {docker_compose_file_path}')
162
+ add_services(
163
+ file_name=docker_compose_file_path,
164
+ new_services={
165
+ f'{kebab_app_name}-{kebab_module_name}-module': {
166
+ 'build': {
167
+ 'dockerfile': 'Dockerfile',
168
+ 'context': './src'
169
+ },
170
+ 'image': '${IMAGE:-' + kebab_app_name + '}',
171
+ 'container_name': f'{snake_app_name}_{snake_module_name}',
172
+ 'hostname': f'snake_app_name_{snake_module_name}',
173
+ 'env_file': [
174
+ 'src/template.env',
175
+ 'all-module-disabled.env'
176
+ ],
177
+ 'environment': {
178
+ 'APP_NAME': '${APP_NAME:-' + kebab_app_name + '}-' + f'{kebab_module_name}-module', # noqa
179
+ 'APP_PORT': app_container_port_env, # noqa
180
+ 'APP_RMQ_CONNECTION': '${APP_CONTAINER_RMQ_CONNECTION:-amqp://guest:guest@rabbitmq/}', # noqa
181
+ 'APP_KAFKA_BOOTSTRAP_SERVERS': '${APP_CONTAINER_KAFKA_BOOTSTRAP_SERVERS:-redpanda:9092}', # noqa
182
+ 'APP_ENABLE_MESSAGE_CONSUMER': 'true',
183
+ 'APP_ENABLE_RPC_SERVER': 'true',
184
+ 'APP_ENABLE_API': 'false',
185
+ 'APP_ENABLE_FRONTEND': 'false',
186
+ f'APP_ENABLE_{upper_snake_module_name}_MODULE': 'true',
187
+ },
188
+ 'ports': [
189
+ f'{app_host_port_env}:{app_container_port_env}'
190
+ ],
191
+ 'restart': 'on-failure',
192
+ 'profiles': [
193
+ 'microservices'
194
+ ],
195
+ 'healthcheck': {
196
+ 'test': [
197
+ "CMD-SHELL",
198
+ "curl --fail http://localhost:${APP_PORT:-8080}/ || exit 1" # noqa
199
+ ],
200
+ 'interval': '5s',
201
+ 'timeout': '1s',
202
+ 'retries': 30
203
+ }
204
+ }
205
+ }
97
206
  )
98
- task.print_out(f'Add "{function_name}" call to the code')
99
- code = add_function_call(
100
- code=code,
101
- function_name=function_name,
102
- parameters=[]
207
+
208
+
209
+ async def append_compose_env(
210
+ task: Task,
211
+ module_app_port: int,
212
+ compose_template_env_path: str,
213
+ upper_snake_module_name: str
214
+ ):
215
+ new_env_str = '\n'.join([
216
+ f'APP_{upper_snake_module_name}_HOST_MODULE_PORT={module_app_port}',
217
+ f'APP_{upper_snake_module_name}_MODULE_PORT={module_app_port}',
218
+ ])
219
+ task.print_out(f'Add new environment to: {compose_template_env_path}')
220
+ await append_text_file_async(compose_template_env_path, new_env_str)
221
+
222
+
223
+ async def append_src_template_env(
224
+ task: Task,
225
+ module_app_port: int,
226
+ src_template_env_path: str,
227
+ upper_snake_module_name: str
228
+ ):
229
+ new_env_str = '\n'.join([
230
+ f'APP_ENABLE_{upper_snake_module_name}_MODULE=true',
231
+ ])
232
+ task.print_out(f'Add new environment to: {src_template_env_path}')
233
+ await append_text_file_async(src_template_env_path, new_env_str)
234
+
235
+
236
+ async def append_all_enabled_env(
237
+ task: Task,
238
+ all_enabled_env_path: str,
239
+ upper_snake_module_name: str
240
+ ):
241
+ task.print_out(f'Add new environment to: {all_enabled_env_path}')
242
+ await append_text_file_async(
243
+ all_enabled_env_path,
244
+ f'APP_ENABLE_{upper_snake_module_name}_MODULE=true'
103
245
  )
104
- task.print_out(f'Write modified code to: {main_file_path}')
105
- with open(main_file_path, 'w') as f:
106
- f.write(code)
107
246
 
108
247
 
109
- @python_task(
110
- name='create-app-config',
111
- inputs=[project_dir_input, app_name_input, module_name_input],
112
- upstreams=[copy_resource]
113
- )
114
- def create_app_config(*args: Any, **kwargs: Any):
115
- task: Task = kwargs.get('_task')
116
- project_dir = kwargs.get('project_dir', '.')
117
- app_name = kwargs.get('app_name')
118
- module_name = kwargs.get('module_name')
119
- kebab_app_name = util.to_kebab_case(app_name)
120
- snake_module_name = util.to_snake_case(module_name)
121
- upper_snake_module_name = snake_module_name.upper()
122
- config_file_path = os.path.join(
123
- project_dir, 'src', kebab_app_name, 'src', 'config.py'
248
+ async def append_all_disabled_env(
249
+ task: Task,
250
+ all_disabled_env_path: str,
251
+ upper_snake_module_name: str
252
+ ):
253
+ task.print_out(f'Add new environment to: {all_disabled_env_path}')
254
+ await append_text_file_async(
255
+ all_disabled_env_path,
256
+ f'APP_ENABLE_{upper_snake_module_name}_MODULE=false'
124
257
  )
258
+
259
+
260
+ async def create_app_config(
261
+ task: Task,
262
+ config_file_path: str,
263
+ snake_module_name: str,
264
+ upper_snake_module_name: str
265
+ ):
125
266
  config_code = '\n'.join([
126
267
  f'app_enable_{snake_module_name}_module = str_to_boolean(os.environ.get(', # noqa
127
268
  f" 'APP_{upper_snake_module_name}', 'true'"
128
269
  '))'
129
270
  ])
130
271
  task.print_out(f'Read config from: {config_file_path}')
131
- with open(config_file_path, 'r') as f:
132
- code = f.read()
272
+ code = await read_text_file_async(config_file_path)
133
273
  code += '\n' + config_code
134
274
  task.print_out(f'Write config to: {config_file_path}')
135
- with open(config_file_path, 'w') as f:
136
- f.write(code)
275
+ await write_text_file_async(config_file_path, code)
137
276
 
138
277
 
139
- @python_task(
140
- name='create-automation-config',
141
- inputs=[project_dir_input, app_name_input, module_name_input],
142
- upstreams=[copy_resource]
143
- )
144
- def create_automation_config(*args: Any, **kwargs: Any):
145
- task: Task = kwargs.get('_task')
146
- project_dir = kwargs.get('project_dir', '.')
147
- app_name = kwargs.get('app_name')
148
- module_name = kwargs.get('module_name')
149
- snake_app_name = util.to_snake_case(app_name)
150
- snake_module_name = util.to_snake_case(module_name)
151
- json_modules_file_path = os.path.join(
152
- project_dir, '_automate', snake_app_name, 'config', 'modules.json'
153
- )
278
+ async def create_automation_json_config(
279
+ task: Task,
280
+ json_modules_file_path: str,
281
+ snake_module_name: str,
282
+ ):
154
283
  task.print_out(f'Read json config from: {json_modules_file_path}')
155
- with open(json_modules_file_path, 'r') as f:
156
- json_str = f.read()
284
+ json_str = await read_text_file_async(json_modules_file_path)
157
285
  task.print_out(f'Add "{snake_module_name}" to json config')
158
286
  modules: List[str] = jsons.loads(json_str)
159
287
  modules.append(snake_module_name)
160
288
  json_str = jsons.dumps(modules)
161
289
  task.print_out(f'Write new json config to: {json_modules_file_path}')
162
- with open(json_modules_file_path, 'w') as f:
163
- f.write(json_str)
290
+ await write_text_file_async(json_modules_file_path, json_str)
291
+ return modules
164
292
 
165
293
 
166
- # TODO: add env to template.env
167
- # TODO: add env to module_enabled.env (use automation path)
168
- # TODO: add env to module_disabled.env (use automation path)
169
- # TODO: create service in docker compose
170
- # TODO: create runner for local microservices
294
+ async def register_module(
295
+ task: Task,
296
+ app_main_file_path: str,
297
+ snake_module_name: str
298
+ ):
299
+ import_module_path = '.'.join(['module', snake_module_name])
300
+ function_name = f'register_{snake_module_name}'
301
+ task.print_out(f'Read code from: {app_main_file_path}')
302
+ code = await read_text_file_async(app_main_file_path)
303
+ task.print_out(
304
+ f'Add import "{function_name}" from "{import_module_path}" to the code'
305
+ )
306
+ code = add_import_module(
307
+ code=code,
308
+ module_path=import_module_path,
309
+ resource=function_name
310
+ )
311
+ task.print_out(f'Add "{function_name}" call to the code')
312
+ code = add_function_call(
313
+ code=code,
314
+ function_name=function_name,
315
+ parameters=[]
316
+ )
317
+ task.print_out(f'Write modified code to: {app_main_file_path}')
318
+ await write_text_file_async(app_main_file_path, code)
171
319
 
172
320
 
173
- @python_task(
174
- name='fastapp-module',
175
- group=project_add_group,
176
- upstreams=[
177
- register_module,
178
- create_app_config,
179
- create_automation_config,
180
- ],
181
- runner=runner
182
- )
183
- async def add_fastapp_module(*args: Any, **kwargs: Any):
184
- task: Task = kwargs.get('_task')
185
- task.print_out('Success')
321
+ def get_docker_compose_file(project_dir: str, kebab_app_name: str):
322
+ return os.path.join(
323
+ project_dir, 'src', kebab_app_name, 'docker-compose.yml'
324
+ )
325
+
326
+
327
+ def get_app_main_file(project_dir: str, kebab_app_name: str):
328
+ return os.path.join(
329
+ project_dir, 'src', kebab_app_name, 'src', 'main.py'
330
+ )
331
+
332
+
333
+ def get_app_config_file(project_dir: str, kebab_app_name: str):
334
+ return os.path.join(
335
+ project_dir, 'src', kebab_app_name, 'src', 'config.py'
336
+ )
337
+
338
+
339
+ def get_json_modules_file(project_dir: str, snake_app_name: str):
340
+ return os.path.join(
341
+ project_dir, '_automate', snake_app_name, 'config', 'modules.json'
342
+ )
343
+
344
+
345
+ def get_compose_env_file(project_dir: str, snake_app_name: str):
346
+ return os.path.join(
347
+ project_dir, '_automate', snake_app_name, 'config',
348
+ 'docker-compose.env'
349
+ )
350
+
351
+
352
+ def get_src_template_env_file(project_dir: str, kebab_app_name: str):
353
+ return os.path.join(
354
+ project_dir, 'src', kebab_app_name, 'src', 'template.env'
355
+ )
356
+
357
+
358
+ def get_all_enabled_env_file(project_dir: str, kebab_app_name: str):
359
+ return os.path.join(
360
+ project_dir, 'src', kebab_app_name, 'all-module-enabled.env'
361
+ )
362
+
363
+
364
+ def get_all_disabled_env_file(project_dir: str, kebab_app_name: str):
365
+ return os.path.join(
366
+ project_dir, 'src', kebab_app_name, 'all-module-disabled.env'
367
+ )
368
+
@@ -33,8 +33,7 @@ pip freeze
33
33
  pip freeze | grep dbt
34
34
  ```
35
35
 
36
-
37
- # How to Start PascalProjectName
36
+ # Activating PascalProjectName
38
37
 
39
38
  ```bash
40
39
  source ./project.sh
@@ -58,4 +57,21 @@ To reload your configurations, you can invoke the following command:
58
57
  reload
59
58
  ```
60
59
 
61
- Please note that PascalProjectName's virtual environment has to be activated first.
60
+ Please note that PascalProjectName's virtual environment has to be activated first.
61
+
62
+ # Getting task environments
63
+
64
+ To get task environments, you can invoke the following command:
65
+
66
+ ```bash
67
+ zrb project get-default-env
68
+ ```
69
+
70
+ It is expected to use the command for informational purposes only.
71
+ You should only override necessary environment variables to keep track of what you need to change.
72
+
73
+ Being said so, you can also add the default task environments to `.env` by invoking the following command:
74
+
75
+ ```bash
76
+ zrb project get-default-env >> .env
77
+ ```
@@ -1,29 +1,28 @@
1
1
  from ....helper.file.copy_tree import copy_tree
2
2
  from ....helper.codemod.add_assert_resource import add_assert_resource
3
3
  from ....helper.codemod.add_import_module import add_import_module
4
+ from ....helper.file.text import read_text_file_async, write_text_file_async
4
5
 
5
6
  import os
6
7
 
7
8
  current_dir = os.path.dirname(__file__)
8
9
 
9
10
 
10
- def add_project_automation(project_dir: str):
11
+ async def add_project_automation(project_dir: str):
11
12
  if os.path.exists(os.path.join(project_dir, '_automate', '_project')):
12
13
  return
13
- copy_tree(
14
+ await copy_tree(
14
15
  src=os.path.join(current_dir, 'template'),
15
16
  dst=project_dir
16
17
  )
17
18
  project_task_module_path = '_automate._project'
18
19
  zrb_init_path = os.path.join(project_dir, 'zrb_init.py')
19
- with open(zrb_init_path, 'r') as f:
20
- code = f.read()
21
- import_alias = project_task_module_path.split('.')[-1]
22
- code = add_import_module(
23
- code=code,
24
- module_path=project_task_module_path,
25
- alias=import_alias
26
- )
27
- code = add_assert_resource(code, import_alias)
28
- with open(zrb_init_path, 'w') as f:
29
- f.write(code)
20
+ code = await read_text_file_async(zrb_init_path)
21
+ import_alias = project_task_module_path.split('.')[-1]
22
+ code = add_import_module(
23
+ code=code,
24
+ module_path=project_task_module_path,
25
+ alias=import_alias
26
+ )
27
+ code = add_assert_resource(code, import_alias)
28
+ await write_text_file_async(zrb_init_path, code)
@@ -5,6 +5,7 @@ from ....task.task import Task
5
5
  from ....helper import util
6
6
  from ....helper.codemod.add_import_module import add_import_module
7
7
  from ....helper.codemod.add_upstream_to_task import add_upstream_to_task
8
+ from ....helper.file.text import read_text_file_async, write_text_file_async
8
9
  from .add import add_project_automation
9
10
  from .task_factory_helper import (
10
11
  _get_app_local_task_file, _get_app_container_task_file,
@@ -29,7 +30,7 @@ def create_add_project_automation(
29
30
  task: Task = kwargs.get('_task')
30
31
  project_dir = kwargs.get('project_dir', '.')
31
32
  task.print_out('Create project automation modules if not exist')
32
- add_project_automation(project_dir)
33
+ await add_project_automation(project_dir)
33
34
  return _task
34
35
 
35
36
 
@@ -184,17 +185,14 @@ def _create_register_app_task(
184
185
  # turn into module path
185
186
  upstream_module_path = '.'.join(upstream_module_parts)
186
187
  task.print_out(f'Add {upstream_task_var} to project automation')
187
- with open(project_automation_path, 'r') as f:
188
- code = f.read()
189
- code = add_import_module(
190
- code=code,
191
- module_path=upstream_module_path,
192
- resource=upstream_task_var
193
- )
194
- code = add_upstream_to_task(
195
- code, project_automation_task_name, upstream_task_var
196
- )
197
- with open(project_automation_path, 'w') as f:
198
- f.write(code)
199
-
188
+ code = await read_text_file_async(project_automation_path)
189
+ code = add_import_module(
190
+ code=code,
191
+ module_path=upstream_module_path,
192
+ resource=upstream_task_var
193
+ )
194
+ code = add_upstream_to_task(
195
+ code, project_automation_task_name, upstream_task_var
196
+ )
197
+ await write_text_file_async(project_automation_path, code)
200
198
  return _task
@@ -66,15 +66,15 @@ register_local_app_module = create_register_local_app_module(
66
66
  )
67
67
 
68
68
  register_container_app_module = create_register_container_app_module(
69
- upstreams=[copy_resource]
69
+ upstreams=[register_local_app_module]
70
70
  )
71
71
 
72
72
  register_image_app_module = create_register_image_app_module(
73
- upstreams=[copy_resource]
73
+ upstreams=[register_container_app_module]
74
74
  )
75
75
 
76
76
  register_deployment_app_module = create_register_deployment_app_module(
77
- upstreams=[copy_resource]
77
+ upstreams=[register_image_app_module]
78
78
  )
79
79
 
80
80
  add_project_task = create_add_project_automation(
@@ -9,4 +9,10 @@ services:
9
9
  environment:
10
10
  APP_PORT: ${APP_PORT:-8080}
11
11
  ports:
12
- - "${HOST_PORT:-8080}:${APP_PORT:-8080}"
12
+ - "${HOST_PORT:-8080}:${APP_PORT:-8080}"
13
+ restart: on-failure
14
+ healthcheck:
15
+ test: ["CMD-SHELL", "curl --fail http://localhost:${APP_PORT:-8080}/ || exit 1"]
16
+ interval: 5s
17
+ timeout: 1s
18
+ retries: 30
@@ -1,5 +1,7 @@
1
1
  FROM python:3.10-slim
2
+ ENV APP_MESSAGE "Hello, world!"
3
+ ENV APP_PORT 8080
2
4
  WORKDIR /home
3
5
  COPY . .
4
6
  RUN pip install -r requirements.txt
5
- CMD python main.py
7
+ CMD uvicorn main:app --host "0.0.0.0" --port "$APP_PORT"
@@ -1,4 +1,3 @@
1
- import uvicorn
2
1
  import os
3
2
 
4
3
  MESSAGE = os.getenv('APP_MESSAGE', 'Hello, world!')
@@ -19,7 +18,3 @@ async def app(scope, receive, send):
19
18
  'type': 'http.response.body',
20
19
  'body': bytes(MESSAGE, 'utf-8'),
21
20
  })
22
-
23
-
24
- if __name__ == "__main__":
25
- uvicorn.run("main:app", host='0.0.0.0', port=PORT, log_level="info")
zrb/builtin/md5.py CHANGED
@@ -4,6 +4,7 @@ from ..task.decorator import python_task
4
4
  from ..task_input.str_input import StrInput
5
5
  from ..runner import runner
6
6
 
7
+ import aiofiles
7
8
  import hashlib
8
9
 
9
10
  # Common definitions
@@ -47,7 +48,7 @@ async def hash_text(*args: str, **kwargs: Any):
47
48
  )
48
49
  async def sum_file(*args: str, **kwargs: Any):
49
50
  file_path: str = kwargs.get('file', '')
50
- with open(file_path, "rb") as f:
51
- contents = f.read()
52
- hashed_text = hashlib.md5(contents).hexdigest()
53
- return hashed_text
51
+ async with aiofiles.open(file_path, mode='rb') as file:
52
+ contents = await file.read()
53
+ hashed_text = hashlib.md5(contents).hexdigest()
54
+ return hashed_text
zrb/builtin/project.py ADDED
@@ -0,0 +1,32 @@
1
+ from typing import Any, Mapping
2
+ from ._group import project_group
3
+ from ..task.decorator import python_task
4
+ from ..task_input.bool_input import BoolInput
5
+ from ..runner import runner
6
+ from ..helper.env_map.fetch import fetch_env_map_from_group
7
+
8
+
9
+ @python_task(
10
+ name='get-default-env',
11
+ description='Get default values for project environments',
12
+ inputs=[
13
+ BoolInput(
14
+ name='export',
15
+ shortcut='e',
16
+ description='Whether add export statement or not',
17
+ default=True
18
+ )
19
+ ],
20
+ group=project_group,
21
+ runner=runner
22
+ )
23
+ async def get_default_env(*args: Any, **kwargs: Any) -> str:
24
+ env_map: Mapping[str, str] = {}
25
+ env_map = fetch_env_map_from_group(env_map, project_group)
26
+ env_keys = list(env_map.keys())
27
+ env_keys.sort()
28
+ should_export = kwargs.get('export', True)
29
+ export_prefix = 'export ' if should_export else ''
30
+ return '\n'.join([
31
+ f'{export_prefix}{key}={env_map[key]}' for key in env_keys
32
+ ])
@@ -0,0 +1,22 @@
1
+ from typing import Any, Mapping
2
+ from ruamel.yaml import YAML, composer, CommentedMap
3
+
4
+
5
+ def read_compose_file(file_name: str) -> Any:
6
+ yaml = YAML()
7
+ with open(file_name, 'r') as file:
8
+ data = yaml.load(file)
9
+ return data
10
+
11
+
12
+ def add_services(file_name: str, new_services: Mapping[str, str]):
13
+ yaml = YAML()
14
+ with open(file_name, 'r') as f:
15
+ data = yaml.load(f)
16
+ # data = round_trip_load(f, preserve_quotes=True)
17
+ data = CommentedMap(data)
18
+ data['services'].update(CommentedMap(new_services))
19
+ # Write the modified data structure back to the file
20
+ with open(file_name, 'w') as f:
21
+ yaml.dump(data, f)
22
+ # round_trip_dump(data, f)