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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +51 -6
  3. data/VERSION +1 -1
  4. data/bin/scout +6 -3
  5. data/lib/rbbt-scout.rb +1 -0
  6. data/lib/scout/cmd.rb +1 -1
  7. data/lib/scout/concurrent_stream.rb +33 -29
  8. data/lib/scout/config.rb +1 -1
  9. data/lib/scout/exceptions.rb +1 -0
  10. data/lib/scout/log/color.rb +4 -2
  11. data/lib/scout/log/progress/report.rb +1 -1
  12. data/lib/scout/log/progress/util.rb +71 -2
  13. data/lib/scout/log/progress.rb +1 -1
  14. data/lib/scout/log/trap.rb +107 -0
  15. data/lib/scout/log.rb +56 -21
  16. data/lib/scout/meta_extension.rb +13 -6
  17. data/lib/scout/misc/digest.rb +1 -1
  18. data/lib/scout/misc/format.rb +12 -0
  19. data/lib/scout/misc/helper.rb +31 -0
  20. data/lib/scout/misc/insist.rb +1 -1
  21. data/lib/scout/misc/monitor.rb +12 -1
  22. data/lib/scout/misc/system.rb +10 -0
  23. data/lib/scout/misc.rb +1 -0
  24. data/lib/scout/named_array.rb +65 -3
  25. data/lib/scout/open/lock/lockfile.rb +587 -0
  26. data/lib/scout/open/lock.rb +28 -2
  27. data/lib/scout/open/remote.rb +4 -0
  28. data/lib/scout/open/stream.rb +111 -42
  29. data/lib/scout/open/util.rb +13 -3
  30. data/lib/scout/path/find.rb +9 -1
  31. data/lib/scout/path/util.rb +35 -0
  32. data/lib/scout/persist/serialize.rb +18 -5
  33. data/lib/scout/persist.rb +60 -30
  34. data/lib/scout/resource/path.rb +53 -0
  35. data/lib/scout/resource/produce.rb +0 -8
  36. data/lib/scout/resource/util.rb +2 -1
  37. data/lib/scout/semaphore.rb +8 -1
  38. data/lib/scout/tmpfile.rb +7 -8
  39. data/lib/scout/tsv/attach.rb +177 -0
  40. data/lib/scout/tsv/change_id.rb +40 -0
  41. data/lib/scout/tsv/dumper.rb +85 -54
  42. data/lib/scout/tsv/index.rb +188 -20
  43. data/lib/scout/tsv/open.rb +182 -0
  44. data/lib/scout/tsv/parser.rb +200 -118
  45. data/lib/scout/tsv/path.rb +5 -6
  46. data/lib/scout/tsv/persist/adapter.rb +26 -37
  47. data/lib/scout/tsv/persist/fix_width_table.rb +327 -0
  48. data/lib/scout/tsv/persist/serialize.rb +117 -0
  49. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -3
  50. data/lib/scout/tsv/persist.rb +4 -2
  51. data/lib/scout/tsv/transformer.rb +141 -0
  52. data/lib/scout/tsv/traverse.rb +136 -37
  53. data/lib/scout/tsv/util/filter.rb +312 -0
  54. data/lib/scout/tsv/util/process.rb +73 -0
  55. data/lib/scout/tsv/util/reorder.rb +81 -0
  56. data/lib/scout/tsv/util/select.rb +265 -0
  57. data/lib/scout/tsv/util/unzip.rb +86 -0
  58. data/lib/scout/tsv/util.rb +126 -19
  59. data/lib/scout/tsv.rb +28 -5
  60. data/lib/scout/work_queue/socket.rb +6 -1
  61. data/lib/scout/work_queue/worker.rb +5 -2
  62. data/lib/scout/work_queue.rb +15 -8
  63. data/lib/scout/workflow/definition.rb +29 -2
  64. data/lib/scout/workflow/step/dependencies.rb +24 -4
  65. data/lib/scout/workflow/step/info.rb +40 -5
  66. data/lib/scout/workflow/step/progress.rb +14 -0
  67. data/lib/scout/workflow/step/provenance.rb +8 -7
  68. data/lib/scout/workflow/step/status.rb +45 -0
  69. data/lib/scout/workflow/step.rb +104 -33
  70. data/lib/scout/workflow/task/inputs.rb +14 -20
  71. data/lib/scout/workflow/task.rb +86 -47
  72. data/lib/scout/workflow/usage.rb +10 -6
  73. data/scout-gear.gemspec +30 -3
  74. data/scout_commands/workflow/task +37 -9
  75. data/scout_commands/workflow/task_old +2 -2
  76. data/test/scout/open/test_stream.rb +61 -59
  77. data/test/scout/path/test_find.rb +10 -1
  78. data/test/scout/resource/test_produce.rb +15 -0
  79. data/test/scout/test_meta_extension.rb +25 -0
  80. data/test/scout/test_named_array.rb +18 -0
  81. data/test/scout/test_persist.rb +67 -0
  82. data/test/scout/test_tmpfile.rb +1 -1
  83. data/test/scout/test_tsv.rb +222 -3
  84. data/test/scout/test_work_queue.rb +21 -18
  85. data/test/scout/tsv/persist/test_adapter.rb +11 -1
  86. data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
  87. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  88. data/test/scout/tsv/test_attach.rb +227 -0
  89. data/test/scout/tsv/test_change_id.rb +98 -0
  90. data/test/scout/tsv/test_dumper.rb +1 -1
  91. data/test/scout/tsv/test_index.rb +127 -3
  92. data/test/scout/tsv/test_open.rb +167 -0
  93. data/test/scout/tsv/test_parser.rb +45 -3
  94. data/test/scout/tsv/test_persist.rb +9 -0
  95. data/test/scout/tsv/test_transformer.rb +108 -0
  96. data/test/scout/tsv/test_traverse.rb +195 -3
  97. data/test/scout/tsv/test_util.rb +24 -0
  98. data/test/scout/tsv/util/test_filter.rb +188 -0
  99. data/test/scout/tsv/util/test_process.rb +47 -0
  100. data/test/scout/tsv/util/test_reorder.rb +94 -0
  101. data/test/scout/tsv/util/test_select.rb +58 -0
  102. data/test/scout/tsv/util/test_unzip.rb +112 -0
  103. data/test/scout/work_queue/test_socket.rb +0 -1
  104. data/test/scout/work_queue/test_worker.rb +63 -6
  105. data/test/scout/workflow/step/test_load.rb +3 -3
  106. data/test/scout/workflow/step/test_status.rb +31 -0
  107. data/test/scout/workflow/task/test_inputs.rb +14 -14
  108. data/test/scout/workflow/test_step.rb +13 -13
  109. data/test/scout/workflow/test_task.rb +168 -32
  110. data/test/scout/workflow/test_usage.rb +33 -6
  111. data/test/test_helper.rb +3 -1
  112. metadata +29 -2
@@ -54,11 +54,10 @@ module Open
54
54
 
55
55
  into_close = false unless into.respond_to? :close
56
56
 
57
- begin
58
- while c = io.readpartial(BLOCK_SIZE)
59
- into << c if into
60
- end
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
- c
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
- #f.sync = true
123
- begin
124
- while block = content.readpartial(BLOCK_SIZE)
125
- f.write block
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 << Log.color(:blue, path) }"
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} -- #{ Log.color :blue, path }"
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
- begin
294
- while block = stream.readpartial(BLOCK_SIZE)
295
-
296
- in_pipes.each_with_index do |sin,i|
297
- begin
298
- sin.write block
299
- rescue IOError
300
- Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
301
- skip[i] = true
302
- rescue
303
- Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
304
- raise $!
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
- rescue IOError
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? :abort
316
- out_pipes.each do |sout|
317
- sout.abort if sout.respond_to? :abort
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
- in_pipes.each do |sin|
339
- sin.close unless sin.closed?
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
@@ -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) or Open.broken_link?(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 = Step::INFO_SERIALIZER.load(Open.open(file + '.info'))[: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.rm target if File.exist?(target)
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
@@ -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
@@ -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
- serialized = serialize(content, type)
103
- Open.sensible_write(file, serialized, :force => true)
104
- return nil
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("var/cache/persist_locks")
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
- TmpFile.tmp_for_file(name, options, other_options)
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
- if Open.exist?(file) && ! update
37
- Persist.load(file, type)
38
- else
39
- return yield(file) if block.arity == 1
40
- res = yield
41
- begin
42
- Open.rm(file)
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
- if IO === res || StringIO === res
45
- tee_copies = options[:tee_copies] || 1
46
- main, *copies = Open.tee_stream_thread_multiple res, tee_copies + 1
47
- t = Thread.new do
48
- Thread.current.report_on_exception = false
49
- Thread.current["name"] = "file saver: " + file
50
- Open.sensible_write(file, main)
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
- Thread.pass until t["name"]
53
- copies.each_with_index do |copy,i|
54
- next_stream = copies[i+1] if copies.length > i
55
- ConcurrentStream.setup copy, :threads => t, :filename => file, :autojoin => true, :next => next_stream
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
- res = copies.first
58
- else
59
- pres = Persist.save(res, file, type)
60
- res = pres unless pres.nil?
92
+ raise $! unless options[:canfail]
61
93
  end
62
- rescue
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, *args, &block)
71
- self.persist(name, :memory, *args, &block)
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
@@ -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
@@ -149,11 +149,3 @@ module Resource
149
149
  end
150
150
 
151
151
  end
152
-
153
- module Path
154
- def produce(force = false)
155
- return self if ! force && Open.exist?(self)
156
- self.pkgdir.produce self if Resource === self.pkgdir
157
- return self
158
- end
159
- end
@@ -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 || self.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
 
@@ -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(1000000000000).to_s) if file.nil?
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