RSS

Newsletter

The CodeKarate Newsletter is the best way for technical ninjas to keep their swords sharpened. Don't worry, we won't flood your inbox and your email address will always remain private.
Back to Top

Drush Integration for your modules

Drush is a very powerful command line utility for creating, managing, and maintaining your Drupal website. There are many things that you can do with Drush, but suffice it to say that if you develop/build Drupal websites and don't currently use Drush, you should most definitely check it out.

Sometimes you may be building a module and need to make your Drupal site do things from the command line. In this case, writing custom Drush integration for your module will make your life easier when it comes to maintaining your Drupal site. Lets say you have some periodic (or sporadic) task that needs to be run, there are a few options.

  • Add the ability to perform the task from the Drupal administration back-end of the site
  • If it's a strictly scheduled task, you can use hook_cron() in your module to run code at specified intervals
  • Add Drush integration to your module to allow you to run the task from the command line

Each of the above has its place depending on the circumstances, however in this post we are only going to look at the Drush integration option. Below I will provide a very simple walkthrough for getting started with adding Drush integration to you module.

To add Drush integration to your custom module you need to start by creating a file in your module directory called "MYMODULE.drush.inc" (replacing MYMODULE with your module name). In this file we will need to declare a few hooks to register your command with Drush. The first hook is hook_drush_help():

/**
 * Implements hook_drush_help().
 */
function MYMODULE_drush_help($command) {
  switch ($command) {
    case 'drush:my-command':
      return dt('Run my command');
  }
}

This hook provides help to drush. The second hook we need to implement is hook_drush_command():

/**
 * Implements hook_drush_command().
 */
function MYMODULE_drush_command() {
  $items = array();
  $items['my-command'] = array(
    'description' => dt('Run my command.'),
    'arguments'   => array(
      'arg1'    => dt('An optional example argument'),
    ),
    'examples' => array(
      'Standard example' => 'drush my-command',
      'Argument example' => 'drush my-command 5',
    ),
    'aliases' => array('myc'),
  );
  return $items;
}

This hook defines the command called "my-command" to Drush. There are a few important things to note:

  • The dt() function is used to provide string translations. This is used in replacement of the Drupal t() function for Drush commands.
  • An array of arguments can be used to accept user input from the command line.
  • An array of examples can be added to provide additional help to the user.
  • Aliases are nice ways to shorten the Drush command. In the example created above, the drush my-command command can also be run using drush myc.

Now that we have the code in place, you should be able to view the help by running:


drush help my-command

or


drush help myc

Now it is time to write the callback function to specify exactly what we want this Drush command to do. This is where the bulk of your code will probably go. Often (but not always) this will include inserting, updating, or deleting data from the database. In this example I will just provide the skeleton code and you can fill in the function with the code you actually want to run for this Drush command.

/**
 * Callback function for drush my-command. 
 * Callback is called by using drush_hook_command() where
 * hook is the name of the module (MYMODULE) and command is the name of
 * the Drush command with all "-" characters converted to "_" characters (my_command)
 *
 * @param $arg1
 *   An optional argument
 */
function drush_MYMODULE_my_command($arg1 = NULL) {
  //check if the argument was passed in and just print it out
  if (isset($arg1)) {
   drush_print($arg1);
  }
 
  //log to the command line with an OK status
  drush_log('Running my-command', 'ok');
}

As you can see there are a few more Drush specific functions that you can use. I have provided a list of a few of them below with simple explanations.

drush_log('Log an event using drush', 'warning');
drush_set_error('Set an error with drush.');
dt('Translate strings with drush');
drush_print('Print to command line with drush');
drush_print_table($rows, TRUE); //print a command line table with drush
drush_confirm('Are you sure you want to continue?', $indent = 0); //Add drush confirmation

That should get you started adding Drush integration to your modules. Try it out and let me know if you run into any questions or need more detailed examples. I am beginning to migrate a lot of what I would normally put into hook_cron over to Drush commands so I can schedule it more flexibly using the server's cron. This works especially well for longer tasks as you can provide more memory and a higher time limit to command line PHP if required. This also provides the benefit of not creating additional overhead on the often overcrowded hook_cron().

Useful? Let me know what you think in the comments.

Discussions

1
Tammie (not verified)

Thanks.

Thanks for the great write up. Much appreciated. :)

2
lucsan (not verified)

Thanks

Very nice, well presented, clear, concise, a joy to follow with excellent examples. Five stars etc. Thank you.

3
Lacey Sanderson (not verified)

Options

To register options for your drush command you need to add define them in 'options' element of MYMODULE_drush_command $item['my-command']. According to the documentation (http://drush.ws/docs/commands.html) 'arguments' is only used by drush-help.

Then in your command callback you need to first get the option via drush_get_option('optionname'). It's not passed as an argument to the function header...

Updated Example:

/**
 * Implements hook_drush_command().
 */
function MYMODULE_drush_command() {
  $items = array();
  $items['my-command'] = array(
    // Used by drush-help
    'description' => dt('Run my command.'),
    'arguments'   => array(
      'arg1'    => dt('An optional example argument'),
    ),
    'examples' => array(
      'Standard example' => 'drush my-command',
      'Argument example' => 'drush my-command 5',
    ),
    //describe options
    'options' => array(
      'arg1' => array(
        'description' => dt('An optional example argument'),
        'example_value' => 5
        'value' => 'optional'
      ),
    ),
    'aliases' => array('myc'),
  );
  return $items;
}
 
/**
 * Callback function for drush my-command. 
 * Callback is called by using drush_hook_command() where
 * hook is the name of the module (MYMODULE) and command is the name of
 * the Drush command with all "-" characters converted to "_" characters (my_command)
 *
 * @param $arg1
 *   An optional argument
 */
function drush_MYMODULE_my_command() {
  // get arguement
  $arg1 = drush_get_option('arg1');
 
  //check if the argument was passed in and just print it out
  if (isset($arg1)) {
   drush_print($arg1);
  }
 
  //log to the command line with an OK status
  drush_log('Running my-command', 'ok');
}

3-1
shane

Interesting

According to the documentation, I think you are right... however the example you included also shows using the argument option (further down the page).

If you wanted to run the command using my example, it would be (using 5 as the argument)


drush myc 5

Using the example you provided, it would be


drush myc --arg1 5

If using your way, it would be best to remove the argument all together to prevent confusion. If you do have an argument, you will need to allow for that variable in the drush_MYMODULE_my_command function.

Overall, according the documentation it would seem as your way is the more correct approach. However, I do know my way works as far as functionality is concerned (that doesn't necessarily mean it is the correct way).

Perhaps some other Drush experts can weigh in here. If the way you provided is actually the preferred way, I will update my example.

Thanks for the comment.

shane's picture
4
Andrew (not verified)

Calling Drush Commands from Module code?

Hello,

i want to call drush commands from a drupal custom module code.
Is it possible?

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <h2> <h3> <blockquote> <img>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <css>, <html>, <php>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <mysql>, <python>, <ruby>. PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.