09a2155995ed73f1031980d9ca806b0de58fe76f
[htsworkflow.git] / scripts / srf
1 #!/usr/bin/python
2
3 from glob import glob
4 import logging
5 import optparse
6 import os
7 import subprocess
8 import sys
9
10 from htsworkflow.util import queuecommands
11 from htsworkflow.pipelines import runfolder
12
13 def make_commands(run_name, lanes, site_name, destdir):
14   """
15   make a subprocess-friendly list of command line arguments to run solexa2srf
16   generates files like: 
17   woldlab:080514_HWI-EAS229_0029_20768AAXX:8.srf
18    site        run name                    lane
19              
20   run_name - most of the file name (run folder name is a good choice)
21   lanes - list of integers corresponding to which lanes to process
22   site_name - name of your "sequencing site" or "Individual"
23   destdir - where to write all the srf files
24   """
25   cmd_list = []
26   for lane in lanes:
27     name_prefix = '%s_%%l_%%t_' % (run_name,)
28     destname = '%s_%s_%d.srf' % (site_name, run_name, lane)
29     destdir = os.path.normpath(destdir)
30     dest_path = os.path.join(destdir, destname)
31     seq_pattern = 's_%d_*_seq.txt' % (lane,)
32
33     cmd = ['solexa2srf', 
34            '-N', name_prefix,
35            '-n', '%3x:%3y', 
36            '-o', dest_path, 
37            seq_pattern]
38     #cmd = ['illumina2srf', 
39     #       '-v1.0',
40     #       '-o', dest_path,
41     #       seq_pattern]
42
43     cmd_list.append(" ".join(cmd))
44   return cmd_list
45
46 def pathname_to_run_name(base):
47   """
48   Convert a pathname to a base runfolder name
49   handle the case with a trailing /
50   """
51   name = ""
52   while len(name) == 0:
53     base, name = os.path.split(base)
54     if len(base) == 0:
55       return None
56   return name
57
58 def make_parser():
59   usage = '%prog: [options] runfolder -l 1,2,3 [runfolder -l 5,6 ...]'
60
61   parser = optparse.OptionParser(usage)
62   parser.add_option('--dry-run', action='store_true',
63                     help='print what would be done',
64                     default=False)
65
66   parser.add_option('-d', '--dest-dir', dest='dest_dir',
67                     help='location to write srf files to',
68                     default='.')
69   parser.add_option('-s', '--site',
70                     help='site name',
71                     default='Individual')
72   parser.add_option('-l', '--lanes', dest='lanes', action="append",
73          default=[],
74          help='comma seperated list of lanes to add to srf'
75   )
76   parser.add_option('-j', '--jobs', default=1, type='int',
77                     help='how many jobs to run simultaneously')
78                      
79   parser.add_option('-v', '--verbose', dest='verbose',
80                     default=False, action='store_true',
81                     help='report more about internals (INFO)')
82   parser.add_option('--debug', dest='debug',
83                     default=False, action='store_true',
84                     help='report even more about internals (DEBUG)')
85  
86   return parser
87
88 def parse_lane_arg(lane_arg):
89     """
90     Convert comma sperated list of lane ids to a list of integers
91     """
92     lanes = []
93     for lane in lane_arg.split(','):
94         try:
95             lane = int(lane)
96             if lane < 1 or lane > 8:
97                 parser.error('Lanes must be in range [1..8]')
98             lanes.append(lane)
99         except ValueError:
100             parser.error('Lane selections must be integers')
101     return lanes
102
103 def main(cmdline=None):
104     parser = make_parser()
105     opts, args = parser.parse_args(cmdline)
106    
107     if opts.debug: 
108         logging.basicConfig(level=logging.DEBUG)
109     elif opts.verbose:
110         logging.basicConfig(level=logging.INFO)
111     else:
112         logging.basicConfig(level=logging.WARNING)
113
114     if len(args) == 0:
115         parser.error('need runfolder arguments')
116
117     # parse lane arguemnts
118     lanes_list = []
119     if len(opts.lanes) == 0:
120         lanes_list = [[1,2,3,4,5,6,7,8]] * len(args)
121     elif len(opts.lanes) == len(args):
122         for lane_arg in opts.lanes:
123             lanes_list.append(parse_lane_arg(lane_arg))
124     else:
125         parser.error(
126           "Number of lane arguments must match number of runfolders"
127         )
128     
129     # build list of commands
130     cmds = {}
131     for runfolder_path, lanes in zip(args, lanes_list):
132         # normalize paths, either relative to home dirs or current dir
133         runfolder_path = os.path.abspath(runfolder_path)
134         # the last part of the path should be a runfolder name
135         name = pathname_to_run_name(runfolder_path)
136         # so any bustard directories?
137         runs = runfolder.get_runs(runfolder_path)
138         # give up if there are anything other than 1 run
139         if len(runs) > 1:
140           print 'ERROR: Too many run directories in %s' %(runfolder_path,)
141           return 1
142         elif len(runs) == 1:
143           bustard_dir = runs[0].bustard.pathname
144           cmds[bustard_dir] = make_commands(name, lanes, opts.site, opts.dest_dir)
145         else:
146           print "ERROR: Couldn't find a bustard directory in", runfolder_path
147           return 1
148
149     if not opts.dry_run:
150       for cwd, cmd_list in cmds.items():
151         curdir = os.getcwd()
152         os.chdir(cwd)
153         q = queuecommands.QueueCommands(cmd_list, opts.jobs)
154         q.run()
155         os.chdir(curdir)
156     else:
157       for cwd, cmd_list in cmds.items():
158         print cwd
159         print cmd_list
160         print 'jobs: ', opts.jobs
161
162     return 0
163
164 if __name__ == "__main__":
165     sys.exit(main(sys.argv[1:]))