Doing something with computers!

Organizing a Drupal Project with Subversion

Organizing a Drupal Project with Subversion

A single Drupal project can be as simple or complicated as you need it to be; this is one of the great advantages of using Drupal. Until recently, I arranged my Drupal projects in the most straight-forward way -- I set up Drupal and imported the whole directory hierarchy into subversion. While this reduces the complexity of the project, it doesn't allow you to easily do things like upgrade Drupal Core when a new security release comes out. So, I spent some time trying to figure out the correct way to organize a project and came up with a solution that utilizes subversion's externals property. I'm not sure that this solution is the absolute best arrangement, but once it's all set up it makes project administration a breeze.

1. Drupal core and contributed modules

First, you're going to need more than just a repository for your project. You need a place to put Drupal core and all those modules that you'll use "out of the box". You probably also want to keep Drupal 5.x and Drupal 6.x core and modules separate. So, this part of my repository looks like this:


/drupal
-- /drupal-5.x
---- /core
------ /drupal-5.9
------ ... plus some older releases just for completeness
---- /modules
------ /adminmenu
-------- /adminmenu-5.x.1.0
-------- /adminmenu-5.x.2.0 (and whatever other versions you have on hand
------ ... all the other modules I keep around
---- /themes
------ /zen
-------- /zen-5.x.1.0
------ ... all the other themes I keep around
-- ... I then have a similar structure for Drupal 6.

Another similar arrangement is to have "core", "modules", and "themes" directories with "drupal-5" and "drupal-6" for each version. For example, your adminmenu folder would look like:


/drupal
-- /modules
---- /adminmenu
------ /drupal-5
-------- /adminmenu-5.x.1.0
------ /drupal-6
-------- /adminmenu-6.x.1.0

This way, all the module code is together regardless of what version of Drupal it is for. But, I still prefer the first arrangement.

2. Your custom development

The goal here is to have a similar arrangement to your "Drupal" repository specifically for the custom stuff you make. So you'll want to have separate "drupal-5" and "drupal-6" directories, each of which containing a "modules" and "themes" directory. So it would look something like this:


/custom
-- /drupal-5
---- /modules
------ /my_fancy_module
---- /themes
------ /my_fancy_theme
-- ... and a similar structure for drupal-6.

3. The project itself

I know this all seems like a lot of overhead, but this is where it all pays off. Your projects can now consist almost entirely of references to these other folders thanks to the "svn:externals" property. I prefer my project directory structure like so:


/projects
-- /my_project
---- /files
---- /db

The files directory will serve as Drupal's "files" directory, and I keep database dumps in the "db" directory. Neither of these are strictly necessary, it's just the way I like it. So, once you have a checkout of your project, you can edit the svn:externals properties to create references to your projects.

There are many ways to do this depending on what tools you use. I use Eclipse, which makes this task easy. But it's not that hard to do it from the command line, either. You'll want to create a file (outside of your project!) and call it something like "externals.txt".

Each line is in the format:

path/inside/project path/to/external/code

So mine looks something like this:

docroot svn://drupal/drupal-5/core/drupal-5.9
docroot/sites/all/modules/adminmenu svn://drupal/drupal-5/modules/adminmenu/adminmenu-5.x.2.0
docroot/sites/all/themes/my_theme svn://custom/drupal-5/themes/my_fancy_theme

You'll notice this is referencing a directory called "docroot" that doesn't exist in the project. This is the way it must be. Don't worry, when you checkout the project, all required directories will be created and the code will be put in them.

Now, just set the property (from inside your working copy):


svn propset svn:externals . -F /path/to/your/externals.txt

Now commit the changes, and when you do an update, it will fetch all the code from the different sources for you!

Tradeoffs

The biggest advantage of this approach is how easy it is to update the 3rd-party code used by your project. New version of Drupal out? No problem, just add the new version to your repository and modify your externals.txt file to use it! Once you've issued the "propset" command again and updated, your Drupal code will be updated.

A nice side-effect of this approach is that Subversion is smart enough to commit changes to the correct repository. So, if you make changes to one of your custom modules while working on this project, they will be committed to the module's repository!

These instructions have assumed that all code exists in the same repository, but there's no reason for this to be the case. You can link to any Subversion repository that you have access to.

The disadvantage of this approach (aside from all the initial set-up, which only really exists the first time you create a project like this) is how much longer it takes to synchronize your working copy. Subversion has to check every one of these external repositories when looking for changes. This delay increases the more external references you have, so this may become a problem for very large Drupal projects.

Do you have a better approach? Let me know!