Skip to content

Instantly share code, notes, and snippets.

@webos-goodies
Created June 20, 2012 06:59
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save webos-goodies/2958517 to your computer and use it in GitHub Desktop.
Copy multiple files and directories with timestamp checking and exclude patterns.
#! /usr/bin/ruby
require 'optparse'
require 'fileutils'
$verbose_mode = false
$update_mode = false
$exclude_patterns = []
$exclude_suffixes = []
$files = []
$target_dir = nil
OptionParser.new('Usage: flexcopy [options] FILE... DIR') do |opt|
opt.on('-e PATTERN', '--exclude=PATTERN', 'exclude files matching PATTERN') do |pat|
$exclude_patterns << pat
end
opt.on('-s SUFFIXES', '--exclude-suffixes=SUFFIXES',
'exclude files with SUFFIXES (comma separeted list)') do |suffix|
$exclude_suffixes = $exclude_suffixes + suffix.downcase.split(',')
end
opt.on('-u', '--[no-]update', 'skip files that are newer on receiver') do |mode|
$update_mode = mode
end
opt.on('-v', '--[no-]verbose', 'verbose mode') do |mode|
$verbose_mode = mode
end
$files = opt.parse!(ARGV)
if $files.size < 2
$stderr << opt.help
exit(1)
end
$target_dir = $files.pop
if !File.directory?($target_dir)
$stderr << "#{$target_dir} is not a directory\n"
exit(1)
end
end
def is_excluded_filename(fname)
return ($exclude_suffixes.include?(File.extname(fname)[1..-1]) ||
$exclude_patterns.any?{|pat| File.fnmatch?(pat, fname) })
end
def is_newer_file(fname, than)
(left_stat = File.stat(fname)) rescue return false
(right_stat = File.stat(than)) rescue return true
return left_stat > right_stat
end
def traverse(path, &block)
return if is_excluded_filename(File.basename(path))
block.call(path)
if File.directory?(path)
Dir.foreach(path) do |fname|
traverse(File.join(path, fname), &block) if fname != '.' && fname != '..'
end
end
end
files = []
$files.each do |source_fname|
base_dir = File.dirname(source_fname)
Dir.chdir(base_dir) do
traverse(File.basename(source_fname)) do |path|
files << [base_dir, path]
end
end
end
files.each do |fname|
src = File.join(*fname)
dst = File.join($target_dir, fname[1])
if File.directory?(src)
if !File.exist?(dst)
$stderr << "makedir: #{fname[1]}\n" if $verbose_mode
FileUtils.mkdir_p(dst)
end
elsif !$update_mode || is_newer_file(src, dst)
$stderr << "copy: #{fname[1]}\n" if $verbose_mode
FileUtils.copy_file(src, dst, true)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment