-
Notifications
You must be signed in to change notification settings - Fork 435
/
Copy pathmerge_env.py
135 lines (108 loc) · 4 KB
/
merge_env.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#
# Usage:
# python merge_env.py [--dry-run] base_env_path target_env_path
#
# e.g.
# Dry run:
# python merge_env.py --dry-run sample.env .env
# Actual run:
# python merge_env.py sample.env .env
#
import sys
PREFERRED_BASE_ENV_KEYS = [
"STRUCTURE_TOOL_IMAGE_URL",
"STRUCTURE_TOOL_IMAGE_TAG",
]
DEFAULT_AUTH_KEY = "unstract"
DEFAULT_ADMIN_KEY = "admin"
SET_DEFAULT_KEYS = {
"DEFAULT_AUTH_USERNAME": DEFAULT_AUTH_KEY,
"DEFAULT_AUTH_PASSWORD": DEFAULT_AUTH_KEY,
"SYSTEM_ADMIN_USERNAME": DEFAULT_ADMIN_KEY,
"SYSTEM_ADMIN_PASSWORD": DEFAULT_ADMIN_KEY,
}
def _extract_kv_from_line(line: str) -> tuple[str, str]:
parts = line.split("=", 1)
if len(parts) != 2:
raise ValueError(f"{line}")
key, value = parts
key = key.strip()
value = value.strip()
return key, value
def _extract_from_env_file(file_path: str) -> dict[str, str]:
env = {}
with open(file_path) as file:
for line in file:
if not line.strip() or line.startswith("#"):
continue
key, value = _extract_kv_from_line(line)
env[key.strip()] = value.strip()
return env
def _merge_to_env_file(base_env_file_path: str, target_env: dict[str, str] = {}) -> str:
"""Generates file contents after merging input base env file path with
target env.
Args:
base_env_file_path (string): Base env file path e.g. `sample.env`
target_env (dict, optional): Target env to use for merge e.g. `.env`
Returns:
string: File contents after merge.
"""
merged_contents = []
with open(base_env_file_path) as file:
for line in file:
# Preserve location of empty lines and comments
# for easy diff.
if not line.strip() or line.startswith("#"):
merged_contents.append(line)
continue
key, value = _extract_kv_from_line(line)
# Preserve following keys at base env file path:
# - preferred keys
# - newly added keys
# Everything else, take existing configured values
# from target env.
if key not in PREFERRED_BASE_ENV_KEYS and key in target_env:
value = target_env.get(key, value)
# Set default value for these keys always.
if not value and key in SET_DEFAULT_KEYS:
value = SET_DEFAULT_KEYS[key]
merged_contents.append(f"{key}={value}\n")
# Allow extras from target_env which is not present in base_env
base_env = _extract_from_env_file(base_env_file_path)
additional_env_header_added = False
for key in target_env:
if key not in base_env:
if not additional_env_header_added:
additional_env_header_added = True
merged_contents.append("\n\n# Additional envs\n")
merged_contents.append(f"{key}={target_env.get(key)}\n")
return "".join(merged_contents)
def _save_merged_contents(
file_path: str, file_contents: str, dry_run: bool = False
) -> None:
if dry_run:
print(f"===== merged:{file_path} =====")
print(file_contents)
print("-----------")
else:
with open(file_path, "w") as file:
file.write(file_contents)
def merge_env(
base_env_file_path: str, target_env_file_path: str, dry_run: bool = False
) -> None:
target_env = _extract_from_env_file(target_env_file_path)
merged_contents = _merge_to_env_file(base_env_file_path, target_env=target_env)
_save_merged_contents(target_env_file_path, merged_contents, dry_run=dry_run)
if __name__ == "__main__":
try:
if len(sys.argv) == 4:
dry_run = True if sys.argv[1] == "--dry-run" else False
merge_env(sys.argv[2], sys.argv[3], dry_run=dry_run)
else:
merge_env(sys.argv[1], sys.argv[2])
except IndexError:
print(f"Invalid env paths for merge: {sys.argv}")
sys.exit(1)
except ValueError as e:
print(f"Malformed env config: {str(e)}")
sys.exit(1)