brew/Library/Homebrew/extend/pathname.rb

439 lines
11 KiB
Ruby
Raw Normal View History

require 'pathname'
require 'bottles'
# we enhance pathname to make our code more readable
class Pathname
2012-02-09 18:43:47 -08:00
def install *sources
results = []
2012-02-09 18:43:47 -08:00
sources.each do |src|
case src
when Array
if src.empty?
2012-03-30 23:02:32 -07:00
opoo "tried to install empty array to #{self}"
return []
end
src.each {|s| results << install_p(s) }
2012-02-09 18:43:47 -08:00
when Hash
if src.empty?
2012-03-30 23:02:32 -07:00
opoo "tried to install empty hash to #{self}"
return []
end
src.each {|s, new_basename| results << install_p(s, new_basename) }
2012-02-09 18:43:47 -08:00
else
results << install_p(src)
2012-02-09 18:43:47 -08:00
end
end
return results
end
def install_p src, new_basename = nil
if new_basename
new_basename = File.basename(new_basename) # rationale: see Pathname.+
dst = self+new_basename
2012-02-08 21:58:46 -08:00
return_value = Pathname.new(dst)
else
dst = self
return_value = self+File.basename(src)
end
src = src.to_s
dst = dst.to_s
# if it's a symlink, don't resolve it to a file because if we are moving
# files one by one, it's likely we will break the symlink by moving what
# it points to before we move it
# and also broken symlinks are not the end of the world
raise "#{src} does not exist" unless File.symlink? src or File.exist? src
mkpath
if File.symlink? src
# we use the BSD mv command because FileUtils copies the target and
# not the link! I'm beginning to wish I'd used Python quite honestly!
raise unless Kernel.system 'mv', src, dst
else
# we mv when possible as it is faster and you should only be using
# this function when installing from the temporary build directory
FileUtils.mv src, dst
end
return return_value
end
2012-02-12 10:36:16 -08:00
# Creates symlinks to sources in this folder.
def install_symlink *sources
results = []
2012-02-12 10:36:16 -08:00
sources.each do |src|
case src
when Array
src.each {|s| results << install_symlink_p(s) }
2012-02-12 10:36:16 -08:00
when Hash
src.each {|s, new_basename| results << install_symlink_p(s, new_basename) }
2012-02-12 10:36:16 -08:00
else
results << install_symlink_p(src)
2012-02-12 10:36:16 -08:00
end
end
return results
2012-02-12 10:36:16 -08:00
end
def install_symlink_p src, new_basename = nil
if new_basename.nil?
dst = self+File.basename(src)
else
dst = self+File.basename(new_basename)
end
src = src.to_s
dst = dst.to_s
mkpath
FileUtils.ln_s src, dst
return dst
end
# we assume this pathname object is a file obviously
def write content
raise "Will not overwrite #{to_s}" if exist? and not ARGV.force?
dirname.mkpath
File.open(self, 'w') {|f| f.write content }
end
2012-03-16 12:58:39 +00:00
# NOTE always overwrites
def atomic_write content
require 'tempfile'
tf = Tempfile.new(self.basename.to_s)
tf.write(content)
tf.close
FileUtils.mv tf.path, self.to_s
end
def cp dst
if file?
FileUtils.cp to_s, dst
else
FileUtils.cp_r to_s, dst
end
return dst
end
# extended to support common double extensions
alias extname_old extname
def extname
return $1 if to_s =~ bottle_regex
return $1 if to_s =~ old_bottle_regex
2012-02-08 21:08:18 -08:00
/(\.(tar|cpio)\.(gz|bz2|xz|Z))$/.match to_s
return $1 if $1
return File.extname(to_s)
end
# for filetypes we support, basename without extension
def stem
return File.basename(to_s, extname)
end
# I don't trust the children.length == 0 check particularly, not to mention
# it is slow to enumerate the whole directory just to see if it is empty,
# instead rely on good ol' libc and the filesystem
def rmdir_if_possible
rmdir
true
rescue SystemCallError => e
raise unless e.errno == Errno::ENOTEMPTY::Errno or e.errno == Errno::EACCES::Errno
false
end
def chmod_R perms
require 'fileutils'
FileUtils.chmod_R perms, to_s
end
def abv
out=''
n=`find #{to_s} -type f ! -name .DS_Store | wc -l`.to_i
out<<"#{n} files, " if n > 1
out<<`/usr/bin/du -hd0 #{to_s} | cut -d"\t" -f1`.strip
end
# attempts to retrieve the version component of this path, so generally
# you'll call it on tarballs or extracted tarball directories, if you add
# to this please provide amend the unittest
def version
if directory?
# directories don't have extnames
stem=basename.to_s
else
# sourceforge /download
if %r[((?:sourceforge.net|sf.net)/.*)/download$].match to_s
stem=Pathname.new(dirname).stem
else
stem=self.stem
end
end
# github tarballs, like v1.2.3
%r[github.com/.*/(zip|tar)ball/v?((\d+\.)+\d+)$].match to_s
2011-06-04 17:29:21 -07:00
return $2 if $2
2012-01-14 03:46:25 +00:00
# eg. https://github.com/sam-github/libnet/tarball/libnet-1.1.4
%r[github.com/.*/(zip|tar)ball/.*-((\d+\.)+\d+)$].match to_s
2012-01-14 03:46:25 +00:00
return $2 if $2
# dashed version
# eg. github.com/isaacs/npm/tarball/v0.2.5-1
%r[github.com/.*/(zip|tar)ball/v?((\d+\.)+\d+-(\d+))$].match to_s
2011-06-04 17:29:21 -07:00
return $2 if $2
# underscore version
# eg. github.com/petdance/ack/tarball/1.93_02
%r[github.com/.*/(zip|tar)ball/v?((\d+\.)+\d+_(\d+))$].match to_s
2011-06-04 17:29:21 -07:00
return $2 if $2
# eg. boost_1_39_0
/((\d+_)+\d+)$/.match stem
return $1.gsub('_', '.') if $1
# eg. foobar-4.5.1-1
2009-08-30 15:49:38 +01:00
# eg. ruby-1.9.1-p243
2010-07-04 14:01:48 -07:00
/-((\d+\.)*\d\.\d+-(p|rc|RC)?\d+)$/.match stem
return $1 if $1
# eg. lame-398-1
/-((\d)+-\d)/.match stem
return $1 if $1
# eg. foobar-4.5.1
/-((\d+\.)*\d+)$/.match stem
return $1 if $1
# eg. foobar-4.5.1b
2010-07-04 14:01:48 -07:00
/-((\d+\.)*\d+([abc]|rc|RC)\d*)$/.match stem
return $1 if $1
# eg foobar-4.5.0-beta1, or foobar-4.50-beta
/-((\d+\.)*\d+-beta(\d+)?)$/.match stem
return $1 if $1
# eg. foobar4.5.1
unless /^erlang-/.match basename
/((\d+\.)*\d+)$/.match stem
return $1 if $1
end
# eg foobar-4.5.0-bin
2012-02-11 15:33:30 -08:00
/-((\d+\.)+\d+[abc]?)[-._](bin|dist|stable|src|sources?)$/.match stem
return $1 if $1
# Debian style eg dash_0.5.5.1.orig.tar.gz
/_((\d+\.)+\d+[abc]?)[.]orig$/.match stem
return $1 if $1
# eg. otp_src_R13B (this is erlang's style)
# eg. astyle_1.23_macosx.tar.gz
stem.scan(/_([^_]+)/) do |match|
return match.first if /\d/.match $1
end
# old erlang bottle style e.g. erlang-R14B03-bottle.tar.gz
/-([^-]+)/.match stem
return $1 if $1
nil
end
def compression_type
# Don't treat jars as compressed
return nil if self.extname == '.jar'
# OS X installer package
return :pkg if self.extname == '.pkg'
# Get enough of the file to detect common file types
# POSIX tar magic has a 257 byte offset
magic_bytes = nil
File.open(self) { |f| magic_bytes = f.read(262) }
# magic numbers stolen from /usr/share/file/magic/
case magic_bytes
when /^PK\003\004/ then :zip
when /^\037\213/ then :gzip
when /^BZh/ then :bzip2
when /^\037\235/ then :compress
when /^.{257}ustar/ then :tar
when /^\xFD7zXZ\x00/ then :xz
when /^Rar!/ then :rar
else
# Assume it is not an archive
nil
end
end
def incremental_hash(hasher)
incr_hash = hasher.new
self.open('r') do |f|
while(buf = f.read(1024))
incr_hash << buf
end
end
incr_hash.hexdigest
end
def md5
require 'digest/md5'
incremental_hash(Digest::MD5)
end
def sha1
require 'digest/sha1'
incremental_hash(Digest::SHA1)
end
def sha2
require 'digest/sha2'
incremental_hash(Digest::SHA2)
2009-12-30 18:56:46 +00:00
end
2009-09-30 22:17:46 -05:00
if '1.9' <= RUBY_VERSION
alias_method :to_str, :to_s
end
2010-02-27 12:29:45 +00:00
def cd
Dir.chdir(self){ yield }
end
def subdirs
children.select{ |child| child.directory? }
end
2010-07-25 12:07:35 -07:00
def resolved_path
self.symlink? ? dirname+readlink : self
end
def resolved_path_exists?
(dirname+readlink).exist?
end
# perhaps confusingly, this Pathname object becomes the symlink pointing to
# the src paramter.
2010-08-15 17:17:26 -07:00
def make_relative_symlink src
src = Pathname.new(src) unless src.kind_of? Pathname
2010-08-15 17:17:26 -07:00
self.dirname.mkpath
Dir.chdir self.dirname do
# NOTE only system ln -s will create RELATIVE symlinks
quiet_system 'ln', '-s', src.relative_path_from(self.dirname), self.basename
if not $?.success?
if self.exist?
raise <<-EOS.undent
Could not symlink file: #{src.expand_path}
Target #{self} already exists. You may need to delete it.
EOS
elsif !dirname.writable?
raise <<-EOS.undent
Could not symlink file: #{src.expand_path}
#{dirname} is not writable. You should change its permissions.
EOS
else
raise <<-EOS.undent
Could not symlink file: #{src.expand_path}
#{self} may already exist.
#{dirname} may not be writable.
EOS
end
end
2010-08-15 17:17:26 -07:00
end
end
def / that
join that.to_s
end
def ensure_writable
2011-06-16 17:38:52 +01:00
saved_perms = nil
unless writable?
saved_perms = stat.mode
chmod 0644
end
yield
ensure
chmod saved_perms if saved_perms
end
def install_info
unless self.symlink?
raise "Cannot install info entry for unbrewed info file '#{self}'"
end
system '/usr/bin/install-info', '--quiet', self.to_s, (self.dirname+'dir').to_s
end
def uninstall_info
unless self.symlink?
raise "Cannot uninstall info entry for unbrewed info file '#{self}'"
end
system '/usr/bin/install-info', '--delete', '--quiet', self.to_s, (self.dirname+'dir').to_s
end
2012-03-02 20:28:54 +00:00
def all_formula pwd = self
2012-03-02 20:28:54 +00:00
children.map{ |child| child.relative_path_from(pwd) }.each do |pn|
yield pn if pn.to_s =~ /.rb$/
end
children.each do |child|
child.all_formula(pwd) do |pn|
2012-03-02 20:28:54 +00:00
yield pn
end if child.directory?
end
end
def find_formula
# remove special casing once tap is established and alt removed
if self == HOMEBREW_LIBRARY/"Taps/adamv-alt"
all_formula do |file|
yield file
end
return
end
[self/:Formula, self/:HomebrewFormula, self].each do |d|
if d.exist?
d.children.map{ |child| child.relative_path_from(self) }.each do |pn|
yield pn if pn.to_s =~ /.rb$/
end
break
end
end
end
end
# sets $n and $d so you can observe creation of stuff
module ObserverPathnameExtension
def unlink
super
puts "rm #{to_s}" if ARGV.verbose?
$n+=1
end
def rmdir
super
puts "rmdir #{to_s}" if ARGV.verbose?
$d+=1
end
def mkpath
super
puts "mkpath #{to_s}" if ARGV.verbose?
$d+=1
end
def make_relative_symlink src
2010-08-15 17:17:26 -07:00
super
$n+=1
end
def install_info
super
puts "info #{to_s}" if ARGV.verbose?
end
def uninstall_info
super
puts "uninfo #{to_s}" if ARGV.verbose?
end
end
$n=0
$d=0