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_core_config_complete Command argument complete callback.
core_core_rsync_complete Command argument complete callback.
core_drush_command Implementation of hook_drush_command().
core_drush_engine_drupal
core_drush_engine_type_info Implementation of hook_drush_engine_type_info().
core_drush_help Implementation of hook_drush_help().
core_help_complete Command argument complete callback.
core_site_install_complete Command argument complete callback.
drush_core_batch_process Process sets from the specified batch.
drush_core_config Command callback. Edit drushrc and alias files.
drush_core_config_load
drush_core_cron Command callback. Runs all cron hooks.
drush_core_drupal_directory Command callback.
drush_core_execute Command callback. Execute specified shell code. Often used by shell aliases that start with !.
drush_core_find_project_path
drush_core_global_options
drush_core_php_eval
drush_core_php_script Command callback. Runs "naked" php scripts and drush "shebang" scripts ("#!/usr/bin/env drush").
drush_core_quick_drupal Callback for core-quick-drupal command.
drush_core_quick_drupal_options Include options and engines for core-quick-drupal command, aggregated from other command options that are available. We prefix option descriptons, to make the long list more navigable.
drush_core_requirements Command callback. Provides information from the 'Status Reports' admin page.
drush_core_self_update
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_core_version Called for `drush version` or `drush --version`
_core_path_aliases
_core_site_credentials
_core_site_credential_list
_core_site_credential_table
_core_site_status_table
_drush_core_config_php_ini_files
_drush_core_directory Given a target (e.g. @site:%modules), return the evaluated directory path.
_drush_core_eval_shebang_script
_drush_core_execute_cmd Helper function for drush_core_execute: run one shell command
_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. See `drush help help` for more options.',
  23. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  24. 'allow-additional-options' => TRUE,
  25. 'options' => array(
  26. 'sort' => 'Sort commands in alphabetical order. drush waits for full bootstrap before printing any commands when this option is used.',
  27. 'filter' => array(
  28. 'description' => 'Restrict command list to those commands defined in the specified file. Omit value to choose from a list of names.',
  29. 'example-value' => 'category',
  30. 'value' => 'optional',
  31. ),
  32. 'format' => 'Format to output . Allowed values are: json, export, html.',
  33. 'html' => 'Print help for all commands in HTML format. Deprecated - see --format option.',
  34. 'pipe' => 'A list of available commands, one per line.',
  35. ),
  36. 'arguments' => array(
  37. 'command' => 'A command name, or command alias.',
  38. ),
  39. 'examples' => array(
  40. 'drush' => 'List all commands.',
  41. 'drush --filter=devel_generate' => 'Show only commands defined in devel_generate.drush.inc',
  42. 'drush help pm-download' => 'Show help for one command.',
  43. 'drush help dl' => 'Show help for one command using an alias.',
  44. ),
  45. 'topics' => array('docs-readme'),
  46. );
  47. $items['version'] = array(
  48. 'description' => 'Show drush version.',
  49. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  50. 'options' => array(
  51. 'pipe' => 'Print just the version number, and nothing else.',
  52. 'self-update' => 'Check for pending updates to Drush itself. Set to 0 to disable.',
  53. ),
  54. );
  55. $items['self-update'] = array(
  56. 'description' => 'Check to see if there is a newer Drush release available.',
  57. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  58. 'aliases' => array('selfupdate'),
  59. );
  60. $items['core-cron'] = array(
  61. 'description' => 'Run all cron hooks in all active modules for specified site.',
  62. 'aliases' => array('cron'),
  63. 'topics' => array('docs-cron'),
  64. );
  65. $items['updatedb'] = array(
  66. 'description' => 'Apply any database updates required (as with running update.php).',
  67. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  68. 'aliases' => array('updb'),
  69. );
  70. $items['core-config'] = array(
  71. 'description' => 'Edit drushrc, site alias, and Drupal settings.php files.',
  72. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  73. 'arguments' => array(
  74. 'filter' => 'A substring for filtering the list of files. Omit this argument to choose from loaded files.',
  75. ),
  76. 'options' => array(
  77. 'bg' => 'Run editor in the background. Does not work with editors such as `vi` that run in the terminal.',
  78. ),
  79. 'examples' => array(
  80. 'drush core-config' => 'Pick from a list of config/alias/settings files. Open selected in editor.',
  81. 'drush --bg core-config' => 'Return to shell prompt as soon as the editor window opens.',
  82. 'drush core-config etc' => 'Edit the global configuration file.',
  83. 'drush core-config demo.alia' => 'Edit a particular alias file.',
  84. 'drush core-config sett' => 'Edit settings.php for the current Drupal site.',
  85. 'drush core-config --choice=2' => 'Edit the second file in the choice list.',
  86. ),
  87. 'aliases' => array('conf', 'config'),
  88. );
  89. $items['core-status'] = array(
  90. 'description' => 'Provides a birds-eye view of the current Drupal installation, if any.',
  91. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  92. 'aliases' => array('status', 'st'),
  93. 'examples' => array(
  94. 'drush core-status version' => 'Show all status lines that contain version information.',
  95. 'drush core-status --pipe' => 'A list key=value items separated by line breaks.',
  96. 'drush core-status drush-version --pipe' => 'Emit just the drush version with no label.',
  97. ),
  98. 'arguments' => array(
  99. 'item' => 'Optional. The status item line(s) to display.',
  100. ),
  101. 'options' => array(
  102. 'show-passwords' => 'Show database password.',
  103. 'full' => 'Show all drush aliases in the report, even if there are a lot.',
  104. 'project' => array(
  105. 'description' => 'One or more projects that should be added to the path list',
  106. 'example-value' => 'foo,bar',
  107. ),
  108. ),
  109. 'topics' => array('docs-readme'),
  110. );
  111. $items['core-requirements'] = array(
  112. 'description' => 'Provides information about things that may be wrong in your Drupal installation, if any.',
  113. 'aliases' => array('status-report','rq'),
  114. 'examples' => array(
  115. 'drush core-requirements' => 'Show all status lines from the Status Report admin page.',
  116. 'drush core-requirements --severity=2' => 'Show only the red lines from the Status Report admin page.',
  117. 'drush core-requirements --pipe' => 'Print out a short report in the format "identifier: severity", where severity 2=error, 1=warning, and 0/-1=OK',
  118. ),
  119. 'options' => array(
  120. 'severity' => array(
  121. 'description' => 'Only show status report messages with a severity greater than or equal to the specified value.',
  122. 'value' => 'required',
  123. 'example-value' => '3',
  124. ),
  125. 'ignore' => 'Comma-separated list of requirements to remove from output. Run with --pipe to see key values to use.',
  126. ),
  127. );
  128. $items['php-eval'] = array(
  129. 'description' => 'Evaluate arbitrary php code after bootstrapping Drupal (if available).',
  130. 'examples' => array(
  131. 'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.',
  132. ),
  133. 'arguments' => array(
  134. 'code' => 'PHP code',
  135. ),
  136. 'required-arguments' => TRUE,
  137. 'allow-additional-options' => TRUE,
  138. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  139. 'aliases' => array('eval', 'ev'),
  140. );
  141. $items['php-script'] = array(
  142. 'description' => "Run php script(s).",
  143. 'examples' => array(
  144. 'drush php-script scratch' => 'Run scratch.php script. See commands/core directory.',
  145. 'drush php-script example --script-path=/path/to/scripts:/another/path' => 'Run script from specified paths',
  146. 'drush php-script' => 'List all available scripts.',
  147. '' => '',
  148. "#!/usr/bin/env drush\n<?php\nvariable_set('key', drush_shift());" => "Execute php code with a full Drupal bootstrap directly from a shell script.",
  149. ),
  150. 'arguments' => array(
  151. '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.',
  152. ),
  153. 'options' => array(
  154. 'script-path' => array(
  155. 'description' => "Additional paths to search for scripts, separated by : (Unix-based systems) or ; (Windows).",
  156. 'example-value' => '~/scripts',
  157. ),
  158. ),
  159. 'allow-additional-options' => TRUE,
  160. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  161. 'aliases' => array('scr'),
  162. 'topics' => array('docs-examplescript', 'docs-scripts'),
  163. );
  164. $items['core-execute'] = array(
  165. 'description' => 'Execute a shell command. Usually used with a site alias.',
  166. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  167. 'arguments' => array(
  168. 'command' => 'The shell command to be executed.',
  169. ),
  170. 'options' => drush_shell_exec_proc_build_options(),
  171. 'required-arguments' => TRUE,
  172. 'allow-additional-options' => TRUE,
  173. 'handle-remote-commands' => TRUE,
  174. 'strict-option-handling' => TRUE,
  175. 'examples' => array(
  176. 'drush core-execute git pull origin rebase' => 'Retrieve latest code from git',
  177. ),
  178. 'aliases' => array('exec', 'execute'),
  179. 'topics' => array('docs-aliases'),
  180. );
  181. $items['core-rsync'] = array(
  182. 'description' => 'Rsync the Drupal tree to/from another server using ssh.',
  183. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  184. 'arguments' => array(
  185. 'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  186. 'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  187. ),
  188. 'options' => array(
  189. 'mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz. Default is -akz.',
  190. 'exclude-conf' => 'Excludes settings.php from being rsynced. Default.',
  191. 'include-conf' => 'Allow settings.php to be rsynced. Default is to exclude settings.php.',
  192. 'include-vcs' => 'Include special version control directories (e.g. .svn). Default is to exclude vcs files.',
  193. 'exclude-files' => 'Exclude the files directory.',
  194. 'exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
  195. '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"',
  196. 'exclude-paths' => 'List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).',
  197. 'include-paths' => 'List of paths to include, seperated by : (Unix-based systems) or ; (Windows).',
  198. '{rsync-option-name}' => "Replace {rsync-option-name} with the rsync option (or option='value') that you would like to pass through to rsync. Examples include --delete, --exclude=*.sql, --filter='merge /etc/rsync/default.rules', etc. See the rsync documentation for a complete explaination of all the rsync options and values.",
  199. ),
  200. 'strict-option-handling' => TRUE,
  201. 'examples' => array(
  202. 'drush rsync @dev @stage' => 'Rsync Drupal root from Drush alias dev to the alias stage (one of which must be local).',
  203. 'drush rsync ./ @stage:%files/img' => 'Rsync all files in the current directory to the \'img\' directory in the file storage folder on the Drush alias stage.',
  204. 'drush -s rsync @dev @stage --exclude=*.sql --delete' => "Simulate Rsync Drupal root from the Drush alias dev to the alias stage (one of which must be local), excluding all files that match the filter '*.sql' and delete all files on the destination that are no longer on the source.",
  205. ),
  206. 'aliases' => array('rsync'),
  207. 'topics' => array('docs-aliases'),
  208. );
  209. $items['site-install'] = array(
  210. 'description' => 'Install Drupal along with modules/themes/configuration using the specified install profile.',
  211. 'arguments' => array(
  212. 'profile' => 'the install profile you wish to run. defaults to \'default\' in D6, \'standard\' in D7+',
  213. 'key=value...' => 'any additional settings you wish to pass to the profile. Fully supported on D7+, partially supported on D6 (single step configure forms only). The key is in the form [form name].[parameter name] on D7 or just [parameter name] on D6.',
  214. ),
  215. 'options' => array(
  216. 'db-url' => array(
  217. 'description' => 'A Drupal 6 style database URL. Only required for initial install - not re-install.',
  218. 'example-value' => 'mysql://root:pass@127.0.0.1/db',
  219. ),
  220. 'db-prefix' => 'An optional table prefix to use for initial install. Can be a key-value array of tables/prefixes in a drushrc file (not the command line).',
  221. 'db-su' => array(
  222. 'description' => 'Account to use when creating a new database. Must have Grant permission (mysql only). Optional.',
  223. 'example-value' => 'root',
  224. ),
  225. 'db-su-pw' => array(
  226. 'description' => 'Password for the "db-su" account. Optional.',
  227. 'example-value' => 'pass',
  228. ),
  229. 'account-name' => 'uid1 name. Defaults to admin',
  230. 'account-pass' => 'uid1 pass. Defaults to a randomly generated password. If desired, set a fixed password in drushrc.php.',
  231. 'account-mail' => 'uid1 email. Defaults to admin@example.com',
  232. 'locale' => array(
  233. 'description' => 'A short language code. Sets the default site language. Language files must already be present. You may use download command to get them.',
  234. 'example-value' => 'en-GB',
  235. ),
  236. 'clean-url'=> 'Defaults to 1',
  237. 'site-name' => 'Defaults to Site-Install',
  238. 'site-mail' => 'From: for system mailings. Defaults to admin@example.com',
  239. 'sites-subdir' => array(
  240. 'description' => "Name of directory under 'sites' which should be created. Only needed when the subdirectory does not already exist. Defaults to 'default'",
  241. 'value' => 'required',
  242. 'example-value' => 'directory_name',
  243. ),
  244. ),
  245. 'examples' => array(
  246. 'drush site-install expert --locale=uk' => '(Re)install using the expert install profile. Set default language to Ukranian.',
  247. 'drush site-install --db-url=mysql://root:pass@localhost:port/dbname' => 'Install using the specified DB params.',
  248. 'drush site-install --db-url=sqlite://sites/example.com/files/.ht.sqlite' => 'Install using SQLite (D7+ only).',
  249. 'drush site-install --account-name=joe --account-pass=mom' => 'Re-install with specified uid1 credentials.',
  250. 'drush site-install standard install_configure_form.site_default_country=FR my_profile_form.my_settings.key=value' => 'Pass additional arguments to the profile (D7 example shown here - for D6, omit the form id).',
  251. "drush site-install install_configure_form.update_status_module='array(FALSE,FALSE)'" => 'Disable email notification during install and later. If your server has no smtp, this gets rid of an error during install.',
  252. ),
  253. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
  254. 'aliases' => array('si'),
  255. );
  256. $items['drupal-directory'] = array(
  257. 'description' => 'Return path to a given module/theme directory.',
  258. 'arguments' => array(
  259. '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.',
  260. ),
  261. 'options' => array(
  262. 'component' => "The portion of the evaluated path to return. Defaults to 'path'; 'name' returns the site alias of the target.",
  263. 'local' => "Reject any target that specifies a remote site.",
  264. ),
  265. 'examples' => array(
  266. 'cd `drush dd devel`' => 'Navigate into the devel module directory',
  267. 'cd `drush dd` ' => 'Navigate to the root of your Drupal site',
  268. 'cd `drush dd files`' => 'Navigate to the files directory.',
  269. 'drush dd @alias:%files' => 'Print the path to the files directory on the site @alias.',
  270. 'edit `drush dd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)",
  271. ),
  272. 'aliases' => array('dd'),
  273. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  274. );
  275. $items['batch-process'] = array(
  276. 'description' => 'Process operations in the specified batch set',
  277. 'hidden' => TRUE,
  278. 'arguments' => array(
  279. 'batch-id' => 'The batch id that will be processed.',
  280. ),
  281. 'required-arguments' => TRUE,
  282. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
  283. );
  284. $items['updatedb-batch-process'] = array(
  285. 'description' => 'Perform update functions',
  286. 'hidden' => TRUE,
  287. 'arguments' => array(
  288. 'batch-id' => 'The batch id that will be processed',
  289. ),
  290. 'required-arguments' => TRUE,
  291. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  292. );
  293. $items['core-global-options'] = array(
  294. 'description' => 'All global options',
  295. 'hidden' => TRUE,
  296. 'topic' => TRUE,
  297. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  298. );
  299. $items['core-quick-drupal'] = array(
  300. 'description' => 'Download, install, serve and login to Drupal with minimal configuration and dependencies.',
  301. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  302. 'aliases' => array('qd'),
  303. 'arguments' => array(
  304. 'site' => 'Short name for the site to be created - used as a directory name and as sqlite file name. Optional - if omitted timestamped "quick-drupal" directory will be used instead.',
  305. 'projects' => 'A list of projects to download into the new site. If projects contain extensions (modules or themes) with the same name they will be enabled by default. See --enable option to control this behaviour further.',
  306. ),
  307. 'examples' => array(
  308. 'drush qd' => 'Download and install stable release of Drupal into a timestamped directory, start server, and open the site logged in as admin.',
  309. 'drush qd --profile=minimal --dev --cache --core=drupal-8.x --yes' => 'Fire up dev release of Drupal site with minimal install profile.',
  310. 'drush qd testsite devel --server=:8081/admin --browser=firefox --cache --yes' => 'Fire up stable release (using the cache) of Drupal site called "testsite", download and enable devel module, start a server on port 8081 and open /admin in firefox.',
  311. 'drush qd commercesite --core=commerce_kickstart --profile=commerce_kickstart --cache --yes --watchdog' => 'Download and install the "Commerce Kickstart" distribution/install profile, display watchdog messages on the server console.',
  312. 'drush qd --makefile=mysite.make' => 'Create and install a site from a makefile.',
  313. ),
  314. );
  315. // Add in options/engines.
  316. drush_core_quick_drupal_options($items);
  317. return $items;
  318. }
  319. /**
  320. * Command argument complete callback.
  321. *
  322. * @return
  323. * Array of available command names.
  324. */
  325. function core_help_complete() {
  326. return array('values' => array_keys(drush_get_commands()));
  327. }
  328. /**
  329. * Command argument complete callback.
  330. *
  331. * @return
  332. * Array of available profile names.
  333. */
  334. function core_site_install_complete() {
  335. $max = drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_ROOT);
  336. if ($max >= DRUSH_BOOTSTRAP_DRUPAL_ROOT) {
  337. return array('values' => array_keys(drush_find_profiles(DRUPAL_ROOT)));
  338. }
  339. }
  340. /**
  341. * Command argument complete callback.
  342. *
  343. * @return
  344. * Array of available site aliases.
  345. */
  346. function core_core_rsync_complete() {
  347. return array('values' => array_keys(_drush_sitealias_all_list()));
  348. }
  349. /**
  350. * @defgroup engines Engine types
  351. * @{
  352. */
  353. /**
  354. * Implementation of hook_drush_engine_type_info().
  355. */
  356. function core_drush_engine_type_info() {
  357. return array(
  358. 'drupal' => array(
  359. ),
  360. );
  361. }
  362. function core_drush_engine_drupal() {
  363. $engines = array();
  364. $engines['batch'] = array();
  365. $engines['update'] = array();
  366. $engines['environment'] = array();
  367. $engines['site_install'] = array();
  368. return $engines;
  369. }
  370. /**
  371. * @} End of "Engine types".
  372. */
  373. /**
  374. * Command handler. Execute update.php code from drush.
  375. */
  376. function drush_core_updatedb() {
  377. if (drush_get_context('DRUSH_SIMULATE')) {
  378. drush_log(dt('updatedb command does not support --simulate option.'), 'ok');
  379. return TRUE;
  380. }
  381. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  382. if (update_main() === FALSE) {
  383. return FALSE;
  384. }
  385. // Clear all caches in a new process. We just performed major surgery.
  386. drush_invoke_process('@self', 'cache-clear', array('all'));
  387. drush_log(dt('Finished performing updates.'), 'ok');
  388. }
  389. /**
  390. * Implementation of hook_drush_help().
  391. *
  392. * This function is called whenever a drush user calls
  393. * 'drush help <name-of-your-command>'
  394. *
  395. * @param
  396. * A string with the help section (prepend with 'drush:')
  397. *
  398. * @return
  399. * A string with the help text for your command.
  400. */
  401. function core_drush_help($section) {
  402. switch ($section) {
  403. case 'meta:core:title':
  404. return dt("Core drush commands");
  405. case 'drush:help':
  406. return dt("Drush provides an extensive help system that describes both drush commands and topics of general interest. Use `drush help --filter` to present a list of command categories to view, and `drush topic` for a list of topics that go more in-depth on how to use and extend drush.");
  407. case 'drush:php-script':
  408. 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 that's more self-documenting. Drush provides commandline options to the script via drush_get_option('option-name'), and commandline arguments can be accessed either via drush_get_arguments(), which returns all arguments in an array, or drush_shift(), which removes the next argument from the list and returns it.");
  409. case 'drush:rsync':
  410. return dt("Sync the entire drupal directory or a subdirectory to a <destination> using ssh. Excludes reserved files and directories for supported VCSs. Useful for pushing copies of your tree to a staging server, or retrieving a files directory from a remote site. Relative paths start from the Drupal root directory if a site alias is used; otherwise they start from the current working directory.");
  411. case 'drush:drupal-directory':
  412. return dt("Return the filesystem path for modules/themes and other key folders.");
  413. case 'error:DRUSH_DRUPAL_DB_ERROR':
  414. $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
  415. $message .= dt("Hint: This may occur when Drush is trying to:\n");
  416. $message .= dt(" * bootstrap a site that has not been installed or does not have a configured database. In this case you can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line. See `drush topic docs-aliases` for details.\n");
  417. $message .= dt(" * connect the database through a socket. The socket file may be wrong or the php-cli may have no access to it in a jailed shell. See http://drupal.org/node/1428638 for details.\n");
  418. $message .= dt("\nDrush was attempting to connect to: \n!credentials\n", array('!credentials' => _core_site_credentials()));
  419. return $message;
  420. case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR':
  421. $message = dt("Drush was not able to start (bootstrap) Drupal.\n");
  422. $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");
  423. $message .= dt("\nDrush was attempting to connect to: \n!credentials\n", array('!credentials' => _core_site_credentials()));
  424. return $message;
  425. break;
  426. }
  427. }
  428. // TODO: consolidate with SQL commands?
  429. function _core_site_credentials() {
  430. $status_table = _core_site_status_table();
  431. return _core_site_credential_table($status_table);
  432. }
  433. function _core_site_credential_table($status_table) {
  434. $credentials = '';
  435. foreach ($status_table as $key => $value) {
  436. $credentials .= sprintf(" %-18s: %s\n", $key, $value);
  437. }
  438. return $credentials;
  439. }
  440. function _core_site_credential_list($status_table) {
  441. $credentials = '';
  442. foreach ($status_table as $key => $value) {
  443. if (isset($value)) {
  444. $credentials .= sprintf("%s=%s\n", strtolower(str_replace(' ', '_', $key)), $value);
  445. }
  446. }
  447. return $credentials;
  448. }
  449. function _core_path_aliases($project = '') {
  450. $paths = array();
  451. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  452. $paths['%root'] = $drupal_root;
  453. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  454. $paths['%site'] = $site_root;
  455. if (is_dir($modules_path = conf_path() . '/modules')) {
  456. $paths['%modules'] = $modules_path;
  457. }
  458. else {
  459. $paths['%modules'] = 'sites/all/modules';
  460. }
  461. if (is_dir($themes_path = conf_path() . '/themes')) {
  462. $paths['%themes'] = $themes_path;
  463. }
  464. else {
  465. $paths['%themes'] = 'sites/all/themes';
  466. }
  467. if (drush_drupal_major_version() >= 7) {
  468. if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_SITE) {
  469. $paths['%files'] = variable_get('file_public_path', conf_path() . '/files');
  470. $private_path = variable_get('file_private_path', FALSE);
  471. if (!empty($private_path)) {
  472. $paths['%private'] = $private_path;
  473. }
  474. }
  475. }
  476. elseif (function_exists('file_directory_path')) {
  477. $paths['%files'] = file_directory_path();
  478. }
  479. if (function_exists('file_directory_temp')) {
  480. $paths['%temp'] = file_directory_temp();
  481. }
  482. // If the 'project' parameter was specified, then search
  483. // for a project (or a few) and add its path to the path list
  484. if (!empty($project)) {
  485. foreach(explode(',', $project) as $target) {
  486. $path = drush_core_find_project_path($target);
  487. if(isset($path)) {
  488. $paths['%' . $target] = $path;
  489. }
  490. }
  491. }
  492. }
  493. }
  494. // Add in all of the global paths from $options['path-aliases']
  495. $paths = array_merge($paths, drush_get_option('path-aliases', array()));
  496. return $paths;
  497. }
  498. function _core_site_status_table($project = '', $full = FALSE) {
  499. $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  500. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  501. $status_table['Drupal version'] = drush_drupal_version();
  502. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  503. $status_table['Site URI'] = drush_get_context('DRUSH_URI');
  504. if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
  505. $status_table['Database driver'] = $creds['driver'];
  506. if (!empty($creds['unix_socket'])) {
  507. $status_table['Database socket'] = $creds['unix_socket'];
  508. }
  509. else {
  510. $status_table['Database hostname'] = $creds['host'];
  511. }
  512. $status_table['Database username'] = $creds['user'];
  513. $status_table['Database name'] = $creds['name'];
  514. if (drush_get_option('show-passwords', FALSE)) {
  515. $status_table['Database password'] = $creds['pass'];
  516. }
  517. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_DATABASE) {
  518. $status_table['Database'] = dt('Connected');
  519. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_FULL) {
  520. $status_table['Drupal bootstrap'] = dt('Successful');
  521. if ($phase == DRUSH_BOOTSTRAP_DRUPAL_LOGIN) {
  522. global $user;
  523. $username = ($user->uid) ? $user->name : dt('Anonymous');
  524. $status_table['Drupal user'] = $username;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. $status_table['Default theme'] = drush_theme_get_default();
  531. $status_table['Administration theme'] = drush_theme_get_admin();
  532. }
  533. if ($php_ini_files = _drush_core_config_php_ini_files()) {
  534. $status_table['PHP configuration'] = implode(' ', $php_ini_files);
  535. }
  536. $status_table['Drush version'] = DRUSH_VERSION;
  537. $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE));
  538. $alias_files = _drush_sitealias_find_alias_files();
  539. if (!empty($alias_files)) {
  540. if ($full || count($alias_files) < 24) {
  541. $status_table['Drush alias files'] = implode(' ', $alias_files);
  542. }
  543. else {
  544. $status_table['Drush alias files'] = dt("There are !count alias files. Run with --full to see the full list.", array('!count' => count($alias_files)));
  545. }
  546. }
  547. // None of the Status keys are in dt(); this helps with machine-parsing of status?
  548. $path_names['root'] = 'Drupal root';
  549. $path_names['site'] = 'Site path';
  550. $path_names['modules'] = 'Modules path';
  551. $path_names['themes'] = 'Themes path';
  552. $path_names['files'] = 'File directory path';
  553. $path_names['private'] = 'Private file directory path';
  554. $path_names['temp'] = 'Temporary file directory path';
  555. $paths = _core_path_aliases($project);
  556. if (!empty($paths)) {
  557. foreach ($paths as $target => $one_path) {
  558. $name = $target;
  559. if (substr($name,0,1) == '%') {
  560. $name = substr($name,1);
  561. }
  562. if (array_key_exists($name, $path_names)) {
  563. $name = $path_names[$name];
  564. }
  565. $status_table[$name] = $one_path;
  566. }
  567. }
  568. // Store the paths into the '%paths' index; this will be
  569. // used by other code, but will not be included in the output
  570. // of the drush status command.
  571. $status_table['%paths'] = $paths;
  572. return $status_table;
  573. }
  574. /**
  575. * Command callback. Runs all cron hooks.
  576. */
  577. function drush_core_cron() {
  578. if (drupal_cron_run()) {
  579. drush_log(dt('Cron run successful.'), 'success');
  580. }
  581. else {
  582. return drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
  583. }
  584. }
  585. /**
  586. * Command callback. Edit drushrc and alias files.
  587. */
  588. function drush_core_config($filter = NULL) {
  589. $all = drush_core_config_load();
  590. // Run in the foreground unless --bg is specified.
  591. $bg = '';
  592. if (drush_get_option('bg', FALSE)) {
  593. $bg = '&';
  594. }
  595. // Apply any filter that was supplied.
  596. if ($filter) {
  597. foreach ($all as $key => $file) {
  598. if (strpos($file, $filter) === FALSE) {
  599. unset($all[$key]);
  600. }
  601. }
  602. }
  603. $all = drush_map_assoc(array_values($all));
  604. $exec = drush_get_editor();
  605. if (count($all) == 1) {
  606. $filepath = current($all);
  607. return drush_shell_exec_interactive($exec, $filepath, $filepath);
  608. }
  609. else {
  610. $choice = drush_choice($all, 'Enter a number to choose which file to edit.', '!key');
  611. if ($choice !== FALSE) {
  612. $filepath = $all[$choice];
  613. drush_shell_exec_interactive($exec, $filepath, $filepath);
  614. }
  615. }
  616. }
  617. /**
  618. * Command argument complete callback.
  619. *
  620. * @return
  621. * Array of available configuration files for editing.
  622. */
  623. function core_core_config_complete() {
  624. return array('values' => drush_core_config_load(FALSE));
  625. }
  626. function drush_core_config_load($headers = TRUE) {
  627. $php_header = $php = $rcs_header = $rcs = $aliases_header = $aliases = $drupal_header = $drupal = array();
  628. $php = _drush_core_config_php_ini_files();
  629. if (!empty($php)) {
  630. if ($headers) {
  631. $php_header = array('phpini' => '-- PHP ini files --');
  632. }
  633. }
  634. drush_sitealias_load_all();
  635. if ($rcs = drush_get_context_options('context-path', TRUE)) {
  636. if ($headers) {
  637. $rcs_header = array('drushrc' => '-- Drushrc --');
  638. }
  639. }
  640. if ($aliases = drush_get_context('drush-alias-files')) {
  641. if ($headers) {
  642. $aliases_header = array('aliases' => '-- Aliases --');
  643. }
  644. }
  645. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  646. $drupal = array_merge(array(realpath($site_root . '/settings.php'), realpath(DRUPAL_ROOT . '/.htaccess')));
  647. if ($headers) {
  648. $drupal_header = array('drupal' => '-- Drupal --');
  649. }
  650. }
  651. return array_merge($php_header, $php, $rcs_header, $rcs, $aliases_header, $aliases, $drupal_header, $drupal);
  652. }
  653. function _drush_core_config_php_ini_files() {
  654. $ini_files = array();
  655. // Function available on PHP >= 5.2.4, but we use it if available to help
  656. // users figure out their php.ini issues.
  657. if (function_exists('php_ini_loaded_file')) {
  658. $ini_files[] = php_ini_loaded_file();
  659. }
  660. foreach (array(DRUSH_BASE_PATH, '/etc/drush', drush_server_home() . '/.drush') as $ini_dir) {
  661. if (file_exists($ini_dir . "/php.ini")) {
  662. $ini_files[] = realpath($ini_dir . "/php.ini");
  663. }
  664. if (file_exists($ini_dir . "/drush.ini")) {
  665. $ini_files[] = realpath($ini_dir . "/drush.ini");
  666. }
  667. }
  668. return $ini_files;
  669. }
  670. /**
  671. * Command callback. Provides information from the 'Status Reports' admin page.
  672. */
  673. function drush_core_requirements() {
  674. include_once DRUSH_DRUPAL_CORE . '/includes/install.inc';
  675. $severities = array(
  676. REQUIREMENT_INFO => t('Info'),
  677. REQUIREMENT_OK => t('OK'),
  678. REQUIREMENT_WARNING => t('Warning'),
  679. REQUIREMENT_ERROR => t('Error'),
  680. );
  681. drupal_load_updates();
  682. $requirements = module_invoke_all('requirements', 'runtime');
  683. $ignore_requirements = drush_get_option_list('ignore');
  684. foreach ($ignore_requirements as $ignore) {
  685. unset($requirements[$ignore]);
  686. }
  687. ksort($requirements);
  688. $min_severity = drush_get_option('severity', -1);
  689. $rows[] = array('Title', 'Severity', 'Description');
  690. foreach($requirements as $key => $info) {
  691. $severity = array_key_exists('severity', $info) ? $info['severity'] : -1;
  692. if ($severity >= $min_severity) {
  693. drush_print_pipe($key . ': ' . $severity . "\n");
  694. $severity = $severities[$severity];
  695. $description = array_key_exists('value', $info) ? strip_tags($info['value']) : '';
  696. if (array_key_exists('description', $info) && !empty($info['description'])) {
  697. if (!empty($description)) {
  698. $description .= "\n";
  699. }
  700. $description .= strip_tags($info['description']);
  701. }
  702. $rows[] = array($info['title'], $severity, $description);
  703. }
  704. }
  705. if (count($rows) > 1) {
  706. drush_print_table($rows, TRUE, array(1 => 8));
  707. }
  708. return $requirements;
  709. }
  710. /**
  711. * Command callback. Provides a birds-eye view of the current Drupal
  712. * installation.
  713. */
  714. function drush_core_status() {
  715. $status_table = _core_site_status_table(drush_get_option('project',''), drush_get_option('full'));
  716. // If args are specified, filter out any entry that is not named
  717. // (in other words, only show lines named by one of the arg values)
  718. $args = func_get_args();
  719. if (!empty($args)) {
  720. foreach ($status_table as $key => $value) {
  721. if (!_drush_core_is_named_in_array($key, $args)) {
  722. unset($status_table[$key]);
  723. }
  724. }
  725. }
  726. $return = $status_table;
  727. unset($status_table['%paths']);
  728. // Print either an ini-format list or a formatted ASCII table
  729. if (drush_get_option('pipe')) {
  730. if (count($status_table) == 1) {
  731. $first_value = array_shift($status_table);
  732. drush_print_pipe($first_value);
  733. }
  734. else {
  735. drush_print_pipe(_core_site_credential_list($status_table));
  736. }
  737. }
  738. else {
  739. unset($status_table['Modules path']);
  740. unset($status_table['Themes path']);
  741. drush_print_table(drush_key_value_to_array_table($status_table));
  742. }
  743. return $return;
  744. }
  745. // Command callback. Show all global options. Exposed via topic command.
  746. function drush_core_global_options() {
  747. drush_print(dt('These options are applicable to most drush commands.'));
  748. drush_print();
  749. $fake = drush_global_options_command(FALSE);
  750. $global_option_rows = drush_format_help_section($fake, 'options');
  751. drush_print_table($global_option_rows);
  752. drush_print();
  753. drush_print("See also: `drush topic docs-strict-options`");
  754. }
  755. function _drush_core_is_named_in_array($key, $the_array) {
  756. $is_named = FALSE;
  757. $simplified_key = str_replace(array(' ', '_', '-'), array('', '', ''), $key);
  758. foreach ($the_array as $name) {
  759. if (stristr($simplified_key, str_replace(array(' ', '_', '-'), array('', '', ''), $name))) {
  760. $is_named = TRUE;
  761. }
  762. }
  763. return $is_named;
  764. }
  765. /**
  766. * Callback for core-quick-drupal command.
  767. */
  768. function drush_core_quick_drupal() {
  769. $requests = FALSE;
  770. $make_projects = array();
  771. $args = func_get_args();
  772. $name = drush_get_option('use-name');
  773. drush_set_option('backend', TRUE);
  774. $makefile = drush_get_option('makefile');
  775. if (drush_get_option('use-existing', FALSE)) {
  776. $root = drush_get_option('root', FALSE);
  777. if (!$root) {
  778. return drush_set_error('QUICK_DRUPAL_NO_ROOT_SPECIFIED', 'Must specify site with --root when using --use-existing.');
  779. }
  780. if (empty($name)) {
  781. $name = basename($root);
  782. }
  783. $base = dirname($root);
  784. }
  785. else {
  786. if (!empty($args) && empty($name)) {
  787. $name = array_shift($args);
  788. }
  789. if (empty($name)) {
  790. $name = 'quick-drupal-' . gmdate('YmdHis', $_SERVER['REQUEST_TIME']);
  791. }
  792. $root = drush_get_option('root', FALSE);
  793. $core = drush_get_option('core', 'drupal');
  794. $project_rename = $core;
  795. if ($root) {
  796. $base = dirname($root);
  797. $project_rename = basename($root);
  798. }
  799. else {
  800. $base = getcwd() . '/' . $name;
  801. $root = $base . '/' . $core;
  802. }
  803. if (!empty($makefile)) {
  804. // Invoke 'drush make $makefile'.
  805. $result = drush_invoke_process('@none', 'make', array($makefile, $root));
  806. if ($result['error_status'] != 0) {
  807. return drush_set_error('DRUSH_QD_MAKE', 'Could not make; aborting.');
  808. }
  809. $make_projects = array_diff(array_keys($result['object']['projects']), array('drupal'));
  810. }
  811. else {
  812. drush_mkdir($base);
  813. drush_set_option('destination', $base);
  814. drush_set_option('drupal-project-rename', $project_rename);
  815. if (drush_invoke('pm-download', array($core)) === FALSE) {
  816. return drush_set_error('QUICK_DRUPAL_CORE_DOWNLOAD_FAIL', 'Drupal core download/extract failed.');
  817. }
  818. }
  819. }
  820. if (!drush_get_option('db-url', FALSE)) {
  821. drush_set_option('db-url', 'sqlite:' . $base . '/' . $name . '.sqlite');
  822. }
  823. drush_set_option('root', $root);
  824. if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_ROOT)) {
  825. return drush_set_error('QUICK_DRUPAL_ROOT_LOCATE_FAIL', 'Unable to locate Drupal root directory.');
  826. }
  827. if (!empty($args)) {
  828. $requests = pm_parse_arguments($args, FALSE);
  829. }
  830. if ($requests) {
  831. // Unset --destination, so that downloads go to the site directories.
  832. drush_unset_option('destination');
  833. if (drush_invoke('pm-download', $requests) === FALSE) {
  834. return drush_set_error('QUICK_DRUPAL_PROJECT_DOWNLOAD_FAIL', 'Project download/extract failed.');
  835. }
  836. }
  837. drush_invoke('site-install', array(drush_get_option('profile')));
  838. // Log in with the admin user.
  839. // TODO: If site-install is given a sites-subdir other than 'default',
  840. // then it will bootstrap to DRUSH_BOOTSTRAP_DRUPAL_SITE get the installer
  841. // to recognize the desired site directory. This somehow interferes
  842. // with our desire to bootstrap to DRUSH_BOOTSTRAP_DRUPAL_LOGIN here.
  843. // We could do the last few steps in a new process iff uri is not 'default'.
  844. drush_set_option('user', '1');
  845. if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_LOGIN)) {
  846. return drush_set_error('QUICK_DRUPAL_INSTALL_FAIL', 'Drupal core install failed.');
  847. }
  848. $enable = array_merge(pm_parse_arguments(drush_get_option('enable', $requests)), $make_projects);
  849. if (!empty($enable)) {
  850. if (drush_invoke('pm-enable', $enable) === FALSE) {
  851. return drush_set_error('QUICK_DRUPAL_PROJECT_ENABLE_FAIL', 'Project enable failed.');
  852. }
  853. }
  854. drush_print(dt('Login URL: ') . drush_invoke('user-login'));
  855. if (!drush_get_option('no-server', FALSE)) {
  856. if ($server = drush_get_option('server', '/')) {
  857. drush_invoke('runserver', array($server));
  858. }
  859. }
  860. }
  861. /**
  862. * Include options and engines for core-quick-drupal command, aggregated from
  863. * other command options that are available. We prefix option descriptons,
  864. * to make the long list more navigable.
  865. *
  866. * @param $items
  867. * The core commandfile command array, by reference. Used to include
  868. * site-install options and add options and engines for core-quick-drupal.
  869. */
  870. function drush_core_quick_drupal_options(&$items) {
  871. $options = array(
  872. 'core' => 'Drupal core to download. Defaults to "drupal" (latest stable version).',
  873. 'use-existing' => 'Use an existing Drupal root, specified with --root. Overrides --core.',
  874. 'profile' => 'The install profile to use. Defaults to standard.',
  875. 'enable' => 'Specific extensions (modules or themes) to enable. By default, extensions with the same name as requested projects will be enabled automatically.',
  876. 'server' => 'Host IP address and port number to bind to and path to open in web browser (hyphen to clear a default path), all elements optional. See runserver examples for shorthand.',
  877. 'no-server' => 'Avoid starting runserver (and browser) for the created Drupal site.',
  878. 'browser' => 'Optional name of a browser to open site in. If omitted the OS default browser will be used. Set --no-browser to disable.',
  879. 'use-name' => array('hidden' => TRUE, 'description' => 'Overrides "name" argument.'),
  880. 'makefile' => array('description' => 'Makefile to use. Makefile must specify which version of Drupal core to build.', 'example-value' => 'mysite.make', 'value' => 'optional'),
  881. 'root' => array('description' => 'Path to Drupal root.', 'example-value' => '/path/to/root', 'value' => 'optional'),
  882. );
  883. $pm = pm_drush_command();
  884. foreach ($pm['pm-download']['options'] as $option => $description) {
  885. if (is_array($description)) {
  886. $description = $description['description'];
  887. }
  888. $options[$option] = 'Download option: ' . $description;
  889. }
  890. // Unset a few options that are not usable here, as we control them ourselves
  891. // or they are otherwise implied by the environment.
  892. unset($options['destination']);
  893. unset($options['drupal-project-rename']);
  894. unset($options['default-major']);
  895. unset($options['use-site-dir']);
  896. foreach ($items['site-install']['options'] as $option => $description) {
  897. if (is_array($description)) {
  898. $description = $description['description'];
  899. }
  900. $options[$option] = 'Site install option: ' . $description;
  901. }
  902. unset($options['sites-subdir']);
  903. $runserver = runserver_drush_command();
  904. foreach ($runserver['runserver']['options'] as $option => $description) {
  905. $options[$option] = 'Runserver option: ' . $description;
  906. }
  907. unset($options['user']);
  908. $items['core-quick-drupal']['options'] = $options;
  909. $items['core-quick-drupal']['engines'] = $pm['pm-download']['engines'];
  910. }
  911. /**
  912. * Command callback. Runs "naked" php scripts
  913. * and drush "shebang" scripts ("#!/usr/bin/env drush").
  914. *
  915. * @params
  916. * Command arguments, optional. First argument is site name, remaining
  917. * argument(s) are contrib modules to install.
  918. */
  919. function drush_core_php_script() {
  920. $found = FALSE;
  921. $script = NULL;
  922. if ($args = func_get_args()) {
  923. $script = $args[0];
  924. }
  925. if ($script == '-') {
  926. eval(stream_get_contents(STDIN));
  927. }
  928. elseif (file_exists($script)) {
  929. $found = $script;
  930. }
  931. else {
  932. // Array of paths to search for scripts
  933. $searchpath['DIR'] = dirname(__FILE__);
  934. $searchpath['cwd'] = drush_cwd();
  935. // Additional script paths, specified by 'script-path' option
  936. if ($script_path = drush_get_option('script-path', FALSE)) {
  937. foreach (explode(PATH_SEPARATOR, $script_path) as $path) {
  938. $searchpath[] = $path;
  939. }
  940. }
  941. drush_log(dt('Searching for scripts in ') . implode(',', $searchpath), 'debug');
  942. if (!isset($script)) {
  943. // List all available scripts.
  944. $all = array();
  945. foreach($searchpath as $key => $path) {
  946. $recurse = !(($key == 'cwd') || ($path == '/'));
  947. $all = array_merge( $all , array_keys(drush_scan_directory($path, '/\.php$/', array('.', '..', 'CVS'), NULL, $recurse)) );
  948. }
  949. drush_print(implode("\n", $all));
  950. }
  951. else {
  952. // Execute the specified script.
  953. foreach($searchpath as $path) {
  954. $script_filename = $path . '/' . $script;
  955. if (file_exists($script_filename . '.php')) {
  956. $script_filename .= '.php';
  957. }
  958. if (file_exists($script_filename)) {
  959. $found = $script_filename;
  960. break;
  961. }
  962. $all[] = $script_filename;
  963. }
  964. if (!$found) {
  965. return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
  966. }
  967. }
  968. }
  969. if ($found) {
  970. // Set the DRUSH_SHIFT_SKIP to two; this will cause
  971. // drush_shift to skip the next two arguments the next
  972. // time it is called. This allows scripts to get all
  973. // arguments, including the 'php-script' and script
  974. // pathname, via drush_get_arguments(), or it can process
  975. // just the arguments that are relevant using drush_shift().
  976. drush_set_context('DRUSH_SHIFT_SKIP', 2);
  977. if (_drush_core_eval_shebang_script($found) === FALSE) {
  978. include($found);
  979. }
  980. }
  981. }
  982. function drush_core_php_eval($command) {
  983. return eval($command . ';');
  984. }
  985. /*
  986. * Evaluate a script that begins with #!drush php-script
  987. */
  988. function _drush_core_eval_shebang_script($script_filename) {
  989. $found = FALSE;
  990. $fp = fopen($script_filename, "r");
  991. if ($fp !== FALSE) {
  992. $line = fgets($fp);
  993. if (_drush_is_drush_shebang_line($line)) {
  994. $first_script_line = '';
  995. while ($line = fgets($fp)) {
  996. $line = trim($line);
  997. if ($line == '<?php') {
  998. $found = TRUE;
  999. break;
  1000. }
  1001. elseif (!empty($line)) {
  1002. $first_script_line = $line . "\n";
  1003. break;
  1004. }
  1005. }
  1006. $script = stream_get_contents($fp);
  1007. // Pop off the first two arguments, the
  1008. // command (php-script) and the path to
  1009. // the script to execute, as a service
  1010. // to the script.
  1011. eval($first_script_line . $script);
  1012. $found = TRUE;
  1013. }
  1014. fclose($fp);
  1015. }
  1016. return $found;
  1017. }
  1018. /**
  1019. * Process sets from the specified batch.
  1020. *
  1021. * This is the default batch processor that will be used if the $command parameter
  1022. * to drush_backend_batch_process() has not been specified.
  1023. */
  1024. function drush_core_batch_process($id) {
  1025. drush_batch_command($id);
  1026. }
  1027. /**
  1028. * Process outstanding updates during updatedb.
  1029. *
  1030. * This is a batch processing command that makes use of the drush_backend_invoke
  1031. * api.
  1032. *
  1033. * This command includes the version specific update engine, which correctly
  1034. * initialises the environment to be able to successfully handle minor and major
  1035. * upgrades.
  1036. */
  1037. function drush_core_updatedb_batch_process($id) {
  1038. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  1039. _update_batch_command($id);
  1040. }
  1041. /**
  1042. * Given a target (e.g. @site:%modules), return the evaluated directory path.
  1043. *
  1044. * @param $target
  1045. * The target to evaluate. Can be @site or /path or @site:path
  1046. * or @site:%pathalias, etc. (just like rsync parameters)
  1047. * @param $component
  1048. * The portion of the evaluated path to return. Possible values:
  1049. * 'path' - the full path to the target (default)
  1050. * 'name' - the name of the site from the path (e.g. @site1)
  1051. * 'user-path' - the part after the ':' (e.g. %modules)
  1052. * 'root' & 'uri' - the Drupal root and URI of the site from the path
  1053. * 'path-component' - The ':' and the path
  1054. */
  1055. function _drush_core_directory($target = 'root', $component = 'path', $local_only = FALSE) {
  1056. // Normalize to a sitealias in the target.
  1057. $normalized_target = $target;
  1058. if (strpos($target, ':') === FALSE) {
  1059. if (substr($target, 0, 1) != '@') {
  1060. // drush_sitealias_evaluate_path() requires bootstrap to database.
  1061. if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_DATABASE)) {
  1062. return drush_set_error('DRUPAL_SITE_NOT_FOUND', dt('You need to specify an alias or run this command within a drupal site.'));
  1063. }
  1064. $normalized_target = '@self:';
  1065. if (substr($target, 0, 1) != '%') {
  1066. $normalized_target .= '%';
  1067. }
  1068. $normalized_target .= $target;
  1069. }
  1070. }
  1071. $additional_options = array();
  1072. $values = drush_sitealias_evaluate_path($normalized_target, $additional_options, $local_only);
  1073. if (isset($values[$component])) {
  1074. // Hurray, we found the destination.
  1075. return $values[$component];
  1076. }
  1077. }
  1078. /**
  1079. * Command callback.
  1080. */
  1081. function drush_core_drupal_directory($target = 'root') {
  1082. $path = _drush_core_directory($target, drush_get_option('component', 'path'), drush_get_option('local', FALSE));
  1083. // If _drush_core_directory is working right, it will turn
  1084. // %blah into the path to the item referred to by the key 'blah'.
  1085. // If there is no such key, then no replacement is done. In the
  1086. // case of the dd command, we will consider it an error if
  1087. // any keys are -not- replaced in _drush_core_directory.
  1088. if ($path && (strpos($path, '%') === FALSE)) {
  1089. drush_print($path);
  1090. return $path;
  1091. }
  1092. else {
  1093. return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt("Target '!target' not found.", array('!target' => $target)));
  1094. }
  1095. }
  1096. /**
  1097. * Called for `drush version` or `drush --version`
  1098. */
  1099. function drush_core_version() {
  1100. drush_print(dt("drush version !version", array('!version' => DRUSH_VERSION)));
  1101. drush_print_pipe(DRUSH_VERSION);
  1102. // Next check to see if there is a newer drush.
  1103. if (!drush_get_context('DRUSH_PIPE') && drush_get_option('self-update', TRUE)) {
  1104. drush_check_self_update();
  1105. }
  1106. }
  1107. function drush_core_self_update() {
  1108. drush_check_self_update();
  1109. }
  1110. function drush_core_find_project_path($target) {
  1111. $path = drush_db_result(drush_db_select('system', array('filename'), 'name = :name', array(':name' => $target)));
  1112. if ($path) {
  1113. $path = dirname($path);
  1114. return DRUPAL_ROOT . '/' . $path;
  1115. }
  1116. }
  1117. /**
  1118. * Command callback. Execute specified shell code. Often used by shell aliases
  1119. * that start with !.
  1120. */
  1121. function drush_core_execute() {
  1122. $result = TRUE;
  1123. // Get all of the args and options that appear after the command name.
  1124. $args = drush_get_original_cli_args_and_options();
  1125. for ($x = 0; $x < sizeof($args); $x++) {
  1126. // escape all args except for command separators.
  1127. if (!in_array($args[$x], array('&&', '||', ';'))) {
  1128. $args[$x] = drush_escapeshellarg($args[$x]);
  1129. }
  1130. }
  1131. $cmd = implode(' ', $args);
  1132. if ($alias = drush_get_context('DRUSH_TARGET_SITE_ALIAS')) {
  1133. $site = drush_sitealias_get_record($alias);
  1134. if (!empty($site['site-list'])) {
  1135. $sites = drush_sitealias_resolve_sitelist($site);
  1136. foreach ($sites as $site_name => $site_spec) {
  1137. $result = _drush_core_execute_cmd($site_spec, $cmd);
  1138. if (!$result) {
  1139. break;
  1140. }
  1141. }
  1142. }
  1143. else {
  1144. $result = _drush_core_execute_cmd($site, $cmd);
  1145. }
  1146. }
  1147. else {
  1148. // Must be a local command.
  1149. $result = (drush_shell_proc_open($cmd) == 0);
  1150. }
  1151. if (!$result) {
  1152. return drush_set_error('CORE_EXECUTE_FAILED', dt("Command !command failed.", array('!command' => $cmd)));
  1153. }
  1154. return $result;
  1155. }
  1156. /**
  1157. * Helper function for drush_core_execute: run one shell command
  1158. */
  1159. function _drush_core_execute_cmd($site, $cmd) {
  1160. if (!empty($site['remote-host'])) {
  1161. // Remote, so execute an ssh command with a bash fragment at the end.
  1162. $exec = drush_shell_proc_build($site, $cmd, TRUE);
  1163. return (drush_shell_proc_open($exec) == 0);
  1164. }
  1165. elseif (!empty($site['root']) && is_dir($site['root'])) {
  1166. return (drush_shell_proc_open('cd ' . drush_escapeshellarg($site['root']) . ' && ' . $cmd) == 0);
  1167. }
  1168. return (drush_shell_proc_open($cmd) == 0);
  1169. }