rake 0.9.2 → 13.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.rdoc +43 -0
  3. data/Gemfile +10 -0
  4. data/History.rdoc +2386 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.rdoc +64 -109
  7. data/Rakefile +22 -386
  8. data/bin/bundle +105 -0
  9. data/bin/console +7 -0
  10. data/bin/rake +20 -23
  11. data/bin/rdoc +29 -0
  12. data/bin/rubocop +29 -0
  13. data/bin/setup +6 -0
  14. data/doc/command_line_usage.rdoc +65 -21
  15. data/doc/glossary.rdoc +40 -49
  16. data/doc/jamis.rb +1 -0
  17. data/doc/rake.1 +156 -0
  18. data/doc/rakefile.rdoc +127 -62
  19. data/exe/rake +27 -0
  20. data/lib/rake.rb +37 -31
  21. data/lib/rake/application.rb +507 -272
  22. data/lib/rake/backtrace.rb +24 -0
  23. data/lib/rake/clean.rb +55 -8
  24. data/lib/rake/cloneable.rb +11 -19
  25. data/lib/rake/cpu_counter.rb +107 -0
  26. data/lib/rake/default_loader.rb +5 -0
  27. data/lib/rake/dsl_definition.rb +74 -46
  28. data/lib/rake/early_time.rb +5 -1
  29. data/lib/rake/ext/core.rb +5 -6
  30. data/lib/rake/ext/string.rb +61 -52
  31. data/lib/rake/file_creation_task.rb +4 -3
  32. data/lib/rake/file_list.rb +81 -49
  33. data/lib/rake/file_task.rb +15 -8
  34. data/lib/rake/file_utils.rb +69 -47
  35. data/lib/rake/file_utils_ext.rb +18 -26
  36. data/lib/rake/invocation_chain.rb +25 -19
  37. data/lib/rake/invocation_exception_mixin.rb +1 -0
  38. data/lib/rake/late_time.rb +18 -0
  39. data/lib/rake/linked_list.rb +112 -0
  40. data/lib/rake/loaders/makefile.rb +23 -9
  41. data/lib/rake/multi_task.rb +4 -6
  42. data/lib/rake/name_space.rb +36 -23
  43. data/lib/rake/packagetask.rb +71 -34
  44. data/lib/rake/phony.rb +16 -0
  45. data/lib/rake/private_reader.rb +21 -0
  46. data/lib/rake/promise.rb +100 -0
  47. data/lib/rake/pseudo_status.rb +8 -2
  48. data/lib/rake/rake_module.rb +41 -3
  49. data/lib/rake/rake_test_loader.rb +21 -7
  50. data/lib/rake/rule_recursion_overflow_error.rb +2 -2
  51. data/lib/rake/scope.rb +43 -0
  52. data/lib/rake/task.rb +186 -79
  53. data/lib/rake/task_argument_error.rb +1 -0
  54. data/lib/rake/task_arguments.rb +50 -15
  55. data/lib/rake/task_manager.rb +89 -65
  56. data/lib/rake/tasklib.rb +2 -12
  57. data/lib/rake/testtask.rb +61 -63
  58. data/lib/rake/thread_history_display.rb +49 -0
  59. data/lib/rake/thread_pool.rb +163 -0
  60. data/lib/rake/trace_output.rb +23 -0
  61. data/lib/rake/version.rb +7 -7
  62. data/lib/rake/win32.rb +14 -18
  63. data/rake.gemspec +43 -0
  64. metadata +82 -221
  65. data/.gemtest +0 -0
  66. data/CHANGES +0 -509
  67. data/RRR +0 -9
  68. data/TODO +0 -20
  69. data/doc/rake.1.gz +0 -0
  70. data/doc/release_notes/rake-0.4.14.rdoc +0 -23
  71. data/doc/release_notes/rake-0.4.15.rdoc +0 -35
  72. data/doc/release_notes/rake-0.5.0.rdoc +0 -53
  73. data/doc/release_notes/rake-0.5.3.rdoc +0 -78
  74. data/doc/release_notes/rake-0.5.4.rdoc +0 -46
  75. data/doc/release_notes/rake-0.6.0.rdoc +0 -141
  76. data/doc/release_notes/rake-0.7.0.rdoc +0 -119
  77. data/doc/release_notes/rake-0.7.1.rdoc +0 -59
  78. data/doc/release_notes/rake-0.7.2.rdoc +0 -121
  79. data/doc/release_notes/rake-0.7.3.rdoc +0 -47
  80. data/doc/release_notes/rake-0.8.0.rdoc +0 -114
  81. data/doc/release_notes/rake-0.8.2.rdoc +0 -165
  82. data/doc/release_notes/rake-0.8.3.rdoc +0 -112
  83. data/doc/release_notes/rake-0.8.4.rdoc +0 -147
  84. data/doc/release_notes/rake-0.8.5.rdoc +0 -53
  85. data/doc/release_notes/rake-0.8.6.rdoc +0 -55
  86. data/doc/release_notes/rake-0.8.7.rdoc +0 -55
  87. data/doc/release_notes/rake-0.9.0.rdoc +0 -112
  88. data/doc/release_notes/rake-0.9.1.rdoc +0 -52
  89. data/doc/release_notes/rake-0.9.2.rdoc +0 -49
  90. data/install.rb +0 -90
  91. data/lib/rake/alt_system.rb +0 -109
  92. data/lib/rake/classic_namespace.rb +0 -9
  93. data/lib/rake/contrib/compositepublisher.rb +0 -21
  94. data/lib/rake/contrib/ftptools.rb +0 -150
  95. data/lib/rake/contrib/publisher.rb +0 -69
  96. data/lib/rake/contrib/rubyforgepublisher.rb +0 -16
  97. data/lib/rake/contrib/sshpublisher.rb +0 -45
  98. data/lib/rake/contrib/sys.rb +0 -191
  99. data/lib/rake/ext/module.rb +0 -39
  100. data/lib/rake/ext/time.rb +0 -14
  101. data/lib/rake/gempackagetask.rb +0 -13
  102. data/lib/rake/pathmap.rb +0 -1
  103. data/lib/rake/rdoctask.rb +0 -230
  104. data/lib/rake/ruby182_test_unit_fix.rb +0 -25
  105. data/lib/rake/runtest.rb +0 -21
  106. data/test/check_expansion.rb +0 -5
  107. data/test/check_no_expansion.rb +0 -5
  108. data/test/data/access/Rakefile +0 -35
  109. data/test/data/chains/Rakefile +0 -15
  110. data/test/data/comments/Rakefile +0 -18
  111. data/test/data/default/Rakefile +0 -17
  112. data/test/data/deprecated_import/Rakefile +0 -1
  113. data/test/data/dryrun/Rakefile +0 -22
  114. data/test/data/extra/Rakefile +0 -1
  115. data/test/data/file_creation_task/Rakefile +0 -31
  116. data/test/data/imports/Rakefile +0 -19
  117. data/test/data/imports/deps.mf +0 -1
  118. data/test/data/multidesc/Rakefile +0 -15
  119. data/test/data/namespace/Rakefile +0 -64
  120. data/test/data/rakelib/test1.rb +0 -4
  121. data/test/data/rbext/rakefile.rb +0 -3
  122. data/test/data/sample.mf +0 -14
  123. data/test/data/statusreturn/Rakefile +0 -6
  124. data/test/data/unittest/Rakefile +0 -1
  125. data/test/data/verbose/Rakefile +0 -34
  126. data/test/file_creation.rb +0 -34
  127. data/test/helper.rb +0 -44
  128. data/test/in_environment.rb +0 -35
  129. data/test/reqfile.rb +0 -3
  130. data/test/reqfile2.rb +0 -3
  131. data/test/shellcommand.rb +0 -3
  132. data/test/test_rake.rb +0 -38
  133. data/test/test_rake_application.rb +0 -364
  134. data/test/test_rake_application_options.rb +0 -382
  135. data/test/test_rake_clean.rb +0 -12
  136. data/test/test_rake_definitions.rb +0 -80
  137. data/test/test_rake_directory_task.rb +0 -55
  138. data/test/test_rake_dsl.rb +0 -73
  139. data/test/test_rake_early_time.rb +0 -31
  140. data/test/test_rake_extension.rb +0 -59
  141. data/test/test_rake_file_creation_task.rb +0 -62
  142. data/test/test_rake_file_list.rb +0 -633
  143. data/test/test_rake_file_list_path_map.rb +0 -8
  144. data/test/test_rake_file_task.rb +0 -104
  145. data/test/test_rake_file_utils.rb +0 -252
  146. data/test/test_rake_ftp_file.rb +0 -59
  147. data/test/test_rake_functional.rb +0 -468
  148. data/test/test_rake_invocation_chain.rb +0 -52
  149. data/test/test_rake_makefile_loader.rb +0 -23
  150. data/test/test_rake_multi_task.rb +0 -51
  151. data/test/test_rake_name_space.rb +0 -43
  152. data/test/test_rake_package_task.rb +0 -78
  153. data/test/test_rake_path_map.rb +0 -157
  154. data/test/test_rake_path_map_explode.rb +0 -31
  155. data/test/test_rake_path_map_partial.rb +0 -18
  156. data/test/test_rake_pseudo_status.rb +0 -20
  157. data/test/test_rake_rdoc_task.rb +0 -81
  158. data/test/test_rake_require.rb +0 -35
  159. data/test/test_rake_rules.rb +0 -346
  160. data/test/test_rake_task.rb +0 -271
  161. data/test/test_rake_task_argument_parsing.rb +0 -116
  162. data/test/test_rake_task_arguments.rb +0 -86
  163. data/test/test_rake_task_lib.rb +0 -9
  164. data/test/test_rake_task_manager.rb +0 -145
  165. data/test/test_rake_task_manager_argument_resolution.rb +0 -36
  166. data/test/test_rake_task_with_arguments.rb +0 -162
  167. data/test/test_rake_test_task.rb +0 -122
  168. data/test/test_rake_top_level_functions.rb +0 -76
  169. data/test/test_rake_win32.rb +0 -83
  170. data/test/test_sys.rb +0 -20
@@ -1,21 +1,27 @@
1
+ # frozen_string_literal: true
1
2
  module Rake
2
3
 
3
- ####################################################################
4
+ ##
4
5
  # Exit status class for times the system just gives us a nil.
5
- class PseudoStatus
6
+ class PseudoStatus # :nodoc: all
6
7
  attr_reader :exitstatus
8
+
7
9
  def initialize(code=0)
8
10
  @exitstatus = code
9
11
  end
12
+
10
13
  def to_i
11
14
  @exitstatus << 8
12
15
  end
16
+
13
17
  def >>(n)
14
18
  to_i >> n
15
19
  end
20
+
16
21
  def stopped?
17
22
  false
18
23
  end
24
+
19
25
  def exited?
20
26
  true
21
27
  end
@@ -1,9 +1,8 @@
1
- require 'rake/application'
1
+ # frozen_string_literal: true
2
+ require "rake/application"
2
3
 
3
4
  module Rake
4
5
 
5
- # Rake module singleton methods.
6
- #
7
6
  class << self
8
7
  # Current Rake Application
9
8
  def application
@@ -15,6 +14,11 @@ module Rake
15
14
  @application = app
16
15
  end
17
16
 
17
+ def suggested_thread_count # :nodoc:
18
+ @cpu_count ||= Rake::CpuCounter.count
19
+ @cpu_count + 4
20
+ end
21
+
18
22
  # Return the original directory where the Rake application was started.
19
23
  def original_dir
20
24
  application.original_dir
@@ -24,6 +28,40 @@ module Rake
24
28
  def load_rakefile(path)
25
29
  load(path)
26
30
  end
31
+
32
+ # Add files to the rakelib list
33
+ def add_rakelib(*files)
34
+ application.options.rakelib ||= []
35
+ application.options.rakelib.concat(files)
36
+ end
37
+
38
+ # Make +block_application+ the default rake application inside a block so
39
+ # you can load rakefiles into a different application.
40
+ #
41
+ # This is useful when you want to run rake tasks inside a library without
42
+ # running rake in a sub-shell.
43
+ #
44
+ # Example:
45
+ #
46
+ # Dir.chdir 'other/directory'
47
+ #
48
+ # other_rake = Rake.with_application do |rake|
49
+ # rake.load_rakefile
50
+ # end
51
+ #
52
+ # puts other_rake.tasks
53
+
54
+ def with_application(block_application = Rake::Application.new)
55
+ orig_application = Rake.application
56
+
57
+ Rake.application = block_application
58
+
59
+ yield block_application
60
+
61
+ block_application
62
+ ensure
63
+ Rake.application = orig_application
64
+ end
27
65
  end
28
66
 
29
67
  end
@@ -1,13 +1,27 @@
1
- require 'rake'
1
+ # frozen_string_literal: true
2
+ require "rake"
2
3
 
3
4
  # Load the test files from the command line.
5
+ argv = ARGV.select do |argument|
6
+ begin
7
+ case argument
8
+ when /^-/ then
9
+ argument
10
+ when /\*/ then
11
+ FileList[argument].to_a.each do |file|
12
+ require File.expand_path file
13
+ end
4
14
 
5
- ARGV.each do |f|
6
- next if f =~ /^-/
15
+ false
16
+ else
17
+ require File.expand_path argument
7
18
 
8
- if f =~ /\*/
9
- FileList[f].to_a.each { |fn| require File.expand_path(fn) }
10
- else
11
- require File.expand_path(f)
19
+ false
20
+ end
21
+ rescue LoadError => e
22
+ raise unless e.path
23
+ abort "\nFile does not exist: #{e.path}\n\n"
12
24
  end
13
25
  end
26
+
27
+ ARGV.replace argv
@@ -1,4 +1,4 @@
1
-
1
+ # frozen_string_literal: true
2
2
  module Rake
3
3
 
4
4
  # Error indicating a recursion overflow error in task selection.
@@ -13,7 +13,7 @@ module Rake
13
13
  end
14
14
 
15
15
  def message
16
- super + ": [" + @targets.reverse.join(' => ') + "]"
16
+ super + ": [" + @targets.reverse.join(" => ") + "]"
17
17
  end
18
18
  end
19
19
 
data/lib/rake/scope.rb ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ module Rake
3
+ class Scope < LinkedList # :nodoc: all
4
+
5
+ # Path for the scope.
6
+ def path
7
+ map(&:to_s).reverse.join(":")
8
+ end
9
+
10
+ # Path for the scope + the named path.
11
+ def path_with_task_name(task_name)
12
+ "#{path}:#{task_name}"
13
+ end
14
+
15
+ # Trim +n+ innermost scope levels from the scope. In no case will
16
+ # this trim beyond the toplevel scope.
17
+ def trim(n)
18
+ result = self
19
+ while n > 0 && !result.empty?
20
+ result = result.tail
21
+ n -= 1
22
+ end
23
+ result
24
+ end
25
+
26
+ # Scope lists always end with an EmptyScope object. See Null
27
+ # Object Pattern)
28
+ class EmptyScope < EmptyLinkedList
29
+ @parent = Scope
30
+
31
+ def path
32
+ ""
33
+ end
34
+
35
+ def path_with_task_name(task_name)
36
+ task_name
37
+ end
38
+ end
39
+
40
+ # Singleton null object for an empty scope.
41
+ EMPTY = EmptyScope.new
42
+ end
43
+ end
data/lib/rake/task.rb CHANGED
@@ -1,8 +1,9 @@
1
- require 'rake/invocation_exception_mixin'
1
+ # frozen_string_literal: true
2
+ require "rake/invocation_exception_mixin"
2
3
 
3
4
  module Rake
4
5
 
5
- # #########################################################################
6
+ ##
6
7
  # A Task is the basic unit of work in a Rakefile. Tasks have associated
7
8
  # actions (possibly more than one) and a list of prerequisites. When
8
9
  # invoked, a task will first ensure that all of its prerequisites have an
@@ -14,6 +15,10 @@ module Rake
14
15
  class Task
15
16
  # List of prerequisites for a task.
16
17
  attr_reader :prerequisites
18
+ alias prereqs prerequisites
19
+
20
+ # List of order only prerequisites for a task.
21
+ attr_reader :order_only_prerequisites
17
22
 
18
23
  # List of actions attached to a task.
19
24
  attr_reader :actions
@@ -21,13 +26,6 @@ module Rake
21
26
  # Application owning this task.
22
27
  attr_accessor :application
23
28
 
24
- # Comment for this task. Restricted to a single line of no more than 50
25
- # characters.
26
- attr_reader :comment
27
-
28
- # Full text of the (possibly multi-line) comment.
29
- attr_reader :full_comment
30
-
31
29
  # Array of nested namespaces names used for task lookup by this task.
32
30
  attr_reader :scope
33
31
 
@@ -36,50 +34,81 @@ module Rake
36
34
  # location option set).
37
35
  attr_reader :locations
38
36
 
37
+ # Has this task already been invoked? Already invoked tasks
38
+ # will be skipped unless you reenable them.
39
+ attr_reader :already_invoked
40
+
39
41
  # Return task name
40
42
  def to_s
41
43
  name
42
44
  end
43
45
 
44
- def inspect
46
+ def inspect # :nodoc:
45
47
  "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
46
48
  end
47
49
 
48
50
  # List of sources for task.
49
51
  attr_writer :sources
50
52
  def sources
51
- @sources ||= []
53
+ if defined?(@sources)
54
+ @sources
55
+ else
56
+ prerequisites
57
+ end
52
58
  end
53
59
 
54
60
  # List of prerequisite tasks
55
61
  def prerequisite_tasks
56
- prerequisites.collect { |pre| lookup_prerequisite(pre) }
62
+ (prerequisites + order_only_prerequisites).map { |pre| lookup_prerequisite(pre) }
57
63
  end
58
64
 
59
- def lookup_prerequisite(prerequisite_name)
60
- application[prerequisite_name, @scope]
65
+ def lookup_prerequisite(prerequisite_name) # :nodoc:
66
+ scoped_prerequisite_task = application[prerequisite_name, @scope]
67
+ if scoped_prerequisite_task == self
68
+ unscoped_prerequisite_task = application[prerequisite_name]
69
+ end
70
+ unscoped_prerequisite_task || scoped_prerequisite_task
61
71
  end
62
72
  private :lookup_prerequisite
63
73
 
74
+ # List of all unique prerequisite tasks including prerequisite tasks'
75
+ # prerequisites.
76
+ # Includes self when cyclic dependencies are found.
77
+ def all_prerequisite_tasks
78
+ seen = {}
79
+ collect_prerequisites(seen)
80
+ seen.values
81
+ end
82
+
83
+ def collect_prerequisites(seen) # :nodoc:
84
+ prerequisite_tasks.each do |pre|
85
+ next if seen[pre.name]
86
+ seen[pre.name] = pre
87
+ pre.collect_prerequisites(seen)
88
+ end
89
+ end
90
+ protected :collect_prerequisites
91
+
64
92
  # First source from a rule (nil if no sources)
65
93
  def source
66
- @sources.first if defined?(@sources)
94
+ sources.first
67
95
  end
68
96
 
69
97
  # Create a task named +task_name+ with no actions or prerequisites. Use
70
98
  # +enhance+ to add actions and prerequisites.
71
99
  def initialize(task_name, app)
72
- @name = task_name.to_s
73
- @prerequisites = []
74
- @actions = []
100
+ @name = task_name.to_s
101
+ @prerequisites = []
102
+ @actions = []
75
103
  @already_invoked = false
76
- @full_comment = nil
77
- @comment = nil
78
- @lock = Monitor.new
79
- @application = app
80
- @scope = app.current_scope
81
- @arg_names = nil
82
- @locations = []
104
+ @comments = []
105
+ @lock = Monitor.new
106
+ @application = app
107
+ @scope = app.current_scope
108
+ @arg_names = nil
109
+ @locations = []
110
+ @invocation_exception = nil
111
+ @order_only_prerequisites = []
83
112
  end
84
113
 
85
114
  # Enhance a task with prerequisites or actions. Returns self.
@@ -105,7 +134,7 @@ module Rake
105
134
 
106
135
  # Argument description (nil if none).
107
136
  def arg_description # :nodoc:
108
- @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
137
+ @arg_names ? "[#{arg_names.join(',')}]" : nil
109
138
  end
110
139
 
111
140
  # Name of arguments for this task.
@@ -117,12 +146,15 @@ module Rake
117
146
  # is invoked again.
118
147
  def reenable
119
148
  @already_invoked = false
149
+ @invocation_exception = nil
120
150
  end
121
151
 
122
- # Clear the existing prerequisites and actions of a rake task.
152
+ # Clear the existing prerequisites, actions, comments, and arguments of a rake task.
123
153
  def clear
124
154
  clear_prerequisites
125
155
  clear_actions
156
+ clear_comments
157
+ clear_args
126
158
  self
127
159
  end
128
160
 
@@ -138,6 +170,18 @@ module Rake
138
170
  self
139
171
  end
140
172
 
173
+ # Clear the existing comments on a rake task.
174
+ def clear_comments
175
+ @comments = []
176
+ self
177
+ end
178
+
179
+ # Clear the existing arguments on a rake task.
180
+ def clear_args
181
+ @arg_names = nil
182
+ self
183
+ end
184
+
141
185
  # Invoke the task if it is needed. Prerequisites are invoked first.
142
186
  def invoke(*args)
143
187
  task_args = TaskArguments.new(arg_names, args)
@@ -146,35 +190,71 @@ module Rake
146
190
 
147
191
  # Same as invoke, but explicitly pass a call chain to detect
148
192
  # circular dependencies.
149
- def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
150
- new_chain = InvocationChain.append(self, invocation_chain)
193
+ #
194
+ # If multiple tasks depend on this
195
+ # one in parallel, they will all fail if the first execution of
196
+ # this task fails.
197
+ def invoke_with_call_chain(task_args, invocation_chain)
198
+ new_chain = Rake::InvocationChain.append(self, invocation_chain)
151
199
  @lock.synchronize do
152
- if application.options.trace
153
- $stderr.puts "** Invoke #{name} #{format_trace_flags}"
200
+ begin
201
+ if application.options.trace
202
+ application.trace "** Invoke #{name} #{format_trace_flags}"
203
+ end
204
+
205
+ if @already_invoked
206
+ if @invocation_exception
207
+ if application.options.trace
208
+ application.trace "** Previous invocation of #{name} failed #{format_trace_flags}"
209
+ end
210
+ raise @invocation_exception
211
+ else
212
+ return
213
+ end
214
+ end
215
+
216
+ @already_invoked = true
217
+
218
+ invoke_prerequisites(task_args, new_chain)
219
+ execute(task_args) if needed?
220
+ rescue Exception => ex
221
+ add_chain_to(ex, new_chain)
222
+ @invocation_exception = ex
223
+ raise ex
154
224
  end
155
- return if @already_invoked
156
- @already_invoked = true
157
- invoke_prerequisites(task_args, new_chain)
158
- execute(task_args) if needed?
159
225
  end
160
- rescue Exception => ex
161
- add_chain_to(ex, new_chain)
162
- raise ex
163
226
  end
164
227
  protected :invoke_with_call_chain
165
228
 
166
- def add_chain_to(exception, new_chain)
167
- exception.extend(InvocationExceptionMixin) unless exception.respond_to?(:chain)
229
+ def add_chain_to(exception, new_chain) # :nodoc:
230
+ exception.extend(InvocationExceptionMixin) unless
231
+ exception.respond_to?(:chain)
168
232
  exception.chain = new_chain if exception.chain.nil?
169
233
  end
170
234
  private :add_chain_to
171
235
 
172
236
  # Invoke all the prerequisites of a task.
173
237
  def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
174
- prerequisite_tasks.each { |prereq|
175
- prereq_args = task_args.new_scope(prereq.arg_names)
176
- prereq.invoke_with_call_chain(prereq_args, invocation_chain)
177
- }
238
+ if application.options.always_multitask
239
+ invoke_prerequisites_concurrently(task_args, invocation_chain)
240
+ else
241
+ prerequisite_tasks.each { |p|
242
+ prereq_args = task_args.new_scope(p.arg_names)
243
+ p.invoke_with_call_chain(prereq_args, invocation_chain)
244
+ }
245
+ end
246
+ end
247
+
248
+ # Invoke all the prerequisites of a task in parallel.
249
+ def invoke_prerequisites_concurrently(task_args, invocation_chain)# :nodoc:
250
+ futures = prerequisite_tasks.map do |p|
251
+ prereq_args = task_args.new_scope(p.arg_names)
252
+ application.thread_pool.future(p) do |r|
253
+ r.invoke_with_call_chain(prereq_args, invocation_chain)
254
+ end
255
+ end
256
+ # Iterate in reverse to improve performance related to thread waiting and switching
257
+ futures.reverse_each(&:value)
178
258
  end
179
259
 
180
260
  # Format the trace flags for display.
@@ -190,20 +270,15 @@ module Rake
190
270
  def execute(args=nil)
191
271
  args ||= EMPTY_TASK_ARGS
192
272
  if application.options.dryrun
193
- $stderr.puts "** Execute (dry run) #{name}"
273
+ application.trace "** Execute (dry run) #{name}"
194
274
  return
195
275
  end
196
- if application.options.trace
197
- $stderr.puts "** Execute #{name}"
198
- end
276
+ application.trace "** Execute #{name}" if application.options.trace
199
277
  application.enhance_with_matching_rule(name) if @actions.empty?
200
- @actions.each do |act|
201
- case act.arity
202
- when 1
203
- act.call(self)
204
- else
205
- act.call(self, args)
206
- end
278
+ if opts = Hash.try_convert(args) and !opts.empty?
279
+ @actions.each { |act| act.call(self, args, **opts)}
280
+ else
281
+ @actions.each { |act| act.call(self, args)}
207
282
  end
208
283
  end
209
284
 
@@ -215,65 +290,97 @@ module Rake
215
290
  # Timestamp for this task. Basic tasks return the current time for their
216
291
  # time stamp. Other tasks can be more sophisticated.
217
292
  def timestamp
218
- prerequisite_tasks.collect { |pre| pre.timestamp }.max || Time.now
293
+ Time.now
219
294
  end
220
295
 
221
296
  # Add a description to the task. The description can consist of an option
222
297
  # argument list (enclosed brackets) and an optional comment.
223
298
  def add_description(description)
224
- return if ! description
299
+ return unless description
225
300
  comment = description.strip
226
- add_comment(comment) if comment && ! comment.empty?
301
+ add_comment(comment) if comment && !comment.empty?
227
302
  end
228
303
 
229
- # Writing to the comment attribute is the same as adding a description.
230
- def comment=(description)
231
- add_description(description)
304
+ def comment=(comment) # :nodoc:
305
+ add_comment(comment)
232
306
  end
233
307
 
234
- # Add a comment to the task. If a comment already exists, separate
235
- # the new comment with " / ".
236
- def add_comment(comment)
237
- if @full_comment
238
- @full_comment << " / "
239
- else
240
- @full_comment = ''
241
- end
242
- @full_comment << comment
243
- if @full_comment =~ /\A([^.]+?\.)( |$)/
244
- @comment = $1
308
+ def add_comment(comment) # :nodoc:
309
+ return if comment.nil?
310
+ @comments << comment unless @comments.include?(comment)
311
+ end
312
+ private :add_comment
313
+
314
+ # Full collection of comments. Multiple comments are separated by
315
+ # newlines.
316
+ def full_comment
317
+ transform_comments("\n")
318
+ end
319
+
320
+ # First line (or sentence) of all comments. Multiple comments are
321
+ # separated by a "/".
322
+ def comment
323
+ transform_comments(" / ") { |c| first_sentence(c) }
324
+ end
325
+
326
+ # Transform the list of comments as specified by the block and
327
+ # join with the separator.
328
+ def transform_comments(separator, &block)
329
+ if @comments.empty?
330
+ nil
245
331
  else
246
- @comment = @full_comment
332
+ block ||= lambda { |c| c }
333
+ @comments.map(&block).join(separator)
247
334
  end
248
335
  end
249
- private :add_comment
336
+ private :transform_comments
337
+
338
+ # Get the first sentence in a string. The sentence is terminated
339
+ # by the first period, exclamation mark, or the end of the line.
340
+ # Decimal points do not count as periods.
341
+ def first_sentence(string)
342
+ string.split(/(?<=\w)(\.|!)[ \t]|(\.$|!)|\n/).first
343
+ end
344
+ private :first_sentence
250
345
 
251
346
  # Set the names of the arguments for this task. +args+ should be
252
347
  # an array of symbols, one for each argument name.
253
348
  def set_arg_names(args)
254
- @arg_names = args.map { |a| a.to_sym }
349
+ @arg_names = args.map(&:to_sym)
255
350
  end
256
351
 
257
352
  # Return a string describing the internal state of a task. Useful for
258
353
  # debugging.
259
354
  def investigation
260
- result = "------------------------------\n"
355
+ result = "------------------------------\n".dup
261
356
  result << "Investigating #{name}\n"
262
357
  result << "class: #{self.class}\n"
263
358
  result << "task needed: #{needed?}\n"
264
359
  result << "timestamp: #{timestamp}\n"
265
360
  result << "pre-requisites: \n"
266
361
  prereqs = prerequisite_tasks
267
- prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
362
+ prereqs.sort! { |a, b| a.timestamp <=> b.timestamp }
268
363
  prereqs.each do |p|
269
364
  result << "--#{p.name} (#{p.timestamp})\n"
270
365
  end
271
- latest_prereq = prerequisite_tasks.collect { |pre| pre.timestamp }.max
366
+ latest_prereq = prerequisite_tasks.map(&:timestamp).max
272
367
  result << "latest-prerequisite time: #{latest_prereq}\n"
273
368
  result << "................................\n\n"
274
369
  return result
275
370
  end
276
371
 
372
+ # Format dependencies parameter to pass to task.
373
+ def self.format_deps(deps)
374
+ deps = [deps] unless deps.respond_to?(:to_ary)
375
+ deps.map { |d| Rake.from_pathname(d).to_s }
376
+ end
377
+
378
+ # Add order only dependencies.
379
+ def |(deps)
380
+ @order_only_prerequisites |= Task.format_deps(deps) - @prerequisites
381
+ self
382
+ end
383
+
277
384
  # ----------------------------------------------------------------
278
385
  # Rake Module Methods
279
386
  #
@@ -319,7 +426,7 @@ module Rake
319
426
  # this kind of task. Generic tasks will accept the scope as
320
427
  # part of the name.
321
428
  def scope_name(scope, task_name)
322
- (scope + [task_name]).join(':')
429
+ scope.path_with_task_name(task_name)
323
430
  end
324
431
 
325
432
  end # class << Rake::Task