lockfile 1.4.3 → 2.0.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.
- 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__
|