scout-gear 7.2.0 → 8.0.0
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 +4 -4
- data/.vimproject +51 -6
- data/VERSION +1 -1
- data/bin/scout +6 -3
- data/lib/rbbt-scout.rb +1 -0
- data/lib/scout/cmd.rb +1 -1
- data/lib/scout/concurrent_stream.rb +33 -29
- data/lib/scout/config.rb +1 -1
- data/lib/scout/exceptions.rb +1 -0
- data/lib/scout/log/color.rb +4 -2
- data/lib/scout/log/progress/report.rb +1 -1
- data/lib/scout/log/progress/util.rb +71 -2
- data/lib/scout/log/progress.rb +1 -1
- data/lib/scout/log/trap.rb +107 -0
- data/lib/scout/log.rb +56 -21
- data/lib/scout/meta_extension.rb +13 -6
- data/lib/scout/misc/digest.rb +1 -1
- data/lib/scout/misc/format.rb +12 -0
- data/lib/scout/misc/helper.rb +31 -0
- data/lib/scout/misc/insist.rb +1 -1
- data/lib/scout/misc/monitor.rb +12 -1
- data/lib/scout/misc/system.rb +10 -0
- data/lib/scout/misc.rb +1 -0
- data/lib/scout/named_array.rb +65 -3
- data/lib/scout/open/lock/lockfile.rb +587 -0
- data/lib/scout/open/lock.rb +28 -2
- data/lib/scout/open/remote.rb +4 -0
- data/lib/scout/open/stream.rb +111 -42
- data/lib/scout/open/util.rb +13 -3
- data/lib/scout/path/find.rb +9 -1
- data/lib/scout/path/util.rb +35 -0
- data/lib/scout/persist/serialize.rb +18 -5
- data/lib/scout/persist.rb +60 -30
- data/lib/scout/resource/path.rb +53 -0
- data/lib/scout/resource/produce.rb +0 -8
- data/lib/scout/resource/util.rb +2 -1
- data/lib/scout/semaphore.rb +8 -1
- data/lib/scout/tmpfile.rb +7 -8
- data/lib/scout/tsv/attach.rb +177 -0
- data/lib/scout/tsv/change_id.rb +40 -0
- data/lib/scout/tsv/dumper.rb +85 -54
- data/lib/scout/tsv/index.rb +188 -20
- data/lib/scout/tsv/open.rb +182 -0
- data/lib/scout/tsv/parser.rb +200 -118
- data/lib/scout/tsv/path.rb +5 -6
- data/lib/scout/tsv/persist/adapter.rb +26 -37
- data/lib/scout/tsv/persist/fix_width_table.rb +327 -0
- data/lib/scout/tsv/persist/serialize.rb +117 -0
- data/lib/scout/tsv/persist/tokyocabinet.rb +6 -3
- data/lib/scout/tsv/persist.rb +4 -2
- data/lib/scout/tsv/transformer.rb +141 -0
- data/lib/scout/tsv/traverse.rb +136 -37
- data/lib/scout/tsv/util/filter.rb +312 -0
- data/lib/scout/tsv/util/process.rb +73 -0
- data/lib/scout/tsv/util/reorder.rb +81 -0
- data/lib/scout/tsv/util/select.rb +265 -0
- data/lib/scout/tsv/util/unzip.rb +86 -0
- data/lib/scout/tsv/util.rb +126 -19
- data/lib/scout/tsv.rb +28 -5
- data/lib/scout/work_queue/socket.rb +6 -1
- data/lib/scout/work_queue/worker.rb +5 -2
- data/lib/scout/work_queue.rb +15 -8
- data/lib/scout/workflow/definition.rb +29 -2
- data/lib/scout/workflow/step/dependencies.rb +24 -4
- data/lib/scout/workflow/step/info.rb +40 -5
- data/lib/scout/workflow/step/progress.rb +14 -0
- data/lib/scout/workflow/step/provenance.rb +8 -7
- data/lib/scout/workflow/step/status.rb +45 -0
- data/lib/scout/workflow/step.rb +104 -33
- data/lib/scout/workflow/task/inputs.rb +14 -20
- data/lib/scout/workflow/task.rb +86 -47
- data/lib/scout/workflow/usage.rb +10 -6
- data/scout-gear.gemspec +30 -3
- data/scout_commands/workflow/task +37 -9
- data/scout_commands/workflow/task_old +2 -2
- data/test/scout/open/test_stream.rb +61 -59
- data/test/scout/path/test_find.rb +10 -1
- data/test/scout/resource/test_produce.rb +15 -0
- data/test/scout/test_meta_extension.rb +25 -0
- data/test/scout/test_named_array.rb +18 -0
- data/test/scout/test_persist.rb +67 -0
- data/test/scout/test_tmpfile.rb +1 -1
- data/test/scout/test_tsv.rb +222 -3
- data/test/scout/test_work_queue.rb +21 -18
- data/test/scout/tsv/persist/test_adapter.rb +11 -1
- data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
- data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
- data/test/scout/tsv/test_attach.rb +227 -0
- data/test/scout/tsv/test_change_id.rb +98 -0
- data/test/scout/tsv/test_dumper.rb +1 -1
- data/test/scout/tsv/test_index.rb +127 -3
- data/test/scout/tsv/test_open.rb +167 -0
- data/test/scout/tsv/test_parser.rb +45 -3
- data/test/scout/tsv/test_persist.rb +9 -0
- data/test/scout/tsv/test_transformer.rb +108 -0
- data/test/scout/tsv/test_traverse.rb +195 -3
- data/test/scout/tsv/test_util.rb +24 -0
- data/test/scout/tsv/util/test_filter.rb +188 -0
- data/test/scout/tsv/util/test_process.rb +47 -0
- data/test/scout/tsv/util/test_reorder.rb +94 -0
- data/test/scout/tsv/util/test_select.rb +58 -0
- data/test/scout/tsv/util/test_unzip.rb +112 -0
- data/test/scout/work_queue/test_socket.rb +0 -1
- data/test/scout/work_queue/test_worker.rb +63 -6
- data/test/scout/workflow/step/test_load.rb +3 -3
- data/test/scout/workflow/step/test_status.rb +31 -0
- data/test/scout/workflow/task/test_inputs.rb +14 -14
- data/test/scout/workflow/test_step.rb +13 -13
- data/test/scout/workflow/test_task.rb +168 -32
- data/test/scout/workflow/test_usage.rb +33 -6
- data/test/test_helper.rb +3 -1
- metadata +29 -2
data/lib/scout/open/stream.rb
CHANGED
@@ -54,11 +54,10 @@ module Open
|
|
54
54
|
|
55
55
|
into_close = false unless into.respond_to? :close
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
rescue EOFError
|
57
|
+
while c = io.read(BLOCK_SIZE)
|
58
|
+
into << c if into
|
59
|
+
last_c = c if c
|
60
|
+
break if io.closed?
|
62
61
|
end
|
63
62
|
|
64
63
|
io.join if io.respond_to? :join
|
@@ -67,13 +66,15 @@ module Open
|
|
67
66
|
into.close if into and into_close and not into.closed?
|
68
67
|
block.call if block_given?
|
69
68
|
|
70
|
-
|
69
|
+
last_c
|
71
70
|
rescue Aborted
|
71
|
+
Thread.current["exception"] = true
|
72
72
|
Log.low "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
|
73
73
|
io.abort $! if io.respond_to? :abort
|
74
74
|
into.close if into.respond_to?(:closed?) && ! into.closed?
|
75
75
|
FileUtils.rm into_path if into_path and File.exist?(into_path)
|
76
76
|
rescue Exception
|
77
|
+
Thread.current["exception"] = true
|
77
78
|
Log.low "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
|
78
79
|
exception = (io.respond_to?(:stream_exception) && io.stream_exception) ? io.stream_exception : $!
|
79
80
|
io.abort exception if io.respond_to? :abort
|
@@ -111,7 +112,6 @@ module Open
|
|
111
112
|
FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory?(File.dirname(tmp_path))
|
112
113
|
FileUtils.rm_f tmp_path if File.exist? tmp_path
|
113
114
|
begin
|
114
|
-
|
115
115
|
case
|
116
116
|
when block_given?
|
117
117
|
File.open(tmp_path, 'wb', &block)
|
@@ -119,13 +119,10 @@ module Open
|
|
119
119
|
File.open(tmp_path, 'wb') do |f| f.write content end
|
120
120
|
when (IO === content or StringIO === content or File === content)
|
121
121
|
Open.write(tmp_path) do |f|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
rescue EOFError
|
128
|
-
end
|
122
|
+
while block = content.read(BLOCK_SIZE)
|
123
|
+
f.write block
|
124
|
+
break if content.closed?
|
125
|
+
end
|
129
126
|
end
|
130
127
|
else
|
131
128
|
File.open(tmp_path, 'wb') do |f| end
|
@@ -143,14 +140,15 @@ module Open
|
|
143
140
|
content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
|
144
141
|
|
145
142
|
Open.notify_write(path)
|
143
|
+
Log.debug "Done sensible write: [#{Process.pid}] -- #{ path }"
|
146
144
|
rescue Aborted
|
147
|
-
Log.low "Aborted sensible_write -- #{ Log.reset <<
|
145
|
+
Log.low "Aborted sensible_write -- #{ Log.reset << path }"
|
148
146
|
content.abort if content.respond_to? :abort
|
149
147
|
Open.rm path if File.exist? path
|
150
148
|
rescue Exception
|
151
149
|
exception = (AbortedStream === content and content.exception) ? content.exception : $!
|
152
|
-
Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{
|
153
|
-
content.abort if content.respond_to? :abort
|
150
|
+
Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ path }"
|
151
|
+
content.abort(exception) if content.respond_to? :abort
|
154
152
|
Open.rm path if File.exist? path
|
155
153
|
raise exception
|
156
154
|
rescue
|
@@ -191,7 +189,7 @@ module Open
|
|
191
189
|
FileUtils.rm path if erase && File.exist?(path)
|
192
190
|
end
|
193
191
|
end
|
194
|
-
|
192
|
+
|
195
193
|
def self.release_pipes(*pipes)
|
196
194
|
PIPE_MUTEX.synchronize do
|
197
195
|
pipes.flatten.each do |pipe|
|
@@ -243,7 +241,7 @@ module Open
|
|
243
241
|
begin
|
244
242
|
Thread.current.report_on_exception = false
|
245
243
|
Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
|
246
|
-
|
244
|
+
|
247
245
|
yield sin
|
248
246
|
|
249
247
|
sin.close if close and not sin.closed? and not sin.aborted?
|
@@ -290,31 +288,36 @@ module Open
|
|
290
288
|
Thread.current["name"] = "Splitter #{Log.fingerprint stream}"
|
291
289
|
|
292
290
|
skip = [false] * num
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
end unless skip[i]
|
306
|
-
end
|
291
|
+
while block = stream.read(BLOCK_SIZE)
|
292
|
+
|
293
|
+
in_pipes.each_with_index do |sin,i|
|
294
|
+
begin
|
295
|
+
sin.write block
|
296
|
+
rescue IOError
|
297
|
+
Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
|
298
|
+
skip[i] = true
|
299
|
+
rescue
|
300
|
+
Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
|
301
|
+
raise $!
|
302
|
+
end unless skip[i]
|
307
303
|
end
|
308
|
-
|
304
|
+
break if stream.closed?
|
309
305
|
end
|
310
306
|
|
311
307
|
stream.join if stream.respond_to? :join
|
312
308
|
stream.close unless stream.closed?
|
313
309
|
in_pipes.first.close unless in_pipes.first.closed?
|
314
310
|
rescue Aborted, Interrupt
|
315
|
-
stream.abort if stream.respond_to?
|
316
|
-
out_pipes.each do |sout|
|
317
|
-
sout.
|
311
|
+
stream.abort if stream.respond_to?(:abort) && ! stream.aborted?
|
312
|
+
out_pipes.reverse.each do |sout|
|
313
|
+
sout.threads.delete(Thread.current)
|
314
|
+
begin
|
315
|
+
sout.abort($!) if sout.respond_to?(:abort) && ! sout.aborted?
|
316
|
+
rescue
|
317
|
+
end
|
318
|
+
end
|
319
|
+
in_pipes.each do |sin|
|
320
|
+
sin.close unless sin.closed?
|
318
321
|
end
|
319
322
|
Log.low "Tee aborting #{Log.fingerprint stream}"
|
320
323
|
raise $!
|
@@ -333,12 +336,14 @@ module Open
|
|
333
336
|
end
|
334
337
|
Log.low "Tee exception #{Log.fingerprint stream}"
|
335
338
|
rescue
|
336
|
-
Log.exception $!
|
337
339
|
ensure
|
338
|
-
|
339
|
-
|
340
|
+
begin
|
341
|
+
in_pipes.each do |sin|
|
342
|
+
sin.close unless sin.closed?
|
343
|
+
end
|
344
|
+
ensure
|
345
|
+
raise $!
|
340
346
|
end
|
341
|
-
raise $!
|
342
347
|
end
|
343
348
|
end
|
344
349
|
end
|
@@ -397,7 +402,7 @@ module Open
|
|
397
402
|
end
|
398
403
|
str
|
399
404
|
end
|
400
|
-
|
405
|
+
|
401
406
|
def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
|
402
407
|
Open.open_pipe do |sin|
|
403
408
|
line = stream.gets
|
@@ -431,5 +436,69 @@ module Open
|
|
431
436
|
end
|
432
437
|
end
|
433
438
|
|
439
|
+
def self.process_stream(s)
|
440
|
+
begin
|
441
|
+
yield s
|
442
|
+
s.close if s.respond_to?(:close) && ! s.closed?
|
443
|
+
s.join if s.respond_to?(:join)
|
444
|
+
rescue
|
445
|
+
s.abort($!) if s.respond_to? :abort
|
446
|
+
raise $!
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
|
451
|
+
def self.collapse_stream(s, line: nil, sep: "\t", header: nil, &block)
|
452
|
+
sep ||= "\t"
|
453
|
+
Open.open_pipe do |sin|
|
454
|
+
sin.puts header if header
|
455
|
+
process_stream(s) do |s|
|
456
|
+
line ||= s.gets
|
457
|
+
|
458
|
+
current_parts = []
|
459
|
+
while line
|
460
|
+
key, *parts = line.chomp.split(sep, -1)
|
461
|
+
case
|
462
|
+
when key.nil?
|
463
|
+
when current_parts.nil?
|
464
|
+
current_parts = parts
|
465
|
+
current_key = key
|
466
|
+
when current_key == key
|
467
|
+
parts.each_with_index do |part,i|
|
468
|
+
if current_parts[i].nil?
|
469
|
+
current_parts[i] = "|" << part
|
470
|
+
else
|
471
|
+
current_parts[i] = current_parts[i] << "|" << part
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
(parts.length..current_parts.length-1).to_a.each do |pos|
|
476
|
+
current_parts[pos] = current_parts[pos] << "|" << ""
|
477
|
+
end
|
478
|
+
when current_key.nil?
|
479
|
+
current_key = key
|
480
|
+
current_parts = parts
|
481
|
+
when current_key != key
|
482
|
+
if block_given?
|
483
|
+
res = block.call(current_parts)
|
484
|
+
sin.puts [current_key, res] * sep
|
485
|
+
else
|
486
|
+
sin.puts [current_key, current_parts].flatten * sep
|
487
|
+
end
|
488
|
+
current_key = key
|
489
|
+
current_parts = parts
|
490
|
+
end
|
491
|
+
line = s.gets
|
492
|
+
end
|
493
|
+
|
494
|
+
if block_given?
|
495
|
+
res = block.call(current_parts)
|
496
|
+
sin.puts [current_key, res] * sep
|
497
|
+
else
|
498
|
+
sin.puts [current_key, current_parts].flatten * sep
|
499
|
+
end unless current_key.nil?
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
434
503
|
|
435
504
|
end
|
data/lib/scout/open/util.rb
CHANGED
@@ -94,6 +94,11 @@ module Open
|
|
94
94
|
File.symlink?(path) && ! File.exist?(File.readlink(path))
|
95
95
|
end
|
96
96
|
|
97
|
+
def self.directory?(file)
|
98
|
+
file = file.find if Path === file
|
99
|
+
File.directory?(file)
|
100
|
+
end
|
101
|
+
|
97
102
|
def self.exists?(file)
|
98
103
|
file = file.find if Path === file
|
99
104
|
File.exist?(file)
|
@@ -111,7 +116,7 @@ module Open
|
|
111
116
|
end
|
112
117
|
|
113
118
|
def self.rm(file)
|
114
|
-
FileUtils.rm(file) if File.exist?(file)
|
119
|
+
FileUtils.rm(file) if File.exist?(file) || Open.broken_link?(file)
|
115
120
|
end
|
116
121
|
|
117
122
|
def self.rm_rf(file)
|
@@ -155,7 +160,7 @@ module Open
|
|
155
160
|
begin
|
156
161
|
if File.symlink?(file) || File.stat(file).nlink > 1
|
157
162
|
if File.exist?(file + '.info') && defined?(Step)
|
158
|
-
done =
|
163
|
+
done = Persist.load(file + '.info', Step::SERIALIZER)[:done]
|
159
164
|
return done if done
|
160
165
|
end
|
161
166
|
|
@@ -173,7 +178,7 @@ module Open
|
|
173
178
|
target = target.find if Path === target
|
174
179
|
|
175
180
|
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
176
|
-
FileUtils.
|
181
|
+
FileUtils.rm_rf target if File.exist?(target)
|
177
182
|
FileUtils.cp_r source, target
|
178
183
|
end
|
179
184
|
|
@@ -222,4 +227,9 @@ module Open
|
|
222
227
|
end
|
223
228
|
nil
|
224
229
|
end
|
230
|
+
|
231
|
+
def self.list(file)
|
232
|
+
file = file.produce_and_find if Path === file
|
233
|
+
Open.read(file).split("\n")
|
234
|
+
end
|
225
235
|
end
|
data/lib/scout/path/find.rb
CHANGED
@@ -10,8 +10,10 @@ module Path
|
|
10
10
|
file =~ /(?:scout|rbbt)\/(?:.*\/)?path\.rb/ or
|
11
11
|
file =~ /(?:scout|rbbt)\/(?:.*\/)?path\/(?:find|refactor|util)\.rb/ or
|
12
12
|
file =~ /(?:scout|rbbt)\/persist.rb/ or
|
13
|
+
file =~ /scout\/resource\/produce.rb/ or
|
13
14
|
file =~ /modules\/rbbt-util/
|
14
15
|
end
|
16
|
+
return nil if file.nil?
|
15
17
|
file = file.sub(/\.rb[^\w].*/,'.rb')
|
16
18
|
end
|
17
19
|
|
@@ -38,7 +40,7 @@ module Path
|
|
38
40
|
sub('{SUBPATH}', path._subpath).
|
39
41
|
sub('{BASENAME}', File.basename(path)).
|
40
42
|
sub('{PATH}', path).
|
41
|
-
sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir).
|
43
|
+
sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir || "NOLIBDIR").
|
42
44
|
sub('{MAPNAME}', map_name.to_s).
|
43
45
|
sub('{REMOVE}/', '').
|
44
46
|
sub('{REMOVE}', '').gsub(/\/+/,'/')
|
@@ -188,4 +190,10 @@ module Path
|
|
188
190
|
.select{|file| file.exist? }.uniq
|
189
191
|
end
|
190
192
|
|
193
|
+
def find_with_extension(extension, *args)
|
194
|
+
found = self.find(*args)
|
195
|
+
return found if found.exists?
|
196
|
+
found_with_extension = self.set_extension(extension).find
|
197
|
+
found_with_extension.exists? ? found_with_extension : found
|
198
|
+
end
|
191
199
|
end
|
data/lib/scout/path/util.rb
CHANGED
@@ -12,6 +12,23 @@ module Path
|
|
12
12
|
return false
|
13
13
|
end
|
14
14
|
|
15
|
+
def self.sanitize_filename(filename, length = 254)
|
16
|
+
if filename.length > length
|
17
|
+
if filename =~ /(\..{2,9})$/
|
18
|
+
extension = $1
|
19
|
+
else
|
20
|
+
extension = ''
|
21
|
+
end
|
22
|
+
|
23
|
+
post_fix = "--#{filename.length}@#{length}_#{Misc.digest(filename)[0..4]}" + extension
|
24
|
+
|
25
|
+
filename = filename[0..(length - post_fix.length - 1)] << post_fix
|
26
|
+
else
|
27
|
+
filename
|
28
|
+
end
|
29
|
+
filename
|
30
|
+
end
|
31
|
+
|
15
32
|
def directory?
|
16
33
|
return nil unless self.exist?
|
17
34
|
File.directory?(self.find)
|
@@ -64,4 +81,22 @@ module Path
|
|
64
81
|
def set_extension(extension)
|
65
82
|
self.annotate(self + ".#{extension}")
|
66
83
|
end
|
84
|
+
|
85
|
+
# Is 'file' newer than 'path'? return non-true if path is newer than file
|
86
|
+
def self.newer?(path, file, by_link = false)
|
87
|
+
return true if not Open.exists?(file)
|
88
|
+
path = path.find if Path === path
|
89
|
+
file = file.find if Path === file
|
90
|
+
if by_link
|
91
|
+
patht = File.exist?(path) ? File.lstat(path).mtime : nil
|
92
|
+
filet = File.exist?(file) ? File.lstat(file).mtime : nil
|
93
|
+
else
|
94
|
+
patht = Open.mtime(path)
|
95
|
+
filet = Open.mtime(file)
|
96
|
+
end
|
97
|
+
return true if patht.nil? || filet.nil?
|
98
|
+
diff = patht - filet
|
99
|
+
return diff if diff < 0
|
100
|
+
return false
|
101
|
+
end
|
67
102
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../open'
|
2
2
|
require_relative 'open'
|
3
|
+
require 'set'
|
3
4
|
|
4
5
|
module Persist
|
5
6
|
TRUE_STRINGS = Set.new ["true", "True", "TRUE", "t", "T", "1", "yes", "Yes", "YES", "y", "Y", "ON", "on"] unless defined? TRUE_STRINGS
|
@@ -19,7 +20,7 @@ module Persist
|
|
19
20
|
type = type.to_sym if String === type
|
20
21
|
type = SERIALIZER if type == :serializer
|
21
22
|
case type
|
22
|
-
when nil, :string, :integer, :float, :boolean, :file, :path
|
23
|
+
when nil, :string, :integer, :float, :boolean, :file, :path, :select, :folder
|
23
24
|
if IO === content || StringIO === content
|
24
25
|
content.read
|
25
26
|
else
|
@@ -46,8 +47,9 @@ module Persist
|
|
46
47
|
def self.deserialize(serialized, type)
|
47
48
|
type = type.to_sym if String === type
|
48
49
|
type = SERIALIZER if type == :serializer
|
50
|
+
|
49
51
|
case type
|
50
|
-
when nil, :string, :file, :stream
|
52
|
+
when nil, :string, :file, :stream, :select, :folder
|
51
53
|
serialized
|
52
54
|
when :path
|
53
55
|
Path.setup(serialized)
|
@@ -99,9 +101,18 @@ module Persist
|
|
99
101
|
return save_drivers[type].call(file, content)
|
100
102
|
end
|
101
103
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
104
|
+
|
105
|
+
if type == :binary
|
106
|
+
content.force_encoding("ASCII-8BIT") if content.respond_to? :force_encoding
|
107
|
+
Open.open(path, :mode => 'wb') do |f|
|
108
|
+
f.puts content
|
109
|
+
end
|
110
|
+
content
|
111
|
+
else
|
112
|
+
serialized = serialize(content, type)
|
113
|
+
Open.sensible_write(file, serialized, :force => true)
|
114
|
+
return nil
|
115
|
+
end
|
105
116
|
end
|
106
117
|
|
107
118
|
def self.load(file, type = :serializer)
|
@@ -118,6 +129,8 @@ module Persist
|
|
118
129
|
end
|
119
130
|
|
120
131
|
case type
|
132
|
+
when :binary
|
133
|
+
Open.read(file, :mode => 'rb')
|
121
134
|
when :yaml
|
122
135
|
Open.yaml(file)
|
123
136
|
when :json
|
data/lib/scout/persist.rb
CHANGED
@@ -14,61 +14,91 @@ module Persist
|
|
14
14
|
|
15
15
|
attr_writer :lock_dir
|
16
16
|
def lock_dir
|
17
|
-
@lock_dir ||= Path.setup("
|
17
|
+
@lock_dir ||= Path.setup("tmp/persist_locks").find
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.persistence_path(name, options = {})
|
22
22
|
options = IndiferentHash.add_defaults options, :dir => Persist.cache_dir
|
23
23
|
other_options = IndiferentHash.pull_keys options, :other
|
24
|
-
|
24
|
+
name = name.filename if name.respond_to?(:filename) && name.filename
|
25
|
+
persist_options = {}
|
26
|
+
TmpFile.tmp_for_file(name, options.merge(persist_options), other_options)
|
25
27
|
end
|
26
28
|
|
29
|
+
MEMORY_CACHE = {}
|
30
|
+
CONNECTIONS = {}
|
27
31
|
def self.persist(name, type = :serializer, options = {}, &block)
|
28
32
|
persist_options = IndiferentHash.pull_keys options, :persist
|
29
33
|
return yield if FalseClass === persist_options[:persist]
|
30
34
|
file = persist_options[:path] || options[:path] || persistence_path(name, options)
|
31
35
|
|
36
|
+
if type == :memory
|
37
|
+
repo = options[:memory] || options[:repo] || MEMORY_CACHE
|
38
|
+
repo[file] ||= yield
|
39
|
+
return repo[file]
|
40
|
+
end
|
41
|
+
|
32
42
|
update = options[:update] || persist_options[:update]
|
33
43
|
update = Open.mtime(update) if Path === update
|
34
44
|
update = Open.mtime(file) >= update ? false : true if Time === update
|
35
45
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
lockfile = persist_options[:lockfile] || options[:lockfile] || Persist.persistence_path(file + '.persist', {:dir => Persist.lock_dir})
|
47
|
+
|
48
|
+
Open.lock lockfile do |lock|
|
49
|
+
if Open.exist?(file) && ! update
|
50
|
+
Persist.load(file, type)
|
51
|
+
else
|
52
|
+
begin
|
53
|
+
file = file.find if Path === file
|
54
|
+
return yield(file) if block.arity == 1
|
55
|
+
res = yield
|
56
|
+
|
57
|
+
if res.nil?
|
58
|
+
return Persist.load(file, type)
|
59
|
+
end
|
60
|
+
|
61
|
+
Open.rm(file)
|
43
62
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
Thread.
|
49
|
-
|
50
|
-
|
63
|
+
if IO === res || StringIO === res
|
64
|
+
tee_copies = options[:tee_copies] || 1
|
65
|
+
main, *copies = Open.tee_stream_thread_multiple res, tee_copies + 1
|
66
|
+
main.lock = lock
|
67
|
+
t = Thread.new do
|
68
|
+
Thread.current.report_on_exception = false
|
69
|
+
Thread.current["name"] = "file saver: " + file
|
70
|
+
Open.sensible_write(file, main)
|
71
|
+
end
|
72
|
+
Thread.pass until t["name"]
|
73
|
+
copies.each_with_index do |copy,i|
|
74
|
+
next_stream = copies[i+1] if copies.length > i
|
75
|
+
ConcurrentStream.setup copy, :threads => t, :filename => file, :autojoin => true, :next => next_stream
|
76
|
+
end
|
77
|
+
res = copies.first
|
78
|
+
raise KeepLocked.new(res)
|
79
|
+
else
|
80
|
+
pres = Persist.save(res, file, type)
|
81
|
+
res = pres unless pres.nil?
|
51
82
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
83
|
+
rescue
|
84
|
+
Thread.handle_interrupt(Exception => :never) do
|
85
|
+
if Open.exist?(file)
|
86
|
+
Log.debug "Failed persistence #{file} - erasing"
|
87
|
+
Open.rm file
|
88
|
+
else
|
89
|
+
Log.debug "Failed persistence #{file}"
|
90
|
+
end
|
56
91
|
end
|
57
|
-
|
58
|
-
else
|
59
|
-
pres = Persist.save(res, file, type)
|
60
|
-
res = pres unless pres.nil?
|
92
|
+
raise $! unless options[:canfail]
|
61
93
|
end
|
62
|
-
|
63
|
-
raise $! unless options[:canfail]
|
64
|
-
Log.debug "Could not persist #{type} on #{file}"
|
94
|
+
res
|
65
95
|
end
|
66
|
-
res
|
67
96
|
end
|
68
97
|
end
|
69
98
|
|
70
|
-
def self.memory(name,
|
71
|
-
|
99
|
+
def self.memory(name, options = {}, &block)
|
100
|
+
options[:persist_path] ||= options[:path] ||= [name, options[:key]].compact * ":"
|
101
|
+
self.persist(name, :memory, options, &block)
|
72
102
|
end
|
73
103
|
|
74
104
|
end
|
data/lib/scout/resource/path.rb
CHANGED
@@ -1,4 +1,47 @@
|
|
1
1
|
module Path
|
2
|
+
def produce(force = false)
|
3
|
+
return self if ! force && (Open.exist?(self) || @produced)
|
4
|
+
begin
|
5
|
+
if Resource === self.pkgdir
|
6
|
+
self.pkgdir.produce self
|
7
|
+
else
|
8
|
+
false
|
9
|
+
end
|
10
|
+
rescue ResourceNotFound
|
11
|
+
false
|
12
|
+
rescue
|
13
|
+
message = $!.message
|
14
|
+
message = "No exception message" if message.nil? || message.empty?
|
15
|
+
Log.warn "Error producing #{self}: #{message}"
|
16
|
+
false
|
17
|
+
ensure
|
18
|
+
@produced = true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def produce_with_extension(extension, *args)
|
23
|
+
begin
|
24
|
+
self.produce(*args)
|
25
|
+
rescue Exception
|
26
|
+
exception = $!
|
27
|
+
begin
|
28
|
+
self.set_extension(extension).produce(*args)
|
29
|
+
rescue Exception
|
30
|
+
raise exception
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def produce_and_find(extension = nil, *args)
|
36
|
+
if extension
|
37
|
+
found = find_with_extension(extension, *args)
|
38
|
+
found.exists? ? found : produce_with_extension(extension, *args)
|
39
|
+
else
|
40
|
+
found = find
|
41
|
+
found.exists? ? found : produce(*args)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
2
45
|
def relocate
|
3
46
|
return self if Open.exists?(self)
|
4
47
|
Resource.relocate(self)
|
@@ -17,4 +60,14 @@ module Path
|
|
17
60
|
def write(*args, &block)
|
18
61
|
Open.write(self.find, *args, &block)
|
19
62
|
end
|
63
|
+
|
64
|
+
def list
|
65
|
+
found = produce_and_find('list')
|
66
|
+
Open.list(found)
|
67
|
+
end
|
68
|
+
|
69
|
+
def exists?
|
70
|
+
return true if Open.exists?(self.find)
|
71
|
+
self.produce
|
72
|
+
end
|
20
73
|
end
|
data/lib/scout/resource/util.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module Resource
|
2
2
|
def identify(path)
|
3
3
|
return path unless path.start_with?("/")
|
4
|
-
path_maps = path.path_maps
|
4
|
+
path_maps = path.path_maps if Path === path
|
5
|
+
path_maps ||= self.path_maps || Path.path_maps
|
5
6
|
path = File.expand_path(path)
|
6
7
|
path += "/" if File.directory?(path)
|
7
8
|
|
data/lib/scout/semaphore.rb
CHANGED
@@ -37,7 +37,13 @@ if continue
|
|
37
37
|
int ret;
|
38
38
|
sem_t* sem;
|
39
39
|
sem = sem_open(name, 0);
|
40
|
+
if (sem == SEM_FAILED){
|
41
|
+
return(errno);
|
42
|
+
}
|
40
43
|
ret = sem_wait(sem);
|
44
|
+
if (ret == -1){
|
45
|
+
return(errno);
|
46
|
+
}
|
41
47
|
sem_close(sem);
|
42
48
|
return(ret);
|
43
49
|
}
|
@@ -51,6 +57,7 @@ if continue
|
|
51
57
|
sem_close(sem);
|
52
58
|
}
|
53
59
|
EOF
|
60
|
+
|
54
61
|
end
|
55
62
|
|
56
63
|
SEM_MUTEX = Mutex.new
|
@@ -66,7 +73,7 @@ if continue
|
|
66
73
|
|
67
74
|
def self.with_semaphore(size, file = nil)
|
68
75
|
if file.nil?
|
69
|
-
file = "/" << Misc.digest(rand(
|
76
|
+
file = "/scout-" << Misc.digest(rand(100000000000).to_s)[0..10] if file.nil?
|
70
77
|
else
|
71
78
|
file = file.gsub('/', '_') if file
|
72
79
|
end
|