Skip to content

Instantly share code, notes, and snippets.

@lox
Created April 20, 2012 05:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lox/2426455 to your computer and use it in GitHub Desktop.
Save lox/2426455 to your computer and use it in GitHub Desktop.
Watch a local folder and synchronize it with a remote folder over SCP
#!/usr/bin/env ruby
require 'rubygems'
require 'rb-fsevent'
require 'optparse'
require 'net/ssh'
require 'net/sftp'
def watch_directory(sftp, watch_dir, target_dir)
fsevent = FSEvent.new
fsevent.watch [watch_dir] do |directories|
directories.each do |dir|
unless dir.include? ".git"
sync_directory sftp, dir, dir.gsub(watch_dir, target_dir)
end
end
end
fsevent.run
end
def sync_directory(sftp, local_dir, remote_dir)
remote_files = {}
# collect remote mtimes
sftp.dir.foreach remote_dir do |f|
remote_files[f.name] = f.attributes.mtime
end
# check local mtimes
Dir.foreach(local_dir) do |local_file|
f = "#{local_dir}#{local_file}"
if File.file?(f) and (!remote_files.key? local_file or remote_files[local_file] < File.mtime(f).to_i)
print "#{f} changed, sending... "
timer = Time.now
begin
sftp.upload! f, "#{remote_dir}#{local_file}"
puts " done in #{(Time.now - timer)*1000}ms"
rescue Exception => e
puts " failed! #{e.message}"
end
end
end
end
options = { :verbose=>false, :git=>false }
OptionParser.new do |opts|
opts.banner = "Usage: watch.rb user@host:path [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
opts.on("-g", "--git", "Sync the remote side to the current git HEAD") do |g|
options[:git] = g
end
end.parse!
remote_user = ARGV[0].split('@').first
remote_host = ARGV[0].split('@').last.split(':').first
watch_dir = File.expand_path(ARGV[0].split('@').last.split(':').last)
remote_dir = "/home/#{remote_user}/"+File.basename(watch_dir)
Net::SSH.start(remote_host, remote_user) do |session|
if options[:git]
branch = `cd #{watch_dir}; git name-rev --name-only HEAD`.chomp
sha1 = `cd #{watch_dir}; git rev-parse HEAD`.chomp
puts "Cleaning remote repo"
session.exec! "git clean -d #{remote_dir}"
puts "Synchronizing remote to #{branch}@#{sha1}"
["git fetch", "git checkout #{branch}", "git reset --hard #{sha1}", "git submodule update --init"].each do |c|
session.exec! "cd #{remote_dir}; #{c}"
end
puts "Sending changed files from local repo"
puts `cd #{watch_dir}; git status -s -u --ignore-submodules`.chomp
end
puts "Listening for changes in #{watch_dir}"
watch_directory session.sftp, watch_dir, remote_dir
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment