drake 0.8.4.1.1.0 → 0.8.4.1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.drake +4 -0
- data/README +2 -85
- data/Rakefile +8 -15
- data/doc/command_line_usage.rdoc +9 -0
- data/doc/parallel.rdoc +112 -0
- data/doc/rakefile.rdoc +6 -0
- data/install.rb +1 -1
- data/lib/rake.rb +59 -96
- data/lib/rake/parallel.rb +137 -32
- data/test/filecreation.rb +12 -0
- data/test/parallel_setup.rb +3 -0
- data/test/rake_test_setup.rb +21 -0
- data/test/serial_setup.rb +3 -0
- data/test/test_application.rb +8 -0
- data/test/test_definitions.rb +6 -2
- data/test/test_file_task.rb +49 -3
- data/test/test_multitask.rb +1 -1
- data/test/test_parallel.rb +177 -38
- data/test/test_require.rb +3 -0
- data/test/test_rules.rb +4 -5
- data/test/test_task_manager.rb +1 -2
- data/test/test_tasks.rb +24 -12
- metadata +25 -21
- data/lib/rake/comp_tree/algorithm.rb +0 -172
- data/lib/rake/comp_tree/comp_tree.rb +0 -42
- data/lib/rake/comp_tree/driver.rb +0 -153
- data/lib/rake/comp_tree/error.rb +0 -23
- data/lib/rake/comp_tree/node.rb +0 -164
- data/test/Rakefile.seq +0 -20
- data/test/Rakefile.simple +0 -18
- data/test/parallel.rb +0 -4
- data/test/single_threaded.rb +0 -3
data/CHANGES.drake
CHANGED
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= DRAKE -- Distributed Rake
|
2
2
|
|
3
|
-
A branch of Rake supporting
|
3
|
+
A branch of Rake supporting automatic parallelizing of tasks.
|
4
4
|
|
5
5
|
== Synopsis
|
6
6
|
|
@@ -18,90 +18,7 @@ or equivalently,
|
|
18
18
|
|
19
19
|
== Notes
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
Drake is 100% compatible with Rake. The code path for
|
24
|
-
<tt>--threads=1</tt> is effectively identical to that of Rake's.
|
25
|
-
Drake passes all of Rake's unit tests, with any number of threads from
|
26
|
-
1 to 1000 (the most tested).
|
27
|
-
|
28
|
-
=== Dependencies
|
29
|
-
|
30
|
-
In a given Rakefile, it is possible (even likely) that the
|
31
|
-
dependency tree has not been properly defined. Consider
|
32
|
-
|
33
|
-
task :a => [:x, :y, :z]
|
34
|
-
|
35
|
-
With single-threaded Rake, _x_,_y_,_z_ will be invoked <em>in that
|
36
|
-
order</em> before _a_ is invoked (assuming there are no other rules
|
37
|
-
involving these tasks). However with <code>drake -jN</code> (for +N+
|
38
|
-
> 1), one should not expect any particular order of execution. Since
|
39
|
-
there is no dependency specified between _x_,_y_,_z_ above, Drake is
|
40
|
-
free to run them in any order.
|
41
|
-
|
42
|
-
If you wish _x_,_y_,_z_ to be invoked sequentially, then write
|
43
|
-
|
44
|
-
task :a => seq[:x, :y, :z]
|
45
|
-
|
46
|
-
This is shorthand for
|
47
|
-
|
48
|
-
task :a => :z
|
49
|
-
task :z => :y
|
50
|
-
task :y => :x
|
51
|
-
|
52
|
-
Upon invoking _a_, the above rules say: "Can't do _a_ until _z_ is
|
53
|
-
complete; can't do _z_ until _y_ is complete; can't do _y_ until _x_
|
54
|
-
is complete; therefore do _x_." In this fashion the sequence
|
55
|
-
_x_,_y_,_z_ is enforced.
|
56
|
-
|
57
|
-
The problem of insufficient dependencies plagues Makefiles as well,
|
58
|
-
and is sometimes called "not j-safe".
|
59
|
-
|
60
|
-
=== MultiTask
|
61
|
-
|
62
|
-
When more than one thread is given, +multitask+ behaves just like
|
63
|
-
+task+. Those tasks which may properly be run in parallel will be run
|
64
|
-
in parallel; those which cannot, will not. It is not the user's job
|
65
|
-
to decide. In other words, for <tt>-jN</tt> (+N+ > 1), +multitask+ is
|
66
|
-
an alias of +task+.
|
67
|
-
|
68
|
-
For <tt>-j1</tt> (default), +multitask+ behaves as the original.
|
69
|
-
|
70
|
-
=== Task#invoke inside Task#invoke
|
71
|
-
|
72
|
-
Parallelizing code means surrendering control over the
|
73
|
-
micro-management of its execution. Manually invoking tasks inside
|
74
|
-
other tasks is rather contrary to this notion, throwing a monkey
|
75
|
-
wrench into the system. An exception will be raised when this is
|
76
|
-
attempted in multi-threaded mode.
|
77
|
-
|
78
|
-
=== Migrating to -j
|
79
|
-
|
80
|
-
First of all, do you want to bother with <tt>-j</tt>? If you are
|
81
|
-
satisfied with your build time, then there is really no reason to use
|
82
|
-
it.
|
83
|
-
|
84
|
-
If on the other hand your build takes twenty minutes to complete, you
|
85
|
-
may be interested in investing some time getting the full dependency
|
86
|
-
tree correct in order to take advantage of multiple CPUs or cores.
|
87
|
-
|
88
|
-
Though Drake cannot fathom what <em>you</em> mean by a correct
|
89
|
-
dependency, there is a tool available which may help you get closer to
|
90
|
-
saying what you mean:
|
91
|
-
|
92
|
-
% drake --rand[=SEED]
|
93
|
-
|
94
|
-
This will randomize the order of sibling prerequisites for each task.
|
95
|
-
When given the optional SEED string, it will call
|
96
|
-
<tt>srand(SEED.hash)</tt> to produce the same permutation each time.
|
97
|
-
The randomize option also disables +multitask+, making it a regular
|
98
|
-
+task+. (In multi-threaded mode, +multitask+ is already a regular
|
99
|
-
+task+.)
|
100
|
-
|
101
|
-
Though this option may produce an error due to unspecified
|
102
|
-
dependencies, with SEED at least it will be an error which is exactly
|
103
|
-
the same on each run. In addition you'll have the major debugging
|
104
|
-
advantage of using a single thread.
|
21
|
+
See parallel.rdoc.
|
105
22
|
|
106
23
|
== Links
|
107
24
|
|
data/Rakefile
CHANGED
@@ -63,23 +63,22 @@ task :tf => :test_functional
|
|
63
63
|
task :tu => :test_units
|
64
64
|
task :tc => :test_contribs
|
65
65
|
task :test => :test_units
|
66
|
+
task :test_all => [:test_serial, :test_parallel]
|
66
67
|
|
67
|
-
|
68
|
+
test_files = FileList[
|
68
69
|
'test/test*.rb',
|
69
70
|
'test/contrib/test*.rb',
|
70
71
|
'test/fun*.rb'
|
71
72
|
]
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
Rake::TestTask.new(:test_parallel) do |t|
|
76
|
-
t.test_files = FileList['test/parallel.rb'] + all_test_files
|
74
|
+
Rake::TestTask.new(:test_serial) do |t|
|
75
|
+
t.test_files = ['test/serial_setup.rb'] + test_files
|
77
76
|
t.warning = true
|
78
77
|
t.verbose = false
|
79
78
|
end
|
80
79
|
|
81
|
-
Rake::TestTask.new(:
|
82
|
-
t.test_files =
|
80
|
+
Rake::TestTask.new(:test_parallel) do |t|
|
81
|
+
t.test_files = ['test/parallel_setup.rb'] + test_files
|
83
82
|
t.warning = true
|
84
83
|
t.verbose = false
|
85
84
|
end
|
@@ -102,12 +101,6 @@ Rake::TestTask.new(:test_contribs) do |t|
|
|
102
101
|
t.verbose = false
|
103
102
|
end
|
104
103
|
|
105
|
-
Rake::TestTask.new(:test_current) do |t|
|
106
|
-
t.test_files = FileList['test/parallel.rb', 'test/test_tasks.rb']
|
107
|
-
t.warning = true
|
108
|
-
t.verbose = false
|
109
|
-
end
|
110
|
-
|
111
104
|
begin
|
112
105
|
require 'rcov/rcovtask'
|
113
106
|
|
@@ -167,7 +160,6 @@ PKG_FILES = FileList[
|
|
167
160
|
'[A-Z]*',
|
168
161
|
'bin/drake',
|
169
162
|
'lib/**/*.rb',
|
170
|
-
'lib/rake/comp_tree/**/*.rb',
|
171
163
|
'test/**/*.rb',
|
172
164
|
'test/**/*.rf',
|
173
165
|
'test/**/*.mf',
|
@@ -187,7 +179,7 @@ else
|
|
187
179
|
|
188
180
|
s.name = 'drake'
|
189
181
|
s.version = $package_version
|
190
|
-
s.summary = "A
|
182
|
+
s.summary = "A branch of Rake supporting automatic parallelizing of tasks."
|
191
183
|
s.description = <<-EOF
|
192
184
|
Rake is a Make-like program implemented in Ruby. Tasks
|
193
185
|
and dependencies are specified in standard Ruby syntax.
|
@@ -195,6 +187,7 @@ else
|
|
195
187
|
|
196
188
|
#### Dependencies and requirements.
|
197
189
|
|
190
|
+
s.add_dependency('comp_tree', '>= 0.7.1')
|
198
191
|
#s.add_dependency('log4r', '> 1.0.4')
|
199
192
|
#s.requirements << ""
|
200
193
|
|
data/doc/command_line_usage.rdoc
CHANGED
@@ -40,6 +40,9 @@ Options are:
|
|
40
40
|
[<tt>--libdir</tt> _directory_ (-I)]
|
41
41
|
Add _directory_ to the list of directories searched for require.
|
42
42
|
|
43
|
+
[<tt>--threads</tt> _number_ (-j)]
|
44
|
+
Run up to N independent tasks simultaneously in separate threads.
|
45
|
+
|
43
46
|
[<tt>--nosearch</tt> (-N)]
|
44
47
|
Do not search for a Rakefile in parent directories.
|
45
48
|
|
@@ -60,6 +63,12 @@ Options are:
|
|
60
63
|
[<tt>--rakelibdir</tt> _rakelibdir_ (-R)]
|
61
64
|
Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')
|
62
65
|
|
66
|
+
[<tt>--randomize</tt>[=_seed_]]
|
67
|
+
Randomize the order of sibling prerequisites for each task. When
|
68
|
+
_seed_ is given, <tt>srand(seed.hash)</tt> will be called so that
|
69
|
+
the same permutations will be produced for subsequent runs with
|
70
|
+
the same _seed_.
|
71
|
+
|
63
72
|
[<tt>--require</tt> _name_ (-r)]
|
64
73
|
Require _name_ before executing the Rakefile.
|
65
74
|
|
data/doc/parallel.rdoc
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
|
2
|
+
= Automatically Running Tasks in Parallel
|
3
|
+
|
4
|
+
Consider these task definitions:
|
5
|
+
|
6
|
+
task :default => [:a, :b]
|
7
|
+
task :a => [:x, :y]
|
8
|
+
task :b
|
9
|
+
|
10
|
+
To create the dependency graph, let nodes represent tasks and child
|
11
|
+
nodes represent prerequisites,
|
12
|
+
|
13
|
+
default
|
14
|
+
/ \
|
15
|
+
/ \
|
16
|
+
a b
|
17
|
+
/ \
|
18
|
+
/ \
|
19
|
+
x y
|
20
|
+
|
21
|
+
Notice the dependency graph already contains the information necessary
|
22
|
+
for parallelizing tasks. In particular, tasks _x_, _y_, and _b_ may
|
23
|
+
run in parallel. When _x_ and _y_ are finished, _a_ and _b_ may run
|
24
|
+
in parallel.
|
25
|
+
|
26
|
+
So why, then, does +multitask+ exist? Rake already has the
|
27
|
+
information it needs -- why must we provide it a second time? The
|
28
|
+
short answer is probably that +multitask+ was easy to implement, while
|
29
|
+
dynamically finding parallelizable tasks and safely executing them in
|
30
|
+
separate threads requires a little more code.
|
31
|
+
|
32
|
+
Rake now supports the -j option which does exactly this. To run up to
|
33
|
+
three tasks in parallel,
|
34
|
+
|
35
|
+
% rake -j3
|
36
|
+
|
37
|
+
or equivalently,
|
38
|
+
|
39
|
+
% rake --threads 3
|
40
|
+
|
41
|
+
== A Note on Dependencies
|
42
|
+
|
43
|
+
Without +multitask+ or -j (or --randomize, explained below), Rake
|
44
|
+
invokes tasks in a predetermined order. Rakefile authors inevitably
|
45
|
+
come to rely on this order. Even though their dependency graph may be
|
46
|
+
wide and hierarchical, the only graph which has ever been tested is
|
47
|
+
linear: one which results from visiting each node in sequence.
|
48
|
+
|
49
|
+
Consider
|
50
|
+
|
51
|
+
task :a => [:x, :y, :z]
|
52
|
+
|
53
|
+
When Rake runs in single-threaded mode (the default), _x_,_y_,_z_ will
|
54
|
+
be invoked <em>in that order</em> before _a_ is invoked, assuming no
|
55
|
+
other rules exist involving these tasks. However with -j _N_ for
|
56
|
+
_N_ > 1, one should not expect any particular order of execution.
|
57
|
+
Since there is no dependency specified between _x_,_y_,_z_ above, Rake
|
58
|
+
is free to run them in any order.
|
59
|
+
|
60
|
+
The problem of underspecified dependencies plagues Makefiles as well
|
61
|
+
(GNU make has supported -j for some time).
|
62
|
+
|
63
|
+
== Migrating to -j
|
64
|
+
|
65
|
+
Suppose -j produces errors from insufficient dependencies in your
|
66
|
+
Rakefile. Do you want to bother fixing them? If you are satisfied
|
67
|
+
with your build time, then there is really no reason to use -j.
|
68
|
+
|
69
|
+
If on the other hand your build takes twenty minutes to complete, you
|
70
|
+
may be interested in getting the full dependency graph correct in
|
71
|
+
order to take advantage of multiple CPUs or cores.
|
72
|
+
|
73
|
+
Though Rake cannot fathom what <em>you</em> mean by a correct
|
74
|
+
dependency, there is a tool available which may help you get closer to
|
75
|
+
saying what you mean:
|
76
|
+
|
77
|
+
% rake --randomize[=SEED]
|
78
|
+
|
79
|
+
This will randomize the order of sibling prerequisites for each task.
|
80
|
+
When SEED is given, <tt>srand(SEED.hash)</tt> will be called so that
|
81
|
+
the same permutations will be produced for subsequent runs with the
|
82
|
+
same SEED.
|
83
|
+
|
84
|
+
Though this option may cause an error due to underspecified
|
85
|
+
dependencies, with SEED at least it will be an error which is exactly
|
86
|
+
the same on each run. In addition you'll have the major debugging
|
87
|
+
advantage of using a single thread.
|
88
|
+
|
89
|
+
== Task#invoke inside Task#invoke
|
90
|
+
|
91
|
+
Parallelizing tasks means surrendering control over the
|
92
|
+
micro-management of their execution. Manually invoking tasks inside
|
93
|
+
other tasks is rather contrary to this notion, throwing a monkey
|
94
|
+
wrench into the system. An exception will be raised when this is
|
95
|
+
attempted in -j mode.
|
96
|
+
|
97
|
+
== What is the Difference Between -j and Multitask?
|
98
|
+
|
99
|
+
What if you replaced +task+ with +multitask+ everywhere in your
|
100
|
+
Rakefile? Isn't that the same as -j?
|
101
|
+
|
102
|
+
It is effectively the same when the number of tasks is small. However
|
103
|
+
an all-multitask Rakefile becomes problematic as the number of tasks
|
104
|
+
and dependencies increase. The number of lines in the dependency
|
105
|
+
graph would be equal to the number of threads running simultaneously.
|
106
|
+
Multitask blindly fires off N threads for the N prerequisites of a
|
107
|
+
task.
|
108
|
+
|
109
|
+
A simplistic +multitask+ setup for compiling 100 C files might spawn
|
110
|
+
100 threads running 100 compiler processes all at the same time. To
|
111
|
+
reduce the load you could make several reasonably-sized multitasks
|
112
|
+
then tie them together with a regular +task+. Or you could just use -j.
|
data/doc/rakefile.rdoc
CHANGED
@@ -150,6 +150,12 @@ to do extra synchronization for Rake's benefit. However, if there are
|
|
150
150
|
user data structures shared between the parallel prerequisites, the
|
151
151
|
user must do whatever is necessary to prevent race conditions.
|
152
152
|
|
153
|
+
=== Automatically Running Tasks in Parallel
|
154
|
+
|
155
|
+
Rake now supports the command-line option -j for automatically
|
156
|
+
detecting non-dependent tasks and safely executing them in parallel.
|
157
|
+
See parallel.rdoc.
|
158
|
+
|
153
159
|
== Tasks with Arguments
|
154
160
|
|
155
161
|
Prior to version 0.8.0, rake was only able to handle command line
|
data/install.rb
CHANGED
data/lib/rake.rb
CHANGED
@@ -29,7 +29,7 @@
|
|
29
29
|
# as a library via a require statement, but it can be distributed
|
30
30
|
# independently as an application.
|
31
31
|
|
32
|
-
RAKEVERSION = '0.8.4.1.
|
32
|
+
RAKEVERSION = '0.8.4.1.2.0'
|
33
33
|
|
34
34
|
require 'rbconfig'
|
35
35
|
require 'fileutils'
|
@@ -37,7 +37,6 @@ require 'singleton'
|
|
37
37
|
require 'monitor'
|
38
38
|
require 'optparse'
|
39
39
|
require 'ostruct'
|
40
|
-
require 'rake/parallel'
|
41
40
|
|
42
41
|
require 'rake/win32'
|
43
42
|
|
@@ -408,13 +407,13 @@ module Rake
|
|
408
407
|
# InvocationChain tracks the chain of task invocations to detect
|
409
408
|
# circular dependencies.
|
410
409
|
class InvocationChain
|
410
|
+
attr_reader :value # :nodoc:
|
411
|
+
|
411
412
|
def initialize(value, tail)
|
412
413
|
@value = value
|
413
414
|
@tail = tail
|
414
415
|
end
|
415
416
|
|
416
|
-
attr_reader :value # :nodoc:
|
417
|
-
|
418
417
|
def member?(obj)
|
419
418
|
@value == obj || @tail.member?(obj)
|
420
419
|
end
|
@@ -580,74 +579,46 @@ module Rake
|
|
580
579
|
self
|
581
580
|
end
|
582
581
|
|
583
|
-
def
|
582
|
+
def invoke_serial(*args) # :nodoc:
|
584
583
|
task_args = TaskArguments.new(arg_names, args)
|
585
584
|
invoke_with_call_chain(task_args, InvocationChain::EMPTY)
|
586
585
|
end
|
587
586
|
|
588
587
|
# Invoke the task if it is needed. Prerequites are invoked first.
|
589
588
|
def invoke(*args)
|
590
|
-
if application.
|
591
|
-
|
589
|
+
if application.options.threads == 1
|
590
|
+
invoke_serial(*args)
|
592
591
|
else
|
593
|
-
|
594
|
-
raise "Calling Task#invoke within a task is not allowed."
|
595
|
-
end
|
596
|
-
application.parallel.lock.synchronize {
|
597
|
-
application.parallel.tasks.clear
|
598
|
-
application.parallel.needed.clear
|
599
|
-
base_invoke(*args)
|
600
|
-
application.invoke_parallel(self.name)
|
601
|
-
}
|
592
|
+
invoke_parallel(*args)
|
602
593
|
end
|
603
594
|
end
|
604
|
-
|
595
|
+
|
605
596
|
# Same as invoke, but explicitly pass a call chain to detect
|
606
597
|
# circular dependencies.
|
607
598
|
def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
|
608
599
|
new_chain = InvocationChain.append(self, invocation_chain)
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
end
|
613
|
-
return if @already_invoked
|
614
|
-
@already_invoked = true
|
615
|
-
|
616
|
-
if application.options.randomize
|
617
|
-
@prerequisites = @prerequisites.sort_by { rand }
|
618
|
-
end
|
619
|
-
|
620
|
-
if application.num_threads == 1
|
600
|
+
if application.options.threads == 1
|
601
|
+
@lock.synchronize do
|
602
|
+
return unless prepare_invoke
|
621
603
|
invoke_prerequisites(task_args, new_chain)
|
622
604
|
execute(task_args) if needed?
|
623
|
-
else
|
624
|
-
#
|
625
|
-
# Parallel mode -- gather tasks for batch execution.
|
626
|
-
#
|
627
|
-
# Either the task knows it's needed or we've marked it as
|
628
|
-
# needed.
|
629
|
-
#
|
630
|
-
# Why do we manually mark tasks as needed? Since this is a
|
631
|
-
# dry run, files are not created or modified. Therefore the
|
632
|
-
# 'needed?' result does not propagate through the recursion.
|
633
|
-
#
|
634
|
-
prereqs = invoke_prerequisites_parallel(task_args, new_chain)
|
635
|
-
if needed? or application.parallel.needed[self]
|
636
|
-
application.parallel.tasks[name] = [task_args, prereqs]
|
637
|
-
unless invocation_chain == InvocationChain::EMPTY
|
638
|
-
application.parallel.needed[invocation_chain.value] = true
|
639
|
-
end
|
640
|
-
end
|
641
605
|
end
|
606
|
+
else
|
607
|
+
return unless prepare_invoke
|
608
|
+
invoke_with_call_chain_collector(task_args, new_chain, invocation_chain)
|
642
609
|
end
|
643
610
|
end
|
644
611
|
protected :invoke_with_call_chain
|
645
612
|
|
646
|
-
def
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
613
|
+
def prepare_invoke # :nodoc:
|
614
|
+
if application.options.randomize
|
615
|
+
@prerequisites = @prerequisites.sort_by { rand }
|
616
|
+
end
|
617
|
+
if application.options.trace
|
618
|
+
puts "** Invoke #{name} #{format_trace_flags}"
|
619
|
+
end
|
620
|
+
return if @already_invoked
|
621
|
+
@already_invoked = true
|
651
622
|
end
|
652
623
|
|
653
624
|
# Invoke all the prerequisites of a task.
|
@@ -657,14 +628,13 @@ module Rake
|
|
657
628
|
}
|
658
629
|
end
|
659
630
|
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
}
|
631
|
+
def invoke_prerequisite(prereq_name, task_args, invocation_chain) #:nodoc:
|
632
|
+
prereq = application[prereq_name, @scope]
|
633
|
+
prereq_args = task_args.new_scope(prereq.arg_names)
|
634
|
+
prereq.invoke_with_call_chain(prereq_args, invocation_chain)
|
635
|
+
prereq
|
666
636
|
end
|
667
|
-
|
637
|
+
|
668
638
|
# Format the trace flags for display.
|
669
639
|
def format_trace_flags
|
670
640
|
flags = []
|
@@ -1009,21 +979,6 @@ def import(*fns)
|
|
1009
979
|
end
|
1010
980
|
end
|
1011
981
|
|
1012
|
-
#
|
1013
|
-
# +seq+ : Force tasks to be executed sequentially.
|
1014
|
-
#
|
1015
|
-
def seq
|
1016
|
-
Rake::SEQ_LAMBDA
|
1017
|
-
end
|
1018
|
-
module Rake
|
1019
|
-
SEQ_LAMBDA = lambda { |*task_names|
|
1020
|
-
(1...task_names.size).each { |n|
|
1021
|
-
task task_names[n] => task_names[n - 1]
|
1022
|
-
}
|
1023
|
-
task_names.last
|
1024
|
-
}
|
1025
|
-
end
|
1026
|
-
|
1027
982
|
# ###########################################################################
|
1028
983
|
# This a FileUtils extension that defines several additional commands to be
|
1029
984
|
# added to the FileUtils utility functions.
|
@@ -1754,22 +1709,12 @@ module Rake
|
|
1754
1709
|
attr_accessor :last_description
|
1755
1710
|
alias :last_comment :last_description # Backwards compatibility
|
1756
1711
|
|
1757
|
-
attr_accessor :num_threads
|
1758
|
-
attr_reader :parallel
|
1759
|
-
|
1760
1712
|
def initialize
|
1761
1713
|
super
|
1762
1714
|
@tasks = Hash.new
|
1763
1715
|
@rules = Array.new
|
1764
1716
|
@scope = Array.new
|
1765
1717
|
@last_description = nil
|
1766
|
-
|
1767
|
-
@num_threads = 1
|
1768
|
-
|
1769
|
-
@parallel = Struct.new(:tasks, :needed, :lock).new
|
1770
|
-
@parallel.tasks = Hash.new
|
1771
|
-
@parallel.needed = Hash.new
|
1772
|
-
@parallel.lock = Mutex.new
|
1773
1718
|
end
|
1774
1719
|
|
1775
1720
|
def create_rule(*args, &block)
|
@@ -2024,6 +1969,26 @@ module Rake
|
|
2024
1969
|
|
2025
1970
|
end # TaskManager
|
2026
1971
|
|
1972
|
+
#
|
1973
|
+
# Lazily pull in the parallelizing code
|
1974
|
+
#
|
1975
|
+
class Options < OpenStruct # :nodoc:
|
1976
|
+
attr_reader :threads
|
1977
|
+
|
1978
|
+
def initialize
|
1979
|
+
super
|
1980
|
+
@threads = 1
|
1981
|
+
end
|
1982
|
+
|
1983
|
+
def threads=(n)
|
1984
|
+
if n > 1 and require('rake/parallel')
|
1985
|
+
Task.module_eval { include Parallel::TaskMixin }
|
1986
|
+
Application.module_eval { include Parallel::ApplicationMixin }
|
1987
|
+
end
|
1988
|
+
@threads = n
|
1989
|
+
end
|
1990
|
+
end
|
1991
|
+
|
2027
1992
|
######################################################################
|
2028
1993
|
# Rake main application object. When invoking +rake+ from the
|
2029
1994
|
# command line, a Rake::Application object is created and run.
|
@@ -2118,7 +2083,7 @@ module Rake
|
|
2118
2083
|
|
2119
2084
|
# Application options from the command line
|
2120
2085
|
def options
|
2121
|
-
@options ||=
|
2086
|
+
@options ||= Options.new
|
2122
2087
|
end
|
2123
2088
|
|
2124
2089
|
# private ----------------------------------------------------------------
|
@@ -2306,17 +2271,8 @@ module Rake
|
|
2306
2271
|
"Execute some Ruby code, then continue with normal task processing.",
|
2307
2272
|
lambda { |value| eval(value) }
|
2308
2273
|
],
|
2309
|
-
['--threads', '-j N', "
|
2310
|
-
lambda { |value|
|
2311
|
-
],
|
2312
|
-
['--randomize[=SEED]', "Randomize task prerequisite orders",
|
2313
|
-
lambda { |value|
|
2314
|
-
MultiTask.class_eval { remove_method(:invoke_prerequisites) }
|
2315
|
-
options.randomize = true
|
2316
|
-
if value
|
2317
|
-
srand(value.hash)
|
2318
|
-
end
|
2319
|
-
}
|
2274
|
+
['--threads', '-j N', "Run up to N independent tasks simultaneously in separate threads.",
|
2275
|
+
lambda { |value| options.threads = value.to_i }
|
2320
2276
|
],
|
2321
2277
|
['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
|
2322
2278
|
lambda { |value| $:.push(value) }
|
@@ -2338,6 +2294,13 @@ module Rake
|
|
2338
2294
|
"Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')",
|
2339
2295
|
lambda { |value| options.rakelib = value.split(':') }
|
2340
2296
|
],
|
2297
|
+
['--randomize[=SEED]', "Randomize the order of sibling prerequisites.",
|
2298
|
+
lambda { |value|
|
2299
|
+
options.randomize = true
|
2300
|
+
MultiTask.class_eval { remove_method(:invoke_prerequisites) }
|
2301
|
+
srand(value.hash) if value
|
2302
|
+
}
|
2303
|
+
],
|
2341
2304
|
['--require', '-r MODULE', "Require MODULE before executing rakefile.",
|
2342
2305
|
lambda { |value|
|
2343
2306
|
begin
|