comparison fubar-galaxytoolfactory-58871556de57/rgToolFactory.py @ 6:cb4937b0c21d draft

This fixes a problem reported by Carlos with perl scripts - now use CDATA segments to protect that horrible syntax from Cheetah - seems to work properly now.
author fubar
date Sun, 24 Feb 2013 17:15:29 -0500
parents
children
comparison
equal deleted inserted replaced
5:a90a05c309d3 6:cb4937b0c21d
1 # rgToolFactory.py
2 # see https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home
3 #
4 # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
5 #
6 # all rights reserved
7 # Licensed under the LGPL
8 # suggestions for improvement and bug fixes welcome at https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home
9 #
10 # January 2013
11 # problem pointed out by Carlos Borroto
12 # added escaping for <>$ - thought I did that ages ago...
13 #
14 # August 11 2012
15 # changed to use shell=False and cl as a sequence
16
17 # This is a Galaxy tool factory for simple scripts in python, R or whatever ails ye.
18 # It also serves as the wrapper for the new tool.
19 #
20 # you paste and run your script
21 # Only works for simple scripts that read one input from the history.
22 # Optionally can write one new history dataset,
23 # and optionally collect any number of outputs into links on an autogenerated HTML page.
24
25 # DO NOT install on a public or important site - please.
26
27 # installed generated tools are fine if the script is safe.
28 # They just run normally and their user cannot do anything unusually insecure
29 # but please, practice safe toolshed.
30 # Read the fucking code before you install any tool
31 # especially this one
32
33 # After you get the script working on some test data, you can
34 # optionally generate a toolshed compatible gzip file
35 # containing your script safely wrapped as an ordinary Galaxy script in your local toolshed for
36 # safe and largely automated installation in a production Galaxy.
37
38 # If you opt for an HTML output, you get all the script outputs arranged
39 # as a single Html history item - all output files are linked, thumbnails for all the pdfs.
40 # Ugly but really inexpensive.
41 #
42 # Patches appreciated please.
43 #
44 #
45 # long route to June 2012 product
46 # Behold the awesome power of Galaxy and the toolshed with the tool factory to bind them
47 # derived from an integrated script model
48 # called rgBaseScriptWrapper.py
49 # Note to the unwary:
50 # This tool allows arbitrary scripting on your Galaxy as the Galaxy user
51 # There is nothing stopping a malicious user doing whatever they choose
52 # Extremely dangerous!!
53 # Totally insecure. So, trusted users only
54 #
55 # preferred model is a developer using their throw away workstation instance - ie a private site.
56 # no real risk. The universe_wsgi.ini admin_users string is checked - only admin users are permitted to run this tool.
57 #
58
59 import sys
60 import shutil
61 import subprocess
62 import os
63 import time
64 import tempfile
65 import optparse
66 import tarfile
67 import re
68 import shutil
69 import math
70
71 progname = os.path.split(sys.argv[0])[1]
72 myversion = 'V000.2 June 2012'
73 verbose = False
74 debug = False
75 toolFactoryURL = 'https://bitbucket.org/fubar/galaxytoolfactory'
76
77 def timenow():
78 """return current time as a string
79 """
80 return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time()))
81
82 cheetah_escape_table = {
83 "$": "\$"
84 }
85
86 cheetah_unescape_table = {
87 "\$": "$"
88 }
89
90 def html_escape(t):
91 """Unescape \$ first in case already done
92 cheetah barfs if any $ without \
93 xml parsing is controlled with <![CDATA[...]]>
94 """
95 text = t
96 for k in cheetah_unescape_table.keys():
97 text = text.replace(k,cheetah_unescape_table[k])
98 for k in cheetah_escape_table.keys():
99 text = text.replace(k,cheetah_escape_table[k])
100 return text
101
102
103 class ScriptRunner:
104 """class is a wrapper for an arbitrary script
105 """
106
107 def __init__(self,opts=None,treatbashSpecial=True):
108 """
109 cleanup inputs, setup some outputs
110
111 """
112 self.treatbashSpecial = treatbashSpecial
113 if opts.output_dir: # simplify for the tool tarball
114 os.chdir(opts.output_dir)
115 self.thumbformat = 'jpg'
116 self.opts = opts
117 self.toolname = re.sub('[^a-zA-Z0-9_]+', '', opts.tool_name) # a sanitizer now does this but..
118 self.toolid = self.toolname
119 self.myname = sys.argv[0] # get our name because we write ourselves out as a tool later
120 self.pyfile = self.myname # crude but efficient - the cruft won't hurt much
121 self.xmlfile = '%s.xml' % self.toolname
122 s = open(self.opts.script_path,'r').readlines()
123 s = [x.rstrip() for x in s] # remove pesky dos line endings if needed
124 self.script = '\n'.join(s)
125 fhandle,self.sfile = tempfile.mkstemp(prefix=self.toolname,suffix=".%s" % (opts.interpreter))
126 tscript = open(self.sfile,'w') # use self.sfile as script source for Popen
127 tscript.write(self.script)
128 tscript.close()
129 self.escapedS = [html_escape(x) for x in s] # for restructured text in help
130 self.escapedScript = '\n'.join(self.escapedS)
131 self.indentedScript = '\n'.join([' %s' % x for x in s]) # for restructured text in help
132 if opts.output_dir: # may not want these complexities
133 self.tlog = os.path.join(opts.output_dir,"%s_runner.log" % self.toolname)
134 art = '%s.%s' % (self.toolname,opts.interpreter)
135 artpath = os.path.join(self.opts.output_dir,art) # need full path
136 artifact = open(artpath,'w') # use self.sfile as script source for Popen
137 artifact.write(self.script)
138 artifact.close()
139 self.cl = []
140 self.html = []
141 a = self.cl.append
142 a(opts.interpreter)
143 if self.treatbashSpecial and opts.interpreter in ['bash','sh']:
144 a(self.sfile)
145 else:
146 a('-') # stdin
147 a(opts.input_tab)
148 a(opts.output_tab)
149 self.outFormats = 'tabular' # TODO make this an option at tool generation time
150 self.inputFormats = 'tabular' # TODO make this an option at tool generation time
151 self.test1Input = '%s_test1_input.xls' % self.toolname
152 self.test1Output = '%s_test1_output.xls' % self.toolname
153 self.test1HTML = '%s_test1_output.html' % self.toolname
154
155 def makeXML(self):
156 """
157 Create a Galaxy xml tool wrapper for the new script as a string to write out
158 fixme - use templating or something less fugly than this example of what we produce
159
160 <tool id="reverse" name="reverse" version="0.01">
161 <description>a tabular file</description>
162 <command interpreter="python">
163 reverse.py --script_path "$runMe" --interpreter "python"
164 --tool_name "reverse" --input_tab "$input1" --output_tab "$tab_file"
165 </command>
166 <inputs>
167 <param name="input1" type="data" format="tabular" label="Select a suitable input file from your history"/><param name="job_name" type="text" label="Supply a name for the outputs to remind you what they contain" value="reverse"/>
168
169 </inputs>
170 <outputs>
171 <data format="tabular" name="tab_file" label="${job_name}"/>
172
173 </outputs>
174 <help>
175
176 **What it Does**
177
178 Reverse the columns in a tabular file
179
180 </help>
181 <configfiles>
182 <configfile name="runMe">
183
184 # reverse order of columns in a tabular file
185 import sys
186 inp = sys.argv[1]
187 outp = sys.argv[2]
188 i = open(inp,'r')
189 o = open(outp,'w')
190 for row in i:
191 rs = row.rstrip().split('\t')
192 rs.reverse()
193 o.write('\t'.join(rs))
194 o.write('\n')
195 i.close()
196 o.close()
197
198
199 </configfile>
200 </configfiles>
201 </tool>
202
203 """
204 newXML="""<tool id="%(toolid)s" name="%(toolname)s" version="%(tool_version)s">
205 %(tooldesc)s
206 %(command)s
207 <inputs>
208 %(inputs)s
209 </inputs>
210 <outputs>
211 %(outputs)s
212 </outputs>
213 <configfiles>
214 <configfile name="runMe">
215 <![CDATA[
216 %(script)s
217 ]]>
218 </configfile>
219 </configfiles>
220 %(tooltests)s
221 <help>
222 <![CDATA[
223 %(help)s
224 ]]>
225
226 </help>
227 </tool>"""
228 # needs a dict with toolname, toolid, interpreter, scriptname, command, inputs as a multi line string ready to write, outputs ditto, help ditto
229
230 newCommand="""<command interpreter="python">
231 %(toolname)s.py --script_path "$runMe" --interpreter "%(interpreter)s"
232 --tool_name "%(toolname)s" %(command_inputs)s %(command_outputs)s
233 </command>""" # may NOT be an input or htmlout
234 tooltestsTabOnly = """<tests><test>
235 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
236 <param name="job_name" value="test1"/>
237 <param name="runMe" value="$runMe"/>
238 <output name="tab_file" file="%(test1Output)s" ftype="tabular"/>
239 </test></tests>"""
240 tooltestsHTMLOnly = """<tests><test>
241 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
242 <param name="job_name" value="test1"/>
243 <param name="runMe" value="$runMe"/>
244 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="5"/>
245 </test></tests>"""
246 tooltestsBoth = """<tests><test>
247 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
248 <param name="job_name" value="test1"/>
249 <param name="runMe" value="$runMe"/>
250 <output name="tab_file" file="%(test1Output)s" ftype="tabular" />
251 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="10"/>
252 </test></tests>"""
253 xdict = {}
254 xdict['tool_version'] = self.opts.tool_version
255 xdict['test1Input'] = self.test1Input
256 xdict['test1HTML'] = self.test1HTML
257 xdict['test1Output'] = self.test1Output
258 if self.opts.make_HTML and self.opts.output_tab <> 'None':
259 xdict['tooltests'] = tooltestsBoth % xdict
260 elif self.opts.make_HTML:
261 xdict['tooltests'] = tooltestsHTMLOnly % xdict
262 else:
263 xdict['tooltests'] = tooltestsTabOnly % xdict
264 xdict['script'] = self.escapedScript
265 # configfile is least painful way to embed script to avoid external dependencies
266 # but requires escaping of <, > and $ to avoid Mako parsing
267 if self.opts.help_text:
268 xdict['help'] = open(self.opts.help_text,'r').read()
269 else:
270 xdict['help'] = 'Please ask the tool author for help as none was supplied at tool generation\n'
271 coda = ['**Script**','Pressing execute will run the following code over your input file and generate some outputs in your history::\n']
272 coda.append(self.indentedScript)
273 coda.append('\n\n')
274 coda.append('**Attribution** This Galaxy tool was created by %s at %s\nusing the Galaxy Tool Factory.' % (self.opts.user_email,timenow()))
275 coda.append('See %s for details of that project' % (toolFactoryURL))
276 coda.append('Please cite: Creating re-usable tools from scripts: The Galaxy Tool Factory. Ross Lazarus; Antony Kaspi; Mark Ziemann; The Galaxy Team. ')
277 coda.append('Bioinformatics 2012; doi: 10.1093/bioinformatics/bts573')
278 xdict['help'] = '%s\n\n%s\n\n' % (xdict['help'],'\n'.join(coda))
279 if self.opts.tool_desc:
280 xdict['tooldesc'] = '<description>%s</description>' % self.opts.tool_desc
281 else:
282 xdict['tooldesc'] = ''
283 xdict['command_outputs'] = ''
284 xdict['outputs'] = ''
285 if self.opts.input_tab <> 'None':
286 xdict['command_inputs'] = '--input_tab "$input1" ' # the space may matter a lot if we append something
287 xdict['inputs'] = '<param name="input1" type="data" format="%s" label="Select a suitable input file from your history"/> \n' % self.inputFormats
288 else:
289 xdict['command_inputs'] = '' # assume no input - eg a random data generator
290 xdict['inputs'] = ''
291 xdict['inputs'] += '<param name="job_name" type="text" label="Supply a name for the outputs to remind you what they contain" value="%s"/> \n' % self.toolname
292 xdict['toolname'] = self.toolname
293 xdict['toolid'] = self.toolid
294 xdict['interpreter'] = self.opts.interpreter
295 xdict['scriptname'] = self.sfile
296 if self.opts.make_HTML:
297 xdict['command_outputs'] += ' --output_dir "$html_file.files_path" --output_html "$html_file" --make_HTML "yes" '
298 xdict['outputs'] += ' <data format="html" name="html_file" label="${job_name}.html"/>\n'
299 if self.opts.output_tab <> 'None':
300 xdict['command_outputs'] += ' --output_tab "$tab_file"'
301 xdict['outputs'] += ' <data format="%s" name="tab_file" label="${job_name}"/>\n' % self.outFormats
302 xdict['command'] = newCommand % xdict
303 xmls = newXML % xdict
304 xf = open(self.xmlfile,'w')
305 xf.write(xmls)
306 xf.write('\n')
307 xf.close()
308 # ready for the tarball
309
310
311 def makeTooltar(self):
312 """
313 a tool is a gz tarball with eg
314 /toolname/tool.xml /toolname/tool.py /toolname/test-data/test1_in.foo ...
315 """
316 retval = self.run()
317 if retval:
318 print >> sys.stderr,'## Run failed. Cannot build yet. Please fix and retry'
319 sys.exit(1)
320 self.makeXML()
321 tdir = self.toolname
322 os.mkdir(tdir)
323 if self.opts.input_tab <> 'None': # no reproducible test otherwise? TODO: maybe..
324 testdir = os.path.join(tdir,'test-data')
325 os.mkdir(testdir) # make tests directory
326 shutil.copyfile(self.opts.input_tab,os.path.join(testdir,self.test1Input))
327 if self.opts.output_tab <> 'None':
328 shutil.copyfile(self.opts.output_tab,os.path.join(testdir,self.test1Output))
329 if self.opts.make_HTML:
330 shutil.copyfile(self.opts.output_html,os.path.join(testdir,self.test1HTML))
331 if self.opts.output_dir:
332 shutil.copyfile(self.tlog,os.path.join(testdir,'test1_out.log'))
333 op = '%s.py' % self.toolname # new name
334 outpiname = os.path.join(tdir,op) # path for the tool tarball
335 pyin = os.path.basename(self.pyfile) # our name - we rewrite ourselves (TM)
336 notes = ['# %s - a self annotated version of %s generated by running %s\n' % (op,pyin,pyin),]
337 notes.append('# to make a new Galaxy tool called %s\n' % self.toolname)
338 notes.append('# User %s at %s\n' % (self.opts.user_email,timenow()))
339 pi = open(self.pyfile,'r').readlines() # our code becomes new tool wrapper (!) - first Galaxy worm
340 notes += pi
341 outpi = open(outpiname,'w')
342 outpi.write(''.join(notes))
343 outpi.write('\n')
344 outpi.close()
345 stname = os.path.join(tdir,self.sfile)
346 if not os.path.exists(stname):
347 shutil.copyfile(self.sfile, stname)
348 xtname = os.path.join(tdir,self.xmlfile)
349 if not os.path.exists(xtname):
350 shutil.copyfile(self.xmlfile,xtname)
351 tarpath = "%s.gz" % self.toolname
352 tar = tarfile.open(tarpath, "w:gz")
353 tar.add(tdir,arcname=self.toolname)
354 tar.close()
355 shutil.copyfile(tarpath,self.opts.new_tool)
356 shutil.rmtree(tdir)
357 ## TODO: replace with optional direct upload to local toolshed?
358 return retval
359
360 def compressPDF(self,inpdf=None,thumbformat='png'):
361 """need absolute path to pdf
362 """
363 assert os.path.isfile(inpdf), "## Input %s supplied to %s compressPDF not found" % (inpdf,self.myName)
364 hf,hlog = tempfile.mkstemp(suffix="%s.log" % self.toolname)
365 sto = open(hlog,'w')
366 outpdf = '%s_compressed' % inpdf
367 cl = ["gs", "-sDEVICE=pdfwrite", "-dNOPAUSE", "-dBATCH", "-sOutputFile=%s" % outpdf,inpdf]
368 x = subprocess.Popen(cl,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
369 retval1 = x.wait()
370 if retval1 == 0:
371 os.unlink(inpdf)
372 shutil.move(outpdf,inpdf)
373 outpng = '%s.%s' % (os.path.splitext(inpdf)[0],thumbformat)
374 cl2 = ['convert', inpdf, outpng]
375 x = subprocess.Popen(cl2,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
376 retval2 = x.wait()
377 sto.close()
378 retval = retval1 or retval2
379 return retval
380
381
382 def getfSize(self,fpath,outpath):
383 """
384 format a nice file size string
385 """
386 size = ''
387 fp = os.path.join(outpath,fpath)
388 if os.path.isfile(fp):
389 size = '0 B'
390 n = float(os.path.getsize(fp))
391 if n > 2**20:
392 size = '%1.1f MB' % (n/2**20)
393 elif n > 2**10:
394 size = '%1.1f KB)' % (n/2**10)
395 elif n > 0:
396 size = '%d B' % (int(n))
397 return size
398
399 def makeHtml(self):
400 """ Create an HTML file content to list all the artifacts found in the output_dir
401 """
402
403 galhtmlprefix = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
404 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
405 <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
406 <meta name="generator" content="Galaxy %s tool output - see http://g2.trac.bx.psu.edu/" />
407 <title></title>
408 <link rel="stylesheet" href="/static/style/base.css" type="text/css" />
409 </head>
410 <body>
411 <div class="toolFormBody">
412 """
413 galhtmlattr = """<hr/><div class="infomessage">This tool (%s) was generated by the <a href="https://bitbucket.org/fubar/galaxytoolfactory/overview">Galaxy Tool Factory</a></div><br/>"""
414 galhtmlpostfix = """</div></body></html>\n"""
415
416 flist = os.listdir(self.opts.output_dir)
417 flist = [x for x in flist if x <> 'Rplots.pdf']
418 flist.sort()
419 html = []
420 html.append(galhtmlprefix % progname)
421 html.append('<div class="infomessage">Galaxy Tool "%s" run at %s</div><br/>' % (self.toolname,timenow()))
422 fhtml = []
423 if len(flist) > 0:
424 pdflist = []
425 npdf = len([x for x in flist if os.path.splitext(x)[-1].lower() == '.pdf'])
426 nacross = 1
427 if npdf > 0:
428 nacross = int(round(math.log(npdf,2)))
429 nacross = max(1,nacross)
430 width = min(400,int(1200/nacross))
431 for rownum,fname in enumerate(flist):
432 dname,e = os.path.splitext(fname)
433 sfsize = self.getfSize(fname,self.opts.output_dir)
434 if e.lower() == '.pdf' : # compress and make a thumbnail
435 thumb = '%s.%s' % (dname,self.thumbformat)
436 pdff = os.path.join(self.opts.output_dir,fname)
437 retval = self.compressPDF(inpdf=pdff,thumbformat=self.thumbformat)
438 if retval == 0:
439 pdflist.append((fname,thumb))
440 if (rownum+1) % 2 == 0:
441 fhtml.append('<tr class="odd_row"><td><a href="%s">%s</a></td><td>%s</td></tr>' % (fname,fname,sfsize))
442 else:
443 fhtml.append('<tr><td><a href="%s">%s</a></td><td>%s</td></tr>' % (fname,fname,sfsize))
444 ntogo = nacross # counter for table row padding with empty cells
445 if len(pdflist) > 0:
446 html.append('<div><table class="simple" cellpadding="2" cellspacing="2">\n<tr>')
447 for i,paths in enumerate(pdflist):
448 fname,thumb = paths
449 s= """<td><a href="%s"><img src="%s" title="Click to download a PDF of %s" hspace="5" width="%d"
450 alt="Image called %s"/></a></td>\n""" % (fname,thumb,fname,width,fname)
451 if ((i+1) % nacross == 0):
452 s += '</tr>\n'
453 ntogo = 0
454 if i < (npdf - 1): # more to come
455 s += '<tr>'
456 ntogo = nacross
457 else:
458 ntogo -= 1
459 html.append(s)
460 if html[-1].strip().endswith('</tr>'):
461 html.append('</table></div>\n')
462 else:
463 if ntogo > 0: # pad
464 html.append('<td>&nbsp;</td>'*ntogo)
465 html.append('</tr></table></div>\n')
466 if len(fhtml) > 0:
467 fhtml.insert(0,'<div><table class="colored" cellpadding="3" cellspacing="3"><tr><th>Output File Name (click to view)</th><th>Size</th></tr>\n')
468 fhtml.append('</table></div><br/>')
469 html += fhtml # add all non-pdf files to the end of the display
470 else:
471 html.append('<div class="warningmessagelarge">### Error - %s returned no files - please confirm that parameters are sane</div>' % self.opts.interpreter)
472 rlog = open(self.tlog,'r').readlines()
473 rlog = [x for x in rlog if x.strip() > '']
474 if len(rlog) > 1:
475 html.append('<div class="toolFormTitle">%s log</div><pre>\n' % self.opts.interpreter)
476 html += rlog
477 html.append('</pre>\n')
478 html.append(galhtmlattr % (self.toolname))
479 html.append(galhtmlpostfix)
480 htmlf = file(self.opts.output_html,'w')
481 htmlf.write('\n'.join(html))
482 htmlf.write('\n')
483 htmlf.close()
484 self.html = html
485
486
487 def run(self):
488 """
489 scripts must be small enough not to fill the pipe!
490 """
491 if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']:
492 retval = self.runBash()
493 else:
494 if self.opts.output_dir:
495 sto = open(self.tlog,'w')
496 sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl))
497 sto.flush()
498 p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,stdin=subprocess.PIPE,cwd=self.opts.output_dir)
499 else:
500 p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE)
501 p.stdin.write(self.script)
502 p.stdin.close()
503 retval = p.wait()
504 if self.opts.output_dir:
505 sto.close()
506 if self.opts.make_HTML:
507 self.makeHtml()
508 return retval
509
510 def runBash(self):
511 """
512 cannot use - for bash so use self.sfile
513 """
514 if self.opts.output_dir:
515 s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl)
516 sto = open(self.tlog,'w')
517 sto.write(s)
518 sto.flush()
519 p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
520 else:
521 p = subprocess.Popen(self.cl,shell=False)
522 retval = p.wait()
523 if self.opts.output_dir:
524 sto.close()
525 if self.opts.make_HTML:
526 self.makeHtml()
527 return retval
528
529
530 def main():
531 u = """
532 This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as:
533 <command interpreter="python">rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript"
534 </command>
535 """
536 op = optparse.OptionParser()
537 a = op.add_option
538 a('--script_path',default=None)
539 a('--tool_name',default=None)
540 a('--interpreter',default=None)
541 a('--output_dir',default=None)
542 a('--output_html',default=None)
543 a('--input_tab',default="None")
544 a('--output_tab',default="None")
545 a('--user_email',default='Unknown')
546 a('--bad_user',default=None)
547 a('--make_Tool',default=None)
548 a('--make_HTML',default=None)
549 a('--help_text',default=None)
550 a('--tool_desc',default=None)
551 a('--new_tool',default=None)
552 a('--tool_version',default=None)
553 opts, args = op.parse_args()
554 assert not opts.bad_user,'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to admin_users in universe_wsgi.ini' % (opts.bad_user,opts.bad_user)
555 assert opts.tool_name,'## Tool Factory expects a tool name - eg --tool_name=DESeq'
556 assert opts.interpreter,'## Tool Factory wrapper expects an interpreter - eg --interpreter=Rscript'
557 assert os.path.isfile(opts.script_path),'## Tool Factory wrapper expects a script path - eg --script_path=foo.R'
558 if opts.output_dir:
559 try:
560 os.makedirs(opts.output_dir)
561 except:
562 pass
563 r = ScriptRunner(opts)
564 if opts.make_Tool:
565 retcode = r.makeTooltar()
566 else:
567 retcode = r.run()
568 os.unlink(r.sfile)
569 if retcode:
570 sys.exit(retcode) # indicate failure to job runner
571
572
573 if __name__ == "__main__":
574 main()
575
576