comparison rgedgeR/rgToolFactory.py @ 0:2122e630b13a draft

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