Skip to content

Instantly share code, notes, and snippets.

@boof
Last active August 29, 2015 14:09
Show Gist options
  • Save boof/1e670391787744d4ed3b to your computer and use it in GitHub Desktop.
Save boof/1e670391787744d4ed3b to your computer and use it in GitHub Desktop.
Sync back files from a vagrant guest (rsync shared folders).
#!/usr/bin/env ruby
# Usage: bin/rsync-back [--dry-run] [pattern ...]
require 'fileutils'
require 'tmpdir'
options = {
user: 'vagrant',
host: 'localhost',
directory: '/vagrant/',
args: %w[
--archive --keep-dirlinks --links
--chmod=ugo=rwX --no-perms --no-owner --no-group
],
# add this file to your excludes list
exclude_from: 'rsync.excludes',
transport: 'rsync',
ssh: {
port: 2222,
key_file: "#{ ENV['HOME'] }/.vagrant.d/insecure_private_key",
options: %w[
StrictHostKeyChecking=no
UserKnownHostsFile=/dev/null
]
},
rsync: {
port: 8873
}
}
root = File.expand_path '..', __FILE__
root = File.dirname root until File.directory? "#{ root }/.git" or root == '/'
abort if root == '/'
ROOT = root
options[:exclude_from] = File.expand_path options[:exclude_from], ROOT
def sync(src, dest, opts)
args = opts[:args] + [%Q'--exclude-from="#{ opts[:exclude_from] }"']
cmd = format 'rsync %s %s %s', args * ' ', src, dest
puts ">> #{ cmd }"
system cmd
end
def uri(options, scheme = '', port = '')
format '%s%s@%s:%s%s', scheme, options[:user], options[:host],
port, options[:directory]
end
def sync_over_rsync(destination, options)
src = uri(options, 'rsync://', options[:rsync][:port])
sync src, destination, options
end
def sync_over_ssh(destination, options)
ssh_config = options[:ssh]
ssh_args = ssh_config[:options].map { |o| "-o #{ o }" }
ssh_args << format('-p %i', ssh_config[:port])
ssh_args << format(%q"-i '%s'", ssh_config[:key_file])
options[:args] << format('--rsh="ssh %s"', ssh_args * ' ')
sync uri(options), destination, options
end
def rsync(destination, options)
send "sync_over_#{ options[:transport] }", destination, options
end
Dir.mktmpdir do |tmp|
rsync(tmp, options) or abort
noop =! ARGV.reject! { |arg| arg == '--dry-run' }.nil?
puts 'Not doing anything, actually.' if noop
excludes = File.readlines(options[:exclude_from]).each(&:chomp!)
includes = ARGV.empty? ? %w[*] : ARGV
# system "diff --brief --recursive --exclude-from=#{ excludes_from } #{ tmp } #{ root }"
`git --work-tree #{ tmp } status --porcelain`.chomp.each_line do |line|
path = line[3..-1].chomp
if excludes.any? { |pattern| File.fnmatch pattern, path }
puts " E #{ path }"
next
end
unless includes.any? { |pattern| File.fnmatch pattern, path }
puts " I #{ path }"
next
end
source = "#{ tmp }/#{ path }"
destination = File.join root,
path !~ %r'/$' ? path : [ File.dirname(path), '' ]
case line
when /^(?: M) / # file modified
FileUtils.cp_r source, destination, noop: noop
puts line
when /^(?: A|\?\?) / # file added
FileUtils.cp_r source, destination, noop: noop
puts line
when /^(?: D) / # file deleted
FileUtils.rm_r destination, noop: true, verbose: true
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment