require 'erb' module Bones::App class FileManager include Bones::Colors Error = Class.new(StandardError) attr_reader :destination attr_accessor :source, :archive, :verbose alias :verbose? :verbose # # def initialize( opts = {} ) self.source = opts[:source] self.destination = opts[:destination] self.verbose = opts[:verbose] @out = opts[:stdout] || $stdout @err = opts[:stderr] || $stderr end # Sets the destination where files will be copied to. At the same time an # archive directory is configured. This is simply the destination # directory with a '.archive' extension. # def destination=( str ) @destination = str @archive = str + '.archive' if str end # If the source is a repository this method returns the type of # repository. This will be :git for Git repositories and :svn for # Subversion repositories. Otherwise, +nil+ is returned. # def repository return :git if source =~ %r/\.git\/?$/i return :svn if source =~ %r/^(svn(\+ssh)?|https?|file):\/\//i nil end alias :repository? :repository # # def archive_destination return false unless test(?e, destination) archiving(destination) FileUtils.rm_rf(archive) FileUtils.mv(destination, archive) true end # # def copy if repository? _checkout(repository) else _files_to_copy.each {|fn| _cp(fn)} end self end # Gernate a new destination folder by copying files from the source, rename # files and directories that contain "NAME", and perform ERB templating on # ".bns" files. The _name_ use used for file/folder renaming and ERB # templating. # def template( name ) name = name.to_s return if name.empty? if repository? _checkout(repository) else _files_to_copy.each {|fn| _cp(fn, false)} end self.destination = _rename(destination, name) _erb(name) self end # # def _checkout( repotype ) case repotype when :git system('git', 'clone', source, destination) FileUtils.rm_rf(File.join(destination, '.git')) when :svn system('svn', 'export', source, destination) else raise Error, "Unknown repository type '#{repotype}'." end end # # def _rename( filename, name ) newname = filename.gsub(%r/NAME/, name) if filename != newname raise "cannot rename '#{filename}' to '#{newname}' - file already exists" if test(?e, newname) FileUtils.mv(filename, newname) end if test(?d, newname) Dir.glob(File.join(newname, '*')).each {|fn| _rename(fn, name)} end newname end # # def _erb( name ) binding = _erb_binding(name) Dir.glob(File.join(destination, '**', '*'), File::FNM_DOTMATCH).each do |fn| next unless test(?f, fn) if File.extname(fn) != '.bns' creating(fn) next end new_fn = fn.sub(%r/\.bns$/, '') creating(new_fn) txt = ERB.new(File.read(fn), nil, '-').result(binding) File.open(new_fn, 'w') {|fd| fd.write(txt)} FileUtils.chmod(File.stat(fn).mode, new_fn) FileUtils.rm_f(fn) end self end # # def _erb_binding( name ) obj = Object.new class << obj alias :__binding__ :binding instance_methods.each {|m| undef_method m unless m[%r/^(__|object_id)/]} def binding(name) classname = name.tr('-','_').split('_').map {|x| x.capitalize}.join __binding__ end end obj.binding name end # Returns a list of the files to copy from the source directory to # the destination directory. # def _files_to_copy rgxp = %r/\A#{source}\/?/ exclude = %r/tmp$|bak$|~$|CVS|\.svn/ ary = Dir.glob(File.join(source, '**', '*'), File::FNM_DOTMATCH).map do |filename| next if exclude =~ filename next if test(?d, filename) filename.sub rgxp, '' end ary.compact! ary.sort! ary end # Copy a file from the Bones prototype project location to the user # specified project location. A message will be displayed to the screen # indicating that the file is being created. # def _cp( file, msg = true ) dir = File.dirname(file) dir = (dir == '.' ? destination : File.join(destination, dir)) dst = File.join(dir, File.basename(file)) src = File.join(source, file) (test(?e, dst) ? updating(dst) : creating(dst)) if msg FileUtils.mkdir_p(dir) FileUtils.cp src, dst FileUtils.chmod(File.stat(src).mode, dst) end private def archiving( filename ) return unless verbose? @put.puts " #{colorize('archiving', :cyan)} #{filename}" end def creating( filename ) return unless verbose? @out.puts " #{colorize('creating', :green)} #{filename}" end def updating( filename ) return unless verbose? @out.puts " #{colorize('updating', :yellow)} #{filename}" end end # class FileManager end # module Bones::App # EOF