drake 0.8.1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +386 -0
- data/MIT-LICENSE +21 -0
- data/README +396 -0
- data/Rakefile +505 -0
- data/TODO +20 -0
- data/bin/drake +31 -0
- data/bin/rake +31 -0
- data/doc/example/Rakefile1 +38 -0
- data/doc/example/Rakefile2 +35 -0
- data/doc/example/a.c +6 -0
- data/doc/example/b.c +6 -0
- data/doc/example/main.c +11 -0
- data/doc/glossary.rdoc +51 -0
- data/doc/jamis.rb +591 -0
- data/doc/proto_rake.rdoc +127 -0
- data/doc/rake.1.gz +0 -0
- data/doc/rakefile.rdoc +534 -0
- data/doc/rational.rdoc +151 -0
- data/doc/release_notes/rake-0.4.14.rdoc +23 -0
- data/doc/release_notes/rake-0.4.15.rdoc +35 -0
- data/doc/release_notes/rake-0.5.0.rdoc +53 -0
- data/doc/release_notes/rake-0.5.3.rdoc +78 -0
- data/doc/release_notes/rake-0.5.4.rdoc +46 -0
- data/doc/release_notes/rake-0.6.0.rdoc +141 -0
- data/doc/release_notes/rake-0.7.0.rdoc +119 -0
- data/doc/release_notes/rake-0.7.1.rdoc +59 -0
- data/doc/release_notes/rake-0.7.2.rdoc +121 -0
- data/doc/release_notes/rake-0.7.3.rdoc +47 -0
- data/doc/release_notes/rake-0.8.0.rdoc +114 -0
- data/doc/release_notes/rake-0.8.2.rdoc +163 -0
- data/install.rb +88 -0
- data/lib/rake.rb +2538 -0
- data/lib/rake/classic_namespace.rb +8 -0
- data/lib/rake/clean.rb +33 -0
- data/lib/rake/comp_tree/algorithm.rb +234 -0
- data/lib/rake/comp_tree/bucket_ipc.rb +175 -0
- data/lib/rake/comp_tree/driver.rb +291 -0
- data/lib/rake/comp_tree/error.rb +51 -0
- data/lib/rake/comp_tree/node.rb +189 -0
- data/lib/rake/comp_tree/quix/builtin/kernel/tap.rb +57 -0
- data/lib/rake/comp_tree/quix/diagnostic.rb +92 -0
- data/lib/rake/comp_tree/quix/kernel.rb +109 -0
- data/lib/rake/comp_tree/retriable_fork.rb +66 -0
- data/lib/rake/comp_tree/task_node.rb +46 -0
- data/lib/rake/contrib/compositepublisher.rb +24 -0
- data/lib/rake/contrib/ftptools.rb +153 -0
- data/lib/rake/contrib/publisher.rb +75 -0
- data/lib/rake/contrib/rubyforgepublisher.rb +18 -0
- data/lib/rake/contrib/sshpublisher.rb +47 -0
- data/lib/rake/contrib/sys.rb +209 -0
- data/lib/rake/gempackagetask.rb +103 -0
- data/lib/rake/loaders/makefile.rb +35 -0
- data/lib/rake/packagetask.rb +185 -0
- data/lib/rake/parallel.rb +54 -0
- data/lib/rake/rake_test_loader.rb +5 -0
- data/lib/rake/rdoctask.rb +147 -0
- data/lib/rake/ruby182_test_unit_fix.rb +23 -0
- data/lib/rake/runtest.rb +23 -0
- data/lib/rake/tasklib.rb +23 -0
- data/lib/rake/testtask.rb +161 -0
- data/test/capture_stdout.rb +26 -0
- data/test/check_expansion.rb +5 -0
- data/test/contrib/test_sys.rb +47 -0
- data/test/data/chains/Rakefile +15 -0
- data/test/data/default/Rakefile +19 -0
- data/test/data/dryrun/Rakefile +22 -0
- data/test/data/file_creation_task/Rakefile +33 -0
- data/test/data/imports/Rakefile +19 -0
- data/test/data/imports/deps.mf +1 -0
- data/test/data/multidesc/Rakefile +17 -0
- data/test/data/namespace/Rakefile +57 -0
- data/test/data/rakelib/test1.rb +3 -0
- data/test/data/rbext/rakefile.rb +3 -0
- data/test/data/sample.mf +12 -0
- data/test/data/statusreturn/Rakefile +8 -0
- data/test/data/unittest/Rakefile +1 -0
- data/test/filecreation.rb +32 -0
- data/test/functional.rb +15 -0
- data/test/in_environment.rb +30 -0
- data/test/parallel.rb +3 -0
- data/test/rake_test_setup.rb +5 -0
- data/test/reqfile.rb +3 -0
- data/test/reqfile2.rb +3 -0
- data/test/session_functional.rb +324 -0
- data/test/shellcommand.rb +3 -0
- data/test/single_threaded.rb +2 -0
- data/test/test_application.rb +714 -0
- data/test/test_clean.rb +14 -0
- data/test/test_definitions.rb +82 -0
- data/test/test_earlytime.rb +35 -0
- data/test/test_extension.rb +63 -0
- data/test/test_file_creation_task.rb +62 -0
- data/test/test_file_task.rb +139 -0
- data/test/test_filelist.rb +618 -0
- data/test/test_fileutils.rb +250 -0
- data/test/test_ftp.rb +59 -0
- data/test/test_invocation_chain.rb +75 -0
- data/test/test_makefile_loader.rb +25 -0
- data/test/test_namespace.rb +36 -0
- data/test/test_package_task.rb +116 -0
- data/test/test_parallel.rb +47 -0
- data/test/test_pathmap.rb +209 -0
- data/test/test_rake.rb +41 -0
- data/test/test_require.rb +33 -0
- data/test/test_rules.rb +348 -0
- data/test/test_task_arguments.rb +89 -0
- data/test/test_task_manager.rb +172 -0
- data/test/test_tasklib.rb +12 -0
- data/test/test_tasks.rb +373 -0
- data/test/test_test_task.rb +75 -0
- data/test/test_top_level_functions.rb +84 -0
- metadata +190 -0
data/doc/proto_rake.rdoc
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
= Original Prototype Rake
|
2
|
+
|
3
|
+
This is the original 100 line prototype rake program.
|
4
|
+
|
5
|
+
---
|
6
|
+
#!/usr/bin/env ruby
|
7
|
+
|
8
|
+
require 'ftools'
|
9
|
+
|
10
|
+
class Task
|
11
|
+
TASKS = Hash.new
|
12
|
+
|
13
|
+
attr_reader :prerequisites
|
14
|
+
|
15
|
+
def initialize(task_name)
|
16
|
+
@name = task_name
|
17
|
+
@prerequisites = []
|
18
|
+
@actions = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def enhance(deps=nil, &block)
|
22
|
+
@prerequisites |= deps if deps
|
23
|
+
@actions << block if block_given?
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
@name.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def invoke
|
32
|
+
@prerequisites.each { |n| Task[n].invoke }
|
33
|
+
execute if needed?
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute
|
37
|
+
return if @triggered
|
38
|
+
@triggered = true
|
39
|
+
@actions.collect { |act| result = act.call(self) }.last
|
40
|
+
end
|
41
|
+
|
42
|
+
def needed?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def timestamp
|
47
|
+
Time.now
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
def [](task_name)
|
52
|
+
TASKS[intern(task_name)] or fail "Don't know how to rake #{task_name}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def define_task(args, &block)
|
56
|
+
case args
|
57
|
+
when Hash
|
58
|
+
fail "Too Many Target Names: #{args.keys.join(' ')}" if args.size > 1
|
59
|
+
fail "No Task Name Given" if args.size < 1
|
60
|
+
task_name = args.keys[0]
|
61
|
+
deps = args[task_name]
|
62
|
+
else
|
63
|
+
task_name = args
|
64
|
+
deps = []
|
65
|
+
end
|
66
|
+
deps = deps.collect {|d| intern(d) }
|
67
|
+
get(task_name).enhance(deps, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get(task_name)
|
71
|
+
name = intern(task_name)
|
72
|
+
TASKS[name] ||= self.new(name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def intern(task_name)
|
76
|
+
(Symbol === task_name) ? task_name : task_name.intern
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class FileTask < Task
|
82
|
+
def needed?
|
83
|
+
return true unless File.exist?(name)
|
84
|
+
latest_prereq = @prerequisites.collect{|n| Task[n].timestamp}.max
|
85
|
+
return false if latest_prereq.nil?
|
86
|
+
timestamp < latest_prereq
|
87
|
+
end
|
88
|
+
|
89
|
+
def timestamp
|
90
|
+
File.new(name.to_s).mtime
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def task(args, &block)
|
95
|
+
Task.define_task(args, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def file(args, &block)
|
99
|
+
FileTask.define_task(args, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def sys(cmd)
|
103
|
+
puts cmd
|
104
|
+
system(cmd) or fail "Command Failed: [#{cmd}]"
|
105
|
+
end
|
106
|
+
|
107
|
+
def rake
|
108
|
+
begin
|
109
|
+
here = Dir.pwd
|
110
|
+
while ! File.exist?("Rakefile")
|
111
|
+
Dir.chdir("..")
|
112
|
+
fail "No Rakefile found" if Dir.pwd == here
|
113
|
+
here = Dir.pwd
|
114
|
+
end
|
115
|
+
puts "(in #{Dir.pwd})"
|
116
|
+
load "./Rakefile"
|
117
|
+
ARGV.push("default") if ARGV.size == 0
|
118
|
+
ARGV.each { |task_name| Task[task_name].invoke }
|
119
|
+
rescue Exception => ex
|
120
|
+
puts "rake aborted ... #{ex.message}"
|
121
|
+
puts ex.backtrace.find {|str| str =~ /Rakefile/ } || ""
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if __FILE__ == $0 then
|
126
|
+
rake
|
127
|
+
end
|
data/doc/rake.1.gz
ADDED
Binary file
|
data/doc/rakefile.rdoc
ADDED
@@ -0,0 +1,534 @@
|
|
1
|
+
= Rakefile Format (as of version 0.8.2)
|
2
|
+
|
3
|
+
First of all, there is no special format for a Rakefile. A Rakefile
|
4
|
+
contains executable Ruby code. Anything legal in a ruby script is
|
5
|
+
allowed in a Rakefile.
|
6
|
+
|
7
|
+
Now that we understand there is no special syntax in a Rakefile, there
|
8
|
+
are some conventions that are used in a Rakefile that are a little
|
9
|
+
unusual in a typical Ruby program. Since a Rakefile is tailored to
|
10
|
+
specifying tasks and actions, the idioms used in a Rakefile are
|
11
|
+
designed to support that.
|
12
|
+
|
13
|
+
So, what goes into a Rakefile?
|
14
|
+
|
15
|
+
== Tasks
|
16
|
+
|
17
|
+
Tasks are the main unit of work in a Rakefile. Tasks have a name
|
18
|
+
(usually given as a symbol or a string), a list of prerequisites (more
|
19
|
+
symbols or strings) and a list of actions (given as a block).
|
20
|
+
|
21
|
+
=== Simple Tasks
|
22
|
+
|
23
|
+
A task is declared by using the +task+ method. +task+ takes a single
|
24
|
+
parameter that is the name of the task.
|
25
|
+
|
26
|
+
task :name
|
27
|
+
|
28
|
+
=== Tasks with Prerequisites
|
29
|
+
|
30
|
+
Any prerequisites are given as a list (inclosed in square brackets)
|
31
|
+
following the name and an arrow (=>).
|
32
|
+
|
33
|
+
task :name => [:prereq1, :prereq2]
|
34
|
+
|
35
|
+
<b>NOTE:</b> Although this syntax looks a little funky, it is legal
|
36
|
+
Ruby. We are constructing a hash where the key is :name and the value
|
37
|
+
for that key is the list of prerequisites. It is equivalent to the
|
38
|
+
following ...
|
39
|
+
|
40
|
+
hash = Hash.new
|
41
|
+
hash[:name] = [:prereq1, :prereq2]
|
42
|
+
task(hash)
|
43
|
+
|
44
|
+
=== Tasks with Actions
|
45
|
+
|
46
|
+
Actions are defined by passing a block to the +task+ method. Any Ruby
|
47
|
+
code can be placed in the block. The block may reference the task
|
48
|
+
object via the block paramter..
|
49
|
+
|
50
|
+
task :name => [:prereq1, :prereq2] do |t|
|
51
|
+
# actions (may reference t)
|
52
|
+
end
|
53
|
+
|
54
|
+
=== Multiple Definitions
|
55
|
+
|
56
|
+
A task may be specified more than once. Each specification adds its
|
57
|
+
prerequisites and actions to the existing definition. This allows one
|
58
|
+
part of a rakefile to specify the actions and a different rakefile
|
59
|
+
(perhaps separately generated) to specify the dependencies.
|
60
|
+
|
61
|
+
For example, the following is equivalent to the single task
|
62
|
+
specification given above.
|
63
|
+
|
64
|
+
task :name
|
65
|
+
task :name => [:prereq1]
|
66
|
+
task :name => [:prereq2]
|
67
|
+
task :name do |t|
|
68
|
+
# actions
|
69
|
+
end
|
70
|
+
|
71
|
+
== File Tasks
|
72
|
+
|
73
|
+
Some tasks are designed to create a file from one or more other files.
|
74
|
+
Tasks that generate these files may be skipped if the file already
|
75
|
+
exists. File tasks are used to specify file creation tasks.
|
76
|
+
|
77
|
+
File tasks are declared using the +file+ method (instead of the +task+
|
78
|
+
method). In addition, file tasks are usually named with a string
|
79
|
+
rather than a symbol.
|
80
|
+
|
81
|
+
The following file task creates a executable program (named +prog+)
|
82
|
+
given two object files name <tt>a.o</tt> and <tt>b.o</tt>. The tasks
|
83
|
+
for creating <tt>a.o</tt> and <tt>b.o</tt> are not shown.
|
84
|
+
|
85
|
+
file "prog" => ["a.o", "b.o"] do |t|
|
86
|
+
sh "cc -o #{t.name} #{t.prerequisites.join(' ')}"
|
87
|
+
end
|
88
|
+
|
89
|
+
== Directory Tasks
|
90
|
+
|
91
|
+
It is common to need to create directories upon demand. The
|
92
|
+
+directory+ convenience method is a short-hand for creating a FileTask
|
93
|
+
that creates the directory. For example, the following declaration
|
94
|
+
...
|
95
|
+
|
96
|
+
directory "testdata/examples/doc"
|
97
|
+
|
98
|
+
is equivalent to ...
|
99
|
+
|
100
|
+
file "testdata" do |t| mkdir t.name end
|
101
|
+
file "testdata/examples" do |t| mkdir t.name end
|
102
|
+
file "testdata/examples/doc" do |t| mkdir t.name end
|
103
|
+
|
104
|
+
The +directory+ method does not accept prerequisites or actions, but
|
105
|
+
both prerequisites and actions can be added later. For example ...
|
106
|
+
|
107
|
+
directory "testdata"
|
108
|
+
file "testdata" => ["otherdata"]
|
109
|
+
file "testdata" do
|
110
|
+
cp Dir["standard_data/*.data"], "testdata"
|
111
|
+
end
|
112
|
+
|
113
|
+
== Tasks with Parallel Prerequisites
|
114
|
+
|
115
|
+
Rake allows parallel execution of prerequisites using the following syntax:
|
116
|
+
|
117
|
+
multitask :copy_files => [:copy_src, :copy_doc, :copy_bin] do
|
118
|
+
puts "All Copies Complete"
|
119
|
+
end
|
120
|
+
|
121
|
+
In this example, +copy_files+ is a normal rake task. Its actions are
|
122
|
+
executed whereever all of its prerequisites are done. The big
|
123
|
+
difference is that the prerequisites (+copy_src+, +copy_bin+ and
|
124
|
+
+copy_doc+) are executed in parallel. Each of the prerequisites are
|
125
|
+
run in their own Ruby thread, possibly allowing faster overall runtime.
|
126
|
+
|
127
|
+
=== Secondary Prerequisites
|
128
|
+
|
129
|
+
If any of the primary prerequites of a multitask have common secondary
|
130
|
+
prerequisites, all of the primary/parallel prerequisites will wait
|
131
|
+
until the common prerequisites have been run.
|
132
|
+
|
133
|
+
For example, if the <tt>copy_<em>xxx</em></tt> tasks have the
|
134
|
+
following prerequisites:
|
135
|
+
|
136
|
+
task :copy_src => [:prep_for_copy]
|
137
|
+
task :copy_bin => [:prep_for_copy]
|
138
|
+
task :copy_doc => [:prep_for_copy]
|
139
|
+
|
140
|
+
Then the +prep_for_copy+ task is run before starting all the copies in
|
141
|
+
parallel. Once +prep_for_copy+ is complete, +copy_src+, +copy_bin+,
|
142
|
+
and +copy_doc+ are all run in parallel. Note that +prep_for_copy+ is
|
143
|
+
run only once, even though it is referenced in multiple threads.
|
144
|
+
|
145
|
+
=== Thread Safety
|
146
|
+
|
147
|
+
The Rake internal data structures are thread-safe with respect
|
148
|
+
to the multitask parallel execution, so there is no need for the user
|
149
|
+
to do extra synchronization for Rake's benefit. However, if there are
|
150
|
+
user data structures shared between the parallel prerequisites, the
|
151
|
+
user must do whatever is necessary to prevent race conditions.
|
152
|
+
|
153
|
+
== Tasks with Arguments
|
154
|
+
|
155
|
+
Prior to version 0.8.0, rake was only able to handle command line
|
156
|
+
arguments of the form NAME=VALUE that were passed into Rake via the
|
157
|
+
ENV hash. Many folks had asked for some kind of simple command line
|
158
|
+
arguments, perhaps using "--" to separate regular task names from
|
159
|
+
argument values on the command line. The problem is that there was no
|
160
|
+
easy way to associate positional arguments on the command line with
|
161
|
+
different tasks. Suppose both tasks :a and :b expect a command line
|
162
|
+
argument: does the first value go with :a? What if :b is run first?
|
163
|
+
Should it then get the first command line argument.
|
164
|
+
|
165
|
+
Rake 0.8.0 solves this problem by explicitly passing values directly
|
166
|
+
to the tasks that need them. For example, if I had a release task
|
167
|
+
that required a version number, I could say:
|
168
|
+
|
169
|
+
rake release[0.8.2]
|
170
|
+
|
171
|
+
And the string "0.8.2" will be passed to the :release task. Multiple
|
172
|
+
arguments can be passed by separating them with a comma, for example:
|
173
|
+
|
174
|
+
rake name[john,doe]
|
175
|
+
|
176
|
+
Just a few words of caution. The rake task name and its arguments
|
177
|
+
need to be a single command line argument to rake. This generally
|
178
|
+
means no spaces. If spaces are needed, then the entire rake +
|
179
|
+
argument string should be quoted. Something like this:
|
180
|
+
|
181
|
+
rake "name[billy bob, smith]"
|
182
|
+
|
183
|
+
(Quoting rules vary between operating systems and shells, so make sure
|
184
|
+
you consult the proper docs for your OS/shell).
|
185
|
+
|
186
|
+
=== Tasks that Expect Parameters
|
187
|
+
|
188
|
+
Parameters are only given to tasks that are setup to expect them. In
|
189
|
+
order to handle named parameters, the task declaration syntax for
|
190
|
+
tasks has been extended slightly.
|
191
|
+
|
192
|
+
For example, a task that needs a first name and last name might be
|
193
|
+
declared as:
|
194
|
+
|
195
|
+
task :name, [:first_name, :last_name]
|
196
|
+
|
197
|
+
The first argument is still the name of the task (:name in this case).
|
198
|
+
The next to argumements are the names of the parameters expected by
|
199
|
+
:name in an array (:first_name and :last_name in the example).
|
200
|
+
|
201
|
+
To access the values of the paramters, the block defining the task
|
202
|
+
behaviour can now accept a second parameter:
|
203
|
+
|
204
|
+
task :name, [:first_name, :last_name] do |t, args|
|
205
|
+
puts "First name is #{args.first_name}"
|
206
|
+
puts "Last name is #{args.last_name}"
|
207
|
+
end
|
208
|
+
|
209
|
+
The first argument of the block "t" is always bound to the current
|
210
|
+
task object. The second argument "args" is an open-struct like object
|
211
|
+
that allows access to the task arguments. Extra command line
|
212
|
+
arguments to a task are ignored. Missing command line arguments are
|
213
|
+
given the nil value.
|
214
|
+
|
215
|
+
If you wish to specify default values for the arguments, you can use
|
216
|
+
the with_defaults method in the task body. Here is the above example
|
217
|
+
where we specify default values for the first and last names:
|
218
|
+
|
219
|
+
task :name, [:first_name, :last_name] do |t, args|
|
220
|
+
args.with_defaults(:first_name => "John", :last_name => "Dough")
|
221
|
+
puts "First name is #{args.first_name}"
|
222
|
+
puts "Last name is #{args.last_name}"
|
223
|
+
end
|
224
|
+
|
225
|
+
=== Tasks that Expect Parameters and Have Prerequisites
|
226
|
+
|
227
|
+
Tasks that use parameters have a slightly different format for
|
228
|
+
prerequisites. Use the <tt>:needs</tt> keyword to specify the
|
229
|
+
prerequisites for tasks with arguments. For example:
|
230
|
+
|
231
|
+
task :name, [:first_name, :last_name] => [:pre_name] do |t, args|
|
232
|
+
args.with_defaults(:first_name => "John", :last_name => "Dough")
|
233
|
+
puts "First name is #{args.first_name}"
|
234
|
+
puts "Last name is #{args.last_name}"
|
235
|
+
end
|
236
|
+
|
237
|
+
=== Deprecated Task Parameters Format
|
238
|
+
|
239
|
+
There is an older format for declaring task parameters that omitted
|
240
|
+
the task array and used the :needs keyword to introduce the
|
241
|
+
dependencies. That format is still supported for compatibility, but
|
242
|
+
is not recommended for use.
|
243
|
+
|
244
|
+
== Accessing Task Programatically
|
245
|
+
|
246
|
+
Sometimes it is useful to manipulate tasks programatically in a
|
247
|
+
Rakefile. To find a task object, use the <tt>:[]</tt> operator on the
|
248
|
+
<tt>Rake::Task</tt>.
|
249
|
+
|
250
|
+
=== Programmatic Task Example
|
251
|
+
|
252
|
+
For example, the following Rakefile defines two tasks. The :doit task
|
253
|
+
simply prints a simple "DONE" message. The :dont class will lookup
|
254
|
+
the doit class and remove (clear) all of its prerequisites and
|
255
|
+
actions.
|
256
|
+
|
257
|
+
task :doit do
|
258
|
+
puts "DONE"
|
259
|
+
end
|
260
|
+
|
261
|
+
task :dont do
|
262
|
+
Rake::Task[:doit].clear
|
263
|
+
end
|
264
|
+
|
265
|
+
Running this example:
|
266
|
+
|
267
|
+
$ rake doit
|
268
|
+
(in /Users/jim/working/git/rake/x)
|
269
|
+
DONE
|
270
|
+
$ rake dont doit
|
271
|
+
(in /Users/jim/working/git/rake/x)
|
272
|
+
$
|
273
|
+
|
274
|
+
The ability to programmatically manipulate tasks gives rake very
|
275
|
+
powerful meta-programming capabilities w.r.t. task execution, but
|
276
|
+
should be used with cation.
|
277
|
+
|
278
|
+
== Rules
|
279
|
+
|
280
|
+
When a file is named as a prerequisite, but does not have a file task
|
281
|
+
defined for it, Rake will attempt to synthesize a task by looking at a
|
282
|
+
list of rules supplied in the Rakefile.
|
283
|
+
|
284
|
+
Suppose we were trying to invoke task "mycode.o", but no task is
|
285
|
+
defined for it. But the rakefile has a rule that look like this ...
|
286
|
+
|
287
|
+
rule '.o' => ['.c'] do |t|
|
288
|
+
sh "cc #{t.source} -c -o #{t.name}"
|
289
|
+
end
|
290
|
+
|
291
|
+
This rule will synthesize any task that ends in ".o". It has a
|
292
|
+
prerequisite a source file with an extension of ".c" must exist. If
|
293
|
+
Rake is able to find a file named "mycode.c", it will automatically
|
294
|
+
create a task that builds "mycode.o" from "mycode.c".
|
295
|
+
|
296
|
+
If the file "mycode.c" does not exist, rake will attempt
|
297
|
+
to recursively synthesize a rule for it.
|
298
|
+
|
299
|
+
When a task is synthesized from a rule, the +source+ attribute of the
|
300
|
+
task is set to the matching source file. This allows us to write
|
301
|
+
rules with actions that reference the source file.
|
302
|
+
|
303
|
+
=== Advanced Rules
|
304
|
+
|
305
|
+
Any regular expression may be used as the rule pattern. Additionally,
|
306
|
+
a proc may be used to calculate the name of the source file. This
|
307
|
+
allows for complex patterns and sources.
|
308
|
+
|
309
|
+
The following rule is equivalent to the example above.
|
310
|
+
|
311
|
+
rule( /\.o$/ => [
|
312
|
+
proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') }
|
313
|
+
]) do |t|
|
314
|
+
sh "cc #{t.source} -c -o #{t.name}"
|
315
|
+
end
|
316
|
+
|
317
|
+
<b>NOTE:</b> Because of a _quirk_ in Ruby syntax, parenthesis are
|
318
|
+
required on *rule* when the first argument is a regular expression.
|
319
|
+
|
320
|
+
The following rule might be used for Java files ...
|
321
|
+
|
322
|
+
rule '.java' => [
|
323
|
+
proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') }
|
324
|
+
] do |t|
|
325
|
+
java_compile(t.source, t.name)
|
326
|
+
end
|
327
|
+
|
328
|
+
<b>NOTE:</b> +java_compile+ is a hypothetical method that invokes the
|
329
|
+
java compiler.
|
330
|
+
|
331
|
+
== Importing Dependencies
|
332
|
+
|
333
|
+
Any ruby file (including other rakefiles) can be included with a
|
334
|
+
standard Ruby +require+ command. The rules and declarations in the
|
335
|
+
required file are just added to the definitions already accumulated.
|
336
|
+
|
337
|
+
Because the files are loaded _before_ the rake targets are evaluated,
|
338
|
+
the loaded files must be "ready to go" when the rake command is
|
339
|
+
invoked. This make generated dependency files difficult to use. By
|
340
|
+
the time rake gets around to updating the dependencies file, it is too
|
341
|
+
late to load it.
|
342
|
+
|
343
|
+
The +import+ command addresses this by specifying a file to be loaded
|
344
|
+
_after_ the main rakefile is loaded, but _before_ any targets on the
|
345
|
+
command line are specified. In addition, if the file name matches an
|
346
|
+
explicit task, that task is invoked before loading the file. This
|
347
|
+
allows dependency files to be generated and used in a single rake
|
348
|
+
command invocation.
|
349
|
+
|
350
|
+
=== Example:
|
351
|
+
|
352
|
+
require 'rake/loaders/makefile'
|
353
|
+
|
354
|
+
file ".depends.mf" => [SRC_LIST] do |t|
|
355
|
+
sh "makedepend -f- -- #{CFLAGS} -- #{t.prerequisites} > #{t.name}"
|
356
|
+
end
|
357
|
+
|
358
|
+
import ".depends.mf"
|
359
|
+
|
360
|
+
If ".depends" does not exist, or is out of date w.r.t. the source
|
361
|
+
files, a new ".depends" file is generated using +makedepend+ before
|
362
|
+
loading.
|
363
|
+
|
364
|
+
== Comments
|
365
|
+
|
366
|
+
Standard Ruby comments (beginning with "#") can be used anywhere it is
|
367
|
+
legal in Ruby source code, including comments for tasks and rules.
|
368
|
+
However, if you wish a task to be described using the "-T" switch,
|
369
|
+
then you need to use the +desc+ command to describe the task.
|
370
|
+
|
371
|
+
=== Example:
|
372
|
+
|
373
|
+
desc "Create a distribution package"
|
374
|
+
task :package => [ ... ] do ... end
|
375
|
+
|
376
|
+
The "-T" switch (or "--tasks" if you like to spell things out) will
|
377
|
+
display a list of tasks that have a defined comment. If you use
|
378
|
+
+desc+ to describe your major tasks, you have a semi-automatic way of
|
379
|
+
generating a summary of your Rake file.
|
380
|
+
|
381
|
+
traken$ rake -T
|
382
|
+
(in /home/.../rake)
|
383
|
+
rake clean # Remove any temporary products.
|
384
|
+
rake clobber # Remove any generated file.
|
385
|
+
rake clobber_rdoc # Remove rdoc products
|
386
|
+
rake contrib_test # Run tests for contrib_test
|
387
|
+
rake default # Default Task
|
388
|
+
rake install # Install the application
|
389
|
+
rake lines # Count lines in the main rake file
|
390
|
+
rake rdoc # Build the rdoc HTML Files
|
391
|
+
rake rerdoc # Force a rebuild of the RDOC files
|
392
|
+
rake test # Run tests
|
393
|
+
rake testall # Run all test targets
|
394
|
+
|
395
|
+
Only tasks with descriptions will be displayed with the "-T" switch.
|
396
|
+
Use "-P" (or "--prereqs") to get a list of all tasks and their
|
397
|
+
prerequisites.
|
398
|
+
|
399
|
+
== Namespaces
|
400
|
+
|
401
|
+
As projects grow (and along with it, the number of tasks), it is
|
402
|
+
common for task names to begin to clash. For example, if you might
|
403
|
+
have a main program and a set of sample programs built by a single
|
404
|
+
Rakefile. By placing the tasks related to the main program in one
|
405
|
+
namespace, and the tasks for building the sample programs in a
|
406
|
+
different namespace, the task names will not will not interfer with
|
407
|
+
each other.
|
408
|
+
|
409
|
+
For example:
|
410
|
+
|
411
|
+
namespace "main"
|
412
|
+
task :build do
|
413
|
+
# Build the main program
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
namespace "samples" do
|
418
|
+
task :build do
|
419
|
+
# Build the sample programs
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
task :build => ["main:build", "samples:build"]
|
424
|
+
|
425
|
+
Referencing a task in a separate namespace can be achieved by
|
426
|
+
prefixing the task name with the namespace and a colon
|
427
|
+
(e.g. "main:build" refers to the :build task in the +main+ namespace).
|
428
|
+
Nested namespaces are supported, so
|
429
|
+
|
430
|
+
Note that the name given in the +task+ command is always the unadorned
|
431
|
+
task name without any namespace prefixes. The +task+ command always
|
432
|
+
defines a task in the current namespace.
|
433
|
+
|
434
|
+
=== FileTasks
|
435
|
+
|
436
|
+
File task names are not scoped by the namespace command. Since the
|
437
|
+
name of a file task is the name of an actual file in the file system,
|
438
|
+
it makes little sense to include file task names in name space.
|
439
|
+
Directory tasks (created by the +directory+ command) are a type of
|
440
|
+
file task and are also not affected by namespaces.
|
441
|
+
|
442
|
+
=== Name Resolution
|
443
|
+
|
444
|
+
When looking up a task name, rake will start with the current
|
445
|
+
namespace and attempt to find the name there. If it fails to find a
|
446
|
+
name in the current namespace, it will search the parent namespaces
|
447
|
+
until a match is found (or an error occurs if there is no match).
|
448
|
+
|
449
|
+
The "rake" namespace is a special implicit namespace that refers to
|
450
|
+
the toplevel names.
|
451
|
+
|
452
|
+
If a task name begins with a "^" character, the name resolution will
|
453
|
+
start in the parent namespace. Multiple "^" characters are allowed.
|
454
|
+
|
455
|
+
Here is an example file with multiple :run tasks and how various names
|
456
|
+
resolve in different locations.
|
457
|
+
|
458
|
+
task :run
|
459
|
+
|
460
|
+
namespace "one" do
|
461
|
+
task :run
|
462
|
+
|
463
|
+
namespace "two" do
|
464
|
+
task :run
|
465
|
+
|
466
|
+
# :run => "one:two:run"
|
467
|
+
# "two:run" => "one:two:run"
|
468
|
+
# "one:two:run" => "one:two:run"
|
469
|
+
# "one:run" => "one:run"
|
470
|
+
# "^run" => "one:run"
|
471
|
+
# "^^run" => "rake:run" (the top level task)
|
472
|
+
# "rake:run" => "rake:run" (the top level task)
|
473
|
+
end
|
474
|
+
|
475
|
+
# :run => "one:run"
|
476
|
+
# "two:run" => "one:two:run"
|
477
|
+
# "^run" => "rake:run"
|
478
|
+
end
|
479
|
+
|
480
|
+
# :run => "rake:run"
|
481
|
+
# "one:run" => "one:run"
|
482
|
+
# "one:two:run" => "one:two:run"
|
483
|
+
|
484
|
+
== FileLists
|
485
|
+
|
486
|
+
FileLists are the way Rake manages lists of files. You can treat a
|
487
|
+
FileList as an array of strings for the most part, but FileLists
|
488
|
+
support some additional operations.
|
489
|
+
|
490
|
+
=== Creating a FileList
|
491
|
+
|
492
|
+
Creating a file list is easy. Just give it the list of file names:
|
493
|
+
|
494
|
+
fl = FileList['file1.rb', file2.rb']
|
495
|
+
|
496
|
+
Or give it a glob pattern:
|
497
|
+
|
498
|
+
fl = FileList['*.rb']
|
499
|
+
|
500
|
+
== Odds and Ends
|
501
|
+
|
502
|
+
=== do/end verses { }
|
503
|
+
|
504
|
+
Blocks may be specified with either a +do+/+end+ pair, or with curly
|
505
|
+
braces in Ruby. We _strongly_ recommend using +do+/+end+ to specify the
|
506
|
+
actions for tasks and rules. Because the rakefile idiom tends to
|
507
|
+
leave off parenthesis on the task/file/rule methods, unusual
|
508
|
+
ambiguities can arise when using curly braces.
|
509
|
+
|
510
|
+
For example, suppose that the method +object_files+ returns a list of
|
511
|
+
object files in a project. Now we use +object_files+ as the
|
512
|
+
prerequistes in a rule specified with actions in curly braces.
|
513
|
+
|
514
|
+
# DON'T DO THIS!
|
515
|
+
file "prog" => object_files {
|
516
|
+
# Actions are expected here (but it doesn't work)!
|
517
|
+
}
|
518
|
+
|
519
|
+
Because curly braces have a higher precedence than +do+/+end+, the
|
520
|
+
block is associated with the +object_files+ method rather than the
|
521
|
+
+file+ method.
|
522
|
+
|
523
|
+
This is the proper way to specify the task ...
|
524
|
+
|
525
|
+
# THIS IS FINE
|
526
|
+
file "prog" => object_files do
|
527
|
+
# Actions go here
|
528
|
+
end
|
529
|
+
|
530
|
+
----
|
531
|
+
|
532
|
+
== See
|
533
|
+
|
534
|
+
* README -- Main documentation for Rake.
|