For one of my recent projects, I’ve decided to try new style of coding: writing code directly on my machine as I usually do, but this time run all unit tests and code itself within project dedicated VM managed by Vagrant.
Overall, it works really well and allows to manage project dependencies
efficiently, without cluttering your system. Biggest challange for this type of
setups is how to quickly share the code between host system and the VM. I’ve
seen many different solutions to this problem - starting from
git ending with the simplest one - shared folders. I believe that
simple solutions, are the best solutions, so this is how it’s setup on my box.
After hours spent on setting up initial project and its dependencies (looking at you FreeTDS…), the time has come to write some specs.
When developing on my local machine, I run my specs automatically through Guard which monitors selected project files for changes and runs respective tests if something has changed.
I was really confused when I wrote the first test and nothing has happened. I’ve triple checked if paths are correct but it all looked good. Forcing tests to be run manually worked without problem.
After investigating this further, I found out that Virtualbox does not forward low-level filesystem notifications to shared folders and that’s a reason why changes are not being detected.
There are at least two possible solutions in this scenario:
Solution 1: Use Polling
This feature simply checks if there are any changes in regular periods of time by asking for modification timestamps. As you can imagine, this works for relatively small projects, but can be CPU intensive if you have lots of files.
To use this feature, start Guard as follows
If you find that your CPU usage goes through roof, increase polling interval by
-l option. For example, to poll every 10 seconds:
guard -p -l 10
Solution 2: Forward host filesystem change events through TCP
This solution is much more efficient, as the guard is being notified about all the changes that occur on host filesystem rather then actively looking for them. The downside is that it requires additional configuration but in my opinion it’s worth it. This is how to set it up:
On the host system
Forward TCP port to the guest machine, so the
listendaemon can send the events to the guest VM. If you are using Vagrant, the example
Vagrantfileentry would be as follows:
config.vm.network :forwarded_port, guest: 4000, host: 4000
gem install listen thor celluloid-io
Restart your guest VM so that port forward takes effect.
Now, every time you work on this project you will have to start monitoring with those two simple steps:
On the host system, run:
listen -f 127.0.0.1:4000
On the guest VM, run:
bundle exec guard -o '10.0.2.2:4000' -w '/Users/marek/devel/project'
Remember to replace
10.2.2.2 with IP address of your host machine on the
vboxnetX interface and
/Users/marek/devel/project with actual path to the
project on your host system.
From now on, your specs should start only when you make a change and CPU usage should be reasonable.