Ryan Davis wrote:
> * Uses ssh with your ssh settings already in place.
> * Uses rsync for efficient transfers.

Since you're using the external ssh program, you might consider using 
the -S option in ssh. It lets you pay the setup cost (authentication, 
tcp connect) once per host, rather than once per ssh or rsync 
invocation. Makes a big difference with slow networks or many invocations.

In rakefiles, it lets you do the following:

   m = SSHMaster.for "some.host.net"
   m.rsync [file1, file2], some_dir_on_that_host
   m.rsync local_dir, remote_dir, "-az" # or other rsync options
   m.ssh some_cmd

Here's the implementation (needs hacking, I'm sure):

class SSHMaster
   def initialize sock, host
     @sock, @host = sock, host
   end

   def ssh cmd, &block
     sh "ssh", "-S", @sock, @host, cmd, &block
   end

   DEFAULT_RSYNC_OPTS = ["-Cavz", "--exclude='*.bck'", "--progress"]

   # dst may be "host:foo/bar" or just "foo/bar"
   def rsync src, dst, opts=DEFAULT_RSYNC_OPTS, *optsrest, &block
     src = [src] unless src.is_a?(Array)
     src = FileList[*src]
     opts = [opts] unless opts.is_a?(Array)
     host_dst = (dst =~ /\A#{@host}:/) ? dst : "#{@host}:#{dst}"
     sh "rsync", "--rsh=ssh -S #{@sock}",
        *((opts + optsrest + src + [host_dst]).flatten), &block
   end

   SOCKET_NAME = "ssh_master_for_%r@%h:%p"

   @master = {}

   def self.for host
     master = @master[host]
     unless master
       sock = File.join(ENV["TMPDIR"], SOCKET_NAME)
       cmd = "ssh -M -S #{sock} #{host} 'echo hello; read'"
       master_pipe = IO.popen(cmd, "r+")
       master_pipe.gets
       at_exit do
         master_pipe.close if master_pipe and not master_pipe.closed?
       end

       master = @master[host] = new(sock, host)
     end
     master

   rescue StandardError => ex
     $stderr.puts "Failed to ssh to #{host}: #{ex.message}"
     false
   end
end

-- 
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407