drake 0.8.4.1.1.0 → 0.8.4.1.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.
- 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
|