drake 0.8.7.0.2.4 → 0.9.0.0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/CHANGES +77 -9
- data/{CHANGES.drake → CHANGES-drake} +6 -2
- data/MIT-LICENSE +2 -0
- data/{README → README.rdoc} +30 -18
- data/Rakefile +144 -130
- data/Rakefile-drake +67 -0
- data/TODO +1 -1
- data/bin/drake +2 -0
- data/doc/command_line_usage.rdoc +25 -11
- data/doc/glossary.rdoc +2 -2
- data/doc/jamis.rb +2 -2
- data/doc/parallel.rdoc +37 -29
- data/doc/proto_rake.rdoc +22 -22
- data/doc/rake.1.gz +0 -0
- data/doc/rakefile.rdoc +56 -33
- data/doc/rational.rdoc +6 -6
- data/doc/release_notes/rake-0.4.15.rdoc +1 -1
- data/doc/release_notes/rake-0.5.0.rdoc +1 -1
- data/doc/release_notes/rake-0.7.0.rdoc +1 -1
- data/doc/release_notes/rake-0.7.2.rdoc +3 -3
- data/doc/release_notes/rake-0.7.3.rdoc +2 -2
- data/doc/release_notes/rake-0.8.0.rdoc +1 -1
- data/doc/release_notes/rake-0.8.2.rdoc +3 -3
- data/doc/release_notes/rake-0.8.3.rdoc +2 -2
- data/doc/release_notes/rake-0.8.4.rdoc +1 -1
- data/doc/release_notes/rake-0.8.5.rdoc +1 -1
- data/doc/release_notes/rake-0.8.6.rdoc +1 -1
- data/doc/release_notes/rake-0.8.7.rdoc +1 -1
- data/doc/release_notes/rake-0.9.0.rdoc +112 -0
- data/install.rb +14 -12
- data/lib/rake.rb +31 -2527
- data/lib/rake/alt_system.rb +7 -6
- data/lib/rake/application.rb +626 -0
- data/lib/rake/classic_namespace.rb +1 -0
- data/lib/rake/clean.rb +2 -4
- data/lib/rake/cloneable.rb +25 -0
- data/lib/rake/contrib/compositepublisher.rb +2 -5
- data/lib/rake/contrib/ftptools.rb +5 -8
- data/lib/rake/contrib/publisher.rb +2 -8
- data/lib/rake/contrib/rubyforgepublisher.rb +2 -4
- data/lib/rake/contrib/sshpublisher.rb +4 -6
- data/lib/rake/contrib/sys.rb +7 -25
- data/lib/rake/default_loader.rb +10 -0
- data/lib/rake/dsl.rb +2 -0
- data/lib/rake/dsl_definition.rb +143 -0
- data/lib/rake/early_time.rb +18 -0
- data/lib/rake/ext/core.rb +27 -0
- data/lib/rake/ext/module.rb +39 -0
- data/lib/rake/ext/string.rb +167 -0
- data/lib/rake/ext/time.rb +14 -0
- data/lib/rake/file_creation_task.rb +24 -0
- data/lib/rake/file_list.rb +403 -0
- data/lib/rake/file_task.rb +47 -0
- data/lib/rake/file_utils.rb +112 -0
- data/lib/rake/file_utils_ext.rb +142 -0
- data/lib/rake/gempackagetask.rb +6 -90
- data/lib/rake/invocation_chain.rb +51 -0
- data/lib/rake/invocation_exception_mixin.rb +16 -0
- data/lib/rake/loaders/makefile.rb +13 -15
- data/lib/rake/multi_task.rb +16 -0
- data/lib/rake/name_space.rb +25 -0
- data/lib/rake/packagetask.rb +13 -12
- data/lib/rake/parallel.rb +17 -28
- data/lib/rake/pathmap.rb +1 -0
- data/lib/rake/pseudo_status.rb +24 -0
- data/lib/rake/rake_module.rb +29 -0
- data/lib/rake/rake_test_loader.rb +10 -2
- data/lib/rake/rdoctask.rb +211 -190
- data/lib/rake/ruby182_test_unit_fix.rb +9 -7
- data/lib/rake/rule_recursion_overflow_error.rb +20 -0
- data/lib/rake/runtest.rb +4 -6
- data/lib/rake/task.rb +351 -0
- data/lib/rake/task_argument_error.rb +7 -0
- data/lib/rake/task_arguments.rb +74 -0
- data/lib/rake/task_manager.rb +307 -0
- data/lib/rake/tasklib.rb +1 -2
- data/lib/rake/testtask.rb +57 -27
- data/lib/rake/version.rb +13 -0
- data/lib/rake/win32.rb +4 -4
- data/test/contrib/test_sys.rb +8 -31
- data/test/data/access/Rakefile +33 -0
- data/test/data/comments/Rakefile +18 -0
- data/test/data/default/Rakefile +1 -1
- data/test/data/deprecated_import/Rakefile +1 -0
- data/test/data/dryrun/Rakefile +1 -1
- data/test/data/file_creation_task/Rakefile +1 -1
- data/test/data/namespace/Rakefile +9 -0
- data/test/data/rakelib/test1.rb +1 -0
- data/test/data/verbose/Rakefile +34 -0
- data/test/{filecreation.rb → file_creation.rb} +11 -7
- data/test/functional/functional_test.rb +25 -0
- data/test/{session_functional.rb → functional/session_based_tests.rb} +141 -23
- data/test/in_environment.rb +7 -5
- data/test/{test_application.rb → lib/application_test.rb} +331 -143
- data/test/{test_clean.rb → lib/clean_test.rb} +1 -0
- data/test/{test_definitions.rb → lib/definitions_test.rb} +4 -4
- data/test/lib/dsl_test.rb +52 -0
- data/test/{test_earlytime.rb → lib/earlytime_test.rb} +1 -2
- data/test/{test_extension.rb → lib/extension_test.rb} +2 -2
- data/test/{test_file_creation_task.rb → lib/file_creation_task_test.rb} +1 -1
- data/test/{test_file_task.rb → lib/file_task_test.rb} +9 -5
- data/test/{test_filelist.rb → lib/filelist_test.rb} +38 -24
- data/test/{test_fileutils.rb → lib/fileutils_test.rb} +27 -22
- data/test/{test_ftp.rb → lib/ftp_test.rb} +0 -0
- data/test/{test_invocation_chain.rb → lib/invocation_chain_test.rb} +0 -0
- data/test/{test_makefile_loader.rb → lib/makefile_loader_test.rb} +0 -0
- data/test/{test_multitask.rb → lib/multitask_test.rb} +3 -2
- data/test/{test_namespace.rb → lib/namespace_test.rb} +0 -0
- data/test/lib/package_task_test.rb +82 -0
- data/test/{test_parallel.rb → lib/parallel_test.rb} +5 -5
- data/test/{test_pathmap.rb → lib/pathmap_test.rb} +3 -2
- data/test/{test_pseudo_status.rb → lib/pseudo_status_test.rb} +0 -0
- data/test/{test_rake.rb → lib/rake_test.rb} +1 -1
- data/test/{test_rdoc_task.rb → lib/rdoc_task_test.rb} +19 -23
- data/test/{test_require.rb → lib/require_test.rb} +8 -2
- data/test/{test_rules.rb → lib/rules_test.rb} +4 -5
- data/test/{test_task_arguments.rb → lib/task_arguments_test.rb} +5 -5
- data/test/{test_task_manager.rb → lib/task_manager_test.rb} +15 -5
- data/test/{test_tasks.rb → lib/task_test.rb} +91 -28
- data/test/{test_tasklib.rb → lib/tasklib_test.rb} +0 -0
- data/test/{test_test_task.rb → lib/test_task_test.rb} +3 -3
- data/test/lib/testtask_test.rb +49 -0
- data/test/{test_top_level_functions.rb → lib/top_level_functions_test.rb} +5 -3
- data/test/{test_win32.rb → lib/win32_test.rb} +19 -0
- data/test/rake_test_setup.rb +6 -10
- data/test/ruby_version_test.rb +3 -0
- data/test/test_helper.rb +19 -0
- metadata +108 -66
- data/Rakefile.drake +0 -73
- data/test/functional.rb +0 -15
- data/test/test_package_task.rb +0 -118
data/doc/rational.rdoc
CHANGED
@@ -38,13 +38,13 @@ too much work. And that was the end of that!
|
|
38
38
|
... Except I couldn't get the thought out of my head. What exactly
|
39
39
|
would be needed to make the about syntax work as a make file? Hmmm, you
|
40
40
|
would need to register the tasks, you need some way of specifying
|
41
|
-
dependencies between tasks, and some way of kicking off the process.
|
41
|
+
dependencies between tasks, and some way of kicking off the process.
|
42
42
|
Hey! What if we did ... and fifteen minutes later I had a working
|
43
43
|
prototype of Ruby make, complete with dependencies and actions.
|
44
44
|
|
45
45
|
I showed the code to my coworker and we had a good laugh. It was just
|
46
46
|
about a page worth of code that reproduced an amazing amount of the
|
47
|
-
functionality of make. We were both
|
47
|
+
functionality of make. We were both truly stunned with the power of
|
48
48
|
Ruby.
|
49
49
|
|
50
50
|
But it didn't do everything make did. In particular, it didn't have
|
@@ -53,7 +53,7 @@ prerequisite files have a later timestamp). Obviously THAT would be a
|
|
53
53
|
pain to add and so Ruby Make would remain an interesting experiment.
|
54
54
|
|
55
55
|
... Except as I walked back to my desk, I started thinking about what
|
56
|
-
file based
|
56
|
+
file based dependencies would really need. Rats! I was hooked again,
|
57
57
|
and by adding a new class and two new methods, file/timestamp
|
58
58
|
dependencies were implemented.
|
59
59
|
|
@@ -97,7 +97,7 @@ Here's another task with dependencies ...
|
|
97
97
|
end
|
98
98
|
|
99
99
|
Task :clobber depends upon task :clean, so :clean will be run before
|
100
|
-
:clobber is executed.
|
100
|
+
:clobber is executed.
|
101
101
|
|
102
102
|
Files are specified by using the "file" command. It is similar to the
|
103
103
|
task command, except that the task name represents a file, and the task
|
@@ -115,7 +115,7 @@ Here is a file based dependency that will compile "hello.cc" to
|
|
115
115
|
|
116
116
|
I normally specify file tasks with string (rather than symbols). Some
|
117
117
|
file names can't be represented by symbols. Plus it makes the
|
118
|
-
distinction between them more clear to the casual reader.
|
118
|
+
distinction between them more clear to the casual reader.
|
119
119
|
|
120
120
|
Currently writing a task for each and every file in the project would be
|
121
121
|
tedious at best. I envision a set of libraries to make this job
|
@@ -133,7 +133,7 @@ created for rake.
|
|
133
133
|
That's it. There's no documentation (other than whats in this
|
134
134
|
message). Does this sound interesting to anyone? If so, I'll continue
|
135
135
|
to clean it up and write it up and publish it on RAA. Otherwise, I'll
|
136
|
-
leave it as an interesting
|
136
|
+
leave it as an interesting exercise and a tribute to the power of Ruby.
|
137
137
|
|
138
138
|
Why /might/ rake be interesting to Ruby programmers. I don't know,
|
139
139
|
perhaps ...
|
@@ -24,7 +24,7 @@ Rake:
|
|
24
24
|
appliation instead of using its own data.
|
25
25
|
|
26
26
|
* Fixed the method name leak from FileUtils (bug found by Glenn
|
27
|
-
Vanderburg).
|
27
|
+
Vanderburg).
|
28
28
|
|
29
29
|
* Added test for noop, bad_option and verbose flags to sh command.
|
30
30
|
|
@@ -40,13 +40,13 @@ Rake:
|
|
40
40
|
The following new features are available in Rake version 0.7.2:
|
41
41
|
|
42
42
|
* Added square and curly bracket patterns to FileList#include (Tilman
|
43
|
-
Sauerbeck).
|
43
|
+
Sauerbeck).
|
44
44
|
|
45
45
|
* FileLists can now pass a block to FileList#exclude to exclude files
|
46
46
|
based on calculated values.
|
47
47
|
|
48
48
|
* Added plain filename support to rule dependents (suggested by Nobu
|
49
|
-
Nakada).
|
49
|
+
Nakada).
|
50
50
|
|
51
51
|
* Added pathmap support to rule dependents. In other words, if a
|
52
52
|
pathmap format (beginning with a '%') is given as a Rake rule
|
@@ -46,14 +46,14 @@ new features and numerous bug fixes.
|
|
46
46
|
|
47
47
|
* Fixed bug with rules involving multiple source, where only the first
|
48
48
|
dependency of a rule has any effect (Patch supplied by Emanuel
|
49
|
-
|
49
|
+
Indermühle)
|
50
50
|
|
51
51
|
* FileList#clone and FileList#dup have better sematics w.r.t. taint
|
52
52
|
and freeze.
|
53
53
|
|
54
54
|
* Changed from using Mutex to Monitor. Evidently Mutex causes thread
|
55
55
|
join errors when Ruby is compiled with -disable-pthreads. (Patch
|
56
|
-
supplied by Ittay Dror)
|
56
|
+
supplied by Ittay Dror)
|
57
57
|
|
58
58
|
* Fixed bug in makefile parser that had problems with extra spaces in
|
59
59
|
file task names. (Patch supplied by Ittay Dror)
|
@@ -157,7 +157,7 @@ otherwise helpful comments. Thanks to ...
|
|
157
157
|
* Gavin Stark
|
158
158
|
* Adam Q. Salter
|
159
159
|
* Adam Majer
|
160
|
-
* Emanuel
|
160
|
+
* Emanuel Indermühle
|
161
161
|
* Ittay Dror
|
162
162
|
* Bheeshmar Redheendran (for spending an afternoon with me debugging
|
163
163
|
windows issues)
|
@@ -12,7 +12,7 @@ Rake version 0.8.3 is a bug-fix release of rake.
|
|
12
12
|
directory.
|
13
13
|
|
14
14
|
* Added fix to handle ruby installations in directories with spaces in
|
15
|
-
their name.
|
15
|
+
their name.
|
16
16
|
|
17
17
|
== What is Rake
|
18
18
|
|
@@ -104,7 +104,7 @@ otherwise helpful comments. Thanks to ...
|
|
104
104
|
* Gavin Stark
|
105
105
|
* Adam Q. Salter
|
106
106
|
* Adam Majer
|
107
|
-
* Emanuel
|
107
|
+
* Emanuel Indermühle
|
108
108
|
* Ittay Dror
|
109
109
|
* Bheeshmar Redheendran (for spending an afternoon with me debugging
|
110
110
|
windows issues)
|
@@ -69,7 +69,7 @@ Otherwise, you can get it from the more traditional places:
|
|
69
69
|
|
70
70
|
Home Page:: http://rake.rubyforge.org/
|
71
71
|
Download:: http://rubyforge.org/project/showfiles.php?group_id=50
|
72
|
-
GitHub:: git://github.com/jimweirich/rake.git
|
72
|
+
GitHub:: git://github.com/jimweirich/rake.git
|
73
73
|
|
74
74
|
== Task Argument Examples
|
75
75
|
|
@@ -39,7 +39,7 @@ Otherwise, you can get it from the more traditional places:
|
|
39
39
|
|
40
40
|
Home Page:: http://rake.rubyforge.org/
|
41
41
|
Download:: http://rubyforge.org/project/showfiles.php?group_id=50
|
42
|
-
GitHub:: git://github.com/jimweirich/rake.git
|
42
|
+
GitHub:: git://github.com/jimweirich/rake.git
|
43
43
|
|
44
44
|
== Thanks
|
45
45
|
|
@@ -41,7 +41,7 @@ Otherwise, you can get it from the more traditional places:
|
|
41
41
|
|
42
42
|
Home Page:: http://rake.rubyforge.org/
|
43
43
|
Download:: http://rubyforge.org/project/showfiles.php?group_id=50
|
44
|
-
GitHub:: git://github.com/jimweirich/rake.git
|
44
|
+
GitHub:: git://github.com/jimweirich/rake.git
|
45
45
|
|
46
46
|
== Thanks
|
47
47
|
|
@@ -42,7 +42,7 @@ Otherwise, you can get it from the more traditional places:
|
|
42
42
|
|
43
43
|
Home Page:: http://rake.rubyforge.org/
|
44
44
|
Download:: http://rubyforge.org/project/showfiles.php?group_id=50
|
45
|
-
GitHub:: git://github.com/jimweirich/rake.git
|
45
|
+
GitHub:: git://github.com/jimweirich/rake.git
|
46
46
|
|
47
47
|
== Thanks
|
48
48
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
= Rake 0.9.0 Released
|
2
|
+
|
3
|
+
Rake version 0.9.0 has a number of bug fixes and enhancments (see
|
4
|
+
below for more details). Additionally, the internals have be slightly
|
5
|
+
restructured and improved.
|
6
|
+
|
7
|
+
== Changes
|
8
|
+
|
9
|
+
=== New Features / Enhancements / Bug Fixes in Version 0.9.0
|
10
|
+
|
11
|
+
* Rake now warns when the deprecated :needs syntax used (and suggests
|
12
|
+
the proper syntax in the warning).
|
13
|
+
|
14
|
+
* Moved Rake DSL commands to top level ruby object 'main'. Rake DSL
|
15
|
+
commands are no longer private methods in Object. (Suggested by
|
16
|
+
James M. Lawrence/quix)
|
17
|
+
|
18
|
+
* Rake now uses case-insensitive comparisons to find the Rakefile on Windows.
|
19
|
+
Based on patch by Roger Pack.
|
20
|
+
|
21
|
+
* Rake now requires (instead of loads) files in the test task. Patch by Cezary
|
22
|
+
Baginski.
|
23
|
+
|
24
|
+
* Fixed typos. Patches by Sean Scot August Moon and R.T. Lechow.
|
25
|
+
|
26
|
+
* Rake now prints the Rakefile directory only when it's different from the
|
27
|
+
current directory. Patch by Alex Chaffee.
|
28
|
+
|
29
|
+
* Improved rakefile_location discovery on Windows. Patch by James Tucker.
|
30
|
+
|
31
|
+
* Rake now recognizes "Windows Server" as a windows system. Patch by Matthias
|
32
|
+
Lüdtke
|
33
|
+
|
34
|
+
* Rake::RDocTask is deprecated. Use RDoc::Task from RDoc 2.4.2+ (require
|
35
|
+
'rdoc/task')
|
36
|
+
|
37
|
+
* Rake::GemPackageTask is deprecated. Use Gem::PackageTask (require
|
38
|
+
'rubygems/package_task')
|
39
|
+
|
40
|
+
* Rake now outputs various messages to $stderr instead of $stdout.
|
41
|
+
|
42
|
+
* Rake no longer emits warnings for Config. Patch by Santiago Pastorino.
|
43
|
+
|
44
|
+
* Removed Rake's DSL methods from the top level scope. If you need to
|
45
|
+
call 'task :xzy' in your code, include Rake::DSL into your class, or
|
46
|
+
put the code in a Rake::DSL.environment do ... end block.
|
47
|
+
|
48
|
+
* Split rake.rb into individual files.
|
49
|
+
|
50
|
+
* Support for the --where (-W) flag for showing where a task is defined.
|
51
|
+
|
52
|
+
* Fixed quoting in test task.
|
53
|
+
(http://onestepback.org/redmine/issues/show/44,
|
54
|
+
http://www.pivotaltracker.com/story/show/1223138)
|
55
|
+
|
56
|
+
* Fixed the silent option parsing problem.
|
57
|
+
(http://onestepback.org/redmine/issues/show/47)
|
58
|
+
|
59
|
+
* Fixed :verbose=>false flag on sh and ruby commands.
|
60
|
+
|
61
|
+
* Rake command line options may be given by default in a RAKEOPT
|
62
|
+
environment variable.
|
63
|
+
|
64
|
+
* Errors in Rake will now display the task invocation chain in effect
|
65
|
+
at the time of the error.
|
66
|
+
|
67
|
+
* Accepted change by warnickr to not expand test patterns in shell
|
68
|
+
(allowing more files in the test suite).
|
69
|
+
|
70
|
+
* Fixed that file tasks did not perform prereq lookups in scope
|
71
|
+
(Redmine #57).
|
72
|
+
|
73
|
+
== What is Rake
|
74
|
+
|
75
|
+
Rake is a build tool similar to the make program in many ways. But
|
76
|
+
instead of cryptic make recipes, Rake uses standard Ruby code to
|
77
|
+
declare tasks and dependencies. You have the full power of a modern
|
78
|
+
scripting language built right into your build tool.
|
79
|
+
|
80
|
+
== Availability
|
81
|
+
|
82
|
+
The easiest way to get and install rake is via RubyGems ...
|
83
|
+
|
84
|
+
gem install rake (you may need root/admin privileges)
|
85
|
+
|
86
|
+
Otherwise, you can get it from the more traditional places:
|
87
|
+
|
88
|
+
Home Page:: http://rake.rubyforge.org/
|
89
|
+
Download:: http://rubyforge.org/project/showfiles.php?group_id=50
|
90
|
+
GitHub:: git://github.com/jimweirich/rake.git
|
91
|
+
|
92
|
+
== Thanks
|
93
|
+
|
94
|
+
As usual, it was input from users that drove a alot of these changes. The
|
95
|
+
following people either contributed patches, made suggestions or made
|
96
|
+
otherwise helpful comments. Thanks to ...
|
97
|
+
|
98
|
+
* James M. Lawrence (quix)
|
99
|
+
* Roger Pack
|
100
|
+
* Cezary Baginski
|
101
|
+
* Sean Scot August Moon
|
102
|
+
* R.T. Lechow
|
103
|
+
* Alex Chaffee
|
104
|
+
* James Tucker
|
105
|
+
* Matthias Lüdtke
|
106
|
+
* Santiago Pastorino
|
107
|
+
|
108
|
+
Also, bit thanks to Eric Hodel for assisting with getting this release
|
109
|
+
out the door (where "assisting" includes, but is not by any means
|
110
|
+
limited to, "pushing" me to get it done).
|
111
|
+
|
112
|
+
-- Jim Weirich
|
data/install.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'rbconfig'
|
2
2
|
require 'find'
|
3
|
-
require '
|
3
|
+
require 'fileutils'
|
4
4
|
|
5
|
-
include
|
5
|
+
include RbConfig
|
6
6
|
|
7
7
|
$ruby = CONFIG['ruby_install_name']
|
8
8
|
|
@@ -27,7 +27,7 @@ def installBIN(from, opfile)
|
|
27
27
|
|
28
28
|
fail "Cannot find a temporary directory" unless tmp_dir
|
29
29
|
tmp_file = File.join(tmp_dir, "_tmp")
|
30
|
-
|
30
|
+
|
31
31
|
File.open(from) do |ip|
|
32
32
|
File.open(tmp_file, "w") do |op|
|
33
33
|
ruby = File.join($realbindir, $ruby)
|
@@ -37,8 +37,9 @@ def installBIN(from, opfile)
|
|
37
37
|
end
|
38
38
|
|
39
39
|
opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i
|
40
|
-
|
41
|
-
|
40
|
+
FileUtils.install(tmp_file, File.join($bindir, opfile),
|
41
|
+
{:mode => 0755, :verbose => true})
|
42
|
+
File.unlink(tmp_file)
|
42
43
|
end
|
43
44
|
|
44
45
|
$sitedir = CONFIG["sitelibdir"]
|
@@ -61,14 +62,14 @@ bindir = CONFIG["bindir"]
|
|
61
62
|
if (destdir = ENV['DESTDIR'])
|
62
63
|
$bindir = destdir + $bindir
|
63
64
|
$sitedir = destdir + $sitedir
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
|
66
|
+
FileUtils.mkdir_p($bindir)
|
67
|
+
FileUtils.mkdir_p($sitedir)
|
67
68
|
end
|
68
69
|
|
69
70
|
rake_dest = File.join($sitedir, "rake")
|
70
|
-
|
71
|
-
File
|
71
|
+
FileUtils.mkdir_p(rake_dest, {:verbose => true})
|
72
|
+
File.chmod(0755, rake_dest)
|
72
73
|
|
73
74
|
# The library files
|
74
75
|
|
@@ -78,9 +79,10 @@ for fn in files
|
|
78
79
|
fn_dir = File.dirname(fn)
|
79
80
|
target_dir = File.join($sitedir, fn_dir)
|
80
81
|
if ! File.exist?(target_dir)
|
81
|
-
|
82
|
+
FileUtils.mkdir_p(target_dir)
|
82
83
|
end
|
83
|
-
|
84
|
+
FileUtils.install(File.join('lib', fn), File.join($sitedir, fn),
|
85
|
+
{:mode => 0644, :verbose => true})
|
84
86
|
end
|
85
87
|
|
86
88
|
# and the executable
|
data/lib/rake.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
#--
|
4
2
|
|
5
|
-
# Copyright 2003
|
3
|
+
# Copyright 2003-2010 by Jim Weirich (jim.weirich@gmail.com)
|
4
|
+
#
|
5
|
+
# Copyright 2008-2011 by James M. Lawrence (quixoticsycophant@gmail.com)
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
# of this software and associated documentation files (the "Software"), to
|
@@ -22,14 +22,10 @@
|
|
22
22
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
23
23
|
# IN THE SOFTWARE.
|
24
24
|
#++
|
25
|
-
#
|
26
|
-
# = Rake -- Ruby Make
|
27
|
-
#
|
28
|
-
# This is the main file for the Rake application. Normally it is referenced
|
29
|
-
# as a library via a require statement, but it can be distributed
|
30
|
-
# independently as an application.
|
31
25
|
|
32
|
-
|
26
|
+
require 'rake/version'
|
27
|
+
|
28
|
+
RAKEVERSION = Rake::VERSION
|
33
29
|
|
34
30
|
require 'rbconfig'
|
35
31
|
require 'fileutils'
|
@@ -38,2526 +34,34 @@ require 'monitor'
|
|
38
34
|
require 'optparse'
|
39
35
|
require 'ostruct'
|
40
36
|
|
41
|
-
require 'rake/
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
######################################################################
|
46
|
-
# Rake extensions to Module.
|
47
|
-
#
|
48
|
-
class Module
|
49
|
-
# Check for an existing method in the current class before extending. IF
|
50
|
-
# the method already exists, then a warning is printed and the extension is
|
51
|
-
# not added. Otherwise the block is yielded and any definitions in the
|
52
|
-
# block will take effect.
|
53
|
-
#
|
54
|
-
# Usage:
|
55
|
-
#
|
56
|
-
# class String
|
57
|
-
# rake_extension("xyz") do
|
58
|
-
# def xyz
|
59
|
-
# ...
|
60
|
-
# end
|
61
|
-
# end
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
def rake_extension(method)
|
65
|
-
if method_defined?(method)
|
66
|
-
$stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
|
67
|
-
else
|
68
|
-
yield
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end # module Module
|
72
|
-
|
73
|
-
|
74
|
-
######################################################################
|
75
|
-
# User defined methods to be added to String.
|
76
|
-
#
|
77
|
-
class String
|
78
|
-
rake_extension("ext") do
|
79
|
-
# Replace the file extension with +newext+. If there is no extension on
|
80
|
-
# the string, append the new extension to the end. If the new extension
|
81
|
-
# is not given, or is the empty string, remove any existing extension.
|
82
|
-
#
|
83
|
-
# +ext+ is a user added method for the String class.
|
84
|
-
def ext(newext='')
|
85
|
-
return self.dup if ['.', '..'].include? self
|
86
|
-
if newext != ''
|
87
|
-
newext = (newext =~ /^\./) ? newext : ("." + newext)
|
88
|
-
end
|
89
|
-
self.chomp(File.extname(self)) << newext
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
rake_extension("pathmap") do
|
94
|
-
# Explode a path into individual components. Used by +pathmap+.
|
95
|
-
def pathmap_explode
|
96
|
-
head, tail = File.split(self)
|
97
|
-
return [self] if head == self
|
98
|
-
return [tail] if head == '.' || tail == '/'
|
99
|
-
return [head, tail] if head == '/'
|
100
|
-
return head.pathmap_explode + [tail]
|
101
|
-
end
|
102
|
-
protected :pathmap_explode
|
103
|
-
|
104
|
-
# Extract a partial path from the path. Include +n+ directories from the
|
105
|
-
# front end (left hand side) if +n+ is positive. Include |+n+|
|
106
|
-
# directories from the back end (right hand side) if +n+ is negative.
|
107
|
-
def pathmap_partial(n)
|
108
|
-
dirs = File.dirname(self).pathmap_explode
|
109
|
-
partial_dirs =
|
110
|
-
if n > 0
|
111
|
-
dirs[0...n]
|
112
|
-
elsif n < 0
|
113
|
-
dirs.reverse[0...-n].reverse
|
114
|
-
else
|
115
|
-
"."
|
116
|
-
end
|
117
|
-
File.join(partial_dirs)
|
118
|
-
end
|
119
|
-
protected :pathmap_partial
|
120
|
-
|
121
|
-
# Preform the pathmap replacement operations on the given path. The
|
122
|
-
# patterns take the form 'pat1,rep1;pat2,rep2...'.
|
123
|
-
def pathmap_replace(patterns, &block)
|
124
|
-
result = self
|
125
|
-
patterns.split(';').each do |pair|
|
126
|
-
pattern, replacement = pair.split(',')
|
127
|
-
pattern = Regexp.new(pattern)
|
128
|
-
if replacement == '*' && block_given?
|
129
|
-
result = result.sub(pattern, &block)
|
130
|
-
elsif replacement
|
131
|
-
result = result.sub(pattern, replacement)
|
132
|
-
else
|
133
|
-
result = result.sub(pattern, '')
|
134
|
-
end
|
135
|
-
end
|
136
|
-
result
|
137
|
-
end
|
138
|
-
protected :pathmap_replace
|
139
|
-
|
140
|
-
# Map the path according to the given specification. The specification
|
141
|
-
# controls the details of the mapping. The following special patterns are
|
142
|
-
# recognized:
|
143
|
-
#
|
144
|
-
# * <b>%p</b> -- The complete path.
|
145
|
-
# * <b>%f</b> -- The base file name of the path, with its file extension,
|
146
|
-
# but without any directories.
|
147
|
-
# * <b>%n</b> -- The file name of the path without its file extension.
|
148
|
-
# * <b>%d</b> -- The directory list of the path.
|
149
|
-
# * <b>%x</b> -- The file extension of the path. An empty string if there
|
150
|
-
# is no extension.
|
151
|
-
# * <b>%X</b> -- Everything *but* the file extension.
|
152
|
-
# * <b>%s</b> -- The alternate file separater if defined, otherwise use
|
153
|
-
# the standard file separator.
|
154
|
-
# * <b>%%</b> -- A percent sign.
|
155
|
-
#
|
156
|
-
# The %d specifier can also have a numeric prefix (e.g. '%2d'). If the
|
157
|
-
# number is positive, only return (up to) +n+ directories in the path,
|
158
|
-
# starting from the left hand side. If +n+ is negative, return (up to)
|
159
|
-
# |+n+| directories from the right hand side of the path.
|
160
|
-
#
|
161
|
-
# Examples:
|
162
|
-
#
|
163
|
-
# 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'
|
164
|
-
# 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
|
165
|
-
#
|
166
|
-
# Also the %d, %p, %f, %n, %x, and %X operators can take a
|
167
|
-
# pattern/replacement argument to perform simple string substititions on a
|
168
|
-
# particular part of the path. The pattern and replacement are speparated
|
169
|
-
# by a comma and are enclosed by curly braces. The replacement spec comes
|
170
|
-
# after the % character but before the operator letter. (e.g.
|
171
|
-
# "%{old,new}d"). Muliple replacement specs should be separated by
|
172
|
-
# semi-colons (e.g. "%{old,new;src,bin}d").
|
173
|
-
#
|
174
|
-
# Regular expressions may be used for the pattern, and back refs may be
|
175
|
-
# used in the replacement text. Curly braces, commas and semi-colons are
|
176
|
-
# excluded from both the pattern and replacement text (let's keep parsing
|
177
|
-
# reasonable).
|
178
|
-
#
|
179
|
-
# For example:
|
180
|
-
#
|
181
|
-
# "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
|
182
|
-
#
|
183
|
-
# returns:
|
184
|
-
#
|
185
|
-
# "bin/org/onestepback/proj/A.class"
|
186
|
-
#
|
187
|
-
# If the replacement text is '*', then a block may be provided to perform
|
188
|
-
# some arbitrary calculation for the replacement.
|
189
|
-
#
|
190
|
-
# For example:
|
191
|
-
#
|
192
|
-
# "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
|
193
|
-
# ext.downcase
|
194
|
-
# }
|
195
|
-
#
|
196
|
-
# Returns:
|
197
|
-
#
|
198
|
-
# "/path/to/file.txt"
|
199
|
-
#
|
200
|
-
def pathmap(spec=nil, &block)
|
201
|
-
return self if spec.nil?
|
202
|
-
result = ''
|
203
|
-
spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
|
204
|
-
case frag
|
205
|
-
when '%f'
|
206
|
-
result << File.basename(self)
|
207
|
-
when '%n'
|
208
|
-
result << File.basename(self).ext
|
209
|
-
when '%d'
|
210
|
-
result << File.dirname(self)
|
211
|
-
when '%x'
|
212
|
-
result << File.extname(self)
|
213
|
-
when '%X'
|
214
|
-
result << self.ext
|
215
|
-
when '%p'
|
216
|
-
result << self
|
217
|
-
when '%s'
|
218
|
-
result << (File::ALT_SEPARATOR || File::SEPARATOR)
|
219
|
-
when '%-'
|
220
|
-
# do nothing
|
221
|
-
when '%%'
|
222
|
-
result << "%"
|
223
|
-
when /%(-?\d+)d/
|
224
|
-
result << pathmap_partial($1.to_i)
|
225
|
-
when /^%\{([^}]*)\}(\d*[dpfnxX])/
|
226
|
-
patterns, operator = $1, $2
|
227
|
-
result << pathmap('%' + operator).pathmap_replace(patterns, &block)
|
228
|
-
when /^%/
|
229
|
-
fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
|
230
|
-
else
|
231
|
-
result << frag
|
232
|
-
end
|
233
|
-
end
|
234
|
-
result
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end # class String
|
238
|
-
|
239
|
-
##############################################################################
|
240
|
-
module Rake
|
241
|
-
|
242
|
-
# Errors -----------------------------------------------------------
|
243
|
-
|
244
|
-
# Error indicating an ill-formed task declaration.
|
245
|
-
class TaskArgumentError < ArgumentError
|
246
|
-
end
|
247
|
-
|
248
|
-
# Error indicating a recursion overflow error in task selection.
|
249
|
-
class RuleRecursionOverflowError < StandardError
|
250
|
-
def initialize(*args)
|
251
|
-
super
|
252
|
-
@targets = []
|
253
|
-
end
|
254
|
-
|
255
|
-
def add_target(target)
|
256
|
-
@targets << target
|
257
|
-
end
|
258
|
-
|
259
|
-
def message
|
260
|
-
super + ": [" + @targets.reverse.join(' => ') + "]"
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
# --------------------------------------------------------------------------
|
265
|
-
# Rake module singleton methods.
|
266
|
-
#
|
267
|
-
class << self
|
268
|
-
# Current Rake Application
|
269
|
-
def application
|
270
|
-
@application ||= Rake::Application.new
|
271
|
-
end
|
272
|
-
|
273
|
-
# Set the current Rake application object.
|
274
|
-
def application=(app)
|
275
|
-
@application = app
|
276
|
-
end
|
277
|
-
|
278
|
-
# Return the original directory where the Rake application was started.
|
279
|
-
def original_dir
|
280
|
-
application.original_dir
|
281
|
-
end
|
282
|
-
|
283
|
-
end
|
284
|
-
|
285
|
-
####################################################################
|
286
|
-
# Mixin for creating easily cloned objects.
|
287
|
-
#
|
288
|
-
module Cloneable
|
289
|
-
# Clone an object by making a new object and setting all the instance
|
290
|
-
# variables to the same values.
|
291
|
-
def dup
|
292
|
-
sibling = self.class.new
|
293
|
-
instance_variables.each do |ivar|
|
294
|
-
value = self.instance_variable_get(ivar)
|
295
|
-
new_value = value.clone rescue value
|
296
|
-
sibling.instance_variable_set(ivar, new_value)
|
297
|
-
end
|
298
|
-
sibling.taint if tainted?
|
299
|
-
sibling
|
300
|
-
end
|
301
|
-
|
302
|
-
def clone
|
303
|
-
sibling = dup
|
304
|
-
sibling.freeze if frozen?
|
305
|
-
sibling
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
####################################################################
|
310
|
-
# Exit status class for times the system just gives us a nil.
|
311
|
-
class PseudoStatus
|
312
|
-
attr_reader :exitstatus
|
313
|
-
def initialize(code=0)
|
314
|
-
@exitstatus = code
|
315
|
-
end
|
316
|
-
def to_i
|
317
|
-
@exitstatus << 8
|
318
|
-
end
|
319
|
-
def >>(n)
|
320
|
-
to_i >> n
|
321
|
-
end
|
322
|
-
def stopped?
|
323
|
-
false
|
324
|
-
end
|
325
|
-
def exited?
|
326
|
-
true
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
####################################################################
|
331
|
-
# TaskAguments manage the arguments passed to a task.
|
332
|
-
#
|
333
|
-
class TaskArguments
|
334
|
-
include Enumerable
|
335
|
-
|
336
|
-
attr_reader :names
|
337
|
-
|
338
|
-
# Create a TaskArgument object with a list of named arguments
|
339
|
-
# (given by :names) and a set of associated values (given by
|
340
|
-
# :values). :parent is the parent argument object.
|
341
|
-
def initialize(names, values, parent=nil)
|
342
|
-
@names = names
|
343
|
-
@parent = parent
|
344
|
-
@hash = {}
|
345
|
-
names.each_with_index { |name, i|
|
346
|
-
@hash[name.to_sym] = values[i] unless values[i].nil?
|
347
|
-
}
|
348
|
-
end
|
349
|
-
|
350
|
-
# Create a new argument scope using the prerequisite argument
|
351
|
-
# names.
|
352
|
-
def new_scope(names)
|
353
|
-
values = names.collect { |n| self[n] }
|
354
|
-
self.class.new(names, values, self)
|
355
|
-
end
|
356
|
-
|
357
|
-
# Find an argument value by name or index.
|
358
|
-
def [](index)
|
359
|
-
lookup(index.to_sym)
|
360
|
-
end
|
361
|
-
|
362
|
-
# Specify a hash of default values for task arguments. Use the
|
363
|
-
# defaults only if there is no specific value for the given
|
364
|
-
# argument.
|
365
|
-
def with_defaults(defaults)
|
366
|
-
@hash = defaults.merge(@hash)
|
367
|
-
end
|
368
|
-
|
369
|
-
def each(&block)
|
370
|
-
@hash.each(&block)
|
371
|
-
end
|
372
|
-
|
373
|
-
def method_missing(sym, *args, &block)
|
374
|
-
lookup(sym.to_sym)
|
375
|
-
end
|
376
|
-
|
377
|
-
def to_hash
|
378
|
-
@hash
|
379
|
-
end
|
380
|
-
|
381
|
-
def to_s
|
382
|
-
@hash.inspect
|
383
|
-
end
|
384
|
-
|
385
|
-
def inspect
|
386
|
-
to_s
|
387
|
-
end
|
388
|
-
|
389
|
-
protected
|
390
|
-
|
391
|
-
def lookup(name)
|
392
|
-
if @hash.has_key?(name)
|
393
|
-
@hash[name]
|
394
|
-
elsif ENV.has_key?(name.to_s)
|
395
|
-
ENV[name.to_s]
|
396
|
-
elsif ENV.has_key?(name.to_s.upcase)
|
397
|
-
ENV[name.to_s.upcase]
|
398
|
-
elsif @parent
|
399
|
-
@parent.lookup(name)
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
EMPTY_TASK_ARGS = TaskArguments.new([], [])
|
405
|
-
|
406
|
-
####################################################################
|
407
|
-
# InvocationChain tracks the chain of task invocations to detect
|
408
|
-
# circular dependencies.
|
409
|
-
class InvocationChain
|
410
|
-
attr_reader :value # :nodoc:
|
411
|
-
|
412
|
-
def initialize(value, tail)
|
413
|
-
@value = value
|
414
|
-
@tail = tail
|
415
|
-
end
|
416
|
-
|
417
|
-
def member?(obj)
|
418
|
-
@value == obj || @tail.member?(obj)
|
419
|
-
end
|
420
|
-
|
421
|
-
def append(value)
|
422
|
-
if member?(value)
|
423
|
-
fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
|
424
|
-
end
|
425
|
-
self.class.new(value, self)
|
426
|
-
end
|
427
|
-
|
428
|
-
def to_s
|
429
|
-
"#{prefix}#{@value}"
|
430
|
-
end
|
431
|
-
|
432
|
-
def self.append(value, chain)
|
433
|
-
chain.append(value)
|
434
|
-
end
|
435
|
-
|
436
|
-
private
|
437
|
-
|
438
|
-
def prefix
|
439
|
-
"#{@tail.to_s} => "
|
440
|
-
end
|
441
|
-
|
442
|
-
class EmptyInvocationChain
|
443
|
-
def member?(obj)
|
444
|
-
false
|
445
|
-
end
|
446
|
-
def append(value)
|
447
|
-
InvocationChain.new(value, self)
|
448
|
-
end
|
449
|
-
def to_s
|
450
|
-
"TOP"
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
EMPTY = EmptyInvocationChain.new
|
455
|
-
|
456
|
-
end # class InvocationChain
|
457
|
-
|
458
|
-
end # module Rake
|
459
|
-
|
460
|
-
module Rake
|
461
|
-
|
462
|
-
###########################################################################
|
463
|
-
# A Task is the basic unit of work in a Rakefile. Tasks have associated
|
464
|
-
# actions (possibly more than one) and a list of prerequisites. When
|
465
|
-
# invoked, a task will first ensure that all of its prerequisites have an
|
466
|
-
# opportunity to run and then it will execute its own actions.
|
467
|
-
#
|
468
|
-
# Tasks are not usually created directly using the new method, but rather
|
469
|
-
# use the +file+ and +task+ convenience methods.
|
470
|
-
#
|
471
|
-
class Task
|
472
|
-
# List of prerequisites for a task.
|
473
|
-
attr_reader :prerequisites
|
474
|
-
|
475
|
-
# List of actions attached to a task.
|
476
|
-
attr_reader :actions
|
477
|
-
|
478
|
-
# Application owning this task.
|
479
|
-
attr_accessor :application
|
480
|
-
|
481
|
-
# Comment for this task. Restricted to a single line of no more than 50
|
482
|
-
# characters.
|
483
|
-
attr_reader :comment
|
484
|
-
|
485
|
-
# Full text of the (possibly multi-line) comment.
|
486
|
-
attr_reader :full_comment
|
487
|
-
|
488
|
-
# Array of nested namespaces names used for task lookup by this task.
|
489
|
-
attr_reader :scope
|
490
|
-
|
491
|
-
# Return task name
|
492
|
-
def to_s
|
493
|
-
name
|
494
|
-
end
|
495
|
-
|
496
|
-
def inspect
|
497
|
-
"<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
|
498
|
-
end
|
499
|
-
|
500
|
-
# List of sources for task.
|
501
|
-
attr_writer :sources
|
502
|
-
def sources
|
503
|
-
@sources ||= []
|
504
|
-
end
|
505
|
-
|
506
|
-
# First source from a rule (nil if no sources)
|
507
|
-
def source
|
508
|
-
@sources.first if defined?(@sources)
|
509
|
-
end
|
510
|
-
|
511
|
-
# Create a task named +task_name+ with no actions or prerequisites. Use
|
512
|
-
# +enhance+ to add actions and prerequisites.
|
513
|
-
def initialize(task_name, app)
|
514
|
-
@name = task_name.to_s
|
515
|
-
@prerequisites = []
|
516
|
-
@actions = []
|
517
|
-
@already_invoked = false
|
518
|
-
@full_comment = nil
|
519
|
-
@comment = nil
|
520
|
-
@lock = Monitor.new
|
521
|
-
@application = app
|
522
|
-
@scope = app.current_scope
|
523
|
-
@arg_names = nil
|
524
|
-
end
|
525
|
-
|
526
|
-
# Enhance a task with prerequisites or actions. Returns self.
|
527
|
-
def enhance(deps=nil, &block)
|
528
|
-
@prerequisites |= deps if deps
|
529
|
-
@actions << block if block_given?
|
530
|
-
self
|
531
|
-
end
|
532
|
-
|
533
|
-
# Name of the task, including any namespace qualifiers.
|
534
|
-
def name
|
535
|
-
@name.to_s
|
536
|
-
end
|
537
|
-
|
538
|
-
# Name of task with argument list description.
|
539
|
-
def name_with_args # :nodoc:
|
540
|
-
if arg_description
|
541
|
-
"#{name}#{arg_description}"
|
542
|
-
else
|
543
|
-
name
|
544
|
-
end
|
545
|
-
end
|
546
|
-
|
547
|
-
# Argument description (nil if none).
|
548
|
-
def arg_description # :nodoc:
|
549
|
-
@arg_names ? "[#{(arg_names || []).join(',')}]" : nil
|
550
|
-
end
|
551
|
-
|
552
|
-
# Name of arguments for this task.
|
553
|
-
def arg_names
|
554
|
-
@arg_names || []
|
555
|
-
end
|
556
|
-
|
557
|
-
# Reenable the task, allowing its tasks to be executed if the task
|
558
|
-
# is invoked again.
|
559
|
-
def reenable
|
560
|
-
@already_invoked = false
|
561
|
-
end
|
562
|
-
|
563
|
-
# Clear the existing prerequisites and actions of a rake task.
|
564
|
-
def clear
|
565
|
-
clear_prerequisites
|
566
|
-
clear_actions
|
567
|
-
self
|
568
|
-
end
|
569
|
-
|
570
|
-
# Clear the existing prerequisites of a rake task.
|
571
|
-
def clear_prerequisites
|
572
|
-
prerequisites.clear
|
573
|
-
self
|
574
|
-
end
|
575
|
-
|
576
|
-
# Clear the existing actions on a rake task.
|
577
|
-
def clear_actions
|
578
|
-
actions.clear
|
579
|
-
self
|
580
|
-
end
|
581
|
-
|
582
|
-
def invoke_serial(*args) # :nodoc:
|
583
|
-
task_args = TaskArguments.new(arg_names, args)
|
584
|
-
invoke_with_call_chain(task_args, InvocationChain::EMPTY)
|
585
|
-
end
|
586
|
-
|
587
|
-
# Invoke the task if it is needed. Prerequites are invoked first.
|
588
|
-
def invoke(*args)
|
589
|
-
if application.options.threads == 1
|
590
|
-
invoke_serial(*args)
|
591
|
-
else
|
592
|
-
invoke_parallel(*args)
|
593
|
-
end
|
594
|
-
end
|
595
|
-
|
596
|
-
# Same as invoke, but explicitly pass a call chain to detect
|
597
|
-
# circular dependencies.
|
598
|
-
def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
|
599
|
-
new_chain = InvocationChain.append(self, invocation_chain)
|
600
|
-
if application.options.threads == 1
|
601
|
-
@lock.synchronize do
|
602
|
-
return unless prepare_invoke
|
603
|
-
invoke_prerequisites(task_args, new_chain)
|
604
|
-
execute(task_args) if needed?
|
605
|
-
end
|
606
|
-
else
|
607
|
-
return unless prepare_invoke
|
608
|
-
invoke_with_call_chain_collector(task_args, new_chain, invocation_chain)
|
609
|
-
end
|
610
|
-
end
|
611
|
-
protected :invoke_with_call_chain
|
612
|
-
|
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
|
622
|
-
end
|
623
|
-
|
624
|
-
# Invoke all the prerequisites of a task.
|
625
|
-
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
|
626
|
-
@prerequisites.each { |n|
|
627
|
-
invoke_prerequisite(n, task_args, invocation_chain)
|
628
|
-
}
|
629
|
-
end
|
630
|
-
|
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
|
636
|
-
end
|
637
|
-
|
638
|
-
# Format the trace flags for display.
|
639
|
-
def format_trace_flags
|
640
|
-
flags = []
|
641
|
-
flags << "first_time" unless @already_invoked
|
642
|
-
flags << "not_needed" unless needed?
|
643
|
-
flags.empty? ? "" : "(" + flags.join(", ") + ")"
|
644
|
-
end
|
645
|
-
private :format_trace_flags
|
646
|
-
|
647
|
-
# Execute the actions associated with this task.
|
648
|
-
def execute(args=nil)
|
649
|
-
args ||= EMPTY_TASK_ARGS
|
650
|
-
if application.options.dryrun
|
651
|
-
puts "** Execute (dry run) #{name}"
|
652
|
-
return
|
653
|
-
end
|
654
|
-
if application.options.trace
|
655
|
-
puts "** Execute #{name}"
|
656
|
-
end
|
657
|
-
application.enhance_with_matching_rule(name) if @actions.empty?
|
658
|
-
@actions.each do |act|
|
659
|
-
case act.arity
|
660
|
-
when 1
|
661
|
-
act.call(self)
|
662
|
-
else
|
663
|
-
act.call(self, args)
|
664
|
-
end
|
665
|
-
end
|
666
|
-
end
|
667
|
-
|
668
|
-
# Is this task needed?
|
669
|
-
def needed?
|
670
|
-
true
|
671
|
-
end
|
672
|
-
|
673
|
-
# Timestamp for this task. Basic tasks return the current time for their
|
674
|
-
# time stamp. Other tasks can be more sophisticated.
|
675
|
-
def timestamp
|
676
|
-
@prerequisites.collect { |p| application[p].timestamp }.max || Time.now
|
677
|
-
end
|
678
|
-
|
679
|
-
# Add a description to the task. The description can consist of an option
|
680
|
-
# argument list (enclosed brackets) and an optional comment.
|
681
|
-
def add_description(description)
|
682
|
-
return if ! description
|
683
|
-
comment = description.strip
|
684
|
-
add_comment(comment) if comment && ! comment.empty?
|
685
|
-
end
|
686
|
-
|
687
|
-
# Writing to the comment attribute is the same as adding a description.
|
688
|
-
def comment=(description)
|
689
|
-
add_description(description)
|
690
|
-
end
|
691
|
-
|
692
|
-
# Add a comment to the task. If a comment alread exists, separate
|
693
|
-
# the new comment with " / ".
|
694
|
-
def add_comment(comment)
|
695
|
-
if @full_comment
|
696
|
-
@full_comment << " / "
|
697
|
-
else
|
698
|
-
@full_comment = ''
|
699
|
-
end
|
700
|
-
@full_comment << comment
|
701
|
-
if @full_comment =~ /\A([^.]+?\.)( |$)/
|
702
|
-
@comment = $1
|
703
|
-
else
|
704
|
-
@comment = @full_comment
|
705
|
-
end
|
706
|
-
end
|
707
|
-
private :add_comment
|
708
|
-
|
709
|
-
# Set the names of the arguments for this task. +args+ should be
|
710
|
-
# an array of symbols, one for each argument name.
|
711
|
-
def set_arg_names(args)
|
712
|
-
@arg_names = args.map { |a| a.to_sym }
|
713
|
-
end
|
714
|
-
|
715
|
-
# Return a string describing the internal state of a task. Useful for
|
716
|
-
# debugging.
|
717
|
-
def investigation
|
718
|
-
result = "------------------------------\n"
|
719
|
-
result << "Investigating #{name}\n"
|
720
|
-
result << "class: #{self.class}\n"
|
721
|
-
result << "task needed: #{needed?}\n"
|
722
|
-
result << "timestamp: #{timestamp}\n"
|
723
|
-
result << "pre-requisites: \n"
|
724
|
-
prereqs = @prerequisites.collect {|name| application[name]}
|
725
|
-
prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
|
726
|
-
prereqs.each do |p|
|
727
|
-
result << "--#{p.name} (#{p.timestamp})\n"
|
728
|
-
end
|
729
|
-
latest_prereq = @prerequisites.collect{|n| application[n].timestamp}.max
|
730
|
-
result << "latest-prerequisite time: #{latest_prereq}\n"
|
731
|
-
result << "................................\n\n"
|
732
|
-
return result
|
733
|
-
end
|
734
|
-
|
735
|
-
# ----------------------------------------------------------------
|
736
|
-
# Rake Module Methods
|
737
|
-
#
|
738
|
-
class << self
|
739
|
-
|
740
|
-
# Clear the task list. This cause rake to immediately forget all the
|
741
|
-
# tasks that have been assigned. (Normally used in the unit tests.)
|
742
|
-
def clear
|
743
|
-
Rake.application.clear
|
744
|
-
end
|
745
|
-
|
746
|
-
# List of all defined tasks.
|
747
|
-
def tasks
|
748
|
-
Rake.application.tasks
|
749
|
-
end
|
750
|
-
|
751
|
-
# Return a task with the given name. If the task is not currently
|
752
|
-
# known, try to synthesize one from the defined rules. If no rules are
|
753
|
-
# found, but an existing file matches the task name, assume it is a file
|
754
|
-
# task with no dependencies or actions.
|
755
|
-
def [](task_name)
|
756
|
-
Rake.application[task_name]
|
757
|
-
end
|
758
|
-
|
759
|
-
# TRUE if the task name is already defined.
|
760
|
-
def task_defined?(task_name)
|
761
|
-
Rake.application.lookup(task_name) != nil
|
762
|
-
end
|
763
|
-
|
764
|
-
# Define a task given +args+ and an option block. If a rule with the
|
765
|
-
# given name already exists, the prerequisites and actions are added to
|
766
|
-
# the existing task. Returns the defined task.
|
767
|
-
def define_task(*args, &block)
|
768
|
-
Rake.application.define_task(self, *args, &block)
|
769
|
-
end
|
770
|
-
|
771
|
-
# Define a rule for synthesizing tasks.
|
772
|
-
def create_rule(*args, &block)
|
773
|
-
Rake.application.create_rule(*args, &block)
|
774
|
-
end
|
775
|
-
|
776
|
-
# Apply the scope to the task name according to the rules for
|
777
|
-
# this kind of task. Generic tasks will accept the scope as
|
778
|
-
# part of the name.
|
779
|
-
def scope_name(scope, task_name)
|
780
|
-
(scope + [task_name]).join(':')
|
781
|
-
end
|
782
|
-
|
783
|
-
end # class << Rake::Task
|
784
|
-
end # class Rake::Task
|
785
|
-
|
786
|
-
|
787
|
-
###########################################################################
|
788
|
-
# A FileTask is a task that includes time based dependencies. If any of a
|
789
|
-
# FileTask's prerequisites have a timestamp that is later than the file
|
790
|
-
# represented by this task, then the file must be rebuilt (using the
|
791
|
-
# supplied actions).
|
792
|
-
#
|
793
|
-
class FileTask < Task
|
794
|
-
|
795
|
-
# Is this file task needed? Yes if it doesn't exist, or if its time stamp
|
796
|
-
# is out of date.
|
797
|
-
def needed?
|
798
|
-
! File.exist?(name) || out_of_date?(timestamp)
|
799
|
-
end
|
800
|
-
|
801
|
-
# Time stamp for file task.
|
802
|
-
def timestamp
|
803
|
-
if File.exist?(name)
|
804
|
-
File.mtime(name.to_s)
|
805
|
-
else
|
806
|
-
Rake::EARLY
|
807
|
-
end
|
808
|
-
end
|
809
|
-
|
810
|
-
private
|
811
|
-
|
812
|
-
# Are there any prerequisites with a later time than the given time stamp?
|
813
|
-
def out_of_date?(stamp)
|
814
|
-
@prerequisites.any? { |n| application[n].timestamp > stamp}
|
815
|
-
end
|
816
|
-
|
817
|
-
# ----------------------------------------------------------------
|
818
|
-
# Task class methods.
|
819
|
-
#
|
820
|
-
class << self
|
821
|
-
# Apply the scope to the task name according to the rules for this kind
|
822
|
-
# of task. File based tasks ignore the scope when creating the name.
|
823
|
-
def scope_name(scope, task_name)
|
824
|
-
task_name
|
825
|
-
end
|
826
|
-
end
|
827
|
-
end # class Rake::FileTask
|
828
|
-
|
829
|
-
###########################################################################
|
830
|
-
# A FileCreationTask is a file task that when used as a dependency will be
|
831
|
-
# needed if and only if the file has not been created. Once created, it is
|
832
|
-
# not re-triggered if any of its dependencies are newer, nor does trigger
|
833
|
-
# any rebuilds of tasks that depend on it whenever it is updated.
|
834
|
-
#
|
835
|
-
class FileCreationTask < FileTask
|
836
|
-
# Is this file task needed? Yes if it doesn't exist.
|
837
|
-
def needed?
|
838
|
-
! File.exist?(name)
|
839
|
-
end
|
840
|
-
|
841
|
-
# Time stamp for file creation task. This time stamp is earlier
|
842
|
-
# than any other time stamp.
|
843
|
-
def timestamp
|
844
|
-
Rake::EARLY
|
845
|
-
end
|
846
|
-
end
|
847
|
-
|
848
|
-
###########################################################################
|
849
|
-
# Same as a regular task, but the immediate prerequisites are done in
|
850
|
-
# parallel using Ruby threads.
|
851
|
-
#
|
852
|
-
class MultiTask < Task
|
853
|
-
private
|
854
|
-
def invoke_prerequisites(args, invocation_chain)
|
855
|
-
threads = @prerequisites.collect { |p|
|
856
|
-
Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
|
857
|
-
}
|
858
|
-
threads.each { |t| t.join }
|
859
|
-
end
|
860
|
-
end
|
861
|
-
end # module Rake
|
862
|
-
|
863
|
-
## ###########################################################################
|
864
|
-
# Task Definition Functions ...
|
865
|
-
|
866
|
-
# Declare a basic task.
|
867
|
-
#
|
868
|
-
# Example:
|
869
|
-
# task :clobber => [:clean] do
|
870
|
-
# rm_rf "html"
|
871
|
-
# end
|
872
|
-
#
|
873
|
-
def task(*args, &block)
|
874
|
-
Rake::Task.define_task(*args, &block)
|
875
|
-
end
|
876
|
-
|
877
|
-
|
878
|
-
# Declare a file task.
|
879
|
-
#
|
880
|
-
# Example:
|
881
|
-
# file "config.cfg" => ["config.template"] do
|
882
|
-
# open("config.cfg", "w") do |outfile|
|
883
|
-
# open("config.template") do |infile|
|
884
|
-
# while line = infile.gets
|
885
|
-
# outfile.puts line
|
886
|
-
# end
|
887
|
-
# end
|
888
|
-
# end
|
889
|
-
# end
|
890
|
-
#
|
891
|
-
def file(*args, &block)
|
892
|
-
Rake::FileTask.define_task(*args, &block)
|
893
|
-
end
|
894
|
-
|
895
|
-
# Declare a file creation task.
|
896
|
-
# (Mainly used for the directory command).
|
897
|
-
def file_create(args, &block)
|
898
|
-
Rake::FileCreationTask.define_task(args, &block)
|
899
|
-
end
|
900
|
-
|
901
|
-
# Declare a set of files tasks to create the given directories on demand.
|
902
|
-
#
|
903
|
-
# Example:
|
904
|
-
# directory "testdata/doc"
|
905
|
-
#
|
906
|
-
def directory(dir)
|
907
|
-
Rake.each_dir_parent(dir) do |d|
|
908
|
-
file_create d do |t|
|
909
|
-
mkdir_p t.name if ! File.exist?(t.name)
|
910
|
-
end
|
911
|
-
end
|
912
|
-
end
|
913
|
-
|
914
|
-
# Declare a task that performs its prerequisites in parallel. Multitasks does
|
915
|
-
# *not* guarantee that its prerequisites will execute in any given order
|
916
|
-
# (which is obvious when you think about it)
|
917
|
-
#
|
918
|
-
# Example:
|
919
|
-
# multitask :deploy => [:deploy_gem, :deploy_rdoc]
|
920
|
-
#
|
921
|
-
def multitask(args, &block)
|
922
|
-
Rake::MultiTask.define_task(args, &block)
|
923
|
-
end
|
924
|
-
|
925
|
-
# Create a new rake namespace and use it for evaluating the given block.
|
926
|
-
# Returns a NameSpace object that can be used to lookup tasks defined in the
|
927
|
-
# namespace.
|
928
|
-
#
|
929
|
-
# E.g.
|
930
|
-
#
|
931
|
-
# ns = namespace "nested" do
|
932
|
-
# task :run
|
933
|
-
# end
|
934
|
-
# task_run = ns[:run] # find :run in the given namespace.
|
935
|
-
#
|
936
|
-
def namespace(name=nil, &block)
|
937
|
-
Rake.application.in_namespace(name, &block)
|
938
|
-
end
|
939
|
-
|
940
|
-
# Declare a rule for auto-tasks.
|
941
|
-
#
|
942
|
-
# Example:
|
943
|
-
# rule '.o' => '.c' do |t|
|
944
|
-
# sh %{cc -o #{t.name} #{t.source}}
|
945
|
-
# end
|
946
|
-
#
|
947
|
-
def rule(*args, &block)
|
948
|
-
Rake::Task.create_rule(*args, &block)
|
949
|
-
end
|
950
|
-
|
951
|
-
# Describe the next rake task.
|
952
|
-
#
|
953
|
-
# Example:
|
954
|
-
# desc "Run the Unit Tests"
|
955
|
-
# task :test => [:build]
|
956
|
-
# runtests
|
957
|
-
# end
|
958
|
-
#
|
959
|
-
def desc(description)
|
960
|
-
Rake.application.last_description = description
|
961
|
-
end
|
962
|
-
|
963
|
-
# Import the partial Rakefiles +fn+. Imported files are loaded _after_ the
|
964
|
-
# current file is completely loaded. This allows the import statement to
|
965
|
-
# appear anywhere in the importing file, and yet allowing the imported files
|
966
|
-
# to depend on objects defined in the importing file.
|
967
|
-
#
|
968
|
-
# A common use of the import statement is to include files containing
|
969
|
-
# dependency declarations.
|
970
|
-
#
|
971
|
-
# See also the --rakelibdir command line option.
|
972
|
-
#
|
973
|
-
# Example:
|
974
|
-
# import ".depend", "my_rules"
|
975
|
-
#
|
976
|
-
def import(*fns)
|
977
|
-
fns.each do |fn|
|
978
|
-
Rake.application.add_import(fn)
|
979
|
-
end
|
980
|
-
end
|
981
|
-
|
982
|
-
#############################################################################
|
983
|
-
# This a FileUtils extension that defines several additional commands to be
|
984
|
-
# added to the FileUtils utility functions.
|
985
|
-
#
|
986
|
-
module FileUtils
|
987
|
-
RUBY_EXT = ((Config::CONFIG['ruby_install_name'] =~ /\.(com|cmd|exe|bat|rb|sh)$/) ?
|
988
|
-
"" :
|
989
|
-
Config::CONFIG['EXEEXT'])
|
990
|
-
|
991
|
-
RUBY = File.join(
|
992
|
-
Config::CONFIG['bindir'],
|
993
|
-
Config::CONFIG['ruby_install_name'] + RUBY_EXT).
|
994
|
-
sub(/.*\s.*/m, '"\&"')
|
995
|
-
|
996
|
-
OPT_TABLE['sh'] = %w(noop verbose)
|
997
|
-
OPT_TABLE['ruby'] = %w(noop verbose)
|
998
|
-
|
999
|
-
# Run the system command +cmd+. If multiple arguments are given the command
|
1000
|
-
# is not run with the shell (same semantics as Kernel::exec and
|
1001
|
-
# Kernel::system).
|
1002
|
-
#
|
1003
|
-
# Example:
|
1004
|
-
# sh %{ls -ltr}
|
1005
|
-
#
|
1006
|
-
# sh 'ls', 'file with spaces'
|
1007
|
-
#
|
1008
|
-
# # check exit status after command runs
|
1009
|
-
# sh %{grep pattern file} do |ok, res|
|
1010
|
-
# if ! ok
|
1011
|
-
# puts "pattern not found (status = #{res.exitstatus})"
|
1012
|
-
# end
|
1013
|
-
# end
|
1014
|
-
#
|
1015
|
-
def sh(*cmd, &block)
|
1016
|
-
options = (Hash === cmd.last) ? cmd.pop : {}
|
1017
|
-
unless block_given?
|
1018
|
-
show_command = cmd.join(" ")
|
1019
|
-
show_command = show_command[0,42] + "..." unless $trace
|
1020
|
-
# TODO code application logic heref show_command.length > 45
|
1021
|
-
block = lambda { |ok, status|
|
1022
|
-
ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
|
1023
|
-
}
|
1024
|
-
end
|
1025
|
-
if RakeFileUtils.verbose_flag == :default
|
1026
|
-
options[:verbose] = true
|
1027
|
-
else
|
1028
|
-
options[:verbose] ||= RakeFileUtils.verbose_flag
|
1029
|
-
end
|
1030
|
-
options[:noop] ||= RakeFileUtils.nowrite_flag
|
1031
|
-
rake_check_options options, :noop, :verbose
|
1032
|
-
rake_output_message cmd.join(" ") if options[:verbose]
|
1033
|
-
unless options[:noop]
|
1034
|
-
res = rake_system(*cmd)
|
1035
|
-
status = $?
|
1036
|
-
status = PseudoStatus.new(1) if !res && status.nil?
|
1037
|
-
block.call(res, status)
|
1038
|
-
end
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
def rake_system(*cmd)
|
1042
|
-
Rake::AltSystem.system(*cmd)
|
1043
|
-
end
|
1044
|
-
private :rake_system
|
1045
|
-
|
1046
|
-
# Run a Ruby interpreter with the given arguments.
|
1047
|
-
#
|
1048
|
-
# Example:
|
1049
|
-
# ruby %{-pe '$_.upcase!' <README}
|
1050
|
-
#
|
1051
|
-
def ruby(*args,&block)
|
1052
|
-
options = (Hash === args.last) ? args.pop : {}
|
1053
|
-
if args.length > 1 then
|
1054
|
-
sh(*([RUBY] + args + [options]), &block)
|
1055
|
-
else
|
1056
|
-
sh("#{RUBY} #{args.first}", options, &block)
|
1057
|
-
end
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
LN_SUPPORTED = [true]
|
1061
|
-
|
1062
|
-
# Attempt to do a normal file link, but fall back to a copy if the link
|
1063
|
-
# fails.
|
1064
|
-
def safe_ln(*args)
|
1065
|
-
unless LN_SUPPORTED[0]
|
1066
|
-
cp(*args)
|
1067
|
-
else
|
1068
|
-
begin
|
1069
|
-
ln(*args)
|
1070
|
-
rescue StandardError, NotImplementedError => ex
|
1071
|
-
LN_SUPPORTED[0] = false
|
1072
|
-
cp(*args)
|
1073
|
-
end
|
1074
|
-
end
|
1075
|
-
end
|
37
|
+
require 'rake/ext/module'
|
38
|
+
require 'rake/ext/string'
|
39
|
+
require 'rake/ext/time'
|
1076
40
|
|
1077
|
-
|
1078
|
-
#
|
1079
|
-
# Example:
|
1080
|
-
# split_all("a/b/c") => ['a', 'b', 'c']
|
1081
|
-
#
|
1082
|
-
def split_all(path)
|
1083
|
-
head, tail = File.split(path)
|
1084
|
-
return [tail] if head == '.' || tail == '/'
|
1085
|
-
return [head, tail] if head == '/'
|
1086
|
-
return split_all(head) + [tail]
|
1087
|
-
end
|
1088
|
-
end
|
1089
|
-
|
1090
|
-
#############################################################################
|
1091
|
-
# RakeFileUtils provides a custom version of the FileUtils methods that
|
1092
|
-
# respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
|
1093
|
-
#
|
1094
|
-
module RakeFileUtils
|
1095
|
-
include FileUtils
|
1096
|
-
|
1097
|
-
class << self
|
1098
|
-
attr_accessor :verbose_flag, :nowrite_flag
|
1099
|
-
end
|
1100
|
-
RakeFileUtils.verbose_flag = :default
|
1101
|
-
RakeFileUtils.nowrite_flag = false
|
1102
|
-
|
1103
|
-
$fileutils_verbose = true
|
1104
|
-
$fileutils_nowrite = false
|
1105
|
-
|
1106
|
-
FileUtils::OPT_TABLE.each do |name, opts|
|
1107
|
-
default_options = []
|
1108
|
-
if opts.include?(:verbose) || opts.include?("verbose")
|
1109
|
-
default_options << ':verbose => RakeFileUtils.verbose_flag'
|
1110
|
-
end
|
1111
|
-
if opts.include?(:noop) || opts.include?("noop")
|
1112
|
-
default_options << ':noop => RakeFileUtils.nowrite_flag'
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
next if default_options.empty?
|
1116
|
-
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
1117
|
-
def #{name}( *args, &block )
|
1118
|
-
super(
|
1119
|
-
*rake_merge_option(args,
|
1120
|
-
#{default_options.join(', ')}
|
1121
|
-
), &block)
|
1122
|
-
end
|
1123
|
-
EOS
|
1124
|
-
end
|
1125
|
-
|
1126
|
-
# Get/set the verbose flag controlling output from the FileUtils utilities.
|
1127
|
-
# If verbose is true, then the utility method is echoed to standard output.
|
1128
|
-
#
|
1129
|
-
# Examples:
|
1130
|
-
# verbose # return the current value of the verbose flag
|
1131
|
-
# verbose(v) # set the verbose flag to _v_.
|
1132
|
-
# verbose(v) { code } # Execute code with the verbose flag set temporarily to _v_.
|
1133
|
-
# # Return to the original value when code is done.
|
1134
|
-
def verbose(value=nil)
|
1135
|
-
oldvalue = RakeFileUtils.verbose_flag
|
1136
|
-
RakeFileUtils.verbose_flag = value unless value.nil?
|
1137
|
-
if block_given?
|
1138
|
-
begin
|
1139
|
-
yield
|
1140
|
-
ensure
|
1141
|
-
RakeFileUtils.verbose_flag = oldvalue
|
1142
|
-
end
|
1143
|
-
end
|
1144
|
-
RakeFileUtils.verbose_flag
|
1145
|
-
end
|
1146
|
-
|
1147
|
-
# Get/set the nowrite flag controlling output from the FileUtils utilities.
|
1148
|
-
# If verbose is true, then the utility method is echoed to standard output.
|
1149
|
-
#
|
1150
|
-
# Examples:
|
1151
|
-
# nowrite # return the current value of the nowrite flag
|
1152
|
-
# nowrite(v) # set the nowrite flag to _v_.
|
1153
|
-
# nowrite(v) { code } # Execute code with the nowrite flag set temporarily to _v_.
|
1154
|
-
# # Return to the original value when code is done.
|
1155
|
-
def nowrite(value=nil)
|
1156
|
-
oldvalue = RakeFileUtils.nowrite_flag
|
1157
|
-
RakeFileUtils.nowrite_flag = value unless value.nil?
|
1158
|
-
if block_given?
|
1159
|
-
begin
|
1160
|
-
yield
|
1161
|
-
ensure
|
1162
|
-
RakeFileUtils.nowrite_flag = oldvalue
|
1163
|
-
end
|
1164
|
-
end
|
1165
|
-
oldvalue
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
# Use this function to prevent protentially destructive ruby code from
|
1169
|
-
# running when the :nowrite flag is set.
|
1170
|
-
#
|
1171
|
-
# Example:
|
1172
|
-
#
|
1173
|
-
# when_writing("Building Project") do
|
1174
|
-
# project.build
|
1175
|
-
# end
|
1176
|
-
#
|
1177
|
-
# The following code will build the project under normal conditions. If the
|
1178
|
-
# nowrite(true) flag is set, then the example will print:
|
1179
|
-
# DRYRUN: Building Project
|
1180
|
-
# instead of actually building the project.
|
1181
|
-
#
|
1182
|
-
def when_writing(msg=nil)
|
1183
|
-
if RakeFileUtils.nowrite_flag
|
1184
|
-
puts "DRYRUN: #{msg}" if msg
|
1185
|
-
else
|
1186
|
-
yield
|
1187
|
-
end
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
# Merge the given options with the default values.
|
1191
|
-
def rake_merge_option(args, defaults)
|
1192
|
-
if Hash === args.last
|
1193
|
-
defaults.update(args.last)
|
1194
|
-
args.pop
|
1195
|
-
end
|
1196
|
-
args.push defaults
|
1197
|
-
args
|
1198
|
-
end
|
1199
|
-
private :rake_merge_option
|
1200
|
-
|
1201
|
-
# Send the message to the default rake output (which is $stderr).
|
1202
|
-
def rake_output_message(message)
|
1203
|
-
$stderr.puts(message)
|
1204
|
-
end
|
1205
|
-
private :rake_output_message
|
1206
|
-
|
1207
|
-
# Check that the options do not contain options not listed in +optdecl+. An
|
1208
|
-
# ArgumentError exception is thrown if non-declared options are found.
|
1209
|
-
def rake_check_options(options, *optdecl)
|
1210
|
-
h = options.dup
|
1211
|
-
optdecl.each do |name|
|
1212
|
-
h.delete name
|
1213
|
-
end
|
1214
|
-
raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
|
1215
|
-
end
|
1216
|
-
private :rake_check_options
|
1217
|
-
|
1218
|
-
extend self
|
1219
|
-
end
|
1220
|
-
|
1221
|
-
#############################################################################
|
1222
|
-
# Include the FileUtils file manipulation functions in the top level module,
|
1223
|
-
# but mark them private so that they don't unintentionally define methods on
|
1224
|
-
# other objects.
|
1225
|
-
|
1226
|
-
include RakeFileUtils
|
1227
|
-
private(*FileUtils.instance_methods(false))
|
1228
|
-
private(*RakeFileUtils.instance_methods(false))
|
1229
|
-
|
1230
|
-
######################################################################
|
1231
|
-
module Rake
|
1232
|
-
|
1233
|
-
###########################################################################
|
1234
|
-
# A FileList is essentially an array with a few helper methods defined to
|
1235
|
-
# make file manipulation a bit easier.
|
1236
|
-
#
|
1237
|
-
# FileLists are lazy. When given a list of glob patterns for possible files
|
1238
|
-
# to be included in the file list, instead of searching the file structures
|
1239
|
-
# to find the files, a FileList holds the pattern for latter use.
|
1240
|
-
#
|
1241
|
-
# This allows us to define a number of FileList to match any number of
|
1242
|
-
# files, but only search out the actual files when then FileList itself is
|
1243
|
-
# actually used. The key is that the first time an element of the
|
1244
|
-
# FileList/Array is requested, the pending patterns are resolved into a real
|
1245
|
-
# list of file names.
|
1246
|
-
#
|
1247
|
-
class FileList
|
1248
|
-
|
1249
|
-
include Cloneable
|
1250
|
-
|
1251
|
-
# == Method Delegation
|
1252
|
-
#
|
1253
|
-
# The lazy evaluation magic of FileLists happens by implementing all the
|
1254
|
-
# array specific methods to call +resolve+ before delegating the heavy
|
1255
|
-
# lifting to an embedded array object (@items).
|
1256
|
-
#
|
1257
|
-
# In addition, there are two kinds of delegation calls. The regular kind
|
1258
|
-
# delegates to the @items array and returns the result directly. Well,
|
1259
|
-
# almost directly. It checks if the returned value is the @items object
|
1260
|
-
# itself, and if so will return the FileList object instead.
|
1261
|
-
#
|
1262
|
-
# The second kind of delegation call is used in methods that normally
|
1263
|
-
# return a new Array object. We want to capture the return value of these
|
1264
|
-
# methods and wrap them in a new FileList object. We enumerate these
|
1265
|
-
# methods in the +SPECIAL_RETURN+ list below.
|
1266
|
-
|
1267
|
-
# List of array methods (that are not in +Object+) that need to be
|
1268
|
-
# delegated.
|
1269
|
-
ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
|
1270
|
-
|
1271
|
-
# List of additional methods that must be delegated.
|
1272
|
-
MUST_DEFINE = %w[to_a inspect]
|
1273
|
-
|
1274
|
-
# List of methods that should not be delegated here (we define special
|
1275
|
-
# versions of them explicitly below).
|
1276
|
-
MUST_NOT_DEFINE = %w[to_a to_ary partition *]
|
1277
|
-
|
1278
|
-
# List of delegated methods that return new array values which need
|
1279
|
-
# wrapping.
|
1280
|
-
SPECIAL_RETURN = %w[
|
1281
|
-
map collect sort sort_by select find_all reject grep
|
1282
|
-
compact flatten uniq values_at
|
1283
|
-
+ - & |
|
1284
|
-
]
|
1285
|
-
|
1286
|
-
DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
|
1287
|
-
|
1288
|
-
# Now do the delegation.
|
1289
|
-
DELEGATING_METHODS.each_with_index do |sym, i|
|
1290
|
-
if SPECIAL_RETURN.include?(sym)
|
1291
|
-
ln = __LINE__+1
|
1292
|
-
class_eval %{
|
1293
|
-
def #{sym}(*args, &block)
|
1294
|
-
resolve
|
1295
|
-
result = @items.send(:#{sym}, *args, &block)
|
1296
|
-
FileList.new.import(result)
|
1297
|
-
end
|
1298
|
-
}, __FILE__, ln
|
1299
|
-
else
|
1300
|
-
ln = __LINE__+1
|
1301
|
-
class_eval %{
|
1302
|
-
def #{sym}(*args, &block)
|
1303
|
-
resolve
|
1304
|
-
result = @items.send(:#{sym}, *args, &block)
|
1305
|
-
result.object_id == @items.object_id ? self : result
|
1306
|
-
end
|
1307
|
-
}, __FILE__, ln
|
1308
|
-
end
|
1309
|
-
end
|
1310
|
-
|
1311
|
-
# Create a file list from the globbable patterns given. If you wish to
|
1312
|
-
# perform multiple includes or excludes at object build time, use the
|
1313
|
-
# "yield self" pattern.
|
1314
|
-
#
|
1315
|
-
# Example:
|
1316
|
-
# file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
|
1317
|
-
#
|
1318
|
-
# pkg_files = FileList.new('lib/**/*') do |fl|
|
1319
|
-
# fl.exclude(/\bCVS\b/)
|
1320
|
-
# end
|
1321
|
-
#
|
1322
|
-
def initialize(*patterns)
|
1323
|
-
@pending_add = []
|
1324
|
-
@pending = false
|
1325
|
-
@exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
|
1326
|
-
@exclude_procs = DEFAULT_IGNORE_PROCS.dup
|
1327
|
-
@exclude_re = nil
|
1328
|
-
@items = []
|
1329
|
-
patterns.each { |pattern| include(pattern) }
|
1330
|
-
yield self if block_given?
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
# Add file names defined by glob patterns to the file list. If an array
|
1334
|
-
# is given, add each element of the array.
|
1335
|
-
#
|
1336
|
-
# Example:
|
1337
|
-
# file_list.include("*.java", "*.cfg")
|
1338
|
-
# file_list.include %w( math.c lib.h *.o )
|
1339
|
-
#
|
1340
|
-
def include(*filenames)
|
1341
|
-
# TODO: check for pending
|
1342
|
-
filenames.each do |fn|
|
1343
|
-
if fn.respond_to? :to_ary
|
1344
|
-
include(*fn.to_ary)
|
1345
|
-
else
|
1346
|
-
@pending_add << fn
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
@pending = true
|
1350
|
-
self
|
1351
|
-
end
|
1352
|
-
alias :add :include
|
1353
|
-
|
1354
|
-
# Register a list of file name patterns that should be excluded from the
|
1355
|
-
# list. Patterns may be regular expressions, glob patterns or regular
|
1356
|
-
# strings. In addition, a block given to exclude will remove entries that
|
1357
|
-
# return true when given to the block.
|
1358
|
-
#
|
1359
|
-
# Note that glob patterns are expanded against the file system. If a file
|
1360
|
-
# is explicitly added to a file list, but does not exist in the file
|
1361
|
-
# system, then an glob pattern in the exclude list will not exclude the
|
1362
|
-
# file.
|
1363
|
-
#
|
1364
|
-
# Examples:
|
1365
|
-
# FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
|
1366
|
-
# FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
|
1367
|
-
#
|
1368
|
-
# If "a.c" is a file, then ...
|
1369
|
-
# FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
|
1370
|
-
#
|
1371
|
-
# If "a.c" is not a file, then ...
|
1372
|
-
# FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
|
1373
|
-
#
|
1374
|
-
def exclude(*patterns, &block)
|
1375
|
-
patterns.each do |pat|
|
1376
|
-
@exclude_patterns << pat
|
1377
|
-
end
|
1378
|
-
if block_given?
|
1379
|
-
@exclude_procs << block
|
1380
|
-
end
|
1381
|
-
resolve_exclude if ! @pending
|
1382
|
-
self
|
1383
|
-
end
|
1384
|
-
|
1385
|
-
|
1386
|
-
# Clear all the exclude patterns so that we exclude nothing.
|
1387
|
-
def clear_exclude
|
1388
|
-
@exclude_patterns = []
|
1389
|
-
@exclude_procs = []
|
1390
|
-
calculate_exclude_regexp if ! @pending
|
1391
|
-
self
|
1392
|
-
end
|
1393
|
-
|
1394
|
-
# Define equality.
|
1395
|
-
def ==(array)
|
1396
|
-
to_ary == array
|
1397
|
-
end
|
1398
|
-
|
1399
|
-
# Return the internal array object.
|
1400
|
-
def to_a
|
1401
|
-
resolve
|
1402
|
-
@items
|
1403
|
-
end
|
1404
|
-
|
1405
|
-
# Return the internal array object.
|
1406
|
-
def to_ary
|
1407
|
-
to_a
|
1408
|
-
end
|
1409
|
-
|
1410
|
-
# Lie about our class.
|
1411
|
-
def is_a?(klass)
|
1412
|
-
klass == Array || super(klass)
|
1413
|
-
end
|
1414
|
-
alias kind_of? is_a?
|
1415
|
-
|
1416
|
-
# Redefine * to return either a string or a new file list.
|
1417
|
-
def *(other)
|
1418
|
-
result = @items * other
|
1419
|
-
case result
|
1420
|
-
when Array
|
1421
|
-
FileList.new.import(result)
|
1422
|
-
else
|
1423
|
-
result
|
1424
|
-
end
|
1425
|
-
end
|
1426
|
-
|
1427
|
-
# Resolve all the pending adds now.
|
1428
|
-
def resolve
|
1429
|
-
if @pending
|
1430
|
-
@pending = false
|
1431
|
-
@pending_add.each do |fn| resolve_add(fn) end
|
1432
|
-
@pending_add = []
|
1433
|
-
resolve_exclude
|
1434
|
-
end
|
1435
|
-
self
|
1436
|
-
end
|
1437
|
-
|
1438
|
-
def calculate_exclude_regexp
|
1439
|
-
ignores = []
|
1440
|
-
@exclude_patterns.each do |pat|
|
1441
|
-
case pat
|
1442
|
-
when Regexp
|
1443
|
-
ignores << pat
|
1444
|
-
when /[*?]/
|
1445
|
-
Dir[pat].each do |p| ignores << p end
|
1446
|
-
else
|
1447
|
-
ignores << Regexp.quote(pat)
|
1448
|
-
end
|
1449
|
-
end
|
1450
|
-
if ignores.empty?
|
1451
|
-
@exclude_re = /^$/
|
1452
|
-
else
|
1453
|
-
re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
|
1454
|
-
@exclude_re = Regexp.new(re_str)
|
1455
|
-
end
|
1456
|
-
end
|
1457
|
-
|
1458
|
-
def resolve_add(fn)
|
1459
|
-
case fn
|
1460
|
-
when %r{[*?\[\{]}
|
1461
|
-
add_matching(fn)
|
1462
|
-
else
|
1463
|
-
self << fn
|
1464
|
-
end
|
1465
|
-
end
|
1466
|
-
private :resolve_add
|
1467
|
-
|
1468
|
-
def resolve_exclude
|
1469
|
-
calculate_exclude_regexp
|
1470
|
-
reject! { |fn| exclude?(fn) }
|
1471
|
-
self
|
1472
|
-
end
|
1473
|
-
private :resolve_exclude
|
1474
|
-
|
1475
|
-
# Return a new FileList with the results of running +sub+ against each
|
1476
|
-
# element of the oringal list.
|
1477
|
-
#
|
1478
|
-
# Example:
|
1479
|
-
# FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
|
1480
|
-
#
|
1481
|
-
def sub(pat, rep)
|
1482
|
-
inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
|
1483
|
-
end
|
1484
|
-
|
1485
|
-
# Return a new FileList with the results of running +gsub+ against each
|
1486
|
-
# element of the original list.
|
1487
|
-
#
|
1488
|
-
# Example:
|
1489
|
-
# FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
|
1490
|
-
# => ['lib\\test\\file', 'x\\y']
|
1491
|
-
#
|
1492
|
-
def gsub(pat, rep)
|
1493
|
-
inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
|
1494
|
-
end
|
1495
|
-
|
1496
|
-
# Same as +sub+ except that the oringal file list is modified.
|
1497
|
-
def sub!(pat, rep)
|
1498
|
-
each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
|
1499
|
-
self
|
1500
|
-
end
|
1501
|
-
|
1502
|
-
# Same as +gsub+ except that the original file list is modified.
|
1503
|
-
def gsub!(pat, rep)
|
1504
|
-
each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
|
1505
|
-
self
|
1506
|
-
end
|
1507
|
-
|
1508
|
-
# Apply the pathmap spec to each of the included file names, returning a
|
1509
|
-
# new file list with the modified paths. (See String#pathmap for
|
1510
|
-
# details.)
|
1511
|
-
def pathmap(spec=nil)
|
1512
|
-
collect { |fn| fn.pathmap(spec) }
|
1513
|
-
end
|
1514
|
-
|
1515
|
-
# Return a new FileList with <tt>String#ext</tt> method applied
|
1516
|
-
# to each member of the array.
|
1517
|
-
#
|
1518
|
-
# This method is a shortcut for:
|
1519
|
-
#
|
1520
|
-
# array.collect { |item| item.ext(newext) }
|
1521
|
-
#
|
1522
|
-
# +ext+ is a user added method for the Array class.
|
1523
|
-
def ext(newext='')
|
1524
|
-
collect { |fn| fn.ext(newext) }
|
1525
|
-
end
|
1526
|
-
|
1527
|
-
|
1528
|
-
# Grep each of the files in the filelist using the given pattern. If a
|
1529
|
-
# block is given, call the block on each matching line, passing the file
|
1530
|
-
# name, line number, and the matching line of text. If no block is given,
|
1531
|
-
# a standard emac style file:linenumber:line message will be printed to
|
1532
|
-
# standard out.
|
1533
|
-
def egrep(pattern, *options)
|
1534
|
-
each do |fn|
|
1535
|
-
open(fn, "rb", *options) do |inf|
|
1536
|
-
count = 0
|
1537
|
-
inf.each do |line|
|
1538
|
-
count += 1
|
1539
|
-
if pattern.match(line)
|
1540
|
-
if block_given?
|
1541
|
-
yield fn, count, line
|
1542
|
-
else
|
1543
|
-
puts "#{fn}:#{count}:#{line}"
|
1544
|
-
end
|
1545
|
-
end
|
1546
|
-
end
|
1547
|
-
end
|
1548
|
-
end
|
1549
|
-
end
|
1550
|
-
|
1551
|
-
# Return a new file list that only contains file names from the current
|
1552
|
-
# file list that exist on the file system.
|
1553
|
-
def existing
|
1554
|
-
select { |fn| File.exist?(fn) }
|
1555
|
-
end
|
1556
|
-
|
1557
|
-
# Modify the current file list so that it contains only file name that
|
1558
|
-
# exist on the file system.
|
1559
|
-
def existing!
|
1560
|
-
resolve
|
1561
|
-
@items = @items.select { |fn| File.exist?(fn) }
|
1562
|
-
self
|
1563
|
-
end
|
1564
|
-
|
1565
|
-
# FileList version of partition. Needed because the nested arrays should
|
1566
|
-
# be FileLists in this version.
|
1567
|
-
def partition(&block) # :nodoc:
|
1568
|
-
resolve
|
1569
|
-
result = @items.partition(&block)
|
1570
|
-
[
|
1571
|
-
FileList.new.import(result[0]),
|
1572
|
-
FileList.new.import(result[1]),
|
1573
|
-
]
|
1574
|
-
end
|
1575
|
-
|
1576
|
-
# Convert a FileList to a string by joining all elements with a space.
|
1577
|
-
def to_s
|
1578
|
-
resolve
|
1579
|
-
self.join(' ')
|
1580
|
-
end
|
1581
|
-
|
1582
|
-
# Add matching glob patterns.
|
1583
|
-
def add_matching(pattern)
|
1584
|
-
Dir[pattern].each do |fn|
|
1585
|
-
self << fn unless exclude?(fn)
|
1586
|
-
end
|
1587
|
-
end
|
1588
|
-
private :add_matching
|
1589
|
-
|
1590
|
-
# Should the given file name be excluded?
|
1591
|
-
def exclude?(fn)
|
1592
|
-
calculate_exclude_regexp unless @exclude_re
|
1593
|
-
fn =~ @exclude_re || @exclude_procs.any? { |p| p.call(fn) }
|
1594
|
-
end
|
1595
|
-
|
1596
|
-
DEFAULT_IGNORE_PATTERNS = [
|
1597
|
-
/(^|[\/\\])CVS([\/\\]|$)/,
|
1598
|
-
/(^|[\/\\])\.svn([\/\\]|$)/,
|
1599
|
-
/\.bak$/,
|
1600
|
-
/~$/
|
1601
|
-
]
|
1602
|
-
DEFAULT_IGNORE_PROCS = [
|
1603
|
-
proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
|
1604
|
-
]
|
1605
|
-
# @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
|
1606
|
-
|
1607
|
-
def import(array)
|
1608
|
-
@items = array
|
1609
|
-
self
|
1610
|
-
end
|
41
|
+
require 'rake/win32'
|
1611
42
|
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
43
|
+
require 'rake/task_argument_error'
|
44
|
+
require 'rake/rule_recursion_overflow_error'
|
45
|
+
require 'rake/rake_module'
|
46
|
+
require 'rake/pseudo_status'
|
47
|
+
require 'rake/task_arguments'
|
48
|
+
require 'rake/invocation_chain'
|
49
|
+
require 'rake/task'
|
50
|
+
require 'rake/file_task'
|
51
|
+
require 'rake/file_creation_task'
|
52
|
+
require 'rake/multi_task'
|
53
|
+
require 'rake/dsl_definition'
|
54
|
+
require 'rake/file_utils_ext'
|
55
|
+
require 'rake/file_list'
|
56
|
+
require 'rake/default_loader'
|
57
|
+
require 'rake/early_time'
|
58
|
+
require 'rake/name_space'
|
59
|
+
require 'rake/task_manager'
|
60
|
+
require 'rake/application'
|
1622
61
|
|
1623
|
-
|
1624
|
-
class << self
|
62
|
+
$trace = false
|
1625
63
|
|
1626
|
-
|
1627
|
-
def each_dir_parent(dir) # :nodoc:
|
1628
|
-
old_length = nil
|
1629
|
-
while dir != '.' && dir.length != old_length
|
1630
|
-
yield(dir)
|
1631
|
-
old_length = dir.length
|
1632
|
-
dir = File.dirname(dir)
|
1633
|
-
end
|
1634
|
-
end
|
1635
|
-
end
|
1636
|
-
end # module Rake
|
64
|
+
# Some top level Constants.
|
1637
65
|
|
1638
|
-
# Alias FileList to be available at the top level.
|
1639
66
|
FileList = Rake::FileList
|
1640
|
-
|
1641
|
-
#############################################################################
|
1642
|
-
module Rake
|
1643
|
-
|
1644
|
-
# Default Rakefile loader used by +import+.
|
1645
|
-
class DefaultLoader
|
1646
|
-
def load(fn)
|
1647
|
-
Kernel.load(File.expand_path(fn))
|
1648
|
-
end
|
1649
|
-
end
|
1650
|
-
|
1651
|
-
# EarlyTime is a fake timestamp that occurs _before_ any other time value.
|
1652
|
-
class EarlyTime
|
1653
|
-
include Comparable
|
1654
|
-
include Singleton
|
1655
|
-
|
1656
|
-
def <=>(other)
|
1657
|
-
-1
|
1658
|
-
end
|
1659
|
-
|
1660
|
-
def to_s
|
1661
|
-
"<EARLY TIME>"
|
1662
|
-
end
|
1663
|
-
end
|
1664
|
-
|
1665
|
-
EARLY = EarlyTime.instance
|
1666
|
-
end # module Rake
|
1667
|
-
|
1668
|
-
#############################################################################
|
1669
|
-
# Extensions to time to allow comparisons with an early time class.
|
1670
|
-
#
|
1671
|
-
class Time
|
1672
|
-
alias rake_original_time_compare :<=>
|
1673
|
-
def <=>(other)
|
1674
|
-
if Rake::EarlyTime === other
|
1675
|
-
- other.<=>(self)
|
1676
|
-
else
|
1677
|
-
rake_original_time_compare(other)
|
1678
|
-
end
|
1679
|
-
end
|
1680
|
-
end # class Time
|
1681
|
-
|
1682
|
-
module Rake
|
1683
|
-
|
1684
|
-
####################################################################
|
1685
|
-
# The NameSpace class will lookup task names in the the scope
|
1686
|
-
# defined by a +namespace+ command.
|
1687
|
-
#
|
1688
|
-
class NameSpace
|
1689
|
-
|
1690
|
-
# Create a namespace lookup object using the given task manager
|
1691
|
-
# and the list of scopes.
|
1692
|
-
def initialize(task_manager, scope_list)
|
1693
|
-
@task_manager = task_manager
|
1694
|
-
@scope = scope_list.dup
|
1695
|
-
end
|
1696
|
-
|
1697
|
-
# Lookup a task named +name+ in the namespace.
|
1698
|
-
def [](name)
|
1699
|
-
@task_manager.lookup(name, @scope)
|
1700
|
-
end
|
1701
|
-
|
1702
|
-
# Return the list of tasks defined in this and nested namespaces.
|
1703
|
-
def tasks
|
1704
|
-
@task_manager.tasks_in_scope(@scope)
|
1705
|
-
end
|
1706
|
-
end # NameSpace
|
1707
|
-
|
1708
|
-
|
1709
|
-
####################################################################
|
1710
|
-
# The TaskManager module is a mixin for managing tasks.
|
1711
|
-
module TaskManager
|
1712
|
-
# Track the last comment made in the Rakefile.
|
1713
|
-
attr_accessor :last_description
|
1714
|
-
alias :last_comment :last_description # Backwards compatibility
|
1715
|
-
|
1716
|
-
def initialize
|
1717
|
-
super
|
1718
|
-
@tasks = Hash.new
|
1719
|
-
@rules = Array.new
|
1720
|
-
@scope = Array.new
|
1721
|
-
@last_description = nil
|
1722
|
-
end
|
1723
|
-
|
1724
|
-
def create_rule(*args, &block)
|
1725
|
-
pattern, arg_names, deps = resolve_args(args)
|
1726
|
-
pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
|
1727
|
-
@rules << [pattern, deps, block]
|
1728
|
-
end
|
1729
|
-
|
1730
|
-
def define_task(task_class, *args, &block)
|
1731
|
-
task_name, arg_names, deps = resolve_args(args)
|
1732
|
-
task_name = task_class.scope_name(@scope, task_name)
|
1733
|
-
deps = [deps] unless deps.respond_to?(:to_ary)
|
1734
|
-
deps = deps.collect {|d| d.to_s }
|
1735
|
-
task = intern(task_class, task_name)
|
1736
|
-
task.set_arg_names(arg_names) unless arg_names.empty?
|
1737
|
-
task.add_description(@last_description)
|
1738
|
-
@last_description = nil
|
1739
|
-
task.enhance(deps, &block)
|
1740
|
-
task
|
1741
|
-
end
|
1742
|
-
|
1743
|
-
# Lookup a task. Return an existing task if found, otherwise
|
1744
|
-
# create a task of the current type.
|
1745
|
-
def intern(task_class, task_name)
|
1746
|
-
@tasks[task_name.to_s] ||= task_class.new(task_name, self)
|
1747
|
-
end
|
1748
|
-
|
1749
|
-
# Find a matching task for +task_name+.
|
1750
|
-
def [](task_name, scopes=nil)
|
1751
|
-
task_name = task_name.to_s
|
1752
|
-
self.lookup(task_name, scopes) or
|
1753
|
-
enhance_with_matching_rule(task_name) or
|
1754
|
-
synthesize_file_task(task_name) or
|
1755
|
-
fail "Don't know how to build task '#{task_name}'"
|
1756
|
-
end
|
1757
|
-
|
1758
|
-
def synthesize_file_task(task_name)
|
1759
|
-
return nil unless File.exist?(task_name)
|
1760
|
-
define_task(Rake::FileTask, task_name)
|
1761
|
-
end
|
1762
|
-
|
1763
|
-
# Resolve the arguments for a task/rule. Returns a triplet of
|
1764
|
-
# [task_name, arg_name_list, prerequisites].
|
1765
|
-
def resolve_args(args)
|
1766
|
-
if args.last.is_a?(Hash)
|
1767
|
-
deps = args.pop
|
1768
|
-
resolve_args_with_dependencies(args, deps)
|
1769
|
-
else
|
1770
|
-
resolve_args_without_dependencies(args)
|
1771
|
-
end
|
1772
|
-
end
|
1773
|
-
|
1774
|
-
# Resolve task arguments for a task or rule when there are no
|
1775
|
-
# dependencies declared.
|
1776
|
-
#
|
1777
|
-
# The patterns recognized by this argument resolving function are:
|
1778
|
-
#
|
1779
|
-
# task :t
|
1780
|
-
# task :t, [:a]
|
1781
|
-
# task :t, :a (deprecated)
|
1782
|
-
#
|
1783
|
-
def resolve_args_without_dependencies(args)
|
1784
|
-
task_name = args.shift
|
1785
|
-
if args.size == 1 && args.first.respond_to?(:to_ary)
|
1786
|
-
arg_names = args.first.to_ary
|
1787
|
-
else
|
1788
|
-
arg_names = args
|
1789
|
-
end
|
1790
|
-
[task_name, arg_names, []]
|
1791
|
-
end
|
1792
|
-
private :resolve_args_without_dependencies
|
1793
|
-
|
1794
|
-
# Resolve task arguments for a task or rule when there are
|
1795
|
-
# dependencies declared.
|
1796
|
-
#
|
1797
|
-
# The patterns recognized by this argument resolving function are:
|
1798
|
-
#
|
1799
|
-
# task :t => [:d]
|
1800
|
-
# task :t, [a] => [:d]
|
1801
|
-
# task :t, :needs => [:d] (deprecated)
|
1802
|
-
# task :t, :a, :needs => [:d] (deprecated)
|
1803
|
-
#
|
1804
|
-
def resolve_args_with_dependencies(args, hash) # :nodoc:
|
1805
|
-
fail "Task Argument Error" if hash.size != 1
|
1806
|
-
key, value = hash.map { |k, v| [k,v] }.first
|
1807
|
-
if args.empty?
|
1808
|
-
task_name = key
|
1809
|
-
arg_names = []
|
1810
|
-
deps = value
|
1811
|
-
elsif key == :needs
|
1812
|
-
task_name = args.shift
|
1813
|
-
arg_names = args
|
1814
|
-
deps = value
|
1815
|
-
else
|
1816
|
-
task_name = args.shift
|
1817
|
-
arg_names = key
|
1818
|
-
deps = value
|
1819
|
-
end
|
1820
|
-
deps = [deps] unless deps.respond_to?(:to_ary)
|
1821
|
-
[task_name, arg_names, deps]
|
1822
|
-
end
|
1823
|
-
private :resolve_args_with_dependencies
|
1824
|
-
|
1825
|
-
# If a rule can be found that matches the task name, enhance the
|
1826
|
-
# task with the prerequisites and actions from the rule. Set the
|
1827
|
-
# source attribute of the task appropriately for the rule. Return
|
1828
|
-
# the enhanced task or nil of no rule was found.
|
1829
|
-
def enhance_with_matching_rule(task_name, level=0)
|
1830
|
-
fail Rake::RuleRecursionOverflowError,
|
1831
|
-
"Rule Recursion Too Deep" if level >= 16
|
1832
|
-
@rules.each do |pattern, extensions, block|
|
1833
|
-
if md = pattern.match(task_name)
|
1834
|
-
task = attempt_rule(task_name, extensions, block, level)
|
1835
|
-
return task if task
|
1836
|
-
end
|
1837
|
-
end
|
1838
|
-
nil
|
1839
|
-
rescue Rake::RuleRecursionOverflowError => ex
|
1840
|
-
ex.add_target(task_name)
|
1841
|
-
fail ex
|
1842
|
-
end
|
1843
|
-
|
1844
|
-
# List of all defined tasks in this application.
|
1845
|
-
def tasks
|
1846
|
-
@tasks.values.sort_by { |t| t.name }
|
1847
|
-
end
|
1848
|
-
|
1849
|
-
# List of all the tasks defined in the given scope (and its
|
1850
|
-
# sub-scopes).
|
1851
|
-
def tasks_in_scope(scope)
|
1852
|
-
prefix = scope.join(":")
|
1853
|
-
tasks.select { |t|
|
1854
|
-
/^#{prefix}:/ =~ t.name
|
1855
|
-
}
|
1856
|
-
end
|
1857
|
-
|
1858
|
-
# Clear all tasks in this application.
|
1859
|
-
def clear
|
1860
|
-
@tasks.clear
|
1861
|
-
@rules.clear
|
1862
|
-
end
|
1863
|
-
|
1864
|
-
# Lookup a task, using scope and the scope hints in the task name.
|
1865
|
-
# This method performs straight lookups without trying to
|
1866
|
-
# synthesize file tasks or rules. Special scope names (e.g. '^')
|
1867
|
-
# are recognized. If no scope argument is supplied, use the
|
1868
|
-
# current scope. Return nil if the task cannot be found.
|
1869
|
-
def lookup(task_name, initial_scope=nil)
|
1870
|
-
initial_scope ||= @scope
|
1871
|
-
task_name = task_name.to_s
|
1872
|
-
if task_name =~ /^rake:/
|
1873
|
-
scopes = []
|
1874
|
-
task_name = task_name.sub(/^rake:/, '')
|
1875
|
-
elsif task_name =~ /^(\^+)/
|
1876
|
-
scopes = initial_scope[0, initial_scope.size - $1.size]
|
1877
|
-
task_name = task_name.sub(/^(\^+)/, '')
|
1878
|
-
else
|
1879
|
-
scopes = initial_scope
|
1880
|
-
end
|
1881
|
-
lookup_in_scope(task_name, scopes)
|
1882
|
-
end
|
1883
|
-
|
1884
|
-
# Lookup the task name
|
1885
|
-
def lookup_in_scope(name, scope)
|
1886
|
-
n = scope.size
|
1887
|
-
while n >= 0
|
1888
|
-
tn = (scope[0,n] + [name]).join(':')
|
1889
|
-
task = @tasks[tn]
|
1890
|
-
return task if task
|
1891
|
-
n -= 1
|
1892
|
-
end
|
1893
|
-
nil
|
1894
|
-
end
|
1895
|
-
private :lookup_in_scope
|
1896
|
-
|
1897
|
-
# Return the list of scope names currently active in the task
|
1898
|
-
# manager.
|
1899
|
-
def current_scope
|
1900
|
-
@scope.dup
|
1901
|
-
end
|
1902
|
-
|
1903
|
-
# Evaluate the block in a nested namespace named +name+. Create
|
1904
|
-
# an anonymous namespace if +name+ is nil.
|
1905
|
-
def in_namespace(name)
|
1906
|
-
name ||= generate_name
|
1907
|
-
@scope.push(name)
|
1908
|
-
ns = NameSpace.new(self, @scope)
|
1909
|
-
yield(ns)
|
1910
|
-
ns
|
1911
|
-
ensure
|
1912
|
-
@scope.pop
|
1913
|
-
end
|
1914
|
-
|
1915
|
-
private
|
1916
|
-
|
1917
|
-
# Generate an anonymous namespace name.
|
1918
|
-
def generate_name
|
1919
|
-
@seed ||= 0
|
1920
|
-
@seed += 1
|
1921
|
-
"_anon_#{@seed}"
|
1922
|
-
end
|
1923
|
-
|
1924
|
-
def trace_rule(level, message)
|
1925
|
-
puts "#{" "*level}#{message}" if Rake.application.options.trace_rules
|
1926
|
-
end
|
1927
|
-
|
1928
|
-
# Attempt to create a rule given the list of prerequisites.
|
1929
|
-
def attempt_rule(task_name, extensions, block, level)
|
1930
|
-
sources = make_sources(task_name, extensions)
|
1931
|
-
prereqs = sources.collect { |source|
|
1932
|
-
trace_rule level, "Attempting Rule #{task_name} => #{source}"
|
1933
|
-
if File.exist?(source) || Rake::Task.task_defined?(source)
|
1934
|
-
trace_rule level, "(#{task_name} => #{source} ... EXIST)"
|
1935
|
-
source
|
1936
|
-
elsif parent = enhance_with_matching_rule(source, level+1)
|
1937
|
-
trace_rule level, "(#{task_name} => #{source} ... ENHANCE)"
|
1938
|
-
parent.name
|
1939
|
-
else
|
1940
|
-
trace_rule level, "(#{task_name} => #{source} ... FAIL)"
|
1941
|
-
return nil
|
1942
|
-
end
|
1943
|
-
}
|
1944
|
-
task = FileTask.define_task({task_name => prereqs}, &block)
|
1945
|
-
task.sources = prereqs
|
1946
|
-
task
|
1947
|
-
end
|
1948
|
-
|
1949
|
-
# Make a list of sources from the list of file name extensions /
|
1950
|
-
# translation procs.
|
1951
|
-
def make_sources(task_name, extensions)
|
1952
|
-
extensions.collect { |ext|
|
1953
|
-
case ext
|
1954
|
-
when /%/
|
1955
|
-
task_name.pathmap(ext)
|
1956
|
-
when %r{/}
|
1957
|
-
ext
|
1958
|
-
when /^\./
|
1959
|
-
task_name.ext(ext)
|
1960
|
-
when String
|
1961
|
-
ext
|
1962
|
-
when Proc
|
1963
|
-
if ext.arity == 1
|
1964
|
-
ext.call(task_name)
|
1965
|
-
else
|
1966
|
-
ext.call
|
1967
|
-
end
|
1968
|
-
else
|
1969
|
-
fail "Don't know how to handle rule dependent: #{ext.inspect}"
|
1970
|
-
end
|
1971
|
-
}.flatten
|
1972
|
-
end
|
1973
|
-
|
1974
|
-
end # TaskManager
|
1975
|
-
|
1976
|
-
#
|
1977
|
-
# Lazily pull in the parallelizing code
|
1978
|
-
#
|
1979
|
-
class Options < OpenStruct # :nodoc:
|
1980
|
-
attr_reader :threads
|
1981
|
-
|
1982
|
-
def initialize
|
1983
|
-
super
|
1984
|
-
@threads = 1
|
1985
|
-
end
|
1986
|
-
|
1987
|
-
def threads=(n)
|
1988
|
-
if n > 1 and require('rake/parallel')
|
1989
|
-
Task.module_eval { include Parallel::TaskMixin }
|
1990
|
-
Application.module_eval { include Parallel::ApplicationMixin }
|
1991
|
-
end
|
1992
|
-
@threads = n
|
1993
|
-
end
|
1994
|
-
end
|
1995
|
-
|
1996
|
-
######################################################################
|
1997
|
-
# Rake main application object. When invoking +rake+ from the
|
1998
|
-
# command line, a Rake::Application object is created and run.
|
1999
|
-
#
|
2000
|
-
class Application
|
2001
|
-
include TaskManager
|
2002
|
-
|
2003
|
-
# The name of the application (typically 'rake')
|
2004
|
-
attr_reader :name
|
2005
|
-
|
2006
|
-
# The original directory where rake was invoked.
|
2007
|
-
attr_reader :original_dir
|
2008
|
-
|
2009
|
-
# Name of the actual rakefile used.
|
2010
|
-
attr_reader :rakefile
|
2011
|
-
|
2012
|
-
# List of the top level task names (task names from the command line).
|
2013
|
-
attr_reader :top_level_tasks
|
2014
|
-
|
2015
|
-
DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
|
2016
|
-
|
2017
|
-
# Initialize a Rake::Application object.
|
2018
|
-
def initialize
|
2019
|
-
super
|
2020
|
-
@name = 'rake'
|
2021
|
-
@rakefiles = DEFAULT_RAKEFILES.dup
|
2022
|
-
@rakefile = nil
|
2023
|
-
@pending_imports = []
|
2024
|
-
@imported = []
|
2025
|
-
@loaders = {}
|
2026
|
-
@default_loader = Rake::DefaultLoader.new
|
2027
|
-
@original_dir = Dir.pwd
|
2028
|
-
@top_level_tasks = []
|
2029
|
-
add_loader('rb', DefaultLoader.new)
|
2030
|
-
add_loader('rf', DefaultLoader.new)
|
2031
|
-
add_loader('rake', DefaultLoader.new)
|
2032
|
-
@tty_output = STDOUT.tty?
|
2033
|
-
end
|
2034
|
-
|
2035
|
-
# Run the Rake application. The run method performs the following three steps:
|
2036
|
-
#
|
2037
|
-
# * Initialize the command line options (+init+).
|
2038
|
-
# * Define the tasks (+load_rakefile+).
|
2039
|
-
# * Run the top level tasks (+run_tasks+).
|
2040
|
-
#
|
2041
|
-
# If you wish to build a custom rake command, you should call +init+ on your
|
2042
|
-
# application. The define any tasks. Finally, call +top_level+ to run your top
|
2043
|
-
# level tasks.
|
2044
|
-
def run
|
2045
|
-
standard_exception_handling do
|
2046
|
-
init
|
2047
|
-
load_rakefile
|
2048
|
-
top_level
|
2049
|
-
end
|
2050
|
-
end
|
2051
|
-
|
2052
|
-
# Initialize the command line parameters and app name.
|
2053
|
-
def init(app_name='rake')
|
2054
|
-
standard_exception_handling do
|
2055
|
-
@name = app_name
|
2056
|
-
handle_options
|
2057
|
-
collect_tasks
|
2058
|
-
end
|
2059
|
-
end
|
2060
|
-
|
2061
|
-
# Find the rakefile and then load it and any pending imports.
|
2062
|
-
def load_rakefile
|
2063
|
-
standard_exception_handling do
|
2064
|
-
raw_load_rakefile
|
2065
|
-
end
|
2066
|
-
end
|
2067
|
-
|
2068
|
-
# Run the top level tasks of a Rake application.
|
2069
|
-
def top_level
|
2070
|
-
standard_exception_handling do
|
2071
|
-
if options.show_tasks
|
2072
|
-
display_tasks_and_comments
|
2073
|
-
elsif options.show_prereqs
|
2074
|
-
display_prerequisites
|
2075
|
-
else
|
2076
|
-
top_level_tasks.each { |task_name| invoke_task(task_name) }
|
2077
|
-
end
|
2078
|
-
end
|
2079
|
-
end
|
2080
|
-
|
2081
|
-
# Add a loader to handle imported files ending in the extension
|
2082
|
-
# +ext+.
|
2083
|
-
def add_loader(ext, loader)
|
2084
|
-
ext = ".#{ext}" unless ext =~ /^\./
|
2085
|
-
@loaders[ext] = loader
|
2086
|
-
end
|
2087
|
-
|
2088
|
-
# Application options from the command line
|
2089
|
-
def options
|
2090
|
-
@options ||= Options.new
|
2091
|
-
end
|
2092
|
-
|
2093
|
-
# private ----------------------------------------------------------------
|
2094
|
-
|
2095
|
-
def invoke_task(task_string)
|
2096
|
-
name, args = parse_task_string(task_string)
|
2097
|
-
t = self[name]
|
2098
|
-
t.invoke(*args)
|
2099
|
-
end
|
2100
|
-
|
2101
|
-
def parse_task_string(string)
|
2102
|
-
if string =~ /^([^\[]+)(\[(.*)\])$/
|
2103
|
-
name = $1
|
2104
|
-
args = $3.split(/\s*,\s*/)
|
2105
|
-
else
|
2106
|
-
name = string
|
2107
|
-
args = []
|
2108
|
-
end
|
2109
|
-
[name, args]
|
2110
|
-
end
|
2111
|
-
|
2112
|
-
# Provide standard execption handling for the given block.
|
2113
|
-
def standard_exception_handling
|
2114
|
-
begin
|
2115
|
-
yield
|
2116
|
-
rescue SystemExit => ex
|
2117
|
-
# Exit silently with current status
|
2118
|
-
raise
|
2119
|
-
rescue OptionParser::InvalidOption => ex
|
2120
|
-
# Exit silently
|
2121
|
-
exit(false)
|
2122
|
-
rescue Exception => ex
|
2123
|
-
# Exit with error message
|
2124
|
-
$stderr.puts "#{name} aborted!"
|
2125
|
-
$stderr.puts ex.message
|
2126
|
-
if options.trace
|
2127
|
-
$stderr.puts ex.backtrace.join("\n")
|
2128
|
-
else
|
2129
|
-
$stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
|
2130
|
-
$stderr.puts "(See full trace by running task with --trace)"
|
2131
|
-
end
|
2132
|
-
exit(false)
|
2133
|
-
end
|
2134
|
-
end
|
2135
|
-
|
2136
|
-
# True if one of the files in RAKEFILES is in the current directory.
|
2137
|
-
# If a match is found, it is copied into @rakefile.
|
2138
|
-
def have_rakefile
|
2139
|
-
@rakefiles.each do |fn|
|
2140
|
-
if File.exist?(fn)
|
2141
|
-
others = Dir.glob(fn, File::FNM_CASEFOLD)
|
2142
|
-
return others.size == 1 ? others.first : fn
|
2143
|
-
elsif fn == ''
|
2144
|
-
return fn
|
2145
|
-
end
|
2146
|
-
end
|
2147
|
-
return nil
|
2148
|
-
end
|
2149
|
-
|
2150
|
-
# True if we are outputting to TTY, false otherwise
|
2151
|
-
def tty_output?
|
2152
|
-
@tty_output
|
2153
|
-
end
|
2154
|
-
|
2155
|
-
# Override the detected TTY output state (mostly for testing)
|
2156
|
-
def tty_output=( tty_output_state )
|
2157
|
-
@tty_output = tty_output_state
|
2158
|
-
end
|
2159
|
-
|
2160
|
-
# We will truncate output if we are outputting to a TTY or if we've been
|
2161
|
-
# given an explicit column width to honor
|
2162
|
-
def truncate_output?
|
2163
|
-
tty_output? || ENV['RAKE_COLUMNS']
|
2164
|
-
end
|
2165
|
-
|
2166
|
-
# Display the tasks and comments.
|
2167
|
-
def display_tasks_and_comments
|
2168
|
-
displayable_tasks = tasks.select { |t|
|
2169
|
-
t.comment && t.name =~ options.show_task_pattern
|
2170
|
-
}
|
2171
|
-
if options.full_description
|
2172
|
-
displayable_tasks.each do |t|
|
2173
|
-
puts "#{name} #{t.name_with_args}"
|
2174
|
-
t.full_comment.split("\n").each do |line|
|
2175
|
-
puts " #{line}"
|
2176
|
-
end
|
2177
|
-
puts
|
2178
|
-
end
|
2179
|
-
else
|
2180
|
-
width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
|
2181
|
-
max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
|
2182
|
-
displayable_tasks.each do |t|
|
2183
|
-
printf "#{name} %-#{width}s # %s\n",
|
2184
|
-
t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
|
2185
|
-
end
|
2186
|
-
end
|
2187
|
-
end
|
2188
|
-
|
2189
|
-
def terminal_width
|
2190
|
-
if ENV['RAKE_COLUMNS']
|
2191
|
-
result = ENV['RAKE_COLUMNS'].to_i
|
2192
|
-
else
|
2193
|
-
result = unix? ? dynamic_width : 80
|
2194
|
-
end
|
2195
|
-
(result < 10) ? 80 : result
|
2196
|
-
rescue
|
2197
|
-
80
|
2198
|
-
end
|
2199
|
-
|
2200
|
-
# Calculate the dynamic width of the
|
2201
|
-
def dynamic_width
|
2202
|
-
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
|
2203
|
-
end
|
2204
|
-
|
2205
|
-
def dynamic_width_stty
|
2206
|
-
%x{stty size 2>/dev/null}.split[1].to_i
|
2207
|
-
end
|
2208
|
-
|
2209
|
-
def dynamic_width_tput
|
2210
|
-
%x{tput cols 2>/dev/null}.to_i
|
2211
|
-
end
|
2212
|
-
|
2213
|
-
def unix?
|
2214
|
-
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
2215
|
-
end
|
2216
|
-
|
2217
|
-
def windows?
|
2218
|
-
Win32.windows?
|
2219
|
-
end
|
2220
|
-
|
2221
|
-
def truncate(string, width)
|
2222
|
-
if string.length <= width
|
2223
|
-
string
|
2224
|
-
else
|
2225
|
-
( string[0, width-3] || "" ) + "..."
|
2226
|
-
end
|
2227
|
-
end
|
2228
|
-
|
2229
|
-
# Display the tasks and prerequisites
|
2230
|
-
def display_prerequisites
|
2231
|
-
tasks.each do |t|
|
2232
|
-
puts "#{name} #{t.name}"
|
2233
|
-
t.prerequisites.each { |pre| puts " #{pre}" }
|
2234
|
-
end
|
2235
|
-
end
|
2236
|
-
|
2237
|
-
# A list of all the standard options used in rake, suitable for
|
2238
|
-
# passing to OptionParser.
|
2239
|
-
def standard_rake_options
|
2240
|
-
[
|
2241
|
-
['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace",
|
2242
|
-
lambda { |value|
|
2243
|
-
require 'rake/classic_namespace'
|
2244
|
-
options.classic_namespace = true
|
2245
|
-
}
|
2246
|
-
],
|
2247
|
-
['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
|
2248
|
-
lambda { |value|
|
2249
|
-
options.show_tasks = true
|
2250
|
-
options.full_description = true
|
2251
|
-
options.show_task_pattern = Regexp.new(value || '')
|
2252
|
-
}
|
2253
|
-
],
|
2254
|
-
['--dry-run', '-n', "Do a dry run without executing actions.",
|
2255
|
-
lambda { |value|
|
2256
|
-
verbose(true)
|
2257
|
-
nowrite(true)
|
2258
|
-
options.dryrun = true
|
2259
|
-
options.trace = true
|
2260
|
-
}
|
2261
|
-
],
|
2262
|
-
['--execute', '-e CODE', "Execute some Ruby code and exit.",
|
2263
|
-
lambda { |value|
|
2264
|
-
eval(value)
|
2265
|
-
exit
|
2266
|
-
}
|
2267
|
-
],
|
2268
|
-
['--execute-print', '-p CODE', "Execute some Ruby code, print the result, then exit.",
|
2269
|
-
lambda { |value|
|
2270
|
-
puts eval(value)
|
2271
|
-
exit
|
2272
|
-
}
|
2273
|
-
],
|
2274
|
-
['--execute-continue', '-E CODE',
|
2275
|
-
"Execute some Ruby code, then continue with normal task processing.",
|
2276
|
-
lambda { |value| eval(value) }
|
2277
|
-
],
|
2278
|
-
['--threads', '-j N', "Run up to N independent tasks simultaneously in separate threads.",
|
2279
|
-
lambda { |value| options.threads = value.to_i }
|
2280
|
-
],
|
2281
|
-
['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
|
2282
|
-
lambda { |value| $:.push(value) }
|
2283
|
-
],
|
2284
|
-
['--prereqs', '-P', "Display the tasks and dependencies, then exit.",
|
2285
|
-
lambda { |value| options.show_prereqs = true }
|
2286
|
-
],
|
2287
|
-
['--quiet', '-q', "Do not log messages to standard output.",
|
2288
|
-
lambda { |value| verbose(false) }
|
2289
|
-
],
|
2290
|
-
['--rakefile', '-f [FILE]', "Use FILE as the rakefile.",
|
2291
|
-
lambda { |value|
|
2292
|
-
value ||= ''
|
2293
|
-
@rakefiles.clear
|
2294
|
-
@rakefiles << value
|
2295
|
-
}
|
2296
|
-
],
|
2297
|
-
['--rakelibdir', '--rakelib', '-R RAKELIBDIR',
|
2298
|
-
"Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')",
|
2299
|
-
lambda { |value| options.rakelib = value.split(':') }
|
2300
|
-
],
|
2301
|
-
['--randomize[=SEED]', "Randomize the order of sibling prerequisites.",
|
2302
|
-
lambda { |value|
|
2303
|
-
options.randomize = true
|
2304
|
-
MultiTask.class_eval { remove_method(:invoke_prerequisites) }
|
2305
|
-
srand(value.hash) if value
|
2306
|
-
}
|
2307
|
-
],
|
2308
|
-
['--require', '-r MODULE', "Require MODULE before executing rakefile.",
|
2309
|
-
lambda { |value|
|
2310
|
-
begin
|
2311
|
-
require value
|
2312
|
-
rescue LoadError => ex
|
2313
|
-
begin
|
2314
|
-
rake_require value
|
2315
|
-
rescue LoadError => ex2
|
2316
|
-
raise ex
|
2317
|
-
end
|
2318
|
-
end
|
2319
|
-
}
|
2320
|
-
],
|
2321
|
-
['--rules', "Trace the rules resolution.",
|
2322
|
-
lambda { |value| options.trace_rules = true }
|
2323
|
-
],
|
2324
|
-
['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
|
2325
|
-
lambda { |value| options.nosearch = true }
|
2326
|
-
],
|
2327
|
-
['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
|
2328
|
-
lambda { |value|
|
2329
|
-
verbose(false)
|
2330
|
-
options.silent = true
|
2331
|
-
}
|
2332
|
-
],
|
2333
|
-
['--system', '-g',
|
2334
|
-
"Using system wide (global) rakefiles (usually '~/.rake/*.rake').",
|
2335
|
-
lambda { |value| options.load_system = true }
|
2336
|
-
],
|
2337
|
-
['--no-system', '--nosystem', '-G',
|
2338
|
-
"Use standard project Rakefile search paths, ignore system wide rakefiles.",
|
2339
|
-
lambda { |value| options.ignore_system = true }
|
2340
|
-
],
|
2341
|
-
['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
|
2342
|
-
lambda { |value|
|
2343
|
-
options.show_tasks = true
|
2344
|
-
options.show_task_pattern = Regexp.new(value || '')
|
2345
|
-
options.full_description = false
|
2346
|
-
}
|
2347
|
-
],
|
2348
|
-
['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
|
2349
|
-
lambda { |value|
|
2350
|
-
options.trace = true
|
2351
|
-
verbose(true)
|
2352
|
-
}
|
2353
|
-
],
|
2354
|
-
['--verbose', '-v', "Log message to standard output.",
|
2355
|
-
lambda { |value| verbose(true) }
|
2356
|
-
],
|
2357
|
-
['--version', '-V', "Display the program version.",
|
2358
|
-
lambda { |value|
|
2359
|
-
puts "rake, version #{RAKEVERSION}"
|
2360
|
-
exit
|
2361
|
-
}
|
2362
|
-
]
|
2363
|
-
]
|
2364
|
-
end
|
2365
|
-
|
2366
|
-
# Read and handle the command line options.
|
2367
|
-
def handle_options
|
2368
|
-
options.rakelib = ['rakelib']
|
2369
|
-
|
2370
|
-
OptionParser.new do |opts|
|
2371
|
-
opts.banner = "rake [-f rakefile] {options} targets..."
|
2372
|
-
opts.separator ""
|
2373
|
-
opts.separator "Options are ..."
|
2374
|
-
|
2375
|
-
opts.on_tail("-h", "--help", "-H", "Display this help message.") do
|
2376
|
-
puts opts
|
2377
|
-
exit
|
2378
|
-
end
|
2379
|
-
|
2380
|
-
standard_rake_options.each { |args| opts.on(*args) }
|
2381
|
-
end.parse!
|
2382
|
-
|
2383
|
-
# If class namespaces are requested, set the global options
|
2384
|
-
# according to the values in the options structure.
|
2385
|
-
if options.classic_namespace
|
2386
|
-
$show_tasks = options.show_tasks
|
2387
|
-
$show_prereqs = options.show_prereqs
|
2388
|
-
$trace = options.trace
|
2389
|
-
$dryrun = options.dryrun
|
2390
|
-
$silent = options.silent
|
2391
|
-
end
|
2392
|
-
end
|
2393
|
-
|
2394
|
-
# Similar to the regular Ruby +require+ command, but will check
|
2395
|
-
# for *.rake files in addition to *.rb files.
|
2396
|
-
def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
|
2397
|
-
return false if loaded.include?(file_name)
|
2398
|
-
paths.each do |path|
|
2399
|
-
fn = file_name + ".rake"
|
2400
|
-
full_path = File.join(path, fn)
|
2401
|
-
if File.exist?(full_path)
|
2402
|
-
load full_path
|
2403
|
-
loaded << fn
|
2404
|
-
return true
|
2405
|
-
end
|
2406
|
-
end
|
2407
|
-
fail LoadError, "Can't find #{file_name}"
|
2408
|
-
end
|
2409
|
-
|
2410
|
-
def find_rakefile_location
|
2411
|
-
here = Dir.pwd
|
2412
|
-
while ! (fn = have_rakefile)
|
2413
|
-
Dir.chdir("..")
|
2414
|
-
if Dir.pwd == here || options.nosearch
|
2415
|
-
return nil
|
2416
|
-
end
|
2417
|
-
here = Dir.pwd
|
2418
|
-
end
|
2419
|
-
[fn, here]
|
2420
|
-
ensure
|
2421
|
-
Dir.chdir(Rake.original_dir)
|
2422
|
-
end
|
2423
|
-
|
2424
|
-
def raw_load_rakefile # :nodoc:
|
2425
|
-
rakefile, location = find_rakefile_location
|
2426
|
-
if (! options.ignore_system) &&
|
2427
|
-
(options.load_system || rakefile.nil?) &&
|
2428
|
-
system_dir && File.directory?(system_dir)
|
2429
|
-
puts "(in #{Dir.pwd})" unless options.silent
|
2430
|
-
glob("#{system_dir}/*.rake") do |name|
|
2431
|
-
add_import name
|
2432
|
-
end
|
2433
|
-
else
|
2434
|
-
fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
|
2435
|
-
rakefile.nil?
|
2436
|
-
@rakefile = rakefile
|
2437
|
-
Dir.chdir(location)
|
2438
|
-
puts "(in #{Dir.pwd})" unless options.silent
|
2439
|
-
$rakefile = @rakefile if options.classic_namespace
|
2440
|
-
load File.expand_path(@rakefile) if @rakefile && @rakefile != ''
|
2441
|
-
options.rakelib.each do |rlib|
|
2442
|
-
glob("#{rlib}/*.rake") do |name|
|
2443
|
-
add_import name
|
2444
|
-
end
|
2445
|
-
end
|
2446
|
-
end
|
2447
|
-
load_imports
|
2448
|
-
end
|
2449
|
-
|
2450
|
-
def glob(path, &block)
|
2451
|
-
Dir[path.gsub("\\", '/')].each(&block)
|
2452
|
-
end
|
2453
|
-
private :glob
|
2454
|
-
|
2455
|
-
# The directory path containing the system wide rakefiles.
|
2456
|
-
def system_dir
|
2457
|
-
@system_dir ||=
|
2458
|
-
begin
|
2459
|
-
if ENV['RAKE_SYSTEM']
|
2460
|
-
ENV['RAKE_SYSTEM']
|
2461
|
-
else
|
2462
|
-
standard_system_dir
|
2463
|
-
end
|
2464
|
-
end
|
2465
|
-
end
|
2466
|
-
|
2467
|
-
# The standard directory containing system wide rake files.
|
2468
|
-
if Win32.windows?
|
2469
|
-
def standard_system_dir #:nodoc:
|
2470
|
-
Win32.win32_system_dir
|
2471
|
-
end
|
2472
|
-
else
|
2473
|
-
def standard_system_dir #:nodoc:
|
2474
|
-
File.join(File.expand_path('~'), '.rake')
|
2475
|
-
end
|
2476
|
-
end
|
2477
|
-
private :standard_system_dir
|
2478
|
-
|
2479
|
-
# Collect the list of tasks on the command line. If no tasks are
|
2480
|
-
# given, return a list containing only the default task.
|
2481
|
-
# Environmental assignments are processed at this time as well.
|
2482
|
-
def collect_tasks
|
2483
|
-
@top_level_tasks = []
|
2484
|
-
ARGV.each do |arg|
|
2485
|
-
if arg =~ /^(\w+)=(.*)$/
|
2486
|
-
ENV[$1] = $2
|
2487
|
-
else
|
2488
|
-
@top_level_tasks << arg unless arg =~ /^-/
|
2489
|
-
end
|
2490
|
-
end
|
2491
|
-
@top_level_tasks.push("default") if @top_level_tasks.size == 0
|
2492
|
-
end
|
2493
|
-
|
2494
|
-
# Add a file to the list of files to be imported.
|
2495
|
-
def add_import(fn)
|
2496
|
-
@pending_imports << fn
|
2497
|
-
end
|
2498
|
-
|
2499
|
-
# Load the pending list of imported files.
|
2500
|
-
def load_imports
|
2501
|
-
while fn = @pending_imports.shift
|
2502
|
-
next if @imported.member?(fn)
|
2503
|
-
if fn_task = lookup(fn)
|
2504
|
-
fn_task.invoke
|
2505
|
-
end
|
2506
|
-
ext = File.extname(fn)
|
2507
|
-
loader = @loaders[ext] || @default_loader
|
2508
|
-
loader.load(fn)
|
2509
|
-
@imported << fn
|
2510
|
-
end
|
2511
|
-
end
|
2512
|
-
|
2513
|
-
# Warn about deprecated use of top level constant names.
|
2514
|
-
def const_warning(const_name)
|
2515
|
-
@const_warning ||= false
|
2516
|
-
if ! @const_warning
|
2517
|
-
$stderr.puts %{WARNING: Deprecated reference to top-level constant '#{const_name}' } +
|
2518
|
-
%{found at: #{rakefile_location}} # '
|
2519
|
-
$stderr.puts %{ Use --classic-namespace on rake command}
|
2520
|
-
$stderr.puts %{ or 'require "rake/classic_namespace"' in Rakefile}
|
2521
|
-
end
|
2522
|
-
@const_warning = true
|
2523
|
-
end
|
2524
|
-
|
2525
|
-
def rakefile_location
|
2526
|
-
begin
|
2527
|
-
fail
|
2528
|
-
rescue RuntimeError => ex
|
2529
|
-
ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
|
2530
|
-
end
|
2531
|
-
end
|
2532
|
-
end
|
2533
|
-
end
|
2534
|
-
|
2535
|
-
|
2536
|
-
class Module
|
2537
|
-
# Rename the original handler to make it available.
|
2538
|
-
alias :rake_original_const_missing :const_missing
|
2539
|
-
|
2540
|
-
# Check for deprecated uses of top level (i.e. in Object) uses of
|
2541
|
-
# Rake class names. If someone tries to reference the constant
|
2542
|
-
# name, display a warning and return the proper object. Using the
|
2543
|
-
# --classic-namespace command line option will define these
|
2544
|
-
# constants in Object and avoid this handler.
|
2545
|
-
def const_missing(const_name)
|
2546
|
-
case const_name
|
2547
|
-
when :Task
|
2548
|
-
Rake.application.const_warning(const_name)
|
2549
|
-
Rake::Task
|
2550
|
-
when :FileTask
|
2551
|
-
Rake.application.const_warning(const_name)
|
2552
|
-
Rake::FileTask
|
2553
|
-
when :FileCreationTask
|
2554
|
-
Rake.application.const_warning(const_name)
|
2555
|
-
Rake::FileCreationTask
|
2556
|
-
when :RakeApp
|
2557
|
-
Rake.application.const_warning(const_name)
|
2558
|
-
Rake::Application
|
2559
|
-
else
|
2560
|
-
rake_original_const_missing(const_name)
|
2561
|
-
end
|
2562
|
-
end
|
2563
|
-
end
|
67
|
+
RakeFileUtils = Rake::FileUtilsExt
|