core.drush.inc

  1. 8.0.x commands/core/core.drush.inc
  2. 6.x commands/core/core.drush.inc
  3. 7.x commands/core/core.drush.inc
  4. 3.x commands/core/core.drush.inc
  5. 4.x commands/core/core.drush.inc
  6. 5.x commands/core/core.drush.inc
  7. master commands/core/core.drush.inc

Core drush commands.

Functions

Namesort descending Description
core_cli_bashrc
core_drush_command Implementation of hook_drush_command().
core_drush_engine_drupal
core_drush_help Implementation of hook_drush_help().
drush_core_batch_process Process sets from the specified batch.
drush_core_cli
drush_core_cron Command callback. Runs cron hooks.
drush_core_drupal_directory
drush_core_find_project_path
drush_core_help This is called if no command or an unknown command is entered.
drush_core_php_eval
drush_core_php_script Command callback. Runs "naked" php scripts.
drush_core_status Command callback. Provides a birds-eye view of the current Drupal installation.
drush_core_updatedb Command handler. Execute update.php code from drush.
drush_core_updatedb_batch_process Process outstanding updates during updatedb.
drush_help_html Return an HTML page documenting all available commands and global options.
_core_path_aliases
_core_site_credentials
_core_site_credential_list
_core_site_credential_table
_core_site_status_table
_drush_core_directory
_drush_core_is_named_in_array

File

commands/core/core.drush.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Core drush commands.
  5. */
  6. /**
  7. * Implementation of hook_drush_command().
  8. *
  9. * In this hook, you specify which commands your
  10. * drush module makes available, what it does and
  11. * description.
  12. *
  13. * Notice how this structure closely resembles how
  14. * you define menu hooks.
  15. *
  16. * @return
  17. * An associative array describing your command(s).
  18. */
  19. function core_drush_command() {
  20. $items = array();
  21. $items['help'] = array(
  22. 'description' => 'Print this help message. Use --filter to limit command list to one command file (e.g. --filter=pm)',
  23. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  24. 'options' => drush_get_option_help(),
  25. 'examples' => array(
  26. 'drush dl cck zen' => 'Download CCK module and Zen theme.',
  27. 'drush --uri=http://example.com status' => 'Show status command for the example.com multi-site.',
  28. 'drush help --pipe' => 'A list of available commands, one per line.',
  29. 'drush help --html' => 'Print help for all commands in HTML format.',
  30. ),
  31. );
  32. $items['core-cron'] = array(
  33. 'description' => 'Run all cron hooks.',
  34. 'aliases' => array('cron'),
  35. );
  36. $items['updatedb'] = array(
  37. 'description' => dt('Execute the update.php process from the command line'),
  38. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  39. 'aliases' => array('updb'),
  40. );
  41. $items['core-status'] = array(
  42. 'description' => 'Provides a birds-eye view of the current Drupal installation, if any.',
  43. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  44. 'aliases' => array('status', 'st'),
  45. 'examples' => array(
  46. 'drush status version' => 'Show all status lines that contain version information.',
  47. 'drush status --pipe' => 'A list key=value items separated by line breaks.',
  48. 'drush status drush-version --pipe' => 'Emit just the drush version with no label.',
  49. ),
  50. 'arguments' => array(
  51. '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.',
  52. ),
  53. 'options' => array(
  54. 'show-passwords' => 'Show database password.',
  55. )
  56. );
  57. $items['php-script'] = array(
  58. 'description' => "Run php script(s).",
  59. 'examples' => array(
  60. 'drush php-script scratch' => 'Run scratch.php script. See commands/core directory.',
  61. 'drush php-script example --script-path=/path/to/scripts:/another/path' => 'Run script from specified paths',
  62. 'drush php-script' => 'List all available scripts.',
  63. ),
  64. 'arguments' => array(
  65. '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.',
  66. ),
  67. 'options' => array(
  68. '--script-path' => "Additional paths to search for scripts. Use POSIX path separator (':') for multiple paths.",
  69. ),
  70. 'aliases' => array('scr'),
  71. 'deprecated-aliases' => array('script'),
  72. );
  73. $items['cache-clear'] = array(
  74. 'description' => 'Clear a specific cache, or all drupal caches.',
  75. 'arguments' => array(
  76. 'type' => 'The particular cache to clear. Omit this argument to choose from available caches.',
  77. ),
  78. 'aliases' => array('cc'),
  79. );
  80. $items['search-status'] = array(
  81. 'description' => 'Show how many items remain to be indexed out of the total.',
  82. 'drupal dependencies' => array('search'),
  83. 'options' => array(
  84. '--pipe' => 'Display in the format remaining/total for processing by scripts.',
  85. ),
  86. );
  87. $items['search-index'] = array(
  88. 'description' => 'Index the remaining search items without wiping the index.',
  89. 'drupal dependencies' => array('search'),
  90. );
  91. $items['search-reindex'] = array(
  92. 'description' => 'Force the search index to be rebuilt.',
  93. 'drupal dependencies' => array('search'),
  94. 'options' => array(
  95. '--immediate' => 'Rebuild the index immediately, instead of waiting for cron.',
  96. ),
  97. );
  98. $items['core-rsync'] = array(
  99. '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.',
  100. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  101. 'arguments' => array(
  102. 'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  103. 'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  104. ),
  105. 'options' => array(
  106. '--mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz. Default is -az.',
  107. '--RSYNC-FLAG' => 'Most rsync flags passed to drush sync will be passed on to rsync. See rsync documentation.',
  108. '--exclude-conf' => 'Excludes settings.php from being rsynced. Default.',
  109. '--include-conf' => 'Allow settings.php to be rsynced',
  110. '--exclude-files' => 'Exclude the files directory.',
  111. '--exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
  112. '--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"',
  113. '--exclude-paths' => 'Coma-separated list of paths to exclude.',
  114. '--include-paths' => 'Coma-separated list of paths to include.',
  115. ),
  116. 'examples' => array(
  117. 'drush rsync @dev @stage' => 'Rsync Drupal root from dev to stage (one of which must be local).',
  118. 'drush rsync ./ @stage:%files/img' => 'Rsync all files in the current directory to the \'img\' directory in the file storage folder on stage.',
  119. ),
  120. 'aliases' => array('rsync'),
  121. 'deprecated-aliases' => array('sync'),
  122. );
  123. $items['php-eval'] = array(
  124. 'description' => 'Evaluate arbitrary php code after bootstrapping Drupal.',
  125. 'examples' => array(
  126. 'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.',
  127. ),
  128. 'arguments' => array(
  129. 'code' => 'PHP code',
  130. ),
  131. 'deprecated-aliases' => array('eval'),
  132. );
  133. $items['site-install'] = array(
  134. 'description' => 'Install Drupal along with modules/themes/configuration using the specified install profile.',
  135. 'arguments' => array(
  136. 'profile' => 'the install profile you wish to run. defaults to \'default\'',
  137. ),
  138. 'options' => array(
  139. 'db-url' => 'A Drupal 5/6 style database URL. Only required for initial install - not re-install.',
  140. 'db-prefix' => 'An optional table prefix to use for initial install.',
  141. 'account-name' => 'uid1 name. defaults to admin',
  142. 'account-pass' => 'uid1 pass. defaults to admin',
  143. 'account-mail' => 'uid1 email. defaults to admin@example.com',
  144. 'locale' => 'A short language code. Sets the default site language. Language files must already be present. You may use download command to get them.',
  145. 'clean-url'=> 'Defaults to 1',
  146. 'site-name' => 'Defaults to Site-Install',
  147. 'site-mail' => 'From: for system mailings. Defaults to admin@example.com',
  148. 'sites-subdir' => "Name of directory under 'sites' which should be created if needed. Defaults to 'default'",
  149. ),
  150. 'examples' => array(
  151. 'drush site-install expert --locale=uk' => '(Re)install using the expert install profile. Set default language to Ukranian.',
  152. 'drush site-install --db-url=mysql://root:pass@localhost:port/dbname ' => 'Install using the specified DB params.',
  153. 'drush site-install --account-user=joe --account-pass=mom' => 'Re-install with specified uid1 credentials.',
  154. ),
  155. 'core' => array(7),
  156. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
  157. 'aliases' => array('si'),
  158. 'deprecated-aliases' => array('installsite', 'is'),
  159. );
  160. $items['drupal-directory'] = array(
  161. 'description' => dt('Return path to a given module/theme directory. See --help for more details.'),
  162. 'arguments' => array(
  163. '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.',
  164. ),
  165. 'examples' => array(
  166. 'cd `drush dd devel`' => 'Navigate into the devel module directory',
  167. 'cd `drush dd` ' => 'Navigate to the root of your Drupal site',
  168. 'cd `drush dd files`' => 'Navigate to the files directory.',
  169. 'drush dd @alias:%files' => 'Print the path to the files directory on the site @alias.',
  170. 'edit `drush dd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)",
  171. ),
  172. 'aliases' => array('dd'),
  173. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  174. );
  175. $items['core-cli'] = array(
  176. 'description' => dt('Enter a new shell optimized for drush use.'),
  177. 'examples' => array(
  178. 'help' => 'Print available drush commands',
  179. 'cdd' => 'Navigate to the root of your Drupal site',
  180. 'cdd files' => 'Navigate to the files directory.',
  181. 'lsd files' => 'List all files in the Drupal files directory.',
  182. 'on @alias status' => 'Run the command "status" on the site indicated by @alias',
  183. ),
  184. 'aliases' => array('cli'),
  185. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  186. );
  187. $items['batch-process'] = array(
  188. 'description' => dt('Process operations in the specified batch set'),
  189. 'hidden' => TRUE,
  190. 'arguments' => array(
  191. 'batch-id' => 'The batch id that will be processed',
  192. ),
  193. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
  194. );
  195. $items['updatedb-batch-process'] = array(
  196. 'description' => dt('Perform update functions'),
  197. 'hidden' => TRUE,
  198. 'arguments' => array(
  199. 'batch-id' => 'The batch id that will be processed',
  200. ),
  201. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  202. );
  203. return $items;
  204. }
  205. function core_drush_engine_drupal() {
  206. $engines = array();
  207. $engines['batch'] = array();
  208. $engines['update'] = array();
  209. $engines['environment'] = array();
  210. return $engines;
  211. }
  212. /**
  213. * Command handler. Execute update.php code from drush.
  214. */
  215. function drush_core_updatedb() {
  216. if (drush_get_context('DRUSH_SIMULATE')) {
  217. return drush_set_error(dt('updatedb command does not support --simulate option.'));
  218. }
  219. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  220. update_main();
  221. // Clear all caches. We just performed major surgery.
  222. drush_drupal_cache_clear_all();
  223. drush_log(dt('Finished performing updates.'), 'ok');
  224. }
  225. /**
  226. * This is called if no command or an unknown command is entered.
  227. */
  228. function drush_core_help() {
  229. $commands = func_get_args();
  230. if (drush_get_option('html')) {
  231. return drush_print(drush_help_html());
  232. }
  233. elseif (empty($commands)) {
  234. drush_show_help(array('help'));
  235. $phases = _drush_bootstrap_phases();
  236. // For speed, only bootstrap up to DRUSH_BOOTSTRAP_DRUPAL_SITE+1.
  237. $phases = array_slice($phases, 0, DRUSH_BOOTSTRAP_DRUPAL_SITE+1);
  238. drush_print(dt('Commands: '));
  239. $printed_rows = array();
  240. $phase_index = DRUSH_BOOTSTRAP_DRUSH;
  241. foreach ($phases as $phase_index) {
  242. if (drush_bootstrap_validate($phase_index)) {
  243. if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
  244. drush_bootstrap($phase_index);
  245. }
  246. $commands = drush_get_commands();
  247. // Filter by command file if specified.
  248. if ($commandfile = drush_get_option('filter')) {
  249. foreach ($commands as $key => $candidate) {
  250. if ($candidate['commandfile'] != $commandfile) {
  251. unset($commands[$key]);
  252. }
  253. }
  254. }
  255. $rows = array();
  256. ksort($commands);
  257. foreach($commands as $key => $command) {
  258. if (!$command['hidden']) {
  259. if (!array_key_exists('is_alias', $command) || !$command['is_alias']) {
  260. if (!array_key_exists($key, $printed_rows)) {
  261. $name = $command['aliases'] ? $key . ' (' . implode(', ', $command['aliases']) . ')': $key;
  262. $rows[$key] = array($name, $command['description']);
  263. $pipe[] = "\"$key\"";
  264. }
  265. }
  266. }
  267. }
  268. drush_print_table($rows, FALSE, array(0 => 20));
  269. $printed_rows = array_merge($printed_rows, $rows);
  270. }
  271. else {
  272. break;
  273. }
  274. }
  275. // Newline-delimited list for use by other scripts. Set the --pipe option.
  276. drush_print_pipe($pipe);
  277. return;
  278. }
  279. else {
  280. return drush_show_help($commands);
  281. }
  282. drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => implode(" ", $commands))));
  283. }
  284. /**
  285. * Return an HTML page documenting all available commands and global options.
  286. */
  287. function drush_help_html() {
  288. foreach (drush_get_commands() as $key => $command) {
  289. // Get rid of aliases in command list.
  290. if (empty($command['is_alias']) && !$command['hidden']) {
  291. $commands[$key] = $command;
  292. }
  293. }
  294. unset($commands['help']);
  295. $output = "<html><head><title>drush help</title><style>dt {font-size: 110%; font-weight: bold}</style></head><body>\n";
  296. // Command table
  297. $output .= '<h3>Command list</h3><table>';
  298. foreach ($commands as $key => $command) {
  299. $output .= "<tr><td><a href=\"#$key\">$key</a></td><td>" . $command['description'] . "</td></tr>\n";
  300. }
  301. $output .= "</table>\n";
  302. // Global options
  303. $options = drush_get_option_help();
  304. $output .= '<h3>Global Options</h3><table>';
  305. foreach ($options as $key => $value) {
  306. $output .= "<tr><td>$key</td><td>" . $value . "</td></tr>\n";
  307. }
  308. $output .= "</table>\n";
  309. // Command details
  310. $output .= '<h3>Command detail</h3><dl>';
  311. foreach ($commands as $key => $command) {
  312. $output .= "\n<a name=\"$key\"></a><dt>$key</dt><dd><pre>\n";
  313. ob_start();
  314. drush_show_help(array($key));
  315. $output .= ob_get_clean();
  316. $output .= "</pre></dd>\n";
  317. }
  318. $output .= "</body></html>\n";
  319. return $output;
  320. }
  321. /**
  322. * Implementation of hook_drush_help().
  323. *
  324. * This function is called whenever a drush user calls
  325. * 'drush help <name-of-your-command>'
  326. *
  327. * @param
  328. * A string with the help section (prepend with 'drush:')
  329. *
  330. * @return
  331. * A string with the help text for your command.
  332. */
  333. function core_drush_help($section) {
  334. switch ($section) {
  335. case 'drush:help':
  336. return dt('Execute a drush command. Run `drush help [command]` to view command-specific help.');
  337. case 'drush:cron':
  338. return dt("Runs all cron hooks in all active modules for specified site.");
  339. case 'drush:status':
  340. return dt("View the Drupal version and DB credentials for the current site.");
  341. case 'drush:php-script':
  342. 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.");
  343. case 'drush:cache-clear':
  344. return dt("Delete a specific drupal cache, or all caches.");
  345. case 'drush:search-status':
  346. return dt("Show how many items remain to be indexed for search, and the total number of items.");
  347. case 'drush:search-index':
  348. return dt("Index the remaining search items.");
  349. case 'drush:search-reindex':
  350. return dt("Force the search index to be rebuilt.");
  351. case 'drush:updatedb':
  352. return dt("Run update.php just as a web browser would.");
  353. case 'drush:rsync':
  354. return dt("Sync the entire drupal directory or a subdirectory to a <destination> 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.");
  355. case 'drush:php-eval':
  356. return dt("Run arbitrary PHP code in the context of Drupal");
  357. case 'drush:site-install':
  358. return dt("Install Drupal using specified install profile.");
  359. case 'drush:drupal-directory':
  360. 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.");
  361. case 'drush:core-cli':
  362. return dt("Enter a new shell optimized for drush use. See help for more details.");
  363. case 'error:DRUSH_DRUPAL_DB_ERROR' :
  364. $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
  365. $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");
  366. $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
  367. $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");
  368. return $message;
  369. case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR' :
  370. $message = dt("Drush was not able to start (bootstrap) Drupal.\n");
  371. $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");
  372. $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
  373. $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");
  374. return $message;
  375. break;
  376. }
  377. }
  378. // TODO: consolidate with SQL commands?
  379. function _core_site_credentials() {
  380. $status_table = _core_site_status_table();
  381. return _core_site_credential_table($status_table);
  382. }
  383. function _core_site_credential_table($status_table) {
  384. $credentials = '';
  385. foreach ($status_table as $key => $value) {
  386. $credentials .= sprintf(" %-18s: %s\n", $key, $value);
  387. }
  388. return $credentials;
  389. }
  390. function _core_site_credential_list($status_table) {
  391. $credentials = '';
  392. foreach ($status_table as $key => $value) {
  393. if (isset($value)) {
  394. $credentials .= sprintf("%s=%s\n", strtolower(str_replace(' ', '_', $key)), $value);
  395. }
  396. }
  397. return $credentials;
  398. }
  399. function _core_path_aliases($project = '') {
  400. $paths = array();
  401. $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  402. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  403. $paths['%root'] = $drupal_root;
  404. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  405. $paths['%site'] = $site_root;
  406. $paths['%modules'] = 'sites'.DIRECTORY_SEPARATOR.'all'.DIRECTORY_SEPARATOR.'modules';
  407. $paths['%themes'] = 'sites'.DIRECTORY_SEPARATOR.'all'.DIRECTORY_SEPARATOR.'themes';
  408. if (drush_drupal_major_version() >= 7) {
  409. $paths['%files'] = DrupalPublicStreamWrapper::getDirectoryPath();
  410. $paths['%private'] = DrupalPrivateStreamWrapper::getDirectoryPath();
  411. }
  412. elseif (function_exists('file_directory_path')) {
  413. $paths['%files'] = file_directory_path();
  414. }
  415. // If the 'project' parameter was specified, then search
  416. // for a project (or a few) and add its path to the path list
  417. if (!empty($project)) {
  418. foreach(explode(',', $project) as $target) {
  419. $path = drush_core_find_project_path($target);
  420. if(isset($path)) {
  421. $paths['%' . $target] = $path;
  422. }
  423. }
  424. }
  425. }
  426. }
  427. // Add in all of the global paths from $options['path-aliases']
  428. $paths = array_merge($paths, drush_get_option('path-aliases', array()));
  429. return $paths;
  430. }
  431. function _core_site_status_table($project = '') {
  432. $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  433. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  434. $status_table['Drupal version'] = drush_drupal_version();
  435. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  436. $status_table['Site URI'] = drush_get_context('DRUSH_URI');
  437. if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
  438. $status_table['Database driver'] = $creds['driver'];
  439. $status_table['Database hostname'] = $creds['host'];
  440. $status_table['Database username'] = $creds['user'];
  441. $status_table['Database name'] = $creds['name'];
  442. if (drush_get_option('show-passwords', FALSE)) {
  443. $status_table['Database password'] = $creds['pass'];
  444. }
  445. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_DATABASE) {
  446. $status_table['Database'] = dt('Connected');
  447. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_FULL) {
  448. $status_table['Drupal bootstrap'] = dt('Successful');
  449. if ($phase == DRUSH_BOOTSTRAP_DRUPAL_LOGIN) {
  450. global $user;
  451. $username = ($user->uid) ? $user->name : dt('Anonymous');
  452. $status_table['Drupal user'] = $username;
  453. }
  454. }
  455. }
  456. }
  457. }
  458. $status_table['Default theme'] = drush_theme_get_default();
  459. $status_table['Administration theme'] = drush_theme_get_admin();
  460. }
  461. if (function_exists('php_ini_loaded_file')) {
  462. // Function available on PHP >= 5.2.4, but we use it if available to help
  463. // users figure out their php.ini issues.
  464. $status_table['PHP configuration'] = php_ini_loaded_file();
  465. }
  466. $status_table['Drush version'] = DRUSH_VERSION;
  467. $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE));
  468. // None of the Status keys are in dt(); this helps with machine-parsing of status?
  469. $path_names['root'] = 'Drupal root';
  470. $path_names['site'] = 'Site path';
  471. $path_names['modules'] = 'Modules path';
  472. $path_names['themes'] = 'Themes path';
  473. $path_names['files'] = 'File directory path';
  474. $path_names['private'] = 'Private file directory path';
  475. $paths = _core_path_aliases($project);
  476. if (!empty($paths)) {
  477. foreach ($paths as $target => $one_path) {
  478. $name = $target;
  479. if (substr($name,0,1) == '%') {
  480. $name = substr($name,1);
  481. }
  482. if (array_key_exists($name, $path_names)) {
  483. $name = $path_names[$name];
  484. }
  485. $status_table[$name] = $one_path;
  486. }
  487. }
  488. // Store the paths into the '%paths' index; this will be
  489. // used by other code, but will not be included in the output
  490. // of the drush status command.
  491. $status_table['%paths'] = $paths;
  492. return $status_table;
  493. }
  494. /**
  495. * Command callback. Runs cron hooks.
  496. *
  497. * This is where the action takes place.
  498. *
  499. * In this function, all of Drupals API is (usually) available, including
  500. * any functions you have added in your own modules/themes.
  501. *
  502. * To print something to the terminal window, use drush_print().
  503. *
  504. */
  505. function drush_core_cron() {
  506. if (drupal_cron_run()) {
  507. drush_log(dt('Cron run successfully.'), 'success');
  508. }
  509. else {
  510. drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
  511. }
  512. }
  513. /**
  514. * Command callback. Provides a birds-eye view of the current Drupal
  515. * installation.
  516. */
  517. function drush_core_status() {
  518. drush_bootstrap_max();
  519. $status_table = _core_site_status_table(drush_get_option('project',''));
  520. // If args are specified, filter out any entry that is not named
  521. // (in other words, only show lines named by one of the arg values)
  522. $args = func_get_args();
  523. if (!empty($args)) {
  524. foreach ($status_table as $key => $value) {
  525. if (!_drush_core_is_named_in_array($key, $args)) {
  526. unset($status_table[$key]);
  527. }
  528. }
  529. }
  530. drush_backend_set_result($status_table);
  531. unset($status_table['%paths']);
  532. // Print either an ini-format list or a formatted ASCII table
  533. if (drush_get_option('pipe')) {
  534. if (count($status_table) == 1) {
  535. $first_value = array_shift($status_table);
  536. drush_print_pipe($first_value);
  537. }
  538. else {
  539. drush_print_pipe(_core_site_credential_list($status_table));
  540. }
  541. }
  542. else {
  543. unset($status_table['Modules path']);
  544. unset($status_table['Themes path']);
  545. drush_print_table(drush_key_value_to_array_table($status_table));
  546. }
  547. return;
  548. }
  549. function _drush_core_is_named_in_array($key, $the_array) {
  550. $is_named = FALSE;
  551. $simplified_key = str_replace(array(' ', '_', '-'), array('', '', ''), $key);
  552. foreach ($the_array as $name) {
  553. if (stristr($simplified_key, str_replace(array(' ', '_', '-'), array('', '', ''), $name))) {
  554. $is_named = TRUE;
  555. }
  556. }
  557. return $is_named;
  558. }
  559. /**
  560. * Command callback. Runs "naked" php scripts.
  561. */
  562. function drush_core_php_script() {
  563. $args = func_get_args();
  564. // Array of paths to search for scripts
  565. $searchpath['DIR'] = dirname(__FILE__);
  566. $searchpath['cwd'] = drush_cwd();
  567. // Additional script paths, specified by 'script-path' option
  568. if ($script_path = drush_get_option('script-path', FALSE)) {
  569. foreach (explode(":", $script_path) as $path) {
  570. $searchpath[] = $path;
  571. }
  572. }
  573. if (empty($args)) {
  574. // List all available scripts.
  575. $all = array();
  576. foreach($searchpath as $key => $path) {
  577. $recurse = !$key == 'cwd';
  578. $all = array_merge( $all , array_keys(drush_scan_directory($path, '/\.php$/', array('.', '..', 'CVS'), NULL, $recurse)) );
  579. }
  580. drush_print(implode("\n", $all));
  581. }
  582. else {
  583. // Execute the specified script.
  584. $script = $args[0];
  585. if (!preg_match('/\.php$/i', $script)) {
  586. $script .= '.php';
  587. }
  588. $found = FALSE;
  589. foreach($searchpath as $path) {
  590. $script_filename = $path . '/' . $script;
  591. if (file_exists($script_filename)) {
  592. include($script_filename);
  593. $found = TRUE;
  594. break;
  595. }
  596. $all[] = $script_filename;
  597. }
  598. if (!$found) {
  599. drush_set_error('Script not found.', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
  600. }
  601. }
  602. }
  603. function drush_core_php_eval($command) {
  604. eval($command . ';');
  605. }
  606. /**
  607. * Process sets from the specified batch.
  608. *
  609. * This is the default batch processor that will be used if the $command parameter
  610. * to drush_backend_batch_process() has not been specified.
  611. */
  612. function drush_core_batch_process($id) {
  613. drush_batch_command($id);
  614. }
  615. /**
  616. * Process outstanding updates during updatedb.
  617. *
  618. * This is a batch processing command that makes use of the drush_backend_invoke
  619. * api.
  620. *
  621. * This command includes the version specific update engine, which correctly
  622. * initialises the environment to be able to successfully handle minor and major
  623. * upgrades.
  624. */
  625. function drush_core_updatedb_batch_process($id) {
  626. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  627. _update_batch_command($id);
  628. }
  629. function _drush_core_directory($target = 'root') {
  630. // Normalize to a sitealias in the target.
  631. $normalized_target = $target;
  632. if (strpos($target, ':') === FALSE) {
  633. if (substr($target,0,1) == '@') {
  634. $normalized_target = $target; // . ':%site';
  635. }
  636. else {
  637. // @self makes no sense before 'site' level.
  638. if(!drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) {
  639. return FALSE;
  640. }
  641. $normalized_target = '@self:';
  642. if (substr($target,0,1) != '%') {
  643. $normalized_target .= '%';
  644. }
  645. $normalized_target .= $target;
  646. }
  647. }
  648. $additional_options = array();
  649. $values = drush_sitealias_evaluate_path($normalized_target, $additional_options);
  650. if (isset($values['path'])) {
  651. // Hurray, we found the destination
  652. return $values['path'];
  653. }
  654. return NULL;
  655. }
  656. function drush_core_drupal_directory($target = 'root') {
  657. $path = _drush_core_directory($target);
  658. if (isset($path)) {
  659. drush_print($path);
  660. }
  661. else {
  662. return drush_set_error(dt('Core directory path !target not found.', array('!target' => $target)));
  663. }
  664. return TRUE;
  665. }
  666. function drush_core_find_project_path($target) {
  667. $theme_suffix = drush_drupal_major_version() >= 6 ? '.info' : '/style.css';
  668. $masks = array(
  669. conf_path() . '/modules' => "/^$target.module/",
  670. 'profiles/default/modules' => "/^$target.module/", // Too early for variable_get('install_profile', 'default'); Just use default.
  671. 'sites/all/modules' => "/^$target.module/", // Add all module paths, even disabled modules.
  672. conf_path() . '/themes' => "/^$target" . "$theme_suffix/",
  673. 'sites/all/themes' => "/^$target" . "$theme_suffix/",
  674. );
  675. $files = array();
  676. foreach ($masks as $key => $mask) {
  677. if ($files = drush_scan_directory("$key", $mask, array('..', '.', 'CVS', '.svn', '.bzr'), 0, TRUE, 'name')) {
  678. // Just use the first match.
  679. $file = reset($files);
  680. return drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename);
  681. }
  682. }
  683. return NULL;
  684. }
  685. function drush_core_cli() {
  686. drush_bootstrap_max();
  687. // Do not allow cli to start recursively, or from backend invoke.
  688. if (drush_get_option('in-cli',FALSE)) {
  689. return drush_set_error(dt('Already in drush core-cli; press control-d to exit.'));
  690. }
  691. if (drush_get_context('DRUSH_BACKEND')) {
  692. return drush_set_error(dt('Cannot run drush core-cli from non-interactive mode; aborting.'));
  693. }
  694. // Make sure that we call drush the same way that we were called.
  695. $drush_command = DRUSH_COMMAND.' --in-cli';
  696. $bashrc_data = implode("/n/n", drush_command_invoke_all('cli_bashrc', $drush_command));
  697. // Before entering the new bash script, cd to the current site root,
  698. // if any. This will make our default site for drush match the
  699. // currently bootstrapped site (at least until the user cd's away).
  700. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  701. chdir($site_root);
  702. }
  703. // Print our entire bashrc file in verbose mode
  704. if (drush_get_context('DRUSH_VERBOSE')) {
  705. drush_print($bashrc_data);
  706. }
  707. drush_print("Entering the drush cli. Use CONTROL-D to exit.");
  708. drush_print("Type 'help' for help.");
  709. // Save out bashrc in a temporary file and launch bash.
  710. // control-d to exit. The temp file will be deleted after
  711. // we exit.
  712. $bashrc = drush_save_data_to_temp_file($bashrc_data);
  713. drush_op('system', 'bash --rcfile ' . $bashrc . ' > `tty`');
  714. }
  715. // Implement our own hook_cli_bashrc()
  716. function core_cli_bashrc($drush_command) {
  717. // Set up our default bashrc file for the drush cli
  718. $bashrc_data = <<<EOD
  719. PS1="drush> "
  720. alias on="$drush_command"
  721. alias drush="$drush_command"
  722. DRUSH_CLI=true
  723. function cdd() {
  724. TARGET=
  725. PARAM=\$1
  726. if [ \$# -gt 1 ] ; then
  727. TARGET=\$1
  728. PARAM=\$2
  729. fi
  730. DEST=`drush \$TARGET drupal-directory \$PARAM`
  731. if [ \$? != 0 ] || [ -z "\$DEST" ]
  732. then
  733. echo "Target \$1 was not found."
  734. else
  735. echo "cd \$DEST"
  736. cd \$DEST;
  737. fi
  738. }
  739. function lsd() {
  740. TARGET=
  741. PARAM=\$1
  742. if [ \$# -gt 1 ] ; then
  743. TARGET=\$1
  744. PARAM=\$2
  745. fi
  746. DEST=`drush \$TARGET drupal-directory \$PARAM`
  747. if [ \$? != 0 ] || [ -z "\$DEST" ]
  748. then
  749. echo "Target \$1 was not found."
  750. else
  751. echo "ls \$DEST"
  752. ls \$DEST;
  753. fi
  754. }
  755. EOD;
  756. // Add aliases for all of our commands
  757. $commands = drush_get_commands();
  758. foreach ($commands as $key => $command) {
  759. // Filter out old commands that still have spaces
  760. if (strpos($key, ' ') === FALSE) {
  761. $bashrc_data .= "function $key() {\n $drush_command $key \"\$@\"\n}\n";
  762. }
  763. }
  764. return $bashrc_data;
  765. }