recipe-maintainer: public snapshot (secrets + deployment plans removed, single commit)
Sanitized single-commit public mirror of recipe-maintainer. - Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders. - Removed plans/ and planned-updates/ (deployment-planning docs) so no client/ deployment domains appear in the public repo. - All other secret stores were already gitignored. - docs.coopcloud.tech retained as a submodule (public upstream).
This commit is contained in:
83
lib/env.py
Normal file
83
lib/env.py
Normal file
@ -0,0 +1,83 @@
|
||||
"""Read and write abra .env files and recipe-info config files.
|
||||
|
||||
Handles the specific format of abra .env files: KEY=VALUE lines,
|
||||
with support for comments (#) and uncommenting keys.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def read_env_file(path: str | Path) -> dict[str, str]:
|
||||
"""Read a KEY=VALUE env file into a dict.
|
||||
|
||||
Ignores empty lines and comments (#).
|
||||
"""
|
||||
result = {}
|
||||
p = Path(path)
|
||||
if not p.exists():
|
||||
return result
|
||||
with open(p) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" in line:
|
||||
key, value = line.split("=", 1)
|
||||
result[key.strip()] = value.strip()
|
||||
return result
|
||||
|
||||
|
||||
def write_env_file(path: str | Path, data: dict[str, str]) -> None:
|
||||
"""Write a dict as a KEY=VALUE env file."""
|
||||
p = Path(path)
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(p, "w") as f:
|
||||
for key, value in data.items():
|
||||
f.write(f"{key}={value}\n")
|
||||
|
||||
|
||||
def apply_env_overrides(env_path: str | Path,
|
||||
overrides: dict[str, str]) -> None:
|
||||
"""Set or uncomment values in an abra .env file.
|
||||
|
||||
For each key in overrides:
|
||||
- If the key exists (even commented out), replace the line
|
||||
- If the key doesn't exist, append it
|
||||
"""
|
||||
p = Path(env_path)
|
||||
if not p.exists():
|
||||
write_env_file(p, overrides)
|
||||
return
|
||||
|
||||
with open(p) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
remaining = dict(overrides)
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
matched = False
|
||||
for key, value in list(remaining.items()):
|
||||
# Match "KEY=...", "#KEY=...", or "# KEY=..."
|
||||
if stripped.lstrip("#").strip().startswith(f"{key}="):
|
||||
new_lines.append(f"{key}={value}\n")
|
||||
remaining.pop(key)
|
||||
matched = True
|
||||
print(f" env: {key}={value}", flush=True)
|
||||
break
|
||||
if not matched:
|
||||
new_lines.append(line)
|
||||
|
||||
# Append any keys that weren't found in the file
|
||||
for key, value in remaining.items():
|
||||
new_lines.append(f"{key}={value}\n")
|
||||
print(f" env: {key}={value} (appended)", flush=True)
|
||||
|
||||
with open(p, "w") as f:
|
||||
f.writelines(new_lines)
|
||||
|
||||
|
||||
def get_abra_env_path(server: str, domain: str) -> Path:
|
||||
"""Return the path to an abra app's .env file."""
|
||||
from lib.config import paths
|
||||
return paths.ABRA_SERVERS_DIR / server / f"{domain}.env"
|
||||
Reference in New Issue
Block a user