Third & GroveThird & Grove
Apr 7, 2017 - Josh Fremer

Calling Drush from Another Drush Command in Drupal

Sometimes you need a drush command to call a different drush command, maybe even from a different Drupal instance. This is quite easy if you have drush site aliases configured for each site. In this example, we add a drush command that compares variable values across two different instances.

First we define our drush command:

/**
 * Implements hook_drush_command().
 *
 * @return
 *   An associative array describing your command(s).
 */
function mymodule_drush_command() {
  return array(
    'variable-compare' => array(
      'description' => dt('Compares a variable value between this and another Drupal instance.'),
      'aliases' => array('vc'),
      'arguments' => array(
        'alias' => array(
          'description' => dt('The drush site alias to test against.  Use drush sa to see valid values.')
        ),
        'variable-name' => array(
          'description' => dt('The name of the variable to compare.')
        ),
      ),
      'examples' => array(
        'drush variable-compare @mysite.stage myvariable' => dt('Compares the value of myvariable with the value on the @mysite.stage alias.'),
      ),
    ),
  );
}

 

The drush_sitealias_get_record() function gives us all the configured information about a site alias, but we don't actually need any of that. We just use it to verify that a site alias is valid.

 

The real magic happens in drush_invoke_process(), which spins up a new drush bootstrap for the given site alias and executes whatever command you specify. We call drush_invoke_process() twice, once against the passed alias and once against @self, which refers to the current drush configuration. We pass in the variable name as a parameter, and add the quiet option so our output isn't cluttered.

Note that the return value of many drush functions is quite different from the log output which we normally see in the console. It's important to look carefully at the code for the drush command you're calling to determine the format of its return value.

/**
 * Compares a variable for an alias against @self.
 */
function drush_mymodule_variable_compare($alias, $variable_name) {
  $config = drush_sitealias_get_record($alias);
  if (empty($config)) {
    return drush_set_error(dt('Site alias !alias not found', array('!alias' => $alias)));
  }
 
  $test_values = drush_invoke_process($alias, 'variable-get', array($variable_name), array('quiet' => 1));
  $control_values = drush_invoke_process('@self', 'variable-get', array($variable_name), array('quiet' => 1));
 
  $test_value = $test_values['object'][$variable_name];
  $control_value = $control_values['object'][$variable_name];
  if ($test_value === $control_value) {
    drush_log(dt('Variable values match.'), 'ok');
    return;
  }
 
  drush_log(dt('Variable values do not match.'), 'ok');
  $rows = array();
  $rows[] = array(dt('Alias'), dt('Value'), dt('Type'));
  $rows[] = array('@self', $control_value, gettype($control_value));
  $rows[] = array($alias, $test_value, gettype($test_value));
  drush_print_table($rows, TRUE);
}

 

For other ways to call drush within drush, refer to the Command Dispatching Functions section of the drush documentation. Good luck!