1 from xml.dom.minidom
import parse
6 DEPEND_ORDERING = [
'buildtool_depend',
'depend',
'build_depend',
'build_export_depend',
7 'run_depend',
'exec_depend',
'test_depend',
'doc_depend']
9 ORDERING = [
'name',
'version',
'description',
10 [
'maintainer',
'license',
'author',
'url']] + DEPEND_ORDERING + [
'export']
12 INDENT_PATTERN = re.compile(
'\n *')
14 PEOPLE_TAGS = [
'maintainer',
'author']
18 for i, o
in enumerate(ORDERING):
25 print(
'\tUnsure of ordering for', name)
37 while c < len(s)
and s[-c - 1] ==
' ':
46 self.
root = self.tree.getElementsByTagName(
'package')[0]
47 contents = open(fn).read()
56 if self.
_name is not None:
58 name_tags = self.root.getElementsByTagName(
'name')
61 name_tag = name_tags[0]
62 self.
_name = name_tag.childNodes[0].nodeValue
69 if not self.root.hasAttribute(
'format'):
72 self.
_format = int(self.root.attributes[
'format'].value)
79 tab_ct = collections.defaultdict(int)
80 for c
in self.root.childNodes:
81 if c.nodeType == c.TEXT_NODE:
87 self.
_std_tab = max(tab_ct.iteritems(), key=operator.itemgetter(1))[0]
92 for el
in self.root.getElementsByTagName(tag):
93 pkgs.append(el.childNodes[0].nodeValue)
99 keys.append(
'build_depend')
101 keys.append(
'run_depend')
102 if self.
format == 2
and mode !=
'test':
103 keys.append(
'depend')
105 keys.append(
'exec_depend')
107 keys.append(
'test_depend')
114 return self.tree.createTextNode(
'\n' +
' ' * (self.
std_tab * tabs))
118 Return a dictionary where the keys are the types of nodes in the xml (build_depend, maintainer, etc) 119 and the values are arrays marking the range of elements in the xml root that match that tag. 121 For example, tags[build_depend] = [(5, 9), (11, 50)] means that elements [5, 9) and [11, 50) are 122 either build_depend elements (or the strings between them) 124 tags = collections.defaultdict(list)
129 while i < len(self.root.childNodes):
130 child = self.root.childNodes[i]
131 if child.nodeType == child.TEXT_NODE:
135 name = child.nodeName
138 tags[current].append((current_start, current_last))
144 tags[current].append((current_start, current_last))
148 """ Returns the index where to insert a new element with the given tag type. 149 If there are already elements of that type, then either insert after the last matching element, 150 or if the list is alphabetized, insert it in the correct place alphabetically using the tag_value. 151 Otherwise, look at the existing elements, and find ones that are supposed to come the closest 152 before the given tag, and insert after them. If none found, add at the end. 156 if len(indexes[tag]) == 1
and tag
in DEPEND_ORDERING:
157 start, end = indexes[tag][0]
162 for i
in range(start, end):
163 child = self.root.childNodes[i]
164 if child.nodeType == child.TEXT_NODE:
166 sub_indexes.append(i)
167 value = child.firstChild.data
168 tag_values.append(value)
169 if tag_value >= value:
171 if sorted(tag_values) == tag_values
and tag_value <= value:
173 return indexes[tag][-1][1]
184 if best_tag
is None or ni > best_index
or indexes[tag][-1] > indexes[best_tag][-1]:
189 return len(self.root.childNodes)
191 return indexes[best_tag][-1][1]
194 if tag.tagName
in DEPEND_ORDERING:
195 value = tag.firstChild.data
200 before = self.root.childNodes[:index + 1]
201 after = self.root.childNodes[index + 1:]
212 all_elements.append(tag)
214 if len(parent.childNodes) == 0:
217 parent.childNodes = parent.childNodes[:-1] + all_elements + parent.childNodes[-1:]
221 for pkg
in sorted(values):
222 print(
'\tInserting %s: %s' % (tag, pkg))
223 node = self.tree.createElement(tag)
224 node.appendChild(self.tree.createTextNode(pkg))
227 def add_packages(self, build_depends, run_depends, test_depends=None, prefer_depend_tag=True):
229 run_depends.update(build_depends)
232 build_depends = build_depends - existing_build
233 run_depends = run_depends - existing_run
237 elif prefer_depend_tag:
238 depend_tags = build_depends.union(run_depends)
247 both = build_depends.intersection(run_depends)
253 if test_depends
is not None and len(test_depends) > 0:
255 test_depends = set(test_depends) - existing_build - build_depends - existing_test
259 """ Remove the given element AND the text element before it if it is just an indentation """ 260 parent = element.parentNode
261 index = parent.childNodes.index(element)
263 previous = parent.childNodes[index - 1]
264 if previous.nodeType == previous.TEXT_NODE
and INDENT_PATTERN.match(previous.nodeValue):
265 parent.removeChild(previous)
266 parent.removeChild(element)
270 for el
in self.root.getElementsByTagName(name):
271 pkg = el.childNodes[0].nodeValue
274 print(
'\tRemoving %s %s' % (name, pkg))
280 elements += self.root.getElementsByTagName(tag)
286 name = el.childNodes[0].nodeValue
287 email = el.getAttribute(
'email')
288 people.append((name, email))
291 def update_people(self, target_name, target_email=None, search_name=None, search_email=None):
293 name = el.childNodes[0].nodeValue
294 email = el.getAttribute(
'email')
if el.hasAttribute(
'email')
else '' 295 if (search_name
is None or name == search_name)
and (search_email
is None or email == search_email):
296 el.childNodes[0].nodeValue = target_name
298 el.setAttribute(
'email', target_email)
299 print(
'\tReplacing %s %s/%s with %s/%s' % (el.nodeName, name, email, target_name, target_email))
303 els = self.root.getElementsByTagName(
'license')
310 return el.childNodes[0].nodeValue
314 if license != el.childNodes[0].nodeValue:
315 el.childNodes[0].nodeValue = license
319 for node
in self.root.getElementsByTagName(
'export'):
320 for child
in node.childNodes:
321 if child.nodeType == child.ELEMENT_NODE:
322 if child.nodeName ==
'metapackage':
327 """ Returns a mapping from the package name to a list of the relative path(s) for the plugin xml(s) """ 328 xmls = collections.defaultdict(list)
329 export = self.root.getElementsByTagName(
'export')
333 for n
in ex.childNodes:
334 if n.nodeType == self.root.ELEMENT_NODE:
335 plugin = n.getAttribute(
'plugin').replace(
'${prefix}/',
'')
336 xmls[n.nodeName].append(plugin)
340 """ Adds the plugin configuration if not found. Adds export tag as needed. 341 Returns the export tag it was added to.""" 342 export_tags = self.root.getElementsByTagName(
'export')
343 if len(export_tags) == 0:
344 export_tag = self.tree.createElement(
'export')
346 export_tags = [export_tag]
348 attr =
'${prefix}/' + xml_path
349 for ex_tag
in export_tags:
350 for tag
in ex_tag.childNodes:
351 if tag.nodeName != pkg_name:
353 plugin = tag.attributes.get(
'plugin')
354 if plugin
and plugin.value == attr:
357 ex_el = export_tags[0]
358 pe = self.tree.createElement(pkg_name)
359 pe.setAttribute(
'plugin', attr)
367 if new_fn == self.
fn and not self.
changed:
370 s = self.tree.toxml(self.tree.encoding)
372 s = self.
header + s[index:]
374 with open(new_fn,
'w')
as f:
375 f.write(s.encode(
'UTF-8'))
def count_trailing_spaces(s)
def get_license_element(self)
def get_elements_by_tags(self, tags)
def update_people(self, target_name, target_email=None, search_name=None, search_email=None)
def get_package_tag_index(s, key='< package')
def remove_dependencies(self, name, pkgs, quiet=False)
def get_packages_by_tag(self, tag)
def add_packages(self, build_depends, run_depends, test_depends=None, prefer_depend_tag=True)
def get_plugin_xmls(self)
def insert_new_packages(self, tag, values)
def get_tab_element(self, tabs=1)
def write(self, new_fn=None)
def get_insertion_index(self, tag, tag_value=None)
def add_plugin_export(self, pkg_name, xml_path)
def get_ordering_index(name, whiny=True)
def get_child_indexes(self)
def insert_new_tags(self, tags)
def get_packages(self, mode='build')
def remove_element(self, element)
def set_license(self, license)
def insert_new_tag(self, tag)
def insert_new_tag_inside_another(self, parent, tag, depth=2)