#!/usr/bin/env ruby -w require 'find' require 'getoptlong' require 'tempfile' def die(message) $stderr.puts("#{$0}: #{message}") exit(1) end def execute(command) puts command system command end $options = { :output_format => :zip, :default_ignores => ['CVS', '\.svn', '.*\..*\.DS_Store'], :user_ignores => [], :output_file_name => 'out' } FORMATS = { 'zip' => { :archive_command => Proc.new do |dir_name| output_file = File.expand_path($options[:output_file_name]) containing_dir = File.dirname(dir_name) local_dir = File.basename(dir_name) execute("cd '#{containing_dir}' && " + "zip -r '#{output_file}' '#{local_dir}'") end }, 'bz2' => { :archive_command => Proc.new do |dir_name| output_file = File.expand_path($options[:output_file_name]) containing_dir = File.dirname(dir_name) local_dir = File.basename(dir_name) execute("cd '#{containing_dir}' && " + "tar -cjf '#{output_file}.tar.bz2' '#{local_dir}'") end }, 'gz' => { :archive_command => Proc.new do |dir_name| output_file = File.expand_path($options[:output_file_name]) containing_dir = File.dirname(dir_name) local_dir = File.basename(dir_name) execute("cd '#{containing_dir}' && " + "tar -czf '#{output_file}.tar.gz' '#{local_dir}'") end }, 'dmg' => { :archive_command => Proc.new do |dir_name| execute("hdiutil create -srcfolder '#{dir_name}' '#{$options[:output_file_name]}' -ov") end }, 'dmg-bz2' => { :archive_command => Proc.new do |dir_name| execute("hdiutil create -srcfolder '#{dir_name}' '#{$options[:output_file_name]}' -ov -format UDBZ") end } } def set_output_format(format) die("Unknown output format '#{format}'") unless FORMATS[format] $options[:output_format] = format.intern end def add_user_ignore(pattern) $options[:user_ignores] << pattern end def remove_default_ignores() $options[:default_ignores] = [] end def set_output_file_name(name) $options[:output_file_name] = name end OPTIONS = { '--output-format' => { :other_names => ['-f'], :flags => GetoptLong::REQUIRED_ARGUMENT, :behavior => Proc.new do |format| set_output_format(format) end }, '--ignore-regexp' => { :other_names => ['-I'], :flags => GetoptLong::REQUIRED_ARGUMENT, :behavior => Proc.new do |pattern| add_user_ignore(pattern) end }, '--no-default-ignores' => { :other_names => ['-n'], :flags => GetoptLong::NO_ARGUMENT, :behavior => Proc.new do remove_default_ignores() end }, '--output-file-name' => { :other_names => ['-o'], :flags => GetoptLong::REQUIRED_ARGUMENT, :behavior => Proc.new do |name| set_output_file_name(name) end } } def build_file_list(root) filters = ($options[:default_ignores] + $options[:user_ignores]).collect do |pattern| Regexp.compile(pattern) end file_list = [] Find.find(root) do |path| next if File.directory?(path) ok = true filters.each do |filter| if filter =~ path then ok = false break end end if ok then file_list << path end end file_list end def make_archive(archive_dir) FORMATS[$options[:output_format].to_s][:archive_command].call(archive_dir) end def run(paths) substitutions = [] file_list = paths.collect do |path| path = File.expand_path(path) substitutions << "|#{path}|#{File.basename(path)}|" build_file_list(path) end.flatten die('No input files') unless file_list.size > 0 pristine_directory = Tempfile.new('pristine-directory') File.unlink(pristine_directory.path) Dir.mkdir(pristine_directory.path) dir_name = "#{pristine_directory.path}/#{File.basename($options[:output_file_name])}" Dir.mkdir(dir_name) pax_command = "pax -r -w -s '#{substitutions.join("' -s '")}' '#{dir_name}'" puts pax_command IO.popen(pax_command, 'w') do |pipe| pipe.puts(file_list.join("\n")) end make_archive(dir_name) execute("rm -rf '#{pristine_directory.path}'") end def main() getoptlong_format = OPTIONS.keys.collect do |option_name| option_hash = OPTIONS[option_name] [option_name, option_hash[:other_names], option_hash[:flags]].flatten end options = GetoptLong.new(*getoptlong_format) begin options.each do |option, argument| OPTIONS[option][:behavior].call(argument) end run(ARGV) rescue => error die(error) end end main() p $options