scout-gear 6.0.0 → 7.1.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 6.0.0
1
+ 7.1.0
@@ -84,6 +84,14 @@ class DoneProcessing < Exception
84
84
  end
85
85
  end
86
86
 
87
+ class WorkerException < ScoutException
88
+ attr_accessor :exception, :pid
89
+ def initialize(exception, pid)
90
+ @exception = exception
91
+ @pid = pid
92
+ end
93
+ end
94
+
87
95
 
88
96
  #class OpenGzipError < StandardError; end
89
97
  #
@@ -143,13 +143,14 @@ module Log
143
143
  CONCEPT_COLORS = IndiferentHash.setup({
144
144
  :title => magenta,
145
145
  :path => blue,
146
- :input => blue,
146
+ :input => cyan,
147
147
  :value => green,
148
148
  :integer => green,
149
149
  :negative => red,
150
150
  :float => green,
151
151
  :waiting => yellow,
152
- :started => blue,
152
+ :started => cyan,
153
+ :start => cyan,
153
154
  :done => green,
154
155
  :error => red,
155
156
  })
@@ -166,10 +167,36 @@ module Log
166
167
  def self.color(color, str = nil, reset = false)
167
168
  return str.dup || "" if nocolor
168
169
 
170
+ if (color == :integer || color == :float) && Numeric === str
171
+ color = if str < 0
172
+ :red
173
+ elsif str > 1
174
+ :cyan
175
+ else
176
+ :green
177
+ end
178
+ end
179
+
180
+ if color == :status
181
+ color = case str.to_sym
182
+ when :done
183
+ :green
184
+ when :error, :aborted
185
+ :red
186
+ when :waiting, :queued
187
+ :yellow
188
+ when :started, :start, :streamming
189
+ :cyan
190
+ else
191
+ :cyan
192
+ end
193
+ end
194
+
169
195
  color = SEVERITY_COLOR[color] if Integer === color
170
196
  color = CONCEPT_COLORS[color] if CONCEPT_COLORS.include?(color)
171
197
  color = Term::ANSIColor.send(color) if Symbol === color and Term::ANSIColor.respond_to?(color)
172
198
 
199
+ str = str.to_s unless str.nil?
173
200
  return str if Symbol === color
174
201
  color_str = reset ? Term::ANSIColor.reset : ""
175
202
  color_str << color
@@ -28,6 +28,8 @@ module Log
28
28
  end
29
29
 
30
30
  def self.new_bar(max, options = {})
31
+ options, max = max, nil if Hash === max
32
+ max = options[:max] if max.nil?
31
33
  cleanup_bars
32
34
  BAR_MUTEX.synchronize do
33
35
  Log::LAST.replace "new_bar" if Log::LAST == "progress"
@@ -24,6 +24,8 @@ module Log
24
24
  IndiferentHash.process_options options, :depth, :desc, :file, :bytes, :frequency, :process, :callback,
25
25
  :depth => 0, :frequency => 2
26
26
 
27
+ max = nil if TrueClass === max
28
+
27
29
  @max = max
28
30
  @ticks = 0
29
31
  @frequency = frequency
data/lib/scout/log.rb CHANGED
@@ -206,7 +206,11 @@ module Log
206
206
  line = line.sub('`',"'")
207
207
  color = :green if line =~ /workflow/
208
208
  color = :blue if line =~ /scout-/
209
- Log.color color, line
209
+ if color
210
+ Log.color color, line
211
+ else
212
+ line
213
+ end
210
214
  end unless stack.nil?
211
215
  end
212
216
 
@@ -41,9 +41,7 @@ module Misc
41
41
 
42
42
  def self.digest(obj)
43
43
  str = Misc.digest_str(obj)
44
- hash = Digest::MD5.hexdigest(str)
45
- Log.debug "Digest #{hash} - #{str}"
46
- hash
44
+ Digest::MD5.hexdigest(str)
47
45
  end
48
46
 
49
47
  def self.file_md5(file)
@@ -31,13 +31,16 @@ module Open
31
31
  Thread.current.report_on_exception = false
32
32
  consume_stream(io, false, into, into_close)
33
33
  end
34
+
34
35
  io.threads.push(consumer_thread) if io.respond_to?(:threads)
36
+ Thread.pass until consumer_thread["name"]
37
+
35
38
  consumer_thread
36
39
  else
37
40
  if into
38
- Log.medium "Consuming stream #{Log.fingerprint io} -> #{Log.fingerprint into}"
41
+ Log.low "Consuming stream #{Log.fingerprint io} -> #{Log.fingerprint into}"
39
42
  else
40
- Log.medium "Consuming stream #{Log.fingerprint io}"
43
+ Log.low "Consuming stream #{Log.fingerprint io}"
41
44
  end
42
45
 
43
46
  begin
@@ -53,7 +56,6 @@ module Open
53
56
  into_close = false unless into.respond_to? :close
54
57
  io.sync = true
55
58
 
56
- Log.high "started consuming stream #{Log.fingerprint io}"
57
59
  begin
58
60
  while c = io.readpartial(BLOCK_SIZE)
59
61
  into << c if into
@@ -67,15 +69,14 @@ module Open
67
69
  into.close if into and into_close and not into.closed?
68
70
  block.call if block_given?
69
71
 
70
- Log.high "Done consuming stream #{Log.fingerprint io} into #{into_path || into}"
71
72
  c
72
73
  rescue Aborted
73
- Log.high "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
74
+ Log.low "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
74
75
  io.abort $! if io.respond_to? :abort
75
76
  into.close if into.respond_to?(:closed?) && ! into.closed?
76
77
  FileUtils.rm into_path if into_path and File.exist?(into_path)
77
78
  rescue Exception
78
- Log.high "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
79
+ Log.low "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
79
80
  exception = io.stream_exception || $!
80
81
  io.abort exception if io.respond_to? :abort
81
82
  into.close if into.respond_to?(:closed?) && ! into.closed?
@@ -145,12 +146,12 @@ module Open
145
146
 
146
147
  Open.notify_write(path)
147
148
  rescue Aborted
148
- Log.medium "Aborted sensible_write -- #{ Log.reset << Log.color(:blue, path) }"
149
+ Log.low "Aborted sensible_write -- #{ Log.reset << Log.color(:blue, path) }"
149
150
  content.abort if content.respond_to? :abort
150
151
  Open.rm path if File.exist? path
151
152
  rescue Exception
152
153
  exception = (AbortedStream === content and content.exception) ? content.exception : $!
153
- Log.medium "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
154
+ Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
154
155
  content.abort if content.respond_to? :abort
155
156
  Open.rm path if File.exist? path
156
157
  raise exception
@@ -219,16 +220,15 @@ module Open
219
220
 
220
221
  #parent_pid = Process.pid
221
222
  pid = Process.fork {
222
- purge_pipes(sin)
223
- sout.close
224
223
  begin
224
+ purge_pipes(sin)
225
+ sout.close
225
226
 
226
227
  yield sin
227
228
  sin.close if close and not sin.closed?
228
229
 
229
230
  rescue Exception
230
231
  Log.exception $!
231
- #Process.kill :INT, parent_pid
232
232
  Kernel.exit!(-1)
233
233
  end
234
234
  Kernel.exit! 0
@@ -242,18 +242,18 @@ module Open
242
242
  ConcurrentStream.setup sout, :pair => sin
243
243
 
244
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
245
  begin
246
+ Thread.current.report_on_exception = false
247
+ Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
248
248
 
249
249
  yield sin
250
250
 
251
251
  sin.close if close and not sin.closed? and not sin.aborted?
252
252
  rescue Aborted
253
- Log.medium "Aborted open_pipe: #{$!.message}"
253
+ Log.low "Aborted open_pipe: #{$!.message}"
254
254
  raise $!
255
255
  rescue Exception
256
- Log.medium "Exception in open_pipe: #{$!.message}"
256
+ Log.low "Exception in open_pipe: #{$!.message}"
257
257
  begin
258
258
  sout.threads.delete(Thread.current)
259
259
  sout.pair = []
@@ -269,6 +269,7 @@ module Open
269
269
 
270
270
  sin.threads = [thread]
271
271
  sout.threads = [thread]
272
+ Thread.pass until thread["name"]
272
273
  end
273
274
 
274
275
  sout
@@ -287,8 +288,8 @@ module Open
287
288
 
288
289
  splitter_thread = Thread.new(Thread.current) do |parent|
289
290
  begin
290
- Thread.current["name"] = "Splitter #{Log.fingerprint stream}"
291
291
  Thread.current.report_on_exception = false
292
+ Thread.current["name"] = "Splitter #{Log.fingerprint stream}"
292
293
 
293
294
  skip = [false] * num
294
295
  begin
@@ -317,7 +318,7 @@ module Open
317
318
  out_pipes.each do |sout|
318
319
  sout.abort if sout.respond_to? :abort
319
320
  end
320
- Log.medium "Tee aborting #{Log.fingerprint stream}"
321
+ Log.low "Tee aborting #{Log.fingerprint stream}"
321
322
  raise $!
322
323
  rescue Exception
323
324
  begin
@@ -332,7 +333,7 @@ module Open
332
333
  in_pipes.each do |sin|
333
334
  sin.close unless sin.closed?
334
335
  end
335
- Log.medium "Tee exception #{Log.fingerprint stream}"
336
+ Log.low "Tee exception #{Log.fingerprint stream}"
336
337
  rescue
337
338
  Log.exception $!
338
339
  ensure
@@ -348,7 +349,7 @@ module Open
348
349
  out_pipes.each do |sout|
349
350
  ConcurrentStream.setup sout, :threads => splitter_thread, :filename => filename, :pair => stream
350
351
  end
351
- splitter_thread.wakeup until splitter_thread["name"]
352
+ Thread.pass until splitter_thread["name"]
352
353
 
353
354
  main_pipe = out_pipes.first
354
355
  main_pipe.autojoin = true
@@ -0,0 +1,144 @@
1
+ module TSV
2
+ def self.cast_value(value, cast)
3
+ if Array === value
4
+ value.collect{|e| cast_value(e, cast) }
5
+ else
6
+ value.send(cast)
7
+ end
8
+ end
9
+
10
+ def self.parse_line(line, type: :list, key: 0, positions: nil, sep: "\t", sep2: "|", cast: nil)
11
+ items = line.split(sep, -1)
12
+
13
+ if positions.nil? && key == 0
14
+ key = items.shift
15
+ elsif positions.nil?
16
+ key = items.delete(key)
17
+ else
18
+ key, items = items[key], items.values_at(*positions)
19
+ end
20
+
21
+ items = case type
22
+ when :list
23
+ items
24
+ when :single
25
+ items.first
26
+ when :flat
27
+ [items]
28
+ when :double
29
+ items.collect{|i| i.split(sep2, -1) }
30
+ end
31
+
32
+ key = key.partition(sep2).first if type == :double
33
+
34
+ if cast
35
+ items = cast_value(items, cast)
36
+ end
37
+
38
+ [key, items]
39
+ end
40
+
41
+ def self.parse_stream(stream, data: nil, merge: true, type: :list, fix: true, bar: false, first_line: nil, **kargs, &block)
42
+ begin
43
+ bar = Log::ProgressBar.new_bar(bar) if bar
44
+
45
+ data = {} if data.nil?
46
+ merge = false if type != :double
47
+ line = first_line || stream.gets
48
+ while line
49
+ begin
50
+ line.strip!
51
+ line = Misc.fixutf8(line) if fix
52
+ bar.tick if bar
53
+ key, items = parse_line(line, type: type, **kargs)
54
+
55
+ if block_given?
56
+ res = block.call(key, items)
57
+ data[key] = res unless res.nil?
58
+ next
59
+ end
60
+
61
+ if ! merge || ! data.include?(key)
62
+ data[key] = items
63
+ else
64
+ current = data[key]
65
+ if merge == :concat
66
+ items.each_with_index do |new,i|
67
+ next if new.empty?
68
+ current[i].concat(new)
69
+ end
70
+ else
71
+ merged = []
72
+ items.each_with_index do |new,i|
73
+ next if new.empty?
74
+ merged[i] = current[i] + new
75
+ end
76
+ data[key] = merged
77
+ end
78
+ end
79
+ ensure
80
+ line = stream.gets
81
+ end
82
+ end
83
+ data
84
+ ensure
85
+ Log::ProgressBar.remove_bar(bar) if bar
86
+ end
87
+ end
88
+
89
+ def self.parse_header(stream, fix: true, header_hash: '#', sep: "\n")
90
+ raise "Closed stream" if IO === stream && stream.closed?
91
+
92
+ options = {}
93
+ preamble = []
94
+
95
+ # Get line
96
+
97
+ #Thread.pass while IO.select([stream], nil, nil, 1).nil? if IO === stream
98
+ line = stream.gets
99
+ return {} if line.nil?
100
+ line = Misc.fixutf8 line.chomp if fix
101
+
102
+ # Process options line
103
+ if line and (String === header_hash && m = line.match(/^#{header_hash}: (.*)/))
104
+ options = IndiferentHash.string2hash m.captures.first.chomp
105
+ line = stream.gets
106
+ line = Misc.fixutf8 line.chomp if line && fix
107
+ end
108
+
109
+ # Determine separator
110
+ sep = options[:sep] if options[:sep]
111
+
112
+ # Process fields line
113
+ preamble << line if line
114
+ while line && (TrueClass === header_hash || (String === header_hash && line.start_with?(header_hash)))
115
+ fields = line.split(sep, -1)
116
+ key_field = fields.shift
117
+ key_field = key_field.sub(header_hash, '') if String === header_hash && ! header_hash.empty?
118
+
119
+ line = (header_hash != "" ? stream.gets : nil)
120
+ line = Misc.fixutf8 line.chomp if line
121
+ preamble << line if line
122
+ break if TrueClass === header_hash || header_hash == ""
123
+ end
124
+
125
+ preamble = preamble[0..-3] * "\n"
126
+
127
+ line ||= stream.gets
128
+
129
+ first_line = line
130
+
131
+ [options, key_field, fields, first_line, preamble]
132
+ end
133
+
134
+ def self.parse(stream, **kwargs)
135
+ options, key_field, fields, first_line, preamble = parse_header(stream)
136
+
137
+ options.each do |option,value|
138
+ option = option.to_sym
139
+ kwargs[option] = value unless kwargs.include?(option)
140
+ end
141
+ data = parse_stream(stream, first_line: first_line, **kwargs)
142
+ TSV.setup data, :key_field => key_field, :fields => fields
143
+ end
144
+ end
data/lib/scout/tsv.rb ADDED
@@ -0,0 +1,14 @@
1
+ require_relative 'meta_extension'
2
+ require_relative 'tsv/parser'
3
+
4
+ module TSV
5
+ extend MetaExtension
6
+ extension_attr :key_field, :fields
7
+
8
+ def self.open(file, options = {})
9
+ Open.open(file) do |f|
10
+ TSV.parse(f,**options)
11
+ end
12
+ end
13
+ end
14
+
@@ -1,16 +1,18 @@
1
1
  class WorkQueue
2
2
  class Worker
3
3
  attr_accessor :pid, :ignore_ouput
4
- def initialize
4
+ def initialize(ignore_ouput = false)
5
+ @ignore_output = ignore_ouput
5
6
  end
6
7
 
7
8
  def run
8
9
  @pid = Process.fork do
10
+ Log.debug "Worker start with #{Process.pid}"
9
11
  yield
10
12
  end
11
13
  end
12
14
 
13
- def process(input, output, &block)
15
+ def process(input, output = nil, &block)
14
16
  run do
15
17
  begin
16
18
  while obj = input.read
@@ -19,33 +21,36 @@ class WorkQueue
19
21
  raise obj
20
22
  end
21
23
  res = block.call obj
22
- output.write res unless ignore_ouput || res == :ignore
24
+ output.write res unless output.nil? || ignore_ouput || res == :ignore
23
25
  end
24
26
  rescue DoneProcessing
25
- Log.log "Worker #{Process.pid} done"
27
+ rescue Interrupt
26
28
  rescue Exception
27
- Log.exception $!
29
+ output.write WorkerException.new($!, Process.pid)
28
30
  exit -1
29
31
  end
30
32
  end
31
33
  end
32
34
 
35
+ def abort
36
+ begin
37
+ Log.log "Aborting worker #{@pid}"
38
+ Process.kill "INT", @pid
39
+ rescue Errno::ECHILD
40
+ end
41
+ end
42
+
33
43
  def join
34
44
  Log.log "Joining worker #{@pid}"
35
45
  Process.waitpid @pid
36
46
  end
37
47
 
38
- def exit(status)
39
- Log.log "Worker #{@pid} exited with status #{Log.color(:green, status)}"
40
- end
41
-
42
48
  def self.join(workers)
43
49
  workers = [workers] unless Array === workers
44
50
  begin
45
51
  while pid = Process.wait
46
52
  status = $?
47
- worker = workers.select{|w| w.pid == pid }.first
48
- worker.exit status.exitstatus if worker
53
+ worker = workers.select{|w| w.pid == pid }.first
49
54
  end
50
55
  rescue Errno::ECHILD
51
56
  end
@@ -35,52 +35,79 @@ class WorkQueue
35
35
  end
36
36
 
37
37
  def remove_worker(pid)
38
- worker = @worker_mutex.synchronize do
39
- Log.debug "Remove #{pid}"
40
- @removed_workers.concat(@workers.delete_if{|w| w.pid == pid })
38
+ @worker_mutex.synchronize do
39
+ @workers.delete_if{|w| w.pid == pid }
40
+ @removed_workers << pid
41
41
  end
42
42
  end
43
43
 
44
44
  def process(&callback)
45
- @workers.each do |w|
46
- w.process @input, @output, &@worker_proc
47
- end
48
- @reader = Thread.new do
45
+ @reader = Thread.new do |parent|
49
46
  begin
47
+ Thread.current.report_on_exception = false
48
+ Thread.current["name"] = "Output reader #{Process.pid}"
49
+ @done_workers ||= []
50
50
  while true
51
51
  obj = @output.read
52
52
  if DoneProcessing === obj
53
- remove_worker obj.pid if obj.pid
53
+ done = @worker_mutex.synchronize do
54
+ Log.low "Worker #{obj.pid} done"
55
+ @done_workers << obj.pid
56
+ @done_workers.length == @removed_workers.length + @workers.length
57
+ end
58
+ break if done
59
+ elsif Exception === obj
60
+ raise obj
54
61
  else
55
62
  callback.call obj if callback
56
63
  end
57
64
  end
65
+ rescue DoneProcessing
58
66
  rescue Aborted
67
+ rescue WorkerException
68
+ Log.error "Exception in worker #{obj.pid} #{Log.fingerprint obj.exception}"
69
+ self.abort
70
+ raise obj.exception
59
71
  end
60
- end if @output
72
+ end
73
+
74
+ @workers.each do |w|
75
+ w.process @input, @output, &@worker_proc
76
+ end
77
+
78
+ Thread.pass until @reader["name"]
79
+
80
+ @waiter = Thread.new do
81
+ begin
82
+ Thread.current.report_on_exception = false
83
+ Thread.current["name"] = "Worker waiter #{Process.pid}"
84
+ while true
85
+ pid = Process.wait
86
+ remove_worker(pid)
87
+ break if workers.empty?
88
+ end
89
+ end
90
+ end
91
+
92
+ Thread.pass until @waiter["name"]
61
93
  end
62
94
 
63
95
  def write(obj)
64
96
  @input.write obj
65
97
  end
66
98
 
99
+ def abort
100
+ workers.each{|w| w.abort }
101
+ end
102
+
67
103
  def close
68
- while @worker_mutex.synchronize{ @workers.length } > 0
69
- begin
70
- @input.write DoneProcessing.new
71
- pid = Process.wait
72
- status = $?
73
- worker = @worker_mutex.synchronize{ @removed_workers.delete_if{|w| w.pid == pid }.first }
74
- worker.exit $?.exitstatus if worker
75
- rescue Errno::ECHILD
76
- Thread.pass until @workers.length == 0
77
- break
78
- end
104
+ @worker_mutex.synchronize{ @workers.length }.times do
105
+ @input.write DoneProcessing.new()
79
106
  end
80
- @reader.raise Aborted if @reader
81
107
  end
82
108
 
83
109
  def join
110
+ @waiter.join if @waiter
84
111
  @reader.join if @reader
85
112
  end
86
113
  end
@@ -55,9 +55,9 @@ class Step
55
55
 
56
56
  def report_status(status, message = nil)
57
57
  if message.nil?
58
- Log.info Log.color(status, status.to_s) + " " + Log.color(:path, path)
58
+ Log.info Log.color(:status, status, true) + " " + Log.color(:path, path)
59
59
  else
60
- Log.info Log.color(status, status.to_s) + " " + Log.color(:path, path) + " " + message
60
+ Log.info Log.color(:status, status, true) + " " + Log.color(:path, path) + " " + message
61
61
  end
62
62
  end
63
63
 
@@ -109,7 +109,8 @@ class Step
109
109
  end
110
110
 
111
111
  def clean
112
- FileUtils.rm path.find if path.exist?
112
+ Open.rm path if Open.exist?(path)
113
+ Open.rm info_file if Open.exist?(info_file)
113
114
  end
114
115
 
115
116
  def recursive_clean
@@ -143,8 +143,8 @@ module Task
143
143
  non_default_inputs.concat provided_inputs.keys.select{|k| String === k && k.include?("#") } if Hash === provided_inputs
144
144
 
145
145
  if non_default_inputs.any?
146
- hash = Misc.digest(:inputs => input_hash, :non_default_inputs => non_default_inputs, :dependencies => dependencies)
147
- Log.debug "Hash #{name} - #{hash}: #{Misc.digest_str(:inputs => inputs, :dependencies => dependencies)}"
146
+ hash = Misc.digest(:inputs => input_hash, :dependencies => dependencies)
147
+ Log.debug "Hash #{name} - #{hash}: #{Misc.digest_str(:inputs => inputs, :non_default_inputs => non_default_inputs, :dependencies => dependencies)}"
148
148
  id = [id, hash] * "_"
149
149
  end
150
150
 
data/scout-gear.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: scout-gear 6.0.0 ruby lib
5
+ # stub: scout-gear 7.1.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-gear".freeze
9
- s.version = "6.0.0"
9
+ s.version = "7.1.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Miguel Vazquez".freeze]
14
- s.date = "2023-04-29"
14
+ s.date = "2023-05-01"
15
15
  s.description = "Temporary files, logs, etc.".freeze
16
16
  s.email = "mikisvaz@gmail.com".freeze
17
17
  s.executables = ["scout".freeze]
@@ -77,6 +77,8 @@ Gem::Specification.new do |s|
77
77
  "lib/scout/simple_opt/parse.rb",
78
78
  "lib/scout/simple_opt/setup.rb",
79
79
  "lib/scout/tmpfile.rb",
80
+ "lib/scout/tsv.rb",
81
+ "lib/scout/tsv/parser.rb",
80
82
  "lib/scout/work_queue.rb",
81
83
  "lib/scout/work_queue/socket.rb",
82
84
  "lib/scout/work_queue/worker.rb",
@@ -137,8 +139,10 @@ Gem::Specification.new do |s|
137
139
  "test/scout/test_resource.rb",
138
140
  "test/scout/test_semaphore.rb",
139
141
  "test/scout/test_tmpfile.rb",
142
+ "test/scout/test_tsv.rb",
140
143
  "test/scout/test_work_queue.rb",
141
144
  "test/scout/test_workflow.rb",
145
+ "test/scout/tsv/test_parser.rb",
142
146
  "test/scout/work_queue/test_socket.rb",
143
147
  "test/scout/work_queue/test_worker.rb",
144
148
  "test/scout/workflow/step/test_info.rb",
@@ -139,7 +139,7 @@ class TestOpenStream < Test::Unit::TestCase
139
139
 
140
140
  def test_tee_stream_save_error
141
141
  Log.with_severity 6 do
142
- 5.times do |i|
142
+ 50.times do |i|
143
143
  TmpFile.with_file do |tmp|
144
144
  Path.setup tmp
145
145
  assert_raise ScoutException do
@@ -4,7 +4,7 @@ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1
4
4
  require 'scout/work_queue/worker'
5
5
  class TestSemaphore < Test::Unit::TestCase
6
6
 
7
- def _test_simple
7
+ def test_simple
8
8
  ScoutSemaphore.with_semaphore 1 do |sem|
9
9
  10.times do
10
10
  ScoutSemaphore.synchronize(sem) do