Skip to content

Instantly share code, notes, and snippets.

@neerolyte
Last active December 14, 2015 23:39
Show Gist options
  • Save neerolyte/5167044 to your computer and use it in GitHub Desktop.
Save neerolyte/5167044 to your computer and use it in GitHub Desktop.
First stab at getting guard to cleanly watch for inotify events outside of a Vagrant VM, send the event inside and report back on the outside again. See comments for more description.
require 'guard'
require 'guard/guard'
require 'guard/jasmine-node'
module ::Guard
class Guard
def vagrant_run_prefix()
prep_ssh_config
"ssh -F #{ssh_conf_file} default -- cd /vagrant\\;"
end
def stop()
clean_ssh_config
super
end
protected
# "vagrant ssh" is exceptionally slow, so we do some
# hackiness here to pull out the ssh_config from vagrant
# and translate it for use during our session
@tempdir = nil
def get_temp_dir()
if @tempdir.nil?
@tempdir = `mktemp -d /tmp/VagrantGuard.XXXXXX`
@tempdir.strip!
end
@tempdir
end
def get_ssh_config()
known_hosts_file = File.join(get_temp_dir, 'known_hosts')
conf = `vagrant ssh-config`
conf.gsub!(/^(\s*UserKnownHostsFile).*$/, "\\1 #{known_hosts_file}")
end
def ssh_conf_file()
File.join(get_temp_dir, 'ssh_config')
end
@ssh_prepped = false
def prep_ssh_config()
if ! @ssh_prepped
conf = get_ssh_config
File.open(ssh_conf_file, 'w') { |file|
file.write(conf)
}
@ssh_prepped = true
end
end
def clean_ssh_config()
if @ssh_prepped
@ssh_prepped = false
`rm -rf -- #{@tempdir}`
@tempdir = nil
end
end
end
# hack in to JasmineNode our ssh prefix
class VagrantJasmineNode < JasmineNode
def start()
DEFAULT_OPTIONS[:jasmine_node_bin] =
vagrant_run_prefix + 'node_modules/jasmine-node/bin/jasmine-node'
super
end
end
end
guard 'VagrantJasmineNode' do
watch(%r{^spec/(.+)\.spec\.js$}) { |m| "#{m[0]}" }
watch(%r{^lib/(.+)\.js$}) { |m| "spec/lib/#{m[1]}.spec.js" }
end
# vim: ft=ruby ts=2 sw=2 et
@neerolyte
Copy link
Author

What's happening:

  • Guard watches files on the parent host (so inotify "just works")
  • Guard is slightly modified to know how to SSH in to the Vagrant VM (at least slightly hacky - doesn't use "vagrant ssh" just because it's soooooooooooo slooooooooooooooooowwwww)
  • We overload calls in JasmineNode to run them over SSH (super hacky)
  • JasmineNode ends up parsing the output as per usual (so NotifySend "just works")

I think feasibly this could be turned in to a plugin given a bit more love, at the moment it can be run directly as a Guardfile (but has some limitations about the parent host for now - e.g. won't work on Windows in its current form). In current form I'd obviously need to overload every Guard test driver available - but maybe there's a more general pattern for overloading them?

This method is quite different from the normal approaches I've seen people trying, including NFS mounts (not portable, difficult to set up), forcing Guard to poll (CPU intensive) and redirecting notifications from within the VM over ssh with vagrant-notify ("oh my eyes, they burn they burn!").

Keen to know if anyone can do this better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment