Mercurial > repos > fubar > tool_factory_2
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.. |
