rbbt-util 5.44.1 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rbbt +67 -90
  3. data/etc/app.d/base.rb +2 -2
  4. data/etc/app.d/semaphores.rb +3 -3
  5. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  6. data/lib/rbbt/annotations/refactor.rb +27 -0
  7. data/lib/rbbt/annotations/util.rb +282 -282
  8. data/lib/rbbt/annotations.rb +343 -320
  9. data/lib/rbbt/association/database.rb +200 -225
  10. data/lib/rbbt/association/index.rb +294 -291
  11. data/lib/rbbt/association/item.rb +227 -227
  12. data/lib/rbbt/association/open.rb +35 -34
  13. data/lib/rbbt/association/util.rb +0 -169
  14. data/lib/rbbt/association.rb +2 -4
  15. data/lib/rbbt/entity/identifiers.rb +119 -118
  16. data/lib/rbbt/entity/refactor.rb +12 -0
  17. data/lib/rbbt/entity.rb +319 -315
  18. data/lib/rbbt/hpc/batch.rb +72 -53
  19. data/lib/rbbt/hpc/lsf.rb +2 -2
  20. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  21. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  22. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  24. data/lib/rbbt/hpc/slurm.rb +18 -18
  25. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  26. data/lib/rbbt/knowledge_base/query.rb +2 -2
  27. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  28. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  29. data/lib/rbbt/knowledge_base.rb +1 -1
  30. data/lib/rbbt/monitor.rb +36 -25
  31. data/lib/rbbt/persist/refactor.rb +166 -0
  32. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  33. data/lib/rbbt/persist/tsv.rb +187 -185
  34. data/lib/rbbt/persist.rb +556 -551
  35. data/lib/rbbt/refactor.rb +20 -0
  36. data/lib/rbbt/resource/path/refactor.rb +178 -0
  37. data/lib/rbbt/resource/path.rb +317 -497
  38. data/lib/rbbt/resource/util.rb +0 -48
  39. data/lib/rbbt/resource.rb +3 -390
  40. data/lib/rbbt/tsv/accessor.rb +2 -838
  41. data/lib/rbbt/tsv/attach.rb +303 -299
  42. data/lib/rbbt/tsv/change_id.rb +244 -245
  43. data/lib/rbbt/tsv/csv.rb +87 -85
  44. data/lib/rbbt/tsv/dumper.rb +2 -100
  45. data/lib/rbbt/tsv/excel.rb +26 -24
  46. data/lib/rbbt/tsv/field_index.rb +4 -1
  47. data/lib/rbbt/tsv/filter.rb +3 -2
  48. data/lib/rbbt/tsv/index.rb +2 -284
  49. data/lib/rbbt/tsv/manipulate.rb +750 -747
  50. data/lib/rbbt/tsv/marshal.rb +3 -3
  51. data/lib/rbbt/tsv/matrix.rb +2 -2
  52. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  53. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  54. data/lib/rbbt/tsv/parser.rb +678 -678
  55. data/lib/rbbt/tsv/refactor.rb +195 -0
  56. data/lib/rbbt/tsv/stream.rb +253 -251
  57. data/lib/rbbt/tsv/util.rb +420 -420
  58. data/lib/rbbt/tsv.rb +210 -208
  59. data/lib/rbbt/util/R/eval.rb +4 -4
  60. data/lib/rbbt/util/R/plot.rb +62 -166
  61. data/lib/rbbt/util/R.rb +21 -18
  62. data/lib/rbbt/util/cmd.rb +2 -318
  63. data/lib/rbbt/util/color.rb +269 -269
  64. data/lib/rbbt/util/colorize.rb +89 -89
  65. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  66. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  67. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  68. data/lib/rbbt/util/config.rb +169 -167
  69. data/lib/rbbt/util/iruby.rb +20 -0
  70. data/lib/rbbt/util/log/progress/report.rb +241 -241
  71. data/lib/rbbt/util/log/progress/util.rb +99 -99
  72. data/lib/rbbt/util/log/progress.rb +102 -102
  73. data/lib/rbbt/util/log/refactor.rb +49 -0
  74. data/lib/rbbt/util/log.rb +486 -532
  75. data/lib/rbbt/util/migrate.rb +1 -1
  76. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  77. data/lib/rbbt/util/misc/development.rb +12 -11
  78. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  79. data/lib/rbbt/util/misc/format.rb +2 -230
  80. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  81. data/lib/rbbt/util/misc/inspect.rb +2 -476
  82. data/lib/rbbt/util/misc/lock.rb +109 -106
  83. data/lib/rbbt/util/misc/omics.rb +9 -1
  84. data/lib/rbbt/util/misc/pipes.rb +765 -793
  85. data/lib/rbbt/util/misc/refactor.rb +20 -0
  86. data/lib/rbbt/util/misc/ssw.rb +27 -17
  87. data/lib/rbbt/util/misc/system.rb +0 -15
  88. data/lib/rbbt/util/misc.rb +39 -20
  89. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  90. data/lib/rbbt/util/named_array.rb +3 -220
  91. data/lib/rbbt/util/open/refactor.rb +7 -0
  92. data/lib/rbbt/util/open.rb +3 -857
  93. data/lib/rbbt/util/procpath.rb +6 -6
  94. data/lib/rbbt/util/python/paths.rb +27 -0
  95. data/lib/rbbt/util/python/run.rb +115 -0
  96. data/lib/rbbt/util/python/script.rb +110 -0
  97. data/lib/rbbt/util/python/util.rb +3 -3
  98. data/lib/rbbt/util/python.rb +22 -81
  99. data/lib/rbbt/util/semaphore.rb +152 -148
  100. data/lib/rbbt/util/simpleopt.rb +9 -8
  101. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  102. data/lib/rbbt/util/ssh.rb +122 -118
  103. data/lib/rbbt/util/tar.rb +117 -115
  104. data/lib/rbbt/util/tmpfile.rb +69 -67
  105. data/lib/rbbt/util/version.rb +2 -0
  106. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  107. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  108. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  109. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  110. data/lib/rbbt/workflow/refactor/task_info.rb +65 -0
  111. data/lib/rbbt/workflow/refactor.rb +153 -0
  112. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  113. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  114. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  115. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  116. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  117. data/lib/rbbt/workflow/step/run.rb +766 -766
  118. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  119. data/lib/rbbt/workflow/step.rb +2 -362
  120. data/lib/rbbt/workflow/task.rb +118 -118
  121. data/lib/rbbt/workflow/usage.rb +289 -287
  122. data/lib/rbbt/workflow/util/archive.rb +6 -5
  123. data/lib/rbbt/workflow/util/data.rb +1 -1
  124. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  125. data/lib/rbbt/workflow/util/trace.rb +79 -44
  126. data/lib/rbbt/workflow.rb +4 -882
  127. data/lib/rbbt-util.rb +21 -13
  128. data/lib/rbbt.rb +16 -3
  129. data/python/rbbt/__init__.py +19 -1
  130. data/share/Rlib/plot.R +37 -37
  131. data/share/Rlib/svg.R +22 -5
  132. data/share/install/software/lib/install_helpers +1 -1
  133. data/share/rbbt_commands/hpc/list +2 -3
  134. data/share/rbbt_commands/hpc/orchestrate +4 -4
  135. data/share/rbbt_commands/hpc/tail +2 -0
  136. data/share/rbbt_commands/hpc/task +10 -7
  137. data/share/rbbt_commands/lsf/list +2 -3
  138. data/share/rbbt_commands/lsf/orchestrate +4 -4
  139. data/share/rbbt_commands/lsf/tail +2 -0
  140. data/share/rbbt_commands/lsf/task +10 -7
  141. data/share/rbbt_commands/migrate +1 -1
  142. data/share/rbbt_commands/pbs/list +2 -3
  143. data/share/rbbt_commands/pbs/orchestrate +4 -4
  144. data/share/rbbt_commands/pbs/tail +2 -0
  145. data/share/rbbt_commands/pbs/task +10 -7
  146. data/share/rbbt_commands/resource/produce +8 -1
  147. data/share/rbbt_commands/slurm/list +2 -3
  148. data/share/rbbt_commands/slurm/orchestrate +4 -4
  149. data/share/rbbt_commands/slurm/tail +2 -0
  150. data/share/rbbt_commands/slurm/task +10 -7
  151. data/share/rbbt_commands/system/clean +5 -5
  152. data/share/rbbt_commands/system/status +5 -5
  153. data/share/rbbt_commands/tsv/get +2 -3
  154. data/share/rbbt_commands/tsv/info +10 -13
  155. data/share/rbbt_commands/tsv/keys +18 -14
  156. data/share/rbbt_commands/tsv/slice +2 -2
  157. data/share/rbbt_commands/tsv/transpose +6 -2
  158. data/share/rbbt_commands/workflow/info +20 -24
  159. data/share/rbbt_commands/workflow/list +1 -1
  160. data/share/rbbt_commands/workflow/prov +20 -13
  161. data/share/rbbt_commands/workflow/server +11 -1
  162. data/share/rbbt_commands/workflow/task +76 -71
  163. data/share/rbbt_commands/workflow/write_info +26 -9
  164. data/share/software/opt/ssw/ssw.c +861 -0
  165. data/share/software/opt/ssw/ssw.h +130 -0
  166. data/share/workflow_config.ru +3 -3
  167. metadata +40 -2
@@ -1,793 +1,765 @@
1
- require 'rbbt'
2
-
3
- module Misc
4
- class << self
5
- attr_accessor :sensiblewrite_lock_dir
6
-
7
- def sensiblewrite_lock_dir
8
- @sensiblewrite_lock_dir ||= Rbbt.tmp.sensiblewrite_locks.find
9
- end
10
- end
11
-
12
- class << self
13
- attr_accessor :sensiblewrite_dir
14
- def sensiblewrite_dir
15
- @sensiblewrite_dir = Rbbt.tmp.sensiblewrite.find
16
- end
17
- end
18
-
19
- BLOCK_SIZE=1024 * 8
20
-
21
- SKIP_TAG="[SKIP TAG]"
22
-
23
- PIPE_MUTEX = Mutex.new
24
-
25
- OPEN_PIPE_IN = []
26
- def self.pipe
27
- OPEN_PIPE_IN.delete_if{|pipe| pipe.closed? }
28
- res = PIPE_MUTEX.synchronize do
29
- sout, sin = IO.pipe
30
- OPEN_PIPE_IN << sin
31
-
32
- [sout, sin]
33
- end
34
- Log.debug{"Creating pipe #{[res.last.inspect, res.first.inspect] * " => "}"}
35
- res
36
- end
37
-
38
- def self.with_fifo(path = nil, clean = true, &block)
39
- begin
40
- erase = path.nil?
41
- path = TmpFile.tmp_file if path.nil?
42
- File.rm path if clean && File.exist?(path)
43
- File.mkfifo path
44
- yield path
45
- ensure
46
- FileUtils.rm path if erase && File.exist?(path)
47
- end
48
- end
49
-
50
- def self.release_pipes(*pipes)
51
- PIPE_MUTEX.synchronize do
52
- pipes.flatten.each do |pipe|
53
- pipe.close unless pipe.closed?
54
- end
55
- end
56
- end
57
-
58
- def self.purge_pipes(*save)
59
- PIPE_MUTEX.synchronize do
60
- OPEN_PIPE_IN.each do |pipe|
61
- next if save.include? pipe
62
- pipe.close unless pipe.closed?
63
- end
64
- end
65
- end
66
-
67
- def self.open_pipe(do_fork = false, close = true)
68
- raise "No block given" unless block_given?
69
-
70
- sout, sin = Misc.pipe
71
-
72
- if do_fork
73
-
74
- #parent_pid = Process.pid
75
- pid = Process.fork {
76
- purge_pipes(sin)
77
- sout.close
78
- begin
79
-
80
- yield sin
81
- sin.close if close and not sin.closed?
82
-
83
- rescue Exception
84
- Log.exception $!
85
- #Process.kill :INT, parent_pid
86
- Kernel.exit! -1
87
- end
88
- Kernel.exit! 0
89
- }
90
- sin.close
91
-
92
- ConcurrentStream.setup sout, :pids => [pid]
93
- else
94
-
95
- ConcurrentStream.setup sin, :pair => sout
96
- ConcurrentStream.setup sout, :pair => sin
97
-
98
- thread = Thread.new do
99
- begin
100
-
101
- yield sin
102
-
103
- sin.close if close and not sin.closed? and not sin.aborted?
104
-
105
- rescue Aborted
106
- Log.medium "Aborted open_pipe: #{$!.message}"
107
- raise $!
108
- rescue Exception
109
- Log.medium "Exception in open_pipe: #{$!.message}"
110
- Log.exception $!
111
- begin
112
- sin.raise($!) if sin.respond_to? :raise
113
- sin.join if sin.respond_to? :join
114
- ensure
115
- raise $!
116
- end
117
- end
118
- end
119
-
120
- sin.threads = [thread]
121
- sout.threads = [thread]
122
- end
123
-
124
- sout
125
- end
126
-
127
- #def self.tee_stream_thread(stream)
128
- # stream_out1, stream_in1 = Misc.pipe
129
- # stream_out2, stream_in2 = Misc.pipe
130
-
131
- # splitter_thread = Thread.new(Thread.current) do |parent|
132
- # begin
133
-
134
- # skip1 = skip2 = false
135
- # while block = stream.read(1024)
136
-
137
- # begin
138
- # stream_in1.write block;
139
- # rescue IOError
140
- # Log.medium("Tee stream 1 #{Misc.fingerprint stream} IOError: #{$!.message}");
141
- # skip1 = true
142
- # end unless skip1
143
-
144
- # begin
145
- # stream_in2.write block
146
- # rescue IOError
147
- # Log.medium("Tee stream 2 #{Misc.fingerprint stream} IOError: #{$!.message}");
148
- # skip2 = true
149
- # end unless skip2
150
-
151
- # end
152
-
153
- # stream_in1.close unless stream_in1.closed?
154
- # stream.join if stream.respond_to? :join
155
- # stream_in2.close unless stream_in2.closed?
156
- # rescue Aborted, Interrupt
157
- # stream_out1.abort if stream_out1.respond_to? :abort
158
- # stream.abort if stream.respond_to? :abort
159
- # stream_out2.abort if stream_out2.respond_to? :abort
160
- # Log.medium "Tee aborting #{Misc.fingerprint stream}"
161
- # raise $!
162
- # rescue Exception
163
- # stream_out1.abort if stream_out1.respond_to? :abort
164
- # stream.abort if stream.respond_to? :abort
165
- # stream_out2.abort if stream_out2.respond_to? :abort
166
- # Log.medium "Tee exception #{Misc.fingerprint stream}"
167
- # raise $!
168
- # end
169
- # end
170
-
171
- # ConcurrentStream.setup stream_out1, :threads => splitter_thread
172
- # ConcurrentStream.setup stream_out2, :threads => splitter_thread
173
-
174
- # [stream_out1, stream_out2]
175
- #end
176
-
177
- def self.tee_stream_thread_multiple(stream, num = 2)
178
- in_pipes = []
179
- out_pipes = []
180
- num.times do
181
- sout, sin = Misc.pipe
182
- in_pipes << sin
183
- out_pipes << sout
184
- end
185
-
186
- filename = stream.filename if stream.respond_to? :filename
187
-
188
- splitter_thread = Thread.new(Thread.current) do |parent|
189
- begin
190
-
191
- skip = [false] * num
192
- begin
193
- while block = stream.readpartial(BLOCK_SIZE)
194
-
195
- in_pipes.each_with_index do |sin,i|
196
- begin
197
- sin.write block
198
- rescue IOError
199
- Log.error("Tee stream #{i} #{Misc.fingerprint stream} IOError: #{$!.message} (#{Misc.fingerprint sin})");
200
- skip[i] = true
201
- rescue
202
- Log.error("Tee stream #{i} #{Misc.fingerprint stream} Exception: #{$!.message} (#{Misc.fingerprint sin})");
203
- raise $!
204
- end unless skip[i]
205
- end
206
- end
207
- rescue IOError
208
- end
209
-
210
- stream.close unless stream.closed?
211
- #stream.join if stream.respond_to? :join
212
- in_pipes.first.close unless in_pipes.first.closed?
213
- #Log.medium "Tee done #{Misc.fingerprint stream}"
214
- rescue Aborted, Interrupt
215
- stream.abort if stream.respond_to? :abort
216
- out_pipes.each do |sout|
217
- sout.abort if sout.respond_to? :abort
218
- end
219
- Log.medium "Tee aborting #{Misc.fingerprint stream}"
220
- raise $!
221
- rescue Exception
222
- stream.abort($!) if stream.respond_to? :abort
223
- out_pipes.each do |sout|
224
- sout.abort if sout.respond_to? :abort
225
- end
226
- Log.medium "Tee exception #{Misc.fingerprint stream}"
227
- raise $!
228
- end
229
- end
230
-
231
- out_pipes.each do |sout|
232
- ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :_pair => stream
233
- end
234
-
235
- main_pipe = out_pipes.first
236
- main_pipe.autojoin = true
237
-
238
- main_pipe.callback = Proc.new do
239
- stream.join if stream.respond_to? :join
240
- in_pipes[1..-1].each do |sin|
241
- sin.close unless sin.closed?
242
- end
243
- end
244
-
245
- out_pipes
246
- end
247
-
248
- def self.tee_stream_thread(stream)
249
- tee_stream_thread_multiple(stream, 2)
250
- end
251
-
252
- def self.dup_stream_multiple(stream, num = 1)
253
- stream_dup = stream.dup
254
- if stream.respond_to? :annotate
255
- stream.annotate stream_dup
256
- stream.clear
257
- end
258
- tee1, *rest = Misc.tee_stream stream_dup, num + 1
259
- stream.reopen(tee1)
260
-
261
- #ToDo: I can't explain why the @threads variable appears with the value of
262
- # @filename
263
- stream.instance_variable_set(:@threads, nil) if stream.instance_variables.include?(:@threads)
264
-
265
- tee1.annotate(stream)
266
- rest
267
- end
268
-
269
- def self.dup_stream(stream)
270
- dup_stream_multiple(stream, 1).first
271
- end
272
-
273
- class << self
274
- alias tee_stream tee_stream_thread_multiple
275
- end
276
-
277
- def self.read_full_stream(io)
278
- str = ""
279
- begin
280
- while block = io.read(BLOCK_SIZE)
281
- str << block
282
- end
283
- io.join if io.respond_to? :join
284
- rescue
285
- io.abort if io.respond_to? :abort
286
- end
287
- str
288
- end
289
-
290
- def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
291
- return if Path === io
292
- return unless io.respond_to? :read
293
-
294
- if io.respond_to? :closed? and io.closed?
295
- io.join if io.respond_to? :join
296
- return
297
- end
298
-
299
- if in_thread
300
- Thread.new(Thread.current) do |parent|
301
- begin
302
- consume_stream(io, false, into, into_close)
303
- rescue Exception
304
- parent.raise $!
305
- end
306
- end
307
- else
308
- if into
309
- Log.medium "Consuming stream #{Misc.fingerprint io} -> #{Misc.fingerprint into}"
310
- else
311
- Log.medium "Consuming stream #{Misc.fingerprint io}"
312
- end
313
-
314
- begin
315
- into = into.find if Path === into
316
- if String === into
317
- dir = File.dirname(into)
318
- Open.mkdir dir unless Open.exists?(dir)
319
- into_path, into = into, Open.open(into, :mode => 'w')
320
- end
321
- #into.sync = true if IO === into
322
- into_close = false unless into.respond_to? :close
323
- #io.sync = true
324
-
325
- begin
326
- while c = io.readpartial(BLOCK_SIZE)
327
- into << c if into
328
- end
329
- rescue EOFError
330
- end
331
-
332
- io.join if io.respond_to? :join
333
- io.close unless io.closed?
334
- into.close if into and into_close and not into.closed?
335
- into.join if into and into_close and into.respond_to?(:joined?) and not into.joined?
336
- block.call if block_given?
337
-
338
- #Log.medium "Done consuming stream #{Misc.fingerprint io}"
339
- rescue Aborted
340
- Log.medium "Consume stream aborted #{Misc.fingerprint io}"
341
- io.abort if io.respond_to? :abort
342
- #io.close unless io.closed?
343
- FileUtils.rm into_path if into_path and File.exist? into_path
344
- rescue Exception
345
- Log.medium "Exception consuming stream: #{Misc.fingerprint io}: #{$!.message}"
346
- io.abort $! if io.respond_to? :abort
347
- FileUtils.rm into_path if into_path and File.exist? into_path
348
- raise $!
349
- end
350
- end
351
- end
352
-
353
- def self.read_stream(stream, size)
354
- str = nil
355
- Thread.pass while IO.select([stream],nil,nil,1).nil?
356
- while not str = stream.read(size)
357
- IO.select([stream],nil,nil,1)
358
- Thread.pass
359
- raise ClosedStream if stream.eof?
360
- end
361
-
362
- while str.length < size
363
- raise ClosedStream if stream.eof?
364
- IO.select([stream],nil,nil,1)
365
- if new = stream.read(size-str.length)
366
- str << new
367
- end
368
- end
369
- str
370
- end
371
-
372
- def self.sensiblewrite(path, content = nil, options = {}, &block)
373
- force = Misc.process_options options, :force
374
-
375
- if Open.exists? path and not force
376
- Misc.consume_stream content
377
- return
378
- end
379
-
380
- lock_options = Misc.pull_keys options.dup, :lock
381
- lock_options = lock_options[:lock] if Hash === lock_options[:lock]
382
- tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
383
- tmp_path_lock = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_lock_dir})
384
-
385
- tmp_path_lock = nil if FalseClass === options[:lock]
386
-
387
- Misc.lock tmp_path_lock, lock_options do
388
-
389
- if Open.exists? path and not force
390
- Log.warn "Path exists in sensiblewrite, not forcing update: #{ path }"
391
- Misc.consume_stream content
392
- else
393
- FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory? File.dirname(tmp_path)
394
- FileUtils.rm_f tmp_path if File.exist? tmp_path
395
- begin
396
-
397
- case
398
- when block_given?
399
- File.open(tmp_path, 'wb', &block)
400
- when String === content
401
- File.open(tmp_path, 'wb') do |f| f.write content end
402
- when (IO === content or StringIO === content or File === content)
403
-
404
- Open.write(tmp_path) do |f|
405
- #f.sync = true
406
- while block = content.read(BLOCK_SIZE)
407
- f.write block
408
- end
409
- end
410
- else
411
- File.open(tmp_path, 'wb') do |f| end
412
- end
413
-
414
- begin
415
- Misc.insist do
416
- Open.mv tmp_path, path, lock_options
417
- end
418
- rescue Exception
419
- raise $! unless Open.exists? path
420
- end
421
-
422
- Open.touch path if Open.exists? path
423
- content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
424
-
425
- Open.notify_write(path)
426
- rescue Aborted
427
- Log.medium "Aborted sensiblewrite -- #{ Log.reset << Log.color(:blue, path) }"
428
- content.abort if content.respond_to? :abort
429
- Open.rm path if File.exist? path
430
- rescue Exception
431
- exception = (AbortedStream === content and content.exception) ? content.exception : $!
432
- Log.medium "Exception in sensiblewrite: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
433
- content.abort if content.respond_to? :abort
434
- Open.rm path if File.exist? path
435
- raise exception
436
- rescue
437
- Log.exception $!
438
- raise $!
439
- ensure
440
- FileUtils.rm_f tmp_path if File.exist? tmp_path
441
- if Lockfile === lock_options[:lock] and lock_options[:lock].locked?
442
- lock_options[:lock].unlock
443
- end
444
- end
445
- end
446
- end
447
- end
448
-
449
- def self.process_stream(s)
450
- begin
451
- yield s
452
- s.join if s.respond_to? :join
453
- rescue
454
- s.abort if s.respond_to? :abort
455
- raise $!
456
- end
457
- end
458
-
459
- def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
460
- Misc.open_pipe do |sin|
461
- stream = TSV.get_stream stream
462
-
463
- line = stream.gets
464
- while line =~ /^#{header_hash}/ do
465
- sin.puts line
466
- line = stream.gets
467
- end
468
-
469
- line_stream = Misc.open_pipe do |line_stream_in|
470
- line_stream_in.puts line
471
- begin
472
- Misc.consume_stream(stream, false, line_stream_in)
473
- rescue
474
- raise $!
475
- end
476
- end
477
-
478
- sorted = CMD.cmd("env LC_ALL=C sort #{cmd_args || ""}", :in => line_stream, :pipe => true)
479
-
480
- begin
481
- Misc.consume_stream(sorted, false, sin)
482
- rescue
483
- Log.exception $!
484
- begin
485
- sorted.raise($!) if sorted.respond_to? :raise
486
- stream.raise($!) if stream.respond_to? :raise
487
- ensure
488
- raise $!
489
- end
490
- end
491
- end
492
- end
493
-
494
- def self.collapse_stream(s, line = nil, sep = "\t", header = nil, &block)
495
- sep ||= "\t"
496
- Misc.open_pipe do |sin|
497
- sin.puts header if header
498
- process_stream(s) do |s|
499
- line ||= s.gets
500
-
501
- current_parts = []
502
- while line
503
- key, *parts = line.chomp.split(sep, -1)
504
- case
505
- when key.nil?
506
- when current_parts.nil?
507
- current_parts = parts
508
- current_key = key
509
- when current_key == key
510
- parts.each_with_index do |part,i|
511
- if current_parts[i].nil?
512
- current_parts[i] = "|" << part
513
- else
514
- current_parts[i] = current_parts[i] << "|" << part
515
- end
516
- end
517
-
518
- (parts.length..current_parts.length-1).to_a.each do |pos|
519
- current_parts[pos] = current_parts[pos] << "|" << ""
520
- end
521
- when current_key.nil?
522
- current_key = key
523
- current_parts = parts
524
- when current_key != key
525
- if block_given?
526
- res = block.call(current_parts)
527
- sin.puts [current_key, res] * sep
528
- else
529
- sin.puts [current_key, current_parts].flatten * sep
530
- end
531
- current_key = key
532
- current_parts = parts
533
- end
534
- line = s.gets
535
- end
536
-
537
- if block_given?
538
- res = block.call(current_parts)
539
- sin.puts [current_key, res] * sep
540
- else
541
- sin.puts [current_key, current_parts].flatten * sep
542
- end unless current_key.nil?
543
- end
544
- end
545
- end
546
-
547
- def self.buffer_stream(stream)
548
- sout, sin = Misc.pipe
549
- Misc.consume_stream(stream, true, sin)
550
- sout
551
- end
552
-
553
- def self._paste_streams(streams, output, lines = nil, sep = "\t", header = nil, &block)
554
- output.puts header if header
555
- streams = streams.collect do |stream|
556
- if defined? Step and Step === stream
557
- io = stream.get_stream
558
- if io
559
- buffer_stream(io)
560
- else
561
- stream.join.path.open
562
- end
563
- else
564
- stream
565
- end
566
- end
567
-
568
- begin
569
-
570
- lines ||= streams.collect{|s| s.gets }
571
- keys = []
572
- parts = []
573
- lines.each_with_index do |line,i|
574
- if line.nil?
575
- keys[i] = nil
576
- parts[i] = []
577
- else
578
- key, *p = line.chomp.split(sep, -1)
579
- keys[i] = key
580
- parts[i] = p
581
- end
582
- end
583
- sizes = parts.collect{|p| p.nil? ? 0 : p.length }
584
- last_min = nil
585
-
586
- while lines.compact.any?
587
- if block_given?
588
- min = keys.compact.sort(&block).first
589
- else
590
- min = keys.compact.sort.first
591
- end
592
- str = []
593
- threads = []
594
- keys.each_with_index do |key,i|
595
- case key
596
- when min
597
- if parts[i] == [SKIP_TAG]
598
- str << [sep * (sizes[i]-1)] if sizes[i] > 0
599
- else
600
- str << [parts[i] * sep]
601
- end
602
-
603
- line = lines[i] = streams[i].gets
604
-
605
- if line.nil?
606
- keys[i] = nil
607
- parts[i] = nil
608
- streams[i].close unless streams[i].closed?
609
- streams[i].join if streams[i].respond_to?(:join)
610
- else
611
- k, *p = line.chomp.split(sep, -1)
612
- keys[i] = k
613
- parts[i] = p
614
- end
615
- else
616
- str << [sep * (sizes[i]-1)] if sizes[i] > 0
617
- end
618
- end
619
-
620
- output.puts [min, str.flatten*sep] * sep
621
- end
622
-
623
- streams.each do |stream|
624
- stream.close unless stream.closed?
625
- stream.join if stream.respond_to?(:join)
626
- end
627
- rescue
628
- Log.exception $!
629
- streams.each do |stream|
630
- stream.abort if stream.respond_to? :abort
631
- end
632
- raise $!
633
- end
634
- end
635
-
636
- def self.paste_streams(streams, lines = nil, sep = "\t", header = nil, &block)
637
- sep ||= "\t"
638
- num_streams = streams.length
639
- Misc.open_pipe do |sin|
640
- self._paste_streams(streams, sin, lines, sep, header, &block)
641
- end
642
- end
643
-
644
- def self.save_stream(file, stream)
645
- save, out = Misc.tee_stream stream
646
- out.filename = file
647
- save.filename = file
648
-
649
- Thread.new(Thread.current) do |parent|
650
- begin
651
- Misc.sensiblewrite(file, save)
652
- rescue Exception
653
- save.abort if save.respond_to? :abort
654
- stream.abort if stream.respond_to? :abort
655
- stream.join
656
- Log.medium "Exception in save_stream: #{$!.message}"
657
- raise $!
658
- end
659
- end
660
-
661
- out
662
- end
663
-
664
- def self.intercalate_streams(streams)
665
- Misc.open_pipe do |sin|
666
- continue = true
667
- while continue
668
- lines = streams.collect{|stream| stream.eof? ? nil : stream.gets }.compact
669
- lines.each do |line|
670
- sin.puts line
671
- end
672
- continue = false if lines.empty?
673
- end
674
- streams.each do |stream|
675
- stream.join if stream.respond_to? :join
676
- stream.close if stream.respond_to? :close and not stream.closed?
677
- end
678
- end
679
- end
680
-
681
- def self.compare_lines(stream1, stream2, args, sort = false)
682
- if sort
683
- stream1 = Misc.sort_stream stream1
684
- stream2 = Misc.sort_stream stream2
685
- compare_lines(stream1, stream2, args, false)
686
- else
687
- erase = []
688
-
689
- if Path === stream1 or (String === stream1 and File.exist? stream1)
690
- file1 = stream1
691
- else
692
- file1 = TmpFile.tmp_file
693
- erase << file1
694
- Misc.consume_stream(TSV.get_stream(stream1), false, file1)
695
- end
696
-
697
- if Path === stream2 or (String === stream2 and File.exist? stream2)
698
- file2 = stream2
699
- else
700
- file2 = TmpFile.tmp_file
701
- erase << file2
702
- Misc.consume_stream(TSV.get_stream(stream2), false, file2)
703
- end
704
-
705
- CMD.cmd("env LC_ALL=C comm #{args} '#{file1}' '#{file2}'", :pipe => true, :post => Proc.new{ erase.each{|f| FileUtils.rm f } })
706
- end
707
- end
708
-
709
- def self.remove_lines(stream1, stream2, sort)
710
- self.compare_lines(stream1, stream2, '-2 -3', sort)
711
- end
712
-
713
- def self.select_lines(stream1, stream2, sort)
714
- self.compare_lines(stream1, stream2, '-1 -2', sort)
715
- end
716
-
717
-
718
- def self.add_stream_filename(io, filename)
719
- if ! io.respond_to? :filename
720
- class << io
721
- attr_accessor :filename
722
- end
723
- io.filename = filename
724
- end
725
- end
726
-
727
- def self.sort_mutation_stream_strict(stream, sep=":")
728
- CMD.cmd("grep '#{sep}' | sort -u | sed 's/^M:/MT:/' | env LC_ALL=C sort -V -k1,1 -k2,2n -k3,3n -t'#{sep}'", :in => stream, :pipe => true, :no_fail => true)
729
- end
730
-
731
- def self.sort_mutation_stream(stream, sep=":")
732
- CMD.cmd("grep '#{sep}' | sort -u | sed 's/^M:/MT:/' | env LC_ALL=C sort -k1,1 -k2,2n -k3,3n -t'#{sep}'", :in => stream, :pipe => true, :no_fail => true)
733
- end
734
-
735
- def self.swap_quoted_character(stream, charout="\n", charin=" ", quote='"')
736
- io = Misc.open_pipe do |sin|
737
- begin
738
- quoted = false
739
- prev = nil
740
- while c = stream.getc
741
- if c == quote and not prev == "\\"
742
- quoted = ! quoted
743
- end
744
- c = charin if c == charout and quoted
745
- sin << c
746
- prev = c
747
- end
748
- rescue
749
- stream.abort if stream.respond_to? :abort
750
- raise $!
751
- ensure
752
- stream.join if stream.respond_to? :join
753
- end
754
- end
755
- end
756
-
757
- def self.remove_quoted_new_line(stream, quote = '"')
758
- swap_quoted_character(stream, "\n", " ", quote)
759
- end
760
-
761
- def self.line_monitor_stream(stream, &block)
762
- monitor, out = tee_stream stream
763
- monitor_thread = Thread.new do
764
- begin
765
- while line = monitor.gets
766
- block.call line
767
- end
768
- rescue
769
- Log.exception $!
770
- monitor.raise $!
771
- monitor.close unless monitor.closed?
772
- monitor.join if monitor.respond_to?(:join) && ! monitor.aborted?
773
- out.raise $! if out.respond_to?(:raise)
774
- ensure
775
- monitor.close unless monitor.closed?
776
- monitor.join if monitor.respond_to?(:join) && ! monitor.aborted?
777
- end
778
- end
779
-
780
- stream.annotate out if stream.respond_to? :annotate
781
- ConcurrentStream.setup out, :threads => monitor_thread
782
- end
783
-
784
- def self.open_gz_pipe
785
- sout = Misc.open_pipe do |sin|
786
- yield sin
787
- sin.close
788
- end
789
-
790
- Open.gzip(sout)
791
- end
792
-
793
- end
1
+ require_relative '../../refactor'
2
+ Rbbt.require_instead 'scout/open/stream'
3
+
4
+ #require 'rbbt'
5
+ #
6
+ #module Misc
7
+ # class << self
8
+ # attr_accessor :sensiblewrite_lock_dir
9
+ #
10
+ # def sensiblewrite_lock_dir
11
+ # @sensiblewrite_lock_dir ||= Rbbt.tmp.sensiblewrite_locks.find
12
+ # end
13
+ # end
14
+ #
15
+ # class << self
16
+ # attr_accessor :sensiblewrite_dir
17
+ # def sensiblewrite_dir
18
+ # @sensiblewrite_dir = Rbbt.tmp.sensiblewrite.find
19
+ # end
20
+ # end
21
+ #
22
+ # BLOCK_SIZE=1024 * 8
23
+ #
24
+ # SKIP_TAG="[SKIP TAG]"
25
+ #
26
+ # PIPE_MUTEX = Mutex.new
27
+ #
28
+ # OPEN_PIPE_IN = []
29
+ # def self.pipe
30
+ # OPEN_PIPE_IN.delete_if{|pipe| pipe.closed? }
31
+ # res = PIPE_MUTEX.synchronize do
32
+ # sout, sin = IO.pipe
33
+ # OPEN_PIPE_IN << sin
34
+ #
35
+ # [sout, sin]
36
+ # end
37
+ # Log.debug{"Creating pipe #{[res.last.inspect, res.first.inspect] * " => "}"}
38
+ # res
39
+ # end
40
+ #
41
+ # def self.with_fifo(path = nil, clean = true, &block)
42
+ # begin
43
+ # erase = path.nil?
44
+ # path = TmpFile.tmp_file if path.nil?
45
+ # File.rm path if clean && File.exist?(path)
46
+ # File.mkfifo path
47
+ # yield path
48
+ # ensure
49
+ # FileUtils.rm path if erase && File.exist?(path)
50
+ # end
51
+ # end
52
+ #
53
+ # def self.release_pipes(*pipes)
54
+ # PIPE_MUTEX.synchronize do
55
+ # pipes.flatten.each do |pipe|
56
+ # pipe.close unless pipe.closed?
57
+ # end
58
+ # end
59
+ # end
60
+ #
61
+ # def self.purge_pipes(*save)
62
+ # PIPE_MUTEX.synchronize do
63
+ # OPEN_PIPE_IN.each do |pipe|
64
+ # next if save.include? pipe
65
+ # pipe.close unless pipe.closed?
66
+ # end
67
+ # end
68
+ # end
69
+ #
70
+ # def self.open_pipe(do_fork = false, close = true)
71
+ # raise "No block given" unless block_given?
72
+ #
73
+ # sout, sin = Misc.pipe
74
+ #
75
+ # if do_fork
76
+ #
77
+ # #parent_pid = Process.pid
78
+ # pid = Process.fork {
79
+ # purge_pipes(sin)
80
+ # sout.close
81
+ # begin
82
+ #
83
+ # yield sin
84
+ # sin.close if close and not sin.closed?
85
+ #
86
+ # rescue Exception
87
+ # Log.exception $!
88
+ # #Process.kill :INT, parent_pid
89
+ # Kernel.exit! -1
90
+ # end
91
+ # Kernel.exit! 0
92
+ # }
93
+ # sin.close
94
+ #
95
+ # ConcurrentStream.setup sout, :pids => [pid]
96
+ # else
97
+ #
98
+ # ConcurrentStream.setup sin, :pair => sout
99
+ # ConcurrentStream.setup sout, :pair => sin
100
+ #
101
+ # thread = Thread.new do
102
+ # begin
103
+ #
104
+ # yield sin
105
+ #
106
+ # sin.close if close and not sin.closed? and not sin.aborted?
107
+ #
108
+ # rescue Aborted
109
+ # Log.medium "Aborted open_pipe: #{$!.message}"
110
+ # raise $!
111
+ # rescue Exception
112
+ # Log.medium "Exception in open_pipe: #{$!.message}"
113
+ # Log.exception $!
114
+ # begin
115
+ # sin.raise($!) if sin.respond_to? :raise
116
+ # sin.join if sin.respond_to? :join
117
+ # ensure
118
+ # raise $!
119
+ # end
120
+ # end
121
+ # end
122
+ #
123
+ # sin.threads = [thread]
124
+ # sout.threads = [thread]
125
+ # end
126
+ #
127
+ # sout
128
+ # end
129
+ #
130
+ # #def self.tee_stream_thread(stream)
131
+ # # stream_out1, stream_in1 = Misc.pipe
132
+ # # stream_out2, stream_in2 = Misc.pipe
133
+ #
134
+ # # splitter_thread = Thread.new(Thread.current) do |parent|
135
+ # # begin
136
+ #
137
+ # # skip1 = skip2 = false
138
+ # # while block = stream.read(1024)
139
+ #
140
+ # # begin
141
+ # # stream_in1.write block;
142
+ # # rescue IOError
143
+ # # Log.medium("Tee stream 1 #{Misc.fingerprint stream} IOError: #{$!.message}");
144
+ # # skip1 = true
145
+ # # end unless skip1
146
+ #
147
+ # # begin
148
+ # # stream_in2.write block
149
+ # # rescue IOError
150
+ # # Log.medium("Tee stream 2 #{Misc.fingerprint stream} IOError: #{$!.message}");
151
+ # # skip2 = true
152
+ # # end unless skip2
153
+ #
154
+ # # end
155
+ #
156
+ # # stream_in1.close unless stream_in1.closed?
157
+ # # stream.join if stream.respond_to? :join
158
+ # # stream_in2.close unless stream_in2.closed?
159
+ # # rescue Aborted, Interrupt
160
+ # # stream_out1.abort if stream_out1.respond_to? :abort
161
+ # # stream.abort if stream.respond_to? :abort
162
+ # # stream_out2.abort if stream_out2.respond_to? :abort
163
+ # # Log.medium "Tee aborting #{Misc.fingerprint stream}"
164
+ # # raise $!
165
+ # # rescue Exception
166
+ # # stream_out1.abort if stream_out1.respond_to? :abort
167
+ # # stream.abort if stream.respond_to? :abort
168
+ # # stream_out2.abort if stream_out2.respond_to? :abort
169
+ # # Log.medium "Tee exception #{Misc.fingerprint stream}"
170
+ # # raise $!
171
+ # # end
172
+ # # end
173
+ #
174
+ # # ConcurrentStream.setup stream_out1, :threads => splitter_thread
175
+ # # ConcurrentStream.setup stream_out2, :threads => splitter_thread
176
+ #
177
+ # # [stream_out1, stream_out2]
178
+ # #end
179
+ #
180
+ # def self.tee_stream_thread_multiple(stream, num = 2)
181
+ # in_pipes = []
182
+ # out_pipes = []
183
+ # num.times do
184
+ # sout, sin = Misc.pipe
185
+ # in_pipes << sin
186
+ # out_pipes << sout
187
+ # end
188
+ #
189
+ # filename = stream.filename if stream.respond_to? :filename
190
+ #
191
+ # splitter_thread = Thread.new(Thread.current) do |parent|
192
+ # begin
193
+ #
194
+ # skip = [false] * num
195
+ # begin
196
+ # while block = stream.readpartial(BLOCK_SIZE)
197
+ #
198
+ # in_pipes.each_with_index do |sin,i|
199
+ # begin
200
+ # sin.write block
201
+ # rescue IOError
202
+ # Log.error("Tee stream #{i} #{Misc.fingerprint stream} IOError: #{$!.message} (#{Misc.fingerprint sin})");
203
+ # skip[i] = true
204
+ # rescue
205
+ # Log.error("Tee stream #{i} #{Misc.fingerprint stream} Exception: #{$!.message} (#{Misc.fingerprint sin})");
206
+ # raise $!
207
+ # end unless skip[i]
208
+ # end
209
+ # end
210
+ # rescue IOError
211
+ # end
212
+ #
213
+ # stream.close unless stream.closed?
214
+ # #stream.join if stream.respond_to? :join
215
+ # in_pipes.first.close unless in_pipes.first.closed?
216
+ # #Log.medium "Tee done #{Misc.fingerprint stream}"
217
+ # rescue Aborted, Interrupt
218
+ # stream.abort if stream.respond_to? :abort
219
+ # out_pipes.each do |sout|
220
+ # sout.abort if sout.respond_to? :abort
221
+ # end
222
+ # Log.medium "Tee aborting #{Misc.fingerprint stream}"
223
+ # raise $!
224
+ # rescue Exception
225
+ # stream.abort($!) if stream.respond_to? :abort
226
+ # out_pipes.each do |sout|
227
+ # sout.abort if sout.respond_to? :abort
228
+ # end
229
+ # Log.medium "Tee exception #{Misc.fingerprint stream}"
230
+ # raise $!
231
+ # end
232
+ # end
233
+ #
234
+ # out_pipes.each do |sout|
235
+ # ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :_pair => stream
236
+ # end
237
+ #
238
+ # main_pipe = out_pipes.first
239
+ # main_pipe.autojoin = true
240
+ #
241
+ # main_pipe.callback = Proc.new do
242
+ # stream.join if stream.respond_to? :join
243
+ # in_pipes[1..-1].each do |sin|
244
+ # sin.close unless sin.closed?
245
+ # end
246
+ # end
247
+ #
248
+ # out_pipes
249
+ # end
250
+ #
251
+ # def self.tee_stream_thread(stream)
252
+ # tee_stream_thread_multiple(stream, 2)
253
+ # end
254
+ #
255
+ # def self.dup_stream_multiple(stream, num = 1)
256
+ # stream_dup = stream.dup
257
+ # if stream.respond_to? :annotate
258
+ # stream.annotate stream_dup
259
+ # stream.clear
260
+ # end
261
+ # tee1, *rest = Misc.tee_stream stream_dup, num + 1
262
+ # stream.reopen(tee1)
263
+ #
264
+ # #ToDo: I can't explain why the @threads variable appears with the value of
265
+ # # @filename
266
+ # stream.instance_variable_set(:@threads, nil) if stream.instance_variables.include?(:@threads)
267
+ #
268
+ # tee1.annotate(stream)
269
+ # rest
270
+ # end
271
+ #
272
+ # def self.dup_stream(stream)
273
+ # dup_stream_multiple(stream, 1).first
274
+ # end
275
+ #
276
+ # class << self
277
+ # alias tee_stream tee_stream_thread_multiple
278
+ # end
279
+ #
280
+ # def self.read_full_stream(io)
281
+ # str = ""
282
+ # begin
283
+ # while block = io.read(BLOCK_SIZE)
284
+ # str << block
285
+ # end
286
+ # io.join if io.respond_to? :join
287
+ # rescue
288
+ # io.abort if io.respond_to? :abort
289
+ # end
290
+ # str
291
+ # end
292
+ #
293
+ # def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
294
+ # return if Path === io
295
+ # return unless io.respond_to? :read
296
+ #
297
+ # if io.respond_to? :closed? and io.closed?
298
+ # io.join if io.respond_to? :join
299
+ # return
300
+ # end
301
+ #
302
+ # if in_thread
303
+ # Thread.new(Thread.current) do |parent|
304
+ # begin
305
+ # consume_stream(io, false, into, into_close)
306
+ # rescue Exception
307
+ # parent.raise $!
308
+ # end
309
+ # end
310
+ # else
311
+ # if into
312
+ # Log.medium "Consuming stream #{Misc.fingerprint io} -> #{Misc.fingerprint into}"
313
+ # else
314
+ # Log.medium "Consuming stream #{Misc.fingerprint io}"
315
+ # end
316
+ #
317
+ # begin
318
+ # into = into.find if Path === into
319
+ # if String === into
320
+ # dir = File.dirname(into)
321
+ # Open.mkdir dir unless Open.exists?(dir)
322
+ # into_path, into = into, Open.open(into, :mode => 'w')
323
+ # end
324
+ # into.sync = true if IO === into
325
+ # into_close = false unless into.respond_to? :close
326
+ # io.sync = true
327
+ #
328
+ # begin
329
+ # while c = io.readpartial(BLOCK_SIZE)
330
+ # into << c if into
331
+ # end
332
+ # rescue EOFError
333
+ # end
334
+ #
335
+ # io.join if io.respond_to? :join
336
+ # io.close unless io.closed?
337
+ # into.close if into and into_close and not into.closed?
338
+ # into.join if into and into_close and into.respond_to?(:joined?) and not into.joined?
339
+ # block.call if block_given?
340
+ #
341
+ # #Log.medium "Done consuming stream #{Misc.fingerprint io}"
342
+ # rescue Aborted
343
+ # Log.medium "Consume stream aborted #{Misc.fingerprint io}"
344
+ # io.abort if io.respond_to? :abort
345
+ # #io.close unless io.closed?
346
+ # FileUtils.rm into_path if into_path and File.exist? into_path
347
+ # rescue Exception
348
+ # Log.medium "Exception consuming stream: #{Misc.fingerprint io}: #{$!.message}"
349
+ # io.abort $! if io.respond_to? :abort
350
+ # FileUtils.rm into_path if into_path and File.exist? into_path
351
+ # raise $!
352
+ # end
353
+ # end
354
+ # end
355
+ #
356
+ # def self.read_stream(stream, size)
357
+ # str = nil
358
+ # Thread.pass while IO.select([stream],nil,nil,1).nil?
359
+ # while not str = stream.read(size)
360
+ # IO.select([stream],nil,nil,1)
361
+ # Thread.pass
362
+ # raise ClosedStream if stream.eof?
363
+ # end
364
+ #
365
+ # while str.length < size
366
+ # raise ClosedStream if stream.eof?
367
+ # IO.select([stream],nil,nil,1)
368
+ # if new = stream.read(size-str.length)
369
+ # str << new
370
+ # end
371
+ # end
372
+ # str
373
+ # end
374
+ #
375
+ # def self.sensiblewrite(*args, &block)
376
+ # Open.sensible_write(*args, &block)
377
+ # end
378
+ #
379
+ # #def self.sensiblewrite(path, content = nil, options = {}, &block)
380
+ # # force = Misc.process_options options, :force
381
+ #
382
+ # # if Open.exists? path and not force
383
+ # # Misc.consume_stream content
384
+ # # return
385
+ # # end
386
+ #
387
+ # # lock_options = Misc.pull_keys options.dup, :lock
388
+ # # lock_options = lock_options[:lock] if Hash === lock_options[:lock]
389
+ # # tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
390
+ # # tmp_path_lock = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_lock_dir})
391
+ #
392
+ # # tmp_path_lock = nil if FalseClass === options[:lock]
393
+ #
394
+ # # Misc.lock tmp_path_lock, lock_options do
395
+ #
396
+ # # if Open.exists? path and not force
397
+ # # Log.warn "Path exists in sensiblewrite, not forcing update: #{ path }"
398
+ # # Misc.consume_stream content
399
+ # # else
400
+ # # FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory? File.dirname(tmp_path)
401
+ # # FileUtils.rm_f tmp_path if File.exist? tmp_path
402
+ # # begin
403
+ #
404
+ # # case
405
+ # # when block_given?
406
+ # # File.open(tmp_path, 'wb', &block)
407
+ # # when String === content
408
+ # # File.open(tmp_path, 'wb') do |f| f.write content end
409
+ # # when (IO === content or StringIO === content or File === content)
410
+ #
411
+ # # Open.write(tmp_path) do |f|
412
+ # # f.sync = true
413
+ # # while block = content.read(BLOCK_SIZE)
414
+ # # f.write block
415
+ # # end
416
+ # # end
417
+ # # else
418
+ # # File.open(tmp_path, 'wb') do |f| end
419
+ # # end
420
+ #
421
+ # # begin
422
+ # # Misc.insist do
423
+ # # Open.mv tmp_path, path, lock_options
424
+ # # end
425
+ # # rescue Exception
426
+ # # raise $! unless Open.exists? path
427
+ # # end
428
+ #
429
+ # # Open.touch path if Open.exists? path
430
+ # # content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
431
+ #
432
+ # # Open.notify_write(path)
433
+ # # rescue Aborted
434
+ # # Log.medium "Aborted sensiblewrite -- #{ Log.reset << Log.color(:blue, path) }"
435
+ # # content.abort if content.respond_to? :abort
436
+ # # Open.rm path if File.exist? path
437
+ # # rescue Exception
438
+ # # exception = (AbortedStream === content and content.exception) ? content.exception : $!
439
+ # # Log.medium "Exception in sensiblewrite: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
440
+ # # content.abort if content.respond_to? :abort
441
+ # # Open.rm path if File.exist? path
442
+ # # raise exception
443
+ # # rescue
444
+ # # Log.exception $!
445
+ # # raise $!
446
+ # # ensure
447
+ # # FileUtils.rm_f tmp_path if File.exist? tmp_path
448
+ # # if Lockfile === lock_options[:lock] and lock_options[:lock].locked?
449
+ # # lock_options[:lock].unlock
450
+ # # end
451
+ # # end
452
+ # # end
453
+ # # end
454
+ # #end
455
+ #
456
+ # def self.process_stream(s)
457
+ # begin
458
+ # yield s
459
+ # s.join if s.respond_to? :join
460
+ # rescue
461
+ # s.abort if s.respond_to? :abort
462
+ # raise $!
463
+ # end
464
+ # end
465
+ #
466
+ # def self.collapse_stream(s, line = nil, sep = "\t", header = nil, &block)
467
+ # sep ||= "\t"
468
+ # Misc.open_pipe do |sin|
469
+ # sin.puts header if header
470
+ # process_stream(s) do |s|
471
+ # line ||= s.gets
472
+ #
473
+ # current_parts = []
474
+ # while line
475
+ # key, *parts = line.chomp.split(sep, -1)
476
+ # case
477
+ # when key.nil?
478
+ # when current_parts.nil?
479
+ # current_parts = parts
480
+ # current_key = key
481
+ # when current_key == key
482
+ # parts.each_with_index do |part,i|
483
+ # if current_parts[i].nil?
484
+ # current_parts[i] = "|" << part
485
+ # else
486
+ # current_parts[i] = current_parts[i] << "|" << part
487
+ # end
488
+ # end
489
+ #
490
+ # (parts.length..current_parts.length-1).to_a.each do |pos|
491
+ # current_parts[pos] = current_parts[pos] << "|" << ""
492
+ # end
493
+ # when current_key.nil?
494
+ # current_key = key
495
+ # current_parts = parts
496
+ # when current_key != key
497
+ # if block_given?
498
+ # res = block.call(current_parts)
499
+ # sin.puts [current_key, res] * sep
500
+ # else
501
+ # sin.puts [current_key, current_parts].flatten * sep
502
+ # end
503
+ # current_key = key
504
+ # current_parts = parts
505
+ # end
506
+ # line = s.gets
507
+ # end
508
+ #
509
+ # if block_given?
510
+ # res = block.call(current_parts)
511
+ # sin.puts [current_key, res] * sep
512
+ # else
513
+ # sin.puts [current_key, current_parts].flatten * sep
514
+ # end unless current_key.nil?
515
+ # end
516
+ # end
517
+ # end
518
+ #
519
+ # def self.buffer_stream(stream)
520
+ # sout, sin = Misc.pipe
521
+ # Misc.consume_stream(stream, true, sin)
522
+ # sout
523
+ # end
524
+ #
525
+ # def self._paste_streams(streams, output, lines = nil, sep = "\t", header = nil, &block)
526
+ # output.puts header if header
527
+ # streams = streams.collect do |stream|
528
+ # if defined? Step and Step === stream
529
+ # io = stream.get_stream
530
+ # if io
531
+ # buffer_stream(io)
532
+ # else
533
+ # stream.join.path.open
534
+ # end
535
+ # else
536
+ # stream
537
+ # end
538
+ # end
539
+ #
540
+ # begin
541
+ #
542
+ # lines ||= streams.collect{|s| s.gets }
543
+ # keys = []
544
+ # parts = []
545
+ # lines.each_with_index do |line,i|
546
+ # if line.nil?
547
+ # keys[i] = nil
548
+ # parts[i] = []
549
+ # else
550
+ # key, *p = line.chomp.split(sep, -1)
551
+ # keys[i] = key
552
+ # parts[i] = p
553
+ # end
554
+ # end
555
+ # sizes = parts.collect{|p| p.nil? ? 0 : p.length }
556
+ # last_min = nil
557
+ #
558
+ # while lines.compact.any?
559
+ # if block_given?
560
+ # min = keys.compact.sort(&block).first
561
+ # else
562
+ # min = keys.compact.sort.first
563
+ # end
564
+ # str = []
565
+ # threads = []
566
+ # keys.each_with_index do |key,i|
567
+ # case key
568
+ # when min
569
+ # if parts[i] == [SKIP_TAG]
570
+ # str << [sep * (sizes[i]-1)] if sizes[i] > 0
571
+ # else
572
+ # str << [parts[i] * sep]
573
+ # end
574
+ #
575
+ # line = lines[i] = streams[i].gets
576
+ #
577
+ # if line.nil?
578
+ # keys[i] = nil
579
+ # parts[i] = nil
580
+ # streams[i].close unless streams[i].closed?
581
+ # streams[i].join if streams[i].respond_to?(:join)
582
+ # else
583
+ # k, *p = line.chomp.split(sep, -1)
584
+ # keys[i] = k
585
+ # parts[i] = p
586
+ # end
587
+ # else
588
+ # str << [sep * (sizes[i]-1)] if sizes[i] > 0
589
+ # end
590
+ # end
591
+ #
592
+ # output.puts [min, str.flatten*sep] * sep
593
+ # end
594
+ #
595
+ # streams.each do |stream|
596
+ # stream.close unless stream.closed?
597
+ # stream.join if stream.respond_to?(:join)
598
+ # end
599
+ # rescue
600
+ # Log.exception $!
601
+ # streams.each do |stream|
602
+ # stream.abort if stream.respond_to? :abort
603
+ # end
604
+ # raise $!
605
+ # end
606
+ # end
607
+ #
608
+ # def self.paste_streams(streams, lines = nil, sep = "\t", header = nil, &block)
609
+ # sep ||= "\t"
610
+ # num_streams = streams.length
611
+ # Misc.open_pipe do |sin|
612
+ # self._paste_streams(streams, sin, lines, sep, header, &block)
613
+ # end
614
+ # end
615
+ #
616
+ # def self.save_stream(file, stream)
617
+ # save, out = Misc.tee_stream stream
618
+ # out.filename = file
619
+ # save.filename = file
620
+ #
621
+ # Thread.new(Thread.current) do |parent|
622
+ # begin
623
+ # Misc.sensiblewrite(file, save)
624
+ # rescue Exception
625
+ # save.abort if save.respond_to? :abort
626
+ # stream.abort if stream.respond_to? :abort
627
+ # stream.join
628
+ # Log.medium "Exception in save_stream: #{$!.message}"
629
+ # raise $!
630
+ # end
631
+ # end
632
+ #
633
+ # out
634
+ # end
635
+ #
636
+ # def self.intercalate_streams(streams)
637
+ # Misc.open_pipe do |sin|
638
+ # continue = true
639
+ # while continue
640
+ # lines = streams.collect{|stream| stream.eof? ? nil : stream.gets }.compact
641
+ # lines.each do |line|
642
+ # sin.puts line
643
+ # end
644
+ # continue = false if lines.empty?
645
+ # end
646
+ # streams.each do |stream|
647
+ # stream.join if stream.respond_to? :join
648
+ # stream.close if stream.respond_to? :close and not stream.closed?
649
+ # end
650
+ # end
651
+ # end
652
+ #
653
+ # def self.compare_lines(stream1, stream2, args, sort = false)
654
+ # if sort
655
+ # stream1 = Misc.sort_stream stream1
656
+ # stream2 = Misc.sort_stream stream2
657
+ # compare_lines(stream1, stream2, args, false)
658
+ # else
659
+ # erase = []
660
+ #
661
+ # if Path === stream1 or (String === stream1 and File.exist? stream1)
662
+ # file1 = stream1
663
+ # else
664
+ # file1 = TmpFile.tmp_file
665
+ # erase << file1
666
+ # Misc.consume_stream(TSV.get_stream(stream1), false, file1)
667
+ # end
668
+ #
669
+ # if Path === stream2 or (String === stream2 and File.exist? stream2)
670
+ # file2 = stream2
671
+ # else
672
+ # file2 = TmpFile.tmp_file
673
+ # erase << file2
674
+ # Misc.consume_stream(TSV.get_stream(stream2), false, file2)
675
+ # end
676
+ #
677
+ # CMD.cmd("env LC_ALL=C comm #{args} '#{file1}' '#{file2}'", :pipe => true, :post => Proc.new{ erase.each{|f| FileUtils.rm f } })
678
+ # end
679
+ # end
680
+ #
681
+ # def self.remove_lines(stream1, stream2, sort)
682
+ # self.compare_lines(stream1, stream2, '-2 -3', sort)
683
+ # end
684
+ #
685
+ # def self.select_lines(stream1, stream2, sort)
686
+ # self.compare_lines(stream1, stream2, '-1 -2', sort)
687
+ # end
688
+ #
689
+ #
690
+ # def self.add_stream_filename(io, filename)
691
+ # if ! io.respond_to? :filename
692
+ # class << io
693
+ # attr_accessor :filename
694
+ # end
695
+ # io.filename = filename
696
+ # end
697
+ # end
698
+ #
699
+ # def self.sort_mutation_stream_strict(stream, sep=":")
700
+ # CMD.cmd("grep '#{sep}' | sort -u | sed 's/^M:/MT:/' | env LC_ALL=C sort -V -k1,1 -k2,2n -k3,3n -t'#{sep}'", :in => stream, :pipe => true, :no_fail => true)
701
+ # end
702
+ #
703
+ # def self.sort_mutation_stream(stream, sep=":")
704
+ # CMD.cmd("grep '#{sep}' | sort -u | sed 's/^M:/MT:/' | env LC_ALL=C sort -k1,1 -k2,2n -k3,3n -t'#{sep}'", :in => stream, :pipe => true, :no_fail => true)
705
+ # end
706
+ #
707
+ # def self.swap_quoted_character(stream, charout="\n", charin=" ", quote='"')
708
+ # io = Misc.open_pipe do |sin|
709
+ # begin
710
+ # quoted = false
711
+ # prev = nil
712
+ # while c = stream.getc
713
+ # if c == quote and not prev == "\\"
714
+ # quoted = ! quoted
715
+ # end
716
+ # c = charin if c == charout and quoted
717
+ # sin << c
718
+ # prev = c
719
+ # end
720
+ # rescue
721
+ # stream.abort if stream.respond_to? :abort
722
+ # raise $!
723
+ # ensure
724
+ # stream.join if stream.respond_to? :join
725
+ # end
726
+ # end
727
+ # end
728
+ #
729
+ # def self.remove_quoted_new_line(stream, quote = '"')
730
+ # swap_quoted_character(stream, "\n", " ", quote)
731
+ # end
732
+ #
733
+ # def self.line_monitor_stream(stream, &block)
734
+ # monitor, out = tee_stream stream
735
+ # monitor_thread = Thread.new do
736
+ # begin
737
+ # while line = monitor.gets
738
+ # block.call line
739
+ # end
740
+ # rescue
741
+ # Log.exception $!
742
+ # monitor.raise $!
743
+ # monitor.close unless monitor.closed?
744
+ # monitor.join if monitor.respond_to?(:join) && ! monitor.aborted?
745
+ # out.raise $! if out.respond_to?(:raise)
746
+ # ensure
747
+ # monitor.close unless monitor.closed?
748
+ # monitor.join if monitor.respond_to?(:join) && ! monitor.aborted?
749
+ # end
750
+ # end
751
+ #
752
+ # stream.annotate out if stream.respond_to? :annotate
753
+ # ConcurrentStream.setup out, :threads => monitor_thread
754
+ # end
755
+ #
756
+ # def self.open_gz_pipe
757
+ # sout = Misc.open_pipe do |sin|
758
+ # yield sin
759
+ # sin.close
760
+ # end
761
+ #
762
+ # Open.gzip(sout)
763
+ # end
764
+ #
765
+ #end