once-only 0.0.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +82 -16
- data/VERSION +1 -1
- data/bin/once-only +102 -17
- data/lib/once-only/check.rb +7 -1
- metadata +32 -12
data/README.md
CHANGED
@@ -7,13 +7,24 @@ Relax with PBS!
|
|
7
7
|
* Computations only happen once
|
8
8
|
* A completed job does not get submitted again to PBS
|
9
9
|
* A job already in the queue does not get submitted again to PBS
|
10
|
+
* A completed job in the PBS queue does not run again
|
11
|
+
* Guarantee independently executed jobs
|
12
|
+
* Do not worry about submitting serial jobs
|
13
|
+
|
14
|
+
and coming
|
15
|
+
|
16
|
+
* Automatically use a scratch disk (nyi)
|
17
|
+
* Garbage collect jobs (nyi)
|
10
18
|
|
11
19
|
Once-only makes a program or script run only *once*, provided the inputs don't
|
12
20
|
change (in a functional style!). This is very useful when running a range of
|
13
21
|
jobs on a compute cluster or GRID. It may even be useful in the context of
|
14
22
|
webservices. Once-only makes it relaxed to run many jobs on compute clusters!
|
15
23
|
A mistake, interruption, or even a parameter tweak, does not mean everything
|
16
|
-
has to be run again.
|
24
|
+
has to be run again. When running jobs serially you can just batch
|
25
|
+
submit them after getting the first results. Any missed jobs can be
|
26
|
+
run later again. This way you can get better utilisation of the
|
27
|
+
cluster.
|
17
28
|
|
18
29
|
Instead of running a tool or script directly, such as
|
19
30
|
|
@@ -27,17 +38,18 @@ Prepend once-only
|
|
27
38
|
once-only bowtie -t e_coli reads/e_coli_1000.fq e_coli.map
|
28
39
|
```
|
29
40
|
|
30
|
-
and once-only will parse the command line for existing files and run a
|
31
|
-
on them (here the binary executable 'bowtie' and data files
|
41
|
+
and once-only will parse the command line for existing files and run a
|
42
|
+
checksum on them (here the binary executable 'bowtie' and data files
|
32
43
|
reads/e_coli_1000.fq and e_coli.map). This checksum, in fact an MD5
|
33
|
-
cryptographic hash, or optionally [pfff](https://github.com/pfff/pfff)
|
34
|
-
large files, is a unique identifier (aka fingerprint) and saved in
|
35
|
-
directory. When the checksum file does not
|
36
|
-
'bowtie -t e_coli
|
44
|
+
cryptographic hash, or optionally [pfff](https://github.com/pfff/pfff)
|
45
|
+
for large files, is a unique identifier (aka fingerprint) and saved in
|
46
|
+
a file in the running directory. When the checksum file does not
|
47
|
+
exist in the directory the command 'bowtie -t e_coli
|
48
|
+
reads/e_coli_1000.fq e_coli.map' is executed.
|
37
49
|
|
38
|
-
When the file already exists execution is skipped. In other words, the
|
39
|
-
file guarantees the program is only run once with the same
|
40
|
-
simple!
|
50
|
+
When the file already exists execution is skipped. In other words, the
|
51
|
+
checksum file guarantees the program is only run once with the same
|
52
|
+
inputs. Really simple!
|
41
53
|
|
42
54
|
In combination with PBS this could be
|
43
55
|
|
@@ -94,13 +106,18 @@ With Ruby 1.9 or later on your system you can run
|
|
94
106
|
gem install once-only
|
95
107
|
```
|
96
108
|
|
109
|
+
It is also easy to check out the git repository, as once-only has no
|
110
|
+
library dependencies.
|
111
|
+
|
97
112
|
### Dependencies
|
98
113
|
|
99
114
|
'md5sum' is used for calculating MD5 hash values.
|
100
115
|
|
101
|
-
'pfff' is optional and used for calculating pfff hash values on very
|
116
|
+
'pfff' is optional and used for calculating pfff hash values on very
|
117
|
+
large files (nyi).
|
102
118
|
|
103
|
-
When you are using
|
119
|
+
When you are using the --pbs option, once-only will use the 'qsub' and
|
120
|
+
'qstat' commands.
|
104
121
|
|
105
122
|
## Usage (command line)
|
106
123
|
|
@@ -112,7 +129,7 @@ once-only --help
|
|
112
129
|
|
113
130
|
Useful switches can be -v (verbose) and -q (quiet).
|
114
131
|
|
115
|
-
|
132
|
+
To skip scanning the executable file (useful in heterogenous environments,
|
116
133
|
such as the GRID) use the --skip-exe switch:
|
117
134
|
|
118
135
|
```sh
|
@@ -141,8 +158,11 @@ once-only --skip-exe --skip-glob 'out*' --skip-glob '*.ph' muscle -in aa.fa -out
|
|
141
158
|
|
142
159
|
For a full range of glob patterns, see this [page](http://ruby.about.com/od/beginningruby/a/dir2.htm).
|
143
160
|
|
144
|
-
Sometimes you want to include input files that are not on the command
|
145
|
-
|
161
|
+
Sometimes you want to include input files that are not on the command
|
162
|
+
line for generating the hash. Maybe some default input file name is
|
163
|
+
being picked up, or it is defined in a configuration file. In that
|
164
|
+
case use the --include/--in options. Another feature is that if an -in
|
165
|
+
file does not exist once-only does not run.
|
146
166
|
|
147
167
|
Another once-only command line option is to change directory before executing the script
|
148
168
|
|
@@ -152,9 +172,30 @@ once-only -d run001 --skip-regex 'out|\.ph$' muscle -in aa.fa -out out-alignment
|
|
152
172
|
|
153
173
|
which is useful with PBS and in scripted environments.
|
154
174
|
|
175
|
+
### Pipes and redirection
|
176
|
+
|
177
|
+
Once-only supports pipes and redirection by stringifying a command on
|
178
|
+
STDIN:
|
179
|
+
|
180
|
+
```sh
|
181
|
+
echo "/bin/cat README.md > tmp.out" | once-only --skip tmp.out
|
182
|
+
```
|
183
|
+
|
184
|
+
With PBS the tricky thing here is using more quotes for spacing. At this point it is
|
185
|
+
recommended to escape internal quotes, and avoid using single quotes, e.g.
|
186
|
+
|
187
|
+
```sh
|
188
|
+
echo "/bin/cat \\\"README.md Version 2\\\" > tmp.out" | once-only --pbs --skip tmp.out
|
189
|
+
```
|
190
|
+
|
155
191
|
### PBS
|
156
192
|
|
157
|
-
Once-only has PBS support built-in.
|
193
|
+
Once-only has PBS support built-in. When a job is in the queue, it
|
194
|
+
won't get submitted again. When a job has completed, it won't run
|
195
|
+
again. Thiss achieved by using once-only before submitting the job
|
196
|
+
to the queue, and right before running the job.
|
197
|
+
|
198
|
+
Once-only with PBS only uses the 'qsub' and 'qstat' commands.
|
158
199
|
|
159
200
|
Basically use the --pbs option:
|
160
201
|
|
@@ -176,6 +217,31 @@ once-only --pbs --skip-exe /bin/cat ~/.bashrc
|
|
176
217
|
|
177
218
|
so once-only won't check the file /bin/cat.
|
178
219
|
|
220
|
+
### Guarantee independent jobs with --copy
|
221
|
+
|
222
|
+
Because once-only 'knows' the input files we can copy them to a unique
|
223
|
+
place before execution. By using the --copy switch a new directory is
|
224
|
+
created in the run directory using the hash value of the process.
|
225
|
+
Input files are copied and the job is run inside that directory. When
|
226
|
+
the job is finished the output file(s) are copied back to the working
|
227
|
+
directory. Example
|
228
|
+
|
229
|
+
```sh
|
230
|
+
once-only --copy /bin/cat ~/.bashrc
|
231
|
+
```
|
232
|
+
|
233
|
+
Note that files that come with a path will be stripped of their path
|
234
|
+
before execution. When files are very large you may want to consider
|
235
|
+
the --scratch option.
|
236
|
+
|
237
|
+
### Use the scratch disk with --scratch (nyi)
|
238
|
+
|
239
|
+
watch this page
|
240
|
+
|
241
|
+
### Garbage collect jobs (nyi)
|
242
|
+
|
243
|
+
watch this page
|
244
|
+
|
179
245
|
## Project home page
|
180
246
|
|
181
247
|
Information on the source tree, documentation, examples, issues and
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.1
|
data/bin/once-only
CHANGED
@@ -11,20 +11,35 @@ once-only runs a command once only when inputs don't change!
|
|
11
11
|
Usage:
|
12
12
|
|
13
13
|
-d path change to directory before executing
|
14
|
+
--copy copy files to hash dir first
|
14
15
|
--pbs [opts] convert to PBS command with optional options
|
15
16
|
--skip|--out file skip making a checksum of the named file (multiple allowed)
|
16
17
|
--skip-exe skip making a checksum of the executable command/script
|
17
18
|
--skip-cli skip making a checksum of full command line
|
18
19
|
--skip-regex regex skip making checksumes of filenames that match the regex (multiple allowed)
|
19
20
|
--skip-glob regex skip making checksumes of filenames that match the glob (multiple allowed)
|
20
|
-
--include|--in file include input filename for making the
|
21
|
+
--include|--in file include input filename for making the checksums (file should exist)
|
21
22
|
-v increase verbosity
|
22
23
|
-q run quietly
|
23
24
|
--debug give debug information
|
24
25
|
--dry-run do not execute command
|
25
26
|
--force force execute command
|
26
27
|
|
27
|
-
|
28
|
+
Examples:
|
29
|
+
|
30
|
+
Basic use
|
31
|
+
|
32
|
+
once-only /bin/cat README.md
|
33
|
+
|
34
|
+
With PBS
|
35
|
+
|
36
|
+
once-only --pbs /bin/cat README.md
|
37
|
+
|
38
|
+
Using redirects
|
39
|
+
|
40
|
+
echo "/bin/cat README.md > tmp.out" | ./bin/once-only --skip tmp.out
|
41
|
+
|
42
|
+
See the README for more examples!
|
28
43
|
|
29
44
|
EOB
|
30
45
|
|
@@ -45,8 +60,9 @@ if ARGV.size == 0
|
|
45
60
|
exit 1
|
46
61
|
end
|
47
62
|
|
48
|
-
def exit_error errval = 1
|
49
|
-
$stderr.print
|
63
|
+
def exit_error errval = 1, msg = nil
|
64
|
+
$stderr.print msg if msg
|
65
|
+
$stderr.print "\n**ERROR** once-only returned error #{errval}\n"
|
50
66
|
exit errval
|
51
67
|
end
|
52
68
|
|
@@ -54,20 +70,28 @@ def parse_args(args)
|
|
54
70
|
options = { :skip => [], :skip_regex => [], :skip_glob => [], :include => [] }
|
55
71
|
|
56
72
|
consume = lambda { |args|
|
73
|
+
if not args[0]
|
74
|
+
# check stdin
|
75
|
+
cmd = $stdin.gets
|
76
|
+
exit_error(1,"Empty command on STDIN") if cmd == nil
|
77
|
+
$stderr.print "Command (STDIN): ",cmd,"\n"
|
78
|
+
options[:stdin] = true
|
79
|
+
return cmd.split(/\s/)
|
80
|
+
end
|
57
81
|
return args if File.exist?(args[0]) # reached the executable command
|
58
82
|
case args[0]
|
59
83
|
when '-d'
|
60
84
|
options[:dir] = File.expand_path(args[1])
|
61
85
|
consume.call(args[2..-1])
|
62
86
|
when '--pbs'
|
63
|
-
if args[1] =~ /\s+/ # optional argument
|
87
|
+
if args[1] and args[1] =~ /\s+/ # optional PBS argument with spacing
|
64
88
|
options[:pbs] = args[1]
|
65
89
|
consume.call(args[2..-1])
|
66
90
|
else
|
67
91
|
options[:pbs] = "''"
|
68
92
|
consume.call(args[1..-1])
|
69
93
|
end
|
70
|
-
when '--skip','--out'
|
94
|
+
when '--skip', '--out'
|
71
95
|
options[:skip] << args[1]
|
72
96
|
consume.call(args[2..-1])
|
73
97
|
when '--skip-exe'
|
@@ -82,9 +106,12 @@ def parse_args(args)
|
|
82
106
|
when '--skip-glob'
|
83
107
|
options[:skip_glob] << args[1]
|
84
108
|
consume.call(args[2..-1])
|
85
|
-
when '--include','--in'
|
109
|
+
when '--include', '--in', '-in'
|
86
110
|
options[:include] << args[1]
|
87
111
|
consume.call(args[2..-1])
|
112
|
+
when '--copy'
|
113
|
+
options[:copy] = true
|
114
|
+
consume.call(args[1..-1])
|
88
115
|
when '-h', '--help'
|
89
116
|
print USAGE
|
90
117
|
exit 1
|
@@ -104,7 +131,7 @@ def parse_args(args)
|
|
104
131
|
options[:force] = true
|
105
132
|
consume.call(args[1..-1])
|
106
133
|
else
|
107
|
-
$stderr.print "Can not parse arguments",args
|
134
|
+
$stderr.print "**ERROR** Can not parse arguments",args
|
108
135
|
exit_error(1)
|
109
136
|
end
|
110
137
|
}
|
@@ -126,6 +153,7 @@ if options[:debug]
|
|
126
153
|
p options
|
127
154
|
end
|
128
155
|
|
156
|
+
# --- Rewrite once-only args for PBS
|
129
157
|
once_only_args = OnceOnly::Check.drop_pbs_option(once_only_args)
|
130
158
|
once_only_args = OnceOnly::Check.drop_dir_option(once_only_args)
|
131
159
|
once_only_command = once_only_args.join(' ')
|
@@ -140,6 +168,8 @@ if options[:dir]
|
|
140
168
|
Dir.chdir options[:dir]
|
141
169
|
end
|
142
170
|
|
171
|
+
base_dir = Dir.pwd
|
172
|
+
|
143
173
|
executable = args[0]
|
144
174
|
args = args[1..-1] if options[:skip_exe]
|
145
175
|
|
@@ -154,34 +184,53 @@ file_list -= options[:skip]
|
|
154
184
|
|
155
185
|
OnceOnly::Check::check_files_exist(options[:include])
|
156
186
|
file_list += options[:include]
|
187
|
+
file_list = file_list.uniq
|
157
188
|
|
158
189
|
checksums = OnceOnly::Check::calc_file_checksums(file_list)
|
159
190
|
checksums.push ['SHA1',command_sha1,command_sorted] if not options[:skip_cli]
|
160
191
|
|
192
|
+
# ---- Create filenames
|
161
193
|
once_only_filename = OnceOnly::Check::make_once_filename(checksums,File.basename(executable))
|
162
194
|
$stderr.print "Check file name ",once_only_filename,"\n" if options[:verbose]
|
163
195
|
error_filename = once_only_filename + '.err'
|
164
|
-
|
196
|
+
tag_filename = once_only_filename + '.run'
|
197
|
+
$stderr.print "**STATUS** Job file exists ",once_only_filename,"!\n" if options[:debug] and File.exist?(once_only_filename)
|
165
198
|
|
199
|
+
# ---- Create job name
|
166
200
|
dirname = File.basename(Dir.pwd).rjust(8,"-") # make sure it is long enough
|
167
201
|
|
168
202
|
job_name = (dirname[-5..-1] + once_only_filename.split(/-/).map{|s|s[0..5]}.join).gsub(/[_-]/,'')[0..15]
|
169
203
|
$stderr.print "Job name ",job_name,"\n" if options[:verbose]
|
170
204
|
|
205
|
+
# ---- Create copy destination
|
206
|
+
if options[:copy]
|
207
|
+
copy_dir = base_dir + '/' + File.basename(once_only_filename,".txt")
|
208
|
+
end
|
209
|
+
|
171
210
|
if options[:force] or not File.exist?(once_only_filename)
|
172
211
|
$stderr.print "Running #{command}\n" if not options[:quiet]
|
212
|
+
OnceOnly::Check::write_file(tag_filename,checksums)
|
173
213
|
if options[:pbs]
|
214
|
+
# --- Submit PBS job
|
215
|
+
pbs_command = 'echo \'' +
|
216
|
+
if options[:stdin]
|
217
|
+
'echo "' + command + '"|'+ once_only_command
|
218
|
+
else
|
219
|
+
once_only_command + ' ' + command
|
220
|
+
end
|
221
|
+
# --- Add PBS part
|
222
|
+
pbs_command += "'|qsub -N #{job_name} "+options[:pbs]
|
223
|
+
pbs_command += ' -d ' + (options[:dir] ? options[:dir] : Dir.pwd)
|
224
|
+
|
225
|
+
$stderr.print("PBS command: ",pbs_command,"\n") if options[:verbose]
|
226
|
+
|
174
227
|
# --- Check if job is already queued in PBS
|
175
228
|
qstat = `/usr/bin/qstat`
|
176
229
|
if qstat =~ /#{job_name}/
|
177
|
-
$stderr.print "Job #{job_name} already in queue!\n"
|
230
|
+
$stderr.print "**STATUS** Job #{job_name} already in queue!\n"
|
178
231
|
exit 0
|
179
232
|
end
|
180
|
-
|
181
|
-
pbs_command = 'echo "' + once_only_command + ' ' + command + "\"|qsub -N #{job_name} "+options[:pbs]+' '
|
182
|
-
pbs_command += '-d ' + (options[:dir] ? options[:dir] : Dir.pwd)
|
183
|
-
|
184
|
-
$stderr.print(pbs_command,"\n") if options[:verbose]
|
233
|
+
|
185
234
|
if !options[:dry_run]
|
186
235
|
if not system(pbs_command)
|
187
236
|
OnceOnly::Check::write_file(error_filename,checksums)
|
@@ -191,18 +240,54 @@ if options[:force] or not File.exist?(once_only_filename)
|
|
191
240
|
else
|
192
241
|
# --- Run on command line
|
193
242
|
if !options[:dry_run]
|
194
|
-
|
243
|
+
success =
|
244
|
+
if options[:copy]
|
245
|
+
exit_error(1,"Directory #{copy_dir} already exists!") if File.directory?(copy_dir)
|
246
|
+
$stderr.print "Running in directory ",copy_dir
|
247
|
+
Dir.mkdir(copy_dir)
|
248
|
+
# --- copy files
|
249
|
+
# p args
|
250
|
+
# p file_list
|
251
|
+
clist = args.dup
|
252
|
+
file_list.each { | fn |
|
253
|
+
# copy file
|
254
|
+
res = `cp #{fn} #{copy_dir}`
|
255
|
+
print res if options[:verbose]
|
256
|
+
# replace command
|
257
|
+
clist = clist.map { |arg| ( fn == arg ? File.basename(arg) : arg ) }
|
258
|
+
}
|
259
|
+
p clist if options[:debug]
|
260
|
+
command_stripped = clist.join(' ')
|
261
|
+
Dir.chdir(copy_dir)
|
262
|
+
system_result = system(command_stripped)
|
263
|
+
if system_result
|
264
|
+
# Copy results back
|
265
|
+
Dir.glob(copy_dir+'/*').each { |outfn|
|
266
|
+
if clist.index(File.basename(outfn)) > 0
|
267
|
+
res = `cp #{outfn} #{base_dir}`
|
268
|
+
print res if options[:verbose]
|
269
|
+
end
|
270
|
+
}
|
271
|
+
end
|
272
|
+
system_result
|
273
|
+
else
|
274
|
+
system(command)
|
275
|
+
end
|
276
|
+
Dir.chdir(base_dir) if options[:copy]
|
277
|
+
if not success
|
195
278
|
OnceOnly::Check::write_file(error_filename,checksums)
|
279
|
+
File.unlink(tag_filename) if File.exist?(tag_filename)
|
196
280
|
exit_error($?.exitstatus)
|
197
281
|
else
|
198
282
|
# --- Success!
|
199
283
|
File.unlink(error_filename) if File.exist?(error_filename)
|
200
284
|
OnceOnly::Check::write_file(once_only_filename,checksums)
|
285
|
+
File.unlink(tag_filename) if File.exist?(tag_filename)
|
201
286
|
end
|
202
287
|
end
|
203
288
|
end
|
204
289
|
else
|
205
|
-
$stderr.print "Inputs unchanged. No need to rerun '#{original_commands}'!\n" if not options[:quiet]
|
290
|
+
$stderr.print "**STATUS** Inputs unchanged. No need to rerun '#{original_commands}'!\n" if not options[:quiet]
|
206
291
|
end
|
207
292
|
|
208
293
|
exit 0 # success!
|
data/lib/once-only/check.rb
CHANGED
@@ -16,7 +16,7 @@ module OnceOnly
|
|
16
16
|
|
17
17
|
def Check::check_files_exist list
|
18
18
|
list.each { |fn|
|
19
|
-
|
19
|
+
Check::exit_error("File #{fn} does not exist!") if not File.exist?(fn)
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
@@ -95,6 +95,12 @@ protected
|
|
95
95
|
return filename if filename and File.exist?(filename)
|
96
96
|
nil
|
97
97
|
end
|
98
|
+
|
99
|
+
def Check::exit_error msg, errval=1
|
100
|
+
$stderr.print "\nERROR: ",msg
|
101
|
+
$stderr.print " (once-only returned error #{errval})!\n"
|
102
|
+
exit errval
|
103
|
+
end
|
98
104
|
end
|
99
105
|
|
100
106
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: once-only
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: 2.8.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.8.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: cucumber
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: jeweler
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: 1.8.4
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.4
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: bundler
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,7 +69,12 @@ dependencies:
|
|
54
69
|
version: 1.0.21
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.0.21
|
58
78
|
description: ! "Run programs and scripts once only. Especially\n useful for PBS and
|
59
79
|
GRID computing"
|
60
80
|
email: pjotr.public01@thebird.nl
|
@@ -98,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
118
|
version: '0'
|
99
119
|
segments:
|
100
120
|
- 0
|
101
|
-
hash: -
|
121
|
+
hash: -4434987383675774210
|
102
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
123
|
none: false
|
104
124
|
requirements:
|
@@ -107,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
127
|
version: '0'
|
108
128
|
requirements: []
|
109
129
|
rubyforge_project:
|
110
|
-
rubygems_version: 1.8.
|
130
|
+
rubygems_version: 1.8.23
|
111
131
|
signing_key:
|
112
132
|
specification_version: 3
|
113
133
|
summary: Run commands once only if inputs do not change
|