diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index c8f63c93908..08defe4a00c 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -17,6 +17,7 @@ from galaxy.util.bunch import Bunch from galaxy.util.template import fill_template from galaxy import util, jobs, model from galaxy.jobs import ParallelismInfo +from copy import deepcopy from elementtree import ElementTree from parameters import * from parameters.grouping import * @@ -520,7 +521,7 @@ class ToolBox( object ): def load_tool( self, config_file, guid=None, **kwds ): """Load a single tool from the file named by `config_file` and return an instance of `Tool`.""" # Parse XML configuration file and get the root element - tree = util.parse_xml( config_file ) + tree = self._load_and_preprocess_tool_xml( config_file ) root = tree.getroot() # Allow specifying a different tool subclass to instantiate if root.find( "type" ) is not None: @@ -704,7 +705,104 @@ class ToolBox( object ): rval = tools return rval - + + def _load_and_preprocess_tool_xml(self, config_file): + tree = util.parse_xml(config_file) + root = tree.getroot() + macros_el = root.find('macros') + if not macros_el: + return tree + tool_dir = os.path.dirname(config_file) + macros = self._load_macros(macros_el, tool_dir) + + self._expand_macros([root], macros) + return tree + + def _expand_macros(self, elements, macros): + for element in elements: + # HACK for elementtree, newer implementations (etree/lxml) won't + # require this parent_map data structure but elementtree does not + # track parents or recongnize .find('..'). + parent_map = dict((c, p) for p in element.getiterator() for c in p) + for expand_el in element.findall('.//expand'): + macro_name = expand_el.get('macro') + macro_def = deepcopy(macros[macro_name]) # deepcopy needed? + + yield_els = [yield_el for macro_def_el in macro_def for yield_el in macro_def_el.findall('.//yield')] + + expand_el_children = expand_el.getchildren() + macro_def_parent_map = \ + dict((c, p) for macro_def_el in macro_def for p in macro_def_el.getiterator() for c in p) + + for yield_el in yield_els: + self._xml_replace(yield_el, expand_el_children, macro_def_parent_map) + + # Recursively expand contained macros. + self._expand_macros(macro_def, macros) + self._xml_replace(expand_el, macro_def, parent_map) + + def _load_macros(self, macros_el, tool_dir): + macros = {} + # Import macros from external files. + macros.update(self._load_imported_macros(macros_el, tool_dir)) + # Load all directly defined macros. + macros.update(self._load_embedded_macros(macros_el, tool_dir)) + return macros + + def _load_embedded_macros(self, macros_el, tool_dir): + macros = {} + + macro_els = [] + if macros_el: + macro_els = macros_el.findall("macro") + for macro in macro_els: + macro_name = macro.get("name") + macros[macro_name] = self._load_macro_def(macro) + + return macros + + def _load_imported_macros(self, macros_el, tool_dir): + macros = {} + + macro_import_els = [] + if macros_el: + macro_import_els = macros_el.findall("import") + for macro_import_el in macro_import_els: + raw_import_path = macro_import_el.text + tool_relative_import_path = \ + os.path.basename(raw_import_path) # Sanitize this + import_path = \ + os.path.join(tool_dir, tool_relative_import_path) + file_macros = self._load_macro_file(import_path, tool_dir) + macros.update(file_macros) + + return macros + + def _load_macro_file(self, path, tool_dir): + tree = util.parse_xml(path) + root = tree.getroot() + return self._load_macros(root, tool_dir) + + def _load_macro_def(self, macro): + return list(macro.getchildren()) + + def _xml_replace(self, query, targets, parent_map): + #parent_el = query.find('..') ## Something like this would be better with newer xml library + parent_el = parent_map[query] + matching_index = -1 + #for index, el in enumerate(parent_el.iter('.')): ## Something like this for newer implementation + for index, el in enumerate(parent_el.getchildren()): + if el == query: + matching_index = index + break + assert matching_index >= 0 + current_index = matching_index + for target in targets: + current_index += 1 + parent_el.insert(current_index, deepcopy(target)) + parent_el.remove(query) + + class ToolSection( object ): """ A group of tools with similar type/purpose that will be displayed as a diff --git a/tools/ngs_rna/tophat2_wrapper.xml b/tools/ngs_rna/tophat2_wrapper.xml index 5733bbe4a6e..fb0f1d19bca 100644 --- a/tools/ngs_rna/tophat2_wrapper.xml +++ b/tools/ngs_rna/tophat2_wrapper.xml @@ -143,23 +143,12 @@ - - - - - - - - - - - - - - - - - + + + + + + @@ -182,17 +171,7 @@ - - - - - - - - - - - + alignments (number of reads divided by average depth of coverage)" help="0.0 to 1.0 (0 to turn off)" /> @@ -201,40 +180,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -319,83 +265,40 @@ (params['settingsType'] == 'full' and params['fusion_search']['do_search'] == 'Yes') - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - + - + + tophat_macros.xml + + + + + + + + + + + + + + + + diff --git a/tools/ngs_rna/tophat_color_wrapper.xml b/tools/ngs_rna/tophat_color_wrapper.xml index 72c0a277b29..399d2c9c46c 100644 --- a/tools/ngs_rna/tophat_color_wrapper.xml +++ b/tools/ngs_rna/tophat_color_wrapper.xml @@ -154,23 +154,12 @@ - - - - - - - - - - - - - - - - - + + + + + + @@ -194,17 +183,7 @@ - - - - - - - - - - - + @@ -230,20 +209,8 @@ - - - - - - - - - - - - - - + + @@ -301,17 +268,7 @@ - - - - - - - - - - - + @@ -399,90 +356,50 @@ ( singlePaired['pParams']['indel_search']['allow_indel_search'] == 'Yes' ) ) ) - - - - - - - - - - - - - + - + + + + + + + + + + + tophat_macros.xml + + ( ( ( 'sParams' in singlePaired ) and ( 'indel_search' in singlePaired['sParams'] ) and ( singlePaired['sParams']['indel_search']['allow_indel_search'] == 'Yes' ) ) or ( ( 'pParams' in singlePaired ) and ( 'indel_search' in singlePaired['pParams'] ) and ( singlePaired['pParams']['indel_search']['allow_indel_search'] == 'Yes' ) ) ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/tools/ngs_rna/tophat_macros.xml b/tools/ngs_rna/tophat_macros.xml new file mode 100644 index 00000000000..51ebec16d9a --- /dev/null +++ b/tools/ngs_rna/tophat_macros.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/ngs_rna/tophat_wrapper.xml b/tools/ngs_rna/tophat_wrapper.xml index 234040bc664..83321cdb9d5 100644 --- a/tools/ngs_rna/tophat_wrapper.xml +++ b/tools/ngs_rna/tophat_wrapper.xml @@ -151,23 +151,12 @@ - - - - - - - - - - - - - - - - - + + + + + + @@ -298,17 +287,7 @@ alignments (number of reads divided by average depth of coverage)" help="0.0 to - - - - - - - - - - - + @@ -316,40 +295,7 @@ alignments (number of reads divided by average depth of coverage)" help="0.0 to - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -387,83 +333,40 @@ alignments (number of reads divided by average depth of coverage)" help="0.0 to - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - + - + + tophat_macros.xml + + + + + + + + + + + + + + + +