This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
module FileUtils
|
||||
|
||||
module_function
|
||||
|
||||
# An intergrated glob like method that takes a set of include globs,
|
||||
# exclude globs and ignore globs to produce a collection of paths.
|
||||
#
|
||||
# The ignore_globs differ from exclude_globs in that they match by
|
||||
# the basename of the path rather than the whole pathname.
|
||||
#
|
||||
# TODO: Should ignore be based on any portion of the path, not just the basename?
|
||||
#
|
||||
def amass(include_globs, exclude_globs=[], ignore=[])
|
||||
|
||||
include_files = [include_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq
|
||||
exclude_files = [exclude_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq
|
||||
|
||||
include_files = include_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive!
|
||||
exclude_files = exclude_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive!
|
||||
|
||||
include_files = include_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq
|
||||
exclude_files = exclude_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq
|
||||
|
||||
files = include_files - exclude_files
|
||||
|
||||
files = files.reject{ |f| [ignore].flatten.any?{ |x| File.fnmatch?(x, File.basename(f)) } }
|
||||
|
||||
files
|
||||
end
|
||||
|
||||
# Make public (for all submodules too).
|
||||
public :amass
|
||||
|
||||
end
|
||||
@@ -0,0 +1,44 @@
|
||||
module FileUtils
|
||||
|
||||
module_function
|
||||
|
||||
# Both of these are modified from the implementations in fileutils.rb from Ruby 1.9.1p378.
|
||||
|
||||
# Like FileUtils.cp_r, but takes a filter proc that can return false to skip a file:
|
||||
#
|
||||
# cp_rx "bigDirectoryTree", "dest", {:noop => true} do |name|
|
||||
# /dontCopyThis$/.match(name)
|
||||
# end
|
||||
#
|
||||
# Note that if the filter rejects a subdirectory then everything within that
|
||||
# subdirectory is automatically skipped as well.
|
||||
|
||||
def cp_rx(src, dest, options = {}, &filter)
|
||||
fu_check_options(options, OPT_TABLE['cp_r'])
|
||||
if options[:verbose]
|
||||
fu_output_message("cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}")
|
||||
end
|
||||
return if options[:noop]
|
||||
fu_each_src_dest(src, dest) do |s, d|
|
||||
copy_entryx(s, d, filter, options[:preserve], options[:dereference_root], options[:remove_destination])
|
||||
end
|
||||
end
|
||||
|
||||
# Like FileUtils.copy_entry, but takes a filter proc that can return false to skip a file.
|
||||
#
|
||||
# Note that if the filter rejects a subdirectory then everything within that
|
||||
# subdirectory is automatically skipped as well.
|
||||
|
||||
def copy_entryx(src, dest, filter, preserve = false, dereference_root = false, remove_destination = false)
|
||||
Entry_.new(src, nil, dereference_root).traverse do |ent|
|
||||
if filter.call(ent.path) then
|
||||
destent = Entry_.new(dest, ent.rel, false)
|
||||
File.unlink destent.path if remove_destination && File.file?(destent.path)
|
||||
ent.copy destent.path
|
||||
ent.copy_metadata(destent.path) if preserve
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
require 'facets/fileutils/slice'
|
||||
@@ -0,0 +1,99 @@
|
||||
module FileUtils
|
||||
|
||||
unless method_defined?(:ln_r)
|
||||
|
||||
#
|
||||
# Options: noop verbose dereference_root remove_destination
|
||||
#
|
||||
# Hard link +src+ to +dest+. If +src+ is a directory, this method links
|
||||
# all its contents recursively. If +dest+ is a directory, links
|
||||
# +src+ to +dest/src+.
|
||||
#
|
||||
# +src+ can be a list of files.
|
||||
#
|
||||
# # Installing ruby library "mylib" under the site_ruby
|
||||
# FileUtils.rm_r site_ruby + '/mylib', :force
|
||||
# FileUtils.ln_r 'lib/', site_ruby + '/mylib'
|
||||
#
|
||||
# # Examples of copying several files to target directory.
|
||||
# FileUtils.ln_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
|
||||
# FileUtils.ln_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
|
||||
#
|
||||
# # If you want to copy all contents of a directory instead of the
|
||||
# # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
|
||||
# # use following code.
|
||||
# FileUtils.ln_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
|
||||
# # but this doesn't.
|
||||
#
|
||||
# TODO: Why --remove-destination and not just --force?
|
||||
def ln_r(src, dest, options = {})
|
||||
fu_check_options options, OPT_TABLE['ln_r']
|
||||
fu_output_message "ln -r#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
|
||||
return if options[:noop]
|
||||
options = options.dup
|
||||
options[:dereference_root] = true unless options.key?(:dereference_root)
|
||||
fu_each_src_dest(src, dest) do |s, d|
|
||||
link_entry s, d, options[:dereference_root], options[:remove_destination]
|
||||
end
|
||||
end
|
||||
module_function :ln_r
|
||||
|
||||
OPT_TABLE = {} unless const_defined?(:OPT_TABLE)
|
||||
OPT_TABLE['ln_r'] = [:noop, :verbose, :dereference_root, :remove_destination]
|
||||
|
||||
#
|
||||
# Hard links a file system entry +src+ to +dest+.
|
||||
# If +src+ is a directory, this method links its contents recursively.
|
||||
#
|
||||
# Both of +src+ and +dest+ must be a path name.
|
||||
# +src+ must exist, +dest+ must not exist.
|
||||
#
|
||||
# If +dereference_root+ is true, this method dereference tree root.
|
||||
#
|
||||
# If +remove_destination+ is true, this method removes each destination file before copy.
|
||||
#
|
||||
def link_entry(src, dest, dereference_root = false, remove_destination = false)
|
||||
Entry_.new(src, nil, dereference_root).traverse do |ent|
|
||||
destent = Entry_.new(dest, ent.rel, false)
|
||||
File.unlink destent.path if remove_destination && File.file?(destent.path)
|
||||
ent.link destent.path
|
||||
end
|
||||
end
|
||||
module_function :link_entry
|
||||
|
||||
class Entry_ #:nodoc:
|
||||
def link(dest)
|
||||
case
|
||||
when directory?
|
||||
if !File.exist?(dest) and descendant_diretory?(dest, path)
|
||||
raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest]
|
||||
end
|
||||
begin
|
||||
Dir.mkdir dest
|
||||
rescue
|
||||
raise unless File.directory?(dest)
|
||||
end
|
||||
else file?
|
||||
File.link path(), dest
|
||||
end
|
||||
end
|
||||
|
||||
unless const_defined?(:DIRECTORY_TERM)
|
||||
if File::ALT_SEPARATOR
|
||||
DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)".freeze
|
||||
else
|
||||
DIRECTORY_TERM = "(?=/|\\z)".freeze
|
||||
end
|
||||
SYSCASE = File::FNM_SYSCASE.nonzero? ? "-i" : ""
|
||||
end
|
||||
|
||||
unless method_defined?(:descendant_diretory?)
|
||||
def descendant_diretory?(descendant, ascendant)
|
||||
/\A(?#{SYSCASE}:#{Regexp.quote(ascendant)})#{DIRECTORY_TERM}/ =~ File.dirname(descendant)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
module_function
|
||||
|
||||
# The opposite of #uptodate?
|
||||
def outofdate?(path, *sources)
|
||||
#return true unless File.exist?(path)
|
||||
! uptodate?(path, sources.flatten)
|
||||
end
|
||||
|
||||
# Alias for #outofdate?
|
||||
alias_method :out_of_date?, :outofdate?
|
||||
|
||||
# Alias for #uptodate?
|
||||
alias_method :up_to_date?, :uptodate?
|
||||
|
||||
# # TODO: Does a path need updating, based on given +sources+?
|
||||
# # This compares mtimes of give paths. Returns false
|
||||
# # if the path needs to be updated.
|
||||
# #
|
||||
# # DEPRECATE: Is this in any way better than `! uptodate?` ?
|
||||
# def out_of_date?(path, *sources)
|
||||
# return true unless File.exist?(path)
|
||||
#
|
||||
# sources = sources.collect{ |source| Dir.glob(source) }.flatten
|
||||
# mtimes = sources.collect{ |file| File.mtime(file) }
|
||||
#
|
||||
# return true if mtimes.empty? # TODO: This the way to go here?
|
||||
#
|
||||
# File.mtime(path) < mtimes.max
|
||||
# end
|
||||
|
||||
# Make public (for all submodules too).
|
||||
public :outofdate?
|
||||
public :out_of_date?
|
||||
public :up_to_date?
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
|
||||
module_function
|
||||
|
||||
LINKING_SUPPORTED = [true]
|
||||
|
||||
# Attempt to do a normal file link, but fall back
|
||||
# to a copy if the link fails.
|
||||
#
|
||||
# CREDIT: Jim Weirich
|
||||
def safe_ln(*args)
|
||||
unless LINKING_SUPPORTED[0]
|
||||
cp(*args)
|
||||
else
|
||||
begin
|
||||
ln(*args)
|
||||
rescue Errno::EOPNOTSUPP
|
||||
LINKING_SUPPORTED[0] = false
|
||||
cp(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
|
||||
module_function
|
||||
|
||||
# In block form, yields lines +from+-+to+. In non-block form, returns
|
||||
# an array of lines +from+-+to+:
|
||||
#
|
||||
# # Returns lines 8-12 of 'myfile'
|
||||
# FileUtils.body("myfile",8,12)
|
||||
#
|
||||
# CREDIT Shashank Date, via Daniel Berger.
|
||||
|
||||
def slice(filename,from,to) #:yield:
|
||||
IO.readlines(filename)[from-1..to-1]
|
||||
end
|
||||
|
||||
# In block form, yields the first number of +lines+ of file +filename+.
|
||||
# In non-block form, it returns an array of the first number of +lines+:
|
||||
#
|
||||
# # Returns first 10 lines of 'myfile'
|
||||
# FileUtils.head("myfile", 10)
|
||||
#
|
||||
def head(filename,lines) #:yield:
|
||||
a = []
|
||||
IO.foreach(filename){|line|
|
||||
break if lines <= 0
|
||||
lines -= 1
|
||||
if block_given?
|
||||
yield line
|
||||
else
|
||||
a << line
|
||||
end
|
||||
}
|
||||
return a.empty? ? nil : a
|
||||
end
|
||||
|
||||
# In block form, yields the last number of +lines+ of file +filename+.
|
||||
# In non-block form, it returns the lines as an array.
|
||||
#
|
||||
# Note that this method slurps the entire file, so I don't recommend it
|
||||
# for very large files. If you want an advanced form of +tail+, I
|
||||
# suggest using file-tail, by Florian Frank (available on the RAA):
|
||||
#
|
||||
# # Returns last 3 lines of 'myfile'
|
||||
# FileUtils.tail("myfile",3)
|
||||
#
|
||||
# And no tail -f.
|
||||
def tail(filename,lines) #:yield
|
||||
IO.readlines(filename).reverse[0..lines-1].reverse
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
module_function
|
||||
|
||||
# Stage by hard linking included files to a stage directory.
|
||||
#
|
||||
# stage_directory - Where to stage the files
|
||||
# source_directory - Where to find files to stage
|
||||
# files - Files to link in stage relative to source
|
||||
#
|
||||
# TODO: Rename to #link_stage or something less likely to name clash?
|
||||
# TODO: Add options for :verbose, :noop and :dryrun ?
|
||||
#
|
||||
def stage(stage_directory, source_directory, files, options={})
|
||||
return stage_directory if options[:noop] || options[:dryrun]
|
||||
|
||||
stage_directory, source_directory = stage_directory.to_s, source_directory.to_s
|
||||
## ensure existance of staging area
|
||||
rm_r(stage_directory) if File.directory?(stage_directory)
|
||||
mkdir_p(stage_directory)
|
||||
## link files into staging area
|
||||
files.each do |f|
|
||||
src = File.join(source_directory, f)
|
||||
file = File.join(stage_directory, f)
|
||||
if File.directory?(src)
|
||||
mkdir_p(file) unless File.exist?(file)
|
||||
else
|
||||
fdir = File.dirname(file)
|
||||
mkdir_p(fdir) unless File.exist?(fdir)
|
||||
unless File.exist?(file) and File.mtime(file) >= File.mtime(src)
|
||||
ln(src, file) #safe_ln ?
|
||||
end
|
||||
end
|
||||
end
|
||||
return stage_directory
|
||||
end
|
||||
|
||||
# Make public (for all submodules too).
|
||||
public :stage
|
||||
|
||||
module NoWrite
|
||||
module_function
|
||||
def stage(stage_directory, files, options={})
|
||||
options[:noop] = true
|
||||
FileUtils.stage(stage_directory, files, options={})
|
||||
end
|
||||
end
|
||||
|
||||
module Verbose
|
||||
module_function
|
||||
def stage(stage_directory, files, options={})
|
||||
options[:verbose] = true
|
||||
FileUtils.stage(stage_directory, files, options={})
|
||||
end
|
||||
end
|
||||
|
||||
module DryRun
|
||||
module_function
|
||||
def stage(stage_directory, files, options={})
|
||||
options[:dryrun] = true
|
||||
FileUtils.stage(stage_directory, files, options={})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
require 'facets/fileutils/slice'
|
||||
@@ -0,0 +1,63 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
|
||||
module_function
|
||||
|
||||
# With no arguments, returns a four element array consisting of the number
|
||||
# of bytes, characters, words and lines in _filename_, respectively.
|
||||
#
|
||||
# Valid options are +bytes+, +characters+ (or just 'chars'),
|
||||
# +words+ and +lines+:
|
||||
#
|
||||
# # Return the number of words in 'myfile'
|
||||
# FileUtils.wc("myfile",'words')
|
||||
#
|
||||
# CREDIT: Daniel J. Berger
|
||||
def wc(filename,option='all')
|
||||
option.downcase!
|
||||
valid = %w/all bytes characters chars lines words/
|
||||
|
||||
unless valid.include?(option)
|
||||
raise "Invalid option: '#{option}'"
|
||||
end
|
||||
|
||||
n = 0
|
||||
if option == 'lines'
|
||||
IO.foreach(filename){ n += 1 }
|
||||
return n
|
||||
elsif option == 'bytes'
|
||||
File.open(filename){ |f|
|
||||
f.each_byte{ n += 1 }
|
||||
}
|
||||
return n
|
||||
elsif option == 'characters' || option == 'chars'
|
||||
File.open(filename){ |f|
|
||||
while f.getc
|
||||
n += 1
|
||||
end
|
||||
}
|
||||
return n
|
||||
elsif option == 'words'
|
||||
IO.foreach(filename){ |line|
|
||||
n += line.split.length
|
||||
}
|
||||
return n
|
||||
else
|
||||
bytes,chars,lines,words = 0,0,0,0
|
||||
IO.foreach(filename){ |line|
|
||||
lines += 1
|
||||
words += line.split.length
|
||||
chars += line.split('').length
|
||||
}
|
||||
File.open(filename){ |f|
|
||||
while f.getc
|
||||
bytes += 1
|
||||
end
|
||||
}
|
||||
return [bytes,chars,words,lines]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
|
||||
if const_defined?(:Win32Exts)
|
||||
Win32Exts.concat %w{.exe .com .bat .cmd}
|
||||
Win32Exts.uniq!
|
||||
else
|
||||
Win32Exts = %w{.exe .com .bat .cmd}
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
# In block form, yields each ((*program*)) within ((*path*)). In non-block
|
||||
# form, returns an array of each ((*program*)) within ((*path*)). Returns
|
||||
# (({nil})) if not found.
|
||||
#
|
||||
# On the MS Windows platform, it looks for executables ending with .exe,
|
||||
# .bat and .com, which you may optionally include in the program name:
|
||||
#
|
||||
# FileUtils.whereis("ruby") #=> ['/usr/local/bin/ruby','/opt/bin/ruby']
|
||||
#
|
||||
# CREDIT: Daniel J. Berger
|
||||
|
||||
def whereis(prog, path=ENV['PATH']) #:yield:
|
||||
dirs = []
|
||||
path.split(File::PATH_SEPARATOR).each{|dir|
|
||||
# Windows checks against specific extensions
|
||||
if File::ALT_SEPARATOR
|
||||
if prog.include?('.')
|
||||
f = File.join(dir,prog)
|
||||
if File.executable?(f) && !File.directory?(f)
|
||||
if block_given?
|
||||
yield f.gsub(/\//,'\\')
|
||||
else
|
||||
dirs << f.gsub(/\//,'\\')
|
||||
end
|
||||
end
|
||||
else
|
||||
Win32Exts.find_all{|ext|
|
||||
f = File.join(dir,prog+ext)
|
||||
if File.executable?(f) && !File.directory?(f)
|
||||
if block_given?
|
||||
yield f.gsub(/\//,'\\')
|
||||
else
|
||||
dirs << f.gsub(/\//,'\\')
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
else
|
||||
f = File.join(dir,prog)
|
||||
# Avoid /usr/lib/ruby, for example
|
||||
if File.executable?(f) && !File.directory?(f)
|
||||
if block_given?
|
||||
yield f
|
||||
else
|
||||
dirs << f
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
dirs.empty? ? nil : dirs
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
require 'fileutils'
|
||||
|
||||
module FileUtils
|
||||
|
||||
if const_defined?(:Win32Exts)
|
||||
Win32Exts.concat %w{.exe .com .bat .cmd}
|
||||
Win32Exts.uniq!
|
||||
else
|
||||
Win32Exts = %w{.exe .com .bat .cmd}
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
# Looks for the first occurrence of _program_ within _path_.
|
||||
#
|
||||
# On the MS Windows platform, it looks for executables ending with .exe,
|
||||
# .bat and .com, which you may optionally include in the program name.
|
||||
# Returns <tt>nil</tt> if not found.
|
||||
#
|
||||
# CREDIT: Daniel J. Berger, Michael Granger
|
||||
#
|
||||
#--
|
||||
# The which() method was adopted from Daniel J. Berger, via PTools
|
||||
# which in in turn was adopted fromt the FileWhich code posted by
|
||||
# Michael Granger on http://www.rubygarden.org.
|
||||
#++
|
||||
def which(prog, path=ENV['PATH'])
|
||||
path.split(File::PATH_SEPARATOR).each {|dir|
|
||||
# Windows checks against specific extensions
|
||||
if File::ALT_SEPARATOR
|
||||
ext = Win32Exts.find{|ext|
|
||||
if prog.include?('.') # Assume extension already included
|
||||
f = File.join(dir,prog)
|
||||
else
|
||||
f = File.join(dir,prog+ext)
|
||||
end
|
||||
File.executable?(f) && !File.directory?(f)
|
||||
}
|
||||
if ext
|
||||
# Use backslashes, not forward slashes
|
||||
if prog.include?('.') # Assume extension already included
|
||||
f = File.join( dir, prog ).gsub(/\//,'\\')
|
||||
else
|
||||
f = File.join( dir, prog + ext ).gsub(/\//,'\\')
|
||||
end
|
||||
return f
|
||||
end
|
||||
else
|
||||
f = File.join(dir,prog)
|
||||
# Avoid /usr/lib/ruby, for example
|
||||
if File.executable?(f) && !File.directory?(f)
|
||||
return File::join( dir, prog )
|
||||
end
|
||||
end
|
||||
}
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user