4 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']
16 FORMAT_3_HEADER =
"""<?xml version="1.0"?> 18 href="http://download.ros.org/schema/package_format3.xsd" 19 schematypens="http://www.w3.org/2001/XMLSchema"?> 24 for i, o
in enumerate(ORDERING):
31 print(
'\tUnsure of ordering for ' + name)
43 while c < len(s)
and s[-c - 1] ==
' ':
49 """Replace all the elements with tags in source_tags with new elements with new_tag.""" 51 for tag
in source_tags:
52 pkgs = set(manifest.get_packages_by_tag(tag))
53 if intersection
is None:
56 intersection = intersection.intersection(pkgs)
57 for tag
in source_tags:
58 manifest.remove_dependencies(tag, intersection)
59 manifest.insert_new_packages(new_tag, intersection)
66 self.
root = self.tree.getElementsByTagName(
'package')[0]
67 contents = open(fn).read()
76 if self.
_name is not None:
78 name_tags = self.root.getElementsByTagName(
'name')
81 name_tag = name_tags[0]
82 self.
_name = name_tag.firstChild.nodeValue
89 if not self.root.hasAttribute(
'format'):
92 self.
_format = int(self.root.attributes[
'format'].value)
99 tab_ct = collections.defaultdict(int)
100 for c
in self.root.childNodes:
101 if c.nodeType == c.TEXT_NODE:
107 self.
_std_tab = max(tab_ct.items(), key=operator.itemgetter(1))[0]
112 for el
in self.root.getElementsByTagName(tag):
113 pkgs.append(el.childNodes[0].nodeValue)
119 keys.append(
'build_depend')
121 keys.append(
'run_depend')
122 if self.
format == 2
and mode !=
'test':
123 keys.append(
'depend')
125 keys.append(
'exec_depend')
127 keys.append(
'test_depend')
134 return self.tree.createTextNode(
'\n' +
' ' * (self.
std_tab * tabs))
137 """Return a dictionary based on which children span which indexes. 139 The keys are the types of nodes in the xml (build_depend, maintainer, etc). 140 The values are arrays marking the range of elements in the xml root that match that tag. 142 For example, tags[build_depend] = [(5, 9), (11, 50)] means that elements [5, 9) and [11, 50) are 143 either build_depend elements (or the strings between them) 145 tags = collections.defaultdict(list)
150 while i < len(self.root.childNodes):
151 child = self.root.childNodes[i]
152 if child.nodeType == child.TEXT_NODE:
156 name = child.nodeName
159 tags[current].append((current_start, current_last))
165 tags[current].append((current_start, current_last))
169 """Return the index where to insert a new element with the given tag type. 171 If there are already elements of that type, then either insert after the last matching element, 172 or if the list is alphabetized, insert it in the correct place alphabetically using the tag_value. 173 Otherwise, look at the existing elements, and find ones that are supposed to come the closest 174 before the given tag, and insert after them. If none found, add at the end. 179 if len(indexes[tag]) == 1
and tag
in DEPEND_ORDERING:
180 start, end = indexes[tag][0]
183 for i
in range(start, end + 1):
184 child = self.root.childNodes[i]
185 if child.nodeType == child.TEXT_NODE:
187 value = child.firstChild.data
188 tag_values.append(value)
189 if tag_value >= value:
193 if tag_values
and sorted(tag_values) == tag_values:
195 if tag_value <= tag_values[0]:
199 if tag_value <= tag_values[-1]:
203 return indexes[tag][-1][1]
216 if best_tag
is None or ni > best_index
or indexes[tag][-1] > indexes[best_tag][-1]:
221 return len(self.root.childNodes)
223 return indexes[best_tag][-1][1]
226 if tag.tagName
in DEPEND_ORDERING:
227 value = tag.firstChild.data
232 before = self.root.childNodes[:index + 1]
233 after = self.root.childNodes[index + 1:]
239 if before
and before[-1].nodeType == before[-1].TEXT_NODE:
240 new_bits = [tag, new_tab_element]
243 new_bits = [new_tab_element, tag]
245 self.root.childNodes = before + new_bits + after
255 all_elements.append(tag)
257 if len(parent.childNodes) == 0:
260 parent.childNodes = parent.childNodes[:-1] + all_elements + parent.childNodes[-1:]
264 for pkg
in sorted(values):
265 print(
'\tInserting %s: %s' % (tag, pkg))
266 node = self.tree.createElement(tag)
267 node.appendChild(self.tree.createTextNode(pkg))
270 def add_packages(self, build_depends, run_depends, test_depends=None, prefer_depend_tag=True):
272 run_depends.update(build_depends)
275 build_depends = build_depends - existing_build
276 run_depends = run_depends - existing_run
280 elif prefer_depend_tag:
281 depend_tags = build_depends.union(run_depends)
290 both = build_depends.intersection(run_depends)
296 if test_depends
is not None and len(test_depends) > 0:
298 test_depends = set(test_depends) - existing_build - build_depends - existing_test
302 """Remove the given element AND the text element before it if it is just an indentation.""" 303 parent = element.parentNode
304 index = parent.childNodes.index(element)
306 previous = parent.childNodes[index - 1]
307 if previous.nodeType == previous.TEXT_NODE
and INDENT_PATTERN.match(previous.nodeValue):
308 parent.removeChild(previous)
309 parent.removeChild(element)
313 for el
in self.root.getElementsByTagName(name):
314 pkg = el.childNodes[0].nodeValue
317 print(
'\tRemoving %s %s' % (name, pkg))
323 elements += self.root.getElementsByTagName(tag)
329 name = el.childNodes[0].nodeValue
330 email = el.getAttribute(
'email')
331 people.append((name, email))
334 def update_people(self, target_name, target_email=None, search_name=None, search_email=None):
336 name = el.childNodes[0].nodeValue
337 email = el.getAttribute(
'email')
if el.hasAttribute(
'email')
else '' 338 if (search_name
is None or name == search_name)
and (search_email
is None or email == search_email):
339 el.childNodes[0].nodeValue = target_name
341 el.setAttribute(
'email', target_email)
342 print(
'\tReplacing %s %s/%s with %s/%s' % (el.nodeName, name, email, target_name, target_email))
346 els = self.root.getElementsByTagName(
'license')
353 return el.childNodes[0].nodeValue
357 if license != el.childNodes[0].nodeValue:
358 el.childNodes[0].nodeValue = license_str
362 for node
in self.root.getElementsByTagName(
'export'):
363 for child
in node.childNodes:
364 if child.nodeType == child.ELEMENT_NODE:
365 if child.nodeName ==
'metapackage':
370 """Return a mapping from the package name to a list of the relative path(s) for the plugin xml(s).""" 371 xmls = collections.defaultdict(list)
372 export = self.root.getElementsByTagName(
'export')
376 for n
in ex.childNodes:
377 if n.nodeType == self.root.ELEMENT_NODE:
378 plugin = n.getAttribute(
'plugin').replace(
'${prefix}/',
'')
379 xmls[n.nodeName].append(plugin)
383 """Get the export tag. Create it if it doesn't exist.""" 384 export_tags = self.root.getElementsByTagName(
'export')
385 if len(export_tags) == 0:
386 export_tag = self.tree.createElement(
'export')
390 return export_tags[0]
393 """Add the plugin configuration if not found. Add export tag as needed. Return the surrounding export tag.""" 396 attr =
'${prefix}/' + xml_path
397 for tag
in ex_tag.childNodes:
398 if tag.nodeName != pkg_name:
400 plugin = tag.attributes.get(
'plugin')
401 if plugin
and plugin.value == attr:
404 pe = self.tree.createElement(pkg_name)
405 pe.setAttribute(
'plugin', attr)
410 if self.
format == new_format:
412 print(
'%s already in format %d!' % (self.
name, self.
format))
415 if new_format
not in [2, 3]:
416 raise RuntimeError(
'Unknown PackageXML version: ' + repr(new_format))
422 self.root.setAttribute(
'format',
'2')
430 self.root.setAttribute(
'format',
'3')
431 self.
header = FORMAT_3_HEADER
439 if new_fn == self.
fn and not self.
changed:
442 s = self.tree.toxml(self.tree.encoding)
444 s = self.
header + s[index:] +
'\n' 446 with open(new_fn,
'wb')
as f:
447 f.write(s.encode(
'UTF-8'))
def count_trailing_spaces(s)
def upgrade(self, new_format=2, quiet=True)
def get_license_element(self)
def get_elements_by_tags(self, tags)
def set_license(self, license_str)
def update_people(self, target_name, target_email=None, search_name=None, search_email=None)
def replace_package_set(manifest, source_tags, new_tag)
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 insert_new_tag(self, tag)
def insert_new_tag_inside_another(self, parent, tag, depth=2)