]> git.donarmstrong.com Git - uiuc_igb_scripts.git/blob - dqsub
fix two typos in dqsub
[uiuc_igb_scripts.git] / dqsub
1 #!/usr/bin/perl
2 # dqsub submits jobs using qsub with better options
3 # and is released under the terms of the GNU GPL version 3, or any
4 # later version, at your option. See the file README and COPYING for
5 # more information.
6 # Copyright 2014 by Don Armstrong <don@donarmstrong.com>.
7
8
9 use warnings;
10 use strict;
11
12 use Getopt::Long;
13 use Pod::Usage;
14
15 =head1 NAME
16
17 dqsub - submits jobs using qsub with better options
18
19 =head1 SYNOPSIS
20
21 dqsub [options]
22
23  Options:
24    --queue, -q Queue to use
25    --interactive, -I call qsub interactively
26    --nodes nodes to use
27    --array array mode (one of 'chdir' or 'xargs' or '')
28    --array-from file to read arrays from (default STDIN)
29    --ppn processors per node to use
30    --mem memory to request
31    --dir Directory to run the script in (default current directory)
32    --debug, -d debugging level (Default 0)
33    --help, -h display this help
34    --man, -m display manual
35
36 =head1 OPTIONS
37
38 =over
39
40 =item B<--array>
41
42 This describes how dqsub will generate array jobs.
43
44 If no B<--array> is given, then the command and any additional
45 arguments given will be run using qsub.
46
47 If B<--array> is C<chdir>, then each line of the input given in
48 B<--array-from> will be used as a directory and the command and any
49 additional arguments given will run in each directory.
50
51 IF B<--array> is C<xargs>, then each line of the input given will be
52 considered to be an additional argument which will be given to the
53 command run in the current directory.
54
55 =item B<--array-from>
56
57 File to read array arguments from. If not provided, and B<--array> is
58 given, arguments will be read from STDIN.
59
60 =item B<--debug, -d>
61
62 Debug verbosity. (Default 0)
63
64 =item B<--help, -h>
65
66 Display brief usage information.
67
68 =item B<--man, -m>
69
70 Display this manual.
71
72 =back
73
74 =head1 EXAMPLES
75
76 dqsub
77
78 =cut
79
80 use IO::File;
81 use Cwd qw(getcwd abs_path);
82 use vars qw($DEBUG);
83
84 my %options = (nodes           => 1,
85                ppn             => 2,
86                mem             => '2G',
87                debug           => 0,
88                help            => 0,
89                man             => 0,
90                interactive     => 0,
91               );
92
93 GetOptions(\%options,
94            'queue|q=s',
95            'interactive|I!',
96            'nodes=i',
97            'array=s',
98            'array_from|array-from=s',
99            'ppn|processors-per-node=i',
100            'mem|memory=s',
101            'dir=s',
102            'debug|d+','help|h|?','man|m');
103
104 pod2usage() if $options{help};
105 pod2usage({verbose=>2}) if $options{man};
106
107 $DEBUG = $options{debug};
108
109 my @USAGE_ERRORS;
110 if (not @ARGV and not $options{interactive}) {
111     push @USAGE_ERRORS,"You must provide a command to run";
112 }
113 if (defined $options{array} and $options{array} !~ /^(?:|chdir|xargs)$/i) {
114     push @USAGE_ERRORS,"--array must be one of chdir, xargs or '' if provided";
115     $options{array} = lc($options{array});
116     if ($options{array} eq '') {
117         $options{array} = undef;
118     }
119 }
120 if ($options{interactive} and @ARGV) {
121     push @USAGE_ERRORS,"Don't provide commands when you're asking for an interactive shell";
122 }
123
124 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
125
126 # OK. Generate the options to qsub which we'll be using
127 my @qsub_options = generate_qsub_options(\%options);
128
129 if ($options{interactive}) {
130     print STDERR 'running: qsub '.join(' ',@qsub_options) if $DEBUG;
131     exec('qsub',@qsub_options);
132 } else {
133     my @array = ();
134     if ($options{array}) {
135         @array = read_array_options(\%options) if $options{array};
136         # the -t option gives the range of elements for an array job
137         push @qsub_options,'-t','1-'. scalar @array;
138     }
139     call_qsub(\@qsub_options,write_qsub_script(\%options,\@ARGV,\@array));
140 }
141
142 sub generate_qsub_options{
143     my ($options) = @_;
144     my @qo;
145     if (defined $options->{queue} and length $options->{queue}) {
146         push @qo,'-q',$options->{queue};
147     }
148     if (defined $options->{dir}) {
149         push @qo,'-d',abs_path($options->{dir});
150     } else {
151         push @qo,'-d',getcwd;
152     }
153     ## handle the -l options
154     my @l;
155     push @l, 'nodes='.$options->{nodes};
156     if (defined $options->{ppn}) {
157         $l[$#l] .= ':ppn='.$options->{ppn};
158     }
159     if ($options->{mem}) {
160         push @l,'mem=',$options->{mem};
161     }
162     push @qo,'-l',join(',',@l) if @l;
163 }
164
165 sub read_array_options{
166     my ($options) = @_;
167     my $fh = \*STDIN;
168     if (defined $options->{array_from}) {
169         $fh = IO::File->new(defined $options->{array_from}) or
170             die "Unable to open $options->{array_from} for reading: $!";
171     }
172     my @array;
173     for (<$fh>) {
174         chomp;
175         push @array,$_;
176     }
177     return @array;
178 }
179
180 sub call_qsub {
181     my ($qsub_options,$script) = @_;
182     my $qsub_fh;
183     open $qsub_fh,'|-','qsub',@{$qsub_options},'-' or
184         die "Unable to start qsub: $!";
185     print {$qsub_fh} $script or
186         die "Unable to print to qsub: $!";
187     close($qsub_fh) or
188         die "Unable to close qsub filehandle: $!";
189 }
190
191 sub write_qsub_script {
192     my ($opt,$arg,$array) = @_;
193
194     my $script = "#!/bin/bash\n";
195     my $command = join(' ',map {qq('$_')} @{$arg});
196         $script .= <<EOF;
197 # this script was written by dqsub
198 EOF
199     if (defined $opt->{array}) {
200         die "--array is currently not implemented";
201     } else {
202         $script .= <<EOF;
203 # there's no array, so just executing the command with arguments
204 exec $command;
205 EOF
206     }
207     return $script;
208 }
209
210
211 __END__