-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfix-update-2-update-set-assignments.py
237 lines (179 loc) · 10.5 KB
/
fix-update-2-update-set-assignments.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import xml.etree.ElementTree as ET
import hashlib
import uuid
import readline
import glob
def generate_sys_id():
return hashlib.md5(uuid.uuid4().bytes).hexdigest()
# Find all 'sys_update_xml' elements and create a list of unique 'application' text
def get_applications_referenced_in_updates(root_element):
return {elem.find('application').text for elem in root_element.findall('.//sys_update_xml')}
def get_base_update_set_name(root_element, base_update_set_id):
# Find the sys_remote_update_set element with the matching sys_id
for update_set in root_element.findall('.//sys_remote_update_set'):
if update_set.find('sys_id').text == base_update_set_id.text:
# Return the name text value
name_element = update_set.find('name')
return name_element.text if name_element is not None else None
def get_base_update_set_id_from_update_sets(root_element):
update_set_count = 0
for update_set in root_element.findall('.//sys_remote_update_set'):
update_set_count += 1
base_update_set = update_set.find('remote_base_update_set')
# Explicitly check if base_update_set is not None and has text content
if base_update_set is not None and base_update_set.text:
print("Base update set found.")
return base_update_set, update_set_count
print("No base update set found.")
return None, update_set_count
def create_or_retrieve_parent_update_set(base_update_set, root, new_base_set_name_parent):
if base_update_set is None:
# Create a new parent update set element
parent_update_set = ET.Element('sys_remote_update_set')
parent_update_set.set('action', 'INSERT_OR_UPDATE')
# Add necessary sub-elements and their text values to the parent update set
parent_name = ET.SubElement(parent_update_set, 'name')
parent_name.text = new_base_set_name_parent
parent_application = ET.SubElement(parent_update_set, 'application')
parent_application.text = 'global'
parent_state = ET.SubElement(parent_update_set, 'state')
parent_state.text = 'loaded'
parent_sys_id_string = generate_sys_id()
parent_sys_id = ET.SubElement(parent_update_set, 'sys_id')
# Generate a unique sys_id for the parent update set. This is just a placeholder.
# In a real-world scenario, this would be generated by the system or a function to ensure uniqueness.
parent_sys_id.text = parent_sys_id_string
parent_remote_base_update_set = ET.SubElement(parent_update_set, 'remote_base_update_set')
parent_remote_base_update_set.text = parent_sys_id_string
parent_sys_class_name = ET.SubElement(parent_update_set, 'sys_class_name')
parent_sys_class_name.text = 'sys_remote_update_set'
parent_sys_created_by = ET.SubElement(parent_update_set, 'sys_created_by')
# Insert the new parent update set element at the top of the root 'unload' element
root.insert(0, parent_update_set)
return parent_sys_id_string
else:
# Retrieve the sys_id of the first base update set
return base_update_set
def update_sys_remote_update_set_elements(root, matched_applications, parent_sys_id_string):
for update_set in root.findall('.//sys_remote_update_set'):
application = update_set.find('application')
if application is not None and application.text in matched_applications:
parent = update_set.find('parent')
if parent is not None:
parent.text = parent_sys_id_string
remote_base_update_set = update_set.find('remote_base_update_set')
if remote_base_update_set is not None:
remote_base_update_set.text = parent_sys_id_string
# Find all 'sys_remote_update_set' elements and create a list of unique 'application' text
def get_applications_from_update_sets(root_element):
return {elem.find('application').text for elem in root_element.findall('.//sys_remote_update_set') if elem.find('application') is not None}
def update_remote_update_set_elements(root, application_id_map):
"""Update 'remote_update_set' elements with the corresponding sys_id from 'application_id_map'.
Args:
root (ElementTree): The root of the XML tree.
application_id_map (dict): A dictionary mapping application names to sys_id values.
"""
for update_xml in root.findall('.//sys_update_xml'):
application_element = update_xml.find('application')
if application_element is not None and application_element.text:
update_set_id = application_id_map.get(application_element.text)
if update_set_id:
remote_update_set_element = update_xml.find('remote_update_set')
if remote_update_set_element is not None:
remote_update_set_element.text = update_set_id
remote_update_set_element.set('display_value', '')
def generate_child_update_sets(unmatched_applications, root, new_base_set_name_child, parent_sys_id_string, created_by_email):
application_id_map = {}
for unmatched_application in unmatched_applications:
sys_remote_update_set = ET.Element('sys_remote_update_set')
sys_remote_update_set.set('action', 'INSERT_OR_UPDATE')
application = ET.SubElement(sys_remote_update_set, 'application')
application.text = unmatched_application
state = ET.SubElement(sys_remote_update_set, 'state')
state.text = 'in_hierarchy'
name = ET.SubElement(sys_remote_update_set, 'name')
name.text = new_base_set_name_child
sys_class_name = ET.SubElement(sys_remote_update_set, 'sys_class_name')
sys_class_name.text = 'sys_remote_update_set'
sys_created_by = ET.SubElement(sys_remote_update_set, 'sys_created_by')
sys_created_by.text = created_by_email
base_update_set = ET.SubElement(sys_remote_update_set, 'remote_base_update_set')
base_update_set.text = parent_sys_id_string
parent = ET.SubElement(sys_remote_update_set, 'parent')
parent.text = parent_sys_id_string
sys_id = ET.SubElement(sys_remote_update_set, 'sys_id')
generated_sys_id = generate_sys_id()
sys_id.text = generated_sys_id
# Map the unmatched application ID to the generated sys_id
application_id_map[unmatched_application] = generated_sys_id
# Insert the new element at the top of the root 'unload' element
root.insert(0, sys_remote_update_set)
return application_id_map
def generate_update_set_names(update_set_name):
suffix_parent = " - Batch Parent"
suffix_child = " - Batch Child"
max_length = 80
base_name_length = max_length - len(suffix_parent)
new_base_set_name_parent = update_set_name[:base_name_length] + suffix_parent
new_base_set_name_child = update_set_name[:base_name_length] + suffix_child
return new_base_set_name_parent, new_base_set_name_child
def infer_base_update_set_name_from_single_update_set(root):
update_set = root.find('.//sys_remote_update_set')
if update_set is not None:
name_element = update_set.find('name')
return name_element.text if name_element is not None else None
return None
def complete(text, state):
return (glob.glob(text+'*')+[None])[state]
def main():
# Use the tab key for autocompletion
readline.parse_and_bind('tab: complete')
# Set the autocompletion function
readline.set_completer(complete)
# Prompt the user for the XML file name with autocompletion
xml_file = input("Enter the path to the XML file: ")
try:
tree = ET.parse(xml_file)
root = tree.getroot()
except FileNotFoundError:
print("File not found. Please check the path and try again.")
return
except ET.ParseError:
print("Error parsing the XML. Please check the file content.")
return
created_by_email = input("Enter the email address to set the `created_by` field on any generated update sets: ")
application_names = get_applications_referenced_in_updates(root)
print(f"The following applications were found in the updates contained within this XML: \033[93m{list(application_names)}\033[0m")
# Determine which applications are in 'sys_update_xml' but not in 'sys_remote_update_set'
applications_from_update_sets = get_applications_from_update_sets(root)
unmatched_applications = application_names - applications_from_update_sets
if not unmatched_applications:
print("No unmatched applications found. Exiting.")
return
# Call the function and print the result
base_update_set_id, update_set_count = get_base_update_set_id_from_update_sets(root)
base_update_set_name = get_base_update_set_name(root, base_update_set_id) if base_update_set_id else infer_base_update_set_name_from_single_update_set(root)
print(f"\033[1m{update_set_count} update set(s)\033[0m found in the XML.")
print(f"Original Base Update Set Name: \033[93m{base_update_set_name}\033[0m")
# Invoke the function to generate new update set names
new_parent_name, new_child_name = generate_update_set_names(base_update_set_name)
print(f"New Base Update Set Name for Parent set: \033[92m{new_parent_name}\033[0m")
print(f"New Base Update Set Name for Child sets: \033[92m{new_child_name}\033[0m")
# Print the list of applications extracted from the update sets
print("Applications referenced in the update sets:", list(applications_from_update_sets))
matched_applications = application_names.intersection(applications_from_update_sets)
print("Matched Applications:", list(matched_applications))
# Invoke the function to create or retrieve the parent update set
parent_sys_id_string = create_or_retrieve_parent_update_set(base_update_set_id, root, new_parent_name)
# Invoke the function
update_sys_remote_update_set_elements(root, matched_applications, parent_sys_id_string)
# Invoke the function to create sys_remote_update_set elements
application_id_map = generate_child_update_sets(unmatched_applications, root, new_child_name, parent_sys_id_string, created_by_email)
# Call the function to update 'remote_update_set' elements
update_remote_update_set_elements(root, application_id_map)
# Save the modified tree back to the file
output_file_name = xml_file.replace('.xml', '_fixed.xml')
tree.write(output_file_name, encoding='utf-8', xml_declaration=True)
if __name__ == "__main__":
main()