MDrush, a Drush python wrapper

Share and options

Some months ago, I was developing some Drupal modules for my Company, I noticed the time I loose each time I have to run a Drush command (such as clear cache) in order to do basic Drupal developer stuff.

1. Some context

The most annoying thing is I always have a lot of opened terminals in order to monitor and do other stuffs, such as:

  • tail -f /var/www/myproject/var/log/error.log
  • drush -r /var/www/myproject/www/ some command
  • grep -iRn "some_function_call(" *
  • svn ci -m "foo"
  • and many more ...

For every of this commands, I need to chdir to the right path (or include the path in some command line argument, which is not possible for all these stuff).

The fact is I'm not well organized, I do all this stuff in a really intuitive way, like each time I want type in another new command I'll do a CTRL+N to open a new console (which is quite stupid some will think).

And probably the most annoying command of all is Drush. Why? Because each time I want to run a drush command on a Drupal site, I have to tell him where is the Drupal root absolute path? Why? Because each time I need to download a new module, I have to specify the full root path of modules dir I want to use. This is becoming quite confusing.

So, I found a nice solution, to handle those drush root pathes: I called it mdrush.

2. The solution

mdrush is a python Drush wrapper. It keeps a list of site in a ini style configuration file, or in a MySQL database small schema. For each site, it keeps this data:

  • An arbitrary user given canonical name, such as myproject
  • Drupal absolute root path on filesystem
  • A list of modules path, for each module path its Drupal root relative path
  • Drush script path to use with this site
  • Optionnaly, a remote hostname in order to use it over SSH

3. Usage

Its usage is quite simple, all you have to do is replace the drush binary in your command line with mdrush <project-name>.

Sample with a project named foo which absolute file system path is /var/www/foo/www:

pounard@guinevere:~$ # This will be the equivalent of drush -r /var/www/foo/www cache clear
pounard@guinevere:~$ mdrush foo cache clear

Because the drush command line can contain arguments and options, which should not conflict with mdrush one, it will assume that every argument until the first non argument parameter (which should always be the project name) will be its own, and the trailing options and arguments passed to the command line will compose drush command line.

So, let's see a complex example:

pounard@guinevere:~$ # Here, -y will be a drush option
pounard@guinevere:~$ mdrush foo -y cache clear
pounard@guinevere:~$ # Here, -y will be a mdrush option
pounard@guinevere:~$ mdrush -y foo cache clear

4. The beauty

So, that's it? But where is it really useful then? Well, I'll say that's not it, I also included a small helper which is site tokens. Let's look at the mdrush --help command output:

pounard@guinevere:~$ mdrush -h
mdrush -- Drush wrapper for multiple site handling.
Usage: /usr/local/bin/mdrush [OPTIONS] | [<SITE> <DRUSHOPTIONS>]

Where options can be:
  -c <SITE> Register a new drupal site instance into your
configuration
  -m <SITE> Modify site instance
  -d <SITE> Delete a drupal site instance from your configuration
  -l [<SITE>] If <SITE> is specified, list all modules path
else list all known sites
  --configure Run configuration wizzard
  -h Display this help

And arguments are:
  <SITE> Identifier configured in ~/.mdrush/sites.conf
Instead of string identifier, you can use an integer
See list with -l
  <DRUSHOPTIONS> Normal drush command line

You can use these tokens within the drush command:
  %mX Use the X module path (see list with -l <SITENAME>)
  %MX Same as %mX but with absolute path
  %r Absolute site root path

Examples
  Clear cache of a specific site:
    mdrush <sitename> cache clear
  Download a module in a specific module dir using token:
    mdrush <sitename> dl <module> --destination=%M2

pounard@guinevere:~$

Two things are beautiful here. The first is as I should have said upper, mdrush will always invoke drush using the -r option. The second is whenever you need to write some absolute or relative paths, you won't need to known where is really located the site, because some tokens will help you.

Let's see how it's great. I will demonstrate how I use it with a custom site of mine:

pounard@guinevere:~$ mdrush -l # List all sites
Configured sites:
0 - blog.processus.org (remote) -> /var/www/vhost/blog.processus.org/htdocs
2 - drupal-demo (local) -> /var/www/drupal-demo/www
5 - drupal-6 (local) -> /var/www/drupal-6/www
pounard@guinevere:~$ # Notice that here, I intentionally removed some entries which are some of
pounard@guinevere:~$ # company projects.

Now, I want to known modules folders pathes of drupal-6 project:

pounard@guinevere:~$ mdrush -l drupal-6
Site 'drupal-6' modules path:
0 - sites/all/modules/contrib
1 - sites/all/modules/custom
2 - sites/all/modules/devel
pounard@guinevere:~$

Nice, now let's download a contribution module to drupal-6 project. Using classical drush, I would have typed:

pounard@guinevere:~$ drush -r /var/www/drupal-6/www -y dl views --destination=/var/www/drupal-6/www/sites/all/modules/contrib

Whow, what such an horrible command to type in. Let's see what mdrush could do for me:

pounard@guinevere:~$ mdrush drupal-6 -y dl --destination=%M0 views
Project views (6.x-2.8) downloaded to /var/www/drupal-6/www/sites/all/modules/contrib/.
pounard@guinevere:~$

I won, drush loose, my command line is totally path free! And lot more quickly written.

5. Remote sites handling

Let's see my module list, did you notice the blog.processus.org (remote) -> /var/www/vhost/blog.processus.org/htdocs entry?

Let's see mdrush in action:

pounard@guinevere:~$ mdrush blog.processus.org cache clear
pounard@hydralisk.processus.org's password:
Cache cleared.
pounard@guinevere:~$

No comments. All you have to do to skip the annoying password phase is to use generate and copy your own ssh key over the server, that's it. It works.

The only limitation here is you have to install the Drush script on your remote site, and precise its full path when you configure your site.

6. What about interractive mode

If you are this careful, don't worry, the python wrapper uses the stdin/stdout streams to interract with the end user, don't worry about the fact you are using a remote or a local site, their is absolutely no differences.

7. And for lazy people

You are that lazy, you probably are a good developer! And because I am a lazy developer, I wrote a CLI wizzard to write your sites configuration file (or database entry), let's see it:

pounard@guinevere:~$ mdrush -c drupal-7
Create site 'drupal-7'
Select in:
* 1 - Local site
   2 - Remote SSH site
>
Path to Drush command to use, leave empty to use default
>
Type the site root path
> /var/www/drupal-7/www
Type one to n module path (e.g. 'sites/all/modules')
One path per line, finish with an empty line
>
New site 'drupal-7' saved
pounard@guinevere:~$

That's it, mdrush knows your site now. Ready to use:

pounard@guinevere:~$ mdrush drupal-7 status
  PHP configuration : /etc/php.ini
  Drupal Root       : /var/www/drupal-7/www
  Drupal version    : 7.0-dev
  Site Path         : sites/default
  Site URI          : http://default
  Database Driver   : mysql
  Database Hostname : localhost
  Database Username : drupal-7
  Database Name     : drupal-7
  Database Password : drupal-7
pounard@guinevere:~$

Quite easy, right?

8. Conclusion

I really want this python application to be free software, and I definitely want to share it. In the future, I may commit it on drupal.org, but I'd rather prefer to use a real DCVS, like git. Because my choice has not been made, I won't share the code.

Don't worry, it will come soon!