rake 0.9.3.beta.1 → 0.9.3.beta.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rake might be problematic. Click here for more details.
- data/CHANGES +2 -0
- data/README.rdoc +9 -8
- data/TODO +1 -0
- data/doc/command_line_usage.rdoc +9 -0
- data/doc/release_notes/rake-0.9.3.rdoc +55 -0
- data/install.rb +1 -1
- data/lib/rake/application.rb +177 -139
- data/lib/rake/clean.rb +1 -1
- data/lib/rake/cloneable.rb +7 -16
- data/lib/rake/contrib/ftptools.rb +2 -1
- data/lib/rake/contrib/sys.rb +6 -6
- data/lib/rake/dsl_definition.rb +2 -2
- data/lib/rake/file_list.rb +2 -2
- data/lib/rake/file_utils_ext.rb +4 -3
- data/lib/rake/multi_task.rb +6 -4
- data/lib/rake/phony.rb +13 -0
- data/lib/rake/rake_module.rb +7 -0
- data/lib/rake/rdoctask.rb +1 -1
- data/lib/rake/runtest.rb +1 -1
- data/lib/rake/task.rb +8 -0
- data/lib/rake/task_arguments.rb +1 -1
- data/lib/rake/testtask.rb +5 -1
- data/lib/rake/thread_pool.rb +133 -0
- data/lib/rake/version.rb +8 -4
- data/test/helper.rb +29 -0
- data/test/test_rake_application.rb +12 -0
- data/test/test_rake_application_options.rb +39 -3
- data/test/test_rake_directory_task.rb +0 -5
- data/test/test_rake_file_task.rb +21 -1
- data/test/test_rake_functional.rb +22 -0
- data/test/test_rake_multi_task.rb +8 -0
- data/test/test_rake_task.rb +18 -1
- data/test/test_rake_thread_pool.rb +146 -0
- metadata +18 -8
data/lib/rake/clean.rb
CHANGED
@@ -16,7 +16,7 @@ require 'rake'
|
|
16
16
|
# :stopdoc:
|
17
17
|
CLEAN = Rake::FileList["**/*~", "**/*.bak", "**/core"]
|
18
18
|
CLEAN.clear_exclude.exclude { |fn|
|
19
|
-
fn.pathmap("%f") == 'core' && File.directory?(fn)
|
19
|
+
fn.pathmap("%f").downcase == 'core' && File.directory?(fn)
|
20
20
|
}
|
21
21
|
|
22
22
|
desc "Remove any temporary products."
|
data/lib/rake/cloneable.rb
CHANGED
@@ -3,23 +3,14 @@ module Rake
|
|
3
3
|
# Mixin for creating easily cloned objects.
|
4
4
|
#
|
5
5
|
module Cloneable
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
value =
|
12
|
-
|
13
|
-
sibling.instance_variable_set(ivar, new_value)
|
6
|
+
# The hook that invoked by 'clone' and 'dup' methods.
|
7
|
+
def initialize_copy(source)
|
8
|
+
super
|
9
|
+
source.instance_variables.each do |var|
|
10
|
+
src_value = source.instance_variable_get(var)
|
11
|
+
value = src_value.clone rescue src_value
|
12
|
+
instance_variable_set(var, value)
|
14
13
|
end
|
15
|
-
sibling.taint if tainted?
|
16
|
-
sibling
|
17
|
-
end
|
18
|
-
|
19
|
-
def clone
|
20
|
-
sibling = dup
|
21
|
-
sibling.freeze if frozen?
|
22
|
-
sibling
|
23
14
|
end
|
24
15
|
end
|
25
16
|
end
|
data/lib/rake/contrib/sys.rb
CHANGED
@@ -27,7 +27,7 @@ module Sys
|
|
27
27
|
# Install all the files matching +wildcard+ into the +dest_dir+
|
28
28
|
# directory. The permission mode is set to +mode+.
|
29
29
|
def install(wildcard, dest_dir, mode)
|
30
|
-
|
30
|
+
Rake.glob(wildcard).each do |fn|
|
31
31
|
File.install(fn, dest_dir, mode, $verbose)
|
32
32
|
end
|
33
33
|
end
|
@@ -81,7 +81,7 @@ module Sys
|
|
81
81
|
# recursively delete directories.
|
82
82
|
def delete(*wildcards)
|
83
83
|
wildcards.each do |wildcard|
|
84
|
-
|
84
|
+
Rake.glob(wildcard).each do |fn|
|
85
85
|
if File.directory?(fn)
|
86
86
|
log "Deleting directory #{fn}"
|
87
87
|
Dir.delete(fn)
|
@@ -96,10 +96,10 @@ module Sys
|
|
96
96
|
# Recursively delete all files and directories matching +wildcard+.
|
97
97
|
def delete_all(*wildcards)
|
98
98
|
wildcards.each do |wildcard|
|
99
|
-
|
99
|
+
Rake.glob(wildcard).each do |fn|
|
100
100
|
next if ! File.exist?(fn)
|
101
101
|
if File.directory?(fn)
|
102
|
-
|
102
|
+
Rake.glob("#{fn}/*").each do |subfn|
|
103
103
|
next if subfn=='.' || subfn=='..'
|
104
104
|
delete_all(subfn)
|
105
105
|
end
|
@@ -161,7 +161,7 @@ module Sys
|
|
161
161
|
# Perform a block with each file matching a set of wildcards.
|
162
162
|
def for_files(*wildcards)
|
163
163
|
wildcards.each do |wildcard|
|
164
|
-
|
164
|
+
Rake.glob(wildcard).each do |fn|
|
165
165
|
yield(fn)
|
166
166
|
end
|
167
167
|
end
|
@@ -172,7 +172,7 @@ module Sys
|
|
172
172
|
private # ----------------------------------------------------------
|
173
173
|
|
174
174
|
def for_matching_files(wildcard, dest_dir)
|
175
|
-
|
175
|
+
Rake.glob(wildcard).each do |fn|
|
176
176
|
dest_file = File.join(dest_dir, fn)
|
177
177
|
parent = File.dirname(dest_file)
|
178
178
|
makedirs(parent) if ! File.directory?(parent)
|
data/lib/rake/dsl_definition.rb
CHANGED
@@ -78,8 +78,8 @@ module Rake
|
|
78
78
|
# Example:
|
79
79
|
# multitask :deploy => [:deploy_gem, :deploy_rdoc]
|
80
80
|
#
|
81
|
-
def multitask(args, &block)
|
82
|
-
Rake::MultiTask.define_task(args, &block)
|
81
|
+
def multitask(*args, &block)
|
82
|
+
Rake::MultiTask.define_task(*args, &block)
|
83
83
|
end
|
84
84
|
|
85
85
|
# Create a new rake namespace and use it for evaluating the given
|
data/lib/rake/file_list.rb
CHANGED
@@ -286,7 +286,7 @@ module Rake
|
|
286
286
|
matched = 0
|
287
287
|
each do |fn|
|
288
288
|
begin
|
289
|
-
open(fn, "
|
289
|
+
open(fn, "r", *options) do |inf|
|
290
290
|
count = 0
|
291
291
|
inf.each do |line|
|
292
292
|
count += 1
|
@@ -340,7 +340,7 @@ module Rake
|
|
340
340
|
|
341
341
|
# Add matching glob patterns.
|
342
342
|
def add_matching(pattern)
|
343
|
-
|
343
|
+
Rake.glob(pattern).each do |fn|
|
344
344
|
self << fn unless exclude?(fn)
|
345
345
|
end
|
346
346
|
end
|
data/lib/rake/file_utils_ext.rb
CHANGED
@@ -21,12 +21,13 @@ module Rake
|
|
21
21
|
$fileutils_verbose = true
|
22
22
|
$fileutils_nowrite = false
|
23
23
|
|
24
|
-
FileUtils
|
24
|
+
FileUtils.commands.each do |name|
|
25
|
+
opts = FileUtils.options_of name
|
25
26
|
default_options = []
|
26
|
-
if opts.include?(
|
27
|
+
if opts.include?("verbose")
|
27
28
|
default_options << ':verbose => FileUtilsExt.verbose_flag'
|
28
29
|
end
|
29
|
-
if opts.include?(
|
30
|
+
if opts.include?("noop")
|
30
31
|
default_options << ':noop => FileUtilsExt.nowrite_flag'
|
31
32
|
end
|
32
33
|
|
data/lib/rake/multi_task.rb
CHANGED
@@ -6,10 +6,12 @@ module Rake
|
|
6
6
|
class MultiTask < Task
|
7
7
|
private
|
8
8
|
def invoke_prerequisites(args, invocation_chain)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
futures = @prerequisites.collect do |p|
|
10
|
+
application.thread_pool.future(p) do |r|
|
11
|
+
application[r, @scope].invoke_with_call_chain(args, invocation_chain)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
futures.each { |f| f.call }
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
data/lib/rake/phony.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Defines a :phony task that you can use as a dependency. This allows
|
2
|
+
# file-based tasks to use non-file-based tasks as prerequisites
|
3
|
+
# without forcing them to rebuild.
|
4
|
+
#
|
5
|
+
# See FileTask#out_of_date? and Task#timestamp for more info.
|
6
|
+
|
7
|
+
require 'rake'
|
8
|
+
|
9
|
+
task :phony
|
10
|
+
|
11
|
+
def (Rake::Task[:phony]).timestamp
|
12
|
+
Time.at 0
|
13
|
+
end
|
data/lib/rake/rake_module.rb
CHANGED
@@ -24,6 +24,13 @@ module Rake
|
|
24
24
|
def load_rakefile(path)
|
25
25
|
load(path)
|
26
26
|
end
|
27
|
+
|
28
|
+
# Get a sorted list of files matching the pattern. This method
|
29
|
+
# should be prefered to Dir[pattern] and Dir.glob[pattern] because
|
30
|
+
# the files returned are guaranteed to be sorted.
|
31
|
+
def glob(pattern, *args)
|
32
|
+
Dir.glob(pattern, *args).sort
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
end
|
data/lib/rake/rdoctask.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# rake/rdoctask is deprecated in favor of rdoc/task
|
2
2
|
|
3
3
|
if Rake.application
|
4
|
-
Rake.application.deprecate('require \'rake/rdoctask\'', 'require \'rdoc/task\' (in RDoc 2.4.2+)',
|
4
|
+
Rake.application.deprecate('require \'rake/rdoctask\'', 'require \'rdoc/task\' (in RDoc 2.4.2+)', caller.first)
|
5
5
|
end
|
6
6
|
|
7
7
|
require 'rubygems'
|
data/lib/rake/runtest.rb
CHANGED
data/lib/rake/task.rb
CHANGED
@@ -123,6 +123,7 @@ module Rake
|
|
123
123
|
def clear
|
124
124
|
clear_prerequisites
|
125
125
|
clear_actions
|
126
|
+
clear_comments
|
126
127
|
self
|
127
128
|
end
|
128
129
|
|
@@ -138,6 +139,13 @@ module Rake
|
|
138
139
|
self
|
139
140
|
end
|
140
141
|
|
142
|
+
# Clear the existing comments on a rake task.
|
143
|
+
def clear_comments
|
144
|
+
@full_comment = nil
|
145
|
+
@comment = nil
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
141
149
|
# Invoke the task if it is needed. Prerequisites are invoked first.
|
142
150
|
def invoke(*args)
|
143
151
|
task_args = TaskArguments.new(arg_names, args)
|
data/lib/rake/task_arguments.rb
CHANGED
data/lib/rake/testtask.rb
CHANGED
@@ -96,7 +96,11 @@ module Rake
|
|
96
96
|
desc "Run tests" + (@name==:test ? "" : " for #{@name}")
|
97
97
|
task @name do
|
98
98
|
FileUtilsExt.verbose(@verbose) do
|
99
|
-
ruby "#{ruby_opts_string} #{run_code} #{file_list_string} #{option_list}"
|
99
|
+
ruby "#{ruby_opts_string} #{run_code} #{file_list_string} #{option_list}" do |ok, status|
|
100
|
+
if !ok && status.respond_to?(:signaled?) && status.signaled?
|
101
|
+
raise SignalException.new(status.termsig)
|
102
|
+
end
|
103
|
+
end
|
100
104
|
end
|
101
105
|
end
|
102
106
|
self
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Rake
|
5
|
+
|
6
|
+
class ThreadPool
|
7
|
+
|
8
|
+
# Creates a ThreadPool object.
|
9
|
+
# The parameter is the size of the pool. By default, the pool uses unlimited threads.
|
10
|
+
def initialize(thread_count=nil)
|
11
|
+
@max_thread_count = [(thread_count||FIXNUM_MAX), 0].max
|
12
|
+
@threads = Set.new
|
13
|
+
@threads_mon = Monitor.new
|
14
|
+
@queue = Queue.new
|
15
|
+
@join_cond = @threads_mon.new_cond
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a future to be executed in the ThreadPool.
|
19
|
+
# The args are passed to the block when executing (similarly to Thread#new)
|
20
|
+
# The return value is a Proc which may or may not be already executing in
|
21
|
+
# another thread. Calling Proc#call will sleep the current thread until
|
22
|
+
# the future is finished and will return the result (or raise an Exception
|
23
|
+
# thrown from the future)
|
24
|
+
def future(*args,&block)
|
25
|
+
# capture the local args for the block (like Thread#start)
|
26
|
+
local_args = args.collect { |a| begin; a.dup; rescue; a; end }
|
27
|
+
|
28
|
+
promise_mutex = Mutex.new
|
29
|
+
promise_result = promise_error = NOT_SET
|
30
|
+
|
31
|
+
# (promise code builds on Ben Lavender's public-domain 'promise' gem)
|
32
|
+
promise = lambda do
|
33
|
+
# return immediately if the future has been executed
|
34
|
+
unless promise_result.equal?(NOT_SET) && promise_error.equal?(NOT_SET)
|
35
|
+
return promise_error.equal?(NOT_SET) ? promise_result : raise(promise_error)
|
36
|
+
end
|
37
|
+
|
38
|
+
# try to get the lock and execute the promise, otherwise, sleep.
|
39
|
+
if promise_mutex.try_lock
|
40
|
+
if promise_result.equal?(NOT_SET) && promise_error.equal?(NOT_SET)
|
41
|
+
#execute the promise
|
42
|
+
begin
|
43
|
+
promise_result = block.call(*local_args)
|
44
|
+
rescue Exception => e
|
45
|
+
promise_error = e
|
46
|
+
end
|
47
|
+
block = local_args = nil # GC can now clean these up
|
48
|
+
end
|
49
|
+
promise_mutex.unlock
|
50
|
+
else
|
51
|
+
# Even if we didn't get the lock, we need to sleep until the promise has
|
52
|
+
# finished executing. If, however, the current thread is part of the thread
|
53
|
+
# pool, we need to free up a new thread in the pool so there will
|
54
|
+
# always be a thread doing work.
|
55
|
+
|
56
|
+
wait_for_promise = lambda { promise_mutex.synchronize{} }
|
57
|
+
|
58
|
+
unless @threads_mon.synchronize { @threads.include? Thread.current }
|
59
|
+
wait_for_promise.call
|
60
|
+
else
|
61
|
+
@threads_mon.synchronize { @max_thread_count += 1 }
|
62
|
+
start_thread
|
63
|
+
wait_for_promise.call
|
64
|
+
@threads_mon.synchronize { @max_thread_count -= 1 }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
promise_error.equal?(NOT_SET) ? promise_result : raise(promise_error)
|
68
|
+
end
|
69
|
+
|
70
|
+
@queue.enq promise
|
71
|
+
start_thread
|
72
|
+
promise
|
73
|
+
end
|
74
|
+
|
75
|
+
# Waits until the queue of futures is empty and all threads have exited.
|
76
|
+
def join
|
77
|
+
@threads_mon.synchronize do
|
78
|
+
begin
|
79
|
+
@join_cond.wait unless @threads.empty?
|
80
|
+
rescue Exception => e
|
81
|
+
STDERR.puts e
|
82
|
+
STDERR.print "Queue contains #{@queue.size} items. Thread pool contains #{@threads.count} threads\n"
|
83
|
+
STDERR.print "Current Thread #{Thread.current} status = #{Thread.current.status}\n"
|
84
|
+
STDERR.puts e.backtrace.join("\n")
|
85
|
+
@threads.each do |t|
|
86
|
+
STDERR.print "Thread #{t} status = #{t.status}\n"
|
87
|
+
STDERR.puts t.backtrace.join("\n") if t.respond_to? :backtrace
|
88
|
+
end
|
89
|
+
raise e
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
def start_thread
|
96
|
+
@threads_mon.synchronize do
|
97
|
+
next unless @threads.count < @max_thread_count
|
98
|
+
|
99
|
+
@threads << Thread.new do
|
100
|
+
begin
|
101
|
+
while @threads.count <= @max_thread_count && !@queue.empty? do
|
102
|
+
# Even though we just asked if the queue was empty,
|
103
|
+
# it still could have had an item which by this statement is now gone.
|
104
|
+
# For this reason we pass true to Queue#deq because we will sleep
|
105
|
+
# indefinitely if it is empty.
|
106
|
+
@queue.deq(true).call
|
107
|
+
end
|
108
|
+
rescue ThreadError # this means the queue is empty
|
109
|
+
ensure
|
110
|
+
@threads_mon.synchronize do
|
111
|
+
@threads.delete Thread.current
|
112
|
+
@join_cond.broadcast if @threads.empty?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# for testing only
|
120
|
+
|
121
|
+
def __queue__
|
122
|
+
@queue
|
123
|
+
end
|
124
|
+
|
125
|
+
def __threads__
|
126
|
+
@threads.dup
|
127
|
+
end
|
128
|
+
|
129
|
+
NOT_SET = Object.new.freeze
|
130
|
+
FIXNUM_MAX = (2**(0.size * 8 - 2) - 1) # FIXNUM_MAX
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
data/lib/rake/version.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
module Rake
|
2
|
-
VERSION = '0.9.3.beta.1'
|
3
|
-
|
4
2
|
module Version # :nodoc: all
|
5
|
-
|
6
|
-
|
3
|
+
NUMBERS = [
|
4
|
+
MAJOR = 0,
|
5
|
+
MINOR = 9,
|
6
|
+
BUILD = 3,
|
7
|
+
'beta',
|
8
|
+
BETA = 2,
|
9
|
+
]
|
7
10
|
end
|
11
|
+
VERSION = Version::NUMBERS.join('.')
|
8
12
|
end
|
data/test/helper.rb
CHANGED
@@ -488,5 +488,34 @@ end
|
|
488
488
|
VERBOSE
|
489
489
|
end
|
490
490
|
|
491
|
+
def rakefile_test_signal
|
492
|
+
rakefile <<-TEST_SIGNAL
|
493
|
+
require 'rake/testtask'
|
494
|
+
|
495
|
+
Rake::TestTask.new(:a) do |t|
|
496
|
+
t.test_files = ['a_test.rb']
|
497
|
+
end
|
498
|
+
|
499
|
+
Rake::TestTask.new(:b) do |t|
|
500
|
+
t.test_files = ['b_test.rb']
|
501
|
+
end
|
502
|
+
|
503
|
+
task :test do
|
504
|
+
Rake::Task[:a].invoke rescue nil
|
505
|
+
Rake::Task[:b].invoke rescue nil
|
491
506
|
end
|
492
507
|
|
508
|
+
task :default => :test
|
509
|
+
TEST_SIGNAL
|
510
|
+
open 'a_test.rb', 'w' do |io|
|
511
|
+
io << 'puts "ATEST"' << "\n"
|
512
|
+
io << '$stdout.flush' << "\n"
|
513
|
+
io << 'Process.kill("TERM", $$)' << "\n"
|
514
|
+
end
|
515
|
+
open 'b_test.rb', 'w' do |io|
|
516
|
+
io << 'puts "BTEST"' << "\n"
|
517
|
+
io << '$stdout.flush' << "\n"
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
end
|