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.

@@ -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."
@@ -3,23 +3,14 @@ module Rake
3
3
  # Mixin for creating easily cloned objects.
4
4
  #
5
5
  module Cloneable
6
- # Clone an object by making a new object and setting all the instance
7
- # variables to the same values.
8
- def dup
9
- sibling = self.class.new
10
- instance_variables.each do |ivar|
11
- value = self.instance_variable_get(ivar)
12
- new_value = value.clone rescue value
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
@@ -127,7 +127,8 @@ module Rake # :nodoc:
127
127
  # Upload all files matching +wildcard+ to the uploader's root
128
128
  # path.
129
129
  def upload_files(wildcard)
130
- Dir[wildcard].each do |fn|
130
+ fail "OUCH"
131
+ Rake.glob(wildcard).each do |fn|
131
132
  upload(fn)
132
133
  end
133
134
  end
@@ -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
- Dir[wildcard].each do |fn|
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
- Dir[wildcard].each do |fn|
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
- Dir[wildcard].each do |fn|
99
+ Rake.glob(wildcard).each do |fn|
100
100
  next if ! File.exist?(fn)
101
101
  if File.directory?(fn)
102
- Dir["#{fn}/*"].each do |subfn|
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
- Dir[wildcard].each do |fn|
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
- Dir[wildcard].each do |fn|
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)
@@ -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
@@ -286,7 +286,7 @@ module Rake
286
286
  matched = 0
287
287
  each do |fn|
288
288
  begin
289
- open(fn, "rb", *options) do |inf|
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
- Dir[pattern].each do |fn|
343
+ Rake.glob(pattern).each do |fn|
344
344
  self << fn unless exclude?(fn)
345
345
  end
346
346
  end
@@ -21,12 +21,13 @@ module Rake
21
21
  $fileutils_verbose = true
22
22
  $fileutils_nowrite = false
23
23
 
24
- FileUtils::OPT_TABLE.each do |name, opts|
24
+ FileUtils.commands.each do |name|
25
+ opts = FileUtils.options_of name
25
26
  default_options = []
26
- if opts.include?(:verbose) || opts.include?("verbose")
27
+ if opts.include?("verbose")
27
28
  default_options << ':verbose => FileUtilsExt.verbose_flag'
28
29
  end
29
- if opts.include?(:noop) || opts.include?("noop")
30
+ if opts.include?("noop")
30
31
  default_options << ':noop => FileUtilsExt.nowrite_flag'
31
32
  end
32
33
 
@@ -6,10 +6,12 @@ module Rake
6
6
  class MultiTask < Task
7
7
  private
8
8
  def invoke_prerequisites(args, invocation_chain)
9
- threads = @prerequisites.collect { |p|
10
- Thread.new(p) { |r| application[r, @scope].invoke_with_call_chain(args, invocation_chain) }
11
- }
12
- threads.each { |t| t.join }
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
 
@@ -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
@@ -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
@@ -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+)', __FILE__)
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'
@@ -5,7 +5,7 @@ module Rake
5
5
  include Test::Unit::Assertions
6
6
 
7
7
  def run_tests(pattern='test/test*.rb', log_enabled=false)
8
- Dir["#{pattern}"].each { |fn|
8
+ Rake.glob(pattern).each { |fn|
9
9
  $stderr.puts fn if log_enabled
10
10
  begin
11
11
  require fn
@@ -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)
@@ -47,7 +47,7 @@ module Rake
47
47
  keys.map { |k| lookup(k) }
48
48
  end
49
49
 
50
- def method_missing(sym, *args, &block)
50
+ def method_missing(sym, *args)
51
51
  lookup(sym.to_sym)
52
52
  end
53
53
 
@@ -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
@@ -1,8 +1,12 @@
1
1
  module Rake
2
- VERSION = '0.9.3.beta.1'
3
-
4
2
  module Version # :nodoc: all
5
- MAJOR, MINOR, BUILD = VERSION.split '.'
6
- NUMBERS = [ MAJOR, MINOR, BUILD ]
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
@@ -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