scout-gear 2.0.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.vimproject +65 -2
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/bin/scout +233 -24
- data/lib/scout/cmd.rb +344 -0
- data/lib/scout/concurrent_stream.rb +259 -0
- data/lib/scout/exceptions.rb +15 -8
- data/lib/scout/indiferent_hash/options.rb +8 -26
- data/lib/scout/log/color.rb +2 -2
- data/lib/scout/log/fingerprint.rb +11 -1
- data/lib/scout/log/progress/report.rb +0 -1
- data/lib/scout/log/progress/util.rb +1 -1
- data/lib/scout/log/progress.rb +4 -4
- data/lib/scout/log.rb +10 -2
- data/lib/scout/meta_extension.rb +19 -3
- data/lib/scout/misc/digest.rb +56 -0
- data/lib/scout/misc/filesystem.rb +26 -0
- data/lib/scout/misc/format.rb +17 -6
- data/lib/scout/misc/insist.rb +56 -0
- data/lib/scout/misc/monitor.rb +23 -0
- data/lib/scout/misc.rb +5 -11
- data/lib/scout/open/lock.rb +61 -0
- data/lib/scout/open/remote.rb +120 -0
- data/lib/scout/open/stream.rb +373 -0
- data/lib/scout/open/util.rb +225 -0
- data/lib/scout/open.rb +169 -0
- data/lib/scout/path/find.rb +68 -21
- data/lib/scout/path/tmpfile.rb +8 -0
- data/lib/scout/path/util.rb +14 -1
- data/lib/scout/path.rb +6 -30
- data/lib/scout/persist/open.rb +17 -0
- data/lib/scout/persist/path.rb +15 -0
- data/lib/scout/persist/serialize.rb +151 -0
- data/lib/scout/persist.rb +54 -0
- data/lib/scout/resource/path.rb +20 -0
- data/lib/scout/resource/produce/rake.rb +69 -0
- data/lib/scout/resource/produce.rb +246 -0
- data/lib/scout/resource/scout.rb +3 -0
- data/lib/scout/resource/util.rb +48 -0
- data/lib/scout/resource.rb +39 -0
- data/lib/scout/simple_opt/accessor.rb +1 -1
- data/lib/scout/simple_opt/doc.rb +29 -23
- data/lib/scout/simple_opt/parse.rb +4 -3
- data/lib/scout/tmpfile.rb +39 -1
- data/lib/scout/workflow/definition.rb +78 -0
- data/lib/scout/workflow/documentation.rb +83 -0
- data/lib/scout/workflow/step/info.rb +77 -0
- data/lib/scout/workflow/step/load.rb +18 -0
- data/lib/scout/workflow/step.rb +132 -0
- data/lib/scout/workflow/task/inputs.rb +114 -0
- data/lib/scout/workflow/task.rb +155 -0
- data/lib/scout/workflow/usage.rb +314 -0
- data/lib/scout/workflow/util.rb +11 -0
- data/lib/scout/workflow.rb +40 -0
- data/lib/scout-gear.rb +4 -0
- data/lib/scout.rb +1 -0
- data/lib/workflow-scout.rb +2 -0
- data/scout-gear.gemspec +77 -5
- data/scout_commands/alias +48 -0
- data/scout_commands/find +83 -0
- data/scout_commands/glob +0 -0
- data/scout_commands/rbbt +23 -0
- data/scout_commands/workflow/info +29 -0
- data/scout_commands/workflow/list +27 -0
- data/scout_commands/workflow/task +58 -0
- data/scout_commands/workflow/task_old +706 -0
- data/test/scout/indiferent_hash/test_options.rb +11 -1
- data/test/scout/misc/test_digest.rb +30 -0
- data/test/scout/misc/test_filesystem.rb +30 -0
- data/test/scout/misc/test_insist.rb +13 -0
- data/test/scout/open/test_lock.rb +52 -0
- data/test/scout/open/test_remote.rb +25 -0
- data/test/scout/open/test_stream.rb +515 -0
- data/test/scout/open/test_util.rb +73 -0
- data/test/scout/path/test_find.rb +28 -0
- data/test/scout/persist/test_open.rb +37 -0
- data/test/scout/persist/test_path.rb +37 -0
- data/test/scout/persist/test_serialize.rb +114 -0
- data/test/scout/resource/test_path.rb +40 -0
- data/test/scout/resource/test_produce.rb +62 -0
- data/test/scout/resource/test_util.rb +27 -0
- data/test/scout/simple_opt/test_doc.rb +16 -0
- data/test/scout/test_cmd.rb +85 -0
- data/test/scout/test_concurrent_stream.rb +29 -0
- data/test/scout/test_meta_extension.rb +9 -0
- data/test/scout/test_misc.rb +0 -7
- data/test/scout/test_open.rb +146 -0
- data/test/scout/test_path.rb +3 -1
- data/test/scout/test_persist.rb +83 -0
- data/test/scout/test_resource.rb +26 -0
- data/test/scout/test_workflow.rb +87 -0
- data/test/scout/workflow/step/test_info.rb +30 -0
- data/test/scout/workflow/step/test_load.rb +65 -0
- data/test/scout/workflow/task/test_inputs.rb +182 -0
- data/test/scout/workflow/test_definition.rb +0 -0
- data/test/scout/workflow/test_documentation.rb +30 -0
- data/test/scout/workflow/test_step.rb +36 -0
- data/test/scout/workflow/test_task.rb +179 -0
- data/test/scout/workflow/test_usage.rb +35 -0
- data/test/scout/workflow/test_util.rb +17 -0
- data/test/test_helper.rb +17 -0
- data/test/test_scout-gear.rb +0 -0
- metadata +75 -3
@@ -0,0 +1,373 @@
|
|
1
|
+
module Open
|
2
|
+
BLOCK_SIZE = 1024
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :sensible_write_lock_dir
|
6
|
+
|
7
|
+
def sensible_write_lock_dir
|
8
|
+
@sensible_write_lock_dir ||= Path.setup("tmp/sensible_write_locks").find
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :sensible_write_dir
|
14
|
+
def sensible_write_dir
|
15
|
+
@sensible_write_dir ||= Path.setup("tmp/sensible_write").find
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
|
20
|
+
return if Path === io
|
21
|
+
return unless io.respond_to? :read
|
22
|
+
|
23
|
+
if io.respond_to? :closed? and io.closed?
|
24
|
+
io.join if io.respond_to? :join
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
if in_thread
|
29
|
+
consumer_thread = Thread.new(Thread.current) do |parent|
|
30
|
+
Thread.current["name"] = "Consumer #{Log.fingerprint io}"
|
31
|
+
Thread.current.report_on_exception = false
|
32
|
+
consume_stream(io, false, into, into_close)
|
33
|
+
end
|
34
|
+
io.threads.push(consumer_thread) if io.respond_to?(:threads)
|
35
|
+
consumer_thread
|
36
|
+
else
|
37
|
+
if into
|
38
|
+
Log.medium "Consuming stream #{Log.fingerprint io} -> #{Log.fingerprint into}"
|
39
|
+
else
|
40
|
+
Log.medium "Consuming stream #{Log.fingerprint io}"
|
41
|
+
end
|
42
|
+
|
43
|
+
begin
|
44
|
+
into = into.find if Path === into
|
45
|
+
|
46
|
+
if String === into
|
47
|
+
dir = File.dirname(into)
|
48
|
+
Open.mkdir dir unless File.exist?(dir)
|
49
|
+
into_path, into = into, File.open(into, 'w')
|
50
|
+
end
|
51
|
+
|
52
|
+
into.sync = true if IO === into
|
53
|
+
into_close = false unless into.respond_to? :close
|
54
|
+
io.sync = true
|
55
|
+
|
56
|
+
Log.high "started consuming stream #{Log.fingerprint io}"
|
57
|
+
begin
|
58
|
+
while c = io.readpartial(BLOCK_SIZE)
|
59
|
+
into << c if into
|
60
|
+
end
|
61
|
+
rescue EOFError
|
62
|
+
end
|
63
|
+
|
64
|
+
io.join if io.respond_to? :join
|
65
|
+
io.close unless io.closed?
|
66
|
+
into.join if into and into_close and into.respond_to?(:joined?) and not into.joined?
|
67
|
+
into.close if into and into_close and not into.closed?
|
68
|
+
block.call if block_given?
|
69
|
+
|
70
|
+
Log.high "Done consuming stream #{Log.fingerprint io} into #{into_path || into}"
|
71
|
+
c
|
72
|
+
rescue Aborted
|
73
|
+
Log.high "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
|
74
|
+
io.abort $! if io.respond_to? :abort
|
75
|
+
into.close if into.respond_to?(:closed?) && ! into.closed?
|
76
|
+
FileUtils.rm into_path if into_path and File.exist?(into_path)
|
77
|
+
rescue Exception
|
78
|
+
Log.high "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
|
79
|
+
exception = io.stream_exception || $!
|
80
|
+
io.abort exception if io.respond_to? :abort
|
81
|
+
into.close if into.respond_to?(:closed?) && ! into.closed?
|
82
|
+
into_path = into if into_path.nil? && String === into
|
83
|
+
if into_path and File.exist?(into_path)
|
84
|
+
FileUtils.rm into_path
|
85
|
+
end
|
86
|
+
raise exception
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.sensible_write(path, content = nil, options = {}, &block)
|
92
|
+
force = IndiferentHash.process_options options, :force
|
93
|
+
|
94
|
+
if File.exist?(path) and not force
|
95
|
+
Open.consume_stream content
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
lock_options = IndiferentHash.pull_keys options.dup, :lock
|
100
|
+
lock_options = lock_options[:lock] if Hash === lock_options[:lock]
|
101
|
+
tmp_path = TmpFile.tmp_for_file(path, {:dir => Open.sensible_write_dir})
|
102
|
+
tmp_path_lock = TmpFile.tmp_for_file(path, {:dir => Open.sensible_write_lock_dir})
|
103
|
+
|
104
|
+
tmp_path_lock = nil if FalseClass === options[:lock]
|
105
|
+
|
106
|
+
Open.lock tmp_path_lock, lock_options do
|
107
|
+
|
108
|
+
if File.exist? path and not force
|
109
|
+
Log.warn "Path exists in sensible_write, not forcing update: #{ path }"
|
110
|
+
Open.consume_stream content
|
111
|
+
else
|
112
|
+
FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory? File.dirname(tmp_path)
|
113
|
+
FileUtils.rm_f tmp_path if File.exist? tmp_path
|
114
|
+
begin
|
115
|
+
|
116
|
+
case
|
117
|
+
when block_given?
|
118
|
+
File.open(tmp_path, 'wb', &block)
|
119
|
+
when String === content
|
120
|
+
File.open(tmp_path, 'wb') do |f| f.write content end
|
121
|
+
when (IO === content or StringIO === content or File === content)
|
122
|
+
Open.write(tmp_path) do |f|
|
123
|
+
f.sync = true
|
124
|
+
begin
|
125
|
+
while block = content.readpartial(BLOCK_SIZE)
|
126
|
+
f.write block
|
127
|
+
end
|
128
|
+
rescue EOFError
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
File.open(tmp_path, 'wb') do |f| end
|
133
|
+
end
|
134
|
+
|
135
|
+
begin
|
136
|
+
Misc.insist do
|
137
|
+
Open.mv tmp_path, path, lock_options
|
138
|
+
end
|
139
|
+
rescue Exception
|
140
|
+
raise $! unless File.exist? path
|
141
|
+
end
|
142
|
+
|
143
|
+
Open.touch path if File.exist? path
|
144
|
+
content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
|
145
|
+
|
146
|
+
Open.notify_write(path)
|
147
|
+
rescue Aborted
|
148
|
+
Log.medium "Aborted sensible_write -- #{ Log.reset << Log.color(:blue, path) }"
|
149
|
+
content.abort if content.respond_to? :abort
|
150
|
+
Open.rm path if File.exist? path
|
151
|
+
rescue Exception
|
152
|
+
exception = (AbortedStream === content and content.exception) ? content.exception : $!
|
153
|
+
Log.medium "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
|
154
|
+
content.abort if content.respond_to? :abort
|
155
|
+
Open.rm path if File.exist? path
|
156
|
+
raise exception
|
157
|
+
rescue
|
158
|
+
raise $!
|
159
|
+
ensure
|
160
|
+
FileUtils.rm_f tmp_path if File.exist? tmp_path
|
161
|
+
if Lockfile === lock_options[:lock] and lock_options[:lock].locked?
|
162
|
+
lock_options[:lock].unlock
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
PIPE_MUTEX = Mutex.new
|
170
|
+
|
171
|
+
OPEN_PIPE_IN = []
|
172
|
+
def self.pipe
|
173
|
+
OPEN_PIPE_IN.delete_if{|pipe| pipe.closed? }
|
174
|
+
res = PIPE_MUTEX.synchronize do
|
175
|
+
sout, sin = IO.pipe
|
176
|
+
OPEN_PIPE_IN << sin
|
177
|
+
|
178
|
+
[sout, sin]
|
179
|
+
end
|
180
|
+
Log.debug{"Creating pipe #{[Log.fingerprint(res.last), Log.fingerprint(res.first)] * " => "}"}
|
181
|
+
res
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.with_fifo(path = nil, clean = true, &block)
|
185
|
+
begin
|
186
|
+
erase = path.nil?
|
187
|
+
path = TmpFile.tmp_file if path.nil?
|
188
|
+
File.rm path if clean && File.exist?(path)
|
189
|
+
File.mkfifo path
|
190
|
+
yield path
|
191
|
+
ensure
|
192
|
+
FileUtils.rm path if erase && File.exist?(path)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.release_pipes(*pipes)
|
197
|
+
PIPE_MUTEX.synchronize do
|
198
|
+
pipes.flatten.each do |pipe|
|
199
|
+
pipe.close unless pipe.closed?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.purge_pipes(*save)
|
205
|
+
PIPE_MUTEX.synchronize do
|
206
|
+
OPEN_PIPE_IN.each do |pipe|
|
207
|
+
next if save.include? pipe
|
208
|
+
pipe.close unless pipe.closed?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.open_pipe(do_fork = false, close = true)
|
214
|
+
raise "No block given" unless block_given?
|
215
|
+
|
216
|
+
sout, sin = Open.pipe
|
217
|
+
|
218
|
+
if do_fork
|
219
|
+
|
220
|
+
#parent_pid = Process.pid
|
221
|
+
pid = Process.fork {
|
222
|
+
purge_pipes(sin)
|
223
|
+
sout.close
|
224
|
+
begin
|
225
|
+
|
226
|
+
yield sin
|
227
|
+
sin.close if close and not sin.closed?
|
228
|
+
|
229
|
+
rescue Exception
|
230
|
+
Log.exception $!
|
231
|
+
#Process.kill :INT, parent_pid
|
232
|
+
Kernel.exit!(-1)
|
233
|
+
end
|
234
|
+
Kernel.exit! 0
|
235
|
+
}
|
236
|
+
sin.close
|
237
|
+
|
238
|
+
ConcurrentStream.setup sout, :pids => [pid]
|
239
|
+
else
|
240
|
+
|
241
|
+
ConcurrentStream.setup sin, :pair => sout
|
242
|
+
ConcurrentStream.setup sout, :pair => sin
|
243
|
+
|
244
|
+
thread = Thread.new do
|
245
|
+
Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
|
246
|
+
Thread.current.report_on_exception = false
|
247
|
+
begin
|
248
|
+
|
249
|
+
yield sin
|
250
|
+
|
251
|
+
sin.close if close and not sin.closed? and not sin.aborted?
|
252
|
+
rescue Aborted
|
253
|
+
Log.medium "Aborted open_pipe: #{$!.message}"
|
254
|
+
raise $!
|
255
|
+
rescue Exception
|
256
|
+
Log.medium "Exception in open_pipe: #{$!.message}"
|
257
|
+
begin
|
258
|
+
sout.threads.delete(Thread.current)
|
259
|
+
sout.pair = []
|
260
|
+
sout.abort($!) if sout.respond_to?(:abort)
|
261
|
+
sin.threads.delete(Thread.current)
|
262
|
+
sin.pair = []
|
263
|
+
sin.abort($!) if sin.respond_to?(:abort)
|
264
|
+
ensure
|
265
|
+
raise $!
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
sin.threads = [thread]
|
271
|
+
sout.threads = [thread]
|
272
|
+
end
|
273
|
+
|
274
|
+
sout
|
275
|
+
end
|
276
|
+
|
277
|
+
def self.tee_stream_thread_multiple(stream, num = 2)
|
278
|
+
in_pipes = []
|
279
|
+
out_pipes = []
|
280
|
+
num.times do
|
281
|
+
sout, sin = Open.pipe
|
282
|
+
in_pipes << sin
|
283
|
+
out_pipes << sout
|
284
|
+
end
|
285
|
+
|
286
|
+
filename = stream.filename if stream.respond_to? :filename
|
287
|
+
|
288
|
+
splitter_thread = Thread.new(Thread.current) do |parent|
|
289
|
+
begin
|
290
|
+
Thread.current["name"] = "Splitter #{Log.fingerprint stream}"
|
291
|
+
Thread.current.report_on_exception = false
|
292
|
+
|
293
|
+
skip = [false] * num
|
294
|
+
begin
|
295
|
+
while block = stream.readpartial(BLOCK_SIZE)
|
296
|
+
|
297
|
+
in_pipes.each_with_index do |sin,i|
|
298
|
+
begin
|
299
|
+
sin.write block
|
300
|
+
rescue IOError
|
301
|
+
Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
|
302
|
+
skip[i] = true
|
303
|
+
rescue
|
304
|
+
Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
|
305
|
+
raise $!
|
306
|
+
end unless skip[i]
|
307
|
+
end
|
308
|
+
end
|
309
|
+
rescue IOError
|
310
|
+
end
|
311
|
+
|
312
|
+
stream.join if stream.respond_to? :join
|
313
|
+
stream.close unless stream.closed?
|
314
|
+
in_pipes.first.close unless in_pipes.first.closed?
|
315
|
+
rescue Aborted, Interrupt
|
316
|
+
stream.abort if stream.respond_to? :abort
|
317
|
+
out_pipes.each do |sout|
|
318
|
+
sout.abort if sout.respond_to? :abort
|
319
|
+
end
|
320
|
+
Log.medium "Tee aborting #{Log.fingerprint stream}"
|
321
|
+
raise $!
|
322
|
+
rescue Exception
|
323
|
+
begin
|
324
|
+
stream.abort($!) if stream.respond_to?(:abort) && ! stream.aborted?
|
325
|
+
out_pipes.reverse.each do |sout|
|
326
|
+
sout.threads.delete(Thread.current)
|
327
|
+
begin
|
328
|
+
sout.abort($!) if sout.respond_to?(:abort) && ! sout.aborted?
|
329
|
+
rescue
|
330
|
+
end
|
331
|
+
end
|
332
|
+
in_pipes.each do |sin|
|
333
|
+
sin.close unless sin.closed?
|
334
|
+
end
|
335
|
+
Log.medium "Tee exception #{Log.fingerprint stream}"
|
336
|
+
rescue
|
337
|
+
Log.exception $!
|
338
|
+
ensure
|
339
|
+
in_pipes.each do |sin|
|
340
|
+
sin.close unless sin.closed?
|
341
|
+
end
|
342
|
+
raise $!
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
out_pipes.each do |sout|
|
349
|
+
ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :pair => stream
|
350
|
+
end
|
351
|
+
splitter_thread.wakeup until splitter_thread["name"]
|
352
|
+
|
353
|
+
main_pipe = out_pipes.first
|
354
|
+
main_pipe.autojoin = true
|
355
|
+
|
356
|
+
main_pipe.callback = Proc.new do
|
357
|
+
stream.join if stream.respond_to? :join
|
358
|
+
in_pipes[1..-1].each do |sin|
|
359
|
+
sin.close unless sin.closed?
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
out_pipes
|
364
|
+
end
|
365
|
+
|
366
|
+
def self.tee_stream_thread(stream)
|
367
|
+
tee_stream_thread_multiple(stream, 2)
|
368
|
+
end
|
369
|
+
|
370
|
+
def self.tee_stream(stream)
|
371
|
+
tee_stream_thread(stream)
|
372
|
+
end
|
373
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module Open
|
2
|
+
GREP_CMD = begin
|
3
|
+
if ENV["GREP_CMD"]
|
4
|
+
ENV["GREP_CMD"]
|
5
|
+
elsif File.exist?('/bin/grep')
|
6
|
+
"/bin/grep"
|
7
|
+
elsif File.exist?('/usr/bin/grep')
|
8
|
+
"/usr/bin/grep"
|
9
|
+
else
|
10
|
+
"grep"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.grep(stream, grep, invert = false, fixed = nil)
|
15
|
+
case
|
16
|
+
when Array === grep
|
17
|
+
TmpFile.with_file(grep * "\n", false) do |f|
|
18
|
+
if FalseClass === fixed
|
19
|
+
CMD.cmd("#{GREP_CMD} #{invert ? '-v' : ''} -", "-f" => f, :in => stream, :pipe => true, :post => proc{FileUtils.rm f})
|
20
|
+
else
|
21
|
+
CMD.cmd("#{GREP_CMD} #{invert ? '-v' : ''} -", "-w" => true, "-F" => true, "-f" => f, :in => stream, :pipe => true, :post => proc{FileUtils.rm f})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
else
|
25
|
+
CMD.cmd("#{GREP_CMD} #{invert ? '-v ' : ''} '#{grep}' -", :in => stream, :pipe => true, :post => proc{begin stream.force_close; rescue Exception; end if stream.respond_to?(:force_close)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.gzip_pipe(file)
|
30
|
+
Open.gzip?(file) ? "<(gunzip -c '#{file}')" : "'#{file}'"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.bgunzip(stream)
|
34
|
+
Bgzf.setup stream
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.gunzip(stream)
|
38
|
+
CMD.cmd('zcat', :in => stream, :pipe => true, :no_fail => true, :no_wait => true)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.gzip(stream)
|
42
|
+
CMD.cmd('gzip', :in => stream, :pipe => true, :no_fail => true, :no_wait => true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.bgzip(stream)
|
46
|
+
CMD.cmd('bgzip', :in => stream, :pipe => true, :no_fail => true, :no_wait => true)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.unzip(stream)
|
50
|
+
TmpFile.with_file(stream.read) do |filename|
|
51
|
+
StringIO.new(CMD.cmd("unzip '{opt}' #{filename}", "-p" => true, :pipe => true).read)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Questions
|
56
|
+
def self.gzip?(file)
|
57
|
+
file = file.find if Path === file
|
58
|
+
!! (file =~ /\.gz$/)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.bgzip?(file)
|
62
|
+
file = file.find if Path === file
|
63
|
+
!! (file =~ /\.bgz$/)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.zip?(file)
|
67
|
+
file = file.find if Path === file
|
68
|
+
!! (file =~ /\.zip$/)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.notify_write(file)
|
72
|
+
begin
|
73
|
+
notification_file = file + '.notify'
|
74
|
+
if Open.exists? notification_file
|
75
|
+
key = Open.read(notification_file).strip
|
76
|
+
key = nil if key.empty?
|
77
|
+
if key && key.include?("@")
|
78
|
+
to = from = key
|
79
|
+
subject = "Wrote " << file
|
80
|
+
message = "Content attached"
|
81
|
+
Misc.send_email(from, to, subject, message, :files => [file])
|
82
|
+
else
|
83
|
+
Misc.notify("Wrote " << file, nil, key)
|
84
|
+
end
|
85
|
+
Open.rm notification_file
|
86
|
+
end
|
87
|
+
rescue
|
88
|
+
Log.exception $!
|
89
|
+
Log.warn "Error notifying write of #{ file }"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.broken_link?(path)
|
94
|
+
File.symlink?(path) && ! File.exist?(File.readlink(path))
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.exists?(file)
|
98
|
+
file = file.find if Path === file
|
99
|
+
File.exist?(file)
|
100
|
+
end
|
101
|
+
class << self; alias exist? exists? end
|
102
|
+
|
103
|
+
def self.mv(source, target, options = {})
|
104
|
+
target = target.find if Path === target
|
105
|
+
source = source.find if Path === source
|
106
|
+
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
107
|
+
tmp_target = File.join(File.dirname(target), '.tmp_mv.' + File.basename(target))
|
108
|
+
FileUtils.mv source, tmp_target
|
109
|
+
FileUtils.mv tmp_target, target
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.rm(file)
|
114
|
+
FileUtils.rm(file) if File.exist?(file) or Open.broken_link?(file)
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.rm_rf(file)
|
118
|
+
FileUtils.rm_rf(file)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.touch(file)
|
122
|
+
FileUtils.touch(file)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.mkdir(target)
|
126
|
+
target = target.find if Path === target
|
127
|
+
if ! File.exist?(target)
|
128
|
+
FileUtils.mkdir_p target
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.writable?(path)
|
133
|
+
path = path.find if Path === path
|
134
|
+
if File.symlink?(path)
|
135
|
+
File.writable?(File.dirname(path))
|
136
|
+
elsif File.exist?(path)
|
137
|
+
File.writable?(path)
|
138
|
+
else
|
139
|
+
File.writable?(File.dirname(File.expand_path(path)))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.ctime(file)
|
144
|
+
file = file.find if Path === file
|
145
|
+
File.ctime(file)
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.realpath(file)
|
149
|
+
file = file.find if Path === file
|
150
|
+
Pathname.new(File.expand_path(file)).realpath.to_s
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.mtime(file)
|
154
|
+
file = file.find if Path === file
|
155
|
+
begin
|
156
|
+
if File.symlink?(file) || File.stat(file).nlink > 1
|
157
|
+
if File.exist?(file + '.info') && defined?(Step)
|
158
|
+
done = Step::INFO_SERIALIZER.load(Open.open(file + '.info'))[:done]
|
159
|
+
return done if done
|
160
|
+
end
|
161
|
+
|
162
|
+
file = Pathname.new(file).realpath.to_s
|
163
|
+
end
|
164
|
+
return nil unless File.exist?(file)
|
165
|
+
File.mtime(file)
|
166
|
+
rescue
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.cp(source, target, options = {})
|
172
|
+
source = source.find if Path === source
|
173
|
+
target = target.find if Path === target
|
174
|
+
|
175
|
+
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
176
|
+
FileUtils.rm target if File.exist?(target)
|
177
|
+
FileUtils.cp_r source, target
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
def self.ln_s(source, target, options = {})
|
182
|
+
source = source.find if Path === source
|
183
|
+
target = target.find if Path === target
|
184
|
+
|
185
|
+
target = File.join(target, File.basename(source)) if File.directory? target
|
186
|
+
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
187
|
+
FileUtils.rm target if File.exist?(target)
|
188
|
+
FileUtils.rm target if File.symlink?(target)
|
189
|
+
FileUtils.ln_s source, target
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.ln(source, target, options = {})
|
193
|
+
source = source.find if Path === source
|
194
|
+
target = target.find if Path === target
|
195
|
+
source = File.realpath(source) if File.symlink?(source)
|
196
|
+
|
197
|
+
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
198
|
+
FileUtils.rm target if File.exist?(target)
|
199
|
+
FileUtils.rm target if File.symlink?(target)
|
200
|
+
FileUtils.ln source, target
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.ln_h(source, target, options = {})
|
204
|
+
source = source.find if Path === source
|
205
|
+
target = target.find if Path === target
|
206
|
+
|
207
|
+
FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
|
208
|
+
FileUtils.rm target if File.exist?(target)
|
209
|
+
begin
|
210
|
+
CMD.cmd("ln -L '#{ source }' '#{ target }'")
|
211
|
+
rescue ProcessFailed
|
212
|
+
Log.debug "Could not hard link #{source} and #{target}: #{$!.message.gsub("\n", '. ')}"
|
213
|
+
CMD.cmd("cp -L '#{ source }' '#{ target }'")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.link(source, target, options = {})
|
218
|
+
begin
|
219
|
+
Open.ln(source, target, options)
|
220
|
+
rescue
|
221
|
+
Open.ln_s(source, target, options)
|
222
|
+
end
|
223
|
+
nil
|
224
|
+
end
|
225
|
+
end
|