lockfile 1.4.3 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README +3 -1
- data/bin/rlock +2 -2
- data/lib/lockfile.rb +95 -119
- data/lockfile.gemspec +46 -0
- data/rakefile +376 -0
- data/readme.erb +227 -0
- data/samples/a.rb +0 -0
- data/samples/lock.sh +0 -0
- metadata +53 -55
- data/bin/rlock-1.4.3 +0 -360
- data/gemspec.rb +0 -27
- data/install.rb +0 -210
- data/lib/lockfile-1.4.3.rb +0 -564
- data/rlock +0 -2
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODM0M2E0ODAyNDY5MzJhZDJhNjU1ZDc5MmMzM2JkN2I4MTA4YjMwNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NThjOTI1M2JjNzYyMjQ4YWIxOGQ4OGNmZWE0NGI0YTI1M2FlMWVlNg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDU2ZGQwMzA0ZWUwMWNjY2Q4MjFiMmNhY2MxNDIwODIyMmRiOGJlZDQ1N2Fk
|
10
|
+
YTJlZWUwMTg2ZTc5OWQ3YjgwYzY5OTFmYWFiZjQwYTFkYjk5OWVjY2I2OTFk
|
11
|
+
N2M0MzRmYTY3OTlhOTQyYWNiYTUzNjY1ZGRmZGJjMmEyMTE3NDk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzAyNjFjYzk3YjgzZmE3M2YyNjZmNjhkZTliZTdhMmFjNDFlNDdhZmIwNzIw
|
14
|
+
OTM2NWI3ZWNhNzI3ZmIzOTU4NGIzNjcyOTUwNmMyNWFhNThiNTAzMTIyYTY1
|
15
|
+
ZmRhYTViMzc0Zjc3MTA1ZmYwMzBlYmFlYjlkNTA3ZTY0OGI1NjE=
|
data/README
CHANGED
@@ -5,7 +5,7 @@ URLS
|
|
5
5
|
|
6
6
|
SYNOPSIS
|
7
7
|
|
8
|
-
lib/lockfile.rb : a ruby library for creating NFS safe lockfiles
|
8
|
+
lib/lockfile.rb : a ruby library for creating perfect and NFS safe lockfiles
|
9
9
|
|
10
10
|
bin/rlock : ruby command line tool which uses this library to create lockfiles
|
11
11
|
and to run arbitrary commands while holding them.
|
@@ -158,6 +158,8 @@ BUGS
|
|
158
158
|
bugno > 1 && bugno < 42
|
159
159
|
|
160
160
|
HISTORY
|
161
|
+
2.0.0:
|
162
|
+
- lock fires up a refresher thread when called without a block
|
161
163
|
|
162
164
|
1.4.3:
|
163
165
|
- fixed a small non-critical bug in the require gaurd
|
data/bin/rlock
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
#
|
8
8
|
# http://raa.ruby-lang.org/project/lockfile/
|
9
9
|
#
|
10
|
-
require 'lockfile
|
10
|
+
require 'lockfile'
|
11
11
|
|
12
12
|
class Main
|
13
13
|
#--{{{
|
@@ -49,7 +49,7 @@
|
|
49
49
|
failure => $? != 0
|
50
50
|
|
51
51
|
AUTHOR
|
52
|
-
ara.t.howard@
|
52
|
+
ara.t.howard@gmail.com
|
53
53
|
|
54
54
|
BUGS
|
55
55
|
1 < bugno && bugno < 42
|
data/lib/lockfile.rb
CHANGED
@@ -5,9 +5,14 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
5
5
|
require 'fileutils'
|
6
6
|
|
7
7
|
class Lockfile
|
8
|
-
|
9
|
-
VERSION = '
|
10
|
-
def version() VERSION end
|
8
|
+
|
9
|
+
VERSION = '2.0.1'
|
10
|
+
def Lockfile.version() Lockfile::VERSION end
|
11
|
+
def version() Lockfile::VERSION end
|
12
|
+
|
13
|
+
def Lockfile.description
|
14
|
+
'a ruby library for creating perfect and NFS safe lockfiles'
|
15
|
+
end
|
11
16
|
|
12
17
|
class LockError < StandardError; end
|
13
18
|
class StolenLockError < LockError; end
|
@@ -19,13 +24,12 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
19
24
|
class UnLockError < LockError; end
|
20
25
|
|
21
26
|
class SleepCycle < Array
|
22
|
-
#--{{{
|
23
27
|
attr :min
|
24
28
|
attr :max
|
25
29
|
attr :range
|
26
30
|
attr :inc
|
27
|
-
|
28
|
-
|
31
|
+
|
32
|
+
def initialize(min, max, inc)
|
29
33
|
@min, @max, @inc = Float(min), Float(max), Float(inc)
|
30
34
|
@range = @max - @min
|
31
35
|
raise RangeError, "max(#{ @max }) <= min(#{ @min })" if @max <= @min
|
@@ -36,24 +40,20 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
36
40
|
push(s) and s += @inc while(s <= @max)
|
37
41
|
self[-1] = @max if self[-1] < @max
|
38
42
|
reset
|
39
|
-
#--}}}
|
40
43
|
end
|
44
|
+
|
41
45
|
def next
|
42
|
-
#--{{{
|
43
46
|
ret = self[@idx]
|
44
47
|
@idx = ((@idx + 1) % self.size)
|
45
48
|
ret
|
46
|
-
#--}}}
|
47
49
|
end
|
50
|
+
|
48
51
|
def reset
|
49
|
-
#--{{{
|
50
52
|
@idx = 0
|
51
|
-
#--}}}
|
52
53
|
end
|
53
|
-
#--}}}
|
54
54
|
end
|
55
55
|
|
56
|
-
HOSTNAME = Socket
|
56
|
+
HOSTNAME = Socket.gethostname
|
57
57
|
|
58
58
|
DEFAULT_RETRIES = nil # maximum number of attempts
|
59
59
|
DEFAULT_TIMEOUT = nil # the longest we will try
|
@@ -71,8 +71,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
71
71
|
|
72
72
|
DEFAULT_DEBUG = ENV['LOCKFILE_DEBUG'] || false
|
73
73
|
|
74
|
-
class <<
|
75
|
-
#--{{{
|
74
|
+
class << Lockfile
|
76
75
|
attr :retries, true
|
77
76
|
attr :max_age, true
|
78
77
|
attr :sleep_inc, true
|
@@ -89,7 +88,6 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
89
88
|
attr :dont_use_lock_id, true
|
90
89
|
|
91
90
|
def init
|
92
|
-
#--{{{
|
93
91
|
@retries = DEFAULT_RETRIES
|
94
92
|
@max_age = DEFAULT_MAX_AGE
|
95
93
|
@sleep_inc = DEFAULT_SLEEP_INC
|
@@ -108,17 +106,17 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
108
106
|
|
109
107
|
STDOUT.sync = true if @debug
|
110
108
|
STDERR.sync = true if @debug
|
111
|
-
#--}}}
|
112
109
|
end
|
113
|
-
#--}}}
|
114
110
|
end
|
115
|
-
|
111
|
+
|
112
|
+
Lockfile.init
|
116
113
|
|
117
114
|
attr :klass
|
118
115
|
attr :path
|
119
116
|
attr :opts
|
120
117
|
attr :locked
|
121
118
|
attr :thief
|
119
|
+
attr :refresher
|
122
120
|
attr :dirname
|
123
121
|
attr :basename
|
124
122
|
attr :clean
|
@@ -136,14 +134,13 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
136
134
|
attr :dont_sweep
|
137
135
|
attr :dont_use_lock_id
|
138
136
|
|
139
|
-
|
137
|
+
attr_accessor :debug
|
140
138
|
|
141
139
|
alias thief? thief
|
142
140
|
alias locked? locked
|
143
141
|
alias debug? debug
|
144
142
|
|
145
|
-
def
|
146
|
-
#--{{{
|
143
|
+
def Lockfile.create(path, *a, &b)
|
147
144
|
opts = {
|
148
145
|
'retries' => 0,
|
149
146
|
'min_sleep' => 0,
|
@@ -164,11 +161,9 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
164
161
|
raise Errno::EEXIST, path
|
165
162
|
end
|
166
163
|
open(path, *a, &b)
|
167
|
-
#--}}}
|
168
164
|
end
|
169
165
|
|
170
166
|
def initialize(path, opts = {}, &block)
|
171
|
-
#--{{{
|
172
167
|
@klass = self.class
|
173
168
|
@path = path
|
174
169
|
@opts = opts
|
@@ -188,19 +183,19 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
188
183
|
@dont_use_lock_id = getopt 'dont_use_lock_id' , @klass.dont_use_lock_id
|
189
184
|
@debug = getopt 'debug' , @klass.debug
|
190
185
|
|
191
|
-
@sleep_cycle = SleepCycle
|
186
|
+
@sleep_cycle = SleepCycle.new @min_sleep, @max_sleep, @sleep_inc
|
192
187
|
|
193
|
-
@clean = @dont_clean ? nil : lambda{ File
|
194
|
-
@dirname = File
|
195
|
-
@basename = File
|
188
|
+
@clean = @dont_clean ? nil : lambda{ File.unlink @path rescue nil }
|
189
|
+
@dirname = File.dirname @path
|
190
|
+
@basename = File.basename @path
|
196
191
|
@thief = false
|
197
192
|
@locked = false
|
193
|
+
@refrsher = nil
|
198
194
|
|
199
195
|
lock(&block) if block
|
200
|
-
#--}}}
|
201
196
|
end
|
197
|
+
|
202
198
|
def lock
|
203
|
-
#--{{{
|
204
199
|
raise StackingLockError, "<#{ @path }> is locked!" if @locked
|
205
200
|
|
206
201
|
sweep unless @dont_sweep
|
@@ -212,7 +207,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
212
207
|
@sleep_cycle.reset
|
213
208
|
create_tmplock do |f|
|
214
209
|
begin
|
215
|
-
Timeout
|
210
|
+
Timeout.timeout(@timeout) do
|
216
211
|
tmp_path = f.path
|
217
212
|
tmp_stat = f.lstat
|
218
213
|
n_retries = 0
|
@@ -222,25 +217,25 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
222
217
|
begin
|
223
218
|
trace{ "polling attempt <#{ i }>..." }
|
224
219
|
begin
|
225
|
-
File
|
220
|
+
File.link tmp_path, @path
|
226
221
|
rescue Errno::ENOENT
|
227
222
|
try_again!
|
228
223
|
end
|
229
|
-
lock_stat = File
|
224
|
+
lock_stat = File.lstat @path
|
230
225
|
raise StatLockError, "stat's do not agree" unless
|
231
226
|
tmp_stat.rdev == lock_stat.rdev and tmp_stat.ino == lock_stat.ino
|
232
227
|
trace{ "aquired lock <#{ @path }>" }
|
233
228
|
@locked = true
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
229
|
+
rescue => e
|
230
|
+
i += 1
|
231
|
+
unless i >= @poll_retries
|
232
|
+
t = [rand(@poll_max_sleep), @poll_max_sleep].min
|
233
|
+
trace{ "poll sleep <#{ t }>..." }
|
234
|
+
sleep t
|
235
|
+
retry
|
236
|
+
end
|
237
|
+
raise
|
241
238
|
end
|
242
|
-
raise
|
243
|
-
end
|
244
239
|
|
245
240
|
rescue => e
|
246
241
|
n_retries += 1
|
@@ -256,7 +251,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
256
251
|
when false
|
257
252
|
trace{ "found invalid lock and removing" }
|
258
253
|
begin
|
259
|
-
File
|
254
|
+
File.unlink @path
|
260
255
|
@thief = true
|
261
256
|
warn "<#{ @path }> stolen by <#{ Process.pid }> at <#{ timestamp }>"
|
262
257
|
trace{ "i am a thief!" }
|
@@ -278,7 +273,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
278
273
|
|
279
274
|
if block_given?
|
280
275
|
stolen = false
|
281
|
-
refresher = (@refresh ? new_refresher : nil)
|
276
|
+
@refresher = (@refresh ? new_refresher : nil)
|
282
277
|
begin
|
283
278
|
begin
|
284
279
|
ret = yield @path
|
@@ -288,12 +283,14 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
288
283
|
end
|
289
284
|
ensure
|
290
285
|
begin
|
291
|
-
refresher.kill if refresher and refresher.status
|
286
|
+
@refresher.kill if @refresher and @refresher.status
|
287
|
+
@refresher = nil
|
292
288
|
ensure
|
293
289
|
unlock unless stolen
|
294
290
|
end
|
295
291
|
end
|
296
292
|
else
|
293
|
+
@refresher = (@refresh ? new_refresher : nil)
|
297
294
|
ObjectSpace.define_finalizer self, @clean if @clean
|
298
295
|
ret = self
|
299
296
|
end
|
@@ -303,16 +300,15 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
303
300
|
end
|
304
301
|
|
305
302
|
return ret
|
306
|
-
#--}}}
|
307
303
|
end
|
304
|
+
|
308
305
|
def sweep
|
309
|
-
#----{{{
|
310
306
|
begin
|
311
|
-
glob = File
|
307
|
+
glob = File.join(@dirname, ".*lck")
|
312
308
|
paths = Dir[glob]
|
313
309
|
paths.each do |path|
|
314
310
|
begin
|
315
|
-
basename = File
|
311
|
+
basename = File.basename path
|
316
312
|
pat = %r/^\s*\.([^_]+)_([^_]+)/o
|
317
313
|
if pat.match(basename)
|
318
314
|
host, pid = $1, $2
|
@@ -327,7 +323,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
327
323
|
unless alive?(pid)
|
328
324
|
trace{ "process <#{ pid }> on <#{ host }> is no longer alive" }
|
329
325
|
trace{ "sweeping <#{ path }>" }
|
330
|
-
FileUtils
|
326
|
+
FileUtils.rm_f path
|
331
327
|
else
|
332
328
|
trace{ "process <#{ pid }> on <#{ host }> is still alive" }
|
333
329
|
trace{ "ignoring <#{ path }>" }
|
@@ -342,24 +338,26 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
342
338
|
rescue => e
|
343
339
|
warn(errmsg(e))
|
344
340
|
end
|
345
|
-
#----}}}
|
346
341
|
end
|
342
|
+
|
347
343
|
def alive? pid
|
348
|
-
#----{{{
|
349
344
|
pid = Integer("#{ pid }")
|
350
345
|
begin
|
351
|
-
Process
|
346
|
+
Process.kill 0, pid
|
352
347
|
true
|
353
348
|
rescue Errno::ESRCH
|
354
349
|
false
|
355
350
|
end
|
356
|
-
#----}}}
|
357
351
|
end
|
352
|
+
|
358
353
|
def unlock
|
359
|
-
#--{{{
|
360
354
|
raise UnLockError, "<#{ @path }> is not locked!" unless @locked
|
355
|
+
|
356
|
+
@refresher.kill if @refresher and @refresher.status
|
357
|
+
@refresher = nil
|
358
|
+
|
361
359
|
begin
|
362
|
-
File
|
360
|
+
File.unlink @path
|
363
361
|
rescue Errno::ENOENT
|
364
362
|
raise StolenLockError, @path
|
365
363
|
ensure
|
@@ -367,11 +365,10 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
367
365
|
@locked = false
|
368
366
|
ObjectSpace.undefine_finalizer self if @clean
|
369
367
|
end
|
370
|
-
#--}}}
|
371
368
|
end
|
369
|
+
|
372
370
|
def new_refresher
|
373
|
-
|
374
|
-
Thread::new(Thread::current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
|
371
|
+
Thread.new(Thread.current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
|
375
372
|
loop do
|
376
373
|
begin
|
377
374
|
touch path
|
@@ -385,48 +382,45 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
385
382
|
rescue Exception => e
|
386
383
|
trace{errmsg e}
|
387
384
|
thread.raise StolenLockError
|
388
|
-
Thread
|
385
|
+
Thread.exit
|
389
386
|
end
|
390
387
|
end
|
391
388
|
end
|
392
|
-
#--}}}
|
393
389
|
end
|
390
|
+
|
394
391
|
def validlock?
|
395
|
-
#--{{{
|
396
392
|
if @max_age
|
397
393
|
uncache @path rescue nil
|
398
394
|
begin
|
399
|
-
return((Time.now - File
|
395
|
+
return((Time.now - File.stat(@path).mtime) < @max_age)
|
400
396
|
rescue Errno::ENOENT
|
401
397
|
return nil
|
402
398
|
end
|
403
399
|
else
|
404
|
-
exist = File
|
400
|
+
exist = File.exist?(@path)
|
405
401
|
return(exist ? true : nil)
|
406
402
|
end
|
407
|
-
#--}}}
|
408
403
|
end
|
404
|
+
|
409
405
|
def uncache file
|
410
|
-
#--{{{
|
411
406
|
refresh = nil
|
412
407
|
begin
|
413
408
|
is_a_file = File === file
|
414
409
|
path = (is_a_file ? file.path : file.to_s)
|
415
|
-
stat = (is_a_file ? file.stat : File
|
416
|
-
refresh = tmpnam(File
|
417
|
-
File
|
418
|
-
File
|
419
|
-
File
|
410
|
+
stat = (is_a_file ? file.stat : File.stat(file.to_s))
|
411
|
+
refresh = tmpnam(File.dirname(path))
|
412
|
+
File.link path, refresh
|
413
|
+
File.chmod stat.mode, path
|
414
|
+
File.utime stat.atime, stat.mtime, path
|
420
415
|
ensure
|
421
416
|
begin
|
422
|
-
File
|
417
|
+
File.unlink refresh if refresh
|
423
418
|
rescue Errno::ENOENT
|
424
419
|
end
|
425
420
|
end
|
426
|
-
#--}}}
|
427
421
|
end
|
422
|
+
|
428
423
|
def create_tmplock
|
429
|
-
#--{{{
|
430
424
|
tmplock = tmpnam @dirname
|
431
425
|
begin
|
432
426
|
create(tmplock) do |f|
|
@@ -440,124 +434,106 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
|
|
440
434
|
yield f
|
441
435
|
end
|
442
436
|
ensure
|
443
|
-
begin; File
|
437
|
+
begin; File.unlink tmplock; rescue Errno::ENOENT; end if tmplock
|
444
438
|
end
|
445
|
-
#--}}}
|
446
439
|
end
|
440
|
+
|
447
441
|
def gen_lock_id
|
448
|
-
#--{{{
|
449
442
|
Hash[
|
450
443
|
'host' => "#{ HOSTNAME }",
|
451
444
|
'pid' => "#{ Process.pid }",
|
452
445
|
'ppid' => "#{ Process.ppid }",
|
453
446
|
'time' => timestamp,
|
454
447
|
]
|
455
|
-
#--}}}
|
456
448
|
end
|
449
|
+
|
457
450
|
def timestamp
|
458
|
-
#--{{{
|
459
451
|
time = Time.now
|
460
452
|
usec = time.usec.to_s
|
461
453
|
usec << '0' while usec.size < 6
|
462
454
|
"#{ time.strftime('%Y-%m-%d %H:%M:%S') }.#{ usec }"
|
463
|
-
#--}}}
|
464
455
|
end
|
465
|
-
|
466
|
-
|
456
|
+
|
457
|
+
def dump_lock_id(lock_id = @lock_id)
|
467
458
|
"host: %s\npid: %s\nppid: %s\ntime: %s\n" %
|
468
459
|
lock_id.values_at('host','pid','ppid','time')
|
469
|
-
#--}}}
|
470
460
|
end
|
471
|
-
|
472
|
-
|
461
|
+
|
462
|
+
def load_lock_id(buf)
|
473
463
|
lock_id = {}
|
474
464
|
kv = %r/([^:]+):(.*)/o
|
475
|
-
buf.
|
465
|
+
buf.each_line do |line|
|
476
466
|
m = kv.match line
|
477
467
|
k, v = m[1], m[2]
|
478
468
|
next unless m and k and v
|
479
469
|
lock_id[k.strip] = v.strip
|
480
470
|
end
|
481
471
|
lock_id
|
482
|
-
#--}}}
|
483
472
|
end
|
484
|
-
|
485
|
-
|
473
|
+
|
474
|
+
def tmpnam(dir, seed = File.basename($0))
|
486
475
|
pid = Process.pid
|
487
476
|
time = Time.now
|
488
477
|
sec = time.to_i
|
489
478
|
usec = time.usec
|
490
479
|
"%s%s.%s_%d_%s_%d_%d_%d.lck" %
|
491
480
|
[dir, File::SEPARATOR, HOSTNAME, pid, seed, sec, usec, rand(sec)]
|
492
|
-
#--}}}
|
493
481
|
end
|
494
|
-
|
495
|
-
|
482
|
+
|
483
|
+
def create(path)
|
496
484
|
umask = nil
|
497
485
|
f = nil
|
498
486
|
begin
|
499
|
-
umask = File
|
487
|
+
umask = File.umask 022
|
500
488
|
f = open path, File::WRONLY|File::CREAT|File::EXCL, 0644
|
501
489
|
ensure
|
502
|
-
File
|
490
|
+
File.umask umask if umask
|
503
491
|
end
|
504
492
|
return(block_given? ? begin; yield f; ensure; f.close; end : f)
|
505
|
-
#--}}}
|
506
493
|
end
|
507
|
-
|
508
|
-
|
494
|
+
|
495
|
+
def touch(path)
|
509
496
|
FileUtils.touch path
|
510
|
-
#--}}}
|
511
497
|
end
|
512
|
-
|
513
|
-
|
498
|
+
|
499
|
+
def getopt(key, default = nil)
|
514
500
|
[ key, key.to_s, key.to_s.intern ].each do |k|
|
515
501
|
return @opts[k] if @opts.has_key?(k)
|
516
502
|
end
|
517
503
|
return default
|
518
|
-
#--}}}
|
519
504
|
end
|
505
|
+
|
520
506
|
def to_str
|
521
|
-
#--{{{
|
522
507
|
@path
|
523
|
-
#--}}}
|
524
508
|
end
|
525
509
|
alias to_s to_str
|
526
|
-
|
527
|
-
|
510
|
+
|
511
|
+
def trace(s = nil)
|
528
512
|
STDERR.puts((s ? s : yield)) if @debug
|
529
|
-
#--}}}
|
530
513
|
end
|
531
|
-
|
532
|
-
|
514
|
+
|
515
|
+
def errmsg(e)
|
533
516
|
"%s (%s)\n%s\n" % [e.class, e.message, e.backtrace.join("\n")]
|
534
|
-
#--}}}
|
535
517
|
end
|
518
|
+
|
536
519
|
def attempt
|
537
|
-
#----{{{
|
538
520
|
ret = nil
|
539
521
|
loop{ break unless catch('attempt'){ ret = yield } == 'try_again' }
|
540
522
|
ret
|
541
|
-
#----}}}
|
542
523
|
end
|
524
|
+
|
543
525
|
def try_again!
|
544
|
-
#----{{{
|
545
526
|
throw 'attempt', 'try_again'
|
546
|
-
#----}}}
|
547
527
|
end
|
548
528
|
alias again! try_again!
|
529
|
+
|
549
530
|
def give_up!
|
550
|
-
#----{{{
|
551
531
|
throw 'attempt', 'give_up'
|
552
|
-
#----}}}
|
553
532
|
end
|
554
|
-
#--}}}
|
555
533
|
end
|
556
534
|
|
557
|
-
def Lockfile
|
558
|
-
#--{{{
|
535
|
+
def Lockfile(path, *a, &b)
|
559
536
|
Lockfile.new(path, *a, &b)
|
560
|
-
#--}}}
|
561
537
|
end
|
562
538
|
|
563
539
|
$__lockfile__ = __FILE__
|