lib/proutils/mint/copier.rb in proutils-0.3.0 vs lib/proutils/mint/copier.rb in proutils-0.3.1

- old
+ new

@@ -15,168 +15,172 @@ require 'proutils/mint/fileutils' module Mint -# def self.lookup(type) -# globs = [] -# paths.each do |path| -# parts = type.split(/[\/\\]/) -# if File.basename(path) == parts.first -# globs << File.join(File.dirname(path), type) -# end -# end -# globs.collect{ |g| Dir.glob(g) }.flatten -# end - def self.paths - @paths ||= ( - builtin = Dir.glob(File.join(datadir, '*')) - paths = ENV['MINT_PATH'].to_s.split(/[:;]/) + builtin - paths.inject({}) do |hash, path| - dir, type = *File.split(path) - hash[type] = dir - hash - end - ) + (ENV['MINT_PATH'] || []) + [datadir] end # TODO Better way to support RubyGems and Rolls? def self.datadir - dir = File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'data', 'mint') + dir = File.expand_path("#{File.dirname(__FILE__)}/../../../data/mint") if File.directory?(dir) dir else File.join(File.join(Config::CONFIG['datadir'], 'mint')) end end - # = Mint Copier + # Mint Copier provides a factility for + # performing interactive, managed copies. class Copier - IGNORE = [ '.', '..', '.svn'] + #IGNORE = [ '.', '..', '.svn'] - attr_reader :sources, :destination, :options + # Look for source file(s) in system locations? - attr_reader :actions + attr_accessor :system - def initialize(sources, destination, options=nil) - @sources = [sources].flatten - @destination = destination - @options = options || {} + # Source paths to copy. This can be a glob or an array of globs. - @special = options[:special] + attr_accessor :source - @dryrun = options[:dryrun] - @force = options[:force] - @skip = options[:skip] + # Directory (or a file, if copying one file) in which to store copied source. - if special? - @sources = special_lookup(*sources) - else - @sources = general_lookup(*sources) - end + attr_accessor :destination + # Just pretend to do the commit action. + + attr_accessor :dryrun + + # Force provided an extra "dangerous" option of "(W)rite all". + + attr_accessor :force + + # Automatically skip all overwrites. + + attr_accessor :skip + + # Stores actions to be performed upon commit. + + attr_reader :actions + + # New copier. + + def initialize(source, destination, options=nil) + @source = [source].flatten + @destination = destination + @actions = [] + + options.each do |k,v| + send("#{k}=",v) + end end - def special? ; @special; end - def dryrun? ; @dryrun ; end - def force? ; @force ; end - def skip? ; @skip ; end + def system? ; @system ; end - # Lookup in special mint locations. + def dryrun? ; @dryrun ; end + def force? ; @force ; end + def skip? ; @skip ; end - def special_lookup(*sources) - # First lets make sure there are not bad requests. - missing = requested_locations(*sources) - Mint.paths.keys - unless missing.empty? - puts "Missing special sources -- #{missing.join(', ')}" - exit 0 + # Files to copy. + + def copies + if system? + system_lookup + else + common_lookup end - # - sources.collect do |source| - type = *source.split(/[\/\\]/).first - [Mint.paths[type], source] - end end - # + # Look up file in system locations. - def requested_locations(*sources) - sources.collect do |source| - source.split(/[\/\\]/).first + def system_lookup + copies = [] + Mint.paths.each do |path| + source.each do |src| + jpath = File.join(path, src) + files = Dir.glob(jpath) + files.each do |file| + file = file.sub(path+'/','') + copies << [path, file] + end + end end + copies end - # + # Non-system lookup. - def general_lookup(*sources) - sources.collect do |source| - [ '.', source ] + def common_lookup + copies = [] + source.each do |src| + files = Dir.glob(File.join(path, src)) + unless files.empty? + copies << [nil, files] + end end + copies end # Copy files. def copy - puts "KEY: (d)iff (r)eplace (s)kip skip(a)ll (q)uit" - sources.each do |dir, file| - path = File.join(dir, file) + puts "KEY: (d)iff (r)eplace (s)kip (a)ll (q)uit" + copies.each do |dir, file| + path = dir ? File.join(dir, file) : file if File.file?(path) copy_file(dir, file) - else - dirs, files = *partition_path(path) + elsif File.directory?(path) + dirs, files = *partition(path) # make empty directories dirs.each do |d| - if File.directory?(d) + if File.directory?(File.join(destination,d)) skip_dir(d) else pth = File.join(path,d) entries = Dir.entries(pth) - IGNORE - make_dir(d) if entries.empty? + make_dir(path, d) if entries.empty? end end # copy files in directories files.each do |f| copy_file(path, f) end + else + raise ArgumentError, "unsupported file object -- #{path}" end end commit end private - # List of source files. + # Partition a directory's content between dirs and files. - #def source_paths - # Dir.glob(File.join(@source, '**/*')) - #end - - # Partition a path's contents between dirs and files. - - def partition_path(path) + def partition(directory) dirs, files = [], [] - chdir(path) do + chdir(directory) do paths = Dir.glob('**/*') dirs, files = *paths.partition do |f| File.directory?(f) end end return dirs, files end # Make a directory. - def make_dir(dir) + def make_dir(source, dir) dst = File.join(destination, dir) if File.file?(dst) puts "Directory to replace file..." - action = query(file) || 'skip' + action = query(source, dir) || 'skip' else action = 'make' end @actions << [action, dst] action_print(action, dst + '/') @@ -185,19 +189,17 @@ # Copy a file. def copy_file(source, file) src = File.join(source, file) dst = File.join(destination, file) - action = 'skip' - if File.directory?(dst) puts "File to replace directory..." - action = query(file) + action = query(source, file) elsif File.file?(dst) unless FileTest.identical?(src, dst) - action = query(file) + action = query(source, file) end else action = 'copy' end @@ -217,38 +219,40 @@ @actions << ['skip', dst] action_print('skip', dst + '/') end # Skip file. + # + # TODO: Why is this never called? def skip_file(src, dst) @actions << ['skip', [src, dst]] action_print('skip', dst) end # Show diff of files. - def diff(file) + def diff(source, file) src = File.join(source, file) dst = File.join(destination, file) diff = FileTest.diff(src, dst) puts diff unless diff.empty? end # Query about file. - def query(file) + def query(source, file) return 's' if @safe return 'o' if @force action = nil #msg = "#{file} -- (d)iff (r)eplace (s)kip (a)ll (q)uit?" msg = " ? #{file} " until action ans = ask(msg).strip[0,1] case ans when 'd', 'D' - diff(file) + diff(source, file) when 'r', 'R' action = 'replace' when 's', 'S' action = 'skip' when 'a', 'A' @@ -259,38 +263,25 @@ end end return action end - # Get user input + # Action print. - def ask(msg) - print "#{msg} " - until inp = $stdin.gets ; sleep 1 ; end - inp.chomp - end - - # Action print def action_print(action, file) file = file.sub(/^[.]\//,'') action = (' ' * (8 - action.size)) + action puts "#{action} #{file}" end - def commit - ans = ask("Commit y/N?") - case ans.downcase - when 'y', 'yes' - commit! - end - end + # Perform actions. def commit! - @actions.each do |action, path| + actions.each do |action, path| case action when 'make' - rm(path) unless File.directory?(path) + #rm(path) if File.directory?(path) mkdir_p(path) when 'copy' src, dst = *path rm_r(dst) if File.directory?(dst) mkdir_p(File.dirname(dst)) @@ -299,17 +290,35 @@ src, dst = *path rm_r(dst) if File.directory?(dst) #mkdir_p(File.dirname(dst)) cp(src, dst) else # skip - # + # do nothing end end end - # Delegate to fileutils. + # Confirm commit. + def commit + ans = ask("Commit y/N?") + case ans.downcase + when 'y', 'yes' + commit! + end + end + + # Get user input. + + def ask(msg) + print "#{msg} " + until inp = $stdin.gets ; sleep 1 ; end + inp.chomp + end + + # Delegation to FileUtils. + def fu @dryrun ? FileUtils::DryRun : FileUtils end def chdir(*a,&b) ; fu.chdir(*a,&b) ; end @@ -319,6 +328,7 @@ def cp_r(*a,&b) ; fu.cp_r(*a,&b) ; end def mkdir(*a,&b) ; fu.mkdir(*a,&b) ; end def mkdir_p(*a,&b) ; fu.mkdir_p(*a,&b) ; end end + end