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_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_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_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. 'options' => array(
  25. 'sort' => 'Sort commands in alphabetical order. drush waits for full bootstrap before printing any commands when this option is used.',
  26. 'filter' => 'Restrict command list to those commands defined in the specified file.',
  27. 'html' => 'Print help for all commands in HTML format.',
  28. 'pipe' => 'A list of available commands, one per line.',
  29. ),
  30. 'examples' => array(
  31. 'drush' => 'List all commands.',
  32. 'drush --filter=devel_generate' => 'Show only commands defined in devel_generate.drush.inc',
  33. 'drush help pm-download' => 'Show help for one command.',
  34. 'drush help dl' => 'Show help for one command using an alias.',
  35. ),
  36. 'topics' => array('docs-readme'),
  37. );
  38. $items['version'] = array(
  39. 'description' => 'Show drush version.',
  40. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  41. 'options' => array(
  42. 'pipe' => 'Print just the version number, and nothing else.',
  43. 'self-update' => 'Check for pending updates to drush itself. Set to 0 to avoid check.',
  44. ),
  45. );
  46. $items['self-update'] = array(
  47. 'description' => 'Update drush to the latest version, if available.',
  48. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  49. 'options' => array(
  50. '--dev' => 'Allow updates to latest dev release.',
  51. ),
  52. 'aliases' => array('selfupdate'),
  53. );
  54. $items['core-cron'] = array(
  55. 'description' => 'Run all cron hooks in all active modules for specified site.',
  56. 'aliases' => array('cron'),
  57. );
  58. $items['updatedb'] = array(
  59. 'description' => 'Apply any database updates required (as with running update.php).',
  60. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  61. 'aliases' => array('updb'),
  62. );
  63. $items['core-status'] = array(
  64. 'description' => 'Provides a birds-eye view of the current Drupal installation, if any.',
  65. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  66. 'aliases' => array('status', 'st'),
  67. 'examples' => array(
  68. 'drush status version' => 'Show all status lines that contain version information.',
  69. 'drush status --pipe' => 'A list key=value items separated by line breaks.',
  70. 'drush status drush-version --pipe' => 'Emit just the drush version with no label.',
  71. ),
  72. 'arguments' => array(
  73. 'item' => 'Optional. The status item line(s) to display.',
  74. ),
  75. 'options' => array(
  76. 'show-passwords' => 'Show database password.',
  77. ),
  78. 'topics' => array('docs-readme'),
  79. );
  80. $items['php-eval'] = array(
  81. 'description' => 'Evaluate arbitrary php code after bootstrapping Drupal (if available).',
  82. 'examples' => array(
  83. 'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.',
  84. ),
  85. 'arguments' => array(
  86. 'code' => 'PHP code',
  87. ),
  88. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  89. 'aliases' => array('eval', 'ev'),
  90. );
  91. $items['php-script'] = array(
  92. 'description' => "Run php script(s).",
  93. 'examples' => array(
  94. 'drush php-script scratch' => 'Run scratch.php script. See commands/core directory.',
  95. 'drush php-script example --script-path=/path/to/scripts:/another/path' => 'Run script from specified paths',
  96. 'drush php-script' => 'List all available scripts.',
  97. '' => '',
  98. "#!/usr/bin/env drush\n<?php\nvariable_set('key', drush_shift());" => "Execute php code with a full Drupal bootstrap directly from a shell script.",
  99. ),
  100. 'arguments' => array(
  101. '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.',
  102. ),
  103. 'options' => array(
  104. 'script-path' => "Additional paths to search for scripts, separated by : (Unix-based systems) or ; (Windows).",
  105. ),
  106. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  107. 'aliases' => array('scr'),
  108. 'deprecated-aliases' => array('script'),
  109. 'topics' => array('docs-examplescript', 'docs-scripts'),
  110. );
  111. $items['search-status'] = array(
  112. 'description' => 'Show how many items remain to be indexed out of the total.',
  113. 'drupal dependencies' => array('search'),
  114. 'options' => array(
  115. 'pipe' => 'Display in the format remaining/total for processing by scripts.',
  116. ),
  117. );
  118. $items['search-index'] = array(
  119. 'description' => 'Index the remaining search items without wiping the index.',
  120. 'drupal dependencies' => array('search'),
  121. );
  122. $items['search-reindex'] = array(
  123. 'description' => 'Force the search index to be rebuilt.',
  124. 'drupal dependencies' => array('search'),
  125. 'options' => array(
  126. 'immediate' => 'Rebuild the index immediately, instead of waiting for cron.',
  127. ),
  128. );
  129. $items['core-rsync'] = array(
  130. 'description' => 'Rsync the Drupal tree to/from another server using ssh.',
  131. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
  132. 'arguments' => array(
  133. 'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  134. 'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
  135. ),
  136. 'options' => array(
  137. 'mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz. Default is -az.',
  138. 'RSYNC-FLAG' => 'Most rsync flags passed to drush sync will be passed on to rsync. See rsync documentation.',
  139. 'exclude-conf' => 'Excludes settings.php from being rsynced. Default.',
  140. 'include-conf' => 'Allow settings.php to be rsynced. Default is to exclude settings.php.',
  141. 'include-vcs' => 'Include special version control directories (e.g. .svn). Default is to exclude vcs files.',
  142. 'exclude-files' => 'Exclude the files directory.',
  143. 'exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
  144. '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"',
  145. 'exclude-paths' => 'List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).',
  146. 'include-paths' => 'List of paths to include, seperated by : (Unix-based systems) or ; (Windows).',
  147. ),
  148. 'examples' => array(
  149. 'drush rsync @dev @stage' => 'Rsync Drupal root from dev to stage (one of which must be local).',
  150. 'drush rsync ./ @stage:%files/img' => 'Rsync all files in the current directory to the \'img\' directory in the file storage folder on stage.',
  151. ),
  152. 'aliases' => array('rsync'),
  153. 'deprecated-aliases' => array('sync'),
  154. 'topics' => array('docs-aliases'),
  155. );
  156. $items['site-install'] = array(
  157. 'description' => 'Install Drupal along with modules/themes/configuration using the specified install profile.',
  158. 'arguments' => array(
  159. 'profile' => 'the install profile you wish to run. defaults to \'default\' in D6, \'standard\' in D7',
  160. 'key=value...' => 'any additional settings you wish to pass to the profile. Only support on D7. The key is in the form [form name].[parameter name].',
  161. ),
  162. 'options' => array(
  163. 'account-name' => 'uid1 name. defaults to admin',
  164. 'account-pass' => 'uid1 pass. defaults to admin',
  165. 'account-mail' => 'uid1 email. defaults to admin@example.com',
  166. 'db-url' => 'A Drupal 5/6 style database URL. Only required for initial install - not re-install.',
  167. '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).',
  168. 'db-su' => 'Account to use when creating a new database. Optional.',
  169. 'db-su-pw' => 'Password for the "db-su" account. Optional.',
  170. 'locale' => 'A short language code. Sets the default site language. Language files must already be present. You may use download command to get them.',
  171. 'clean-url'=> 'Defaults to 1',
  172. 'site-name' => 'Defaults to Site-Install',
  173. 'site-mail' => 'From: for system mailings. Defaults to admin@example.com',
  174. 'sites-subdir' => "Name of directory under 'sites' which should be created. Only needed when the subdirectory does not already exist. Defaults to 'default'",
  175. ),
  176. 'examples' => array(
  177. 'drush site-install expert --locale=uk' => '(Re)install using the expert install profile. Set default language to Ukranian.',
  178. 'drush site-install --db-url=mysql://root:pass@localhost:port/dbname' => 'Install using the specified DB params.',
  179. 'drush site-install --db-url=sqlite:/full/path/to/database.sqlite' => 'Install using SQLite (D7 only).',
  180. 'drush site-install --account-name=joe --account-pass=mom' => 'Re-install with specified uid1 credentials.',
  181. '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 only).',
  182. ),
  183. 'core' => array('6+'),
  184. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
  185. 'aliases' => array('si'),
  186. 'deprecated-aliases' => array('installsite', 'is'),
  187. );
  188. $items['drupal-directory'] = array(
  189. 'description' => 'Return path to a given module/theme directory.',
  190. 'arguments' => array(
  191. '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.',
  192. ),
  193. 'options' => array(
  194. 'component' => "The portion of the evaluated path to return. Defaults to 'path'; 'name' returns the site alias of the target.",
  195. 'local' => "Reject any target that specifies a remote site.",
  196. ),
  197. 'examples' => array(
  198. 'cd `drush dd devel`' => 'Navigate into the devel module directory',
  199. 'cd `drush dd` ' => 'Navigate to the root of your Drupal site',
  200. 'cd `drush dd files`' => 'Navigate to the files directory.',
  201. 'drush dd @alias:%files' => 'Print the path to the files directory on the site @alias.',
  202. 'edit `drush dd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)",
  203. ),
  204. 'aliases' => array('dd'),
  205. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  206. );
  207. $items['core-cli'] = array(
  208. 'description' => 'Enter a new shell optimized for drush use.',
  209. 'options' => array(
  210. 'override' => 'List of drush commands or aliases that should override built-in shell functions and commands; otherwise, built-ins override drush commands. Defaults to dd,help,sa.',
  211. 'contextual' => 'Additional drush overrides that function ONLY when the prompt is "@alias>". Defaults to cc,cron,rsync,status,sync,updatedb.',
  212. 'ignore' => 'Drush commands or aliases that should not be usable from core-cli. Takes precedence over override and contextual options. Defaults to core-cli,cli.',
  213. 'pipe' => 'Print the generated .bashrc file and exit.',
  214. ),
  215. 'examples' => array(
  216. 'help' => 'Print available drush commands',
  217. 'cd @alias' => 'Navigate to the root of the site indicated by @alias; subsequent commands will target that site.',
  218. 'cd %files' => 'Navigate to the files directory.',
  219. 'cd ~' => 'Navigate back to your $HOME directory.',
  220. 'lsd files' => 'List all files in the Drupal files directory.',
  221. 'on @alias core-status' => 'Run the command "core-status" on the site indicated by @alias',
  222. '@alias core-status' => 'An even shorter form that also runs "core-status" on the site @alias',
  223. 'use @alias' => 'Run subsequent commands on the site indicated by @alias',
  224. 'use -' => 'Switch back to the last alias "used".',
  225. 'use ~' => 'Use the default alias.',
  226. 'use' => 'Revert to an ordinary prompt; do not use an alias.',
  227. 'drush core-cli --pipe > ~/.bash_aliases' => 'Convert your default shell into drush core-cli. Make sure that your .bashrc file includes .bash_aliases (e.g. "source ~/.bash_aliases" or ". ~/.bash_aliases").',
  228. ),
  229. 'aliases' => array('cli'),
  230. 'bootstrap' => DRUSH_BOOTSTRAP_MAX,
  231. );
  232. $items['batch-process'] = array(
  233. 'description' => 'Process operations in the specified batch set',
  234. 'hidden' => TRUE,
  235. 'arguments' => array(
  236. 'batch-id' => 'The batch id that will be processed',
  237. ),
  238. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
  239. );
  240. $items['updatedb-batch-process'] = array(
  241. 'description' => 'Perform update functions',
  242. 'hidden' => TRUE,
  243. 'arguments' => array(
  244. 'batch-id' => 'The batch id that will be processed',
  245. ),
  246. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
  247. );
  248. $items['core-global-options'] = array(
  249. 'description' => 'All global options',
  250. 'hidden' => TRUE,
  251. 'topic' => TRUE,
  252. 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
  253. );
  254. return $items;
  255. }
  256. function core_drush_engine_drupal() {
  257. $engines = array();
  258. $engines['batch'] = array();
  259. $engines['update'] = array();
  260. $engines['environment'] = array();
  261. $engines['site_install'] = array();
  262. return $engines;
  263. }
  264. /**
  265. * Command handler. Execute update.php code from drush.
  266. */
  267. function drush_core_updatedb() {
  268. if (drush_get_context('DRUSH_SIMULATE')) {
  269. drush_log(dt('updatedb command does not support --simulate option.'), 'ok');
  270. return TRUE;
  271. }
  272. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  273. if (update_main() === FALSE) {
  274. return FALSE;
  275. }
  276. if (drush_drupal_major_version() <= 6) {
  277. // Clear all caches. We just performed major surgery.
  278. drush_drupal_cache_clear_all();
  279. }
  280. else {
  281. // Should be unnecessary on D7.
  282. // On D7 site-upgrade, this cache_clear was leading to:
  283. // Call to undefined function field_read_fields() in field_sql_storage.install line 17
  284. }
  285. drush_log(dt('Finished performing updates.'), 'ok');
  286. }
  287. /**
  288. * Implementation of hook_drush_help().
  289. *
  290. * This function is called whenever a drush user calls
  291. * 'drush help <name-of-your-command>'
  292. *
  293. * @param
  294. * A string with the help section (prepend with 'drush:')
  295. *
  296. * @return
  297. * A string with the help text for your command.
  298. */
  299. function core_drush_help($section) {
  300. switch ($section) {
  301. case 'meta:core:title':
  302. return dt("Core drush commands");
  303. case 'drush:help':
  304. 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.");
  305. case 'drush:php-script':
  306. 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.");
  307. case 'drush:rsync':
  308. 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.");
  309. case 'drush:drupal-directory':
  310. return dt("Return the filesystem path for modules/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.");
  311. case 'drush:core-cli':
  312. return dt("Enter a new shell optimized for drush use. All .bashrc customizations are still available.");
  313. case 'error:DRUSH_DRUPAL_DB_ERROR':
  314. $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
  315. $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");
  316. $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
  317. $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");
  318. return $message;
  319. case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR':
  320. $message = dt("Drush was not able to start (bootstrap) Drupal.\n");
  321. $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");
  322. $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
  323. $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");
  324. return $message;
  325. break;
  326. }
  327. }
  328. // TODO: consolidate with SQL commands?
  329. function _core_site_credentials() {
  330. $status_table = _core_site_status_table();
  331. return _core_site_credential_table($status_table);
  332. }
  333. function _core_site_credential_table($status_table) {
  334. $credentials = '';
  335. foreach ($status_table as $key => $value) {
  336. $credentials .= sprintf(" %-18s: %s\n", $key, $value);
  337. }
  338. return $credentials;
  339. }
  340. function _core_site_credential_list($status_table) {
  341. $credentials = '';
  342. foreach ($status_table as $key => $value) {
  343. if (isset($value)) {
  344. $credentials .= sprintf("%s=%s\n", strtolower(str_replace(' ', '_', $key)), $value);
  345. }
  346. }
  347. return $credentials;
  348. }
  349. function _core_path_aliases($project = '') {
  350. $paths = array();
  351. $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  352. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  353. $paths['%root'] = $drupal_root;
  354. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  355. $paths['%site'] = $site_root;
  356. if (is_dir($modules_path = conf_path() . '/modules')) {
  357. $paths['%modules'] = $modules_path;
  358. }
  359. else {
  360. $paths['%modules'] = 'sites/all/modules';
  361. }
  362. if (is_dir($themes_path = conf_path() . '/themes')) {
  363. $paths['%themes'] = $themes_path;
  364. }
  365. else {
  366. $paths['%themes'] = 'sites/all/themes';
  367. }
  368. if (drush_drupal_major_version() >= 7) {
  369. if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_SITE) {
  370. $paths['%files'] = variable_get('file_public_path', conf_path() . '/files');
  371. $private_path = variable_get('file_private_path', FALSE);
  372. if ($private_path !== FALSE) {
  373. $paths['%private'] = $private_path;
  374. }
  375. }
  376. }
  377. elseif (function_exists('file_directory_path')) {
  378. $paths['%files'] = file_directory_path();
  379. }
  380. // If the 'project' parameter was specified, then search
  381. // for a project (or a few) and add its path to the path list
  382. if (!empty($project)) {
  383. foreach(explode(',', $project) as $target) {
  384. $path = drush_core_find_project_path($target);
  385. if(isset($path)) {
  386. $paths['%' . $target] = $path;
  387. }
  388. }
  389. }
  390. }
  391. }
  392. // Add in all of the global paths from $options['path-aliases']
  393. $paths = array_merge($paths, drush_get_option('path-aliases', array()));
  394. return $paths;
  395. }
  396. function _core_site_status_table($project = '') {
  397. $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  398. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  399. $status_table['Drupal version'] = drush_drupal_version();
  400. if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  401. $status_table['Site URI'] = drush_get_context('DRUSH_URI');
  402. if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
  403. $status_table['Database driver'] = $creds['driver'];
  404. $status_table['Database hostname'] = $creds['host'];
  405. $status_table['Database username'] = $creds['user'];
  406. $status_table['Database name'] = $creds['name'];
  407. if (drush_get_option('show-passwords', FALSE)) {
  408. $status_table['Database password'] = $creds['pass'];
  409. }
  410. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_DATABASE) {
  411. $status_table['Database'] = dt('Connected');
  412. if ($phase > DRUSH_BOOTSTRAP_DRUPAL_FULL) {
  413. $status_table['Drupal bootstrap'] = dt('Successful');
  414. if ($phase == DRUSH_BOOTSTRAP_DRUPAL_LOGIN) {
  415. global $user;
  416. $username = ($user->uid) ? $user->name : dt('Anonymous');
  417. $status_table['Drupal user'] = $username;
  418. }
  419. }
  420. }
  421. }
  422. }
  423. $status_table['Default theme'] = drush_theme_get_default();
  424. $status_table['Administration theme'] = drush_theme_get_admin();
  425. }
  426. if ($php_ini_files = _drush_core_config_php_ini_files()) {
  427. $status_table['PHP configuration'] = implode(' ', $php_ini_files);
  428. }
  429. drush_sitealias_load_all();
  430. $status_table['Drush version'] = DRUSH_VERSION;
  431. $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE));
  432. $status_table['Drush alias files'] = implode(' ', drush_get_context('drush-alias-files'));
  433. // None of the Status keys are in dt(); this helps with machine-parsing of status?
  434. $path_names['root'] = 'Drupal root';
  435. $path_names['site'] = 'Site path';
  436. $path_names['modules'] = 'Modules path';
  437. $path_names['themes'] = 'Themes path';
  438. $path_names['files'] = 'File directory path';
  439. $path_names['private'] = 'Private file directory path';
  440. $paths = _core_path_aliases($project);
  441. if (!empty($paths)) {
  442. foreach ($paths as $target => $one_path) {
  443. $name = $target;
  444. if (substr($name,0,1) == '%') {
  445. $name = substr($name,1);
  446. }
  447. if (array_key_exists($name, $path_names)) {
  448. $name = $path_names[$name];
  449. }
  450. $status_table[$name] = $one_path;
  451. }
  452. }
  453. // Store the paths into the '%paths' index; this will be
  454. // used by other code, but will not be included in the output
  455. // of the drush status command.
  456. $status_table['%paths'] = $paths;
  457. return $status_table;
  458. }
  459. function _drush_core_config_php_ini_files() {
  460. $ini_files = array();
  461. // Function available on PHP >= 5.2.4, but we use it if available to help
  462. // users figure out their php.ini issues.
  463. if (function_exists('php_ini_loaded_file')) {
  464. $ini_files[] = php_ini_loaded_file();
  465. }
  466. foreach (array(DRUSH_BASE_PATH, '/etc/drush', drush_server_home() . '/.drush') as $ini_dir) {
  467. if (file_exists($ini_dir . "/php.ini")) {
  468. $ini_files[] = realpath($ini_dir . "/php.ini");
  469. }
  470. if (file_exists($ini_dir . "/drush.ini")) {
  471. $ini_files[] = realpath($ini_dir . "/drush.ini");
  472. }
  473. }
  474. return $ini_files;
  475. }
  476. /**
  477. * Command callback. Runs cron hooks.
  478. *
  479. * This is where the action takes place.
  480. *
  481. * In this function, all of Drupals API is (usually) available, including
  482. * any functions you have added in your own modules/themes.
  483. *
  484. * To print something to the terminal window, use drush_print().
  485. *
  486. */
  487. function drush_core_cron() {
  488. if (drupal_cron_run()) {
  489. drush_log(dt('Cron run successfully.'), 'success');
  490. }
  491. else {
  492. return drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
  493. }
  494. }
  495. /**
  496. * Command callback. Provides a birds-eye view of the current Drupal
  497. * installation.
  498. */
  499. function drush_core_status() {
  500. $status_table = _core_site_status_table(drush_get_option('project',''));
  501. // If args are specified, filter out any entry that is not named
  502. // (in other words, only show lines named by one of the arg values)
  503. $args = func_get_args();
  504. if (!empty($args)) {
  505. foreach ($status_table as $key => $value) {
  506. if (!_drush_core_is_named_in_array($key, $args)) {
  507. unset($status_table[$key]);
  508. }
  509. }
  510. }
  511. drush_backend_set_result($status_table);
  512. unset($status_table['%paths']);
  513. // Print either an ini-format list or a formatted ASCII table
  514. if (drush_get_option('pipe')) {
  515. if (count($status_table) == 1) {
  516. $first_value = array_shift($status_table);
  517. drush_print_pipe($first_value);
  518. }
  519. else {
  520. drush_print_pipe(_core_site_credential_list($status_table));
  521. }
  522. }
  523. else {
  524. unset($status_table['Modules path']);
  525. unset($status_table['Themes path']);
  526. drush_print_table(drush_key_value_to_array_table($status_table));
  527. }
  528. return;
  529. }
  530. // Command callback. Show all global options. Exposed via topic command.
  531. function drush_core_global_options() {
  532. drush_print(dt('These options are applicable to most drush commands.'));
  533. drush_print();
  534. $fake = drush_global_options_command(FALSE);
  535. $global_option_rows = drush_format_help_section($fake, 'options');
  536. drush_print_table($global_option_rows);
  537. }
  538. function _drush_core_is_named_in_array($key, $the_array) {
  539. $is_named = FALSE;
  540. $simplified_key = str_replace(array(' ', '_', '-'), array('', '', ''), $key);
  541. foreach ($the_array as $name) {
  542. if (stristr($simplified_key, str_replace(array(' ', '_', '-'), array('', '', ''), $name))) {
  543. $is_named = TRUE;
  544. }
  545. }
  546. return $is_named;
  547. }
  548. /**
  549. * Command callback. Runs "naked" php scripts
  550. * and drush "shebang" scripts ("#!/usr/bin/env drush").
  551. */
  552. function drush_core_php_script() {
  553. $found = FALSE;
  554. $script = NULL;
  555. if ($args = func_get_args()) {
  556. $script = $args[0];
  557. }
  558. if ($script == '-') {
  559. eval(stream_get_contents(STDIN));
  560. }
  561. elseif (file_exists($script)) {
  562. $found = $script;
  563. }
  564. else {
  565. // Array of paths to search for scripts
  566. $searchpath['DIR'] = dirname(__FILE__);
  567. $searchpath['cwd'] = drush_cwd();
  568. // Additional script paths, specified by 'script-path' option
  569. if ($script_path = drush_get_option('script-path', FALSE)) {
  570. foreach (explode(PATH_SEPARATOR, $script_path) as $path) {
  571. $searchpath[] = $path;
  572. }
  573. }
  574. drush_log(dt('Searching for scripts in ') . implode(',', $searchpath), 'debug');
  575. if (!isset($script)) {
  576. // List all available scripts.
  577. $all = array();
  578. foreach($searchpath as $key => $path) {
  579. $recurse = !(($key == 'cwd') || ($path == '/'));
  580. $all = array_merge( $all , array_keys(drush_scan_directory($path, '/\.php$/', array('.', '..', 'CVS'), NULL, $recurse)) );
  581. }
  582. drush_print(implode("\n", $all));
  583. }
  584. else {
  585. // Execute the specified script.
  586. foreach($searchpath as $path) {
  587. $script_filename = $path . '/' . $script;
  588. if (file_exists($script_filename . '.php')) {
  589. $script_filename .= '.php';
  590. }
  591. if (file_exists($script_filename)) {
  592. $found = $script_filename;
  593. break;
  594. }
  595. $all[] = $script_filename;
  596. }
  597. if (!$found) {
  598. return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
  599. }
  600. }
  601. }
  602. if ($found) {
  603. // Set the DRUSH_SHIFT_SKIP to two; this will cause
  604. // drush_shift to skip the next two arguments the next
  605. // time it is called. This allows scripts to get all
  606. // arguments, including the 'php-script' and script
  607. // pathname, via drush_get_arguments(), or it can process
  608. // just the arguments that are relevant using drush_shift().
  609. drush_set_context('DRUSH_SHIFT_SKIP', 2);
  610. if (_drush_core_eval_shebang_script($found) === FALSE) {
  611. include($found);
  612. }
  613. }
  614. }
  615. function drush_core_php_eval($command) {
  616. eval($command . ';');
  617. }
  618. /*
  619. * Evaluate a script that begins with #!drush php-script
  620. */
  621. function _drush_core_eval_shebang_script($script_filename) {
  622. $found = FALSE;
  623. $fp = fopen($script_filename, "r");
  624. if ($fp !== FALSE) {
  625. $line = fgets($fp);
  626. if (_drush_is_drush_shebang_line($line)) {
  627. $first_script_line = '';
  628. while ($line = fgets($fp)) {
  629. $line = trim($line);
  630. if ($line == '<?php') {
  631. $found = TRUE;
  632. break;
  633. }
  634. elseif (!empty($line)) {
  635. $first_script_line = $line . "\n";
  636. break;
  637. }
  638. }
  639. $script = stream_get_contents($fp);
  640. // Pop off the first two arguments, the
  641. // command (php-script) and the path to
  642. // the script to execute, as a service
  643. // to the script.
  644. eval($first_script_line . $script);
  645. $found = TRUE;
  646. }
  647. fclose($fp);
  648. }
  649. return $found;
  650. }
  651. /**
  652. * Process sets from the specified batch.
  653. *
  654. * This is the default batch processor that will be used if the $command parameter
  655. * to drush_backend_batch_process() has not been specified.
  656. */
  657. function drush_core_batch_process($id) {
  658. drush_batch_command($id);
  659. }
  660. /**
  661. * Process outstanding updates during updatedb.
  662. *
  663. * This is a batch processing command that makes use of the drush_backend_invoke
  664. * api.
  665. *
  666. * This command includes the version specific update engine, which correctly
  667. * initialises the environment to be able to successfully handle minor and major
  668. * upgrades.
  669. */
  670. function drush_core_updatedb_batch_process($id) {
  671. drush_include_engine('drupal', 'update', drush_drupal_major_version());
  672. _update_batch_command($id);
  673. }
  674. /**
  675. * Given a target (e.g. @site:%modules), return the evaluated
  676. * directory path
  677. *
  678. * @param $target
  679. * The target to evaluate. Can be @site or /path or @site:path
  680. * or @site:%pathalais, etc. (just like rsync parameters)
  681. * @param $component
  682. * The portion of the evaluated path to return. Possible values:
  683. * 'path' - the full path to the target (default)
  684. * 'name' - the name of the site from the path (e.g. @site1)
  685. * 'user-path' - the part after the ':' (e.g. %modules)
  686. * 'root' & 'uri' - the Drupal root and URI of the site from the path
  687. * 'path-component' - The ':' and the path
  688. */
  689. function _drush_core_directory($target = 'root', $component = 'path', $local_only = FALSE) {
  690. // Normalize to a sitealias in the target.
  691. $normalized_target = $target;
  692. if (strpos($target, ':') === FALSE) {
  693. if (substr($target,0,1) == '@') {
  694. $normalized_target = $target; // . ':%site';
  695. }
  696. else {
  697. // @self makes no sense before 'site' level.
  698. if(!drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) {
  699. return FALSE;
  700. }
  701. $normalized_target = '@self:';
  702. if (substr($target,0,1) != '%') {
  703. $normalized_target .= '%';
  704. }
  705. $normalized_target .= $target;
  706. }
  707. }
  708. $additional_options = array();
  709. $values = drush_sitealias_evaluate_path($normalized_target, $additional_options, $local_only);
  710. if (isset($values[$component])) {
  711. // Hurray, we found the destination
  712. return $values[$component];
  713. }
  714. return NULL;
  715. }
  716. function drush_core_drupal_directory($target = 'root') {
  717. $path = _drush_core_directory($target, drush_get_option('component', 'path'), drush_get_option('local', FALSE));
  718. // If _drush_core_directory is working right, it will turn
  719. // %blah into the path to the item referred to by the key 'blah'.
  720. // If there is no such key, then no replacement is done. In the
  721. // case of the dd command, we will consider it an error if
  722. // any keys are -not- replaced in _drush_core_directory.
  723. if ((isset($path)) && (strpos($path, '%') === FALSE)) {
  724. drush_print($path);
  725. }
  726. else {
  727. return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt("Target '!target' not found.", array('!target' => $target)));
  728. }
  729. return TRUE;
  730. }
  731. /**
  732. * Called for `drush version` or `drush --version`
  733. */
  734. function drush_core_version() {
  735. drush_print(dt("drush version !version", array('!version' => DRUSH_VERSION)));
  736. drush_print_pipe(DRUSH_VERSION);
  737. // Next check to see if there is a newer drush.
  738. if (!drush_get_context('DRUSH_PIPE') && !drush_get_option('self-update', TRUE)) {
  739. drush_check_self_update();
  740. }
  741. }
  742. function drush_core_self_update() {
  743. drush_set_option('select', TRUE);
  744. return drush_invoke('pm-download', 'drush');
  745. }
  746. function drush_core_find_project_path($target) {
  747. $theme_suffix = drush_drupal_major_version() >= 6 ? '.info' : '/style.css';
  748. $masks = array(
  749. conf_path() . '/modules' => "/^$target\.module$/",
  750. 'profiles/default/modules' => "/^$target\.module$/", // Too early for variable_get('install_profile', 'default'); Just use default.
  751. 'sites/all/modules' => "/^$target\.module$/", // Add all module paths, even disabled modules.
  752. conf_path() . '/themes' => "/^$target" . "$theme_suffix/",
  753. 'sites/all/themes' => "/^$target" . "$theme_suffix/",
  754. );
  755. $files = array();
  756. foreach ($masks as $key => $mask) {
  757. $skip_list = array('.', '..', 'CVS');
  758. $skip_list = array_merge($skip_list, drush_version_control_reserved_files());
  759. if ($files = drush_scan_directory("$key", $mask, $skip_list, 0, TRUE, 'name')) {
  760. // Just use the first match.
  761. $file = reset($files);
  762. return drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename);
  763. }
  764. }
  765. return NULL;
  766. }
  767. function drush_core_cli() {
  768. // Do not allow cli to start recursively, or from backend invoke.
  769. if (drush_get_option('in-cli', FALSE)) {
  770. return drush_set_error('DRUSH_CLI_NOT_REENTRANT', dt('Already in drush core-cli; press control-d to exit.'));
  771. }
  772. if (drush_get_context('DRUSH_BACKEND') || drush_get_context('DRUSH_AFFIRMATIVE') || drush_get_context('DRUSH_NEGATIVE')) {
  773. return drush_set_error('DRUSH_CLI_INTERACTIVE_ERROR', dt('Cannot run drush core-cli from non-interactive mode; aborting.'));
  774. }
  775. // We set interactive mode if we are about to run a bash subshell.
  776. // The purpose of doing this is that some options are set differently
  777. // in --pipe mode. To see everything with --pipe, use --pipe --verbose.
  778. $interactive_mode = !drush_get_context('DRUSH_PIPE') || drush_get_context('DRUSH_VERBOSE');
  779. // Make sure that we call drush the same way that we were called.
  780. // In --pipe mode, just use 'drush'.
  781. $drush_command = $interactive_mode ? DRUSH_COMMAND.' --in-cli' : 'drush';
  782. $bashrc_data = implode("\n\n", drush_command_invoke_all('cli_bashrc', $drush_command, $interactive_mode));
  783. // Print our bashrc file and exit in --pipe mode
  784. if (drush_get_context('DRUSH_PIPE')) {
  785. drush_print_pipe($bashrc_data);
  786. return TRUE;
  787. }
  788. // If there were any errors, then exit.
  789. if (drush_get_error()) {
  790. return FALSE;
  791. }
  792. drush_print("Entering the drush cli. Use CONTROL-D to exit.");
  793. drush_print("Type 'help' for help.");
  794. // Save out bashrc in a temporary file and launch bash.
  795. // control-d to exit. The temp file will be deleted after
  796. // we exit.
  797. $bashrc = drush_save_data_to_temp_file($bashrc_data);
  798. return drush_op_system('bash --rcfile ' . $bashrc . ' > `tty`');
  799. }
  800. // Implement our own hook_cli_bashrc()
  801. function core_cli_bashrc($drush_command, $interactive_mode) {
  802. $bashrc_data = '';
  803. $initial_site = '';
  804. $site_list = drush_sitealias_resolve_sitespecs(array('@self'));
  805. if (!empty($site_list)) {
  806. $site_list = array_keys($site_list);
  807. if ($site_list[0] != "@self") {
  808. $initial_site = $site_list[0];
  809. }
  810. }
  811. if (empty($initial_site)) {
  812. drush_sitealias_load_all(TRUE);
  813. $initial_site = _drush_sitealias_find_local_alias_name(drush_get_context('DRUSH_DRUPAL_ROOT'), str_replace('http://','',drush_get_context('DRUSH_URI')));
  814. }
  815. $searchpath[] = drush_get_context('SHARE_PREFIX', '/usr') . '/share/drush/commands';
  816. $searchpath[] = drush_get_context('ETC_PREFIX', '') . '/etc/drush';
  817. $searchpath[] = realpath(dirname(__FILE__) . '/../../');
  818. $bashrc_searchpath = implode(' ', $searchpath);
  819. // Set the prompt to 'drush> ' in interactive mode.
  820. if ($interactive_mode) {
  821. $bashrc_data .= "# Set our prompt to 'drush> '\nPS1='drush> '\n\n";
  822. }
  823. // Set up our default bashrc file for the drush cli
  824. $bashrc_data .= <<<EOD
  825. # Drush .bashrc file. Copy selected portions of this
  826. # into your own bash resource file to add features of the
  827. # drush core-cli command to your default shell.
  828. # Where we will search for .bashrc files
  829. BASHRC_PATH="~/.drush $bashrc_searchpath"
  830. # Set the DRUSH_CLI variable; it may also be of use
  831. # in the user's .bashrc, or elsewhere. If we have not
  832. # already set DRUSH_CLI, add ~ to our BASHRC_PATH.
  833. # This allows us to source ~/.bashrc when we are running
  834. # `drush core-cli` without causing problems with reentrancy
  835. # if someone sources this file from ~/.bashrc.
  836. [ -z \$DRUSH_CLI ] && BASHRC_PATH="~ \$BASHRC_PATH"
  837. DRUSH_CLI=true
  838. # Cache our initial site
  839. INITIAL_SITE=$initial_site
  840. # Look for drush-specific bashrc files and
  841. # source any that are found. Will also source
  842. # \$HOME/.bashrc if run via `drush core-cli`
  843. for d in \$BASHRC_PATH ; do
  844. [ -r \$d/.bashrc ] && {
  845. . \$d/.bashrc
  846. }
  847. done
  848. # Display our initial site in the bash prompt.
  849. INITIAL_PS1="\$PS1"
  850. # When using the drush shell, all commands will
  851. # by default target the site specified by the
  852. # shell variable \$DRUPAL_SITE. To run a command
  853. # on some other site, use either:
  854. # drush @site command
  855. # or
  856. # on @site command
  857. alias on="$drush_command"
  858. # To specify a new DRUPAL_SITE without changing
  859. # your current directory:
  860. # use @site
  861. # To use the previous site (like `cd -`):
  862. # use -
  863. # To use the initial site set when the shell was
  864. # first entered:
  865. # use ~
  866. function use() {
  867. if [ "x\$1" == "x-" ]
  868. then
  869. use \$PREVIOUS_SITE
  870. # `use ~1` will go back to our initial site. Note, however,
  871. # that the shell will convert ~ to \$HOME before we get here,
  872. # so we will simply test for either ~ or \$HOME for this feature.
  873. elif [ "x\$1" == "x~" ] || [ "x\$1" == "x\$HOME" ]
  874. then
  875. use \$INITIAL_SITE
  876. elif [ "x\$1" != "x" ] && [ "x\$1" != "x@self" ]
  877. then
  878. SITE=`drush site-alias \$1 --short 2>/dev/null`
  879. if [ \$? != 0 ] || [ -z "\$SITE" ]
  880. then
  881. echo "Alias \$1 not found."
  882. else
  883. REMOTE_DRUPAL=`drush site-alias \$1 --component='remote-host' 2>/dev/null`
  884. PREVIOUS_SITE=\$DRUPAL_SITE
  885. DRUPAL_SITE=$1
  886. if [ -n "\$REMOTE_DRUPAL" ]
  887. then
  888. PS1="\$REMOTE_DRUPAL:\${1:-drush}> "
  889. else
  890. PS1="\${1:-drush}> "
  891. fi
  892. fi
  893. else
  894. PREVIOUS_SITE=\$DRUPAL_SITE
  895. DRUPAL_SITE=
  896. PS1="\$INITIAL_PS1"
  897. fi
  898. }
  899. # We override the cd command to allow convenient
  900. # shorthand notations, such as:
  901. # cd @site1
  902. # cd %modules
  903. # cd %devel
  904. # cd @site2:%files
  905. # When changing the cwd to a new site, the DRUPAL_SITE
  906. # variable is also changed, so the new site becomes
  907. # the default drush target.
  908. function cd() {
  909. d=\$1;
  910. # If we do not have a \$DRUPAL_SITE from `use @alias`,
  911. # then 'cd @alias' will still cd to @alias, but all other
  912. # patterns will be passed to builtin cd. The same behavior
  913. # will be used if \$DRUPAL_SITE points to a remote alias.
  914. if [ -z \$DRUPAL_SITE ] || [ -n "\$REMOTE_DRUPAL" ]
  915. then
  916. if [ -n "\$d" ] && [ \${d:0:1} == "@" ]
  917. then
  918. cdd \$@;
  919. else
  920. builtin cd "\$d";
  921. fi
  922. else
  923. # First special-case the no-parameter cd
  924. if [ -z "\$d" ]
  925. then
  926. cdd %root;
  927. # Next test and see if this should be an 'ordinary' cd
  928. elif [ "\$1" == "-" ] || [ -d "\$d" ]
  929. then
  930. builtin cd "\$d";
  931. else
  932. cdd \$@
  933. fi
  934. fi
  935. }
  936. # Do a special drush core-cli cd, handling
  937. # shorthand notation directory names -- anything
  938. # understood by drupal-directory
  939. function cdd() {
  940. DEST=`drupal-directory \$1 --local 2>/dev/null`
  941. if [ \$? == 0 ]
  942. then
  943. SITE=`drupal-directory \$1 --component=name 2>/dev/null`
  944. if [ -n "\$SITE" ]
  945. then
  946. use \$SITE;
  947. fi
  948. echo "cd \$DEST";
  949. builtin cd "\$DEST";
  950. else
  951. builtin cd "\$1"
  952. fi
  953. }
  954. # The command lsd will quickly do an 'ls' on the
  955. # specified special drush directory, e.g.:
  956. # lsd %modules
  957. function lsd() {
  958. # First special-case the no-parameter cd
  959. if [ "x\$1" == "x" ]
  960. then
  961. lsd %root
  962. else
  963. # Do a special drush core-cli cd, handling
  964. # shorthand notation directory names -- anything
  965. # understood by drupal-directory
  966. DEST=`drupal-directory \$1 --local`
  967. if [ \$? == 0 ]
  968. then
  969. echo "ls \$DEST";
  970. ls \$DEST;
  971. fi
  972. fi
  973. }
  974. EOD;
  975. // Add aliases for all drush commands
  976. $bashrc_data .= "# Add aliases for all drush commands\n";
  977. $commands = drush_get_commands();
  978. $cli_overrides = _convert_csv_to_array(drush_get_option('override', 'dd,help,sa'));
  979. $cli_contextual_commands = _convert_csv_to_array(drush_get_option('contextual', 'cc,cron,rsync,status,sync,updatedb'));
  980. $cli_ignore = _convert_csv_to_array(drush_get_option('ignore','core-cli,cli'));
  981. foreach ($commands as $key => $command) {
  982. // Filter out old commands that still have spaces;
  983. // do not mask any existing bash command (e.g. 'grep')
  984. // or builtin (e.g. 'eval') with drush aliases.
  985. if ((strpos($key, ' ') === FALSE) && (!in_array($key, $cli_ignore))) {
  986. $conflict = FALSE;
  987. $is_shell_builtin = (drush_shell_exec("bash -c \"builtin $key\"") == "1");
  988. if (!in_array($key, $cli_overrides)) {
  989. $status = drush_shell_exec("which $key 2>&1");
  990. if ($status !== FALSE) {
  991. $output_lines = drush_shell_exec_output();
  992. $conflict = $output_lines[0];
  993. }
  994. elseif ($is_shell_builtin) {
  995. $conflict = "builtin $key";
  996. }
  997. }
  998. elseif ($is_shell_builtin && ($key != "help")) {
  999. drush_set_error('DRUSH_OVERRIDE_BUILTIN', dt("Cannot override shell builtin function !builtin", array('!builtin' => $key)));
  1000. }
  1001. if (!$conflict) {
  1002. $bashrc_data .= "function $key() {\n $drush_command \$DRUPAL_SITE $key \"\$@\"\n}\n";
  1003. }
  1004. elseif (in_array($key, $cli_contextual_commands)) {
  1005. if ($is_shell_builtin) {
  1006. $warning = dt("Warning: overriding shell built-in command !builtin. This could cause unpredictable results with shell scripts.", array('!builtin' => $key));
  1007. drush_log($warning, 'warning');
  1008. $bashrc_data .= "# $warning\n";
  1009. }
  1010. if ($key == 'rsync') {
  1011. $bashrc_data .= "function $key() { \n HAS_SITE_PARAMS=\n for p in \"\$@\" ; do\n if [ \"x\${p:0:1}\" == \"x@\" ] || [ \"x\${p:0:1}\" == \"x%\" ]\n then\n HAS_SITE_PARAMS=true\n fi\n done\n if [ -z \$HAS_SITE_PARAMS ]\n then \n $conflict \"\$@\"\n else\n $drush_command \$DRUPAL_SITE $key \"\$@\"\n fi\n}\n";
  1012. }
  1013. else {
  1014. $bashrc_data .= "function $key() {\n if [ -z \$DRUPAL_SITE ]\n then \n $conflict \"\$@\"\n else\n $drush_command \$DRUPAL_SITE $key \"\$@\"\n fi\n}\n";
  1015. }
  1016. }
  1017. else {
  1018. $bashrc_data .= "# drush $key skipped; conflicts with $conflict\n";
  1019. }
  1020. }
  1021. }
  1022. // Make bash aliases for all drush site aliases.
  1023. // @sitealias becomes an alias for "drush @sitealias".
  1024. // This allows:
  1025. // $ @sitealias status
  1026. drush_sitealias_load_all();
  1027. foreach (drush_get_context('site-aliases') as $site_name => $site_record) {
  1028. $bashrc_data .= "alias $site_name='drush $site_name'\n";
  1029. }
  1030. // Add some additional statements to the bashrc data that
  1031. // should not go into --pipe mode.
  1032. if ($interactive_mode) {
  1033. // If there is an initial site, then cd to it. This will set the prompt.
  1034. if (!empty($initial_site)) {
  1035. $bashrc_data .= "cd $initial_site\n";
  1036. }
  1037. // Before entering the new bash script, cd to the current site root,
  1038. // if any. This will make our default site for drush match the
  1039. // currently bootstrapped site (at least until the user cd's away).
  1040. // We do this -after- the drush_print_pipe($bashrc_data) because
  1041. // we DO NOT want to change the working directory if this bashrc
  1042. // is being used by a login shell.
  1043. elseif ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  1044. $site_root = drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $site_root;
  1045. $bashrc_data .= "builtin cd $site_root\n";
  1046. }
  1047. if ($drush_command != 'drush') {
  1048. $bashrc_data .= "alias drush=\"$drush_command\"\n";
  1049. }
  1050. }
  1051. // Add some additional statements that should only appear in non-interactive mode.
  1052. else {
  1053. // If there is an initial site, then use. This will set the prompt.
  1054. if (!empty($initial_site)) {
  1055. $bashrc_data .= "use $initial_site\n";
  1056. }
  1057. }
  1058. return $bashrc_data;
  1059. }