rake 13.0.0

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 (75) hide show
  1. checksums.yaml +7 -0
  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 +43 -0
  7. data/Gemfile +10 -0
  8. data/History.rdoc +2359 -0
  9. data/MIT-LICENSE +21 -0
  10. data/README.rdoc +155 -0
  11. data/Rakefile +41 -0
  12. data/bin/bundle +105 -0
  13. data/bin/console +7 -0
  14. data/bin/rake +29 -0
  15. data/bin/rdoc +29 -0
  16. data/bin/rubocop +29 -0
  17. data/bin/setup +6 -0
  18. data/doc/command_line_usage.rdoc +158 -0
  19. data/doc/example/Rakefile1 +38 -0
  20. data/doc/example/Rakefile2 +35 -0
  21. data/doc/example/a.c +6 -0
  22. data/doc/example/b.c +6 -0
  23. data/doc/example/main.c +11 -0
  24. data/doc/glossary.rdoc +42 -0
  25. data/doc/jamis.rb +592 -0
  26. data/doc/proto_rake.rdoc +127 -0
  27. data/doc/rake.1 +156 -0
  28. data/doc/rakefile.rdoc +622 -0
  29. data/doc/rational.rdoc +151 -0
  30. data/exe/rake +27 -0
  31. data/lib/rake.rb +71 -0
  32. data/lib/rake/application.rb +824 -0
  33. data/lib/rake/backtrace.rb +24 -0
  34. data/lib/rake/clean.rb +78 -0
  35. data/lib/rake/cloneable.rb +17 -0
  36. data/lib/rake/cpu_counter.rb +107 -0
  37. data/lib/rake/default_loader.rb +15 -0
  38. data/lib/rake/dsl_definition.rb +195 -0
  39. data/lib/rake/early_time.rb +22 -0
  40. data/lib/rake/ext/core.rb +26 -0
  41. data/lib/rake/ext/string.rb +176 -0
  42. data/lib/rake/file_creation_task.rb +25 -0
  43. data/lib/rake/file_list.rb +435 -0
  44. data/lib/rake/file_task.rb +54 -0
  45. data/lib/rake/file_utils.rb +134 -0
  46. data/lib/rake/file_utils_ext.rb +134 -0
  47. data/lib/rake/invocation_chain.rb +57 -0
  48. data/lib/rake/invocation_exception_mixin.rb +17 -0
  49. data/lib/rake/late_time.rb +18 -0
  50. data/lib/rake/linked_list.rb +112 -0
  51. data/lib/rake/loaders/makefile.rb +54 -0
  52. data/lib/rake/multi_task.rb +14 -0
  53. data/lib/rake/name_space.rb +38 -0
  54. data/lib/rake/packagetask.rb +222 -0
  55. data/lib/rake/phony.rb +16 -0
  56. data/lib/rake/private_reader.rb +21 -0
  57. data/lib/rake/promise.rb +100 -0
  58. data/lib/rake/pseudo_status.rb +30 -0
  59. data/lib/rake/rake_module.rb +67 -0
  60. data/lib/rake/rake_test_loader.rb +27 -0
  61. data/lib/rake/rule_recursion_overflow_error.rb +20 -0
  62. data/lib/rake/scope.rb +43 -0
  63. data/lib/rake/task.rb +433 -0
  64. data/lib/rake/task_argument_error.rb +8 -0
  65. data/lib/rake/task_arguments.rb +109 -0
  66. data/lib/rake/task_manager.rb +328 -0
  67. data/lib/rake/tasklib.rb +12 -0
  68. data/lib/rake/testtask.rb +224 -0
  69. data/lib/rake/thread_history_display.rb +49 -0
  70. data/lib/rake/thread_pool.rb +163 -0
  71. data/lib/rake/trace_output.rb +23 -0
  72. data/lib/rake/version.rb +10 -0
  73. data/lib/rake/win32.rb +51 -0
  74. data/rake.gemspec +36 -0
  75. metadata +132 -0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module Rake
3
+
4
+ ##
5
+ # Exit status class for times the system just gives us a nil.
6
+ class PseudoStatus # :nodoc: all
7
+ attr_reader :exitstatus
8
+
9
+ def initialize(code=0)
10
+ @exitstatus = code
11
+ end
12
+
13
+ def to_i
14
+ @exitstatus << 8
15
+ end
16
+
17
+ def >>(n)
18
+ to_i >> n
19
+ end
20
+
21
+ def stopped?
22
+ false
23
+ end
24
+
25
+ def exited?
26
+ true
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ require "rake/application"
3
+
4
+ module Rake
5
+
6
+ class << self
7
+ # Current Rake Application
8
+ def application
9
+ @application ||= Rake::Application.new
10
+ end
11
+
12
+ # Set the current Rake application object.
13
+ def application=(app)
14
+ @application = app
15
+ end
16
+
17
+ def suggested_thread_count # :nodoc:
18
+ @cpu_count ||= Rake::CpuCounter.count
19
+ @cpu_count + 4
20
+ end
21
+
22
+ # Return the original directory where the Rake application was started.
23
+ def original_dir
24
+ application.original_dir
25
+ end
26
+
27
+ # Load a rakefile.
28
+ def load_rakefile(path)
29
+ load(path)
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
65
+ end
66
+
67
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "rake"
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
14
+
15
+ false
16
+ else
17
+ require File.expand_path argument
18
+
19
+ false
20
+ end
21
+ rescue LoadError => e
22
+ raise unless e.path
23
+ abort "\nFile does not exist: #{e.path}\n\n"
24
+ end
25
+ end
26
+
27
+ ARGV.replace argv
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Rake
3
+
4
+ # Error indicating a recursion overflow error in task selection.
5
+ class RuleRecursionOverflowError < StandardError
6
+ def initialize(*args)
7
+ super
8
+ @targets = []
9
+ end
10
+
11
+ def add_target(target)
12
+ @targets << target
13
+ end
14
+
15
+ def message
16
+ super + ": [" + @targets.reverse.join(" => ") + "]"
17
+ end
18
+ end
19
+
20
+ end
@@ -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
@@ -0,0 +1,433 @@
1
+ # frozen_string_literal: true
2
+ require "rake/invocation_exception_mixin"
3
+
4
+ module Rake
5
+
6
+ ##
7
+ # A Task is the basic unit of work in a Rakefile. Tasks have associated
8
+ # actions (possibly more than one) and a list of prerequisites. When
9
+ # invoked, a task will first ensure that all of its prerequisites have an
10
+ # opportunity to run and then it will execute its own actions.
11
+ #
12
+ # Tasks are not usually created directly using the new method, but rather
13
+ # use the +file+ and +task+ convenience methods.
14
+ #
15
+ class Task
16
+ # List of prerequisites for a task.
17
+ attr_reader :prerequisites
18
+ alias prereqs prerequisites
19
+
20
+ # List of order only prerequisites for a task.
21
+ attr_reader :order_only_prerequisites
22
+
23
+ # List of actions attached to a task.
24
+ attr_reader :actions
25
+
26
+ # Application owning this task.
27
+ attr_accessor :application
28
+
29
+ # Array of nested namespaces names used for task lookup by this task.
30
+ attr_reader :scope
31
+
32
+ # File/Line locations of each of the task definitions for this
33
+ # task (only valid if the task was defined with the detect
34
+ # location option set).
35
+ attr_reader :locations
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
+
41
+ # Return task name
42
+ def to_s
43
+ name
44
+ end
45
+
46
+ def inspect # :nodoc:
47
+ "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
48
+ end
49
+
50
+ # List of sources for task.
51
+ attr_writer :sources
52
+ def sources
53
+ if defined?(@sources)
54
+ @sources
55
+ else
56
+ prerequisites
57
+ end
58
+ end
59
+
60
+ # List of prerequisite tasks
61
+ def prerequisite_tasks
62
+ (prerequisites + order_only_prerequisites).map { |pre| lookup_prerequisite(pre) }
63
+ end
64
+
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
71
+ end
72
+ private :lookup_prerequisite
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
+
92
+ # First source from a rule (nil if no sources)
93
+ def source
94
+ sources.first
95
+ end
96
+
97
+ # Create a task named +task_name+ with no actions or prerequisites. Use
98
+ # +enhance+ to add actions and prerequisites.
99
+ def initialize(task_name, app)
100
+ @name = task_name.to_s
101
+ @prerequisites = []
102
+ @actions = []
103
+ @already_invoked = false
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 = []
112
+ end
113
+
114
+ # Enhance a task with prerequisites or actions. Returns self.
115
+ def enhance(deps=nil, &block)
116
+ @prerequisites |= deps if deps
117
+ @actions << block if block_given?
118
+ self
119
+ end
120
+
121
+ # Name of the task, including any namespace qualifiers.
122
+ def name
123
+ @name.to_s
124
+ end
125
+
126
+ # Name of task with argument list description.
127
+ def name_with_args # :nodoc:
128
+ if arg_description
129
+ "#{name}#{arg_description}"
130
+ else
131
+ name
132
+ end
133
+ end
134
+
135
+ # Argument description (nil if none).
136
+ def arg_description # :nodoc:
137
+ @arg_names ? "[#{arg_names.join(',')}]" : nil
138
+ end
139
+
140
+ # Name of arguments for this task.
141
+ def arg_names
142
+ @arg_names || []
143
+ end
144
+
145
+ # Reenable the task, allowing its tasks to be executed if the task
146
+ # is invoked again.
147
+ def reenable
148
+ @already_invoked = false
149
+ end
150
+
151
+ # Clear the existing prerequisites, actions, comments, and arguments of a rake task.
152
+ def clear
153
+ clear_prerequisites
154
+ clear_actions
155
+ clear_comments
156
+ clear_args
157
+ self
158
+ end
159
+
160
+ # Clear the existing prerequisites of a rake task.
161
+ def clear_prerequisites
162
+ prerequisites.clear
163
+ self
164
+ end
165
+
166
+ # Clear the existing actions on a rake task.
167
+ def clear_actions
168
+ actions.clear
169
+ self
170
+ end
171
+
172
+ # Clear the existing comments on a rake task.
173
+ def clear_comments
174
+ @comments = []
175
+ self
176
+ end
177
+
178
+ # Clear the existing arguments on a rake task.
179
+ def clear_args
180
+ @arg_names = nil
181
+ self
182
+ end
183
+
184
+ # Invoke the task if it is needed. Prerequisites are invoked first.
185
+ def invoke(*args)
186
+ task_args = TaskArguments.new(arg_names, args)
187
+ invoke_with_call_chain(task_args, InvocationChain::EMPTY)
188
+ end
189
+
190
+ # Same as invoke, but explicitly pass a call chain to detect
191
+ # circular dependencies.
192
+ #
193
+ # If multiple tasks depend on this
194
+ # one in parallel, they will all fail if the first execution of
195
+ # this task fails.
196
+ def invoke_with_call_chain(task_args, invocation_chain)
197
+ new_chain = Rake::InvocationChain.append(self, invocation_chain)
198
+ @lock.synchronize do
199
+ begin
200
+ if application.options.trace
201
+ application.trace "** Invoke #{name} #{format_trace_flags}"
202
+ end
203
+
204
+ if @already_invoked
205
+ if @invocation_exception
206
+ if application.options.trace
207
+ application.trace "** Previous invocation of #{name} failed #{format_trace_flags}"
208
+ end
209
+ raise @invocation_exception
210
+ else
211
+ return
212
+ end
213
+ end
214
+
215
+ @already_invoked = true
216
+
217
+ invoke_prerequisites(task_args, new_chain)
218
+ execute(task_args) if needed?
219
+ rescue Exception => ex
220
+ add_chain_to(ex, new_chain)
221
+ @invocation_exception = ex
222
+ raise ex
223
+ end
224
+ end
225
+ end
226
+ protected :invoke_with_call_chain
227
+
228
+ def add_chain_to(exception, new_chain) # :nodoc:
229
+ exception.extend(InvocationExceptionMixin) unless
230
+ exception.respond_to?(:chain)
231
+ exception.chain = new_chain if exception.chain.nil?
232
+ end
233
+ private :add_chain_to
234
+
235
+ # Invoke all the prerequisites of a task.
236
+ def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
237
+ if application.options.always_multitask
238
+ invoke_prerequisites_concurrently(task_args, invocation_chain)
239
+ else
240
+ prerequisite_tasks.each { |p|
241
+ prereq_args = task_args.new_scope(p.arg_names)
242
+ p.invoke_with_call_chain(prereq_args, invocation_chain)
243
+ }
244
+ end
245
+ end
246
+
247
+ # Invoke all the prerequisites of a task in parallel.
248
+ def invoke_prerequisites_concurrently(task_args, invocation_chain)# :nodoc:
249
+ futures = prerequisite_tasks.map do |p|
250
+ prereq_args = task_args.new_scope(p.arg_names)
251
+ application.thread_pool.future(p) do |r|
252
+ r.invoke_with_call_chain(prereq_args, invocation_chain)
253
+ end
254
+ end
255
+ # Iterate in reverse to improve performance related to thread waiting and switching
256
+ futures.reverse_each(&:value)
257
+ end
258
+
259
+ # Format the trace flags for display.
260
+ def format_trace_flags
261
+ flags = []
262
+ flags << "first_time" unless @already_invoked
263
+ flags << "not_needed" unless needed?
264
+ flags.empty? ? "" : "(" + flags.join(", ") + ")"
265
+ end
266
+ private :format_trace_flags
267
+
268
+ # Execute the actions associated with this task.
269
+ def execute(args=nil)
270
+ args ||= EMPTY_TASK_ARGS
271
+ if application.options.dryrun
272
+ application.trace "** Execute (dry run) #{name}"
273
+ return
274
+ end
275
+ application.trace "** Execute #{name}" if application.options.trace
276
+ application.enhance_with_matching_rule(name) if @actions.empty?
277
+ if opts = Hash.try_convert(args) and !opts.empty?
278
+ @actions.each { |act| act.call(self, args, **opts)}
279
+ else
280
+ @actions.each { |act| act.call(self, args)}
281
+ end
282
+ end
283
+
284
+ # Is this task needed?
285
+ def needed?
286
+ true
287
+ end
288
+
289
+ # Timestamp for this task. Basic tasks return the current time for their
290
+ # time stamp. Other tasks can be more sophisticated.
291
+ def timestamp
292
+ Time.now
293
+ end
294
+
295
+ # Add a description to the task. The description can consist of an option
296
+ # argument list (enclosed brackets) and an optional comment.
297
+ def add_description(description)
298
+ return unless description
299
+ comment = description.strip
300
+ add_comment(comment) if comment && !comment.empty?
301
+ end
302
+
303
+ def comment=(comment) # :nodoc:
304
+ add_comment(comment)
305
+ end
306
+
307
+ def add_comment(comment) # :nodoc:
308
+ return if comment.nil?
309
+ @comments << comment unless @comments.include?(comment)
310
+ end
311
+ private :add_comment
312
+
313
+ # Full collection of comments. Multiple comments are separated by
314
+ # newlines.
315
+ def full_comment
316
+ transform_comments("\n")
317
+ end
318
+
319
+ # First line (or sentence) of all comments. Multiple comments are
320
+ # separated by a "/".
321
+ def comment
322
+ transform_comments(" / ") { |c| first_sentence(c) }
323
+ end
324
+
325
+ # Transform the list of comments as specified by the block and
326
+ # join with the separator.
327
+ def transform_comments(separator, &block)
328
+ if @comments.empty?
329
+ nil
330
+ else
331
+ block ||= lambda { |c| c }
332
+ @comments.map(&block).join(separator)
333
+ end
334
+ end
335
+ private :transform_comments
336
+
337
+ # Get the first sentence in a string. The sentence is terminated
338
+ # by the first period, exclamation mark, or the end of the line.
339
+ # Decimal points do not count as periods.
340
+ def first_sentence(string)
341
+ string.split(/(?<=\w)(\.|!)[ \t]|(\.$|!)|\n/).first
342
+ end
343
+ private :first_sentence
344
+
345
+ # Set the names of the arguments for this task. +args+ should be
346
+ # an array of symbols, one for each argument name.
347
+ def set_arg_names(args)
348
+ @arg_names = args.map(&:to_sym)
349
+ end
350
+
351
+ # Return a string describing the internal state of a task. Useful for
352
+ # debugging.
353
+ def investigation
354
+ result = "------------------------------\n".dup
355
+ result << "Investigating #{name}\n"
356
+ result << "class: #{self.class}\n"
357
+ result << "task needed: #{needed?}\n"
358
+ result << "timestamp: #{timestamp}\n"
359
+ result << "pre-requisites: \n"
360
+ prereqs = prerequisite_tasks
361
+ prereqs.sort! { |a, b| a.timestamp <=> b.timestamp }
362
+ prereqs.each do |p|
363
+ result << "--#{p.name} (#{p.timestamp})\n"
364
+ end
365
+ latest_prereq = prerequisite_tasks.map(&:timestamp).max
366
+ result << "latest-prerequisite time: #{latest_prereq}\n"
367
+ result << "................................\n\n"
368
+ return result
369
+ end
370
+
371
+ # Format dependencies parameter to pass to task.
372
+ def self.format_deps(deps)
373
+ deps = [deps] unless deps.respond_to?(:to_ary)
374
+ deps.map { |d| Rake.from_pathname(d).to_s }
375
+ end
376
+
377
+ # Add order only dependencies.
378
+ def |(deps)
379
+ @order_only_prerequisites |= Task.format_deps(deps) - @prerequisites
380
+ self
381
+ end
382
+
383
+ # ----------------------------------------------------------------
384
+ # Rake Module Methods
385
+ #
386
+ class << self
387
+
388
+ # Clear the task list. This cause rake to immediately forget all the
389
+ # tasks that have been assigned. (Normally used in the unit tests.)
390
+ def clear
391
+ Rake.application.clear
392
+ end
393
+
394
+ # List of all defined tasks.
395
+ def tasks
396
+ Rake.application.tasks
397
+ end
398
+
399
+ # Return a task with the given name. If the task is not currently
400
+ # known, try to synthesize one from the defined rules. If no rules are
401
+ # found, but an existing file matches the task name, assume it is a file
402
+ # task with no dependencies or actions.
403
+ def [](task_name)
404
+ Rake.application[task_name]
405
+ end
406
+
407
+ # TRUE if the task name is already defined.
408
+ def task_defined?(task_name)
409
+ Rake.application.lookup(task_name) != nil
410
+ end
411
+
412
+ # Define a task given +args+ and an option block. If a rule with the
413
+ # given name already exists, the prerequisites and actions are added to
414
+ # the existing task. Returns the defined task.
415
+ def define_task(*args, &block)
416
+ Rake.application.define_task(self, *args, &block)
417
+ end
418
+
419
+ # Define a rule for synthesizing tasks.
420
+ def create_rule(*args, &block)
421
+ Rake.application.create_rule(*args, &block)
422
+ end
423
+
424
+ # Apply the scope to the task name according to the rules for
425
+ # this kind of task. Generic tasks will accept the scope as
426
+ # part of the name.
427
+ def scope_name(scope, task_name)
428
+ scope.path_with_task_name(task_name)
429
+ end
430
+
431
+ end # class << Rake::Task
432
+ end # class Rake::Task
433
+ end