rake 13.0.0

Sign up to get free protection for your applications and to get access to all the features.
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