How to Copy Folders Recursively With Ruby

July 28, 2009

Ruby, out of the box, provides many useful classes for working with files and directories. Most of these handy-dandy methods can be found on the FileUtils class. Ruby even makes it easy to copy directories recursively. Since recursive directory copying is the topic of the day, I thought I’d burn a few lines talking about just that. The FileUtils.cp_r method is a fine way to copy directories recursively. It works exactly as advertised.

The FileUtils class, IMHO, has a missing a method. It’s a method very similar in behavior to cp_r, that accepts a list of files to ignore/exclude recursively. If for some wacky reason you also have a need for this behavior, then you’re in luck.

Below you’ll find a tiny script that allows you to do just that. You can initialize the object with an array of files or patterns to exclude, then invoke the solitary copy method. That’s all there is to it. The script will recursively copy the source directory to the destination directory and compare each file against your exclude list.

require 'FileUtils'

class DaCopier

  def initialize(exclude)
    @exclude = exclude
  end

  def copy src, dest

    stage dest

    Dir.foreach(src) do |file|
      next if exclude?(file)

      s = File.join(src, file)
      d = File.join(dest, file)

      if File.directory?(s)
        FileUtils.mkdir(d)
        copy s, d
      else
        FileUtils.cp(s, d)
      end

      puts d

    end
  end

  private

  def stage dest
    if File.directory?(dest)
      FileUtils.rm_rf(dest)
    end

    FileUtils.mkdir(dest)
  end

  def exclude? file
    @exclude.each do |s|
      if file.match(/#{s}/i)
        return true
      end
    end
    false
  end
end

src = '/Users/Emilio/Dropbox'
dest = '/Users/Emilio/Dropbox 2'
exclude = ["^\\.", "_old", "cheese.jpg"]

dc = DaCopier.new(exclude)

dc.copy src, dest

DISCLAIMER: This script is not battle tested and you’ll probably want to run it through your own tests before using it in any production scenario.