Local Development with Ariadne
I recently started a new development position with Blink Reaction so I needed to get somewhat serious about setting up a local Drupal development environment.
Ariadne
I was leaning towards making use of Vagrant for managing local development environments so I can easily switch between different projects or branches. I also believe Vagrant makes it easier to have as close a mirror to production locally as possible.
I discovered a very interesting project from MyPlanet Digital named vagrant-ariadne. Ariadne is a customized implementation of Vagrant and allows for easy deployment of Drupal installation profiles to a local VM. Another nice feature is that it attempts to emulate Acquia’s infrastructure. This is useful as a lot of Blink’s clients are deployed on the Acquia Cloud.
Assuming you have Vagrant, rvm and a ruby environment installed on your workstation, installing Ariadne is pretty straightforward:
<span class="go">j</span><span class="go">vagrant gem install vagrant-vbguest vagrant-hostmaster vagrant-librarian</span><span class="go">[sudo] gem install librarian rake knife-solo</span><span class="go">git clone https://github.com/myplanetdigital/vagrant-ariadne.git</span><span class="go">cd vagrant-ariadne</span><span class="go">bundle install</span><span class="go">bundle exec rake setup</span>
Everything is now configured to boot a virtual box. Ariadne comes with a simple example that can be deployed:
<span class="go">j</span><span class="go">project=example vagrant up</span>
Once that command finishes running, the site can be viewed at http://example.dev/
(Ariadne uses vagrant-hostmaster for managing /etc/hosts
entries).
A more involved cookbook is a cookbook for deploying the Web Experience Toolkit available on github also. If we wanted to deploy the master branch of this site, we could do:
bundle exec rake "init_project[https://github.com/wet-boew/ariadne-wet-boew-drupal]"project=wet-boew-drupal branch=master vagrant up
And that’s it!
Another nice feature of these deployed environments is that they are configured to allow remote debugging (relevant when setting up an IDE as mentioned later) and the actual site code is shared as an NFS mount. For example, the contents of my /etc/exports
file after booting a box with Ariadne looks like:
<span class="gp">#</span> VAGRANT-BEGIN: 7ac1cf50-4498-4e49-bd66-edac4a9b2d7e<span class="go">"/Users/posullivan/vagrant-ariadne/tmp/apt/cache" 33.33.33.10 -mapall=501:20</span><span class="go">"/Users/posullivan/vagrant-ariadne/tmp/drush/cache" 33.33.33.10 -mapall=501:20</span><span class="go">"/Users/posullivan/vagrant-ariadne/data/html" 33.33.33.10 -mapall=501:20</span><span class="gp">#</span> VAGRANT-END: 7ac1cf50-4498-4e49-bd66-edac4a9b2d7e
Thus, if I navigate to the ~/vagrant-ariadne/data/html
directory or import that in my IDE, I can edit the code deployed on the vagrant box.
Drupal Core from git
Another use I’ve found for ariadne is building a local environment for the latest drupal core. To accomplish this, I created a role file named roles/core.rb
with the following contents:
<span class="nb">name</span> <span class="s2">"core"</span><span class="n">description</span> <span class="s2">"Install requirements to run Drupal core."</span><span class="n">run_list</span><span class="p">(</span><span class="o">[</span> <span class="s2">"recipe[mysql::server]"</span><span class="p">,</span> <span class="s2">"recipe[mysql::client]"</span><span class="p">,</span> <span class="s2">"recipe[php::module_mysql]"</span><span class="p">,</span> <span class="s2">"recipe[php::module_curl]"</span><span class="p">,</span> <span class="s2">"recipe[php::module_gd]"</span><span class="p">,</span> <span class="s2">"recipe[php::module_apc]"</span><span class="p">,</span> <span class="s2">"recipe[drush::utils]"</span><span class="p">,</span> <span class="s2">"recipe[drush::make]"</span><span class="p">,</span> <span class="s2">"recipe[php::write_inis]"</span><span class="p">,</span><span class="o">]</span><span class="p">)</span><span class="n">default_attributes</span><span class="p">({</span> <span class="ss">:drush</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:version</span> <span class="o">=></span> <span class="s2">"5.8.0"</span><span class="p">,</span> <span class="p">},</span> <span class="ss">:mysql</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:server_debian_password</span> <span class="o">=></span> <span class="s2">"root"</span><span class="p">,</span> <span class="ss">:server_root_password</span> <span class="o">=></span> <span class="s2">"root"</span><span class="p">,</span> <span class="ss">:server_repl_password</span> <span class="o">=></span> <span class="s2">"root"</span><span class="p">,</span> <span class="ss">:bind_address</span> <span class="o">=></span> <span class="s2">"127.0.0.1"</span><span class="p">,</span> <span class="ss">:tunable</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:key_buffer</span> <span class="o">=></span> <span class="s2">"384M"</span><span class="p">,</span> <span class="ss">:table_cache</span> <span class="o">=></span> <span class="s2">"4096"</span><span class="p">,</span> <span class="p">},</span> <span class="p">},</span><span class="p">})</span>
j
Next, I created a new cookbook project named core
and created a simple default.rb
recipe for this cookbook. This recipe looks like:
<span class="n">branch</span> <span class="o">=</span> <span class="n">node</span><span class="o">[</span><span class="s1">'ariadne'</span><span class="o">][</span><span class="s1">'branch'</span><span class="o">]</span><span class="n">git</span> <span class="s2">"/mnt/www/html/drupal"</span> <span class="k">do</span> <span class="n">user</span> <span class="s2">"vagrant"</span> <span class="n">repository</span> <span class="s2">"http://git.drupal.org/project/drupal.git"</span> <span class="n">reference</span> <span class="n">branch</span> <span class="n">enable_submodules</span> <span class="kp">true</span> <span class="n">action</span> <span class="ss">:sync</span> <span class="n">notifies</span> <span class="ss">:run</span><span class="p">,</span> <span class="s2">"bash[Installing Drupal...]"</span><span class="p">,</span> <span class="ss">:immediately</span><span class="k">end</span><span class="n">bash</span> <span class="s2">"Installing Drupal..."</span> <span class="k">do</span> <span class="n">user</span> <span class="s2">"vagrant"</span> <span class="n">group</span> <span class="s2">"vagrant"</span> <span class="n">code</span> <span class="o"><<-</span><span class="no">EOH</span><span class="sh"> drush -y si \</span><span class="sh"> --root=/mnt/www/html/drupal \</span><span class="sh"> --db-url=mysqli://root:root@localhost/drupal \</span><span class="sh"> --site-name="Drupal Core Installed from Git" \</span><span class="sh"> --site-mail=vagrant+site@localhost \</span><span class="sh"> --account-mail=vagrant+admin@locahost \</span><span class="sh"> --account-name=admin \</span><span class="sh"> --account-pass=admin</span><span class="no"> EOH</span><span class="k">end</span><span class="n">site</span> <span class="o">=</span> <span class="n">node</span><span class="o">[</span><span class="s1">'ariadne'</span><span class="o">][</span><span class="s1">'host_name'</span><span class="o">].</span><span class="n">nil?</span> <span class="p">?</span> <span class="s2">"</span><span class="si">#{</span><span class="n">node</span><span class="o">[</span><span class="s1">'ariadne'</span><span class="o">][</span><span class="s1">'project'</span><span class="o">]</span><span class="si">}</span><span class="s2">.dev"</span> <span class="p">:</span> <span class="n">node</span><span class="o">[</span><span class="s1">'ariadne'</span><span class="o">][</span><span class="s1">'host_name'</span><span class="o">]</span><span class="n">web_app</span> <span class="n">site</span> <span class="k">do</span> <span class="n">cookbook</span> <span class="s2">"ariadne"</span> <span class="n">template</span> <span class="s2">"drupal-site.conf.erb"</span> <span class="n">port</span> <span class="n">node</span><span class="o">[</span><span class="s1">'apache'</span><span class="o">][</span><span class="s1">'listen_ports'</span><span class="o">].</span><span class="n">to_a</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="n">server_name</span> <span class="n">site</span> <span class="n">server_aliases</span> <span class="o">[</span> <span class="s2">"www.</span><span class="si">#{</span><span class="n">site</span><span class="si">}</span><span class="s2">"</span> <span class="o">]</span> <span class="n">docroot</span> <span class="s2">"/mnt/www/html/drupal"</span> <span class="n">notifies</span> <span class="ss">:reload</span><span class="p">,</span> <span class="s2">"service[apache2]"</span><span class="k">end</span>
With all of the above in place, its quite simple to create a local VM based on the latest in the 7.x
branch of drupal core:
<span class="nv">project</span><span class="o">=</span>core <span class="nv">branch</span><span class="o">=</span>7.x vagrant up
The above command simply needs to have the branch name modified to deploy a different branch. Once the above command completes, a site will be available at core.dev
and I can log in as the admin
user using the credentials specified in my cookbook.
Private Repositories
Most repositories for client projects are stored in private repositories. Thankfully, thats not an issue with ariadne. Ariadne uses agent forwarding to forward the host machine’s ssh session into the VM, including keys and passphrases stored by ssh-agent. What this means is that your VM will have the same Git/SSH access that you enjoy on your local machine. I’ve not had a problem checking out code stored in private repositories on bitbucket for example.
IDE
For an IDE, I’ve been an Eclipse user in the past for Java projects I’ve worked on so Aptana seemed like a good fit for my needs at the moment. A few existing articles already exist on configuring Aptana for Drupal development so I’m not going to go into too much details here.
Installation is very straightforward with the binary downloaded from the site. A ruble exists for Drupal so its pretty natural to install that:
<span class="go">git clone git://github.com/arcaneadam/Drupal-Bundle-for-Aptana.git ~/Documents/Aptana Rubles/Drupal-Bundle-for-Aptana</span>
Next item is to configure Aptana to adhere to the Drupal coding standards. I used an existing profile for Aptana that could be imported for this.
The final thing I needed to configure was a debug configuration. To do this, I created a new PHP web page configuration. First, a new PHP server needs to be added. In this example, lets assume I am using the example box I mentioned in the Ariadne section whose hostname is example.dev
. The web server configuration dialog when configured with this hostname and appropriate directory for the site root looks like:
Once a PHP server has been added, the rest of the information to fill in for the debug configuration is pretty straightforward as shown below:
I like to select the break at first line option to make sure the debug configuration works correctly.
With this in place, any visit to example.dev
will result in the breakpoint being hit.
Conclusion
I’ve still not settled on this combination for my development environment but I was definitely pretty excited upon discovering the Ariadne project. The drawbacks that I see to using Ariadne are: 1) the need to create a cookbook for each project you want to work with, 2) the project is still in beta stage so documentation is fairly lacking (fair enough for a beta project though), and 3) if you are not familiar with chef, using Ariadne may prove challenging (although it provides the perfect excuse to become familiar with chef).
PHPStorm is the IDE that seems to be pretty popular when I ask what other people are using for an editor but given there is a license fee associated with it, I didn’t want to splurge on that just yet. Aptana looks to work just fine for me and satisfies my needs nicely.