'Print this help message. Use --filter to limit command list to one command file (e.g. --filter=pm)', 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap. 'options' => drush_get_option_help(), 'examples' => array( 'drush dl cck zen' => 'Download CCK module and Zen theme.', 'drush --uri=http://example.com status' => 'Show status command for the example.com multi-site.', 'drush help --pipe' => 'A list of available commands, one per line.', 'drush help --html' => 'Print help for all commands in HTML format.', ), ); $items['core-cron'] = array( 'description' => 'Run all cron hooks.', 'aliases' => array('cron'), ); $items['updatedb'] = array( 'description' => dt('Execute the update.php process from the command line'), 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE, 'aliases' => array('updb'), ); $items['core-status'] = array( 'description' => 'Provides a birds-eye view of the current Drupal installation, if any.', 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, 'aliases' => array('status', 'st'), 'examples' => array( 'drush status version' => 'Show all status lines that contain version information.', 'drush status --pipe' => 'A list key=value items separated by line breaks.', 'drush status drush-version --pipe' => 'Emit just the drush version with no label.', ), 'arguments' => array( 'item' => 'Optional. The status item line(s) to display. Any matching line is shown; if only one line matches, then only the value is displayed. Otherwise, key=value is output.', ), 'options' => array( 'show-passwords' => 'Show database password.', ) ); $items['php-script'] = array( 'description' => "Run php script(s).", 'examples' => array( 'drush php-script scratch' => 'Run scratch.php script. See commands/core directory.', 'drush php-script example --script-path=/path/to/scripts:/another/path' => 'Run script from specified paths', 'drush php-script' => 'List all available scripts.', ), 'arguments' => array( 'filename' => 'Optional. The file you wish to execute (without extension). If omitted, list files ending in .php in the current working directory and specified script-path. Some might not be real drush scripts. Beware.', ), 'options' => array( '--script-path' => "Additional paths to search for scripts. Use POSIX path separator (':') for multiple paths.", ), 'aliases' => array('scr'), 'deprecated-aliases' => array('script'), ); $items['cache-clear'] = array( 'description' => 'Clear a specific cache, or all drupal caches.', 'arguments' => array( 'type' => 'The particular cache to clear. Omit this argument to choose from available caches.', ), 'aliases' => array('cc'), ); $items['search-status'] = array( 'description' => 'Show how many items remain to be indexed out of the total.', 'drupal dependencies' => array('search'), 'options' => array( '--pipe' => 'Display in the format remaining/total for processing by scripts.', ), ); $items['search-index'] = array( 'description' => 'Index the remaining search items without wiping the index.', 'drupal dependencies' => array('search'), ); $items['search-reindex'] = array( 'description' => 'Force the search index to be rebuilt.', 'drupal dependencies' => array('search'), 'options' => array( '--immediate' => 'Rebuild the index immediately, instead of waiting for cron.', ), ); $items['core-rsync'] = array( 'description' => 'Rsync the Drupal tree to/from another server using ssh. Relative paths start from the Drupal root folder if a site alias is used; otherwise they start from the current working directory.', 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap. 'arguments' => array( 'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.', 'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.', ), 'options' => array( '--mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz. Default is -az.', '--RSYNC-FLAG' => 'Most rsync flags passed to drush sync will be passed on to rsync. See rsync documentation.', '--exclude-conf' => 'Excludes settings.php from being rsynced. Default.', '--include-conf' => 'Allow settings.php to be rsynced', '--exclude-files' => 'Exclude the files directory.', '--exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".', '--exclude-other-sites' => 'Exclude all directories in "sites/" except for "sites/all" and the site directory for the site being synced. Note: if the site directory is different between the source and destination, use --exclude-sites followed by "drush rsync @from:%site @to:%site"', '--exclude-paths' => 'Coma-separated list of paths to exclude.', '--include-paths' => 'Coma-separated list of paths to include.', ), 'examples' => array( 'drush rsync @dev @stage' => 'Rsync Drupal root from dev to stage (one of which must be local).', 'drush rsync ./ @stage:%files/img' => 'Rsync all files in the current directory to the \'img\' directory in the file storage folder on stage.', ), 'aliases' => array('rsync'), 'deprecated-aliases' => array('sync'), ); $items['php-eval'] = array( 'description' => 'Evaluate arbitrary php code after bootstrapping Drupal.', 'examples' => array( 'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.', ), 'arguments' => array( 'code' => 'PHP code', ), 'deprecated-aliases' => array('eval'), ); $items['site-install'] = array( 'description' => 'Install Drupal along with modules/themes/configuration using the specified install profile.', 'arguments' => array( 'profile' => 'the install profile you wish to run. defaults to \'default\'', ), 'options' => array( 'db-url' => 'A Drupal 5/6 style database URL. Only required for initial install - not re-install.', 'db-prefix' => 'An optional table prefix to use for initial install.', 'account-name' => 'uid1 name. defaults to admin', 'account-pass' => 'uid1 pass. defaults to admin', 'account-mail' => 'uid1 email. defaults to admin@example.com', 'locale' => 'A short language code. Sets the default site language. Language files must already be present. You may use download command to get them.', 'clean-url'=> 'Defaults to 1', 'site-name' => 'Defaults to Site-Install', 'site-mail' => 'From: for system mailings. Defaults to admin@example.com', 'sites-subdir' => "Name of directory under 'sites' which should be created if needed. Defaults to 'default'", ), 'examples' => array( 'drush site-install expert --locale=uk' => '(Re)install using the expert install profile. Set default language to Ukranian.', 'drush site-install --db-url=mysql://root:pass@localhost:port/dbname ' => 'Install using the specified DB params.', 'drush site-install --account-user=joe --account-pass=mom' => 'Re-install with specified uid1 credentials.', ), 'core' => array(7), 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT, 'aliases' => array('si'), 'deprecated-aliases' => array('installsite', 'is'), ); $items['drupal-directory'] = array( 'description' => dt('Return path to a given module/theme directory. See --help for more details.'), 'arguments' => array( 'target' => 'A module/theme name, or special names like root, files, private, or an alias : path alias string such as @alias:%files. Defaults to root.', ), 'examples' => array( 'cd `drush dd devel`' => 'Navigate into the devel module directory', 'cd `drush dd` ' => 'Navigate to the root of your Drupal site', 'cd `drush dd files`' => 'Navigate to the files directory.', 'drush dd @alias:%files' => 'Print the path to the files directory on the site @alias.', 'edit `drush dd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)", ), 'aliases' => array('dd'), 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, ); $items['core-cli'] = array( 'description' => dt('Enter a new shell optimized for drush use.'), 'examples' => array( 'help' => 'Print available drush commands', 'cdd' => 'Navigate to the root of your Drupal site', 'cdd files' => 'Navigate to the files directory.', 'lsd files' => 'List all files in the Drupal files directory.', 'on @alias status' => 'Run the command "status" on the site indicated by @alias', ), 'aliases' => array('cli'), 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, ); $items['batch-process'] = array( 'description' => dt('Process operations in the specified batch set'), 'hidden' => TRUE, 'arguments' => array( 'batch-id' => 'The batch id that will be processed', ), 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN, ); $items['updatedb-batch-process'] = array( 'description' => dt('Perform update functions'), 'hidden' => TRUE, 'arguments' => array( 'batch-id' => 'The batch id that will be processed', ), 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE, ); return $items; } function core_drush_engine_drupal() { $engines = array(); $engines['batch'] = array(); $engines['update'] = array(); $engines['environment'] = array(); return $engines; } /** * Command handler. Execute update.php code from drush. */ function drush_core_updatedb() { if (drush_get_context('DRUSH_SIMULATE')) { return drush_set_error(dt('updatedb command does not support --simulate option.')); } drush_include_engine('drupal', 'update', drush_drupal_major_version()); update_main(); // Clear all caches. We just performed major surgery. drush_drupal_cache_clear_all(); drush_log(dt('Finished performing updates.'), 'ok'); } /** * This is called if no command or an unknown command is entered. */ function drush_core_help() { $commands = func_get_args(); if (drush_get_option('html')) { return drush_print(drush_help_html()); } elseif (empty($commands)) { drush_show_help(array('help')); $phases = _drush_bootstrap_phases(); // For speed, only bootstrap up to DRUSH_BOOTSTRAP_DRUPAL_SITE+1. $phases = array_slice($phases, 0, DRUSH_BOOTSTRAP_DRUPAL_SITE+1); drush_print(dt('Commands: ')); $printed_rows = array(); $phase_index = DRUSH_BOOTSTRAP_DRUSH; foreach ($phases as $phase_index) { if (drush_bootstrap_validate($phase_index)) { if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) { drush_bootstrap($phase_index); } $commands = drush_get_commands(); // Filter by command file if specified. if ($commandfile = drush_get_option('filter')) { foreach ($commands as $key => $candidate) { if ($candidate['commandfile'] != $commandfile) { unset($commands[$key]); } } } $rows = array(); ksort($commands); foreach($commands as $key => $command) { if (!$command['hidden']) { if (!array_key_exists('is_alias', $command) || !$command['is_alias']) { if (!array_key_exists($key, $printed_rows)) { $name = $command['aliases'] ? $key . ' (' . implode(', ', $command['aliases']) . ')': $key; $rows[$key] = array($name, $command['description']); $pipe[] = "\"$key\""; } } } } drush_print_table($rows, FALSE, array(0 => 20)); $printed_rows = array_merge($printed_rows, $rows); } else { break; } } // Newline-delimited list for use by other scripts. Set the --pipe option. drush_print_pipe($pipe); return; } else { return drush_show_help($commands); } drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => implode(" ", $commands)))); } /** * Return an HTML page documenting all available commands and global options. */ function drush_help_html() { foreach (drush_get_commands() as $key => $command) { // Get rid of aliases in command list. if (empty($command['is_alias']) && !$command['hidden']) { $commands[$key] = $command; } } unset($commands['help']); $output = "drush help\n"; // Command table $output .= '

Command list

'; foreach ($commands as $key => $command) { $output .= "\n"; } $output .= "
$key" . $command['description'] . "
\n"; // Global options $options = drush_get_option_help(); $output .= '

Global Options

'; foreach ($options as $key => $value) { $output .= "\n"; } $output .= "
$key" . $value . "
\n"; // Command details $output .= '

Command detail

'; foreach ($commands as $key => $command) { $output .= "\n
$key
\n";
    ob_start();
    drush_show_help(array($key));
    $output .= ob_get_clean();
    $output .=  "
\n"; } $output .= "\n"; return $output; } /** * Implementation of hook_drush_help(). * * This function is called whenever a drush user calls * 'drush help ' * * @param * A string with the help section (prepend with 'drush:') * * @return * A string with the help text for your command. */ function core_drush_help($section) { switch ($section) { case 'drush:help': return dt('Execute a drush command. Run `drush help [command]` to view command-specific help.'); case 'drush:cron': return dt("Runs all cron hooks in all active modules for specified site."); case 'drush:status': return dt("View the Drupal version and DB credentials for the current site."); case 'drush:php-script': return dt("Runs the given php script(s) after a full Drupal bootstrap. A useful alternative to eval command when your php is lengthy or you can't be bothered to figure out bash quoting. if you plan to share a script with others, consider making a full drush command instead since thats more self-documenting."); case 'drush:cache-clear': return dt("Delete a specific drupal cache, or all caches."); case 'drush:search-status': return dt("Show how many items remain to be indexed for search, and the total number of items."); case 'drush:search-index': return dt("Index the remaining search items."); case 'drush:search-reindex': return dt("Force the search index to be rebuilt."); case 'drush:updatedb': return dt("Run update.php just as a web browser would."); case 'drush:rsync': return dt("Sync the entire drupal directory or a subdirectory to a using ssh. Excludes .svn directories. Useful for pushing copies of your tree to a staging server, or retrieving a files directory from a remote site. Local paths should be specified relative to Drupal root."); case 'drush:php-eval': return dt("Run arbitrary PHP code in the context of Drupal"); case 'drush:site-install': return dt("Install Drupal using specified install profile."); case 'drush:drupal-directory': return dt("Return the filesystem path for projects/themes and other key folders. Used by `cli` command for handy commands `cdd` and `lsd`. If you want to use this command directly, you usually want to prefix the command with cd and enclose the command invocation in backticks. See Examples below."); case 'drush:core-cli': return dt("Enter a new shell optimized for drush use. See help for more details."); case 'error:DRUSH_DRUPAL_DB_ERROR' : $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n"); $message .= dt("Hint: This error often occurs when Drush is trying to bootstrap a site that has not been installed or does not have a configured database.\n"); $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials())); $message .= dt("You can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line or \$options['uri'] in your drushrc.php file.\n"); return $message; case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR' : $message = dt("Drush was not able to start (bootstrap) Drupal.\n"); $message .= dt("Hint: This error can only occur once the database connection has already been successfully initiated, therefore this error generally points to a site configuration issue, and not a problem connecting to the database.\n"); $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials())); $message .= dt("You can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line or \$options['uri'] in your drushrc.php file.\n"); return $message; break; } } // TODO: consolidate with SQL commands? function _core_site_credentials() { $status_table = _core_site_status_table(); return _core_site_credential_table($status_table); } function _core_site_credential_table($status_table) { $credentials = ''; foreach ($status_table as $key => $value) { $credentials .= sprintf(" %-18s: %s\n", $key, $value); } return $credentials; } function _core_site_credential_list($status_table) { $credentials = ''; foreach ($status_table as $key => $value) { if (isset($value)) { $credentials .= sprintf("%s=%s\n", strtolower(str_replace(' ', '_', $key)), $value); } } return $credentials; } function _core_path_aliases($project = '') { $paths = array(); $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE'); if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) { $paths['%root'] = $drupal_root; if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) { $paths['%site'] = $site_root; $paths['%modules'] = 'sites'.DIRECTORY_SEPARATOR.'all'.DIRECTORY_SEPARATOR.'modules'; $paths['%themes'] = 'sites'.DIRECTORY_SEPARATOR.'all'.DIRECTORY_SEPARATOR.'themes'; if (drush_drupal_major_version() >= 7) { $paths['%files'] = DrupalPublicStreamWrapper::getDirectoryPath(); $paths['%private'] = DrupalPrivateStreamWrapper::getDirectoryPath(); } elseif (function_exists('file_directory_path')) { $paths['%files'] = file_directory_path(); } // If the 'project' parameter was specified, then search // for a project (or a few) and add its path to the path list if (!empty($project)) { foreach(explode(',', $project) as $target) { $path = drush_core_find_project_path($target); if(isset($path)) { $paths['%' . $target] = $path; } } } } } // Add in all of the global paths from $options['path-aliases'] $paths = array_merge($paths, drush_get_option('path-aliases', array())); return $paths; } function _core_site_status_table($project = '') { $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE'); if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) { $status_table['Drupal version'] = drush_drupal_version(); if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) { $status_table['Site URI'] = drush_get_context('DRUSH_URI'); if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) { $status_table['Database driver'] = $creds['driver']; $status_table['Database hostname'] = $creds['host']; $status_table['Database username'] = $creds['user']; $status_table['Database name'] = $creds['name']; if (drush_get_option('show-passwords', FALSE)) { $status_table['Database password'] = $creds['pass']; } if ($phase > DRUSH_BOOTSTRAP_DRUPAL_DATABASE) { $status_table['Database'] = dt('Connected'); if ($phase > DRUSH_BOOTSTRAP_DRUPAL_FULL) { $status_table['Drupal bootstrap'] = dt('Successful'); if ($phase == DRUSH_BOOTSTRAP_DRUPAL_LOGIN) { global $user; $username = ($user->uid) ? $user->name : dt('Anonymous'); $status_table['Drupal user'] = $username; } } } } } $status_table['Default theme'] = drush_theme_get_default(); $status_table['Administration theme'] = drush_theme_get_admin(); } if (function_exists('php_ini_loaded_file')) { // Function available on PHP >= 5.2.4, but we use it if available to help // users figure out their php.ini issues. $status_table['PHP configuration'] = php_ini_loaded_file(); } $status_table['Drush version'] = DRUSH_VERSION; $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE)); // None of the Status keys are in dt(); this helps with machine-parsing of status? $path_names['root'] = 'Drupal root'; $path_names['site'] = 'Site path'; $path_names['modules'] = 'Modules path'; $path_names['themes'] = 'Themes path'; $path_names['files'] = 'File directory path'; $path_names['private'] = 'Private file directory path'; $paths = _core_path_aliases($project); if (!empty($paths)) { foreach ($paths as $target => $one_path) { $name = $target; if (substr($name,0,1) == '%') { $name = substr($name,1); } if (array_key_exists($name, $path_names)) { $name = $path_names[$name]; } $status_table[$name] = $one_path; } } // Store the paths into the '%paths' index; this will be // used by other code, but will not be included in the output // of the drush status command. $status_table['%paths'] = $paths; return $status_table; } /** * Command callback. Runs cron hooks. * * This is where the action takes place. * * In this function, all of Drupals API is (usually) available, including * any functions you have added in your own modules/themes. * * To print something to the terminal window, use drush_print(). * */ function drush_core_cron() { if (drupal_cron_run()) { drush_log(dt('Cron run successfully.'), 'success'); } else { drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.')); } } /** * Command callback. Provides a birds-eye view of the current Drupal * installation. */ function drush_core_status() { drush_bootstrap_max(); $status_table = _core_site_status_table(drush_get_option('project','')); // If args are specified, filter out any entry that is not named // (in other words, only show lines named by one of the arg values) $args = func_get_args(); if (!empty($args)) { foreach ($status_table as $key => $value) { if (!_drush_core_is_named_in_array($key, $args)) { unset($status_table[$key]); } } } drush_backend_set_result($status_table); unset($status_table['%paths']); // Print either an ini-format list or a formatted ASCII table if (drush_get_option('pipe')) { if (count($status_table) == 1) { $first_value = array_shift($status_table); drush_print_pipe($first_value); } else { drush_print_pipe(_core_site_credential_list($status_table)); } } else { unset($status_table['Modules path']); unset($status_table['Themes path']); drush_print_table(drush_key_value_to_array_table($status_table)); } return; } function _drush_core_is_named_in_array($key, $the_array) { $is_named = FALSE; $simplified_key = str_replace(array(' ', '_', '-'), array('', '', ''), $key); foreach ($the_array as $name) { if (stristr($simplified_key, str_replace(array(' ', '_', '-'), array('', '', ''), $name))) { $is_named = TRUE; } } return $is_named; } /** * Command callback. Runs "naked" php scripts. */ function drush_core_php_script() { $args = func_get_args(); // Array of paths to search for scripts $searchpath['DIR'] = dirname(__FILE__); $searchpath['cwd'] = drush_cwd(); // Additional script paths, specified by 'script-path' option if ($script_path = drush_get_option('script-path', FALSE)) { foreach (explode(":", $script_path) as $path) { $searchpath[] = $path; } } if (empty($args)) { // List all available scripts. $all = array(); foreach($searchpath as $key => $path) { $recurse = !$key == 'cwd'; $all = array_merge( $all , array_keys(drush_scan_directory($path, '/\.php$/', array('.', '..', 'CVS'), NULL, $recurse)) ); } drush_print(implode("\n", $all)); } else { // Execute the specified script. $script = $args[0]; if (!preg_match('/\.php$/i', $script)) { $script .= '.php'; } $found = FALSE; foreach($searchpath as $path) { $script_filename = $path . '/' . $script; if (file_exists($script_filename)) { include($script_filename); $found = TRUE; break; } $all[] = $script_filename; } if (!$found) { drush_set_error('Script not found.', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all)))); } } } function drush_core_php_eval($command) { eval($command . ';'); } /** * Process sets from the specified batch. * * This is the default batch processor that will be used if the $command parameter * to drush_backend_batch_process() has not been specified. */ function drush_core_batch_process($id) { drush_batch_command($id); } /** * Process outstanding updates during updatedb. * * This is a batch processing command that makes use of the drush_backend_invoke * api. * * This command includes the version specific update engine, which correctly * initialises the environment to be able to successfully handle minor and major * upgrades. */ function drush_core_updatedb_batch_process($id) { drush_include_engine('drupal', 'update', drush_drupal_major_version()); _update_batch_command($id); } function _drush_core_directory($target = 'root') { // Normalize to a sitealias in the target. $normalized_target = $target; if (strpos($target, ':') === FALSE) { if (substr($target,0,1) == '@') { $normalized_target = $target; // . ':%site'; } else { // @self makes no sense before 'site' level. if(!drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) { return FALSE; } $normalized_target = '@self:'; if (substr($target,0,1) != '%') { $normalized_target .= '%'; } $normalized_target .= $target; } } $additional_options = array(); $values = drush_sitealias_evaluate_path($normalized_target, $additional_options); if (isset($values['path'])) { // Hurray, we found the destination return $values['path']; } return NULL; } function drush_core_drupal_directory($target = 'root') { $path = _drush_core_directory($target); if (isset($path)) { drush_print($path); } else { return drush_set_error(dt('Core directory path !target not found.', array('!target' => $target))); } return TRUE; } function drush_core_find_project_path($target) { $theme_suffix = drush_drupal_major_version() >= 6 ? '.info' : '/style.css'; $masks = array( conf_path() . '/modules' => "/^$target.module/", 'profiles/default/modules' => "/^$target.module/", // Too early for variable_get('install_profile', 'default'); Just use default. 'sites/all/modules' => "/^$target.module/", // Add all module paths, even disabled modules. conf_path() . '/themes' => "/^$target" . "$theme_suffix/", 'sites/all/themes' => "/^$target" . "$theme_suffix/", ); $files = array(); foreach ($masks as $key => $mask) { if ($files = drush_scan_directory("$key", $mask, array('..', '.', 'CVS', '.svn', '.bzr'), 0, TRUE, 'name')) { // Just use the first match. $file = reset($files); return drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename); } } return NULL; } function drush_core_cli() { drush_bootstrap_max(); // Do not allow cli to start recursively, or from backend invoke. if (drush_get_option('in-cli',FALSE)) { return drush_set_error(dt('Already in drush core-cli; press control-d to exit.')); } if (drush_get_context('DRUSH_BACKEND')) { return drush_set_error(dt('Cannot run drush core-cli from non-interactive mode; aborting.')); } // Make sure that we call drush the same way that we were called. $drush_command = DRUSH_COMMAND.' --in-cli'; $bashrc_data = implode("/n/n", drush_command_invoke_all('cli_bashrc', $drush_command)); // Before entering the new bash script, cd to the current site root, // if any. This will make our default site for drush match the // currently bootstrapped site (at least until the user cd's away). if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) { chdir($site_root); } // Print our entire bashrc file in verbose mode if (drush_get_context('DRUSH_VERBOSE')) { drush_print($bashrc_data); } drush_print("Entering the drush cli. Use CONTROL-D to exit."); drush_print("Type 'help' for help."); // Save out bashrc in a temporary file and launch bash. // control-d to exit. The temp file will be deleted after // we exit. $bashrc = drush_save_data_to_temp_file($bashrc_data); drush_op('system', 'bash --rcfile ' . $bashrc . ' > `tty`'); } // Implement our own hook_cli_bashrc() function core_cli_bashrc($drush_command) { // Set up our default bashrc file for the drush cli $bashrc_data = << $command) { // Filter out old commands that still have spaces if (strpos($key, ' ') === FALSE) { $bashrc_data .= "function $key() {\n $drush_command $key \"\$@\"\n}\n"; } } return $bashrc_data; }