zrb 0.0.46__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 (42) hide show
  1. zrb/action/runner.py +1 -1
  2. zrb/builtin/generator/_common.py +7 -8
  3. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/docker-compose.yml +7 -1
  4. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/image/Dockerfile +3 -1
  5. zrb/builtin/generator/docker_compose_task/template/src/kebab-task-name/image/main.py +0 -5
  6. zrb/builtin/generator/fastapp/add.py +3 -3
  7. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/_common.py +11 -7
  8. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/config/docker-compose.env +3 -0
  9. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/container.py +4 -2
  10. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/image.py +1 -1
  11. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/local.py +1 -2
  12. zrb/builtin/generator/fastapp/template/src/kebab-app-name/docker-compose.yml +19 -6
  13. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/template.env +1 -1
  14. zrb/builtin/generator/fastapp_module/add.py +259 -106
  15. zrb/builtin/generator/project_task/add.py +5 -6
  16. zrb/builtin/generator/project_task/task_factory.py +4 -6
  17. zrb/builtin/generator/simple_python_app/add.py +3 -3
  18. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/docker-compose.yml +7 -1
  19. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/src/Dockerfile +3 -1
  20. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/src/main.py +0 -5
  21. zrb/builtin/md5.py +3 -2
  22. zrb/builtin/project.py +2 -60
  23. zrb/helper/docker_compose/file.py +22 -0
  24. zrb/helper/env_map/__init__.py +0 -0
  25. zrb/helper/env_map/fetch.py +68 -0
  26. zrb/helper/file/copy_tree.py +6 -7
  27. zrb/helper/file/text.py +12 -4
  28. zrb/task/base_task.py +10 -10
  29. zrb/task/docker_compose_task.py +2 -2
  30. zrb/task/installer/factory.py +6 -5
  31. zrb/task/path_checker.py +2 -2
  32. zrb/task/resource_maker.py +1 -1
  33. zrb/task_env/env.py +4 -3
  34. {zrb-0.0.46.dist-info → zrb-0.0.47.dist-info}/METADATA +1 -1
  35. {zrb-0.0.46.dist-info → zrb-0.0.47.dist-info}/RECORD +41 -38
  36. zrb/helper/dockercompose/read.py +0 -9
  37. /zrb/builtin/generator/fastapp/template/src/kebab-app-name/{src/module_disabled.env → all-module-disabled.env} +0 -0
  38. /zrb/builtin/generator/fastapp/template/src/kebab-app-name/{src/module_enabled.env → all-module-enabled.env} +0 -0
  39. /zrb/helper/{dockercompose → docker_compose}/fetch_external_env.py +0 -0
  40. {zrb-0.0.46.dist-info → zrb-0.0.47.dist-info}/LICENSE +0 -0
  41. {zrb-0.0.46.dist-info → zrb-0.0.47.dist-info}/WHEEL +0 -0
  42. {zrb-0.0.46.dist-info → zrb-0.0.47.dist-info}/entry_points.txt +0 -0
@@ -13,12 +13,15 @@ from .._common import (
13
13
  from ....helper import util
14
14
  from ....helper.codemod.add_import_module import add_import_module
15
15
  from ....helper.codemod.add_function_call import add_function_call
16
- from ....helper.file.text import read_text_file, write_text_file
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
+ )
17
20
 
21
+ import asyncio
18
22
  import os
19
23
  import jsons
20
24
 
21
-
22
25
  current_dir = os.path.dirname(__file__)
23
26
 
24
27
 
@@ -68,148 +71,298 @@ copy_resource = ResourceMaker(
68
71
 
69
72
 
70
73
  @python_task(
71
- name='register-module',
72
- inputs=[project_dir_input, app_name_input, module_name_input],
73
- upstreams=[copy_resource]
74
+ name='fastapp-module',
75
+ group=project_add_group,
76
+ upstreams=[copy_resource],
77
+ runner=runner
74
78
  )
75
- async def register_module(*args: Any, **kwargs: Any):
79
+ async def add_fastapp_module(*args: Any, **kwargs: Any):
76
80
  task: Task = kwargs.get('_task')
77
81
  project_dir = kwargs.get('project_dir', '.')
78
82
  app_name = kwargs.get('app_name')
79
83
  module_name = kwargs.get('module_name')
80
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)
81
87
  snake_module_name = util.to_snake_case(module_name)
82
- import_module_path = '.'.join([
83
- '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
+ )),
84
111
  ])
85
- function_name = f'register_{snake_module_name}'
86
- main_file_path = os.path.join(
87
- 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
88
116
  )
89
- task.print_out(f'Read code from: {main_file_path}')
90
- code = await read_text_file(main_file_path)
91
- task.print_out(
92
- 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
93
122
  )
94
- code = add_import_module(
95
- code=code,
96
- module_path=import_module_path,
97
- 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
+ }
98
206
  )
99
- task.print_out(f'Add "{function_name}" call to the code')
100
- code = add_function_call(
101
- code=code,
102
- function_name=function_name,
103
- 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'
104
245
  )
105
- task.print_out(f'Write modified code to: {main_file_path}')
106
- await write_text_file(main_file_path, 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
- async 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
- code = await read_text_file(config_file_path)
272
+ code = await read_text_file_async(config_file_path)
132
273
  code += '\n' + config_code
133
274
  task.print_out(f'Write config to: {config_file_path}')
134
- await write_text_file(config_file_path, code)
275
+ await write_text_file_async(config_file_path, code)
135
276
 
136
277
 
137
- @python_task(
138
- name='create-automation-config',
139
- inputs=[project_dir_input, app_name_input, module_name_input],
140
- upstreams=[copy_resource]
141
- )
142
- async def create_automation_config(*args: Any, **kwargs: Any):
143
- task: Task = kwargs.get('_task')
144
- project_dir = kwargs.get('project_dir', '.')
145
- app_name = kwargs.get('app_name')
146
- module_name = kwargs.get('module_name')
147
- snake_app_name = util.to_snake_case(app_name)
148
- snake_module_name = util.to_snake_case(module_name)
149
- json_modules_file_path = os.path.join(
150
- project_dir, '_automate', snake_app_name, 'config', 'modules.json'
151
- )
278
+ async def create_automation_json_config(
279
+ task: Task,
280
+ json_modules_file_path: str,
281
+ snake_module_name: str,
282
+ ):
152
283
  task.print_out(f'Read json config from: {json_modules_file_path}')
153
- json_str = await read_text_file(json_modules_file_path)
284
+ json_str = await read_text_file_async(json_modules_file_path)
154
285
  task.print_out(f'Add "{snake_module_name}" to json config')
155
286
  modules: List[str] = jsons.loads(json_str)
156
287
  modules.append(snake_module_name)
157
288
  json_str = jsons.dumps(modules)
158
289
  task.print_out(f'Write new json config to: {json_modules_file_path}')
159
- await write_text_file(json_modules_file_path, json_str)
290
+ await write_text_file_async(json_modules_file_path, json_str)
291
+ return modules
160
292
 
161
293
 
162
- @python_task(
163
- name='append-template-env',
164
- inputs=[project_dir_input, app_name_input, module_name_input],
165
- upstreams=[create_automation_config]
166
- )
167
- async def append_template_env(*args: Any, **kwargs: Any):
168
- task: Task = kwargs.get('_task')
169
- project_dir = kwargs.get('project_dir', '.')
170
- app_name = kwargs.get('app_name')
171
- module_name = kwargs.get('module_name')
172
- kebab_app_name = util.to_kebab_case(app_name)
173
- snake_app_name = util.to_snake_case(app_name)
174
- snake_module_name = util.to_snake_case(module_name)
175
- upper_snake_module_name = snake_module_name.upper()
176
- json_modules_file_path = os.path.join(
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)
319
+
320
+
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(
177
341
  project_dir, '_automate', snake_app_name, 'config', 'modules.json'
178
342
  )
179
- template_env_path = os.path.join(
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(
180
354
  project_dir, 'src', kebab_app_name, 'src', 'template.env'
181
355
  )
182
- template_env_map = dotenv_values(template_env_path)
183
- app_port = int(template_env_map.get('APP_PORT', '8080'))
184
- task.print_out(f'Read json config from: {json_modules_file_path}')
185
- json_str = await read_text_file(json_modules_file_path)
186
- modules: List[str] = jsons.loads(json_str)
187
- module_app_port = app_port + len(modules)
188
- template_env_str = await read_text_file(template_env_path)
189
- template_env_str += '\n' + '\n'.join([
190
- f'APP_ENABLE_{upper_snake_module_name}_MODULE=true',
191
- f'APP_{upper_snake_module_name}_MODULE_PORT={module_app_port}',
192
- ])
193
- await write_text_file(template_env_path, template_env_str)
194
356
 
195
357
 
196
- # TODO: add env to module_enabled.env <-- use the ones in src, because of docker-compose
197
- # TODO: add env to module_disabled.env
198
- # TODO: create service in docker compose
199
- # TODO: create runner for local microservices
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
+ )
200
362
 
201
363
 
202
- @python_task(
203
- name='fastapp-module',
204
- group=project_add_group,
205
- upstreams=[
206
- register_module,
207
- create_app_config,
208
- create_automation_config,
209
- append_template_env,
210
- ],
211
- runner=runner
212
- )
213
- async def add_fastapp_module(*args: Any, **kwargs: Any):
214
- task: Task = kwargs.get('_task')
215
- task.print_out('Success')
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
+
@@ -1,23 +1,23 @@
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()
20
+ code = await read_text_file_async(zrb_init_path)
21
21
  import_alias = project_task_module_path.split('.')[-1]
22
22
  code = add_import_module(
23
23
  code=code,
@@ -25,5 +25,4 @@ def add_project_automation(project_dir: str):
25
25
  alias=import_alias
26
26
  )
27
27
  code = add_assert_resource(code, import_alias)
28
- with open(zrb_init_path, 'w') as f:
29
- f.write(code)
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,8 +185,7 @@ 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()
188
+ code = await read_text_file_async(project_automation_path)
189
189
  code = add_import_module(
190
190
  code=code,
191
191
  module_path=upstream_module_path,
@@ -194,7 +194,5 @@ def _create_register_app_task(
194
194
  code = add_upstream_to_task(
195
195
  code, project_automation_task_name, upstream_task_var
196
196
  )
197
- with open(project_automation_path, 'w') as f:
198
- f.write(code)
199
-
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()
51
+ async with aiofiles.open(file_path, mode='rb') as file:
52
+ contents = await file.read()
52
53
  hashed_text = hashlib.md5(contents).hexdigest()
53
54
  return hashed_text
zrb/builtin/project.py CHANGED
@@ -1,11 +1,9 @@
1
- from typing import Any, List, Mapping
1
+ from typing import Any, Mapping
2
2
  from ._group import project_group
3
3
  from ..task.decorator import python_task
4
- from ..task.base_task import Group, BaseTask
5
- from ..task_env.env import Env
6
4
  from ..task_input.bool_input import BoolInput
7
5
  from ..runner import runner
8
- from ..helper.string.jinja import is_probably_jinja
6
+ from ..helper.env_map.fetch import fetch_env_map_from_group
9
7
 
10
8
 
11
9
  @python_task(
@@ -32,59 +30,3 @@ async def get_default_env(*args: Any, **kwargs: Any) -> str:
32
30
  return '\n'.join([
33
31
  f'{export_prefix}{key}={env_map[key]}' for key in env_keys
34
32
  ])
35
-
36
-
37
- def fetch_env_map_from_group(
38
- env_map: Mapping[str, str], group: Group
39
- ) -> Mapping[str, str]:
40
- for task in group.tasks:
41
- env_map = fetch_env_map_from_task(env_map, task)
42
- for sub_group in group.children:
43
- sub_env_map: Mapping[str, str] = fetch_env_map_from_group(
44
- env_map, sub_group
45
- )
46
- env_map = cascade_env_map(env_map, sub_env_map)
47
- return env_map
48
-
49
-
50
- def fetch_env_map_from_task(
51
- env_map: Mapping[str, str], task: BaseTask
52
- ):
53
- task_env_map: Mapping[str, str] = {}
54
- for env_file in task.env_files:
55
- envs = env_file.get_envs()
56
- task_env_map = add_envs_to_env_map(task_env_map, envs)
57
- task_env_map = add_envs_to_env_map(task_env_map, task.envs)
58
- env_map = cascade_env_map(env_map, task_env_map)
59
- for upstream in task.upstreams:
60
- task_env_map = fetch_env_map_from_task(env_map, upstream)
61
- for checker in task.checkers:
62
- task_env_map = fetch_env_map_from_task(env_map, checker)
63
- return env_map
64
-
65
-
66
- def add_envs_to_env_map(
67
- env_map: Mapping[str, str], envs: List[Env]
68
- ) -> Mapping[str, str]:
69
- for env in envs:
70
- if (
71
- env.os_name == '' or
72
- env.default == '' or
73
- is_probably_jinja(env.default)
74
- ):
75
- if env.name.startswith('FASTAPP'):
76
- print(env)
77
- continue
78
- env_map[env.os_name] = env.default
79
- return env_map
80
-
81
-
82
- def cascade_env_map(
83
- env_map: Mapping[str, str],
84
- other_env_map: Mapping[str, str]
85
- ) -> Mapping[str, str]:
86
- for key, value in other_env_map.items():
87
- if key in env_map:
88
- continue
89
- env_map[key] = value
90
- return env_map
@@ -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)
File without changes