rake 0.9.3.beta.2 → 0.9.3.beta.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rake might be problematic. Click here for more details.
- data/README.rdoc +1 -0
- data/doc/command_line_usage.rdoc +4 -1
- data/lib/rake/application.rb +69 -15
- data/lib/rake/backtrace.rb +8 -6
- data/lib/rake/dsl_definition.rb +9 -3
- data/lib/rake/multi_task.rb +2 -7
- data/lib/rake/rake_module.rb +8 -0
- data/lib/rake/task.rb +21 -7
- data/lib/rake/task_manager.rb +1 -1
- data/lib/rake/thread_history_display.rb +45 -0
- data/lib/rake/thread_pool.rb +101 -45
- data/lib/rake/version.rb +1 -1
- data/test/helper.rb +1 -0
- data/test/test_rake_application_options.rb +73 -0
- data/test/test_rake_backtrace.rb +18 -0
- data/test/test_rake_directory_task.rb +16 -0
- data/test/test_rake_task.rb +32 -0
- data/test/test_rake_thread_pool.rb +13 -13
- data/test/test_thread_history_display.rb +91 -0
- metadata +4 -2
data/README.rdoc
CHANGED
@@ -129,6 +129,7 @@ Issues and bug reports can also be tracked here:
|
|
129
129
|
* Rake Source Code Repo: http://github.com/jimweirich/rake
|
130
130
|
* Rake Git Repo Clone URL: git://github.com/jimweirich/rake.git
|
131
131
|
* Rake Bug Reports: https://github.com/jimweirich/rake/issues
|
132
|
+
* Rake Continuous Build Server: https://travis-ci.org/#!/jimweirich/rake
|
132
133
|
|
133
134
|
=== Presentations and Articles about Rake
|
134
135
|
|
data/doc/command_line_usage.rdoc
CHANGED
@@ -31,7 +31,7 @@ Options are:
|
|
31
31
|
[<tt>--execute-print</tt> _code_ (-p)]
|
32
32
|
Execute some Ruby code, print the result, and exit.
|
33
33
|
|
34
|
-
[<tt>--execute-continue</tt> _code_ (-
|
34
|
+
[<tt>--execute-continue</tt> _code_ (-E)]
|
35
35
|
Execute some Ruby code, then continue with normal task processing.
|
36
36
|
|
37
37
|
[<tt>--help</tt> (-H)]
|
@@ -49,6 +49,9 @@ Options are:
|
|
49
49
|
[<tt>--libdir</tt> _directory_ (-I)]
|
50
50
|
Add _directory_ to the list of directories searched for require.
|
51
51
|
|
52
|
+
[<tt>--multitask</tt> (-m)]
|
53
|
+
Treat all tasks as multitasks. ('make/drake' semantics)
|
54
|
+
|
52
55
|
[<tt>--nosearch</tt> (-N)]
|
53
56
|
Do not search for a Rakefile in parent directories.
|
54
57
|
|
data/lib/rake/application.rb
CHANGED
@@ -3,10 +3,13 @@ require 'optparse'
|
|
3
3
|
|
4
4
|
require 'rake/task_manager'
|
5
5
|
require 'rake/thread_pool'
|
6
|
+
require 'rake/thread_history_display'
|
6
7
|
require 'rake/win32'
|
7
8
|
|
8
9
|
module Rake
|
9
10
|
|
11
|
+
CommandLineOptionError = Class.new(StandardError)
|
12
|
+
|
10
13
|
######################################################################
|
11
14
|
# Rake main application object. When invoking +rake+ from the
|
12
15
|
# command line, a Rake::Application object is created and run.
|
@@ -64,8 +67,15 @@ module Rake
|
|
64
67
|
standard_exception_handling do
|
65
68
|
init
|
66
69
|
load_rakefile
|
70
|
+
thread_pool.gather_history if options.job_stats == :history
|
67
71
|
top_level
|
68
72
|
thread_pool.join
|
73
|
+
if options.job_stats
|
74
|
+
stats = thread_pool.statistics
|
75
|
+
puts "Maximum active threads: #{stats[:max_active_threads]}"
|
76
|
+
puts "Total threads in play: #{stats[:total_threads_in_play]}"
|
77
|
+
end
|
78
|
+
ThreadHistoryDisplay.new(thread_pool.history).show if options.job_stats == :history
|
69
79
|
end
|
70
80
|
end
|
71
81
|
|
@@ -108,8 +118,9 @@ module Rake
|
|
108
118
|
@options ||= OpenStruct.new
|
109
119
|
end
|
110
120
|
|
111
|
-
|
112
|
-
|
121
|
+
# Return the thread pool used for multithreaded processing.
|
122
|
+
def thread_pool # :nodoc:
|
123
|
+
@thread_pool ||= ThreadPool.new(options.thread_pool_size||FIXNUM_MAX)
|
113
124
|
end
|
114
125
|
|
115
126
|
# private ----------------------------------------------------------------
|
@@ -150,15 +161,15 @@ module Rake
|
|
150
161
|
|
151
162
|
# Display the error message that caused the exception.
|
152
163
|
def display_error_message(ex)
|
153
|
-
|
154
|
-
|
164
|
+
trace "#{name} aborted!"
|
165
|
+
trace ex.message
|
155
166
|
if options.backtrace
|
156
|
-
|
167
|
+
trace ex.backtrace.join("\n")
|
157
168
|
else
|
158
|
-
|
169
|
+
trace Backtrace.collapse(ex.backtrace)
|
159
170
|
end
|
160
|
-
|
161
|
-
|
171
|
+
trace "Tasks: #{ex.chain}" if has_chain?(ex)
|
172
|
+
trace "(See full trace by running task with --trace)" unless options.backtrace
|
162
173
|
end
|
163
174
|
|
164
175
|
# Warn about deprecated usage.
|
@@ -293,6 +304,11 @@ module Rake
|
|
293
304
|
end
|
294
305
|
end
|
295
306
|
|
307
|
+
def trace(*str)
|
308
|
+
options.trace_output ||= $stderr
|
309
|
+
options.trace_output.puts(*str)
|
310
|
+
end
|
311
|
+
|
296
312
|
def sort_options(options)
|
297
313
|
options.sort_by { |opt|
|
298
314
|
opt.select { |o| o =~ /^-/ }.map { |o| o.downcase }.sort.reverse
|
@@ -310,9 +326,10 @@ module Rake
|
|
310
326
|
options.show_all_tasks = value
|
311
327
|
}
|
312
328
|
],
|
313
|
-
['--backtrace', "Enable full backtrace.",
|
329
|
+
['--backtrace [OUT]', "Enable full backtrace. OUT can be stderr (default) or stdout.",
|
314
330
|
lambda { |value|
|
315
|
-
options.backtrace =
|
331
|
+
options.backtrace = true
|
332
|
+
select_trace_output(options, 'backtrace', value)
|
316
333
|
}
|
317
334
|
],
|
318
335
|
['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace",
|
@@ -328,7 +345,7 @@ module Rake
|
|
328
345
|
],
|
329
346
|
['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
|
330
347
|
lambda { |value|
|
331
|
-
select_tasks_to_show :describe, value
|
348
|
+
select_tasks_to_show(options, :describe, value)
|
332
349
|
}
|
333
350
|
],
|
334
351
|
['--dry-run', '-n', "Do a dry run without executing actions.",
|
@@ -359,9 +376,22 @@ module Rake
|
|
359
376
|
"Specifies the maximum number of tasks to execute in parallel. (default:2)",
|
360
377
|
lambda { |value| options.thread_pool_size = [(value || 2).to_i,2].max }
|
361
378
|
],
|
379
|
+
['--job-stats [LEVEL]',
|
380
|
+
"Display job statistics. LEVEL=history displays a complete job list",
|
381
|
+
lambda { |value|
|
382
|
+
if value =~ /^history/i
|
383
|
+
options.job_stats = :history
|
384
|
+
else
|
385
|
+
options.job_stats = true
|
386
|
+
end
|
387
|
+
}
|
388
|
+
],
|
362
389
|
['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
|
363
390
|
lambda { |value| $:.push(value) }
|
364
391
|
],
|
392
|
+
['--multitask', '-m', "Treat all tasks as multitasks.",
|
393
|
+
lambda { |value| options.always_multitask = true }
|
394
|
+
],
|
365
395
|
['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
|
366
396
|
lambda { |value| options.nosearch = true }
|
367
397
|
],
|
@@ -409,6 +439,11 @@ module Rake
|
|
409
439
|
options.silent = true
|
410
440
|
}
|
411
441
|
],
|
442
|
+
['--suppress-backtrace PATTERN', "Suppress backtrace lines matching regexp PATTERN. Ignored if --trace is on.",
|
443
|
+
lambda { |value|
|
444
|
+
options.suppress_backtrace_pattern = Regexp.new(value)
|
445
|
+
}
|
446
|
+
],
|
412
447
|
['--system', '-g',
|
413
448
|
"Using system wide (global) rakefiles (usually '~/.rake/*.rake').",
|
414
449
|
lambda { |value| options.load_system = true }
|
@@ -419,13 +454,14 @@ module Rake
|
|
419
454
|
],
|
420
455
|
['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
|
421
456
|
lambda { |value|
|
422
|
-
select_tasks_to_show :tasks, value
|
457
|
+
select_tasks_to_show(options, :tasks, value)
|
423
458
|
}
|
424
459
|
],
|
425
|
-
['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
|
460
|
+
['--trace', '-t [OUT]', "Turn on invoke/execute tracing, enable full backtrace. OUT can be stderr (default) or stdout.",
|
426
461
|
lambda { |value|
|
427
462
|
options.trace = true
|
428
463
|
options.backtrace = true
|
464
|
+
select_trace_output(options, 'trace', value)
|
429
465
|
Rake.verbose(true)
|
430
466
|
}
|
431
467
|
],
|
@@ -440,7 +476,7 @@ module Rake
|
|
440
476
|
],
|
441
477
|
['--where', '-W [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
|
442
478
|
lambda { |value|
|
443
|
-
select_tasks_to_show :lines, value
|
479
|
+
select_tasks_to_show(options, :lines, value)
|
444
480
|
options.show_all_tasks = true
|
445
481
|
}
|
446
482
|
],
|
@@ -452,16 +488,30 @@ module Rake
|
|
452
488
|
])
|
453
489
|
end
|
454
490
|
|
455
|
-
def select_tasks_to_show(show_tasks, value
|
491
|
+
def select_tasks_to_show(options, show_tasks, value)
|
456
492
|
options.show_tasks = show_tasks
|
457
493
|
options.show_task_pattern = Regexp.new(value || '')
|
458
494
|
Rake::TaskManager.record_task_metadata = true
|
459
495
|
end
|
460
496
|
private :select_tasks_to_show
|
461
497
|
|
498
|
+
def select_trace_output(options, trace_option, value)
|
499
|
+
value = value.strip unless value.nil?
|
500
|
+
case value
|
501
|
+
when 'stdout'
|
502
|
+
options.trace_output = $stdout
|
503
|
+
when 'stderr', nil
|
504
|
+
options.trace_output = $stderr
|
505
|
+
else
|
506
|
+
fail CommandLineOptionError, "Unrecognized --#{trace_option} option '#{value}'"
|
507
|
+
end
|
508
|
+
end
|
509
|
+
private :select_trace_output
|
510
|
+
|
462
511
|
# Read and handle the command line options.
|
463
512
|
def handle_options
|
464
513
|
options.rakelib = ['rakelib']
|
514
|
+
options.trace_output = $stderr
|
465
515
|
|
466
516
|
OptionParser.new do |opts|
|
467
517
|
opts.banner = "rake [-f rakefile] {options} targets..."
|
@@ -632,5 +682,9 @@ module Rake
|
|
632
682
|
|
633
683
|
backtrace.find { |str| str =~ re } || ''
|
634
684
|
end
|
685
|
+
|
686
|
+
private
|
687
|
+
FIXNUM_MAX = (2**(0.size * 8 - 2) - 1) # :nodoc:
|
688
|
+
|
635
689
|
end
|
636
690
|
end
|
data/lib/rake/backtrace.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
module Rake
|
2
2
|
module Backtrace
|
3
|
-
SUPPRESSED_PATHS =
|
4
|
-
RbConfig::CONFIG
|
5
|
-
|
6
|
-
|
3
|
+
SUPPRESSED_PATHS =
|
4
|
+
RbConfig::CONFIG.values_at(*RbConfig::CONFIG.
|
5
|
+
keys.grep(/(prefix|libdir)/)) + [
|
6
|
+
File.join(File.dirname(__FILE__), ".."),
|
7
|
+
].map { |f| Regexp.quote(File.expand_path(f)) }
|
7
8
|
|
8
9
|
SUPPRESS_PATTERN = %r!(\A#{SUPPRESSED_PATHS.join('|')}|bin/rake:\d+)!
|
9
10
|
|
10
|
-
# Elide backtrace elements which match one of SUPPRESS_PATHS.
|
11
11
|
def self.collapse(backtrace)
|
12
|
-
|
12
|
+
pattern = Rake.application.options.suppress_backtrace_pattern ||
|
13
|
+
SUPPRESS_PATTERN
|
14
|
+
backtrace.reject { |elem| elem =~ pattern }
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
data/lib/rake/dsl_definition.rb
CHANGED
@@ -52,8 +52,8 @@ module Rake
|
|
52
52
|
|
53
53
|
# Declare a file creation task.
|
54
54
|
# (Mainly used for the directory command).
|
55
|
-
def file_create(args, &block)
|
56
|
-
Rake::FileCreationTask.define_task(args, &block)
|
55
|
+
def file_create(*args, &block)
|
56
|
+
Rake::FileCreationTask.define_task(*args, &block)
|
57
57
|
end
|
58
58
|
|
59
59
|
# Declare a set of files tasks to create the given directories on
|
@@ -62,12 +62,15 @@ module Rake
|
|
62
62
|
# Example:
|
63
63
|
# directory "testdata/doc"
|
64
64
|
#
|
65
|
-
def directory(
|
65
|
+
def directory(*args, &block)
|
66
|
+
result = file_create(*args, &block)
|
67
|
+
dir, _ = *Rake.application.resolve_args(args)
|
66
68
|
Rake.each_dir_parent(dir) do |d|
|
67
69
|
file_create d do |t|
|
68
70
|
mkdir_p t.name if ! File.exist?(t.name)
|
69
71
|
end
|
70
72
|
end
|
73
|
+
result
|
71
74
|
end
|
72
75
|
|
73
76
|
# Declare a task that performs its prerequisites in
|
@@ -172,5 +175,8 @@ module Rake
|
|
172
175
|
extend FileUtilsExt
|
173
176
|
end
|
174
177
|
|
178
|
+
# Extend the main object with the DSL commands. This allows top-level
|
179
|
+
# calls to task, etc. to work from a Rakefile without polluting the
|
180
|
+
# object inheritance tree.
|
175
181
|
self.extend Rake::DSL
|
176
182
|
include Rake::DeprecatedObjectDSL unless defined? Rake::REDUCE_COMPAT
|
data/lib/rake/multi_task.rb
CHANGED
@@ -5,13 +5,8 @@ module Rake
|
|
5
5
|
#
|
6
6
|
class MultiTask < Task
|
7
7
|
private
|
8
|
-
def invoke_prerequisites(
|
9
|
-
|
10
|
-
application.thread_pool.future(p) do |r|
|
11
|
-
application[r, @scope].invoke_with_call_chain(args, invocation_chain)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
futures.each { |f| f.call }
|
8
|
+
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
|
9
|
+
invoke_prerequisites_concurrently(task_args, invocation_chain)
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
data/lib/rake/rake_module.rb
CHANGED
@@ -25,6 +25,14 @@ module Rake
|
|
25
25
|
load(path)
|
26
26
|
end
|
27
27
|
|
28
|
+
# Add files to the rakelib list
|
29
|
+
def add_rakelib(*files)
|
30
|
+
application.options.rakelib ||= []
|
31
|
+
files.each do |file|
|
32
|
+
application.options.rakelib << file
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
28
36
|
# Get a sorted list of files matching the pattern. This method
|
29
37
|
# should be prefered to Dir[pattern] and Dir.glob[pattern] because
|
30
38
|
# the files returned are guaranteed to be sorted.
|
data/lib/rake/task.rb
CHANGED
@@ -158,7 +158,7 @@ module Rake
|
|
158
158
|
new_chain = InvocationChain.append(self, invocation_chain)
|
159
159
|
@lock.synchronize do
|
160
160
|
if application.options.trace
|
161
|
-
|
161
|
+
application.trace "** Invoke #{name} #{format_trace_flags}"
|
162
162
|
end
|
163
163
|
return if @already_invoked
|
164
164
|
@already_invoked = true
|
@@ -179,10 +179,24 @@ module Rake
|
|
179
179
|
|
180
180
|
# Invoke all the prerequisites of a task.
|
181
181
|
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
182
|
+
if application.options.always_multitask
|
183
|
+
invoke_prerequisites_concurrently(task_args, invocation_chain)
|
184
|
+
else
|
185
|
+
prerequisite_tasks.each { |prereq|
|
186
|
+
prereq_args = task_args.new_scope(prereq.arg_names)
|
187
|
+
prereq.invoke_with_call_chain(prereq_args, invocation_chain)
|
188
|
+
}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Invoke all the prerequisites of a task in parallel.
|
193
|
+
def invoke_prerequisites_concurrently(args, invocation_chain) # :nodoc:
|
194
|
+
futures = @prerequisites.collect do |p|
|
195
|
+
application.thread_pool.future(p) do |r|
|
196
|
+
application[r, @scope].invoke_with_call_chain(args, invocation_chain)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
futures.each { |f| f.call }
|
186
200
|
end
|
187
201
|
|
188
202
|
# Format the trace flags for display.
|
@@ -198,11 +212,11 @@ module Rake
|
|
198
212
|
def execute(args=nil)
|
199
213
|
args ||= EMPTY_TASK_ARGS
|
200
214
|
if application.options.dryrun
|
201
|
-
|
215
|
+
application.trace "** Execute (dry run) #{name}"
|
202
216
|
return
|
203
217
|
end
|
204
218
|
if application.options.trace
|
205
|
-
|
219
|
+
application.trace "** Execute #{name}"
|
206
220
|
end
|
207
221
|
application.enhance_with_matching_rule(name) if @actions.empty?
|
208
222
|
@actions.each do |act|
|
data/lib/rake/task_manager.rb
CHANGED
@@ -238,7 +238,7 @@ module Rake
|
|
238
238
|
end
|
239
239
|
|
240
240
|
def trace_rule(level, message)
|
241
|
-
|
241
|
+
options.trace_output.puts "#{" "*level}#{message}" if Rake.application.options.trace_rules
|
242
242
|
end
|
243
243
|
|
244
244
|
# Attempt to create a rule given the list of prerequisites.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Rake
|
2
|
+
|
3
|
+
class ThreadHistoryDisplay
|
4
|
+
attr_reader :stats, :items, :threads
|
5
|
+
private :stats, :items, :threads
|
6
|
+
|
7
|
+
def initialize(stats)
|
8
|
+
@stats = stats
|
9
|
+
@items = { :_seq_ => 1 }
|
10
|
+
@threads = { :_seq_ => "A" }
|
11
|
+
end
|
12
|
+
|
13
|
+
def show
|
14
|
+
puts "Job History:"
|
15
|
+
stats.each do |stat|
|
16
|
+
stat[:data] ||= []
|
17
|
+
rename(stat, :thread, threads)
|
18
|
+
rename(stat[:data], :item_id, items)
|
19
|
+
rename(stat[:data], :new_thread, threads)
|
20
|
+
rename(stat[:data], :deleted_thread, threads)
|
21
|
+
printf("%8d %2s %-20s %s\n",
|
22
|
+
(stat[:time] * 1_000_000).round,
|
23
|
+
stat[:thread],
|
24
|
+
stat[:event],
|
25
|
+
stat[:data].map { |k,v| "#{k}:#{v}" }.join(" "))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def rename(hash, key, renames)
|
32
|
+
if hash && hash[key]
|
33
|
+
original = hash[key]
|
34
|
+
value = renames[original]
|
35
|
+
unless value
|
36
|
+
value = renames[:_seq_]
|
37
|
+
renames[:_seq_] = renames[:_seq_].succ
|
38
|
+
renames[original] = value
|
39
|
+
end
|
40
|
+
hash[key] = value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/rake/thread_pool.rb
CHANGED
@@ -3,24 +3,31 @@ require 'set'
|
|
3
3
|
|
4
4
|
module Rake
|
5
5
|
|
6
|
-
class ThreadPool
|
6
|
+
class ThreadPool # :nodoc: all
|
7
7
|
|
8
8
|
# Creates a ThreadPool object.
|
9
|
-
# The parameter is the size of the pool.
|
10
|
-
def initialize(thread_count
|
11
|
-
@
|
9
|
+
# The parameter is the size of the pool.
|
10
|
+
def initialize(thread_count)
|
11
|
+
@max_active_threads = [thread_count, 0].max
|
12
12
|
@threads = Set.new
|
13
13
|
@threads_mon = Monitor.new
|
14
14
|
@queue = Queue.new
|
15
15
|
@join_cond = @threads_mon.new_cond
|
16
|
+
|
17
|
+
@history_start_time = nil
|
18
|
+
@history = []
|
19
|
+
@history_mon = Monitor.new
|
20
|
+
@total_threads_in_play = 0
|
16
21
|
end
|
17
|
-
|
18
|
-
# Creates a future
|
19
|
-
#
|
20
|
-
# The
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
22
|
+
|
23
|
+
# Creates a future executed by the +ThreadPool+.
|
24
|
+
#
|
25
|
+
# The args are passed to the block when executing (similarly to
|
26
|
+
# <tt>Thread#new</tt>) The return value is an object representing
|
27
|
+
# a future which has been created and added to the queue in the
|
28
|
+
# pool. Sending <tt>#value</tt> to the object will sleep the
|
29
|
+
# current thread until the future is finished and will return the
|
30
|
+
# result (or raise an exception thrown from the future)
|
24
31
|
def future(*args,&block)
|
25
32
|
# capture the local args for the block (like Thread#start)
|
26
33
|
local_args = args.collect { |a| begin; a.dup; rescue; a; end }
|
@@ -34,7 +41,7 @@ module Rake
|
|
34
41
|
unless promise_result.equal?(NOT_SET) && promise_error.equal?(NOT_SET)
|
35
42
|
return promise_error.equal?(NOT_SET) ? promise_result : raise(promise_error)
|
36
43
|
end
|
37
|
-
|
44
|
+
|
38
45
|
# try to get the lock and execute the promise, otherwise, sleep.
|
39
46
|
if promise_mutex.try_lock
|
40
47
|
if promise_result.equal?(NOT_SET) && promise_error.equal?(NOT_SET)
|
@@ -48,86 +55,135 @@ module Rake
|
|
48
55
|
end
|
49
56
|
promise_mutex.unlock
|
50
57
|
else
|
51
|
-
# Even if we didn't get the lock, we need to sleep until the
|
52
|
-
# finished executing. If, however, the current
|
53
|
-
# pool, we need to free up a
|
54
|
-
# always be a thread
|
58
|
+
# Even if we didn't get the lock, we need to sleep until the
|
59
|
+
# promise has finished executing. If, however, the current
|
60
|
+
# thread is part of the thread pool, we need to free up a
|
61
|
+
# new thread in the pool so there will always be a thread
|
62
|
+
# doing work.
|
55
63
|
|
56
|
-
wait_for_promise = lambda {
|
64
|
+
wait_for_promise = lambda {
|
65
|
+
stat :waiting, item_id: promise.object_id
|
66
|
+
promise_mutex.synchronize {}
|
67
|
+
stat :continue, item_id: promise.object_id
|
68
|
+
}
|
57
69
|
|
58
70
|
unless @threads_mon.synchronize { @threads.include? Thread.current }
|
59
71
|
wait_for_promise.call
|
60
72
|
else
|
61
|
-
@threads_mon.synchronize { @
|
73
|
+
@threads_mon.synchronize { @max_active_threads += 1 }
|
62
74
|
start_thread
|
63
75
|
wait_for_promise.call
|
64
|
-
@threads_mon.synchronize { @
|
76
|
+
@threads_mon.synchronize { @max_active_threads -= 1 }
|
65
77
|
end
|
66
78
|
end
|
67
79
|
promise_error.equal?(NOT_SET) ? promise_result : raise(promise_error)
|
68
80
|
end
|
69
81
|
|
82
|
+
def promise.value
|
83
|
+
call
|
84
|
+
end
|
85
|
+
|
70
86
|
@queue.enq promise
|
87
|
+
stat :item_queued, item_id: promise.object_id
|
71
88
|
start_thread
|
72
89
|
promise
|
73
90
|
end
|
74
|
-
|
91
|
+
|
75
92
|
# Waits until the queue of futures is empty and all threads have exited.
|
76
93
|
def join
|
77
94
|
@threads_mon.synchronize do
|
78
95
|
begin
|
79
96
|
@join_cond.wait unless @threads.empty?
|
80
97
|
rescue Exception => e
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
98
|
+
$stderr.puts e
|
99
|
+
$stderr.print "Queue contains #{@queue.size} items. Thread pool contains #{@threads.count} threads\n"
|
100
|
+
$stderr.print "Current Thread #{Thread.current} status = #{Thread.current.status}\n"
|
101
|
+
$stderr.puts e.backtrace.join("\n")
|
85
102
|
@threads.each do |t|
|
86
|
-
|
87
|
-
|
103
|
+
$stderr.print "Thread #{t} status = #{t.status}\n"
|
104
|
+
$stderr.puts t.backtrace.join("\n") if t.respond_to? :backtrace
|
88
105
|
end
|
89
106
|
raise e
|
90
107
|
end
|
91
108
|
end
|
92
109
|
end
|
93
110
|
|
94
|
-
|
95
|
-
def
|
111
|
+
# Enable the gathering of history events.
|
112
|
+
def gather_history #:nodoc:
|
113
|
+
@history_start_time = Time.now if @history_start_time.nil?
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return a array of history events for the thread pool.
|
117
|
+
#
|
118
|
+
# History gathering must be enabled to be able to see the events
|
119
|
+
# (see #gather_history). Best to call this when the job is
|
120
|
+
# complete (i.e. after ThreadPool#join is called).
|
121
|
+
def history # :nodoc:
|
122
|
+
@history_mon.synchronize { @history.dup }
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return a hash of always collected statistics for the thread pool.
|
126
|
+
def statistics # :nodoc:
|
127
|
+
{
|
128
|
+
total_threads_in_play: @total_threads_in_play,
|
129
|
+
max_active_threads: @max_active_threads,
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def start_thread # :nodoc:
|
96
136
|
@threads_mon.synchronize do
|
97
|
-
next unless @threads.count < @
|
137
|
+
next unless @threads.count < @max_active_threads
|
98
138
|
|
99
|
-
|
139
|
+
t = Thread.new do
|
100
140
|
begin
|
101
|
-
while @threads.count <= @
|
102
|
-
# Even though we just asked if the queue was empty,
|
103
|
-
#
|
104
|
-
# For this reason we pass true to Queue#deq
|
105
|
-
# indefinitely if it is empty.
|
106
|
-
@queue.deq(true)
|
141
|
+
while @threads.count <= @max_active_threads && !@queue.empty? do
|
142
|
+
# Even though we just asked if the queue was empty, it
|
143
|
+
# still could have had an item which by this statement
|
144
|
+
# is now gone. For this reason we pass true to Queue#deq
|
145
|
+
# because we will sleep indefinitely if it is empty.
|
146
|
+
block = @queue.deq(true)
|
147
|
+
stat :item_dequeued, item_id: block.object_id
|
148
|
+
block.call
|
107
149
|
end
|
108
150
|
rescue ThreadError # this means the queue is empty
|
109
151
|
ensure
|
110
152
|
@threads_mon.synchronize do
|
111
153
|
@threads.delete Thread.current
|
154
|
+
stat :thread_deleted, deleted_thread: Thread.current.object_id, thread_count: @threads.count
|
112
155
|
@join_cond.broadcast if @threads.empty?
|
113
156
|
end
|
114
157
|
end
|
115
158
|
end
|
159
|
+
@threads << t
|
160
|
+
stat :thread_created, new_thread: t.object_id, thread_count: @threads.count
|
161
|
+
@total_threads_in_play = @threads.count if @threads.count > @total_threads_in_play
|
116
162
|
end
|
117
163
|
end
|
118
|
-
|
164
|
+
|
165
|
+
def stat(event, data=nil) # :nodoc:
|
166
|
+
return if @history_start_time.nil?
|
167
|
+
info = {
|
168
|
+
event: event,
|
169
|
+
data: data,
|
170
|
+
time: (Time.now-@history_start_time),
|
171
|
+
thread: Thread.current.object_id,
|
172
|
+
}
|
173
|
+
@history_mon.synchronize { @history << info }
|
174
|
+
end
|
175
|
+
|
119
176
|
# for testing only
|
120
|
-
|
121
|
-
def __queue__
|
177
|
+
|
178
|
+
def __queue__ # :nodoc:
|
122
179
|
@queue
|
123
180
|
end
|
124
|
-
|
125
|
-
def __threads__
|
181
|
+
|
182
|
+
def __threads__ # :nodoc:
|
126
183
|
@threads.dup
|
127
184
|
end
|
128
|
-
|
129
|
-
NOT_SET = Object.new.freeze
|
130
|
-
FIXNUM_MAX = (2**(0.size * 8 - 2) - 1) # FIXNUM_MAX
|
185
|
+
|
186
|
+
NOT_SET = Object.new.freeze # :nodoc:
|
131
187
|
end
|
132
|
-
|
188
|
+
|
133
189
|
end
|
data/lib/rake/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -34,6 +34,7 @@ class TestRakeApplicationOptions < Rake::TestCase
|
|
34
34
|
assert_nil opts.dryrun
|
35
35
|
assert_nil opts.ignore_system
|
36
36
|
assert_nil opts.load_system
|
37
|
+
assert_nil opts.always_multitask
|
37
38
|
assert_nil opts.nosearch
|
38
39
|
assert_equal ['rakelib'], opts.rakelib
|
39
40
|
assert_nil opts.show_prereqs
|
@@ -132,6 +133,12 @@ class TestRakeApplicationOptions < Rake::TestCase
|
|
132
133
|
$:.delete('xx')
|
133
134
|
end
|
134
135
|
|
136
|
+
def test_multitask
|
137
|
+
flags('--multitask', '-m') do |opts|
|
138
|
+
assert_equal opts.always_multitask, true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
135
142
|
def test_rakefile
|
136
143
|
flags(['--rakefile', 'RF'], ['--rakefile=RF'], ['-f', 'RF'], ['-fRF']) do |opts|
|
137
144
|
assert_equal ['RF'], @app.instance_eval { @rakefiles }
|
@@ -213,19 +220,74 @@ class TestRakeApplicationOptions < Rake::TestCase
|
|
213
220
|
flags('--trace', '-t') do |opts|
|
214
221
|
assert opts.trace, "should enable trace option"
|
215
222
|
assert opts.backtrace, "should enabled backtrace option"
|
223
|
+
assert_equal $stderr, opts.trace_output
|
216
224
|
assert Rake::FileUtilsExt.verbose_flag
|
217
225
|
assert ! Rake::FileUtilsExt.nowrite_flag
|
218
226
|
end
|
219
227
|
end
|
220
228
|
|
229
|
+
def test_trace_with_stdout
|
230
|
+
flags('--trace=stdout', '-tstdout', '-t stdout') do |opts|
|
231
|
+
assert opts.trace, "should enable trace option"
|
232
|
+
assert opts.backtrace, "should enabled backtrace option"
|
233
|
+
assert_equal $stdout, opts.trace_output
|
234
|
+
assert Rake::FileUtilsExt.verbose_flag
|
235
|
+
assert ! Rake::FileUtilsExt.nowrite_flag
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_trace_with_stderr
|
240
|
+
flags('--trace=stderr', '-tstderr', '-t stderr') do |opts|
|
241
|
+
assert opts.trace, "should enable trace option"
|
242
|
+
assert opts.backtrace, "should enabled backtrace option"
|
243
|
+
assert_equal $stderr, opts.trace_output
|
244
|
+
assert Rake::FileUtilsExt.verbose_flag
|
245
|
+
assert ! Rake::FileUtilsExt.nowrite_flag
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_trace_with_error
|
250
|
+
ex = assert_raises(Rake::CommandLineOptionError) do
|
251
|
+
flags('--trace=xyzzy') do |opts| end
|
252
|
+
end
|
253
|
+
assert_match(/un(known|recognized).*\btrace\b.*xyzzy/i, ex.message)
|
254
|
+
end
|
255
|
+
|
256
|
+
|
221
257
|
def test_backtrace
|
222
258
|
flags('--backtrace') do |opts|
|
223
259
|
assert opts.backtrace, "should enable backtrace option"
|
260
|
+
assert_equal $stderr, opts.trace_output
|
224
261
|
assert ! opts.trace, "should not enable trace option"
|
225
262
|
assert ! Rake::FileUtilsExt.verbose_flag
|
226
263
|
end
|
227
264
|
end
|
228
265
|
|
266
|
+
def test_backtrace_with_stdout
|
267
|
+
flags('--backtrace=stdout') do |opts|
|
268
|
+
assert opts.backtrace, "should enable backtrace option"
|
269
|
+
assert_equal $stdout, opts.trace_output
|
270
|
+
assert ! opts.trace, "should not enable trace option"
|
271
|
+
assert ! Rake::FileUtilsExt.verbose_flag
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_backtrace_with_stderr
|
276
|
+
flags('--backtrace=stderr') do |opts|
|
277
|
+
assert opts.backtrace, "should enable backtrace option"
|
278
|
+
assert_equal $stderr, opts.trace_output
|
279
|
+
assert ! opts.trace, "should not enable trace option"
|
280
|
+
assert ! Rake::FileUtilsExt.verbose_flag
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_backtrace_with_error
|
285
|
+
ex = assert_raises(Rake::CommandLineOptionError) do
|
286
|
+
flags('--backtrace=xyzzy') do |opts| end
|
287
|
+
end
|
288
|
+
assert_match(/un(known|recognized).*\bbacktrace\b.*xyzzy/i, ex.message)
|
289
|
+
end
|
290
|
+
|
229
291
|
def test_trace_rules
|
230
292
|
flags('--rules') do |opts|
|
231
293
|
assert opts.trace_rules
|
@@ -345,6 +407,17 @@ class TestRakeApplicationOptions < Rake::TestCase
|
|
345
407
|
assert '12', ENV['TESTKEY']
|
346
408
|
end
|
347
409
|
|
410
|
+
def test_rake_explicit_task_library
|
411
|
+
Rake.add_rakelib 'app/task', 'other'
|
412
|
+
|
413
|
+
libs = Rake.application.options.rakelib
|
414
|
+
|
415
|
+
assert libs.include?("app/task")
|
416
|
+
assert libs.include?("other")
|
417
|
+
end
|
418
|
+
|
419
|
+
private
|
420
|
+
|
348
421
|
def flags(*sets)
|
349
422
|
sets.each do |set|
|
350
423
|
ARGV.clear
|
data/test/test_rake_backtrace.rb
CHANGED
@@ -46,4 +46,22 @@ class TestRakeBacktrace < Rake::TestCase
|
|
46
46
|
assert_match %r!\A#{Regexp.quote Dir.pwd}/Rakefile:3!, lines[3]
|
47
47
|
assert_match %r!\ATasks:!, lines[4]
|
48
48
|
end
|
49
|
+
|
50
|
+
def test_suppress_option
|
51
|
+
rakefile %q{
|
52
|
+
task :baz do
|
53
|
+
raise "bazzz!"
|
54
|
+
end
|
55
|
+
}
|
56
|
+
|
57
|
+
lines = rake("baz").split("\n")
|
58
|
+
assert_equal "rake aborted!", lines[0]
|
59
|
+
assert_equal "bazzz!", lines[1]
|
60
|
+
assert_match %r!Rakefile!, lines[2]
|
61
|
+
|
62
|
+
lines = rake("--suppress-backtrace", "R.k.file", "baz").split("\n")
|
63
|
+
assert_equal "rake aborted!", lines[0]
|
64
|
+
assert_equal "bazzz!", lines[1]
|
65
|
+
refute_match %r!Rakefile!, lines[2]
|
66
|
+
end
|
49
67
|
end
|
@@ -38,4 +38,20 @@ class TestRakeDirectoryTask < Rake::TestCase
|
|
38
38
|
assert_nil Task['c:/a/b'].comment
|
39
39
|
end
|
40
40
|
end
|
41
|
+
|
42
|
+
def test_can_use_blocks
|
43
|
+
runlist = []
|
44
|
+
|
45
|
+
t1 = directory("a/b/c" => :t2) { |t| runlist << t.name }
|
46
|
+
t2 = task(:t2) { |t| runlist << t.name }
|
47
|
+
|
48
|
+
verbose(false) {
|
49
|
+
t1.invoke
|
50
|
+
}
|
51
|
+
|
52
|
+
assert_equal Task["a/b/c"], t1
|
53
|
+
assert_equal FileCreationTask, Task["a/b/c"].class
|
54
|
+
assert_equal ["t2", "a/b/c"], runlist
|
55
|
+
assert File.directory?("a/b/c")
|
56
|
+
end
|
41
57
|
end
|
data/test/test_rake_task.rb
CHANGED
@@ -241,6 +241,38 @@ class TestRakeTask < Rake::TestCase
|
|
241
241
|
assert_in_delta now + 10, a.timestamp, 0.1, 'computer too slow?'
|
242
242
|
end
|
243
243
|
|
244
|
+
def test_always_multitask
|
245
|
+
mx = Mutex.new
|
246
|
+
result = []
|
247
|
+
|
248
|
+
t_a = task(:a) do |t|
|
249
|
+
sleep 0.02
|
250
|
+
mx.synchronize{ result << t.name }
|
251
|
+
end
|
252
|
+
|
253
|
+
t_b = task(:b) do |t|
|
254
|
+
mx.synchronize{ result << t.name }
|
255
|
+
end
|
256
|
+
|
257
|
+
t_c = task(:c => [:a,:b]) do |t|
|
258
|
+
mx.synchronize{ result << t.name }
|
259
|
+
end
|
260
|
+
|
261
|
+
t_c.invoke
|
262
|
+
|
263
|
+
# task should always run in order
|
264
|
+
assert_equal ['a', 'b', 'c'], result
|
265
|
+
|
266
|
+
[t_a, t_b, t_c].each { |t| t.reenable }
|
267
|
+
result.clear
|
268
|
+
|
269
|
+
Rake.application.options.always_multitask = true
|
270
|
+
t_c.invoke
|
271
|
+
|
272
|
+
# with multitask, task 'b' should grab the mutex first
|
273
|
+
assert_equal ['b', 'a', 'c'], result
|
274
|
+
end
|
275
|
+
|
244
276
|
def test_investigation_output
|
245
277
|
t1 = task(:t1 => [:t2, :t3]) { |t| runlist << t.name; 3321 }
|
246
278
|
task(:t2)
|
@@ -9,19 +9,19 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
9
9
|
pool = ThreadPool.new(0)
|
10
10
|
f = pool.future{Thread.current}
|
11
11
|
pool.join
|
12
|
-
assert_equal Thread.current, f.
|
12
|
+
assert_equal Thread.current, f.value
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_pool_executes_in_other_thread_for_pool_of_size_one
|
16
16
|
pool = ThreadPool.new(1)
|
17
17
|
f = pool.future{Thread.current}
|
18
18
|
pool.join
|
19
|
-
refute_equal Thread.current, f.
|
19
|
+
refute_equal Thread.current, f.value
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_pool_executes_in_two_other_threads_for_pool_of_size_two
|
23
23
|
pool = ThreadPool.new(2)
|
24
|
-
threads = 2.times.collect{ pool.future{ sleep 0.1; Thread.current } }.each{|f|f.
|
24
|
+
threads = 2.times.collect{ pool.future{ sleep 0.1; Thread.current } }.each{|f|f.value}
|
25
25
|
|
26
26
|
refute_equal threads[0], threads[1]
|
27
27
|
refute_equal Thread.current, threads[0]
|
@@ -79,11 +79,11 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
79
79
|
|
80
80
|
deep_exception_block = lambda do |count|
|
81
81
|
next raise Exception.new if ( count < 1 )
|
82
|
-
pool.future(count-1, &deep_exception_block).
|
82
|
+
pool.future(count-1, &deep_exception_block).value
|
83
83
|
end
|
84
84
|
|
85
85
|
assert_raises(Exception) do
|
86
|
-
pool.future(2, &deep_exception_block).
|
86
|
+
pool.future(2, &deep_exception_block).value
|
87
87
|
end
|
88
88
|
|
89
89
|
end
|
@@ -94,7 +94,7 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
94
94
|
pool = ThreadPool.new(2)
|
95
95
|
initial_sleep_time = 0.2
|
96
96
|
future1 = pool.future { sleep initial_sleep_time }
|
97
|
-
dependent_futures = 5.times.collect { pool.future{ future1.
|
97
|
+
dependent_futures = 5.times.collect { pool.future{ future1.value } }
|
98
98
|
future2 = pool.future { sleep initial_sleep_time }
|
99
99
|
future3 = pool.future { sleep 0.01 }
|
100
100
|
|
@@ -107,7 +107,7 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
107
107
|
# future 3 is in the queue because there aren't enough active threads to work on it.
|
108
108
|
assert_equal pool.__send__(:__queue__).size, 1
|
109
109
|
|
110
|
-
[future1, dependent_futures, future2, future3].flatten.each { |f| f.
|
110
|
+
[future1, dependent_futures, future2, future3].flatten.each { |f| f.value }
|
111
111
|
pool.join
|
112
112
|
end
|
113
113
|
|
@@ -115,12 +115,12 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
115
115
|
pool = ThreadPool.new(5)
|
116
116
|
|
117
117
|
common_dependency_a = pool.future { sleep 0.2 }
|
118
|
-
futures_a = 10.times.collect { pool.future{ common_dependency_a.
|
118
|
+
futures_a = 10.times.collect { pool.future{ common_dependency_a.value; sleep(rand() * 0.01) } }
|
119
119
|
|
120
|
-
common_dependency_b = pool.future { futures_a.each { |f| f.
|
121
|
-
futures_b = 10.times.collect { pool.future{ common_dependency_b.
|
120
|
+
common_dependency_b = pool.future { futures_a.each { |f| f.value } }
|
121
|
+
futures_b = 10.times.collect { pool.future{ common_dependency_b.value; sleep(rand() * 0.01) } }
|
122
122
|
|
123
|
-
futures_b.each{|f|f.
|
123
|
+
futures_b.each{|f|f.value}
|
124
124
|
pool.join
|
125
125
|
end
|
126
126
|
|
@@ -135,9 +135,9 @@ class TestRakeTestThreadPool < Rake::TestCase
|
|
135
135
|
pool.future do
|
136
136
|
b.times.collect do
|
137
137
|
pool.future { sleep rand * 0.001; c }
|
138
|
-
end.inject(0) { |m,f| m+f.
|
138
|
+
end.inject(0) { |m,f| m+f.value }
|
139
139
|
end
|
140
|
-
end.inject(0) { |m,f| m+f.
|
140
|
+
end.inject(0) { |m,f| m+f.value }
|
141
141
|
|
142
142
|
assert_equal( (a*b*c), result )
|
143
143
|
pool.join
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
require 'rake/thread_history_display'
|
4
|
+
|
5
|
+
class TestThreadHistoryDisplay < Rake::TestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@time = 1000000
|
9
|
+
@stats = []
|
10
|
+
@display = Rake::ThreadHistoryDisplay.new(@stats)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_banner
|
14
|
+
out, _ = capture_io do
|
15
|
+
@display.show
|
16
|
+
end
|
17
|
+
assert_match(/Job History/i, out)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_item_queued
|
21
|
+
@stats << event(:item_queued, item_id: 123)
|
22
|
+
out, _ = capture_io do
|
23
|
+
@display.show
|
24
|
+
end
|
25
|
+
assert_match(/^ *1000000 +A +item_queued +item_id:1$/, out)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_item_dequeued
|
29
|
+
@stats << event(:item_dequeued, item_id: 123)
|
30
|
+
out, _ = capture_io do
|
31
|
+
@display.show
|
32
|
+
end
|
33
|
+
assert_match(/^ *1000000 +A +item_dequeued +item_id:1$/, out)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_multiple_items
|
37
|
+
@stats << event(:item_queued, item_id: 123)
|
38
|
+
@stats << event(:item_queued, item_id: 124)
|
39
|
+
out, _ = capture_io do
|
40
|
+
@display.show
|
41
|
+
end
|
42
|
+
assert_match(/^ *1000000 +A +item_queued +item_id:1$/, out)
|
43
|
+
assert_match(/^ *1000001 +A +item_queued +item_id:2$/, out)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_waiting
|
47
|
+
@stats << event(:waiting, item_id: 123)
|
48
|
+
out, _ = capture_io do
|
49
|
+
@display.show
|
50
|
+
end
|
51
|
+
assert_match(/^ *1000000 +A +waiting +item_id:1$/, out)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_continue
|
55
|
+
@stats << event(:continue, item_id: 123)
|
56
|
+
out, _ = capture_io do
|
57
|
+
@display.show
|
58
|
+
end
|
59
|
+
assert_match(/^ *1000000 +A +continue +item_id:1$/, out)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_thread_deleted
|
63
|
+
@stats << event(:thread_deleted, deleted_thread: 123456, thread_count: 12)
|
64
|
+
out, _ = capture_io do
|
65
|
+
@display.show
|
66
|
+
end
|
67
|
+
assert_match(/^ *1000000 +A +thread_deleted +deleted_thread:B +thread_count:12$/, out)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_thread_created
|
71
|
+
@stats << event(:thread_created, new_thread: 123456, thread_count: 13)
|
72
|
+
out, _ = capture_io do
|
73
|
+
@display.show
|
74
|
+
end
|
75
|
+
assert_match(/^ *1000000 +A +thread_created +new_thread:B +thread_count:13$/, out)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def event(type, data={})
|
81
|
+
result = {
|
82
|
+
event: type,
|
83
|
+
time: @time / 1_000_000.0,
|
84
|
+
data: data,
|
85
|
+
thread: Thread.current.object_id
|
86
|
+
}
|
87
|
+
@time += 1
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.3.beta.
|
4
|
+
version: 0.9.3.beta.3
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- lib/rake/task_manager.rb
|
121
121
|
- lib/rake/tasklib.rb
|
122
122
|
- lib/rake/testtask.rb
|
123
|
+
- lib/rake/thread_history_display.rb
|
123
124
|
- lib/rake/thread_pool.rb
|
124
125
|
- lib/rake/version.rb
|
125
126
|
- lib/rake/win32.rb
|
@@ -168,6 +169,7 @@ files:
|
|
168
169
|
- test/test_rake_top_level_functions.rb
|
169
170
|
- test/test_rake_win32.rb
|
170
171
|
- test/test_sys.rb
|
172
|
+
- test/test_thread_history_display.rb
|
171
173
|
- doc/command_line_usage.rdoc
|
172
174
|
- doc/example/Rakefile1
|
173
175
|
- doc/example/Rakefile2
|