bio-gemma-wrapper 0.99.2 → 0.99.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e27a8a3abb00b758095df5956b3854674faf5ff681a93bc028df273c40125c0d
4
- data.tar.gz: e9675dbb0ea0f087dd21774635d38f3cda11b46a88b36c77dd308086fd0ec5f2
3
+ metadata.gz: 69d74ac5f1a705132d7ddc86bd1182c11fc37cf32062dbb28909f16684a827cb
4
+ data.tar.gz: 6f912b3c03474c1334a105d6c9471c02d39c205e94b0d07e5281718beec65ee7
5
5
  SHA512:
6
- metadata.gz: 81cf5440fa531d5a831efa787800c8bea230d47cddc666a31fff066551ff347708a41ddf1368c0d3946c7ba9faef8e5882e398ad340850253c53961cce96f662
7
- data.tar.gz: 582ae78c48a1eb8eeca01172eaeaba9d5ca23e69601967e334f8c218e3a4dd74b297861b01ce49b1357798b49a96c12e737100dcacec7fc34b70da1fc9c75f0d
6
+ metadata.gz: 35fbdf4ccfc482f6898e35b1e46e840db87f34efb35a096206ffef4a131ac8b21a4e6b7893be6ee053a59837eadba6547258d2360d796794c71a60670458943f
7
+ data.tar.gz: 43f7a7438f475583930e6cf1f50d34206fba7674b3df836791cf7064bd7ca55dddc2cc101f7c5a89d8042645b6dd06245b84d3b38501bc1eab7d18774703a01a
data/README.md CHANGED
@@ -8,11 +8,12 @@ Nat. Genet., 2016)](cfw.gif)
8
8
  ## Introduction
9
9
 
10
10
  Gemma-wrapper allows running GEMMA with LOCO, GEMMA with caching,
11
- GEMMA in parallel (now the default), and GEMMA on PBS. Gemma-wrapper
12
- is used to run GEMMA as part of the https://genenetwork.org/
13
- environment.
11
+ GEMMA in parallel (now the default with LOCO), and GEMMA on
12
+ PBS. Gemma-wrapper is used to run GEMMA as part of the
13
+ https://genenetwork.org/ environment.
14
14
 
15
- Note that gemma-wrapper is projected to be integrated into gemma2/lib.
15
+ Note that a version of gemma-wrapper is projected to be integrated
16
+ into gemma itself.
16
17
 
17
18
  GEMMA is a software toolkit for fast application of linear mixed
18
19
  models (LMMs) and related models to genome-wide association studies
@@ -29,6 +30,14 @@ does a pass-through of all standard GEMMA invocation switches. On
29
30
  return gemma-wrapper can return a JSON object (--json) which is
30
31
  useful for web-services.
31
32
 
33
+ ## Performance
34
+
35
+ LOCO runs in parallel by default which is at least a 5x performance
36
+ improvement on a machine with enough cores. GEMMA without LOCO,
37
+ however, does not run in parallel by default. Performance
38
+ improvements with the parallel implementation for LOCO and non-LOCO
39
+ can be viewed [here](./test/performance/releases.gmi).
40
+
32
41
  ## Installation
33
42
 
34
43
  Prerequisites are
@@ -53,15 +62,19 @@ and it will render something like
53
62
  Usage: gemma-wrapper [options] -- [gemma-options]
54
63
  --permutate n Permutate # times by shuffling phenotypes
55
64
  --permute-phenotypes filen Phenotypes to be shuffled in permutations
56
- --loco [x,y,1,2,3...] Run full LOCO
65
+ --loco Run full leave-one-chromosome-out (LOCO)
66
+ --chromosomes [1,2,3] Run specific chromosomes
57
67
  --input filen JSON input variables (used for LOCO)
58
68
  --cache-dir path Use a cache directory
59
69
  --json Create output file in JSON format
60
- --force Force computation
61
- --slurm [options] Submit to slurm PBS
70
+ --force Force computation (override cache)
71
+ --parallel Run jobs in parallel
72
+ --no-parallel Do not run jobs in parallel
73
+ --slurm[=opts] Use slurm PBS for submitting jobs
62
74
  --q, --quiet Run quietly
63
75
  -v, --verbose Run verbosely
64
- --debug Show debug messages and keep intermediate output
76
+ -d, --debug Show debug messages and keep intermediate output
77
+ --dry-run Show commands, but don't execute
65
78
  -- Anything after gets passed to GEMMA
66
79
 
67
80
  -h, --help display this help and exit
@@ -99,6 +112,7 @@ the data files are found):
99
112
  gemma-wrapper -- \
100
113
  -g test/data/input/BXD_geno.txt.gz \
101
114
  -p test/data/input/BXD_pheno.txt \
115
+ -a test/data/input/BXD_snps.txt \
102
116
  -gk \
103
117
  -debug
104
118
 
@@ -116,6 +130,7 @@ You can also get JSON output on STDOUT by providing the --json switch
116
130
  gemma-wrapper --json -- \
117
131
  -g test/data/input/BXD_geno.txt.gz \
118
132
  -p test/data/input/BXD_pheno.txt \
133
+ -a test/data/input/BXD_snps.txt \
119
134
  -gk \
120
135
  -debug > K.json
121
136
 
@@ -133,6 +148,7 @@ default. If you want something else provide a --cache-dir, e.g.
133
148
  gemma-wrapper --cache-dir ~/.gemma-cache -- \
134
149
  -g test/data/input/BXD_geno.txt.gz \
135
150
  -p test/data/input/BXD_pheno.txt \
151
+ -a test/data/input/BXD_snps.txt \
136
152
  -gk \
137
153
  -debug
138
154
 
@@ -143,7 +159,7 @@ will store K in ~/.gemma-cache.
143
159
  Run the LMM using the K's captured earlier in K.json using the --input
144
160
  switch
145
161
 
146
- gemma-wrapper --json --loco --input K.json -- \
162
+ gemma-wrapper --json --input K.json -- \
147
163
  -g test/data/input/BXD_geno.txt.gz \
148
164
  -p test/data/input/BXD_pheno.txt \
149
165
  -c test/data/input/BXD_covariates2.txt \
@@ -163,7 +179,7 @@ https://github.com/genetics-statistics/GEMMA/issues/46). To loop all
163
179
  chromosomes first create all K's with
164
180
 
165
181
  gemma-wrapper --json \
166
- --loco 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,X -- \
182
+ --loco -- \
167
183
  -g test/data/input/BXD_geno.txt.gz \
168
184
  -p test/data/input/BXD_pheno.txt \
169
185
  -a test/data/input/BXD_snps.txt \
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.99.2
1
+ 0.99.6
data/bin/gemma-wrapper CHANGED
@@ -4,7 +4,7 @@
4
4
  # Author:: Pjotr Prins
5
5
  # License:: GPL3
6
6
  #
7
- # Copyright (C) 2017-2021 Pjotr Prins <pjotr.prins@thebird.nl>
7
+ # Copyright (C) 2017-2022 Pjotr Prins <pjotr.prins@thebird.nl>
8
8
 
9
9
  USAGE = "
10
10
  GEMMA wrapper example:
@@ -14,12 +14,12 @@ GEMMA wrapper example:
14
14
  gemma-wrapper -- \\
15
15
  -g test/data/input/BXD_geno.txt.gz \\
16
16
  -p test/data/input/BXD_pheno.txt \\
17
+ -a test/data/input/BXD_snps.txt \
17
18
  -gk
18
19
 
19
20
  LOCO K computation with caching and JSON output
20
21
 
21
- gemma-wrapper --json \\
22
- --loco 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,X -- \\
22
+ gemma-wrapper --json --loco -- \\
23
23
  -g test/data/input/BXD_geno.txt.gz \\
24
24
  -p test/data/input/BXD_pheno.txt \\
25
25
  -a test/data/input/BXD_snps.txt \\
@@ -64,6 +64,7 @@ if not gemma_command
64
64
  end
65
65
  end
66
66
 
67
+ hashme = nil
67
68
 
68
69
  require 'digest/sha1'
69
70
  require 'fileutils'
@@ -71,12 +72,15 @@ require 'optparse'
71
72
  require 'tempfile'
72
73
  require 'tmpdir'
73
74
 
75
+ require 'lock'
76
+
74
77
  split_at = ARGV.index('--')
78
+
75
79
  if split_at
76
80
  gemma_args = ARGV[split_at+1..-1]
77
81
  end
78
82
 
79
- options = { show_help: false, source: 'https://github.com/genetics-statistics/gemma-wrapper', version: version+' (Pjotr Prins)', date: Time.now.to_s, gemma_command: gemma_command, cache_dir: Dir.tmpdir(), quiet: false, parallel: true }
83
+ options = { show_help: false, source: 'https://github.com/genetics-statistics/gemma-wrapper', version: version+' (Pjotr Prins)', date: Time.now.to_s, gemma_command: gemma_command, cache_dir: Dir.tmpdir(), quiet: false, permute_phenotypes: false, parallel: nil }
80
84
 
81
85
  opts = OptionParser.new do |o|
82
86
  o.banner = "\nUsage: #{File.basename($0)} [options] -- [gemma-options]"
@@ -91,8 +95,12 @@ opts = OptionParser.new do |o|
91
95
  raise "Phenotype input file #{phenotypes} does not exist" if !File.exist?(phenotypes)
92
96
  end
93
97
 
94
- o.on('--loco [x,y,1,2,3...]', Array, 'Run full leave-one-chromosome-out (LOCO)') do |lst|
95
- options[:loco] = lst
98
+ o.on('--loco', 'Run full leave-one-chromosome-out (LOCO)') do |b|
99
+ options[:loco] = b
100
+ end
101
+
102
+ o.on('--chromosomes [1,2,3]',Array,'Run specific chromosomes') do |lst|
103
+ options[:chromosomes] = lst
96
104
  end
97
105
 
98
106
  o.on('--input filen',String, 'JSON input variables (used for LOCO)') do |filen|
@@ -112,6 +120,10 @@ opts = OptionParser.new do |o|
112
120
  options[:force] = true
113
121
  end
114
122
 
123
+ o.on("--parallel", "Run jobs in parallel") do |b|
124
+ options[:parallel] = true
125
+ end
126
+
115
127
  o.on("--no-parallel", "Do not run jobs in parallel") do |b|
116
128
  options[:parallel] = false
117
129
  end
@@ -185,26 +197,36 @@ warning = lambda do |*msg|
185
197
  record[:warnings].push *msg.join("")
186
198
  OUTPUT.print "WARNING: ",*msg,"\n"
187
199
  end
200
+
188
201
  info = lambda do |*msg|
189
202
  record[:debug].push *msg.join("") if options[:json] and options[:debug]
190
203
  OUTPUT.print *msg,"\n" if !options[:quiet]
191
204
  end
192
205
 
206
+ # Fetch chromosomes
207
+ def get_chromosomes annofn
208
+ h = {}
209
+ File.open(annofn,"r").each_line do | line |
210
+ chr = line.split(/\s+/)[2]
211
+ h[chr] = true
212
+ end
213
+ h.map { |k,v| k }
214
+ end
193
215
  # ---- Start banner
194
216
 
195
217
  GEMMA_K_VERSION=version
196
- GEMMA_K_BANNER = "gemma-wrapper #{version} (Ruby #{RUBY_VERSION}) by Pjotr Prins 2017-2021\n"
218
+ GEMMA_K_BANNER = "gemma-wrapper #{version} (Ruby #{RUBY_VERSION}) by Pjotr Prins 2017-2022\n"
197
219
  info.call GEMMA_K_BANNER
198
220
 
199
221
  # Check gemma version
200
- GEMMA_COMMAND=options[:gemma_command]
201
- info.call "NOTE: gemma-wrapper is soon to be replaced by gemma2/lib"
202
-
203
222
  begin
204
- GEMMA_INFO = `#{GEMMA_COMMAND}`
223
+ gemma_command2 = options[:gemma_command]
224
+ info.call "NOTE: gemma-wrapper is soon to be replaced"
225
+
226
+ GEMMA_INFO = `#{gemma_command2}`
205
227
  rescue Errno::ENOENT
206
- GEMMA_COMMAND = "gemma" if not GEMMA_COMMAND
207
- error.call "<#{GEMMA_COMMAND}> command not found"
228
+ gemma_command2 = "gemma"
229
+ error.call "<#{gemma_command2}> command not found"
208
230
  end
209
231
 
210
232
  gemma_version_header = GEMMA_INFO.split("\n").grep(/GEMMA|Version/)[0].strip
@@ -230,13 +252,17 @@ if RUBY_VERSION =~ /^1/
230
252
  warning "runs on Ruby 2.x only\n"
231
253
  end
232
254
 
255
+ # ---- LOCO defaults to parallel
256
+ if options[:parallel] == nil
257
+ options[:parallel] = true if options[:loco]
258
+ end
259
+
233
260
  debug.call(options) # some debug output
234
261
  debug.call(record)
235
262
 
236
263
  DO_COMPUTE_KINSHIP = gemma_args.include?("-gk")
237
264
  DO_COMPUTE_GWA = !DO_COMPUTE_KINSHIP
238
265
 
239
- # ---- Set up parallel
240
266
  if options[:parallel]
241
267
  begin
242
268
  skip_cite = `echo "will cite" |parallel --citation`
@@ -248,8 +274,12 @@ if options[:parallel]
248
274
  parallel_cmds = []
249
275
  end
250
276
 
277
+ # ---- Fetch chromosomes from SNP annotation file
278
+ anno_idx = gemma_args.index '-a'
279
+ raise "Expected GEMMA -a genotype file switch" if anno_idx == nil
280
+ CHROMOSOMES = get_chromosomes(gemma_args[anno_idx+1])
281
+
251
282
  # ---- Compute HASH on inputs
252
- hashme = []
253
283
  geno_idx = gemma_args.index '-g'
254
284
  raise "Expected GEMMA -g genotype file switch" if geno_idx == nil
255
285
  pheno_idx = gemma_args.index '-p'
@@ -279,14 +309,15 @@ execute = lambda { |cmd|
279
309
 
280
310
  compute_hash = lambda do | phenofn = nil |
281
311
  # Compute a HASH on the inputs
282
- debug.call "Hashing on ",hashme,"\n"
312
+ error.call "Hash is empty" if hashme == nil or hashme == []
313
+ debug.call "Hashing on ",hashme," before phenofn inject"
283
314
  hashes = []
284
315
  hm = if phenofn
285
316
  hashme + ["-p", phenofn]
286
317
  else
287
318
  hashme
288
319
  end
289
- debug.call(hm)
320
+ debug.call("Hashing on ",hm)
290
321
  hm.each do | item |
291
322
  if File.file?(item)
292
323
  hashes << Digest::SHA1.hexdigest(File.read(item))
@@ -299,20 +330,9 @@ compute_hash = lambda do | phenofn = nil |
299
330
  Digest::SHA1.hexdigest hashes.join(' ')
300
331
  end
301
332
 
302
- HASH = compute_hash.call()
303
- options[:hash] = HASH
304
-
305
- # Create cache dir
306
- FileUtils::mkdir_p options[:cache_dir]
307
-
308
- Dir.mktmpdir do |tmpdir| # tmpdir for GEMMA output
309
-
310
333
  error.call "Do not use the GEMMA -o switch!" if gemma_args.include? '-o'
311
334
  error.call "Do not use the GEMMA -outdir switch!" if gemma_args.include? '-outdir'
312
335
  GEMMA_ARGS_HASH = gemma_args.dup # do not include outdir
313
- gemma_args << '-outdir'
314
- gemma_args << tmpdir
315
- GEMMA_ARGS = gemma_args
316
336
 
317
337
  hashme =
318
338
  if DO_COMPUTE_KINSHIP and pheno_idx != nil
@@ -322,10 +342,30 @@ hashme =
322
342
  GEMMA_ARGS_HASH
323
343
  end
324
344
 
345
+ HASH = compute_hash.call()
346
+ options[:hash] = HASH
347
+
348
+ at_exit do
349
+ Lock.release(HASH)
350
+ end
351
+
352
+ Lock.create(HASH) # this will wait for a lock to expire
353
+
354
+ joblog = options[:cache_dir]+"/"+HASH+"-parallel.log"
355
+
356
+ # Create cache dir
357
+ FileUtils::mkdir_p options[:cache_dir]
358
+
359
+ Dir.mktmpdir do |tmpdir| # tmpdir for GEMMA output
360
+
361
+ gemma_args << '-outdir'
362
+ gemma_args << tmpdir
363
+ GEMMA_ARGS = gemma_args
364
+
325
365
  debug.call "Options: ",options,"\n" if !options[:quiet]
326
366
 
327
367
  invoke_gemma = lambda do |extra_args, cache_hit = false, chr = "full", permutation = 1|
328
- cmd = "#{GEMMA_COMMAND} #{GEMMA_ARGS.join(' ')} #{extra_args.join(' ')}"
368
+ cmd = "#{gemma_command2} #{GEMMA_ARGS.join(' ')} #{extra_args.join(' ')}"
329
369
  record[:gemma_command] = cmd
330
370
  return if cache_hit
331
371
  if options[:slurm]
@@ -434,11 +474,17 @@ gwas = lambda do | chr, kfn, pfn, permutation=0 |
434
474
  end
435
475
 
436
476
  LOCO = options[:loco]
477
+ if LOCO
478
+ if options[:chromosomes]
479
+ CHROMOSOMES = options[:chromosomes]
480
+ end
481
+ end
482
+
437
483
  if DO_COMPUTE_KINSHIP
438
484
  # compute K
439
- info.call LOCO
440
- if LOCO != nil
441
- LOCO.each do |chr|
485
+ info.call CHROMOSOMES
486
+ if LOCO
487
+ CHROMOSOMES.each do |chr|
442
488
  info.call "LOCO for ",chr
443
489
  kinship.call(chr)
444
490
  end
@@ -447,13 +493,24 @@ if DO_COMPUTE_KINSHIP
447
493
  end
448
494
  else
449
495
  # DO_COMPUTE_GWA
450
- json_in = JSON.parse(File.read(options[:input]))
496
+ begin
497
+ json_in = JSON.parse(File.read(options[:input]))
498
+ rescue TypeError
499
+ raise "Missing JSON input file?"
500
+ end
451
501
  raise "JSON problem, file #{options[:input]} is not -gk derived" if json_in["type"] != "K"
452
502
 
453
503
  pfn = options[:permute_phenotypes] # can be nil
454
- k_files = json_in["files"].map { |rec| [rec[0],rec[2]] }
455
- k_files.each do | chr, kfn | # call a GWA for each chromosome
456
- gwas.call(chr,kfn,pfn)
504
+ if LOCO
505
+ k_files = json_in["files"].map { |rec| [rec[0],rec[2]] }
506
+ k_files.each do | chr, kfn | # call a GWA for each chromosome
507
+ gwas.call(chr,kfn,pfn)
508
+ end
509
+ else
510
+ kfn = json_in["files"][0][2]
511
+ CHROMOSOMES.each do | chr |
512
+ gwas.call(chr,kfn,pfn)
513
+ end
457
514
  end
458
515
  # Permute
459
516
  if options[:permutate]
@@ -505,22 +562,34 @@ end
505
562
  # ---- Invoke parallel
506
563
  if options[:parallel]
507
564
  # parallel_cmds = ["echo 1","sleep 1 && echo 2", "false", "echo 3"]
508
- cmd = parallel_cmds.join("\\n")
509
-
510
- cmd = "echo -e \"#{cmd}\""
511
- err = execute.call(cmd+"|parallel") # all jobs in parallel
512
- if err != 0
513
- [16,8,4,1].each do |jobs|
514
- info.call("Failed to complete parallel run -- retrying with smaller RAM footprint!")
515
- err = execute.call(cmd+"|parallel -j #{jobs}")
516
- break if err == 0
565
+
566
+ Tempfile.open("commands.txt") do |f|
567
+ cmdfn = f.path
568
+ File.open(cmdfn,"w") do |f|
569
+ parallel_cmds.each do |c|
570
+ f.puts(c)
571
+ end
517
572
  end
573
+ cmd = "cat \"#{cmdfn}\""
574
+ err = execute.call(cmd+"|parallel --joblog #{joblog}") # first try optimistically to run all jobs in parallel
518
575
  if err != 0
519
- info.call("Run failed!")
520
- exit err
576
+ [16,8,4,1].each do |jobs|
577
+ info.call("Failed to complete parallel run -- retrying with smaller RAM footprint!")
578
+ err = execute.call(cmd+"|parallel -j #{jobs} --resume --joblog #{joblog}")
579
+ break if err == 0
580
+ end
581
+ if err != 0
582
+ info.call("Parallel run failed!")
583
+ debug.call("Job log is: ",File.read(joblog))
584
+ # Remove remaining files
585
+ FileUtils.mv joblog, joblog+".bak", verbose: false, force: true
586
+ FileUtils.rm_rf("#{tmpdir}/*", secure: true)
587
+ exit err
588
+ end
521
589
  end
522
590
  end
523
591
  info.call("Run successful!")
592
+ FileUtils.mv joblog, joblog+".bak", verbose: false, force: true
524
593
  end
525
594
  json_out.call
526
595
 
@@ -6,6 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.authors = ["Pjotr Prins"]
7
7
  s.email = 'pjotr.public01@thebird.nl'
8
8
  s.files = ["bin/gemma-wrapper",
9
+ "lib/lock.rb",
9
10
  "Gemfile",
10
11
  "LICENSE.txt",
11
12
  "README.md",
data/lib/lock.rb ADDED
@@ -0,0 +1,95 @@
1
+ # Locking module for gemma (wrapper)
2
+ #
3
+
4
+ =begin
5
+
6
+ The logic is as follows:
7
+
8
+ 1. a program creates a named lock file (based on a hash of its inputs) with its PID
9
+ 2. on exit it destroys the file
10
+ 3. a new program checks for the lock file
11
+ 4. if it exists and the PID is still in the ps table - wait
12
+ 5. when the pid disappears or the lock file - continue
13
+ 6. a timeout will return an error in 3 minutes
14
+
15
+ Note that there is a theoretical chance the lock file existed, but disappeared. I think I have it covered by ignoring the unlink errors. Also the use of /proc/PID is Linux specific.
16
+
17
+ =end
18
+
19
+
20
+ require 'timeout'
21
+
22
+ module Lock
23
+
24
+ def self.local name
25
+ ENV['HOME']+"/."+name.gsub("/","-")+".lck"
26
+ end
27
+
28
+ def self.lock_pid name
29
+ lockfn = local(name)
30
+ if File.exist?(lockfn)
31
+ File.read(lockfn).to_i
32
+ else
33
+ 0
34
+ end
35
+ end
36
+
37
+ def self.locked? name
38
+ lockfn = local(name)
39
+ pid = lock_pid(name)
40
+ if File.exist?("/proc/#{pid}")
41
+ true
42
+ else
43
+ # the program went away - remove any 'stale' lock
44
+ begin
45
+ File.unlink(lockfn)
46
+ rescue Errno::ENOENT
47
+ # ignore error when the lock file went missing
48
+ end
49
+ false # --> no longer locked
50
+ end
51
+ end
52
+
53
+ def Lock::create name
54
+ wait_for(name)
55
+ lockfn = local(name)
56
+ if File.exist?(lockfn)
57
+ $stderr.print "\nERROR: Can not steal #{lockfn}"
58
+ exit 1
59
+ end
60
+ File.open(lockfn, File::RDWR|File::CREAT, 0644) do |f|
61
+ f.flock(File::LOCK_EX)
62
+ f.print(Process.pid)
63
+ end
64
+ end
65
+
66
+ def Lock::wait_for name
67
+ lockfn = local(name)
68
+ begin
69
+ status = Timeout::timeout(180) { # 3 minutes
70
+ while locked?(name)
71
+ $stderr.print("\nWaiting for lock #{lockfn}...")
72
+ sleep 2
73
+ end
74
+ }
75
+ rescue Timeout::Error
76
+ $stderr.print "\nERROR: Timed out, but I can not steal #{lockfn}"
77
+ exit 1
78
+ end
79
+ # yah! lock is released
80
+ end
81
+
82
+ def Lock::release name
83
+ lockfn = local(name)
84
+ if Process.pid == lock_pid(name)
85
+ begin
86
+ File.unlink(lockfn) # PID expired
87
+ rescue Errno::ENOENT
88
+ # ignore error when the lock file went missing
89
+ end
90
+ else
91
+ $stderr.print "\nERROR: can not release #{lockfn} because it is not owned by me"
92
+ end
93
+ end
94
+
95
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bio-gemma-wrapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.2
4
+ version: 0.99.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pjotr Prins
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-08 00:00:00.000000000 Z
11
+ date: 2022-01-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: GEMMA wrapper adds LOCO and permutation support. Also runs in parallel
14
14
  and caches K between runs with LOCO support
@@ -24,11 +24,12 @@ files:
24
24
  - VERSION
25
25
  - bin/gemma-wrapper
26
26
  - gemma-wrapper.gemspec
27
+ - lib/lock.rb
27
28
  homepage: https://github.com/genetics-statistics/gemma-wrapper
28
29
  licenses:
29
30
  - GPL3
30
31
  metadata: {}
31
- post_install_message:
32
+ post_install_message:
32
33
  rdoc_options: []
33
34
  require_paths:
34
35
  - lib
@@ -43,8 +44,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
44
  - !ruby/object:Gem::Version
44
45
  version: '0'
45
46
  requirements: []
46
- rubygems_version: 3.2.5
47
- signing_key:
47
+ rubygems_version: 3.2.22
48
+ signing_key:
48
49
  specification_version: 4
49
50
  summary: GEMMA with LOCO and permutations
50
51
  test_files: []