scout-gear 7.3.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +44 -16
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +21 -7
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/rbbt-scout.rb +1 -0
  9. data/lib/scout/cmd.rb +24 -25
  10. data/lib/scout/concurrent_stream.rb +59 -39
  11. data/lib/scout/config.rb +1 -1
  12. data/lib/scout/exceptions.rb +10 -0
  13. data/lib/scout/log/color.rb +15 -12
  14. data/lib/scout/log/progress/report.rb +8 -6
  15. data/lib/scout/log/progress/util.rb +61 -54
  16. data/lib/scout/log/progress.rb +1 -1
  17. data/lib/scout/log/trap.rb +107 -0
  18. data/lib/scout/log.rb +115 -52
  19. data/lib/scout/meta_extension.rb +47 -6
  20. data/lib/scout/misc/digest.rb +12 -3
  21. data/lib/scout/misc/format.rb +24 -7
  22. data/lib/scout/misc/insist.rb +1 -1
  23. data/lib/scout/misc/monitor.rb +22 -0
  24. data/lib/scout/misc/system.rb +58 -0
  25. data/lib/scout/named_array.rb +73 -3
  26. data/lib/scout/offsite/ssh.rb +171 -0
  27. data/lib/scout/offsite/step.rb +83 -0
  28. data/lib/scout/offsite/sync.rb +55 -0
  29. data/lib/scout/offsite.rb +3 -0
  30. data/lib/scout/open/lock/lockfile.rb +587 -0
  31. data/lib/scout/open/lock.rb +9 -2
  32. data/lib/scout/open/remote.rb +16 -1
  33. data/lib/scout/open/stream.rb +146 -83
  34. data/lib/scout/open/util.rb +22 -3
  35. data/lib/scout/open.rb +5 -4
  36. data/lib/scout/path/find.rb +24 -11
  37. data/lib/scout/path/util.rb +40 -0
  38. data/lib/scout/persist/serialize.rb +19 -6
  39. data/lib/scout/persist.rb +29 -13
  40. data/lib/scout/resource/path.rb +57 -0
  41. data/lib/scout/resource/produce.rb +0 -8
  42. data/lib/scout/resource/util.rb +12 -5
  43. data/lib/scout/tmpfile.rb +7 -8
  44. data/lib/scout/tsv/attach.rb +177 -0
  45. data/lib/scout/tsv/change_id.rb +40 -0
  46. data/lib/scout/tsv/dumper.rb +74 -46
  47. data/lib/scout/tsv/index.rb +85 -87
  48. data/lib/scout/tsv/open.rb +160 -85
  49. data/lib/scout/tsv/parser.rb +142 -80
  50. data/lib/scout/tsv/path.rb +1 -2
  51. data/lib/scout/tsv/persist/adapter.rb +15 -45
  52. data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
  53. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -1
  54. data/lib/scout/tsv/persist.rb +4 -0
  55. data/lib/scout/tsv/stream.rb +204 -0
  56. data/lib/scout/tsv/transformer.rb +152 -0
  57. data/lib/scout/tsv/traverse.rb +96 -92
  58. data/lib/scout/tsv/util/filter.rb +9 -0
  59. data/lib/scout/tsv/util/reorder.rb +81 -0
  60. data/lib/scout/tsv/util/select.rb +78 -33
  61. data/lib/scout/tsv/util/unzip.rb +86 -0
  62. data/lib/scout/tsv/util.rb +60 -11
  63. data/lib/scout/tsv.rb +34 -4
  64. data/lib/scout/work_queue/socket.rb +6 -1
  65. data/lib/scout/work_queue/worker.rb +5 -2
  66. data/lib/scout/work_queue.rb +51 -20
  67. data/lib/scout/workflow/definition.rb +23 -3
  68. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  69. data/lib/scout/workflow/deployment.rb +1 -0
  70. data/lib/scout/workflow/step/dependencies.rb +56 -10
  71. data/lib/scout/workflow/step/file.rb +5 -0
  72. data/lib/scout/workflow/step/info.rb +40 -7
  73. data/lib/scout/workflow/step/load.rb +1 -1
  74. data/lib/scout/workflow/step/provenance.rb +9 -7
  75. data/lib/scout/workflow/step/status.rb +43 -0
  76. data/lib/scout/workflow/step.rb +160 -49
  77. data/lib/scout/workflow/task/dependencies.rb +114 -0
  78. data/lib/scout/workflow/task/inputs.rb +40 -32
  79. data/lib/scout/workflow/task.rb +38 -102
  80. data/lib/scout/workflow/usage.rb +48 -18
  81. data/lib/scout/workflow.rb +4 -2
  82. data/lib/scout-gear.rb +2 -0
  83. data/lib/scout.rb +6 -0
  84. data/scout-gear.gemspec +52 -23
  85. data/scout_commands/doc +37 -0
  86. data/scout_commands/find +1 -0
  87. data/scout_commands/offsite +30 -0
  88. data/scout_commands/update +29 -0
  89. data/scout_commands/workflow/info +15 -3
  90. data/scout_commands/workflow/install +102 -0
  91. data/scout_commands/workflow/task +57 -9
  92. data/test/scout/offsite/test_ssh.rb +15 -0
  93. data/test/scout/offsite/test_step.rb +33 -0
  94. data/test/scout/offsite/test_sync.rb +36 -0
  95. data/test/scout/offsite/test_task.rb +0 -0
  96. data/test/scout/open/test_stream.rb +60 -58
  97. data/test/scout/path/test_find.rb +10 -1
  98. data/test/scout/resource/test_path.rb +6 -0
  99. data/test/scout/resource/test_produce.rb +15 -0
  100. data/test/scout/test_meta_extension.rb +25 -0
  101. data/test/scout/test_named_array.rb +24 -0
  102. data/test/scout/test_persist.rb +9 -2
  103. data/test/scout/test_tsv.rb +229 -2
  104. data/test/scout/test_work_queue.rb +65 -41
  105. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  106. data/test/scout/tsv/test_attach.rb +227 -0
  107. data/test/scout/tsv/test_change_id.rb +98 -0
  108. data/test/scout/tsv/test_dumper.rb +1 -1
  109. data/test/scout/tsv/test_index.rb +49 -3
  110. data/test/scout/tsv/test_open.rb +160 -2
  111. data/test/scout/tsv/test_parser.rb +33 -2
  112. data/test/scout/tsv/test_persist.rb +2 -0
  113. data/test/scout/tsv/test_stream.rb +200 -0
  114. data/test/scout/tsv/test_transformer.rb +120 -0
  115. data/test/scout/tsv/test_traverse.rb +88 -3
  116. data/test/scout/tsv/test_util.rb +1 -0
  117. data/test/scout/tsv/util/test_reorder.rb +94 -0
  118. data/test/scout/tsv/util/test_select.rb +25 -11
  119. data/test/scout/tsv/util/test_unzip.rb +112 -0
  120. data/test/scout/work_queue/test_socket.rb +0 -1
  121. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  122. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  123. data/test/scout/workflow/step/test_info.rb +18 -0
  124. data/test/scout/workflow/step/test_status.rb +30 -0
  125. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  126. data/test/scout/workflow/task/test_inputs.rb +67 -14
  127. data/test/scout/workflow/test_definition.rb +18 -0
  128. data/test/scout/workflow/test_documentation.rb +24 -0
  129. data/test/scout/workflow/test_step.rb +112 -3
  130. data/test/scout/workflow/test_task.rb +0 -151
  131. data/test/scout/workflow/test_usage.rb +33 -6
  132. data/test/test_scout.rb +9 -0
  133. metadata +100 -8
  134. data/scout_commands/workflow/task_old +0 -706
@@ -3,7 +3,7 @@ module Open
3
3
 
4
4
  class << self
5
5
  attr_accessor :sensible_write_lock_dir
6
-
6
+
7
7
  def sensible_write_lock_dir
8
8
  @sensible_write_lock_dir ||= Path.setup("tmp/sensible_write_locks").find
9
9
  end
@@ -18,7 +18,7 @@ module Open
18
18
 
19
19
  def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
20
20
  return if Path === io
21
- return unless io.respond_to? :read
21
+ return unless io.respond_to? :read
22
22
 
23
23
  if io.respond_to? :closed? and io.closed?
24
24
  io.join if io.respond_to? :join
@@ -46,16 +46,17 @@ module Open
46
46
  begin
47
47
  into = into.find if Path === into
48
48
 
49
- if String === into
49
+ if String === into
50
50
  dir = File.dirname(into)
51
51
  Open.mkdir dir unless File.exist?(dir)
52
- into_path, into = into, File.open(into, 'w')
52
+ into_path, into = into, File.open(into, 'w')
53
53
  end
54
-
54
+
55
55
  into_close = false unless into.respond_to? :close
56
56
 
57
57
  while c = io.read(BLOCK_SIZE)
58
58
  into << c if into
59
+ last_c = c if c
59
60
  break if io.closed?
60
61
  end
61
62
 
@@ -65,20 +66,23 @@ module Open
65
66
  into.close if into and into_close and not into.closed?
66
67
  block.call if block_given?
67
68
 
68
- c
69
+ Log.debug "Consume stream done #{Log.fingerprint io} -> #{Log.fingerprint(into_path ||into)}"
70
+ last_c
69
71
  rescue Aborted
72
+ Thread.current["exception"] = true
70
73
  Log.low "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
71
74
  io.abort $! if io.respond_to? :abort
72
75
  into.close if into.respond_to?(:closed?) && ! into.closed?
73
76
  FileUtils.rm into_path if into_path and File.exist?(into_path)
74
77
  rescue Exception
78
+ Thread.current["exception"] = true
75
79
  Log.low "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
76
80
  exception = (io.respond_to?(:stream_exception) && io.stream_exception) ? io.stream_exception : $!
77
81
  io.abort exception if io.respond_to? :abort
78
82
  into.close if into.respond_to?(:closed?) && ! into.closed?
79
83
  into_path = into if into_path.nil? && String === into
80
84
  if into_path and File.exist?(into_path)
81
- FileUtils.rm into_path
85
+ FileUtils.rm into_path
82
86
  end
83
87
  raise exception
84
88
  end
@@ -89,7 +93,7 @@ module Open
89
93
  force = IndiferentHash.process_options options, :force
90
94
 
91
95
  if File.exist?(path) and not force
92
- Open.consume_stream content
96
+ Open.consume_stream content
93
97
  return
94
98
  end
95
99
 
@@ -104,12 +108,12 @@ module Open
104
108
 
105
109
  if File.exist? path and not force
106
110
  Log.warn "Path exists in sensible_write, not forcing update: #{ path }"
107
- Open.consume_stream content
111
+ Open.consume_stream content
108
112
  else
109
113
  FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory?(File.dirname(tmp_path))
110
114
  FileUtils.rm_f tmp_path if File.exist? tmp_path
115
+ Log.low "Sensible write stream #{Log.fingerprint content} -> #{Log.fingerprint path}" if IO === content
111
116
  begin
112
-
113
117
  case
114
118
  when block_given?
115
119
  File.open(tmp_path, 'wb', &block)
@@ -117,11 +121,10 @@ module Open
117
121
  File.open(tmp_path, 'wb') do |f| f.write content end
118
122
  when (IO === content or StringIO === content or File === content)
119
123
  Open.write(tmp_path) do |f|
120
- #f.sync = true
121
124
  while block = content.read(BLOCK_SIZE)
122
125
  f.write block
123
126
  break if content.closed?
124
- end
127
+ end
125
128
  end
126
129
  else
127
130
  File.open(tmp_path, 'wb') do |f| end
@@ -138,15 +141,15 @@ module Open
138
141
  Open.touch path if File.exist? path
139
142
  content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
140
143
 
141
- Open.notify_write(path)
144
+ Open.notify_write(path)
142
145
  rescue Aborted
143
- Log.low "Aborted sensible_write -- #{ Log.reset << Log.color(:blue, path) }"
146
+ Log.low "Aborted sensible_write -- #{ Log.reset << path }"
144
147
  content.abort if content.respond_to? :abort
145
148
  Open.rm path if File.exist? path
146
149
  rescue Exception
147
150
  exception = (AbortedStream === content and content.exception) ? content.exception : $!
148
- Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
149
- content.abort if content.respond_to? :abort
151
+ Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ path }"
152
+ content.abort(exception) if content.respond_to? :abort
150
153
  Open.rm path if File.exist? path
151
154
  raise exception
152
155
  rescue
@@ -172,7 +175,7 @@ module Open
172
175
 
173
176
  [sout, sin]
174
177
  end
175
- Log.debug{"Creating pipe #{[Log.fingerprint(res.last), Log.fingerprint(res.first)] * " => "}"}
178
+ Log.low{"Creating pipe #{[Log.fingerprint(res.last), Log.fingerprint(res.first)] * " -> "}"}
176
179
  res
177
180
  end
178
181
 
@@ -187,7 +190,7 @@ module Open
187
190
  FileUtils.rm path if erase && File.exist?(path)
188
191
  end
189
192
  end
190
-
193
+
191
194
  def self.release_pipes(*pipes)
192
195
  PIPE_MUTEX.synchronize do
193
196
  pipes.flatten.each do |pipe|
@@ -212,14 +215,13 @@ module Open
212
215
 
213
216
  if do_fork
214
217
 
215
- #parent_pid = Process.pid
216
218
  pid = Process.fork {
217
219
  begin
218
220
  purge_pipes(sin)
219
221
  sout.close
220
222
 
221
223
  yield sin
222
- sin.close if close and not sin.closed?
224
+ sin.close if close and not sin.closed?
223
225
 
224
226
  rescue Exception
225
227
  Log.exception $!
@@ -235,34 +237,20 @@ module Open
235
237
  ConcurrentStream.setup sin, :pair => sout
236
238
  ConcurrentStream.setup sout, :pair => sin
237
239
 
238
- thread = Thread.new do
240
+ thread = Thread.new do
239
241
  begin
240
- Thread.current.report_on_exception = false
241
- Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
242
-
243
- yield sin
242
+ ConcurrentStream.process_stream(sin, :message => "Open pipe") do
243
+ Thread.current.report_on_exception = false
244
+ Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
244
245
 
245
- sin.close if close and not sin.closed? and not sin.aborted?
246
- rescue Aborted
247
- Log.low "Aborted open_pipe: #{$!.message}"
248
- raise $!
249
- rescue Exception
250
- Log.low "Exception in open_pipe: #{$!.message}"
251
- begin
252
- sout.threads.delete(Thread.current)
253
- sout.pair = []
254
- sout.abort($!) if sout.respond_to?(:abort)
255
- sin.threads.delete(Thread.current)
256
- sin.pair = []
257
- sin.abort($!) if sin.respond_to?(:abort)
258
- ensure
259
- raise $!
246
+ yield sin
260
247
  end
261
248
  end
262
249
  end
263
250
 
264
251
  sin.threads = [thread]
265
252
  sout.threads = [thread]
253
+
266
254
  Thread.pass until thread["name"]
267
255
  end
268
256
 
@@ -272,12 +260,14 @@ module Open
272
260
  def self.tee_stream_thread_multiple(stream, num = 2)
273
261
  in_pipes = []
274
262
  out_pipes = []
275
- num.times do
263
+ num.times do
276
264
  sout, sin = Open.pipe
277
265
  in_pipes << sin
278
266
  out_pipes << sout
279
267
  end
280
268
 
269
+ Log.low("Tee stream #{Log.fingerprint stream} -> #{Log.fingerprint out_pipes}")
270
+
281
271
  filename = stream.filename if stream.respond_to? :filename
282
272
 
283
273
  splitter_thread = Thread.new(Thread.current) do |parent|
@@ -289,7 +279,7 @@ module Open
289
279
  while block = stream.read(BLOCK_SIZE)
290
280
 
291
281
  in_pipes.each_with_index do |sin,i|
292
- begin
282
+ begin
293
283
  sin.write block
294
284
  rescue IOError
295
285
  Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
@@ -297,18 +287,24 @@ module Open
297
287
  rescue
298
288
  Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
299
289
  raise $!
300
- end unless skip[i]
290
+ end unless skip[i]
301
291
  end
302
292
  break if stream.closed?
303
293
  end
304
294
 
305
295
  stream.join if stream.respond_to? :join
306
- stream.close unless stream.closed?
307
296
  in_pipes.first.close unless in_pipes.first.closed?
308
297
  rescue Aborted, Interrupt
309
- stream.abort if stream.respond_to? :abort
310
- out_pipes.each do |sout|
311
- sout.abort if sout.respond_to? :abort
298
+ stream.abort if stream.respond_to?(:abort) && ! stream.aborted?
299
+ out_pipes.reverse.each do |sout|
300
+ sout.threads.delete(Thread.current)
301
+ begin
302
+ sout.abort($!) if sout.respond_to?(:abort) && ! sout.aborted?
303
+ rescue
304
+ end
305
+ end
306
+ in_pipes.each do |sin|
307
+ sin.close unless sin.closed?
312
308
  end
313
309
  Log.low "Tee aborting #{Log.fingerprint stream}"
314
310
  raise $!
@@ -327,28 +323,44 @@ module Open
327
323
  end
328
324
  Log.low "Tee exception #{Log.fingerprint stream}"
329
325
  rescue
330
- Log.exception $!
331
326
  ensure
332
- in_pipes.each do |sin|
333
- sin.close unless sin.closed?
327
+ begin
328
+ in_pipes.each do |sin|
329
+ sin.close unless sin.closed?
330
+ end
331
+ ensure
332
+ raise $!
334
333
  end
335
- raise $!
336
334
  end
337
335
  end
338
336
  end
339
337
 
340
- out_pipes.each do |sout|
341
- ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :pair => stream
342
- end
343
338
  Thread.pass until splitter_thread["name"]
344
339
 
345
340
  main_pipe = out_pipes.first
346
- main_pipe.autojoin = true
347
341
 
348
- main_pipe.callback = Proc.new do
349
- stream.join if stream.respond_to? :join
350
- in_pipes[1..-1].each do |sin|
351
- sin.close unless sin.closed?
342
+ ConcurrentStream.setup(main_pipe, :threads => [splitter_thread], :filename => filename, :autojoin => true)
343
+
344
+ out_pipes[1..-1].each do |sout|
345
+ ConcurrentStream.setup sout, :filename => filename, :threads => [splitter_thread]
346
+ end
347
+
348
+ main_pipe.callback = proc do
349
+ begin
350
+ stream.join if stream.respond_to?(:join) && ! stream.joined?
351
+ in_pipes[1..-1].each do |sin|
352
+ sin.close unless sin.closed?
353
+ end
354
+ rescue
355
+ main_pipe.abort_callback.call($!)
356
+ raise $!
357
+ end
358
+ end
359
+
360
+ main_pipe.abort_callback = proc do |exception|
361
+ stream.abort(exception)
362
+ out_pipes[1..-1].each do |sout|
363
+ sout.abort(exception)
352
364
  end
353
365
  end
354
366
 
@@ -367,7 +379,7 @@ module Open
367
379
  str = nil
368
380
  Thread.pass while IO.select([stream],nil,nil,1).nil?
369
381
  while not str = stream.read(size)
370
- IO.select([stream],nil,nil,1)
382
+ IO.select([stream],nil,nil,1)
371
383
  Thread.pass
372
384
  raise ClosedStream if stream.eof?
373
385
  end
@@ -392,38 +404,89 @@ module Open
392
404
  str
393
405
  end
394
406
 
395
- def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
396
- Open.open_pipe do |sin|
397
- line = stream.gets
398
- while line =~ /^#{header_hash}/ do
399
- sin.puts line
407
+ def self.sort_stream(stream, header_hash: "#", cmd_args: "-u", memory: false)
408
+ sout = Open.open_pipe do |sin|
409
+ ConcurrentStream.process_stream(stream) do
400
410
  line = stream.gets
401
- end
411
+ while line && line.start_with?(header_hash) do
412
+ sin.puts line
413
+ line = stream.gets
414
+ end
402
415
 
403
- line_stream = Open.open_pipe do |line_stream_in|
404
- line_stream_in.puts line
405
- begin
416
+ line_stream = Open.open_pipe do |line_stream_in|
417
+ line_stream_in.puts line if line
406
418
  Open.consume_stream(stream, false, line_stream_in)
407
- rescue
408
- raise $!
409
419
  end
410
- end
411
-
412
- sorted = CMD.cmd("env LC_ALL=C sort #{cmd_args || ""}", :in => line_stream, :pipe => true)
420
+ Log.low "Sub-sort stream #{Log.fingerprint stream} -> #{Log.fingerprint line_stream}"
413
421
 
414
- begin
415
- Open.consume_stream(sorted, false, sin)
416
- rescue
417
- Log.exception $!
418
- begin
419
- sorted.raise($!) if sorted.respond_to? :raise
420
- stream.raise($!) if stream.respond_to? :raise
421
- ensure
422
- raise $!
422
+ if memory
423
+ line_stream.read.split("\n").sort.each do |line|
424
+ sin.puts line
425
+ end
426
+ else
427
+ io = CMD.cmd("env LC_ALL=C sort #{cmd_args || ""}", :in => line_stream, :pipe => true)
428
+ Open.consume_stream(io, false, sin)
423
429
  end
424
430
  end
425
431
  end
432
+ Log.low "Sort #{Log.fingerprint stream} -> #{Log.fingerprint sout}"
433
+ sout
426
434
  end
427
435
 
436
+ #def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
437
+ # StringIO.new stream.read.split("\n").sort.uniq * "\n"
438
+ #end
439
+
440
+ def self.collapse_stream(s, line: nil, sep: "\t", header: nil, &block)
441
+ sep ||= "\t"
442
+ Open.open_pipe do |sin|
428
443
 
444
+ sin.puts header if header
445
+
446
+ line ||= s.gets
447
+
448
+ current_parts = []
449
+ while line
450
+ key, *parts = line.chomp.split(sep, -1)
451
+ case
452
+ when key.nil?
453
+ when current_parts.nil?
454
+ current_parts = parts
455
+ current_key = key
456
+ when current_key == key
457
+ parts.each_with_index do |part,i|
458
+ if current_parts[i].nil?
459
+ current_parts[i] = "|" << part
460
+ else
461
+ current_parts[i] = current_parts[i] << "|" << part
462
+ end
463
+ end
464
+
465
+ (parts.length..current_parts.length-1).to_a.each do |pos|
466
+ current_parts[pos] = current_parts[pos] << "|" << ""
467
+ end
468
+ when current_key.nil?
469
+ current_key = key
470
+ current_parts = parts
471
+ when current_key != key
472
+ if block_given?
473
+ res = block.call(current_parts)
474
+ sin.puts [current_key, res] * sep
475
+ else
476
+ sin.puts [current_key, current_parts].flatten * sep
477
+ end
478
+ current_key = key
479
+ current_parts = parts
480
+ end
481
+ line = s.gets
482
+ end
483
+
484
+ if block_given?
485
+ res = block.call(current_parts)
486
+ sin.puts [current_key, res] * sep
487
+ else
488
+ sin.puts [current_key, current_parts].flatten * sep
489
+ end unless current_key.nil?
490
+ end
491
+ end
429
492
  end
@@ -68,6 +68,15 @@ module Open
68
68
  !! (file =~ /\.zip$/)
69
69
  end
70
70
 
71
+ def self.is_stream?(obj)
72
+ IO === obj || StringIO === obj
73
+ end
74
+
75
+ def self.has_stream?(obj)
76
+ obj.respond_to?(:stream)
77
+ end
78
+
79
+
71
80
  def self.notify_write(file)
72
81
  begin
73
82
  notification_file = file + '.notify'
@@ -94,6 +103,11 @@ module Open
94
103
  File.symlink?(path) && ! File.exist?(File.readlink(path))
95
104
  end
96
105
 
106
+ def self.directory?(file)
107
+ file = file.find if Path === file
108
+ File.directory?(file)
109
+ end
110
+
97
111
  def self.exists?(file)
98
112
  file = file.find if Path === file
99
113
  File.exist?(file)
@@ -111,7 +125,7 @@ module Open
111
125
  end
112
126
 
113
127
  def self.rm(file)
114
- FileUtils.rm(file) if File.exist?(file) or Open.broken_link?(file)
128
+ FileUtils.rm(file) if File.exist?(file) || Open.broken_link?(file)
115
129
  end
116
130
 
117
131
  def self.rm_rf(file)
@@ -155,7 +169,7 @@ module Open
155
169
  begin
156
170
  if File.symlink?(file) || File.stat(file).nlink > 1
157
171
  if File.exist?(file + '.info') && defined?(Step)
158
- done = Step::INFO_SERIALIZER.load(Open.open(file + '.info'))[:done]
172
+ done = Persist.load(file + '.info', Step::SERIALIZER)[:done]
159
173
  return done if done
160
174
  end
161
175
 
@@ -173,7 +187,7 @@ module Open
173
187
  target = target.find if Path === target
174
188
 
175
189
  FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
176
- FileUtils.rm target if File.exist?(target)
190
+ FileUtils.rm_rf target if File.exist?(target)
177
191
  FileUtils.cp_r source, target
178
192
  end
179
193
 
@@ -222,4 +236,9 @@ module Open
222
236
  end
223
237
  nil
224
238
  end
239
+
240
+ def self.list(file)
241
+ file = file.produce_and_find if Path === file
242
+ Open.read(file).split("\n")
243
+ end
225
244
  end
data/lib/scout/open.rb CHANGED
@@ -21,6 +21,8 @@ module Open
21
21
  end
22
22
 
23
23
  def self.get_stream(file, mode = 'r')
24
+ return file if Open.is_stream?(file)
25
+ return file.stream if Open.has_stream?(file)
24
26
  file = file.find if Path === file
25
27
 
26
28
  return Open.ssh(file) if Open.ssh?(file)
@@ -56,11 +58,11 @@ module Open
56
58
  def self.open(file, options = {})
57
59
  if IO === file || StringIO === file
58
60
  if block_given?
59
- res = yield file
61
+ res = yield file
60
62
  file.close
61
63
  return res
62
64
  else
63
- return file
65
+ return file
64
66
  end
65
67
  end
66
68
 
@@ -163,7 +165,6 @@ module Open
163
165
  raise "Content unknown #{Log.fingerprint content}"
164
166
  end
165
167
 
166
- notify_write(file)
168
+ notify_write(file)
167
169
  end
168
-
169
170
  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
 
@@ -32,13 +34,14 @@ module Path
32
34
 
33
35
  def self.follow(path, map, map_name = nil)
34
36
  file = map.sub('{PKGDIR}', path.pkgdir.respond_to?(:pkgdir) ? path.pkgdir.pkgdir || Path.default_pkgdir : path.pkgdir || Path.default_pkgdir).
37
+ sub('{HOME}', ENV["HOME"]).
35
38
  sub('{RESOURCE}', path.pkgdir.to_s).
36
39
  sub('{PWD}', FileUtils.pwd).
37
40
  sub('{TOPLEVEL}', path._toplevel).
38
41
  sub('{SUBPATH}', path._subpath).
39
42
  sub('{BASENAME}', File.basename(path)).
40
43
  sub('{PATH}', path).
41
- sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir).
44
+ sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir || "NOLIBDIR").
42
45
  sub('{MAPNAME}', map_name.to_s).
43
46
  sub('{REMOVE}/', '').
44
47
  sub('{REMOVE}', '').gsub(/\/+/,'/')
@@ -57,16 +60,17 @@ module Path
57
60
 
58
61
  def self.path_maps
59
62
  @@path_maps ||= IndiferentHash.setup({
60
- :current => File.join("{PWD}", "{TOPLEVEL}", "{SUBPATH}"),
61
- :user => File.join(ENV['HOME'], ".{PKGDIR}", "{TOPLEVEL}", "{SUBPATH}"),
62
- :global => File.join('/', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
63
- :usr => File.join('/usr/', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
64
- :local => File.join('/usr/local', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
65
- :fast => File.join('/fast', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
66
- :cache => File.join('/cache', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
67
- :bulk => File.join('/bulk', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
68
- :lib => File.join('{LIBDIR}', "{TOPLEVEL}", "{SUBPATH}"),
69
- :base => File.join(Path.caller_lib_dir(__FILE__), "{TOPLEVEL}", "{SUBPATH}"),
63
+ :current => "{PWD}/{TOPLEVEL}/{SUBPATH}",
64
+ :user => "{HOME}/.{PKGDIR}/{TOPLEVEL}/{SUBPATH}",
65
+ :global => '/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
66
+ :usr => '/usr/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
67
+ :local => '/usr/local/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
68
+ :fast => '/fast/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
69
+ :cache => '/cache/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
70
+ :bulk => '/bulk/{TOPLEVEL}/{PKGDIR}/{SUBPATH}',
71
+ :lib => '{LIBDIR}/{TOPLEVEL}/{SUBPATH}',
72
+ :scout_gear => File.join(Path.caller_lib_dir(__FILE__), "{TOPLEVEL}/{SUBPATH}"),
73
+ :tmp => '/tmp/{PKGDIR}/{TOPLEVEL}/{SUBPATH}',
70
74
  :default => :user
71
75
  })
72
76
  end
@@ -125,6 +129,9 @@ module Path
125
129
  def follow(map_name = :default, annotate = true)
126
130
  IndiferentHash.setup(path_maps)
127
131
  map = path_maps[map_name] || Path.path_maps[map_name]
132
+ if map.nil? && String === map_name
133
+ map = File.join(map_name, '{TOPLEVEL}/{SUBPATH}')
134
+ end
128
135
  raise "Map not found #{Log.fingerprint map_name} not in #{Log.fingerprint path_maps.keys}" if map.nil?
129
136
  while Symbol === map
130
137
  map_name = map
@@ -188,4 +195,10 @@ module Path
188
195
  .select{|file| file.exist? }.uniq
189
196
  end
190
197
 
198
+ def find_with_extension(extension, *args)
199
+ found = self.find(*args)
200
+ return found if found.exists?
201
+ found_with_extension = self.set_extension(extension).find
202
+ found_with_extension.exists? ? found_with_extension : found
203
+ end
191
204
  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,27 @@ module Path
64
81
  def set_extension(extension)
65
82
  self.annotate(self + ".#{extension}")
66
83
  end
84
+
85
+ def unset_extension
86
+ self.annotate(self.split(".")[0..-2] * ".")
87
+ end
88
+
89
+
90
+ # Is 'file' newer than 'path'? return non-true if path is newer than file
91
+ def self.newer?(path, file, by_link = false)
92
+ return true if not Open.exists?(file)
93
+ path = path.find if Path === path
94
+ file = file.find if Path === file
95
+ if by_link
96
+ patht = File.exist?(path) ? File.lstat(path).mtime : nil
97
+ filet = File.exist?(file) ? File.lstat(file).mtime : nil
98
+ else
99
+ patht = Open.mtime(path)
100
+ filet = Open.mtime(file)
101
+ end
102
+ return true if patht.nil? || filet.nil?
103
+ diff = patht - filet
104
+ return diff if diff < 0
105
+ return false
106
+ end
67
107
  end