forked from galaxyproject/galaxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild_toolbox.py
167 lines (138 loc) · 5.95 KB
/
build_toolbox.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
import os
from collections import defaultdict
from xml.dom import minidom
from xml.etree import ElementTree as ET
def prettify(elem):
rough_string = ET.tostring(elem, "utf-8")
repaired = minidom.parseString(rough_string)
return repaired.toprettyxml(indent=" ")
# Build a list of all toolconf xml files in the tools directory
def getfilenamelist(startdir):
filenamelist = []
for root, _dirs, files in os.walk(startdir):
for fn in files:
fullfn = os.path.join(root, fn)
if fn.endswith("toolconf.xml"):
filenamelist.append(fullfn)
elif fn.endswith(".xml"):
try:
doc = ET.parse(fullfn)
except Exception:
print("An OOPS on", fullfn)
raise
rootelement = doc.getroot()
# Only interpret those 'tool' XML files that have
# the 'section' element.
if rootelement.tag == "tool":
if rootelement.findall("toolboxposition"):
filenamelist.append(fullfn)
else:
print("DBG> tool config does not have a <section>:", fullfn)
return filenamelist
class ToolBox:
def __init__(self):
self.tools = defaultdict(list)
self.sectionorders = {}
def add(self, toolelement, toolboxpositionelement):
section = toolboxpositionelement.attrib.get("section", "")
label = toolboxpositionelement.attrib.get("label", "")
order = int(toolboxpositionelement.attrib.get("order", "0"))
sectionorder = int(toolboxpositionelement.attrib.get("sectionorder", "0"))
# If this is the first time we encounter the section, store its order
# number. If we have seen it before, ignore the given order and use
# the stored one instead
if section not in self.sectionorders:
self.sectionorders[section] = sectionorder
else:
sectionorder = self.sectionorders[section]
# Sortorder: add intelligent mix to the front
self.tools[(f"{sectionorder:05d}-{section}", label, order, section)].append(toolelement)
def addElementsTo(self, rootelement):
toolkeys = list(self.tools.keys())
toolkeys.sort()
# Initialize the loop: IDs to zero, current section and label to ''
currentsection = ""
sectionnumber = 0
currentlabel = ""
labelnumber = 0
for toolkey in toolkeys:
section = toolkey[3]
# If we change sections, add the new section to the XML tree,
# and start adding stuff to the new section. If the new section
# is '', start adding stuff to the root again.
if currentsection != section:
currentsection = section
# Start the section with empty label
currentlabel = ""
if section:
sectionnumber += 1
attrib = {"name": section, "id": f"section{sectionnumber}"}
sectionelement = ET.Element("section", attrib)
rootelement.append(sectionelement)
currentelement = sectionelement
else:
currentelement = rootelement
label = toolkey[1]
# If we change labels, add the new label to the XML tree
if currentlabel != label:
currentlabel = label
if label:
labelnumber += 1
attrib = {"text": label, "id": f"label{labelnumber}"}
labelelement = ET.Element("label", attrib)
currentelement.append(labelelement)
# Add the tools that are in this place
for toolelement in self.tools[toolkey]:
currentelement.append(toolelement)
# Analyze all the toolconf xml files given in the filenamelist
# Build a list of all sections
def scanfiles(filenamelist):
# Build an empty tool box
toolbox = ToolBox()
# Read each of the files in the list
for fn in filenamelist:
doc = ET.parse(fn)
root = doc.getroot()
if root.tag == "tool":
toolelements = [root]
else:
toolelements = doc.findall("tool")
for toolelement in toolelements:
# Figure out where the tool XML file is, absolute path.
if "file" in toolelement.attrib:
# It is mentioned, we need to make it absolute
fileattrib = os.path.join(os.getcwd(), os.path.dirname(fn), toolelement.attrib["file"])
else:
# It is the current file
fileattrib = os.path.join(os.getcwd(), fn)
# Store the file in the attibutes of the new tool element
attrib = {"file": fileattrib}
# Add the tags into the attributes
tags = toolelement.find("tags")
if tags:
tagarray = []
for tag in tags.findall("tag"):
tagarray.append(tag.text)
attrib["tags"] = ",".join(tagarray)
else:
print("DBG> No tags in", fn)
# Build the tool element
newtoolelement = ET.Element("tool", attrib)
toolboxpositionelements = toolelement.findall("toolboxposition")
if not toolboxpositionelements:
print(f"DBG> {fn} has no toolboxposition")
else:
for toolboxpositionelement in toolboxpositionelements:
toolbox.add(newtoolelement, toolboxpositionelement)
return toolbox
def assemble():
filenamelist = []
for directorytree in ["tools"]:
filenamelist.extend(getfilenamelist(directorytree))
filenamelist.sort()
toolbox = scanfiles(filenamelist)
toolboxelement = ET.Element("toolbox")
toolbox.addElementsTo(toolboxelement)
print(prettify(toolboxelement))
if __name__ == "__main__":
assemble()