comparison tools/ilmn_pacbio/smrtpipe_galaxy.py @ 0:9071e359b9a3

Uploaded
author xuebing
date Fri, 09 Mar 2012 19:37:19 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:9071e359b9a3
1 #!/usr/bin/python
2 import sys
3 import os
4 import subprocess
5 import optparse as op
6 import xml.etree.cElementTree as et
7
8 TRACE=False
9 #
10 # Turn on tracing to dump out __input__.xml and __settings__.xml somewhere
11 #
12 #TRACE=True
13 #TRACE_PATH='/home/UNIXHOME/jsorenson'
14
15 class SmrtpipeGalaxy:
16 """Wrapper for running smrtpipe under galaxy"""
17 def __init__( self, argv ):
18 self.__parseOptions( argv )
19
20 def __parseOptions( self, argv ):
21 usage = 'Usage: %prog [--help] [options] smrtpipe.ini'
22 parser = op.OptionParser( usage=usage, description=SmrtpipeGalaxy.__doc__ )
23 parser.add_option( "--output",
24 help="Designate a file generated by smrtpipe as the expected output for galaxy" )
25 parser.add_option( "--nproc", type="int",
26 help="Number of processes to use (-D NPROC)" )
27 parser.add_option( "--galaxy_output",
28 help="File name provided by galaxy where output should be placed" )
29 parser.add_option( "--dry_run", action="store_true",
30 help="Create auxiliary XML files and exit" )
31 parser.add_option( "--dat_extension",
32 help="Soft link .dat files to have this extension (some pipelines require certain extensions)" )
33
34 parser.set_defaults( output=None, dry_run=False, galaxy_output=None,
35 dat_extension=None, nproc=0 )
36 self.options, self.args = parser.parse_args( argv )
37
38 if len(self.args)!=2:
39 parser.error( 'Expected 1 argument' )
40
41 self.configFile = self.args[1]
42
43 def __parseConfig( self ):
44 infile = open( self.configFile, 'r' )
45 section = None
46 sections = []
47 for line in infile:
48 l = line.strip()
49 if len(l)==0 or line.startswith('#'):
50 continue
51 if l.startswith('[') and l.endswith(']'):
52 section = section_factory( l[1:-1] )
53 sections.append(section)
54 continue
55 if section is None:
56 continue
57 if '=' in l:
58 section.addParameterLine(l)
59 else:
60 section.addLine(l)
61 infile.close()
62 return sections
63
64 def transferOutput( self ):
65 if not self.options.output or not self.options.galaxy_output:
66 return True, ''
67 if not os.path.exists(self.options.output):
68 return False, "Can't find file %s (job error?)" % self.options.output
69 os.system( 'cp %s %s' % (self.options.output, self.options.galaxy_output ))
70 return True, ''
71
72 def run( self ):
73 if not os.path.exists( self.configFile ):
74 print >>sys.stderr, "Can't find config file %s" % self.configFile
75 return 1
76
77 sections = self.__parseConfig()
78
79 if len(sections)==0:
80 print >>sys.stderr, "No sections found in %s" % self.configFile
81 return 1
82 if sections[0].name != 'input':
83 print >>sys.stderr, "No [input] section found in %s" % self.configFile
84 return 1
85
86 INPUT_FILE = '__input__.xml'
87 SETTINGS_FILE = '__settings__.xml'
88
89 sections[0].softLinkDats( self.options.dat_extension )
90 inputXml = sections[0].makeXmlElement()
91 write_xml_to_file( INPUT_FILE, inputXml )
92 if TRACE:
93 write_xml_to_file( os.path.join(TRACE_PATH,INPUT_FILE), inputXml )
94
95 settings = et.Element( 'smrtpipeSettings' )
96 for s in sections[1:]:
97 s.makeXmlElement( settings )
98
99 write_xml_to_file( SETTINGS_FILE, settings )
100 if TRACE:
101 write_xml_to_file( os.path.join(TRACE_PATH,SETTINGS_FILE), settings )
102
103 nproc = '-D NPROC=%d' % self.options.nproc if self.options.nproc>0 else ''
104 cmd = 'smrtpipe.py %s --params=%s xml:%s > smrtpipe.err 2>1' % \
105 ( nproc, SETTINGS_FILE, INPUT_FILE )
106
107 if self.options.dry_run:
108 print 'Command to run:'
109 print cmd
110 return 0
111
112 out, errCode, errMsg = backticks( cmd )
113 if errCode!=0:
114 print >>sys.stderr, "error while running: %s" % cmd
115 print >>sys.stderr, errMsg
116 if os.path.exists('log/smrtpipe.log'):
117 print >>sys.stderr, 'Log:'
118 infile = open('log/smrtpipe.log','r')
119 for line in infile: sys.stderr.write(line)
120 infile.close()
121 return errCode
122
123 success, errMsg = self.transferOutput()
124 if not success:
125 print >>sys.stderr, errMsg
126 return 1
127
128 return 0
129
130 def write_xml_to_file( fileName, root ):
131 outfile = open( fileName, 'w' )
132 outfile.write( '<?xml version="1.0"?>\n' )
133 outfile.write( et.tostring(root) + '\n' )
134 outfile.close()
135
136 def section_factory( name ):
137 if name=='input':
138 return InputSection(name)
139 else:
140 return Section(name)
141
142 class Section:
143 def __init__( self, name ):
144 self._name = name
145 self._lines = []
146 self._vars = {}
147
148 @property
149 def name(self):
150 return self._name
151
152 def addLine( self, line ):
153 self._lines.append(line)
154
155 def addParameterLine( self, line ):
156 self.addLine(line)
157 i = line.find( '=' )
158 key = line[:i].strip()
159 value = line[i+1:].strip()
160 self._vars[key] = value
161
162 def makeXmlElement( self, settings ):
163 if self._name=='global':
164 root = et.SubElement( settings, "protocol", {'name':'generic'} )
165 else:
166 root = et.SubElement( settings, "module", {'name':self._name} )
167 for k,v in self._vars.iteritems():
168 param = et.SubElement( root, 'param', {'name':k} )
169 val = et.SubElement( param, 'value' )
170 val.text = v
171 return None
172
173 def __str__( self ):
174 "for debugging"
175 buffer = [ 'S { name=' ]
176 buffer.append(self._name)
177 buffer.append('; lines=%s' % ','.join(self._lines) )
178 for k,v in self._vars.iteritems():
179 buffer.append('; %s=%s' % (k,v) )
180 buffer.append(' }')
181 return ''.join(buffer)
182
183 class InputSection( Section ):
184 def __init__( self, name ):
185 Section.__init__(self,name)
186
187 def softLinkDats( self, newExtension ):
188 if not newExtension:
189 return
190 newLines = []
191 for l in self._lines:
192 if ':' in l:
193 protocol = l[:l.find(':')+1]
194 file = l[l.find(':')+1:]
195 else:
196 protocol = ''
197 file = l
198 if os.path.exists(file) and file.endswith('.dat'):
199 newFile = '%s.%s' % ( file, newExtension )
200 if not os.path.exists(newFile):
201 os.system( 'ln -s %s %s' % ( file, newFile ) )
202 newLines.append(protocol+newFile)
203 else:
204 newLines.append(l)
205 self._lines = newLines
206
207 def makeXmlElement( self, parent=None ):
208 root = et.Element( "pacbioAnalysisInputs" )
209 data = et.SubElement( root, 'dataReferences' )
210 iRef = 0
211 for l in self._lines:
212 def add(x,iRef):
213 if len(x)==0: return iRef
214 node = et.SubElement( data, 'url' )
215 if ':' in x:
216 node.attrib[ 'ref' ] = x
217 else:
218 node.attrib[ 'ref' ] = 'run:0000000-%04d' % iRef
219 node2 = et.SubElement( node, 'location' )
220 node2.text = x
221 return iRef+1
222 if l.endswith('fofn') and os.path.exists(l):
223 infile = open(l,'r')
224 for j,line in enumerate(infile): iRef=add(line.strip(),iRef)
225 infile.close()
226 else:
227 iRef=add(l,iRef)
228 return root
229
230 def backticks( cmd, merge_stderr=True ):
231 """
232 Simulates the perl backticks (``) command with error-handling support
233 Returns ( command output as sequence of strings, error code, error message )
234 """
235 if merge_stderr:
236 _stderr = subprocess.STDOUT
237 else:
238 _stderr = subprocess.PIPE
239
240 p = subprocess.Popen( cmd, shell=True, stdin=subprocess.PIPE,
241 stdout=subprocess.PIPE, stderr=_stderr,
242 close_fds=True )
243
244 out = [ l[:-1] for l in p.stdout.readlines() ]
245
246 p.stdout.close()
247 if not merge_stderr:
248 p.stderr.close()
249
250 # need to allow process to terminate
251 p.wait()
252
253 errCode = p.returncode and p.returncode or 0
254 if p.returncode>0:
255 errorMessage = os.linesep.join(out)
256 output = []
257 else:
258 errorMessage = ''
259 output = out
260
261 return output, errCode, errorMessage
262
263 if __name__=='__main__':
264 app = SmrtpipeGalaxy( sys.argv )
265 sys.exit( app.run() )