rake 0.8.7 → 0.9.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 (124) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGES +77 -9
  3. data/{README → README.rdoc} +14 -10
  4. data/Rakefile +129 -118
  5. data/TODO +1 -1
  6. data/doc/command_line_usage.rdoc +18 -6
  7. data/doc/glossary.rdoc +2 -2
  8. data/doc/jamis.rb +2 -2
  9. data/doc/proto_rake.rdoc +22 -22
  10. data/doc/rake.1.gz +0 -0
  11. data/doc/rakefile.rdoc +55 -32
  12. data/doc/rational.rdoc +6 -6
  13. data/doc/release_notes/rake-0.4.15.rdoc +1 -1
  14. data/doc/release_notes/rake-0.5.0.rdoc +1 -1
  15. data/doc/release_notes/rake-0.7.0.rdoc +1 -1
  16. data/doc/release_notes/rake-0.7.2.rdoc +3 -3
  17. data/doc/release_notes/rake-0.7.3.rdoc +2 -2
  18. data/doc/release_notes/rake-0.8.0.rdoc +1 -1
  19. data/doc/release_notes/rake-0.8.2.rdoc +3 -3
  20. data/doc/release_notes/rake-0.8.3.rdoc +2 -2
  21. data/doc/release_notes/rake-0.8.4.rdoc +1 -1
  22. data/doc/release_notes/rake-0.8.5.rdoc +1 -1
  23. data/doc/release_notes/rake-0.8.6.rdoc +1 -1
  24. data/doc/release_notes/rake-0.8.7.rdoc +1 -1
  25. data/doc/release_notes/rake-0.9.0.rdoc +112 -0
  26. data/install.rb +14 -12
  27. data/lib/rake/alt_system.rb +7 -6
  28. data/lib/rake/application.rb +589 -0
  29. data/lib/rake/classic_namespace.rb +1 -0
  30. data/lib/rake/clean.rb +2 -4
  31. data/lib/rake/cloneable.rb +25 -0
  32. data/lib/rake/contrib/compositepublisher.rb +2 -5
  33. data/lib/rake/contrib/ftptools.rb +5 -8
  34. data/lib/rake/contrib/publisher.rb +2 -8
  35. data/lib/rake/contrib/rubyforgepublisher.rb +2 -4
  36. data/lib/rake/contrib/sshpublisher.rb +4 -6
  37. data/lib/rake/contrib/sys.rb +7 -25
  38. data/lib/rake/default_loader.rb +10 -0
  39. data/lib/rake/dsl.rb +2 -0
  40. data/lib/rake/dsl_definition.rb +143 -0
  41. data/lib/rake/early_time.rb +18 -0
  42. data/lib/rake/ext/core.rb +27 -0
  43. data/lib/rake/ext/module.rb +39 -0
  44. data/lib/rake/ext/string.rb +167 -0
  45. data/lib/rake/ext/time.rb +14 -0
  46. data/lib/rake/file_creation_task.rb +24 -0
  47. data/lib/rake/file_list.rb +403 -0
  48. data/lib/rake/file_task.rb +47 -0
  49. data/lib/rake/file_utils.rb +112 -0
  50. data/lib/rake/file_utils_ext.rb +142 -0
  51. data/lib/rake/gempackagetask.rb +6 -90
  52. data/lib/rake/invocation_chain.rb +51 -0
  53. data/lib/rake/invocation_exception_mixin.rb +16 -0
  54. data/lib/rake/loaders/makefile.rb +13 -15
  55. data/lib/rake/multi_task.rb +16 -0
  56. data/lib/rake/name_space.rb +25 -0
  57. data/lib/rake/packagetask.rb +13 -12
  58. data/lib/rake/pathmap.rb +1 -0
  59. data/lib/rake/pseudo_status.rb +24 -0
  60. data/lib/rake/rake_module.rb +29 -0
  61. data/lib/rake/rake_test_loader.rb +10 -2
  62. data/lib/rake/rdoctask.rb +211 -190
  63. data/lib/rake/ruby182_test_unit_fix.rb +9 -7
  64. data/lib/rake/rule_recursion_overflow_error.rb +20 -0
  65. data/lib/rake/runtest.rb +4 -6
  66. data/lib/rake/task.rb +327 -0
  67. data/lib/rake/task_argument_error.rb +7 -0
  68. data/lib/rake/task_arguments.rb +74 -0
  69. data/lib/rake/task_manager.rb +307 -0
  70. data/lib/rake/tasklib.rb +1 -2
  71. data/lib/rake/testtask.rb +57 -27
  72. data/lib/rake/version.rb +10 -0
  73. data/lib/rake/win32.rb +4 -4
  74. data/lib/rake.rb +29 -2470
  75. data/test/contrib/test_sys.rb +8 -31
  76. data/test/data/access/Rakefile +33 -0
  77. data/test/data/comments/Rakefile +18 -0
  78. data/test/data/default/Rakefile +1 -1
  79. data/test/data/deprecated_import/Rakefile +1 -0
  80. data/test/data/dryrun/Rakefile +1 -1
  81. data/test/data/file_creation_task/Rakefile +1 -1
  82. data/test/data/namespace/Rakefile +9 -0
  83. data/test/data/rakelib/test1.rb +1 -0
  84. data/test/data/verbose/Rakefile +34 -0
  85. data/test/{filecreation.rb → file_creation.rb} +11 -7
  86. data/test/functional/functional_test.rb +25 -0
  87. data/test/{session_functional.rb → functional/session_based_tests.rb} +141 -23
  88. data/test/in_environment.rb +7 -5
  89. data/test/{test_application.rb → lib/application_test.rb} +331 -143
  90. data/test/{test_clean.rb → lib/clean_test.rb} +1 -0
  91. data/test/{test_definitions.rb → lib/definitions_test.rb} +3 -3
  92. data/test/lib/dsl_test.rb +52 -0
  93. data/test/{test_earlytime.rb → lib/earlytime_test.rb} +1 -2
  94. data/test/{test_extension.rb → lib/extension_test.rb} +2 -2
  95. data/test/{test_file_creation_task.rb → lib/file_creation_task_test.rb} +1 -1
  96. data/test/{test_file_task.rb → lib/file_task_test.rb} +4 -4
  97. data/test/{test_filelist.rb → lib/filelist_test.rb} +38 -24
  98. data/test/{test_fileutils.rb → lib/fileutils_test.rb} +27 -22
  99. data/test/{test_multitask.rb → lib/multitask_test.rb} +14 -6
  100. data/test/lib/package_task_test.rb +82 -0
  101. data/test/{test_pathmap.rb → lib/pathmap_test.rb} +3 -2
  102. data/test/{test_rake.rb → lib/rake_test.rb} +1 -1
  103. data/test/{test_rdoc_task.rb → lib/rdoc_task_test.rb} +19 -23
  104. data/test/{test_require.rb → lib/require_test.rb} +8 -2
  105. data/test/{test_rules.rb → lib/rules_test.rb} +2 -3
  106. data/test/{test_task_arguments.rb → lib/task_arguments_test.rb} +5 -5
  107. data/test/{test_task_manager.rb → lib/task_manager_test.rb} +15 -5
  108. data/test/{test_tasks.rb → lib/task_test.rb} +84 -21
  109. data/test/{test_test_task.rb → lib/test_task_test.rb} +3 -3
  110. data/test/lib/testtask_test.rb +49 -0
  111. data/test/{test_top_level_functions.rb → lib/top_level_functions_test.rb} +5 -3
  112. data/test/{test_win32.rb → lib/win32_test.rb} +19 -0
  113. data/test/rake_test_setup.rb +5 -9
  114. data/test/ruby_version_test.rb +3 -0
  115. data/test/test_helper.rb +19 -0
  116. metadata +108 -49
  117. data/test/functional.rb +0 -15
  118. data/test/test_package_task.rb +0 -118
  119. /data/test/{test_ftp.rb → lib/ftp_test.rb} +0 -0
  120. /data/test/{test_invocation_chain.rb → lib/invocation_chain_test.rb} +0 -0
  121. /data/test/{test_makefile_loader.rb → lib/makefile_loader_test.rb} +0 -0
  122. /data/test/{test_namespace.rb → lib/namespace_test.rb} +0 -0
  123. /data/test/{test_pseudo_status.rb → lib/pseudo_status_test.rb} +0 -0
  124. /data/test/{test_tasklib.rb → lib/tasklib_test.rb} +0 -0
@@ -0,0 +1,403 @@
1
+ require 'rake/cloneable'
2
+ require 'rake/file_utils_ext'
3
+ require 'rake/pathmap'
4
+
5
+ ######################################################################
6
+ module Rake
7
+
8
+ # #########################################################################
9
+ # A FileList is essentially an array with a few helper methods defined to
10
+ # make file manipulation a bit easier.
11
+ #
12
+ # FileLists are lazy. When given a list of glob patterns for possible files
13
+ # to be included in the file list, instead of searching the file structures
14
+ # to find the files, a FileList holds the pattern for latter use.
15
+ #
16
+ # This allows us to define a number of FileList to match any number of
17
+ # files, but only search out the actual files when then FileList itself is
18
+ # actually used. The key is that the first time an element of the
19
+ # FileList/Array is requested, the pending patterns are resolved into a real
20
+ # list of file names.
21
+ #
22
+ class FileList
23
+
24
+ include Cloneable
25
+
26
+ # == Method Delegation
27
+ #
28
+ # The lazy evaluation magic of FileLists happens by implementing all the
29
+ # array specific methods to call +resolve+ before delegating the heavy
30
+ # lifting to an embedded array object (@items).
31
+ #
32
+ # In addition, there are two kinds of delegation calls. The regular kind
33
+ # delegates to the @items array and returns the result directly. Well,
34
+ # almost directly. It checks if the returned value is the @items object
35
+ # itself, and if so will return the FileList object instead.
36
+ #
37
+ # The second kind of delegation call is used in methods that normally
38
+ # return a new Array object. We want to capture the return value of these
39
+ # methods and wrap them in a new FileList object. We enumerate these
40
+ # methods in the +SPECIAL_RETURN+ list below.
41
+
42
+ # List of array methods (that are not in +Object+) that need to be
43
+ # delegated.
44
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
45
+
46
+ # List of additional methods that must be delegated.
47
+ MUST_DEFINE = %w[to_a inspect <=>]
48
+
49
+ # List of methods that should not be delegated here (we define special
50
+ # versions of them explicitly below).
51
+ MUST_NOT_DEFINE = %w[to_a to_ary partition *]
52
+
53
+ # List of delegated methods that return new array values which need
54
+ # wrapping.
55
+ SPECIAL_RETURN = %w[
56
+ map collect sort sort_by select find_all reject grep
57
+ compact flatten uniq values_at
58
+ + - & |
59
+ ]
60
+
61
+ DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
62
+
63
+ # Now do the delegation.
64
+ DELEGATING_METHODS.each_with_index do |sym, i|
65
+ if SPECIAL_RETURN.include?(sym)
66
+ ln = __LINE__+1
67
+ class_eval %{
68
+ def #{sym}(*args, &block)
69
+ resolve
70
+ result = @items.send(:#{sym}, *args, &block)
71
+ FileList.new.import(result)
72
+ end
73
+ }, __FILE__, ln
74
+ else
75
+ ln = __LINE__+1
76
+ class_eval %{
77
+ def #{sym}(*args, &block)
78
+ resolve
79
+ result = @items.send(:#{sym}, *args, &block)
80
+ result.object_id == @items.object_id ? self : result
81
+ end
82
+ }, __FILE__, ln
83
+ end
84
+ end
85
+
86
+ # Create a file list from the globbable patterns given. If you wish to
87
+ # perform multiple includes or excludes at object build time, use the
88
+ # "yield self" pattern.
89
+ #
90
+ # Example:
91
+ # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
92
+ #
93
+ # pkg_files = FileList.new('lib/**/*') do |fl|
94
+ # fl.exclude(/\bCVS\b/)
95
+ # end
96
+ #
97
+ def initialize(*patterns)
98
+ @pending_add = []
99
+ @pending = false
100
+ @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
101
+ @exclude_procs = DEFAULT_IGNORE_PROCS.dup
102
+ @items = []
103
+ patterns.each { |pattern| include(pattern) }
104
+ yield self if block_given?
105
+ end
106
+
107
+ # Add file names defined by glob patterns to the file list. If an array
108
+ # is given, add each element of the array.
109
+ #
110
+ # Example:
111
+ # file_list.include("*.java", "*.cfg")
112
+ # file_list.include %w( math.c lib.h *.o )
113
+ #
114
+ def include(*filenames)
115
+ # TODO: check for pending
116
+ filenames.each do |fn|
117
+ if fn.respond_to? :to_ary
118
+ include(*fn.to_ary)
119
+ else
120
+ @pending_add << fn
121
+ end
122
+ end
123
+ @pending = true
124
+ self
125
+ end
126
+ alias :add :include
127
+
128
+ # Register a list of file name patterns that should be excluded from the
129
+ # list. Patterns may be regular expressions, glob patterns or regular
130
+ # strings. In addition, a block given to exclude will remove entries that
131
+ # return true when given to the block.
132
+ #
133
+ # Note that glob patterns are expanded against the file system. If a file
134
+ # is explicitly added to a file list, but does not exist in the file
135
+ # system, then an glob pattern in the exclude list will not exclude the
136
+ # file.
137
+ #
138
+ # Examples:
139
+ # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
140
+ # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
141
+ #
142
+ # If "a.c" is a file, then ...
143
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
144
+ #
145
+ # If "a.c" is not a file, then ...
146
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
147
+ #
148
+ def exclude(*patterns, &block)
149
+ patterns.each do |pat|
150
+ @exclude_patterns << pat
151
+ end
152
+ if block_given?
153
+ @exclude_procs << block
154
+ end
155
+ resolve_exclude if ! @pending
156
+ self
157
+ end
158
+
159
+
160
+ # Clear all the exclude patterns so that we exclude nothing.
161
+ def clear_exclude
162
+ @exclude_patterns = []
163
+ @exclude_procs = []
164
+ self
165
+ end
166
+
167
+ # Define equality.
168
+ def ==(array)
169
+ to_ary == array
170
+ end
171
+
172
+ # Return the internal array object.
173
+ def to_a
174
+ resolve
175
+ @items
176
+ end
177
+
178
+ # Return the internal array object.
179
+ def to_ary
180
+ to_a
181
+ end
182
+
183
+ # Lie about our class.
184
+ def is_a?(klass)
185
+ klass == Array || super(klass)
186
+ end
187
+ alias kind_of? is_a?
188
+
189
+ # Redefine * to return either a string or a new file list.
190
+ def *(other)
191
+ result = @items * other
192
+ case result
193
+ when Array
194
+ FileList.new.import(result)
195
+ else
196
+ result
197
+ end
198
+ end
199
+
200
+ # Resolve all the pending adds now.
201
+ def resolve
202
+ if @pending
203
+ @pending = false
204
+ @pending_add.each do |fn| resolve_add(fn) end
205
+ @pending_add = []
206
+ resolve_exclude
207
+ end
208
+ self
209
+ end
210
+
211
+ def resolve_add(fn)
212
+ case fn
213
+ when %r{[*?\[\{]}
214
+ add_matching(fn)
215
+ else
216
+ self << fn
217
+ end
218
+ end
219
+ private :resolve_add
220
+
221
+ def resolve_exclude
222
+ reject! { |fn| exclude?(fn) }
223
+ self
224
+ end
225
+ private :resolve_exclude
226
+
227
+ # Return a new FileList with the results of running +sub+ against each
228
+ # element of the original list.
229
+ #
230
+ # Example:
231
+ # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
232
+ #
233
+ def sub(pat, rep)
234
+ inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
235
+ end
236
+
237
+ # Return a new FileList with the results of running +gsub+ against each
238
+ # element of the original list.
239
+ #
240
+ # Example:
241
+ # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
242
+ # => ['lib\\test\\file', 'x\\y']
243
+ #
244
+ def gsub(pat, rep)
245
+ inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
246
+ end
247
+
248
+ # Same as +sub+ except that the original file list is modified.
249
+ def sub!(pat, rep)
250
+ each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
251
+ self
252
+ end
253
+
254
+ # Same as +gsub+ except that the original file list is modified.
255
+ def gsub!(pat, rep)
256
+ each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
257
+ self
258
+ end
259
+
260
+ # Apply the pathmap spec to each of the included file names, returning a
261
+ # new file list with the modified paths. (See String#pathmap for
262
+ # details.)
263
+ def pathmap(spec=nil)
264
+ collect { |fn| fn.pathmap(spec) }
265
+ end
266
+
267
+ # Return a new FileList with <tt>String#ext</tt> method applied to
268
+ # each member of the array.
269
+ #
270
+ # This method is a shortcut for:
271
+ #
272
+ # array.collect { |item| item.ext(newext) }
273
+ #
274
+ # +ext+ is a user added method for the Array class.
275
+ def ext(newext='')
276
+ collect { |fn| fn.ext(newext) }
277
+ end
278
+
279
+
280
+ # Grep each of the files in the filelist using the given pattern. If a
281
+ # block is given, call the block on each matching line, passing the file
282
+ # name, line number, and the matching line of text. If no block is given,
283
+ # a standard emacs style file:linenumber:line message will be printed to
284
+ # standard out. Returns the number of matched items.
285
+ def egrep(pattern, *options)
286
+ matched = 0
287
+ each do |fn|
288
+ begin
289
+ open(fn, "rb", *options) do |inf|
290
+ count = 0
291
+ inf.each do |line|
292
+ count += 1
293
+ if pattern.match(line)
294
+ matched += 1
295
+ if block_given?
296
+ yield fn, count, line
297
+ else
298
+ puts "#{fn}:#{count}:#{line}"
299
+ end
300
+ end
301
+ end
302
+ end
303
+ rescue StandardError => ex
304
+ $stderr.puts "Error while processing '#{fn}': #{ex}"
305
+ end
306
+ end
307
+ matched
308
+ end
309
+
310
+ # Return a new file list that only contains file names from the current
311
+ # file list that exist on the file system.
312
+ def existing
313
+ select { |fn| File.exist?(fn) }
314
+ end
315
+
316
+ # Modify the current file list so that it contains only file name that
317
+ # exist on the file system.
318
+ def existing!
319
+ resolve
320
+ @items = @items.select { |fn| File.exist?(fn) }
321
+ self
322
+ end
323
+
324
+ # FileList version of partition. Needed because the nested arrays should
325
+ # be FileLists in this version.
326
+ def partition(&block) # :nodoc:
327
+ resolve
328
+ result = @items.partition(&block)
329
+ [
330
+ FileList.new.import(result[0]),
331
+ FileList.new.import(result[1]),
332
+ ]
333
+ end
334
+
335
+ # Convert a FileList to a string by joining all elements with a space.
336
+ def to_s
337
+ resolve
338
+ self.join(' ')
339
+ end
340
+
341
+ # Add matching glob patterns.
342
+ def add_matching(pattern)
343
+ Dir[pattern].each do |fn|
344
+ self << fn unless exclude?(fn)
345
+ end
346
+ end
347
+ private :add_matching
348
+
349
+ # Should the given file name be excluded?
350
+ def exclude?(fn)
351
+ return true if @exclude_patterns.any? do |pat|
352
+ case pat
353
+ when Regexp
354
+ fn =~ pat
355
+ when /[*?]/
356
+ File.fnmatch?(pat, fn, File::FNM_PATHNAME)
357
+ else
358
+ fn == pat
359
+ end
360
+ end
361
+ @exclude_procs.any? { |p| p.call(fn) }
362
+ end
363
+
364
+ DEFAULT_IGNORE_PATTERNS = [
365
+ /(^|[\/\\])CVS([\/\\]|$)/,
366
+ /(^|[\/\\])\.svn([\/\\]|$)/,
367
+ /\.bak$/,
368
+ /~$/
369
+ ]
370
+ DEFAULT_IGNORE_PROCS = [
371
+ proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
372
+ ]
373
+
374
+ def import(array)
375
+ @items = array
376
+ self
377
+ end
378
+
379
+ class << self
380
+ # Create a new file list including the files listed. Similar to:
381
+ #
382
+ # FileList.new(*args)
383
+ def [](*args)
384
+ new(*args)
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ module Rake
391
+ class << self
392
+
393
+ # Yield each file or directory component.
394
+ def each_dir_parent(dir) # :nodoc:
395
+ old_length = nil
396
+ while dir != '.' && dir.length != old_length
397
+ yield(dir)
398
+ old_length = dir.length
399
+ dir = File.dirname(dir)
400
+ end
401
+ end
402
+ end
403
+ end # module Rake
@@ -0,0 +1,47 @@
1
+ require 'rake/task.rb'
2
+ require 'rake/early_time'
3
+
4
+ module Rake
5
+ # #########################################################################
6
+ # A FileTask is a task that includes time based dependencies. If any of a
7
+ # FileTask's prerequisites have a timestamp that is later than the file
8
+ # represented by this task, then the file must be rebuilt (using the
9
+ # supplied actions).
10
+ #
11
+ class FileTask < Task
12
+
13
+ # Is this file task needed? Yes if it doesn't exist, or if its time stamp
14
+ # is out of date.
15
+ def needed?
16
+ ! File.exist?(name) || out_of_date?(timestamp)
17
+ end
18
+
19
+ # Time stamp for file task.
20
+ def timestamp
21
+ if File.exist?(name)
22
+ File.mtime(name.to_s)
23
+ else
24
+ Rake::EARLY
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # Are there any prerequisites with a later time than the given time stamp?
31
+ def out_of_date?(stamp)
32
+ @prerequisites.any? { |n| application[n, @scope].timestamp > stamp}
33
+ end
34
+
35
+ # ----------------------------------------------------------------
36
+ # Task class methods.
37
+ #
38
+ class << self
39
+ # Apply the scope to the task name according to the rules for this kind
40
+ # of task. File based tasks ignore the scope when creating the name.
41
+ def scope_name(scope, task_name)
42
+ task_name
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,112 @@
1
+ require 'rbconfig'
2
+ require 'fileutils'
3
+
4
+ # ###########################################################################
5
+ # This a FileUtils extension that defines several additional commands to be
6
+ # added to the FileUtils utility functions.
7
+ #
8
+ module FileUtils
9
+ # Path to the currently running Ruby program
10
+ RUBY = File.join(
11
+ RbConfig::CONFIG['bindir'],
12
+ RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']).
13
+ sub(/.*\s.*/m, '"\&"')
14
+
15
+ OPT_TABLE['sh'] = %w(noop verbose)
16
+ OPT_TABLE['ruby'] = %w(noop verbose)
17
+
18
+ # Run the system command +cmd+. If multiple arguments are given the command
19
+ # is not run with the shell (same semantics as Kernel::exec and
20
+ # Kernel::system).
21
+ #
22
+ # Example:
23
+ # sh %{ls -ltr}
24
+ #
25
+ # sh 'ls', 'file with spaces'
26
+ #
27
+ # # check exit status after command runs
28
+ # sh %{grep pattern file} do |ok, res|
29
+ # if ! ok
30
+ # puts "pattern not found (status = #{res.exitstatus})"
31
+ # end
32
+ # end
33
+ #
34
+ def sh(*cmd, &block)
35
+ options = (Hash === cmd.last) ? cmd.pop : {}
36
+ shell_runner = block_given? ? block : create_shell_runner(cmd)
37
+ set_verbose_option(options)
38
+ options[:noop] ||= Rake::FileUtilsExt.nowrite_flag
39
+ Rake.rake_check_options options, :noop, :verbose
40
+ Rake.rake_output_message cmd.join(" ") if options[:verbose]
41
+ unless options[:noop]
42
+ res = rake_system(*cmd)
43
+ status = $?
44
+ status = PseudoStatus.new(1) if !res && status.nil?
45
+ shell_runner.call(res, status)
46
+ end
47
+ end
48
+
49
+ def create_shell_runner(cmd)
50
+ show_command = cmd.join(" ")
51
+ show_command = show_command[0,42] + "..." unless $trace
52
+ lambda { |ok, status|
53
+ ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
54
+ }
55
+ end
56
+ private :create_shell_runner
57
+
58
+ def set_verbose_option(options)
59
+ if options[:verbose].nil?
60
+ options[:verbose] = Rake::FileUtilsExt.verbose_flag.nil? || Rake::FileUtilsExt.verbose_flag
61
+ end
62
+ end
63
+ private :set_verbose_option
64
+
65
+ def rake_system(*cmd)
66
+ Rake::AltSystem.system(*cmd)
67
+ end
68
+ private :rake_system
69
+
70
+ # Run a Ruby interpreter with the given arguments.
71
+ #
72
+ # Example:
73
+ # ruby %{-pe '$_.upcase!' <README}
74
+ #
75
+ def ruby(*args,&block)
76
+ options = (Hash === args.last) ? args.pop : {}
77
+ if args.length > 1 then
78
+ sh(*([RUBY] + args + [options]), &block)
79
+ else
80
+ sh("#{RUBY} #{args.first}", options, &block)
81
+ end
82
+ end
83
+
84
+ LN_SUPPORTED = [true]
85
+
86
+ # Attempt to do a normal file link, but fall back to a copy if the link
87
+ # fails.
88
+ def safe_ln(*args)
89
+ unless LN_SUPPORTED[0]
90
+ cp(*args)
91
+ else
92
+ begin
93
+ ln(*args)
94
+ rescue StandardError, NotImplementedError
95
+ LN_SUPPORTED[0] = false
96
+ cp(*args)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Split a file path into individual directory names.
102
+ #
103
+ # Example:
104
+ # split_all("a/b/c") => ['a', 'b', 'c']
105
+ #
106
+ def split_all(path)
107
+ head, tail = File.split(path)
108
+ return [tail] if head == '.' || tail == '/'
109
+ return [head, tail] if head == '/'
110
+ return split_all(head) + [tail]
111
+ end
112
+ end
@@ -0,0 +1,142 @@
1
+ require 'rake/file_utils'
2
+
3
+ module Rake
4
+ #
5
+ # FileUtilsExt provides a custom version of the FileUtils methods
6
+ # that respond to the <tt>verbose</tt> and <tt>nowrite</tt>
7
+ # commands.
8
+ #
9
+ module FileUtilsExt
10
+ include FileUtils
11
+
12
+ class << self
13
+ attr_accessor :verbose_flag, :nowrite_flag
14
+ end
15
+ FileUtilsExt.verbose_flag = nil
16
+ FileUtilsExt.nowrite_flag = false
17
+
18
+ $fileutils_verbose = true
19
+ $fileutils_nowrite = false
20
+
21
+ FileUtils::OPT_TABLE.each do |name, opts|
22
+ default_options = []
23
+ if opts.include?(:verbose) || opts.include?("verbose")
24
+ default_options << ':verbose => FileUtilsExt.verbose_flag'
25
+ end
26
+ if opts.include?(:noop) || opts.include?("noop")
27
+ default_options << ':noop => FileUtilsExt.nowrite_flag'
28
+ end
29
+
30
+ next if default_options.empty?
31
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
32
+ def #{name}( *args, &block )
33
+ super(
34
+ *rake_merge_option(args,
35
+ #{default_options.join(', ')}
36
+ ), &block)
37
+ end
38
+ EOS
39
+ end
40
+
41
+ # Get/set the verbose flag controlling output from the FileUtils
42
+ # utilities. If verbose is true, then the utility method is
43
+ # echoed to standard output.
44
+ #
45
+ # Examples:
46
+ # verbose # return the current value of the
47
+ # # verbose flag
48
+ # verbose(v) # set the verbose flag to _v_.
49
+ # verbose(v) { code } # Execute code with the verbose flag set
50
+ # # temporarily to _v_. Return to the
51
+ # # original value when code is done.
52
+ def verbose(value=nil)
53
+ oldvalue = FileUtilsExt.verbose_flag
54
+ FileUtilsExt.verbose_flag = value unless value.nil?
55
+ if block_given?
56
+ begin
57
+ yield
58
+ ensure
59
+ FileUtilsExt.verbose_flag = oldvalue
60
+ end
61
+ end
62
+ FileUtilsExt.verbose_flag
63
+ end
64
+
65
+ # Get/set the nowrite flag controlling output from the FileUtils
66
+ # utilities. If verbose is true, then the utility method is
67
+ # echoed to standard output.
68
+ #
69
+ # Examples:
70
+ # nowrite # return the current value of the
71
+ # # nowrite flag
72
+ # nowrite(v) # set the nowrite flag to _v_.
73
+ # nowrite(v) { code } # Execute code with the nowrite flag set
74
+ # # temporarily to _v_. Return to the
75
+ # # original value when code is done.
76
+ def nowrite(value=nil)
77
+ oldvalue = FileUtilsExt.nowrite_flag
78
+ FileUtilsExt.nowrite_flag = value unless value.nil?
79
+ if block_given?
80
+ begin
81
+ yield
82
+ ensure
83
+ FileUtilsExt.nowrite_flag = oldvalue
84
+ end
85
+ end
86
+ oldvalue
87
+ end
88
+
89
+ # Use this function to prevent potentially destructive ruby code
90
+ # from running when the :nowrite flag is set.
91
+ #
92
+ # Example:
93
+ #
94
+ # when_writing("Building Project") do
95
+ # project.build
96
+ # end
97
+ #
98
+ # The following code will build the project under normal
99
+ # conditions. If the nowrite(true) flag is set, then the example
100
+ # will print:
101
+ #
102
+ # DRYRUN: Building Project
103
+ #
104
+ # instead of actually building the project.
105
+ #
106
+ def when_writing(msg=nil)
107
+ if FileUtilsExt.nowrite_flag
108
+ $stderr.puts "DRYRUN: #{msg}" if msg
109
+ else
110
+ yield
111
+ end
112
+ end
113
+
114
+ # Merge the given options with the default values.
115
+ def rake_merge_option(args, defaults)
116
+ if Hash === args.last
117
+ defaults.update(args.last)
118
+ args.pop
119
+ end
120
+ args.push defaults
121
+ args
122
+ end
123
+
124
+ # Send the message to the default rake output (which is $stderr).
125
+ def rake_output_message(message)
126
+ $stderr.puts(message)
127
+ end
128
+
129
+ # Check that the options do not contain options not listed in
130
+ # +optdecl+. An ArgumentError exception is thrown if non-declared
131
+ # options are found.
132
+ def rake_check_options(options, *optdecl)
133
+ h = options.dup
134
+ optdecl.each do |name|
135
+ h.delete name
136
+ end
137
+ raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
138
+ end
139
+
140
+ extend self
141
+ end
142
+ end