comparison rgToolFactory2.py @ 10:8de2b7571d98 draft

Uploaded
author fubar
date Thu, 15 Jan 2015 07:35:06 -0500
parents ce5ec1d989fd
children
comparison
equal deleted inserted replaced
9:ce5ec1d989fd 10:8de2b7571d98
4 # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 4 # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
5 # 5 #
6 # all rights reserved 6 # all rights reserved
7 # Licensed under the LGPL 7 # Licensed under the LGPL
8 # suggestions for improvement and bug fixes welcome at https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home 8 # suggestions for improvement and bug fixes welcome at https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home
9 #
10 # January 2015
11 # in the process of building a complex tool
12 # added ability to choose one of the current toolshed package_r or package_perl or package_python dependencies and source that package
13 # need to add that package to tool_dependencies
9 # 14 #
10 # sept 2014 added additional params from 15 # sept 2014 added additional params from
11 # https://bitbucket.org/mvdbeek/dockertoolfactory/src/d4863bcf7b521532c7e8c61b6333840ba5393f73/DockerToolFactory.py?at=default 16 # https://bitbucket.org/mvdbeek/dockertoolfactory/src/d4863bcf7b521532c7e8c61b6333840ba5393f73/DockerToolFactory.py?at=default
12 # passing them is complex 17 # passing them is complex
13 # and they are restricted to NOT contain commas or double quotes to ensure that they can be safely passed together on 18 # and they are restricted to NOT contain commas or double quotes to ensure that they can be safely passed together on
105 debug = False 110 debug = False
106 toolFactoryURL = 'https://bitbucket.org/fubar/galaxytoolfactory' 111 toolFactoryURL = 'https://bitbucket.org/fubar/galaxytoolfactory'
107 112
108 # if we do html we need these dependencies specified in a tool_dependencies.xml file and referred to in the generated 113 # if we do html we need these dependencies specified in a tool_dependencies.xml file and referred to in the generated
109 # tool xml 114 # tool xml
110 toolhtmldepskel = """<?xml version="1.0"?>
111 <tool_dependency>
112 <package name="ghostscript" version="9.10">
113 <repository name="package_ghostscript_9_10" owner="devteam" prior_installation_required="True" />
114 </package>
115 <package name="graphicsmagick" version="1.3.18">
116 <repository name="package_graphicsmagick_1_3" owner="iuc" prior_installation_required="True" />
117 </package>
118 <readme>
119 %s
120 </readme>
121 </tool_dependency>
122 """
123
124 emptytoolhtmldepskel = """<?xml version="1.0"?>
125 <tool_dependency>
126 <readme>
127 %s
128 </readme>
129 </tool_dependency>
130 """
131
132 protorequirements = """<requirements>
133 <requirement type="package" version="9.10">ghostscript</requirement>
134 <requirement type="package" version="1.3.18">graphicsmagick</requirement>
135 </requirements>"""
136 115
137 def timenow(): 116 def timenow():
138 """return current time as a string 117 """return current time as a string
139 """ 118 """
140 return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time())) 119 return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time()))
186 newenv = dict((line.split("=", 1) for line in outl)) 165 newenv = dict((line.split("=", 1) for line in outl))
187 os.environ.update(newenv) 166 os.environ.update(newenv)
188 167
189 class ScriptRunner: 168 class ScriptRunner:
190 """class is a wrapper for an arbitrary script 169 """class is a wrapper for an arbitrary script
170 note funky templating. this should all be done proper.
171 Problem is, this kludge developed quite naturally and seems to work ok with
172 little overhead...
173
191 """ 174 """
175
192 176
193 def __init__(self,opts=None,treatbashSpecial=True): 177 def __init__(self,opts=None,treatbashSpecial=True):
194 """ 178 """
195 cleanup inputs, setup some outputs 179 cleanup inputs, setup some outputs
196 180
197 """ 181 """
182
183 self.toolhtmldepinterpskel = """<?xml version="1.0"?>
184 <tool_dependency>
185 <package name="ghostscript" version="9.10">
186 <repository name="package_ghostscript_9_10" owner="devteam" prior_installation_required="True" />
187 </package>
188 <package name="graphicsmagick" version="1.3.18">
189 <repository name="package_graphicsmagick_1_3" owner="iuc" prior_installation_required="True" />
190 </package>
191 <package name="%(interpreter)s" version="%(interpreter_version)s">
192 <repository name="%(interpreter_name)s" owner="%(interpreter_owner)s" prior_installation_required="True" />
193 </package>
194
195 <readme>
196 %(readme)s
197 </readme>
198 </tool_dependency>
199 """
200
201 self.toolhtmldepskel = """<?xml version="1.0"?>
202 <tool_dependency>
203 <package name="ghostscript" version="9.10">
204 <repository name="package_ghostscript_9_10" owner="devteam" prior_installation_required="True" />
205 </package>
206 <package name="graphicsmagick" version="1.3.18">
207 <repository name="package_graphicsmagick_1_3" owner="iuc" prior_installation_required="True" />
208 </package>
209 <readme>
210 %(readme)s
211 </readme>
212 </tool_dependency>
213 """
214
215 self.emptytoolhtmldepskel = """<?xml version="1.0"?>
216 <tool_dependency>
217 <readme>
218 %(readme)s
219 </readme>
220 </tool_dependency>
221 """
222
223 self.protorequirements = """<requirements>
224 <requirement type="package" version="9.10">ghostscript</requirement>
225 <requirement type="package" version="1.3.18">graphicsmagick</requirement>
226 </requirements>"""
227
228 self.protorequirements_interpreter = """<requirements>
229 <requirement type="package" version="9.10">ghostscript</requirement>
230 <requirement type="package" version="1.3.18">graphicsmagick</requirement>
231 <requirement type="package" version="%(interpreter_version)s">%(interpreter_name)s</requirement>
232 </requirements>"""
233
234
235 self.newCommand="""
236 %(toolname)s.py --script_path "$runMe" --interpreter "%(interpreter)s"
237 --tool_name "%(toolname)s"
238 %(command_inputs)s
239 %(command_outputs)s
240 """
241
242 self.tooltestsTabOnly = """
243 <test>
244 %(test1Inputs)s
245 <param name="job_name" value="test1"/>
246 <param name="runMe" value="$runMe"/>
247 <output name="output1="%(test1Output)s" ftype="tabular"/>
248 %(additionalParams)s
249 </test>
250 """
251
252 self.tooltestsHTMLOnly = """
253 <test>
254 %(test1Inputs)s
255 <param name="job_name" value="test1"/>
256 <param name="runMe" value="$runMe"/>
257 %(additionalParams)s
258 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="5"/>
259 </test>
260 """
261
262 self.tooltestsBoth = """
263 <test>
264 %(test1Inputs)s
265 <param name="job_name" value="test1"/>
266 <param name="runMe" value="$runMe"/>
267 %(additionalParams)s
268 <output name="output1" file="%(test1Output)s" ftype="tabular" />
269 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="10"/>
270 </test>
271 """
272
273 self.newXML="""<tool id="%(toolid)s" name="%(toolname)s" version="%(tool_version)s">
274 %(tooldesc)s
275 %(requirements)s
276 <command interpreter="python">
277 %(command)s
278 </command>
279 <inputs>
280 %(inputs)s
281 %(additionalInputs)s
282 </inputs>
283 <outputs>
284 %(outputs)s
285 </outputs>
286 <configfiles>
287 <configfile name="runMe">
288 %(script)s
289 </configfile>
290 </configfiles>
291 <tests>
292 %(tooltests)s
293 </tests>
294 <help>
295
296 %(help)s
297
298 </help>
299 <citations>
300 %(citations)s
301 <citation type="doi">10.1093/bioinformatics/bts573</citation>
302 </citations>
303 </tool>"""
304
198 self.useGM = cmd_exists('gm') 305 self.useGM = cmd_exists('gm')
199 self.useIM = cmd_exists('convert') 306 self.useIM = cmd_exists('convert')
200 self.useGS = cmd_exists('gs') 307 self.useGS = cmd_exists('gs')
201 self.temp_warned = False # we want only one warning if $TMP not set 308 self.temp_warned = False # we want only one warning if $TMP not set
202 self.treatbashSpecial = treatbashSpecial 309 self.treatbashSpecial = treatbashSpecial
313 a('%s="%s"' % (param,value)) 420 a('%s="%s"' % (param,value))
314 self.cl.insert(4+i,'%s="%s"' % (param,value)) 421 self.cl.insert(4+i,'%s="%s"' % (param,value))
315 else: 422 else:
316 a('%s=%s' % (param,value)) 423 a('%s=%s' % (param,value))
317 self.cl.insert(4+i,'%s=%s' % (param,value)) 424 self.cl.insert(4+i,'%s=%s' % (param,value))
318 425 self.interp_owner = None
319 426 self.interp_pack = None
427 self.interp_revision = None
428 self.interp_version = None
429 if opts.envshpath <> 'system': # need to parse out details for our tool_dependency
430 try:
431 packdetails = opts.envshpath.split(os.path.sep)[-4:-1] # eg ['fubar', 'package_r_3_1_1', '63cdb9b2234c']
432 self.interpreter_owner = packdetails[0]
433 self.interpreter_pack = packdetails[1]
434 self.interpreter_revision = packdetails[2]
435 self.interpreter_version = '.'.join(self.interpreter_pack.split('_')[2:])
436 # hope our naming convention as at jan 2015 = package_[interp]_v0_v1_v2... = version v0.v1.v2.. is in play
437 except:
438 pass
320 self.outFormats = opts.output_format 439 self.outFormats = opts.output_format
321 self.inputFormats = opts.input_formats 440 self.inputFormats = opts.input_formats
322 self.test1Output = '%s_test1_output.xls' % self.toolname 441 self.test1Output = '%s_test1_output.xls' % self.toolname
323 self.test1HTML = '%s_test1_output.html' % self.toolname 442 self.test1HTML = '%s_test1_output.html' % self.toolname
324 443
369 </configfile> 488 </configfile>
370 </configfiles> 489 </configfiles>
371 </tool> 490 </tool>
372 491
373 """ 492 """
374 newXML="""<tool id="%(toolid)s" name="%(toolname)s" version="%(tool_version)s"> 493
375 %(tooldesc)s 494 # these templates need a dict with the right keys to match the parameters - outputs, help, code...
376 %(requirements)s 495
377 <command interpreter="python">
378 %(command)s
379 </command>
380 <inputs>
381 %(inputs)s
382 %(additionalInputs)s
383 </inputs>
384 <outputs>
385 %(outputs)s
386 </outputs>
387 <configfiles>
388 <configfile name="runMe">
389 %(script)s
390 </configfile>
391 </configfiles>
392 <tests>
393 %(tooltests)s
394 </tests>
395 <help>
396
397 %(help)s
398
399 </help>
400 <citations>
401 %(citations)s
402 <citation type="doi">10.1093/bioinformatics/bts573</citation>
403 </citations>
404 </tool>"""
405 # needs a dict with toolname, toolid, interpreter, scriptname, command, inputs as a multi line string ready to write, outputs ditto, help ditto
406
407 newCommand="""
408 %(toolname)s.py --script_path "$runMe" --interpreter "%(interpreter)s"
409 --tool_name "%(toolname)s"
410 %(command_inputs)s
411 %(command_outputs)s
412 """
413 # may NOT be an input or htmlout - appended later
414 tooltestsTabOnly = """
415 <test>
416 %(test1Inputs)s
417 <param name="job_name" value="test1"/>
418 <param name="runMe" value="$runMe"/>
419 <output name="output1="%(test1Output)s" ftype="tabular"/>
420 %(additionalParams)s
421 </test>
422 """
423 tooltestsHTMLOnly = """
424 <test>
425 %(test1Inputs)s
426 <param name="job_name" value="test1"/>
427 <param name="runMe" value="$runMe"/>
428 %(additionalParams)s
429 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="5"/>
430 </test>
431 """
432 tooltestsBoth = """
433 <test>
434 %(test1Inputs)s
435 <param name="job_name" value="test1"/>
436 <param name="runMe" value="$runMe"/>
437 %(additionalParams)s
438 <output name="output1" file="%(test1Output)s" ftype="tabular" />
439 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="10"/>
440 </test>
441 """
442 xdict = {} 496 xdict = {}
443 xdict['additionalParams'] = '' 497 xdict['additionalParams'] = ''
444 xdict['additionalInputs'] = '' 498 xdict['additionalInputs'] = ''
445 if self.opts.additional_parameters: 499 if self.opts.additional_parameters:
446 if self.opts.edit_additional_parameters: # add to new tool form with default value set to original value 500 if self.opts.edit_additional_parameters: # add to new tool form with default value set to original value
447 xdict['additionalInputs'] = '\n'.join(['<param name="%s" value="%s" label="%s" help="%s" type="%s"/>' % \ 501 xdict['additionalInputs'] = '\n'.join(['<param name="%s" value="%s" label="%s" help="%s" type="%s"/>' % \
448 (x.split(',')[0],html_escape(x.split(',')[1]),html_escape(x.split(',')[2]),html_escape(x.split(',')[3]), x.split(',')[4]) for x in self.opts.additional_parameters]) 502 (x.split(',')[0],html_escape(x.split(',')[1]),html_escape(x.split(',')[2]),html_escape(x.split(',')[3]), x.split(',')[4]) for x in self.opts.additional_parameters])
449 xdict['additionalParams'] = '\n'.join(['<param name="%s" value="%s" />' % (x.split(',')[0],html_escape(x.split(',')[1])) for x in self.opts.additional_parameters]) 503 xdict['additionalParams'] = '\n'.join(['<param name="%s" value="%s" />' % (x.split(',')[0],html_escape(x.split(',')[1])) for x in self.opts.additional_parameters])
504 xdict['interpreter_owner'] = self.interpreter_owner
505 xdict['interpreter_version'] = self.interpreter_version
506 xdict['interpreter_name'] = self.interpreter_pack
450 xdict['requirements'] = '' 507 xdict['requirements'] = ''
451 if self.opts.make_HTML: 508 if self.opts.include_dependencies == "yes":
452 if self.opts.include_dependencies == "yes": 509 if self.opts.envshpath <> 'system':
453 xdict['requirements'] = protorequirements 510 xdict['requirements'] = self.protorequirements_interpreter % xdict
511 else:
512 xdict['requirements'] = self.protorequirements
454 xdict['tool_version'] = self.opts.tool_version 513 xdict['tool_version'] = self.opts.tool_version
455 xdict['test1HTML'] = self.test1HTML 514 xdict['test1HTML'] = self.test1HTML
456 xdict['test1Output'] = self.test1Output 515 xdict['test1Output'] = self.test1Output
457 xdict['test1Inputs'] = self.test1Inputs 516 xdict['test1Inputs'] = self.test1Inputs
458 if self.opts.make_HTML and self.opts.output_tab: 517 if self.opts.make_HTML and self.opts.output_tab:
459 xdict['tooltests'] = tooltestsBoth % xdict 518 xdict['tooltests'] = self.tooltestsBoth % xdict
460 elif self.opts.make_HTML: 519 elif self.opts.make_HTML:
461 xdict['tooltests'] = tooltestsHTMLOnly % xdict 520 xdict['tooltests'] = self.tooltestsHTMLOnly % xdict
462 else: 521 else:
463 xdict['tooltests'] = tooltestsTabOnly % xdict 522 xdict['tooltests'] = self.tooltestsTabOnly % xdict
464 xdict['script'] = self.escapedScript 523 xdict['script'] = self.escapedScript
465 # configfile is least painful way to embed script to avoid external dependencies 524 # configfile is least painful way to embed script to avoid external dependencies
466 # but requires escaping of <, > and $ to avoid Mako parsing 525 # but requires escaping of <, > and $ to avoid Mako parsing
467 if self.opts.help_text: 526 if self.opts.help_text:
468 helptext = open(self.opts.help_text,'r').readlines() 527 helptext = open(self.opts.help_text,'r').readlines()
518 else: 577 else:
519 xdict['command_outputs'] += ' --output_dir "./"' 578 xdict['command_outputs'] += ' --output_dir "./"'
520 if self.opts.output_tab: 579 if self.opts.output_tab:
521 xdict['command_outputs'] += ' --output_tab "$output1"' 580 xdict['command_outputs'] += ' --output_tab "$output1"'
522 xdict['outputs'] += ' <data format="%s" name="output1" label="${job_name}"/>\n' % self.outFormats 581 xdict['outputs'] += ' <data format="%s" name="output1" label="${job_name}"/>\n' % self.outFormats
523 xdict['command'] = newCommand % xdict 582 xdict['command'] = self.newCommand % xdict
524 if self.opts.citations: 583 if self.opts.citations:
525 citationstext = open(self.opts.citations,'r').read() 584 citationstext = open(self.opts.citations,'r').read()
526 citation_tuples = parse_citations(citationstext) 585 citation_tuples = parse_citations(citationstext)
527 citations_xml = "" 586 citations_xml = ""
528 for citation_type, citation_content in citation_tuples: 587 for citation_type, citation_content in citation_tuples:
529 citation_xml = """<citation type="%s">%s</citation>""" % (citation_type, html_escape(citation_content)) 588 citation_xml = """<citation type="%s">%s</citation>""" % (citation_type, html_escape(citation_content))
530 citations_xml += citation_xml 589 citations_xml += citation_xml
531 xdict['citations'] = citations_xml 590 xdict['citations'] = citations_xml
532 else: 591 else:
533 xdict['citations'] = "" 592 xdict['citations'] = ""
534 xmls = newXML % xdict 593 xmls = self.newXML % xdict
535 xf = open(self.xmlfile,'w') 594 xf = open(self.xmlfile,'w')
536 xf.write(xmls) 595 xf.write(xmls)
537 xf.write('\n') 596 xf.write('\n')
538 xf.close() 597 xf.close()
539 # ready for the tarball 598 # ready for the tarball
553 self.makeXML() 612 self.makeXML()
554 if self.opts.help_text: 613 if self.opts.help_text:
555 hlp = open(self.opts.help_text,'r').read() 614 hlp = open(self.opts.help_text,'r').read()
556 else: 615 else:
557 hlp = 'Please ask the tool author for help as none was supplied at tool generation\n' 616 hlp = 'Please ask the tool author for help as none was supplied at tool generation\n'
617 readme_dict = {'readme':hlp,'interpreter':self.opts.interpreter,'interpreter_version':self.interpreter_version,'interpreter_name':self.interpreter_pack,
618 'interpreter_owner':self.interpreter_owner}
558 if self.opts.include_dependencies == "yes": 619 if self.opts.include_dependencies == "yes":
559 tooldepcontent = toolhtmldepskel % hlp 620 if self.opts.envshpath == 'system':
560 else: 621 tooldepcontent = self.toolhtmldepskel % readme_dict
561 tooldepcontent = emptytoolhtmldepskel % hlp 622 else:
623 tooldepcontent = self.toolhtmldepinterpskel % readme_dict
624 else:
625 tooldepcontent = self.emptytoolhtmldepskel % readme_dictls -l
562 depf = open(os.path.join(tdir,'tool_dependencies.xml'),'w') 626 depf = open(os.path.join(tdir,'tool_dependencies.xml'),'w')
563 depf.write(tooldepcontent) 627 depf.write(tooldepcontent)
564 depf.write('\n') 628 depf.write('\n')
565 depf.close() 629 depf.close()
566 if self.opts.input_tab: # no reproducible test otherwise? TODO: maybe.. 630 if self.opts.input_tab: # no reproducible test otherwise? TODO: maybe..