Buildr C0 Coverage Information - RCov

lib/buildr/core/util.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
lib/buildr/core/util.rb 537 353
12.10%
13.03%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with this
3 # work for additional information regarding copyright ownership.  The ASF
4 # licenses this file to you under the Apache License, Version 2.0 (the
5 # "License"); you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13 # License for the specific language governing permissions and limitations under
14 # the License.
15 
16 
17 require 'rbconfig'
18 require 'pathname'
19 autoload :Tempfile, 'tempfile'
20 autoload :YAML, 'yaml'
21 autoload :REXML, 'rexml/document'
22 gem 'xml-simple' ; autoload :XmlSimple, 'xmlsimple'
23 gem 'builder' ; autoload :Builder, 'builder' # A different kind of buildr, one we use to create XML.
24 require 'highline/import'
25 
26 
27 module Buildr
28 
29   module Util
30     extend self
31 
32     def java_platform?
33       RUBY_PLATFORM =~ /java/
34     end
35 
36     # In order to determine if we are running on a windows OS,
37     # prefer this function instead of using Gem.win_platform?.
38     #
39     # Gem.win_platform? only checks these RUBY_PLATFORM global,
40     # that in some cases like when running on JRuby is not
41     # succifient for our purpose:
42     #
43     # For JRuby, the value for RUBY_PLATFORM will always be 'java'
44     # That's why this function checks on Config::CONFIG['host_os']
45     def win_os?
46       Config::CONFIG['host_os'] =~ /windows|cygwin|bccwin|cygwin|djgpp|mingw|mswin|wince/i
47     end
48 
49     # Runs Ruby with these command line arguments.  The last argument may be a hash,
50     # supporting the following keys:
51     #   :command  -- Runs the specified script (e.g., :command=>'gem')
52     #   :sudo     -- Run as sudo on operating systems that require it.
53     #   :verbose  -- Override Rake's verbose flag.
54     def ruby(*args)
55       options = Hash === args.last ? args.pop : {}
56       cmd = []
57       ruby_bin = normalize_path(Config::CONFIG['ruby_install_name'], Config::CONFIG['bindir'])
58       if options.delete(:sudo) && !(win_os? || Process.uid == File.stat(ruby_bin).uid)
59         cmd << 'sudo' << '-u' << "##{File.stat(ruby_bin).uid}"
60       end
61       cmd << ruby_bin
62       cmd << '-S' << options.delete(:command) if options[:command]
63       cmd.concat args.flatten
64       cmd.push options
65       sh *cmd do |ok, status|
66         ok or fail "Command ruby failed with status (#{status ? status.exitstatus : 'unknown'}): [#{cmd.join(" ")}]"
67       end
68     end
69 
70     # Just like File.expand_path, but for windows systems it
71     # capitalizes the drive name and ensures backslashes are used
72     def normalize_path(path, *dirs)
73       path = File.expand_path(path, *dirs)
74       if win_os?
75         path.gsub!('/', '\\').gsub!(/^[a-zA-Z]+:/) { |s| s.upcase }
76       else
77         path
78       end
79     end
80 
81     # Return the timestamp of file, without having to create a file task
82     def timestamp(file)
83       if File.exist?(file)
84         File.mtime(file)
85       else
86         Rake::EARLY
87       end
88     end
89 
90     # Return the path to the first argument, starting from the path provided by the
91     # second argument.
92     #
93     # For example:
94     #   relative_path('foo/bar', 'foo')
95     #   => 'bar'
96     #   relative_path('foo/bar', 'baz')
97     #   => '../foo/bar'
98     #   relative_path('foo/bar')
99     #   => 'foo/bar'
100     #   relative_path('/foo/bar', 'baz')
101     #   => '/foo/bar'
102     def relative_path(to, from = '.')
103       to = Pathname.new(to).cleanpath
104       return to.to_s if from.nil?
105       to_path = Pathname.new(File.expand_path(to.to_s, "/"))
106       from_path = Pathname.new(File.expand_path(from.to_s, "/"))
107       to_path.relative_path_from(from_path).to_s
108     end
109 
110     # Generally speaking, it's not a good idea to operate on dot files (files starting with dot).
111     # These are considered invisible files (.svn, .hg, .irbrc, etc).  Dir.glob/FileList ignore them
112     # on purpose.  There are few cases where we do have to work with them (filter, zip), a better
113     # solution is welcome, maybe being more explicit with include.  For now, this will do.
114     def recursive_with_dot_files(*dirs)
115       FileList[dirs.map { |dir| File.join(dir, '/**/{*,.*}') }].reject { |file| File.basename(file) =~ /^[.]{1,2}$/ }
116     end
117 
118     # :call-seq:
119     #   replace_extension(filename) => filename_with_updated_extension
120     #
121     # Replace the file extension, e.g.,
122     #   replace_extension("foo.zip", "txt") => "foo.txt"
123     def replace_extension(filename, new_ext)
124       ext = File.extname(filename)
125       if filename =~ /\.$/
126         filename + new_ext
127       elsif ext == ""
128         filename + "." + new_ext
129       else
130         filename[0..-ext.length] + new_ext
131       end
132     end
133 
134     # Utility methods for running gem commands
135     module Gems #:nodoc:
136       extend self
137 
138       # Install gems specified by each Gem::Dependency if they are missing. This method prompts the user
139       # for permission before installing anything.
140       #
141       # Returns the installed Gem::Dependency objects or fails if permission not granted or when buildr
142       # is not running interactively (on a tty)
143       def install(*dependencies)
144         raise ArgumentError, "Expected at least one argument" if dependencies.empty?
145         not_found_deps = []
146         to_install = []
147         remote = dependencies.each do |dep|
148           if spec = Gem.source_index.search(dep).last
149             # Found in local repo
150             to_install << spec
151           elsif (spec = Gem::SpecFetcher.fetcher.fetch(dep, true).map { |spec, source| spec }.last)
152             # Found in remote repo
153             to_install << spec
154           else
155             # Not found anywhere
156             not_found_deps << "#{dep.name} #{dep.requirement}"
157           end
158         end
159         fail Gem::LoadError, "Build requires the gems #{not_found_deps.join(', ')}, which cannot be found in local or remote repository." unless not_found_deps.empty?
160         uses = "This build requires the gems #{to_install.map(&:full_name).join(', ')}:"
161         fail Gem::LoadError, "#{uses} to install, run Buildr interactively." unless $stdout.isatty
162         unless agree("#{uses} do you want me to install them? [Y/n]", true)
163           fail Gem::LoadError, 'Cannot build without these gems.'
164         end
165         to_install.each do |spec|
166           say "Installing #{spec.full_name} ... " if verbose
167           command 'install', spec.name, '-v', spec.version.to_s, :verbose => false
168           Gem.source_index.load_gems_in Gem::SourceIndex.installed_spec_directories
169         end
170         to_install
171       end
172 
173       # Execute a GemRunner command
174       def command(cmd, *args)
175         options = Hash === args.last ? args.pop : {}
176         gem_home = ENV['GEM_HOME'] || Gem.path.find { |f| File.writable?(f) }
177         options[:sudo] = :root unless Util.win_os? || gem_home
178         options[:command] = 'gem'
179         args << options
180         args.unshift '-i', gem_home if cmd == 'install' && gem_home && !args.any?{ |a| a[/-i|--install-dir/] }
181         Util.ruby cmd, *args
182       end
183 
184     end # Gems
185 
186   end # Util
187 end
188 
189 
190 class Object #:nodoc:
191   unless defined? instance_exec # 1.9
192     module InstanceExecMethods #:nodoc:
193     end
194     include InstanceExecMethods
195 
196     # Evaluate the block with the given arguments within the context of
197     # this object, so self is set to the method receiver.
198     #
199     # From Mauricio's http://eigenclass.org/hiki/bounded+space+instance_exec
200     def instance_exec(*args, &block)
201       begin
202         old_critical, Thread.critical = Thread.critical, true
203         n = 0
204         n += 1 while respond_to?(method_name = "__instance_exec#{n}")
205         InstanceExecMethods.module_eval { define_method(method_name, &block) }
206       ensure
207         Thread.critical = old_critical
208       end
209 
210       begin
211         send(method_name, *args)
212       ensure
213         InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil
214       end
215     end
216   end
217 end
218 
219 module Kernel #:nodoc:
220   unless defined? tap # 1.9
221     def tap
222       yield self if block_given?
223       self
224     end
225   end
226 end
227 
228 class Symbol #:nodoc:
229   unless defined? to_proc # 1.9
230     # Borrowed from Ruby 1.9.
231     def to_proc
232       Proc.new{|*args| args.shift.__send__(self, *args)}
233     end
234   end
235 end
236 
237 unless defined? BasicObject # 1.9
238   class BasicObject #:nodoc:
239     (instance_methods - ['__send__', '__id__', '==', 'send', 'send!', 'respond_to?', 'equal?', 'object_id']).
240       each do |method|
241         undef_method method
242       end
243 
244     def self.ancestors
245       [Kernel]
246     end
247   end
248 end
249 
250 
251 class OpenObject < Hash
252 
253   def initialize(source=nil, &block)
254     super &block
255     update source if source
256   end
257 
258   def method_missing(symbol, *args)
259     if symbol.to_s =~ /=$/
260       self[symbol.to_s[0..-2].to_sym] = args.first
261     else
262       self[symbol]
263     end
264   end
265 end
266 
267 
268 class Hash
269 
270   class << self
271 
272     # :call-seq:
273     #   Hash.from_java_properties(string)
274     #
275     # Returns a hash from a string in the Java properties file format. For example:
276     #   str = 'foo=bar\nbaz=fab'
277     #   Hash.from_properties(str)
278     #   => { 'foo'=>'bar', 'baz'=>'fab' }.to_properties
279     def from_java_properties(string)
280       hash = {}
281       input_stream = Java.java.io.StringBufferInputStream.new(string)
282       java_properties = Java.java.util.Properties.new
283       java_properties.load input_stream
284       keys = java_properties.keySet.iterator
285       while keys.hasNext
286         # Calling key.next in JRuby returns a java.lang.String, behaving as a Ruby string and life is good.
287         # MRI, unfortunately, treats next() like the interface says returning an object that's not a String,
288         # and the Hash doesn't work the way we need it to.  Unfortunately, we can call toString on MRI's object,
289         # but not on the JRuby one; calling to_s on the JRuby object returns what we need, but ... you guessed it.
290         #  So this seems like the one hack to unite them both.
291         #key = Java.java.lang.String.valueOf(keys.next.to_s)
292         key = keys.next
293         key = key.toString unless String === key
294         hash[key] = java_properties.getProperty(key)
295       end
296       hash
297     end
298 
299   end
300 
301   # :call-seq:
302   #   only(keys*) => hash
303   #
304   # Returns a new hash with only the specified keys.
305   #
306   # For example:
307   #   { :a=>1, :b=>2, :c=>3, :d=>4 }.only(:a, :c)
308   #   => { :a=>1, :c=>3 }
309   def only(*keys)
310     keys.inject({}) { |hash, key| has_key?(key) ? hash.merge(key=>self[key]) : hash }
311   end
312 
313 
314   # :call-seq:
315   #   except(keys*) => hash
316   #
317   # Returns a new hash without the specified keys.
318   #
319   # For example:
320   #   { :a=>1, :b=>2, :c=>3, :d=>4 }.except(:a, :c)
321   #   => { :b=>2, :d=>4 }
322   def except(*keys)
323     (self.keys - keys).inject({}) { |hash, key| hash.merge(key=>self[key]) }
324   end
325 
326   # :call-seq:
327   #   to_java_properties => string
328   #
329   # Convert hash to string format used for Java properties file. For example:
330   #   { 'foo'=>'bar', 'baz'=>'fab' }.to_properties
331   #   => foo=bar
332   #      baz=fab
333   def to_java_properties
334     keys.sort.map { |key|
335       value = self[key].gsub(/[\t\r\n\f\\]/) { |escape| "\\" + {"\t"=>"t", "\r"=>"r", "\n"=>"n", "\f"=>"f", "\\"=>"\\"}[escape] }
336       "#{key}=#{value}"
337     }.join("\n")
338   end
339 
340 end
341 
342 if Buildr::Util.java_platform?
343   require 'ffi'
344 
345   # Workaround for BUILDR-535: when requiring 'ffi', JRuby defines an :error
346   # method with arity 0.
347   class Module
348     remove_method :error if method_defined?(:error)
349   end
350 
351   # Fix for BUILDR-292.
352   # JRuby fails to rename a file on different devices
353   # this monkey-patch wont be needed when JRUBY-3381 gets resolved.
354   module FileUtils #:nodoc:
355     alias_method :__mv_native, :mv
356 
357     def mv(from, to, options = nil)
358       dir_to = File.directory?(to) ? to : File.dirname(to)
359       Array(from).each do |from|
360         dir_from = File.dirname(from)
361         if File.stat(dir_from).dev != File.stat(dir_to).dev
362           cp from, to, options
363           rm from, options
364         else
365           __mv_native from, to, options
366         end
367       end
368     end
369     private :mv
370   end
371 
372   module RakeFileUtils #:nodoc:
373     def rake_merge_option(args, defaults)
374       defaults[:verbose] = false if defaults[:verbose] == :default
375 
376       if Hash === args.last
377         defaults.update(args.last)
378         args.pop
379       end
380       args.push defaults
381       args
382     end
383     private :rake_merge_option
384   end
385 
386   module Buildr
387     class ProcessStatus
388       attr_reader :pid, :termsig, :stopsig, :exitstatus
389 
390       def initialize(pid, success, exitstatus)
391         @pid = pid
392         @success = success
393         @exitstatus = exitstatus
394 
395         @termsig = nil
396         @stopsig = nil
397       end
398 
399       def &(num)
400         pid & num
401       end
402 
403       def ==(other)
404         pid == other.pid
405       end
406 
407       def >>(num)
408         pid >> num
409       end
410 
411       def coredump?
412         false
413       end
414 
415       def exited?
416         true
417       end
418 
419       def stopped?
420         false
421       end
422 
423       def success?
424         @success
425       end
426 
427       def to_i
428         pid
429       end
430 
431       def to_int
432         pid
433       end
434 
435       def to_s
436         pid.to_s
437       end
438     end
439   end
440 
441   module FileUtils
442     extend FFI::Library
443 
444     ffi_lib FFI::Platform::LIBC
445 
446     alias_method :__jruby_system__, :system
447     attach_function :system, [:string], :int
448     alias_method :__native_system__, :system
449     alias_method :system, :__jruby_system__
450 
451     # code "borrowed" directly from Rake
452     def sh(*cmd, &block)
453       options = (Hash === cmd.last) ? cmd.pop : {}
454       unless block_given?
455         show_command = cmd.join(" ")
456         show_command = show_command[0,42] + "..."
457 
458         block = lambda { |ok, status|
459           ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
460         }
461       end
462       if RakeFileUtils.verbose_flag == :default
463         options[:verbose] = false
464       else
465         options[:verbose] ||= RakeFileUtils.verbose_flag
466       end
467       options[:noop]    ||= RakeFileUtils.nowrite_flag
468       rake_check_options options, :noop, :verbose
469       rake_output_message cmd.join(" ") if options[:verbose]
470       unless options[:noop]
471         if Buildr::Util.win_os?
472           # Ruby uses forward slashes regardless of platform,
473           # unfortunately cd c:/some/path fails on Windows
474           pwd = Dir.pwd.gsub(%r{/}, '\\')
475           cd = "cd /d \"#{pwd}\" && "
476         else
477           cd = "cd '#{Dir.pwd}' && "
478         end
479         args = if cmd.size > 1 then cmd[1..cmd.size] else [] end
480 
481         res = if Buildr::Util.win_os? && cmd.size == 1
482           __native_system__("#{cd} call #{cmd.first}")
483         else
484           arg_str = args.map { |a| "'#{a}'" }
485           __native_system__(cd + cmd.first + ' ' + arg_str.join(' '))
486         end
487         status = Buildr::ProcessStatus.new(0, res == 0, res)    # KLUDGE
488         block.call(res == 0, status)
489       end
490     end
491 
492   end
493 else
494   module FileUtils
495     # code "borrowed" directly from Rake
496     def sh(*cmd, &block)
497       options = (Hash === cmd.last) ? cmd.pop : {}
498       unless block_given?
499         show_command = cmd.join(" ")
500         show_command = show_command[0,42] + "..."
501 
502         block = lambda { |ok, status|
503           ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
504         }
505       end
506       if RakeFileUtils.verbose_flag == :default
507         options[:verbose] = false
508       else
509         options[:verbose] ||= RakeFileUtils.verbose_flag
510       end
511       options[:noop]    ||= RakeFileUtils.nowrite_flag
512       rake_check_options options, :noop, :verbose
513       rake_output_message cmd.join(" ") if options[:verbose]
514       unless options[:noop]
515         if Buildr::Util.win_os?
516           # Ruby uses forward slashes regardless of platform,
517           # unfortunately cd c:/some/path fails on Windows
518           pwd = Dir.pwd.gsub(%r{/}, '\\')
519           cd = "cd /d \"#{pwd}\" && "
520         else
521           cd = "cd '#{Dir.pwd}' && "
522         end
523 
524         args = if cmd.size > 1 then cmd[1..cmd.size] else [] end
525 
526         res = if Buildr::Util.win_os? && cmd.size == 1
527           system("#{cd} call #{cmd.first}")
528         else
529           arg_str = args.map { |a| "'#{a}'" }
530           system(cd + cmd.first + ' ' + arg_str.join(' '))
531         end
532 
533         block.call(res, $?)
534       end
535     end
536   end
537 end

Generated on 2011-07-06 23:35:37 -0700 with rcov 0.9.8