blob: b8b83b70eb06fd118d64bc2c2b008d2c796b0968 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
module Buildr #:nodoc:
module Util
extend self
def java_platform?
!!(RUBY_PLATFORM =~ /java/)
end
# In order to determine if we are running on a windows OS,
# prefer this function instead of using Gem.win_platform?.
#
# Gem.win_platform? only checks these RUBY_PLATFORM global,
# that in some cases like when running on JRuby is not
# sufficient for our purpose:
#
# For JRuby, the value for RUBY_PLATFORM will always be 'java'
# That's why this function checks on Config::CONFIG['host_os']
def win_os?
!!(RbConfig::CONFIG['host_os'] =~ /windows|cygwin|bccwin|cygwin|djgpp|mingw|mswin|mswin32|wince/i)
end
# Runs Ruby with these command line arguments. The last argument may be a hash,
# supporting the following keys:
# :command -- Runs the specified script (e.g., :command=>'gem')
# :sudo -- Run as sudo on operating systems that require it.
# :verbose -- Override Rake's verbose flag.
def ruby(*args)
options = Hash === args.last ? args.pop : {}
cmd = []
ruby_bin = normalize_path(RbConfig::CONFIG['ruby_install_name'], RbConfig::CONFIG['bindir'])
if options.delete(:sudo) && !(win_os? || Process.uid == File.stat(ruby_bin).uid)
cmd << 'sudo' << '-u' << "##{File.stat(ruby_bin).uid}"
end
cmd << ruby_bin
cmd << '-S' << options.delete(:command) if options[:command]
cmd.concat args.flatten
cmd.push options
sh *cmd do |ok, status|
ok or fail "Command ruby failed with status (#{status ? status.exitstatus : 'unknown'}): [#{cmd.join(" ")}]"
end
end
# Just like File.expand_path, but for windows systems it
# capitalizes the drive name and ensures backslashes are used
def normalize_path(path, *dirs)
path = File.expand_path(path, *dirs)
if win_os?
path.gsub!('/', '\\').gsub!(/^[a-zA-Z]+:/) { |s| s.upcase }
else
path
end
end
# Return the timestamp of file, without having to create a file task
def timestamp(file)
if File.exist?(file)
File.mtime(file)
else
Rake::EARLY
end
end
def uuid
return SecureRandom.uuid if SecureRandom.respond_to?(:uuid)
ary = SecureRandom.random_bytes(16).unpack("NnnnnN")
ary[2] = (ary[2] & 0x0fff) | 0x4000
ary[3] = (ary[3] & 0x3fff) | 0x8000
"%08x-%04x-%04x-%04x-%04x%08x" % ary
end
# Return the path to the first argument, starting from the path provided by the
# second argument.
#
# For example:
# relative_path('foo/bar', 'foo')
# => 'bar'
# relative_path('foo/bar', 'baz')
# => '../foo/bar'
# relative_path('foo/bar')
# => 'foo/bar'
# relative_path('/foo/bar', 'baz')
# => '/foo/bar'
def relative_path(to, from = '.')
to = Pathname.new(to).cleanpath
return to.to_s if from.nil?
to_path = Pathname.new(File.expand_path(to.to_s, "/"))
from_path = Pathname.new(File.expand_path(from.to_s, "/"))
to_path.relative_path_from(from_path).to_s
end
# Generally speaking, it's not a good idea to operate on dot files (files starting with dot).
# These are considered invisible files (.svn, .hg, .irbrc, etc). Dir.glob/FileList ignore them
# on purpose. There are few cases where we do have to work with them (filter, zip), a better
# solution is welcome, maybe being more explicit with include. For now, this will do.
def recursive_with_dot_files(*dirs)
FileList[dirs.map { |dir| File.join(dir, '/**/{*,.*}') }].reject { |file| File.basename(file) =~ /^[.]{1,2}$/ }
end
# :call-seq:
# replace_extension(filename) => filename_with_updated_extension
#
# Replace the file extension, e.g.,
# replace_extension("foo.zip", "txt") => "foo.txt"
def replace_extension(filename, new_ext)
ext = File.extname(filename)
if filename =~ /\.$/
filename + new_ext
elsif ext == ""
filename + "." + new_ext
else
filename[0..-ext.length] + new_ext
end
end
end # Util
end
class Object #:nodoc:
unless defined? instance_exec # 1.9
module InstanceExecMethods #:nodoc:
end
include InstanceExecMethods
# Evaluate the block with the given arguments within the context of
# this object, so self is set to the method receiver.
#
# From Mauricio's http://eigenclass.org/hiki/bounded+space+instance_exec
def instance_exec(*args, &block)
begin
old_critical, Thread.critical = Thread.critical, true
n = 0
n += 1 while respond_to?(method_name = "__instance_exec#{n}")
InstanceExecMethods.module_eval { define_method(method_name, &block) }
ensure
Thread.critical = old_critical
end
begin
send(method_name, *args)
ensure
InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil
end
end
end
end
module Kernel #:nodoc:
unless defined? tap # 1.9
def tap
yield self if block_given?
self
end
end
end
class Symbol #:nodoc:
unless defined? to_proc # 1.9
# Borrowed from Ruby 1.9.
def to_proc
Proc.new{|*args| args.shift.__send__(self, *args)}
end
end
end
unless defined? BasicObject # 1.9
class BasicObject #:nodoc:
(instance_methods - ['__send__', '__id__', '==', 'send', 'send!', 'respond_to?', 'equal?', 'object_id']).
each do |method|
undef_method method
end
def self.ancestors
[Kernel]
end
end
end
class OpenObject < Hash
def initialize(source=nil, &block)
super &block
update source if source
end
def method_missing(symbol, *args)
if symbol.to_s =~ /=$/
self[symbol.to_s[0..-2].to_sym] = args.first
else
self[symbol]
end
end
end
class Hash
class << self
# :call-seq:
# Hash.from_java_properties(string)
#
# Returns a hash from a string in the Java properties file format. For example:
# str = 'foo=bar\nbaz=fab'
# Hash.from_properties(str)
# => { 'foo'=>'bar', 'baz'=>'fab' }.to_properties
def from_java_properties(string)
hash = {}
input_stream = Java.java.io.StringBufferInputStream.new(string)
java_properties = Java.java.util.Properties.new
java_properties.load input_stream
keys = java_properties.keySet.iterator
while keys.hasNext
# Calling key.next in JRuby returns a java.lang.String, behaving as a Ruby string and life is good.
# MRI, unfortunately, treats next() like the interface says returning an object that's not a String,
# and the Hash doesn't work the way we need it to. Unfortunately, we can call toString on MRI's object,
# but not on the JRuby one; calling to_s on the JRuby object returns what we need, but ... you guessed it.
# So this seems like the one hack to unite them both.
#key = Java.java.lang.String.valueOf(keys.next.to_s)
key = keys.next
key = key.toString unless String === key
hash[key] = java_properties.getProperty(key)
end
hash
end
end
# :call-seq:
# only(keys*) => hash
#
# Returns a new hash with only the specified keys.
#
# For example:
# { :a=>1, :b=>2, :c=>3, :d=>4 }.only(:a, :c)
# => { :a=>1, :c=>3 }
def only(*keys)
keys.inject({}) { |hash, key| has_key?(key) ? hash.merge(key=>self[key]) : hash }
end
# :call-seq:
# except(keys*) => hash
#
# Returns a new hash without the specified keys.
#
# For example:
# { :a=>1, :b=>2, :c=>3, :d=>4 }.except(:a, :c)
# => { :b=>2, :d=>4 }
def except(*keys)
(self.keys - keys).inject({}) { |hash, key| hash.merge(key=>self[key]) }
end
# :call-seq:
# to_java_properties => string
#
# Convert hash to string format used for Java properties file. For example:
# { 'foo'=>'bar', 'baz'=>'fab' }.to_properties
# => foo=bar
# baz=fab
def to_java_properties
keys.sort.map { |key|
value = self[key].gsub(/[\t\r\n\f\\]/) { |escape| "\\" + {"\t"=>"t", "\r"=>"r", "\n"=>"n", "\f"=>"f", "\\"=>"\\"}[escape] }
"#{key}=#{value}"
}.join("\n")
end
end
if Buildr::Util.java_platform?
require 'ffi'
# Workaround for BUILDR-535: when requiring 'ffi', JRuby defines an :error
# method with arity 0.
class Module
remove_method :error if method_defined?(:error)
end
module Buildr
class ProcessStatus
attr_reader :pid, :termsig, :stopsig, :exitstatus
def initialize(pid, success, exitstatus)
@pid = pid
@success = success
@exitstatus = exitstatus
@termsig = nil
@stopsig = nil
end
def &(num)
pid & num
end
def ==(other)
pid == other.pid
end
def >>(num)
pid >> num
end
def coredump?
false
end
def exited?
true
end
def stopped?
false
end
def success?
@success
end
def to_i
pid
end
def to_int
pid
end
def to_s
pid.to_s
end
end
end
module FileUtils
extend FFI::Library
ffi_lib FFI::Platform::LIBC
alias_method :__jruby_system__, :system
attach_function :system, [:string], :int
alias_method :__native_system__, :system
alias_method :system, :__jruby_system__
# code "borrowed" directly from Rake
def sh(*cmd, &block)
options = (Hash === cmd.last) ? cmd.pop : {}
unless block_given?
show_command = cmd.join(" ")
show_command = show_command[0,42] + "..."
block = lambda { |ok, status|
ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
}
end
if RakeFileUtils.verbose_flag == Rake::FileUtilsExt::DEFAULT
options[:verbose] = false
else
options[:verbose] ||= RakeFileUtils.verbose_flag
end
options[:noop] ||= RakeFileUtils.nowrite_flag
rake_check_options options, :noop, :verbose
rake_output_message cmd.join(" ") if options[:verbose]
unless options[:noop]
if Buildr::Util.win_os?
# Ruby uses forward slashes regardless of platform,
# unfortunately cd c:/some/path fails on Windows
pwd = Dir.pwd.gsub(%r{/}, '\\')
cd = "cd /d \"#{pwd}\" && "
else
cd = "cd '#{Dir.pwd}' && "
end
args = if cmd.size > 1 then cmd[1..cmd.size] else [] end
res = if Buildr::Util.win_os? && cmd.size == 1
__native_system__("#{cd} call #{cmd.first}")
else
arg_str = args.map { |a| "'#{a}'" }
__native_system__(cd + cmd.first + ' ' + arg_str.join(' '))
end
status = Buildr::ProcessStatus.new(0, res == 0, res) # KLUDGE
block.call(res == 0, status)
end
end
end
else
module FileUtils
# code "borrowed" directly from Rake
def sh(*cmd, &block)
options = (Hash === cmd.last) ? cmd.pop : {}
unless block_given?
show_command = cmd.join(" ")
show_command = show_command[0,42] + "..."
block = lambda { |ok, status|
ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
}
end
if RakeFileUtils.verbose_flag == Rake::FileUtilsExt::DEFAULT
options[:verbose] = false
else
options[:verbose] ||= RakeFileUtils.verbose_flag
end
options[:noop] ||= RakeFileUtils.nowrite_flag
rake_check_options options, :noop, :verbose
rake_output_message cmd.join(" ") if options[:verbose]
unless options[:noop]
if Buildr::Util.win_os?
# Ruby uses forward slashes regardless of platform,
# unfortunately cd c:/some/path fails on Windows
pwd = Dir.pwd.gsub(%r{/}, '\\')
cd = "cd /d \"#{pwd}\" && "
else
cd = "cd '#{Dir.pwd}' && "
end
args = if cmd.size > 1 then cmd[1..cmd.size] else [] end
res = if Buildr::Util.win_os? && cmd.size == 1
system("#{cd} call #{cmd.first}")
else
arg_str = args.map { |a| "'#{a}'" }
system(cd + cmd.first + ' ' + arg_str.join(' '))
end
block.call(res, $?)
end
end
end
end