00001 from ros_introspection.package_xml import count_trailing_spaces, get_ordering_index
00002 from util import get_ignore_data, roscompile, get_config
00003
00004
00005 @roscompile
00006 def check_manifest_dependencies(package):
00007 build_depends = package.get_build_dependencies()
00008 run_depends = package.get_run_dependencies()
00009 test_depends = package.get_test_dependencies()
00010 package.manifest.add_packages(build_depends, run_depends, test_depends)
00011
00012 if package.generators:
00013 md = package.get_dependencies_from_msgs()
00014 package.manifest.add_packages(md, md)
00015
00016 if package.manifest.format == 1:
00017 pairs = [('build_depend', 'message_generation'),
00018 ('run_depend', 'message_runtime')]
00019 else:
00020 pairs = [('build_depend', 'message_generation'),
00021 ('build_export_depend', 'message_runtime'),
00022 ('exec_depend', 'message_runtime')]
00023 package.manifest.remove_dependencies('depend', ['message_generation', 'message_runtime'])
00024 for tag, msg_pkg in pairs:
00025 existing = package.manifest.get_packages_by_tag(tag)
00026 if msg_pkg not in existing:
00027 package.manifest.insert_new_packages(tag, [msg_pkg])
00028
00029
00030 @roscompile
00031 def check_python_dependencies(package):
00032 run_depends = package.source_code.get_external_python_dependencies()
00033 package.manifest.add_packages(set(), run_depends, prefer_depend_tag=False)
00034
00035
00036 def has_element_child(node):
00037 for child in node.childNodes:
00038 if child.nodeType == child.ELEMENT_NODE:
00039 return True
00040 return False
00041
00042
00043 @roscompile
00044 def remove_empty_export_tag(package):
00045 exports = package.manifest.root.getElementsByTagName('export')
00046 if len(exports) == 0:
00047 return False
00048 for export in exports:
00049 if not has_element_child(export):
00050 package.manifest.remove_element(export)
00051 return True
00052
00053
00054 def replace_package_set(manifest, source_tags, new_tag):
00055 """
00056 Find the set of packages that are defined in the manifest using all of the tags listed in source_tags.
00057 Remove all those elements and replace them with the new_tag.
00058 """
00059 intersection = None
00060 for tag in source_tags:
00061 pkgs = set(manifest.get_packages_by_tag(tag))
00062 if intersection is None:
00063 intersection = pkgs
00064 else:
00065 intersection = intersection.intersection(pkgs)
00066 for tag in source_tags:
00067 manifest.remove_dependencies(tag, intersection)
00068 manifest.insert_new_packages(new_tag, intersection)
00069
00070
00071 @roscompile
00072 def greedy_depend_tag(package):
00073 if package.manifest.format == 1:
00074 return
00075 replace_package_set(package.manifest, ['build_depend', 'build_export_depend', 'exec_depend'], 'depend')
00076
00077
00078 def enforce_tabbing_helper(manifest, node, tabs=1):
00079 ideal_length = manifest.std_tab * tabs
00080 prev_was_node = True
00081 insert_before_list = []
00082 if not node:
00083 return
00084 changed = False
00085 for c in node.childNodes:
00086 if c.nodeType == c.TEXT_NODE:
00087 prev_was_node = False
00088 if c == node.childNodes[-1]:
00089 continue
00090 spaces = count_trailing_spaces(c.data)
00091 if spaces > ideal_length:
00092 c.data = c.data[: ideal_length - spaces]
00093 changed = True
00094 elif spaces < ideal_length:
00095 c.data = c.data + ' ' * (ideal_length - spaces)
00096 changed = True
00097 if '\n' not in c.data:
00098 c.data = '\n' + c.data
00099 changed = True
00100 elif prev_was_node:
00101 changed = True
00102 insert_before_list.append(c)
00103 else:
00104 prev_was_node = True
00105
00106 for c in insert_before_list:
00107 node.insertBefore(manifest.get_tab_element(tabs), c)
00108
00109 manifest.changed = manifest.changed or changed
00110
00111 if len(node.childNodes) == 0:
00112 return
00113 last = node.childNodes[-1]
00114 if last.nodeType != last.TEXT_NODE:
00115 node.appendChild(manifest.get_tab_element(tabs - 1))
00116 manifest.changed = True
00117
00118
00119 @roscompile
00120 def enforce_manifest_tabbing(package):
00121 enforce_tabbing_helper(package.manifest, package.manifest.root)
00122
00123
00124 def get_sort_key(node, alphabetize_depends=True):
00125 if node:
00126 name = node.nodeName
00127 else:
00128 name = None
00129
00130 index = get_ordering_index(name)
00131
00132 if not alphabetize_depends:
00133 return index
00134 if name and 'depend' in name:
00135 return index, node.firstChild.data
00136 else:
00137 return index, None
00138
00139
00140 def get_chunks(children):
00141 """ Given the children, group the elements into tuples that are
00142 (an element node, [(some number of text nodes), that element node again])
00143 """
00144 chunks = []
00145 current = []
00146 for child_node in children:
00147 current.append(child_node)
00148 if child_node.nodeType == child_node.ELEMENT_NODE:
00149 chunks.append((child_node, current))
00150 current = []
00151 if len(current) > 0:
00152 chunks.append((None, current))
00153 return chunks
00154
00155
00156 @roscompile
00157 def enforce_manifest_ordering(package, alphabetize=True):
00158 root = package.manifest.root
00159 chunks = get_chunks(root.childNodes)
00160
00161 new_children = []
00162
00163 for a, b in sorted(chunks, key=lambda d: get_sort_key(d[0], alphabetize)):
00164 new_children += b
00165
00166 if root.childNodes != new_children:
00167 package.manifest.changed = True
00168 root.childNodes = new_children
00169
00170
00171 def cleanup_text_elements(node):
00172 new_children = []
00173 changed = False
00174
00175 for child in node.childNodes:
00176 if child.nodeType == child.TEXT_NODE and len(new_children) and new_children[-1].nodeType == child.TEXT_NODE:
00177 changed = True
00178 new_children[-1].data += child.data
00179 elif child.nodeType == child.TEXT_NODE and child.data == '':
00180 continue
00181 else:
00182 new_children.append(child)
00183
00184 node.childNodes = new_children
00185 return changed
00186
00187
00188 def replace_text_node_contents(node, ignorables):
00189 changed = False
00190 removable = []
00191 for i, c in enumerate(node.childNodes):
00192 if c.nodeType == c.TEXT_NODE:
00193 continue
00194 elif c.nodeType == c.COMMENT_NODE:
00195 short = c.data.strip()
00196 if short in ignorables:
00197 removable.append(i)
00198 changed = True
00199 continue
00200 else:
00201 changed = replace_text_node_contents(c, ignorables) or changed
00202 for node_index in reversed(removable):
00203 if node_index > 0:
00204 before = node.childNodes[node_index - 1]
00205 if before.nodeType == c.TEXT_NODE:
00206 trailing = count_trailing_spaces(before.data)
00207 before.data = before.data[:-trailing]
00208
00209 if node_index < len(node.childNodes) - 1:
00210 after = node.childNodes[node_index + 1]
00211 if after.nodeType == c.TEXT_NODE:
00212 while len(after.data) and after.data[0] == ' ':
00213 after.data = after.data[1:]
00214 if len(after.data) and after.data[0] == '\n':
00215 after.data = after.data[1:]
00216
00217 node.childNodes.remove(node.childNodes[node_index])
00218 changed = cleanup_text_elements(node) or changed
00219 return changed
00220
00221
00222 @roscompile
00223 def remove_boilerplate_manifest_comments(package):
00224 ignorables = get_ignore_data('package', {'package': package.name}, add_newline=False)
00225 changed = replace_text_node_contents(package.manifest.root, ignorables)
00226 if changed:
00227 package.manifest.changed = changed
00228 remove_empty_manifest_lines(package)
00229
00230
00231 def remove_empty_lines_helper(node):
00232 changed = False
00233 for child in node.childNodes:
00234 if child.nodeType == child.TEXT_NODE:
00235 while '\n\n\n' in child.data:
00236 child.data = child.data.replace('\n\n\n', '\n\n')
00237 changed = True
00238 else:
00239 changed = remove_empty_lines_helper(child) or changed
00240 return changed
00241
00242
00243 @roscompile
00244 def remove_empty_manifest_lines(package):
00245 if remove_empty_lines_helper(package.manifest.root):
00246 package.manifest.changed = True
00247
00248
00249 @roscompile
00250 def update_people(package, config=None):
00251 if config is None:
00252 config = get_config()
00253 for d in config.get('replace_rules', []):
00254 package.manifest.update_people(d['to']['name'], d['to']['email'],
00255 d['from'].get('name', None), d['from'].get('email', None))
00256
00257
00258 @roscompile
00259 def update_license(package, config=None):
00260 if config is None:
00261 config = get_config()
00262 if 'default_license' not in config or package.manifest.get_license() != 'TODO':
00263 return
00264
00265 package.manifest.set_license(config['default_license'])