Skip to content

Commit f5117a6

Browse files
authored
Yaml Editor (#736)
* Yaml Editor Created yaml editor to help with creating/updating override files * Update ye * Update ye
1 parent 48dc9cc commit f5117a6

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

yaml-editor/requirments.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dictdiffer

yaml-editor/ye

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import sys
4+
import subprocess
5+
import tempfile
6+
import yaml
7+
import copy
8+
9+
10+
def load_yaml_file(filename):
11+
try:
12+
with open(filename, "r") as f:
13+
data = yaml.safe_load(f)
14+
return data if data is not None else {}
15+
except FileNotFoundError:
16+
return {}
17+
18+
19+
def save_yaml_file(data, filename):
20+
with open(filename, "w") as f:
21+
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False)
22+
23+
24+
def merge_dicts(base, overrides):
25+
result = copy.deepcopy(base)
26+
for key, override_value in overrides.items():
27+
if (
28+
key in result
29+
and isinstance(result[key], dict)
30+
and isinstance(override_value, dict)
31+
):
32+
result[key] = merge_dicts(result[key], override_value)
33+
else:
34+
result[key] = override_value
35+
return result
36+
37+
38+
def launch_editor(initial_content):
39+
editor = os.environ.get("EDITOR", "vim")
40+
with tempfile.NamedTemporaryFile(suffix=".yaml", mode="w+", delete=False) as tf:
41+
temp_filename = tf.name
42+
tf.write(initial_content)
43+
tf.flush()
44+
45+
subprocess.call([editor, temp_filename])
46+
47+
with open(temp_filename, "r") as tf:
48+
edited_content = tf.read()
49+
50+
os.unlink(temp_filename)
51+
return edited_content
52+
53+
54+
def compute_patch(base, edited):
55+
patch = {}
56+
for key, edited_value in edited.items():
57+
if key not in base:
58+
patch[key] = edited_value
59+
else:
60+
base_value = base[key]
61+
if isinstance(base_value, dict) and isinstance(edited_value, dict):
62+
sub_patch = compute_patch(base_value, edited_value)
63+
if sub_patch: # Only include non-empty patches.
64+
patch[key] = sub_patch
65+
else:
66+
if edited_value != base_value:
67+
patch[key] = edited_value
68+
return patch
69+
70+
71+
def main():
72+
if len(sys.argv) != 3:
73+
print("Usage: {} <base_yaml_file> <override_yaml_file>".format(sys.argv[0]))
74+
print(
75+
"ye - (YamlEditor) will launch an editor to edit the values in base_yaml_file. If the override_yaml_file exists, "
76+
"it will read its values in and will overlay the valies on top of base."
77+
"After editing, the edited values will be saved to override_yaml_file and base will remain the same."
78+
)
79+
sys.exit(1)
80+
81+
base_filename = sys.argv[1]
82+
override_filename = sys.argv[2]
83+
base_data = load_yaml_file(base_filename)
84+
if not base_data:
85+
print(f"Error: Base file '{base_filename}' not found or is empty.")
86+
sys.exit(1)
87+
88+
previous_overrides = load_yaml_file(override_filename)
89+
if not isinstance(previous_overrides, dict):
90+
previous_overrides = {}
91+
effective_data = merge_dicts(base_data, previous_overrides)
92+
initial_yaml_str = yaml.safe_dump(
93+
effective_data, default_flow_style=False, sort_keys=False
94+
)
95+
print("Launching editor. Modify values as needed, then save and exit.")
96+
edited_yaml_str = launch_editor(initial_yaml_str)
97+
try:
98+
edited_data = yaml.safe_load(edited_yaml_str)
99+
if edited_data is None:
100+
edited_data = {}
101+
except yaml.YAMLError as e:
102+
print("Error parsing YAML from editor:", e)
103+
sys.exit(1)
104+
patch = compute_patch(base_data, edited_data)
105+
print("Computed patch (overrides):")
106+
print(yaml.safe_dump(patch, default_flow_style=False, sort_keys=False))
107+
save_yaml_file(patch, override_filename)
108+
print(f"Overrides saved to '{override_filename}'.")
109+
110+
111+
if __name__ == "__main__":
112+
main()

0 commit comments

Comments
 (0)