Skip to content

Instantly share code, notes, and snippets.

@lox
Created April 20, 2012 05:57
Show Gist options
  • Save lox/2426455 to your computer and use it in GitHub Desktop.
Save lox/2426455 to your computer and use it in GitHub Desktop.

Revisions

  1. lox created this gist Apr 20, 2012.
    87 changes: 87 additions & 0 deletions watch.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    #!/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