require 'fileutils' require 'reap/extensions' require 'facets/ziputils' require 'facets/net/smtp_tls' module Reap # = Utilities # # Gerenal methods useful to project and tools. module Utilities #attr_accessor :dryrun #attr_accessor :trace #attr_accessor :force #attr_accessor :verbose #def dryrun? ; @dryrun ; end #def trace? ; @trace ; end #def force? ; @force ; end #def verbose? ; @verbose ; end # Helper method for cleaning list options. # This will split the option on ':' or ';' # if it is a string, rather than an array. # And it will make sure there are no nil elements. def list_option(option) option = option.to_s.split(/[:;,]/) unless Array===option [option].compact.flatten end # Internal status report. # Only output if dryrun or trace mode. def status(message) if dryrun? or trace? puts message end end # Shell runner. def sh(cmd) if dryrun? puts cmd true else puts "--> system call: #{cmd}" if trace? system(cmd) end end # Convenient method to get simple console reply. def ask(question, answers=nil) print "#{question}" print " [#{answers}] " if answers until inp = $stdin.gets ; sleep 1 ; end inp.strip end # Ask for a password. (FIXME: only for unix so far) def password(prompt=nil) msg ||= "Enter Password: " inp = '' print "#{prompt} " begin #system "stty -echo" #inp = gets.chomp until inp = $stdin.gets sleep 1 end ensure #system "stty echo" end return inp.chomp end # Delegate access to FileUtils. def fileutils dryrun? ? ::FileUtils::DryRun : ::FileUtils end # Add FileUtils Features ::FileUtils.private_instance_methods(false).each do |meth| next if meth =~ /^fu_/ module_eval %{ def #{meth}(*a,&b) fileutils.#{meth}(*a,&b) end } end # Add FileTest Features ::FileTest.private_instance_methods(false).each do |meth| next if meth =~ /^fu_/ module_eval %{ def #{meth}(*a,&b) FileTest.#{meth}(*a,&b) end } end # Specific. def rm_r(*a) if dryrun? puts "rm_r #{a.join(' ')}" else fileutils.rm_r(*a) end end # Bonus FileUtils features. def cd(*a,&b) puts "cd #{a}" if dryrun? or trace? fileutils.chdir(*a,&b) end # Read file. def read(path) File.read(path) end # Write file. def write(path, text) if dryrun? puts "write #{path}" else File.open(path, 'w'){ |f| f << text } end end # Assert that a path exists. def exists?(path) paths = Dir.glob(path) paths.not_empty? end alias_method :exist?, :exists? ; module_function :exist? alias_method :path?, :exists? ; module_function :path? # Assert that a path exists. def exists!(*paths) abort "path not found #{path}" unless paths.any?{|path| exists?(path)} end alias_method :exist!, :exists! ; module_function :exist! alias_method :path!, :exists! ; module_function :path! # Is a given path a regular file? If +path+ is a glob # then checks to see if all matches are refular files. def file?(path) paths = Dir.glob(path) paths.not_empty? && paths.all?{ |f| FileTest.file?(f) } end # Assert that a given path is a file. def file!(*paths) abort "file not found #{path}" unless paths.any?{|path| file?(path)} end # Is a given path a directory? If +path+ is a glob # checks to see if all matches are directories. def dir?(path) paths = Dir.glob(path) paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) } end alias_method :directory?, :dir? ; module_function :directory? # Assert that a given path is a directory. def dir!(*paths) paths.each do |path| abort "Directory not found: '#{path}'." unless dir?(path) end end alias_method :directory!, :dir! ; module_function :directory! # Return a cached list of the PATH environment variable. # This is a support method used by #bin? def command_paths @command_paths ||= ENV['PATH'].split(/[:;]/) end # Is a file a command executable? # # TODO: Make more robust. Probably needs to be fixed for Windows. def bin?(fname) #@command_paths ||= ENV['PATH'].split(/[:;]/) is_bin = command_paths.any? do |f| FileTest.exist?(File.join(f, fname)) end #is_bin ? File.basename(fname) : false is_bin ? fname : false end # Is a path considered reasonably "safe"? # # TODO: Make more robust. def safe?(path) case path when *[ '/', '/*', '/**/*' ] return false end true end # Does a path need updating, based on given +sources+? # This compares mtimes of give paths. Returns false # if the path needs to be updated. 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 # Glob files. def glob(*args, &blk) Dir.glob(*args, &blk) end def multiglob(*args, &blk) Dir.multiglob(*args, &blk) end def multiglob_r(*args, &blk) Dir.multiglob_r(*args, &blk) end # Stage package by hard linking included files to a stage directory. # Stage files in a directory. # # stage_directory Stage directory. # files Files to link to stage. def stage(stage_directory, files) return stage_directory if dryrun? # Don't link to stage if dryrun. if File.directory?(stage_directory) # Ensure existance of staging area. #raise(???Error, stage_directory) unless force? rm_r(stage_directory) end mkdir_p(stage_directory) #dir = File.expand_path(stage) #files = package.filelist #+ [package.manifest_file] # TODO Dryrun test here or before folder creation? files.each do |f| # Link files into staging area. file = File.join(stage_directory, f) if File.directory?(f) mkdir_p(file) else unless File.exist?(file) and File.mtime(file) >= File.mtime(f) ln(f, file) #safe_ln ? end end end # stage manifest ? return stage_directory end # Create manifest for a directory. def stage_manifest(directory) cd(directory) do #sh 'manifest up' files = Dir['**/*'] File.open('MANIFEST', 'w'){|f| f << file.join("\n") } end end # Delegate access to ZipUtils. def ziputils dryrun? ? ::ZipUtils::DryRun : ::ZipUtils end # def compress(format, folder, file=nil, options={}) case format.to_s.downcase when 'zip' ziputils.zip(folder, file, options) when 'tgz' ziputils.tgz(folder, file, options) when 'tbz', 'bzip' ziputils.tar_bzip(folder, file, options) else raise ArguementError, "unsupported compression format -- #{format}" end end =begin # Zip folder into file. def zip(folder, file=nil, options={}) ziputils.zip(folder, file, options) end # BZip and tarball folder into file. def tar_bzip(folder, file=nil, options={}) ziputils.tar_bzip(folder, file, options) end # GZip and tarball folder into file. Shortcut for ziputils.tgz. def tgz(folder, file=nil, options={}) ziputils.tgz(folder, file, options) end =end def email(message, options) Emailer.new(options).email(message) end end end