|
|
|
import os |
|
import re |
|
import sys |
|
|
|
|
|
def parse_env_example(file_path): |
|
""" |
|
Parses the .env.example file and returns a dictionary with variable names as keys and default values as values. |
|
""" |
|
env_vars = {} |
|
with open(file_path, "r") as f: |
|
for line_number, line in enumerate(f, 1): |
|
line = line.strip() |
|
|
|
if not line or line.startswith("#"): |
|
continue |
|
|
|
match = re.match(r"^([^=]+)=(.*)$", line) |
|
if match: |
|
key = match.group(1).strip() |
|
value = match.group(2).strip() |
|
|
|
if (value.startswith('"') and value.endswith('"')) or ( |
|
value.startswith("'") and value.endswith("'") |
|
): |
|
value = value[1:-1] |
|
env_vars[key] = value |
|
else: |
|
print(f"Warning: Unable to parse line {line_number}: {line}") |
|
return env_vars |
|
|
|
|
|
def generate_shared_env_block(env_vars, anchor_name="shared-api-worker-env"): |
|
""" |
|
Generates a shared environment variables block as a YAML string. |
|
""" |
|
lines = [f"x-shared-env: &{anchor_name}"] |
|
for key, default in env_vars.items(): |
|
if key == "COMPOSE_PROFILES": |
|
continue |
|
|
|
if default == "": |
|
lines.append(f" {key}: ${{{key}:-}}") |
|
else: |
|
|
|
if re.search(r"[:\s]", default): |
|
default = f"{default}" |
|
lines.append(f" {key}: ${{{key}:-{default}}}") |
|
return "\n".join(lines) |
|
|
|
|
|
def insert_shared_env(template_path, output_path, shared_env_block, header_comments): |
|
""" |
|
Inserts the shared environment variables block and header comments into the template file, |
|
removing any existing x-shared-env anchors, and generates the final docker-compose.yaml file. |
|
""" |
|
with open(template_path, "r") as f: |
|
template_content = f.read() |
|
|
|
|
|
template_content = re.sub( |
|
r"^x-shared-env: &shared-api-worker-env\s*\n?", |
|
"", |
|
template_content, |
|
flags=re.MULTILINE, |
|
) |
|
|
|
|
|
final_content = f"{header_comments}\n{shared_env_block}\n\n{template_content}" |
|
|
|
with open(output_path, "w") as f: |
|
f.write(final_content) |
|
print(f"Generated {output_path}") |
|
|
|
|
|
def main(): |
|
env_example_path = ".env.example" |
|
template_path = "docker-compose-template.yaml" |
|
output_path = "docker-compose.yaml" |
|
anchor_name = "shared-api-worker-env" |
|
|
|
|
|
header_comments = ( |
|
"# ==================================================================\n" |
|
"# WARNING: This file is auto-generated by generate_docker_compose\n" |
|
"# Do not modify this file directly. Instead, update the .env.example\n" |
|
"# or docker-compose-template.yaml and regenerate this file.\n" |
|
"# ==================================================================\n" |
|
) |
|
|
|
|
|
for path in [env_example_path, template_path]: |
|
if not os.path.isfile(path): |
|
print(f"Error: File {path} does not exist.") |
|
sys.exit(1) |
|
|
|
|
|
env_vars = parse_env_example(env_example_path) |
|
|
|
if not env_vars: |
|
print("Warning: No environment variables found in .env.example.") |
|
|
|
|
|
shared_env_block = generate_shared_env_block(env_vars, anchor_name) |
|
|
|
|
|
insert_shared_env(template_path, output_path, shared_env_block, header_comments) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|