rake 11.3.0 → 13.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/macos.yml +22 -0
  3. data/.github/workflows/ubuntu-rvm.yml +28 -0
  4. data/.github/workflows/ubuntu.yml +20 -0
  5. data/.github/workflows/windows.yml +20 -0
  6. data/CONTRIBUTING.rdoc +11 -4
  7. data/Gemfile +8 -1
  8. data/History.rdoc +171 -37
  9. data/README.rdoc +9 -11
  10. data/Rakefile +21 -13
  11. data/bin/bundle +105 -0
  12. data/bin/rake +29 -0
  13. data/bin/rdoc +29 -0
  14. data/bin/rubocop +29 -0
  15. data/doc/jamis.rb +1 -0
  16. data/doc/rake.1 +139 -124
  17. data/doc/rakefile.rdoc +2 -4
  18. data/exe/rake +1 -1
  19. data/lib/rake/application.rb +119 -79
  20. data/lib/rake/backtrace.rb +3 -2
  21. data/lib/rake/clean.rb +7 -5
  22. data/lib/rake/cloneable.rb +1 -0
  23. data/lib/rake/cpu_counter.rb +3 -2
  24. data/lib/rake/default_loader.rb +1 -0
  25. data/lib/rake/dsl_definition.rb +5 -4
  26. data/lib/rake/early_time.rb +1 -0
  27. data/lib/rake/ext/core.rb +1 -0
  28. data/lib/rake/ext/string.rb +22 -21
  29. data/lib/rake/file_creation_task.rb +4 -3
  30. data/lib/rake/file_list.rb +13 -14
  31. data/lib/rake/file_task.rb +12 -4
  32. data/lib/rake/file_utils.rb +17 -22
  33. data/lib/rake/file_utils_ext.rb +8 -18
  34. data/lib/rake/invocation_chain.rb +1 -0
  35. data/lib/rake/invocation_exception_mixin.rb +1 -0
  36. data/lib/rake/late_time.rb +2 -1
  37. data/lib/rake/linked_list.rb +1 -0
  38. data/lib/rake/loaders/makefile.rb +5 -4
  39. data/lib/rake/multi_task.rb +2 -1
  40. data/lib/rake/name_space.rb +1 -1
  41. data/lib/rake/packagetask.rb +28 -16
  42. data/lib/rake/phony.rb +2 -1
  43. data/lib/rake/private_reader.rb +1 -0
  44. data/lib/rake/promise.rb +13 -12
  45. data/lib/rake/pseudo_status.rb +1 -0
  46. data/lib/rake/rake_module.rb +30 -1
  47. data/lib/rake/rake_test_loader.rb +18 -12
  48. data/lib/rake/rule_recursion_overflow_error.rb +2 -1
  49. data/lib/rake/scope.rb +3 -2
  50. data/lib/rake/task.rb +70 -27
  51. data/lib/rake/task_argument_error.rb +1 -0
  52. data/lib/rake/task_arguments.rb +10 -4
  53. data/lib/rake/task_manager.rb +54 -39
  54. data/lib/rake/tasklib.rb +2 -1
  55. data/lib/rake/testtask.rb +28 -16
  56. data/lib/rake/thread_history_display.rb +4 -3
  57. data/lib/rake/thread_pool.rb +15 -14
  58. data/lib/rake/trace_output.rb +1 -0
  59. data/lib/rake/version.rb +3 -2
  60. data/lib/rake/win32.rb +9 -8
  61. data/lib/rake.rb +34 -33
  62. data/rake.gemspec +22 -9
  63. metadata +25 -108
  64. data/.gitignore +0 -14
  65. data/.rubocop.yml +0 -18
  66. data/.travis.yml +0 -28
  67. data/appveyor.yml +0 -22
  68. data/doc/release_notes/README.md +0 -4
  69. data/doc/release_notes/rake-0.4.14.rdoc +0 -23
  70. data/doc/release_notes/rake-0.4.15.rdoc +0 -35
  71. data/doc/release_notes/rake-0.5.0.rdoc +0 -53
  72. data/doc/release_notes/rake-0.5.3.rdoc +0 -78
  73. data/doc/release_notes/rake-0.5.4.rdoc +0 -46
  74. data/doc/release_notes/rake-0.6.0.rdoc +0 -141
  75. data/doc/release_notes/rake-0.7.0.rdoc +0 -119
  76. data/doc/release_notes/rake-0.7.1.rdoc +0 -59
  77. data/doc/release_notes/rake-0.7.2.rdoc +0 -121
  78. data/doc/release_notes/rake-0.7.3.rdoc +0 -47
  79. data/doc/release_notes/rake-0.8.0.rdoc +0 -114
  80. data/doc/release_notes/rake-0.8.2.rdoc +0 -165
  81. data/doc/release_notes/rake-0.8.3.rdoc +0 -112
  82. data/doc/release_notes/rake-0.8.4.rdoc +0 -147
  83. data/doc/release_notes/rake-0.8.5.rdoc +0 -53
  84. data/doc/release_notes/rake-0.8.6.rdoc +0 -37
  85. data/doc/release_notes/rake-0.8.7.rdoc +0 -55
  86. data/doc/release_notes/rake-0.9.0.rdoc +0 -112
  87. data/doc/release_notes/rake-0.9.1.rdoc +0 -52
  88. data/doc/release_notes/rake-0.9.2.2.rdoc +0 -55
  89. data/doc/release_notes/rake-0.9.2.rdoc +0 -49
  90. data/doc/release_notes/rake-0.9.3.rdoc +0 -102
  91. data/doc/release_notes/rake-0.9.4.rdoc +0 -60
  92. data/doc/release_notes/rake-0.9.5.rdoc +0 -55
  93. data/doc/release_notes/rake-0.9.6.rdoc +0 -64
  94. data/doc/release_notes/rake-10.0.0.rdoc +0 -178
  95. data/doc/release_notes/rake-10.0.1.rdoc +0 -58
  96. data/doc/release_notes/rake-10.0.2.rdoc +0 -53
  97. data/doc/release_notes/rake-10.0.3.rdoc +0 -191
  98. data/doc/release_notes/rake-10.1.0.rdoc +0 -61
  99. data/lib/rake/contrib/compositepublisher.rb +0 -21
  100. data/lib/rake/contrib/ftptools.rb +0 -137
  101. data/lib/rake/contrib/sshpublisher.rb +0 -60
  102. data/lib/rake/ext/pathname.rb +0 -25
data/lib/rake/task.rb CHANGED
@@ -1,4 +1,5 @@
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
 
@@ -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
@@ -54,7 +59,7 @@ module Rake
54
59
 
55
60
  # List of prerequisite tasks
56
61
  def prerequisite_tasks
57
- prerequisites.map { |pre| lookup_prerequisite(pre) }
62
+ (prerequisites + order_only_prerequisites).map { |pre| lookup_prerequisite(pre) }
58
63
  end
59
64
 
60
65
  def lookup_prerequisite(prerequisite_name) # :nodoc:
@@ -102,6 +107,8 @@ module Rake
102
107
  @scope = app.current_scope
103
108
  @arg_names = nil
104
109
  @locations = []
110
+ @invocation_exception = nil
111
+ @order_only_prerequisites = []
105
112
  end
106
113
 
107
114
  # Enhance a task with prerequisites or actions. Returns self.
@@ -139,13 +146,15 @@ module Rake
139
146
  # is invoked again.
140
147
  def reenable
141
148
  @already_invoked = false
149
+ @invocation_exception = nil
142
150
  end
143
151
 
144
- # Clear the existing prerequisites and actions of a rake task.
152
+ # Clear the existing prerequisites, actions, comments, and arguments of a rake task.
145
153
  def clear
146
154
  clear_prerequisites
147
155
  clear_actions
148
156
  clear_comments
157
+ clear_args
149
158
  self
150
159
  end
151
160
 
@@ -167,6 +176,12 @@ module Rake
167
176
  self
168
177
  end
169
178
 
179
+ # Clear the existing arguments on a rake task.
180
+ def clear_args
181
+ @arg_names = nil
182
+ self
183
+ end
184
+
170
185
  # Invoke the task if it is needed. Prerequisites are invoked first.
171
186
  def invoke(*args)
172
187
  task_args = TaskArguments.new(arg_names, args)
@@ -175,20 +190,39 @@ module Rake
175
190
 
176
191
  # Same as invoke, but explicitly pass a call chain to detect
177
192
  # circular dependencies.
178
- def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
179
- 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)
180
199
  @lock.synchronize do
181
- if application.options.trace
182
- application.trace "** 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
183
224
  end
184
- return if @already_invoked
185
- @already_invoked = true
186
- invoke_prerequisites(task_args, new_chain)
187
- execute(task_args) if needed?
188
225
  end
189
- rescue Exception => ex
190
- add_chain_to(ex, new_chain)
191
- raise ex
192
226
  end
193
227
  protected :invoke_with_call_chain
194
228
 
@@ -219,7 +253,8 @@ module Rake
219
253
  r.invoke_with_call_chain(prereq_args, invocation_chain)
220
254
  end
221
255
  end
222
- futures.each { |f| f.value }
256
+ # Iterate in reverse to improve performance related to thread waiting and switching
257
+ futures.reverse_each(&:value)
223
258
  end
224
259
 
225
260
  # Format the trace flags for display.
@@ -240,13 +275,10 @@ module Rake
240
275
  end
241
276
  application.trace "** Execute #{name}" if application.options.trace
242
277
  application.enhance_with_matching_rule(name) if @actions.empty?
243
- @actions.each do |act|
244
- case act.arity
245
- when 1
246
- act.call(self)
247
- else
248
- act.call(self, args)
249
- 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)}
250
282
  end
251
283
  end
252
284
 
@@ -266,7 +298,7 @@ module Rake
266
298
  def add_description(description)
267
299
  return unless description
268
300
  comment = description.strip
269
- add_comment(comment) if comment && ! comment.empty?
301
+ add_comment(comment) if comment && !comment.empty?
270
302
  end
271
303
 
272
304
  def comment=(comment) # :nodoc:
@@ -314,13 +346,13 @@ module Rake
314
346
  # Set the names of the arguments for this task. +args+ should be
315
347
  # an array of symbols, one for each argument name.
316
348
  def set_arg_names(args)
317
- @arg_names = args.map { |a| a.to_sym }
349
+ @arg_names = args.map(&:to_sym)
318
350
  end
319
351
 
320
352
  # Return a string describing the internal state of a task. Useful for
321
353
  # debugging.
322
354
  def investigation
323
- result = "------------------------------\n"
355
+ result = "------------------------------\n".dup
324
356
  result << "Investigating #{name}\n"
325
357
  result << "class: #{self.class}\n"
326
358
  result << "task needed: #{needed?}\n"
@@ -331,12 +363,24 @@ module Rake
331
363
  prereqs.each do |p|
332
364
  result << "--#{p.name} (#{p.timestamp})\n"
333
365
  end
334
- latest_prereq = prerequisite_tasks.map { |pre| pre.timestamp }.max
366
+ latest_prereq = prerequisite_tasks.map(&:timestamp).max
335
367
  result << "latest-prerequisite time: #{latest_prereq}\n"
336
368
  result << "................................\n\n"
337
369
  return result
338
370
  end
339
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
+
340
384
  # ----------------------------------------------------------------
341
385
  # Rake Module Methods
342
386
  #
@@ -382,7 +426,6 @@ module Rake
382
426
  # this kind of task. Generic tasks will accept the scope as
383
427
  # part of the name.
384
428
  def scope_name(scope, task_name)
385
- # (scope + [task_name]).join(':')
386
429
  scope.path_with_task_name(task_name)
387
430
  end
388
431
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Rake
2
3
 
3
4
  # Error indicating an ill-formed task declaration.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Rake
2
3
 
3
4
  ##
@@ -17,7 +18,7 @@ module Rake
17
18
  @hash = {}
18
19
  @values = values
19
20
  names.each_with_index { |name, i|
20
- next if values[i].nil? || values[i] == ''
21
+ next if values[i].nil? || values[i] == ""
21
22
  @hash[name.to_sym] = values[i]
22
23
  }
23
24
  end
@@ -68,21 +69,26 @@ module Rake
68
69
 
69
70
  # Returns a Hash of arguments and their values
70
71
  def to_hash
71
- @hash
72
+ @hash.dup
72
73
  end
73
74
 
74
75
  def to_s # :nodoc:
75
- @hash.inspect
76
+ inspect
76
77
  end
77
78
 
78
79
  def inspect # :nodoc:
79
- to_s
80
+ inspection = @hash.map do |k,v|
81
+ "#{k.to_s}: #{v.to_s}"
82
+ end.join(", ")
83
+
84
+ "#<#{self.class} #{inspection}>"
80
85
  end
81
86
 
82
87
  # Returns true if +key+ is one of the arguments
83
88
  def has_key?(key)
84
89
  @hash.has_key?(key)
85
90
  end
91
+ alias key? has_key?
86
92
 
87
93
  def fetch(*args, &block)
88
94
  @hash.fetch(*args, &block)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Rake
2
3
 
3
4
  # The TaskManager module is a mixin for managing tasks.
@@ -5,19 +6,6 @@ module Rake
5
6
  # Track the last comment made in the Rakefile.
6
7
  attr_accessor :last_description
7
8
 
8
- # Remove Rake 12
9
- def last_comment # :nodoc:
10
- warn "[DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead."
11
- @last_description
12
- end
13
-
14
- # Remove Rake 12
15
- def last_comment=(comment) # :nodoc:
16
- warn "[DEPRECATION] `last_comment=` is deprecated. Please use `last_description=` instead."
17
- @last_description = comment
18
- @last_description # ignore warning
19
- end
20
-
21
9
  def initialize # :nodoc:
22
10
  super
23
11
  @tasks = Hash.new
@@ -27,31 +15,31 @@ module Rake
27
15
  end
28
16
 
29
17
  def create_rule(*args, &block) # :nodoc:
30
- pattern, args, deps = resolve_args(args)
31
- pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
32
- @rules << [pattern, args, deps, block]
18
+ pattern, args, deps, order_only = resolve_args(args)
19
+ pattern = Regexp.new(Regexp.quote(pattern) + "$") if String === pattern
20
+ @rules << [pattern, args, deps, order_only, block]
33
21
  end
34
22
 
35
23
  def define_task(task_class, *args, &block) # :nodoc:
36
- task_name, arg_names, deps = resolve_args(args)
24
+ task_name, arg_names, deps, order_only = resolve_args(args)
37
25
 
38
26
  original_scope = @scope
39
27
  if String === task_name and
40
- not task_class.ancestors.include? Rake::FileTask then
28
+ not task_class.ancestors.include? Rake::FileTask
41
29
  task_name, *definition_scope = *(task_name.split(":").reverse)
42
30
  @scope = Scope.make(*(definition_scope + @scope.to_a))
43
31
  end
44
32
 
45
33
  task_name = task_class.scope_name(@scope, task_name)
46
- deps = [deps] unless deps.respond_to?(:to_ary)
47
- deps = deps.map { |d| Rake.from_pathname(d).to_s }
48
34
  task = intern(task_class, task_name)
49
35
  task.set_arg_names(arg_names) unless arg_names.empty?
50
36
  if Rake::TaskManager.record_task_metadata
51
37
  add_location(task)
52
38
  task.add_description(get_description(task))
53
39
  end
54
- task.enhance(deps, &block)
40
+ task.enhance(Task.format_deps(deps), &block)
41
+ task | order_only unless order_only.nil?
42
+ task
55
43
  ensure
56
44
  @scope = original_scope
57
45
  end
@@ -68,7 +56,26 @@ module Rake
68
56
  self.lookup(task_name, scopes) or
69
57
  enhance_with_matching_rule(task_name) or
70
58
  synthesize_file_task(task_name) or
71
- fail "Don't know how to build task '#{task_name}' (see --tasks)"
59
+ fail generate_message_for_undefined_task(task_name)
60
+ end
61
+
62
+ def generate_message_for_undefined_task(task_name)
63
+ message = "Don't know how to build task '#{task_name}' "\
64
+ "(See the list of available tasks with `#{Rake.application.name} --tasks`)"
65
+ message + generate_did_you_mean_suggestions(task_name)
66
+ end
67
+
68
+ def generate_did_you_mean_suggestions(task_name)
69
+ return "" unless defined?(::DidYouMean::SpellChecker)
70
+
71
+ suggestions = ::DidYouMean::SpellChecker.new(dictionary: @tasks.keys).correct(task_name.to_s)
72
+ if ::DidYouMean.respond_to?(:formatter)# did_you_mean v1.2.0 or later
73
+ ::DidYouMean.formatter.message_for(suggestions)
74
+ elsif defined?(::DidYouMean::Formatter) # before did_you_mean v1.2.0
75
+ ::DidYouMean::Formatter.new(suggestions).to_s
76
+ else
77
+ ""
78
+ end
72
79
  end
73
80
 
74
81
  def synthesize_file_task(task_name) # :nodoc:
@@ -76,8 +83,8 @@ module Rake
76
83
  define_task(Rake::FileTask, task_name)
77
84
  end
78
85
 
79
- # Resolve the arguments for a task/rule. Returns a triplet of
80
- # [task_name, arg_name_list, prerequisites].
86
+ # Resolve the arguments for a task/rule. Returns a tuple of
87
+ # [task_name, arg_name_list, prerequisites, order_only_prerequisites].
81
88
  def resolve_args(args)
82
89
  if args.last.is_a?(Hash)
83
90
  deps = args.pop
@@ -102,7 +109,7 @@ module Rake
102
109
  else
103
110
  arg_names = args
104
111
  end
105
- [task_name, arg_names, []]
112
+ [task_name, arg_names, [], nil]
106
113
  end
107
114
  private :resolve_args_without_dependencies
108
115
 
@@ -111,11 +118,17 @@ module Rake
111
118
  #
112
119
  # The patterns recognized by this argument resolving function are:
113
120
  #
121
+ # task :t, order_only: [:e]
114
122
  # task :t => [:d]
123
+ # task :t => [:d], order_only: [:e]
115
124
  # task :t, [a] => [:d]
125
+ # task :t, [a] => [:d], order_only: [:e]
116
126
  #
117
127
  def resolve_args_with_dependencies(args, hash) # :nodoc:
118
- fail "Task Argument Error" if hash.size != 1
128
+ fail "Task Argument Error" if
129
+ hash.size != 1 &&
130
+ (hash.size != 2 || !hash.key?(:order_only))
131
+ order_only = hash.delete(:order_only)
119
132
  key, value = hash.map { |k, v| [k, v] }.first
120
133
  if args.empty?
121
134
  task_name = key
@@ -123,11 +136,11 @@ module Rake
123
136
  deps = value || []
124
137
  else
125
138
  task_name = args.shift
126
- arg_names = key
127
- deps = value
139
+ arg_names = key || args.shift|| []
140
+ deps = value || []
128
141
  end
129
142
  deps = [deps] unless deps.respond_to?(:to_ary)
130
- [task_name, arg_names, deps]
143
+ [task_name, arg_names, deps, order_only]
131
144
  end
132
145
  private :resolve_args_with_dependencies
133
146
 
@@ -138,9 +151,10 @@ module Rake
138
151
  def enhance_with_matching_rule(task_name, level=0)
139
152
  fail Rake::RuleRecursionOverflowError,
140
153
  "Rule Recursion Too Deep" if level >= 16
141
- @rules.each do |pattern, args, extensions, block|
142
- if pattern.match(task_name)
143
- task = attempt_rule(task_name, args, extensions, block, level)
154
+ @rules.each do |pattern, args, extensions, order_only, block|
155
+ if pattern && pattern.match(task_name)
156
+ task = attempt_rule(task_name, pattern, args, extensions, block, level)
157
+ task | order_only unless order_only.nil?
144
158
  return task if task
145
159
  end
146
160
  end
@@ -180,10 +194,10 @@ module Rake
180
194
  task_name = task_name.to_s
181
195
  if task_name =~ /^rake:/
182
196
  scopes = Scope.make
183
- task_name = task_name.sub(/^rake:/, '')
197
+ task_name = task_name.sub(/^rake:/, "")
184
198
  elsif task_name =~ /^(\^+)/
185
199
  scopes = initial_scope.trim($1.size)
186
- task_name = task_name.sub(/^(\^+)/, '')
200
+ task_name = task_name.sub(/^(\^+)/, "")
187
201
  else
188
202
  scopes = initial_scope
189
203
  end
@@ -254,8 +268,8 @@ module Rake
254
268
  end
255
269
 
256
270
  # Attempt to create a rule given the list of prerequisites.
257
- def attempt_rule(task_name, args, extensions, block, level)
258
- sources = make_sources(task_name, extensions)
271
+ def attempt_rule(task_name, task_pattern, args, extensions, block, level)
272
+ sources = make_sources(task_name, task_pattern, extensions)
259
273
  prereqs = sources.map { |source|
260
274
  trace_rule level, "Attempting Rule #{task_name} => #{source}"
261
275
  if File.exist?(source) || Rake::Task.task_defined?(source)
@@ -269,14 +283,14 @@ module Rake
269
283
  return nil
270
284
  end
271
285
  }
272
- task = FileTask.define_task(task_name, {args => prereqs}, &block)
286
+ task = FileTask.define_task(task_name, { args => prereqs }, &block)
273
287
  task.sources = prereqs
274
288
  task
275
289
  end
276
290
 
277
291
  # Make a list of sources from the list of file name extensions /
278
292
  # translation procs.
279
- def make_sources(task_name, extensions)
293
+ def make_sources(task_name, task_pattern, extensions)
280
294
  result = extensions.map { |ext|
281
295
  case ext
282
296
  when /%/
@@ -284,7 +298,8 @@ module Rake
284
298
  when %r{/}
285
299
  ext
286
300
  when /^\./
287
- task_name.ext(ext)
301
+ source = task_name.sub(task_pattern, ext)
302
+ source == ext ? task_name.ext(ext) : source
288
303
  when String
289
304
  ext
290
305
  when Proc, Method