Yaffs site version 1.1
[yaffs-website] / vendor / drush / drush / commands / core / core.drush.inc
1 <?php
2
3 /**
4  * @file
5  *   Core drush commands.
6  */
7
8 use Drush\Log\LogLevel;
9
10 /**
11  * Implementation of hook_drush_help().
12  *
13  * This function is called whenever a drush user calls
14  * 'drush help <name-of-your-command>'
15  *
16  * @param
17  *   A string with the help section (prepend with 'drush:')
18  *
19  * @return
20  *   A string with the help text for your command.
21  */
22 function core_drush_help($section) {
23   switch ($section) {
24     case 'meta:core:title':
25       return dt("Core Drush commands");
26     case 'drush:php-script':
27       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.");
28     case 'drush:rsync':
29       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.");
30     case 'error:DRUSH_DRUPAL_DB_ERROR':
31       $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
32       $message .= dt("Hint: This may occur when Drush is trying to:\n");
33       $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");
34       $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");
35       $message .= dt("\nDrush was attempting to connect to: \n!credentials\n", array('!credentials' => _core_site_credentials(12)));
36       return $message;
37     case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR':
38       $message = dt("Drush was not able to start (bootstrap) Drupal.\n");
39       $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");
40       $message .= dt("\nDrush was attempting to connect to: \n!credentials\n", array('!credentials' => _core_site_credentials(12)));
41       return $message;
42       break;
43   }
44 }
45
46 /**
47  * Implements hook_drush_help_alter().
48  */
49 function core_drush_help_alter(&$command) {
50   // Drupal 8+ only options.
51   if (drush_drupal_major_version() < 8) {
52     if ($command['commandfile'] == 'core' && $command['command'] == 'updatedb') {
53       unset($command['options']['entity-updates']);
54     }
55   }
56 }
57
58 /**
59  * Implementation of hook_drush_command().
60  *
61  * In this hook, you specify which commands your
62  * drush module makes available, what it does and
63  * description.
64  *
65  * Notice how this structure closely resembles how
66  * you define menu hooks.
67  *
68  * @return
69  *   An associative array describing your command(s).
70  */
71 function core_drush_command() {
72   $items = array();
73
74   $items['version'] = array(
75     'description' => 'Show drush version.',
76     'bootstrap' => DRUSH_BOOTSTRAP_NONE, // No bootstrap.
77     'options' => array(
78       'pipe' => 'Print just the version number, and nothing else.',
79     ),
80     'outputformat' => array(
81       'default' => 'key-value',
82       'pipe-format' => 'string',
83       'label' => 'Drush Version',
84       'output-data-type' => 'format-single',
85     ),
86   );
87   $items['core-cron'] = array(
88     'description' => 'Run all cron hooks in all active modules for specified site.',
89     'aliases' => array('cron'),
90     'topics' => array('docs-cron'),
91   );
92   $items['updatedb'] = array(
93     'description' => 'Apply any database updates required (as with running update.php).',
94     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
95     'global-options' => array(
96       'cache-clear',
97     ),
98     'options' => array(
99       'entity-updates' => 'Run automatic entity schema updates at the end of any update hooks. Defaults to --no-entity-updates.',
100     ),
101     'aliases' => array('updb'),
102   );
103   $items['entity-updates'] = array(
104     'description' => 'Apply pending entity schema updates.',
105     'aliases' => array('entup'),
106     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
107     'core' => array('8+'),
108   );
109   $items['twig-compile'] = array(
110     'description' => 'Compile all Twig template(s).',
111     'aliases' => array('twigc'),
112     'core' => array('8+'),
113   );
114   $items['updatedb-status'] = array(
115     'description' => 'List any pending database updates.',
116     'outputformat' => array(
117       'default' => 'table',
118       'pipe-format' => 'csv',
119       'field-labels' => array('module' => 'Module', 'update_id' => 'Update ID', 'description' => 'Description'),
120       'fields-default' => array('module', 'update_id', 'description'),
121       'output-data-type' => 'format-table',
122     ),
123     'aliases' => array('updbst'),
124   );
125   $items['core-config'] = array(
126     'description' => 'Edit drushrc, site alias, and Drupal settings.php files.',
127     'bootstrap' => DRUSH_BOOTSTRAP_MAX,
128     'arguments' => array(
129       'filter' => 'A substring for filtering the list of files. Omit this argument to choose from loaded files.',
130     ),
131     'global-options' => array('editor', 'bg'),
132     'examples' => array(
133       'drush core-config' => 'Pick from a list of config/alias/settings files. Open selected in editor.',
134       'drush --bg core-config' => 'Return to shell prompt as soon as the editor window opens.',
135       'drush core-config etc' => 'Edit the global configuration file.',
136       'drush core-config demo.alia' => 'Edit a particular alias file.',
137       'drush core-config sett' => 'Edit settings.php for the current Drupal site.',
138       'drush core-config --choice=2' => 'Edit the second file in the choice list.',
139     ),
140     'aliases' => array('conf', 'config'),
141   );
142   $items['core-status'] = array(
143     'description' => 'Provides a birds-eye view of the current Drupal installation, if any.',
144     'bootstrap' => DRUSH_BOOTSTRAP_MAX,
145     'aliases' => array('status', 'st'),
146     'examples' => array(
147       'drush core-status version' => 'Show all status lines that contain version information.',
148       'drush core-status --pipe' => 'A list key=value items separated by line breaks.',
149       'drush core-status drush-version --pipe' => 'Emit just the drush version with no label.',
150       'drush core-status config-sync --pipe' => 'Emit just the sync Config directory with no label.',
151     ),
152     'arguments' => array(
153       'item' => 'Optional.  The status item line(s) to display.',
154     ),
155     'options' => array(
156       'show-passwords' => 'Show database password.  Defaults to --no-show-passwords.',
157       'full' => 'Show all file paths and drush aliases in the report, even if there are a lot.',
158       'project' => array(
159         'description' => 'One or more projects that should be added to the path list',
160         'example-value' => 'foo,bar',
161       ),
162     ),
163     'outputformat' => array(
164       'default' => 'key-value',
165       'pipe-format' => 'json',
166       'field-labels' => array('drupal-version' => 'Drupal version', 'uri' => 'Site URI', 'db-driver' => 'Database driver', 'db-hostname' => 'Database hostname', 'db-port' => 'Database port', 'db-username' => 'Database username', 'db-password' => 'Database password', 'db-name' => 'Database name', 'db-status' => 'Database', 'bootstrap' => 'Drupal bootstrap', 'user' => 'Drupal user', 'theme' => 'Default theme', 'admin-theme' => 'Administration theme', 'php-bin' => 'PHP executable', 'php-conf' => 'PHP configuration', 'php-os' => 'PHP OS', 'drush-script' => 'Drush script', 'drush-version' => 'Drush version', 'drush-temp' => 'Drush temp directory', 'drush-conf' => 'Drush configuration', 'drush-alias-files' => 'Drush alias files', 'install-profile' => 'Install profile', 'root' => 'Drupal root', 'drupal-settings-file' => 'Drupal Settings File', 'site-path' => 'Site path', 'root' => 'Drupal root', 'site' => 'Site path', 'themes' => 'Themes path', 'modules' => 'Modules path', 'files' => 'File directory path', 'private' => 'Private file directory path', 'temp' => 'Temporary file directory path', 'config-sync' => 'Sync config path', 'files-path' => 'File directory path', 'temp-path' => 'Temporary file directory path', '%paths' => 'Other paths'),
167       'formatted-filter' => '_drush_core_status_format_table_data',
168       'private-fields' => 'db-password',
169       'simplify-single' => TRUE,
170       'table-metadata' => array(
171         'list-separator' => ' ',
172       ),
173       'output-data-type' => 'format-list',
174     ),
175     'topics' => array('docs-readme'),
176   );
177
178   $items['core-requirements'] = array(
179     'description' => 'Provides information about things that may be wrong in your Drupal installation, if any.',
180     'aliases' => array('status-report','rq'),
181     'examples' => array(
182       'drush core-requirements' => 'Show all status lines from the Status Report admin page.',
183       'drush core-requirements --severity=2' => 'Show only the red lines from the Status Report admin page.',
184       'drush core-requirements --pipe' => 'Print out a short report in JSON format, where severity 2=error, 1=warning, and 0/-1=OK',
185     ),
186     'options' => array(
187       'severity' => array(
188         'description' => 'Only show status report messages with a severity greater than or equal to the specified value.',
189         'value' => 'required',
190         'example-value' => '3',
191       ),
192       'ignore' => 'Comma-separated list of requirements to remove from output. Run with --pipe to see key values to use.',
193     ),
194     'outputformat' => array(
195       'default' => 'table',
196       'pipe-format' => 'json',
197       'field-labels' => array('title' => 'Title', 'severity' => 'Severity', 'sid' => 'SID', 'description' => 'Description', 'value' => 'Summary', 'reason' => 'Reason', 'weight' => 'Weight'),
198       'fields-default' => array('title', 'severity', 'description'),
199       'column-widths' => array('severity' => 8),
200       'concatenate-columns' => array('description' => array('value', 'description')),
201       'strip-tags' => TRUE,
202       'ini-item' => 'sid',
203       'key-value-item' => 'severity',
204       'list-metadata' => array(
205         'list-item' => 'severity',
206       ),
207       'output-data-type' => 'format-table',
208     ),
209   );
210   $items['php-eval'] = array(
211     'description' => 'Evaluate arbitrary php code after bootstrapping Drupal (if available).',
212     'examples' => array(
213       'drush php-eval \'variable_set("hello", "world");\'' => 'Sets the hello variable using Drupal API.',
214       'drush php-eval \'$node = node_load(1); print $node->title;\'' => 'Loads node with nid 1 and then prints its title.',
215       'drush php-eval "file_unmanaged_copy(\'$HOME/Pictures/image.jpg\', \'public://image.jpg\');"' => 'Copies a file whose path is determined by an environment\'s variable. Note the use of double quotes so the variable $HOME gets replaced by its value.',
216       'drush php-eval "node_access_rebuild();"' => 'Rebuild node access permissions.',
217     ),
218     'arguments' => array(
219       'code' => 'PHP code',
220     ),
221     'required-arguments' => TRUE,
222     'allow-additional-options' => TRUE,
223     'bootstrap' => DRUSH_BOOTSTRAP_MAX,
224     'aliases' => array('eval', 'ev'),
225     'outputformat' => array(
226       'default' => 'var_export',
227     ),
228   );
229   $items['php-script'] = array(
230     'description' => "Run php script(s).",
231     'examples' => array(
232       'drush php-script scratch' => 'Run scratch.php script. See commands/core directory.',
233       'drush php-script example --script-path=/path/to/scripts:/another/path' => 'Run script from specified paths',
234       'drush php-script' => 'List all available scripts.',
235       '' => '',
236       "#!/usr/bin/env drush\n<?php\nvariable_set('key', drush_shift());" => "Execute php code with a full Drupal bootstrap directly from a shell script.",
237     ),
238     'arguments' => array(
239       '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.',
240     ),
241     'options' => array(
242       'script-path' => array(
243         'description' => "Additional paths to search for scripts, separated by : (Unix-based systems) or ; (Windows).",
244         'example-value' => '~/scripts',
245       ),
246     ),
247     'allow-additional-options' => TRUE,
248     'bootstrap' => DRUSH_BOOTSTRAP_MAX,
249     'aliases' => array('scr'),
250     'topics' => array('docs-examplescript', 'docs-scripts'),
251   );
252   $items['core-execute'] = array(
253     'description' => 'Execute a shell command. Usually used with a site alias.',
254     'bootstrap' => DRUSH_BOOTSTRAP_NONE, // No bootstrap.
255     'arguments' => array(
256       'command' => 'The shell command to be executed.',
257     ),
258     'options' => array(
259       'escape' => 'Escape parameters before executing them with the shell. Default is escape; use --no-escape to disable.',
260     ) + drush_shell_exec_proc_build_options(),
261     'required-arguments' => TRUE,
262     'allow-additional-options' => TRUE,
263     'handle-remote-commands' => TRUE,
264     'strict-option-handling' => TRUE,
265     'examples' => array(
266       'drush core-execute git pull origin rebase' => 'Retrieve latest code from git',
267     ),
268     'aliases' => array('exec', 'execute'),
269     'topics' => array('docs-aliases'),
270   );
271   $items['core-rsync'] = array(
272     'description' => 'Rsync the Drupal tree to/from another server using ssh.',
273     'bootstrap' => DRUSH_BOOTSTRAP_NONE, // No bootstrap.
274     'arguments' => array(
275       'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
276       'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
277     ),
278     'options' => array(
279       'mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz.  Default is -akz.',
280       'exclude-conf' => 'Excludes settings.php from being rsynced.  Default.',
281       'include-conf' => 'Allow settings.php to be rsynced. Default is to exclude settings.php.',
282       'include-vcs' => 'Include special version control directories (e.g. .svn).  Default is to exclude vcs files.',
283       'exclude-files' => 'Exclude the files directory.',
284       'exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
285       '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"',
286       'exclude-paths' => 'List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).',
287       'include-paths' => 'List of paths to include, seperated by : (Unix-based systems) or ; (Windows).',
288       '{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 explanation of all the rsync options and values.",
289       'rsync-version' => 'Set to the version of rsync you are using to signal Drush to go into backwards-compatibility mode when using very old versions of rsync. For example, --rsync-version=2.6.8 or earlier will cause Drush to avoid the --remove-source-files flag.',
290
291     ),
292     'strict-option-handling' => TRUE,
293     'examples' => array(
294       'drush rsync @dev @stage' => 'Rsync Drupal root from Drush alias dev to the alias stage. Either or both may be remote.',
295       '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.',
296       '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.",
297     ),
298     'aliases' => array('rsync'),
299     'topics' => array('docs-aliases'),
300   );
301   $items['drupal-directory'] = array(
302     'description' => 'Return the filesystem path for modules/themes and other key folders.',
303     'arguments' => array(
304       '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.',
305     ),
306     'options' => array(
307       'component' => "The portion of the evaluated path to return.  Defaults to 'path'; 'name' returns the site alias of the target.",
308       'local-only' => "Reject any target that specifies a remote site.",
309     ),
310     'examples' => array(
311       'cd `drush dd devel`' => 'Navigate into the devel module directory',
312       'cd `drush dd` ' => 'Navigate to the root of your Drupal site',
313       'cd `drush dd files`' => 'Navigate to the files directory.',
314       'drush dd @alias:%files' => 'Print the path to the files directory on the site @alias.',
315       'edit `drush dd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)",
316     ),
317     'aliases' => array('dd'),
318     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
319   );
320
321   $items['batch-process'] = array(
322     'description' => 'Process operations in the specified batch set',
323     'hidden' => TRUE,
324     'arguments' => array(
325       'batch-id' => 'The batch id that will be processed.',
326     ),
327     'required-arguments' => TRUE,
328     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
329   );
330
331   $items['updatedb-batch-process'] = array(
332     'description' => 'Perform update functions',
333     'hidden' => TRUE,
334     'arguments' => array(
335       'batch-id' => 'The batch id that will be processed',
336     ),
337     'required-arguments' => TRUE,
338     // Drupal 7 needs DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION, while Drupal 8 needs _FULL.
339     // Therefore we bootstrap to _FULL in commands/core/drupal/update.inc.
340     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
341   );
342   $items['core-global-options'] = array(
343     'description' => 'All global options',
344     'hidden' => TRUE,
345     'topic' => TRUE,
346     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
347     'outputformat' => array(
348       'default' => 'table',
349       'pipe-format' => 'csv',
350       'field-labels' => array('label' => 'Label', 'description' => 'Description'),
351       'output-data-type' => 'format-table',
352     ),
353   );
354   $items['core-quick-drupal'] = array(
355     'description' => 'Download, install, serve and login to Drupal with minimal configuration and dependencies.',
356     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
357     'aliases' => array('qd', 'cutie'),
358     'arguments' => array(
359       '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.',
360       '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.',
361     ),
362     'examples' => array(
363       'drush qd' => 'Download and install stable release of Drupal into a timestamped directory, start server, and open the site logged in as admin.',
364       'drush qd --profile=minimal --cache --core=drupal-8.0.x --yes' => 'Fire up dev release of Drupal site with minimal install profile.',
365       '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.',
366       '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.',
367       'drush qd --makefile=mysite.make' => 'Create and install a site from a makefile.',
368     ),
369   );
370   // Add in options/engines.
371   drush_core_quick_drupal_options($items);
372   // Add in topics for engines
373   $items += drush_get_engine_topics();
374   return $items;
375 }
376
377 /**
378  * Command argument complete callback.
379  *
380  * @return
381  *   Array of available profile names.
382  */
383 function core_site_install_complete() {
384   $max = drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_ROOT);
385   if ($max >= DRUSH_BOOTSTRAP_DRUPAL_ROOT) {
386     return array('values' => array_keys(drush_find_profiles(DRUPAL_ROOT)));
387   }
388 }
389
390 /**
391  * Command argument complete callback.
392  *
393  * @return
394  *  Array of available site aliases.
395  */
396 function core_core_rsync_complete() {
397   return array('values' => array_keys(_drush_sitealias_all_list()));
398 }
399
400 /**
401  * @defgroup engines Engine types
402  * @{
403  */
404
405 /**
406  * Implementation of hook_drush_engine_type_info().
407  */
408 function core_drush_engine_type_info() {
409   $info = array();
410   $info['drupal'] = array();
411   return $info;
412 }
413
414 /**
415  * Implements hook_drush_engine_ENGINE_TYPE().
416  */
417 function core_drush_engine_drupal() {
418   $engines = array(
419     'batch' => array(),
420     'update'=> array(),
421     'environment' => array(),
422     'site_install' => array(),
423     'pm' => array(),
424     'cache' => array(),
425     'image' => array(),
426   );
427   return $engines;
428 }
429
430 /**
431  * @} End of "Engine types".
432  */
433
434 /**
435  * Command handler. Apply pending entity schema updates.
436  */
437 function drush_core_entity_updates() {
438   if (drush_get_context('DRUSH_SIMULATE')) {
439     drush_log(dt('entity-updates command does not support --simulate option.'), LogLevel::OK);
440   }
441
442   drush_include_engine('drupal', 'update');
443   if (entity_updates_main() === FALSE) {
444     return FALSE;
445   }
446
447   drush_drupal_cache_clear_all();
448
449   drush_log(dt('Finished performing updates.'), LogLevel::OK);
450 }
451
452 /**
453  * Command handler. Execute update.php code from drush.
454  */
455 function drush_core_updatedb() {
456   if (drush_get_context('DRUSH_SIMULATE')) {
457     drush_log(dt('updatedb command does not support --simulate option.'), LogLevel::OK);
458     return TRUE;
459   }
460
461   drush_include_engine('drupal', 'update');
462   $result = update_main();
463   if ($result === FALSE) {
464     return FALSE;
465   }
466   elseif ($result > 0) {
467     // Clear all caches in a new process. We just performed major surgery.
468     drush_drupal_cache_clear_all();
469
470     drush_log(dt('Finished performing updates.'), LogLevel::OK);
471   }
472 }
473
474 /**
475  * Command handler. List pending DB updates.
476  */
477 function drush_core_updatedb_status() {
478   require_once DRUSH_DRUPAL_CORE . '/includes/install.inc';
479   drupal_load_updates();
480   drush_include_engine('drupal', 'update');
481   list($pending, $start) = updatedb_status();
482   if (empty($pending)) {
483     drush_log(dt("No database updates required"), LogLevel::OK);
484   }
485   return $pending;
486 }
487
488 function _core_site_credentials($right_margin = 0) {
489   // Leave some space on the right so that we can put the result into the
490   // drush_log, which will again wordwrap the result.
491   $original_columns = drush_get_context('DRUSH_COLUMNS', 80);
492   drush_set_context('DRUSH_COLUMNS', $original_columns - $right_margin);
493   $status_table = _core_site_status_table();
494   $metadata = drush_get_command_format_metadata('core-status');
495   $output = drush_format($status_table, $metadata, 'key-value');
496   drush_set_context('DRUSH_COLUMNS', $original_columns);
497   return $output;
498 }
499
500 function _core_path_aliases($project = '') {
501   $paths = array();
502   $site_wide = drush_drupal_sitewide_directory();
503   $boot = drush_get_bootstrap_object();
504   if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
505     $paths['%root'] = $drupal_root;
506     if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
507       $paths['%site'] = $site_root;
508       if (is_dir($modules_path = $boot->conf_path() . '/modules')) {
509         $paths['%modules'] = $modules_path;
510       }
511       else {
512         $paths['%modules'] = ltrim($site_wide . '/modules', '/');
513       }
514       if (is_dir($themes_path = $boot->conf_path() . '/themes')) {
515         $paths['%themes'] = $themes_path;
516       }
517       else {
518         $paths['%themes'] = ltrim($site_wide . '/themes', '/');
519       }
520       if (drush_drupal_major_version() >= 8 && drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION)) {
521         try {
522           if (isset($GLOBALS['config_directories'])) {
523             foreach ($GLOBALS['config_directories'] as $label => $unused) {
524               $paths["%config-$label"] = config_get_config_directory($label);
525             }
526           }
527         }
528         catch (Exception $e) {
529           // Nothing to do.
530         }
531       }
532
533       if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) {
534         $paths['%files'] = drush_file_get_public();
535         if ($private_path = drush_file_get_private()) {
536           $paths['%private'] = $private_path;
537         }
538       }
539
540       if (function_exists('file_directory_temp')) {
541         $paths['%temp'] = file_directory_temp();
542       }
543       // If the 'project' parameter was specified, then search
544       // for a project (or a few) and add its path to the path list
545       if (!empty($project)) {
546         drush_include_engine('drupal', 'environment');
547         $projects = array_merge(drush_get_modules(), drush_get_themes());
548         foreach(explode(',', $project) as $target) {
549           if (array_key_exists($target, $projects)) {
550             $paths['%' . $target] = $drupal_root . '/' . _drush_extension_get_path($projects[$target]);
551           }
552         }
553       }
554     }
555   }
556
557   // Add in all of the global paths from $options['path-aliases']
558   $paths = array_merge($paths, drush_get_option('path-aliases', array()));
559
560   return $paths;
561 }
562
563 function _core_site_status_table($project = '') {
564   $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
565   if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
566     $status_table['drupal-version'] = drush_drupal_version();
567     $boot_object = drush_get_bootstrap_object();
568     $conf_dir = $boot_object->conf_path();
569     $settings_file = "$conf_dir/settings.php";
570     $status_table['drupal-settings-file'] = file_exists($settings_file) ? $settings_file : '';
571     if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
572       $status_table['uri'] = drush_get_context('DRUSH_URI');
573       try {
574         $sql = drush_sql_get_class();
575         $db_spec = $sql->db_spec();
576         $status_table['db-driver'] = $db_spec['driver'];
577         if (!empty($db_spec['unix_socket'])) {
578           $status_table['db-socket'] = $db_spec['unix_socket'];
579         }
580         elseif (isset($db_spec['host'])) {
581           $status_table['db-hostname'] = $db_spec['host'];
582         }
583         $status_table['db-username'] = isset($db_spec['username']) ? $db_spec['username'] : NULL;
584         $status_table['db-password'] = isset($db_spec['password']) ? $db_spec['password'] : NULL;
585         $status_table['db-name'] = isset($db_spec['database']) ? $db_spec['database'] : NULL;
586         $status_table['db-port'] = isset($db_spec['port']) ? $db_spec['port'] : NULL;
587         if ($phase > DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION) {
588           $status_table['install-profile'] = $boot_object->get_profile();
589           if ($phase > DRUSH_BOOTSTRAP_DRUPAL_DATABASE) {
590             $status_table['db-status'] = dt('Connected');
591             if ($phase > DRUSH_BOOTSTRAP_DRUPAL_FULL) {
592               $status_table['bootstrap'] = dt('Successful');
593               if ($phase == DRUSH_BOOTSTRAP_DRUPAL_LOGIN) {
594                 $status_table['user'] = drush_user_get_class()->getCurrentUserAsSingle()->getUsername();
595               }
596             }
597           }
598         }
599       }
600       catch (Exception $e) {
601         // Don't worry be happy.
602       }
603     }
604     if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) {
605       $status_table['theme'] = drush_theme_get_default();
606       $status_table['admin-theme'] = drush_theme_get_admin();
607     }
608   }
609   if ($php_bin = drush_get_option('php')) {
610     $status_table['php-bin'] = $php_bin;
611   }
612   $status_table['php-os'] = PHP_OS;
613   if ($php_ini_files = _drush_core_config_php_ini_files()) {
614     $status_table['php-conf'] = $php_ini_files;
615   }
616   $status_table['drush-script'] = DRUSH_COMMAND;
617   $status_table['drush-version'] = DRUSH_VERSION;
618   $status_table['drush-temp'] = drush_find_tmp();
619   $status_table['drush-conf'] = drush_flatten_array(drush_get_context_options('context-path', ''));
620   $alias_files = _drush_sitealias_find_alias_files();
621   $status_table['drush-alias-files'] = $alias_files;
622
623   $paths = _core_path_aliases($project);
624   if (!empty($paths)) {
625     foreach ($paths as $target => $one_path) {
626       $name = $target;
627       if (substr($name,0,1) == '%') {
628         $name = substr($name,1);
629       }
630       $status_table[$name] = $one_path;
631     }
632   }
633
634   // Store the paths into the '%paths' index; this will be
635   // used by other code, but will not be included in the output
636   // of the drush status command.
637   $status_table['%paths'] = $paths;
638
639   return $status_table;
640 }
641
642 // Adjust the status output for any non-pipe output format
643 function _drush_core_status_format_table_data($output, $metadata) {
644   if (drush_get_option('full', FALSE) == FALSE) {
645     // Hide any key that begins with a %
646     foreach ($output as $key => $value) {
647       if ($key[0] == '%') {
648         unset($output[$key]);
649       }
650     }
651     // Hide 'Modules path' and 'Themes path' as well
652     unset($output['modules']);
653     unset($output['themes']);
654     // Shorten the list of alias files if there are too many
655     if (isset($output['drush-alias-files']) && count($output['drush-alias-files']) > 24) {
656       $msg = dt("\nThere are !count more alias files. Run with --full to see the full list.", array('!count' => count($output['drush-alias-files']) - 1));
657       $output['drush-alias-files'] = array($output['drush-alias-files'][0] , $msg);
658     }
659     if (isset($output['drupal-settings-file']) && empty($output['drupal-settings-file'])) {
660       $output['drupal-settings-file'] = dt('MISSING');
661     }
662   }
663   return $output;
664 }
665
666 /**
667  * Command callback. Runs all cron hooks.
668  */
669 function drush_core_cron() {
670   if (drush_drupal_major_version() < 8) {
671     $result = drupal_cron_run();
672   }
673   else {
674     $result = \Drupal::service('cron')->run();
675   }
676   if ($result) {
677     drush_log(dt('Cron run successful.'), LogLevel::SUCCESS);
678   }
679   else {
680     return drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
681   }
682 }
683
684 /**
685  * Command callback. Edit drushrc and alias files.
686  */
687 function drush_core_config($filter = NULL) {
688   $all = drush_core_config_load();
689
690   // Apply any filter that was supplied.
691   if ($filter) {
692     foreach ($all as $key => $file) {
693       if (strpos($file, $filter) === FALSE) {
694         unset($all[$key]);
695       }
696     }
697   }
698   $all = drush_map_assoc(array_values($all));
699
700   $exec = drush_get_editor();
701   if (count($all) == 1) {
702     $filepath = current($all);
703   }
704   else {
705     $choice = drush_choice($all, 'Enter a number to choose which file to edit.', '!key');
706     if (!$choice) {
707       return drush_user_abort();
708     }
709     $filepath = $all[$choice];
710   }
711   return drush_shell_exec_interactive($exec, $filepath, $filepath);
712 }
713
714 /**
715  * Command argument complete callback.
716  *
717  * @return
718  *   Array of available configuration files for editing.
719  */
720 function core_core_config_complete() {
721   return array('values' => drush_core_config_load(FALSE));
722 }
723
724 function drush_core_config_load($headers = TRUE) {
725   $php_header = $php = $rcs_header = $rcs = $aliases_header = $aliases = $drupal_header = $drupal = array();
726   $php = _drush_core_config_php_ini_files();
727   if (!empty($php)) {
728     if ($headers) {
729       $php_header = array('phpini' => '-- PHP ini files --');
730     }
731   }
732
733   $bash = _drush_core_config_bash_files();
734   if (!empty($bash)) {
735     if ($headers) {
736       $bash_header = array('bash' => '-- Bash files --');
737     }
738   }
739
740   drush_sitealias_load_all();
741   if ($rcs = drush_get_context_options('context-path', TRUE)) {
742     if ($headers) {
743       $rcs_header = array('drushrc' => '-- Drushrc --');
744     }
745   }
746   if ($aliases = drush_get_context('drush-alias-files')) {
747     if ($headers) {
748       $aliases_header = array('aliases' => '-- Aliases --');
749     }
750   }
751   if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
752     $drupal[] = realpath($site_root . '/settings.php');
753     if (file_exists($site_root . '/settings.local.php')) {
754       $drupal[] = realpath($site_root . '/settings.local.php');
755     }
756     $drupal[] = realpath(DRUPAL_ROOT . '/.htaccess');
757     if ($headers) {
758       $drupal_header = array('drupal' => '-- Drupal --');
759     }
760   }
761   return array_merge($php_header, $php, $bash_header, $bash, $rcs_header, $rcs, $aliases_header, $aliases, $drupal_header, $drupal);
762 }
763
764 function _drush_core_config_php_ini_files() {
765   $ini_files = array();
766   $ini_files[] = php_ini_loaded_file();
767   if ($drush_ini = getenv('DRUSH_INI')) {
768     if (file_exists($drush_ini)) {
769       $ini_files[] = $drush_ini;
770     }
771   }
772   foreach (array(DRUSH_BASE_PATH, '/etc/drush', drush_server_home() . '/.drush') as $ini_dir) {
773     if (file_exists($ini_dir . "/drush.ini")) {
774       $ini_files[] = realpath($ini_dir . "/drush.ini");
775     }
776   }
777   return array_unique($ini_files);
778 }
779
780 function _drush_core_config_bash_files() {
781   $bash_files = array();
782   $home = drush_server_home();
783   if ($bashrc = drush_init_find_bashrc($home)) {
784     $bash_files[] = $bashrc;
785   }
786   $prompt = $home . '/.drush/drush.prompt.sh';
787   if (file_exists($prompt)) {
788     $bash_files[] = $prompt;
789   }
790   return $bash_files;
791 }
792
793 /**
794  * Command callback. Provides information from the 'Status Reports' admin page.
795  */
796 function drush_core_requirements() {
797   include_once DRUSH_DRUPAL_CORE . '/includes/install.inc';
798   $severities = array(
799     REQUIREMENT_INFO => t('Info'),
800     REQUIREMENT_OK => t('OK'),
801     REQUIREMENT_WARNING => t('Warning'),
802     REQUIREMENT_ERROR => t('Error'),
803   );
804
805   drupal_load_updates();
806
807   drush_include_engine('drupal', 'environment');
808   $requirements = drush_module_invoke_all('requirements', 'runtime');
809   // If a module uses "$requirements[] = " instead of
810   // "$requirements['label'] = ", then build a label from
811   // the title.
812   foreach($requirements as $key => $info) {
813     if (is_numeric($key)) {
814       unset($requirements[$key]);
815       $new_key = strtolower(str_replace(' ', '_', $info['title']));
816       $requirements[$new_key] = $info;
817     }
818   }
819   $ignore_requirements = drush_get_option_list('ignore');
820   foreach ($ignore_requirements as $ignore) {
821     unset($requirements[$ignore]);
822   }
823   ksort($requirements);
824
825   $min_severity = drush_get_option('severity', -1);
826   foreach($requirements as $key => $info) {
827     $severity = array_key_exists('severity', $info) ? $info['severity'] : -1;
828     $requirements[$key]['sid'] = $severity;
829     $requirements[$key]['severity'] = $severities[$severity];
830     if ($severity < $min_severity) {
831       unset($requirements[$key]);
832     }
833     if (isset($requirements[$key]['description'])) {
834       $requirements[$key]['description'] = drush_render($requirements[$key]['description']);
835     }
836   }
837   return $requirements;
838 }
839
840 /**
841  * Command callback. Provides a birds-eye view of the current Drupal
842  * installation.
843  */
844 function drush_core_status() {
845   $status_table = _core_site_status_table(drush_get_option('project',''));
846   // If args are specified, filter out any entry that is not named
847   // (in other words, only show lines named by one of the arg values)
848   $args = func_get_args();
849   if (!empty($args)) {
850     $field_list = $args;
851     $metadata = drush_get_command_format_metadata('core-status');
852     foreach ($metadata['field-labels'] as $field_key => $field_label) {
853       if (_drush_core_is_named_in_array($field_label, $args)) {
854         $field_list[] = $field_key;
855       }
856     }
857     foreach ($status_table as $key => $value) {
858       if (!_drush_core_is_named_in_array($key, $field_list)) {
859         unset($status_table[$key]);
860       }
861     }
862   }
863   return $status_table;
864 }
865
866 // Command callback. Show all global options. Exposed via topic command.
867 function drush_core_global_options() {
868   drush_print(dt('These options are applicable to most drush commands. Most options can be disabled by using --no-option (i.e. --no-debug to disable --debug.)'));
869   drush_print();
870   $fake = drush_global_options_command(FALSE);
871   return drush_format_help_section($fake, 'options');
872 }
873
874 function _drush_core_is_named_in_array($key, $the_array) {
875   $is_named = FALSE;
876
877   $simplified_key = str_replace(array(' ', '_', '-'), array('', '', ''), $key);
878
879   foreach ($the_array as $name) {
880     if (stristr($simplified_key, str_replace(array(' ', '_', '-'), array('', '', ''), $name))) {
881       $is_named = TRUE;
882     }
883   }
884
885   return $is_named;
886 }
887
888 /**
889  * Callback for core-quick-drupal command.
890  */
891 function drush_core_quick_drupal() {
892   $requests = FALSE;
893   $make_projects = array();
894   $args = func_get_args();
895   $name = drush_get_option('use-name');
896   drush_set_option('backend', TRUE);
897   drush_set_option('strict', FALSE); // We fail option validation because do so much internal drush_invoke().
898   $makefile = drush_get_option('makefile');
899   $root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
900   if (drush_get_option('use-existing', ($root != FALSE))) {
901     if (!$root) {
902       return drush_set_error('QUICK_DRUPAL_NO_ROOT_SPECIFIED', 'Must specify site with --root when using --use-existing.');
903     }
904     // If a --db-url was not explicitly provided, and if there is already
905     // a settings.php file provided, then use the db-url defined inside it.
906     if (!drush_get_option('db-url', FALSE)) {
907       $values = drush_invoke_process('@self', 'site-alias', array('@self'), array('with-db-url' => TRUE), array('integrate' => FALSE, 'override-simulated' => TRUE));
908       if (!empty($values['object']['self']['db-url'])) {
909         drush_set_option('db-url', $values['object']['self']['db-url']);
910       }
911     }
912     if (empty($name)) {
913       $name = basename($root);
914     }
915     $base = dirname($root);
916   }
917   else {
918     if (!empty($args) && empty($name)) {
919       $name = array_shift($args);
920     }
921     if (empty($name)) {
922       $name = 'quick-drupal-' . gmdate('YmdHis', $_SERVER['REQUEST_TIME']);
923     }
924     $root = drush_get_option('root', FALSE);
925     $core = drush_get_option('core', 'drupal');
926     $project_rename = $core;
927     if ($root) {
928       $base = dirname($root);
929       $project_rename = basename($root);
930     }
931     else {
932       $base = getcwd() . '/' . $name;
933       $root = $base . '/' . $core;
934     }
935     if (!empty($makefile)) {
936       // Invoke 'drush make $makefile'.
937       $result = drush_invoke_process('@none', 'make', array($makefile, $root), array('core-quick-drupal' => TRUE));
938       if ($result['error_status'] != 0) {
939         return drush_set_error('DRUSH_QD_MAKE', 'Could not make; aborting.');
940       }
941       $make_projects = array_diff(array_keys($result['object']['projects']), array('drupal'));
942     }
943     else {
944       drush_mkdir($base);
945       drush_set_option('destination', $base);
946       drush_set_option('drupal-project-rename', $project_rename);
947       if (drush_invoke('pm-download', array($core)) === FALSE) {
948         return drush_set_error('QUICK_DRUPAL_CORE_DOWNLOAD_FAIL', 'Drupal core download/extract failed.');
949       }
950     }
951   }
952   if (!drush_get_option('db-url', FALSE)) {
953     drush_set_option('db-url', 'sqlite://sites/' . strtolower(drush_get_option('sites-subdir', 'default')) . "/files/$name.sqlite");
954   }
955   // We have just created a site root where one did not exist before.
956   // We therefore must manually reset DRUSH_SELECTED_DRUPAL_ROOT to
957   // our new root, and force a bootstrap to DRUSH_BOOTSTRAP_DRUPAL_ROOT.
958   drush_set_context('DRUSH_SELECTED_DRUPAL_ROOT', $root);
959   if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_ROOT)) {
960     return drush_set_error('QUICK_DRUPAL_ROOT_LOCATE_FAIL', 'Unable to locate Drupal root directory.');
961   }
962   if (!empty($args)) {
963     $requests = pm_parse_arguments($args, FALSE);
964   }
965   if ($requests) {
966     // Unset --destination, so that downloads go to the site directories.
967     drush_unset_option('destination');
968     if (drush_invoke('pm-download', $requests) === FALSE) {
969       return drush_set_error('QUICK_DRUPAL_PROJECT_DOWNLOAD_FAIL', 'Project download/extract failed.');
970     }
971   }
972   drush_invoke('site-install', array(drush_get_option('profile')));
973   // Log in with the admin user.
974   // TODO: If site-install is given a sites-subdir other than 'default',
975   // then it will bootstrap to DRUSH_BOOTSTRAP_DRUPAL_SITE get the installer
976   // to recognize the desired site directory. This somehow interferes
977   // with our desire to bootstrap to DRUSH_BOOTSTRAP_DRUPAL_LOGIN here.
978   // We could do the last few steps in a new process if uri is not 'default'.
979   drush_set_option('user', '1');
980   if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_LOGIN)) {
981     return drush_set_error('QUICK_DRUPAL_INSTALL_FAIL', 'Drupal core install failed.');
982   }
983   $enable = array_merge(pm_parse_arguments(drush_get_option('enable', $requests)), $make_projects);
984   if (!empty($enable)) {
985     if (drush_invoke('pm-enable', $enable) === FALSE) {
986      return drush_set_error('QUICK_DRUPAL_PROJECT_ENABLE_FAIL', 'Project enable failed.');
987     }
988   }
989   $server = drush_get_option('server', '/');
990   if ($server) {
991     $server_uri = runserver_uri($server);
992     _drush_core_qd_cache_uri($server_uri);
993   }
994   if (!drush_get_option('no-server', FALSE)) {
995     if ($server) {
996       // Current CLI user is also the web server user, which is for development
997       // only. Hence we can safely make the site directory writable. This makes
998       // it easier to delete and edit settings.php.
999       $boot = drush_get_bootstrap_object();
1000       @chmod($boot->conf_path(), 0700);
1001       drush_invoke_process(array('root' => $root, 'uri' => $server_uri), 'runserver', array($server));
1002     }
1003   }
1004   else {
1005     drush_print(dt('Login URL: ') . drush_invoke('user-login'));
1006   }
1007 }
1008
1009 // Write a drushrc.php to cache the server information for future Drush calls
1010 function _drush_core_qd_cache_uri($uri) {
1011   $server = $uri['host'];
1012   if (!empty($uri["port"])) {
1013     $server .= ':' . $uri["port"];
1014   }
1015   $dir = DRUPAL_ROOT . '/drush';
1016   $target_file = $dir . '/drushrc.php';
1017   drush_log(dt("Caching 'uri' !uri in !target", array('!uri' => $server, '!target' => $target_file)), LogLevel::OK);
1018   $create_file = TRUE;
1019   if (file_exists($target_file)) {
1020     // Don't bother to ask with --use-existing; just
1021     // continue.
1022     if (drush_get_option('use-existing', FALSE)) {
1023       $create_file = FALSE;
1024     }
1025     else {
1026       $create_file = drush_confirm(dt('!target already exists. Overwrite?', array('!target' => $target_file)));
1027     }
1028   }
1029   $content = <<<EOT
1030 <?php
1031
1032 // Inserted by `drush quick-drupal`.  This allows `drush user-login`
1033 // and similar commands to work seemlessly.  Remove if using
1034 // Drupal multisite feature.
1035 \$options['uri'] = "$server";
1036 EOT;
1037   if ($create_file) {
1038     drush_mkdir($dir);
1039     file_put_contents($target_file, $content);
1040   }
1041 }
1042
1043 /**
1044  * Include options and engines for core-quick-drupal command, aggregated from
1045  * other command options that are available. We prefix option descriptons,
1046  * to make the long list more navigable.
1047  *
1048  * @param $items
1049  *   The core commandfile command array, by reference. Used to include
1050  *   site-install options and add options and engines for core-quick-drupal.
1051  */
1052 function drush_core_quick_drupal_options(&$items) {
1053   $options = array(
1054     'core' => 'Drupal core to download. Defaults to "drupal" (latest stable version).',
1055     'use-existing' => 'Use an existing Drupal root, specified with --root. Overrides --core. Defaults to true when run from an existing site.',
1056     'profile' => 'The install profile to use. Defaults to standard.',
1057     'enable' => 'Specific extensions (modules or themes) to enable. By default, extensions with the same name as requested projects will be enabled automatically.',
1058     '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.',
1059     'no-server' => 'Avoid starting runserver (and browser) for the created Drupal site.',
1060     'browser' => 'Optional name of a browser to open site in. If omitted the OS default browser will be used. Set --no-browser to disable.',
1061     'use-name' => array('hidden' => TRUE, 'description' => 'Overrides "name" argument.'),
1062     'makefile' => array('description' => 'Makefile to use. Makefile must specify which version of Drupal core to build.', 'example-value' => 'mysite.make', 'value' => 'optional'),
1063     'root' => array('description' => 'Path to Drupal root.', 'example-value' => '/path/to/root', 'value' => 'optional'),
1064   );
1065   $pm = pm_drush_command();
1066   foreach ($pm['pm-download']['options'] as $option => $description) {
1067     if (is_array($description)) {
1068       $description = $description['description'];
1069     }
1070     $options[$option] = 'Download option: ' . $description;
1071   }
1072   // Unset a few options that are not usable here, as we control them ourselves
1073   // or they are otherwise implied by the environment.
1074   unset($options['destination']);
1075   unset($options['drupal-project-rename']);
1076   unset($options['default-major']);
1077   unset($options['use-site-dir']);
1078   $si = site_install_drush_command();
1079   foreach ($si['site-install']['options'] as $option => $description) {
1080     if (is_array($description)) {
1081       $description = $description['description'];
1082     }
1083     $options[$option] = 'Site install option: ' . $description;
1084   }
1085   unset($options['sites-subdir']);
1086   $runserver = runserver_drush_command();
1087   foreach ($runserver['runserver']['options'] as $option => $description) {
1088     $options[$option] = 'Runserver option: ' . $description;
1089   }
1090   unset($options['user']);
1091   $items['core-quick-drupal']['options'] = $options;
1092   $items['core-quick-drupal']['engines'] = $pm['pm-download']['engines'];
1093 }
1094
1095 /**
1096  * Command callback. Runs "naked" php scripts
1097  * and drush "shebang" scripts ("#!/usr/bin/env drush").
1098  */
1099 function drush_core_php_script() {
1100   $found = FALSE;
1101   $script = NULL;
1102   if ($args = func_get_args()) {
1103     $script = $args[0];
1104   }
1105
1106   if ($script == '-') {
1107     return eval(stream_get_contents(STDIN));
1108   }
1109   elseif (file_exists($script)) {
1110     $found = $script;
1111   }
1112   else {
1113     // Array of paths to search for scripts
1114     $searchpath['DIR'] = dirname(__FILE__);
1115     $searchpath['cwd'] = drush_cwd();
1116
1117     // Additional script paths, specified by 'script-path' option
1118     if ($script_path = drush_get_option('script-path', FALSE)) {
1119       foreach (explode(PATH_SEPARATOR, $script_path) as $path) {
1120         $searchpath[] = $path;
1121       }
1122     }
1123     drush_log(dt('Searching for scripts in ') . implode(',', $searchpath), LogLevel::DEBUG);
1124
1125     if (!isset($script)) {
1126       // List all available scripts.
1127       $all = array();
1128       foreach($searchpath as $key => $path) {
1129         $recurse = !(($key == 'cwd') || ($path == '/'));
1130         $all = array_merge( $all , array_keys(drush_scan_directory($path, '/\.php$/', array('.', '..', 'CVS'), NULL, $recurse)) );
1131       }
1132       drush_print(implode("\n", $all));
1133     }
1134     else {
1135       // Execute the specified script.
1136       foreach($searchpath as $path) {
1137         $script_filename = $path . '/' . $script;
1138         if (file_exists($script_filename . '.php')) {
1139           $script_filename .= '.php';
1140         }
1141         if (file_exists($script_filename)) {
1142           $found = $script_filename;
1143           break;
1144         }
1145         $all[] = $script_filename;
1146       }
1147       if (!$found) {
1148         return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
1149       }
1150     }
1151   }
1152
1153   if ($found) {
1154     // Set the DRUSH_SHIFT_SKIP to two; this will cause
1155     // drush_shift to skip the next two arguments the next
1156     // time it is called.  This allows scripts to get all
1157     // arguments, including the 'php-script' and script
1158     // pathname, via drush_get_arguments(), or it can process
1159     // just the arguments that are relevant using drush_shift().
1160     drush_set_context('DRUSH_SHIFT_SKIP', 2);
1161     if (_drush_core_eval_shebang_script($found) === FALSE) {
1162       return include($found);
1163     }
1164   }
1165 }
1166
1167 function drush_core_php_eval($php) {
1168   return eval($php . ';');
1169 }
1170
1171 /**
1172  * Evaluate a script that begins with #!drush php-script
1173  */
1174 function _drush_core_eval_shebang_script($script_filename) {
1175   $found = FALSE;
1176   $fp = fopen($script_filename, "r");
1177   if ($fp !== FALSE) {
1178     $line = fgets($fp);
1179     if (_drush_is_drush_shebang_line($line)) {
1180       $first_script_line = '';
1181       while ($line = fgets($fp)) {
1182         $line = trim($line);
1183         if ($line == '<?php') {
1184           $found = TRUE;
1185           break;
1186         }
1187         elseif (!empty($line)) {
1188           $first_script_line = $line . "\n";
1189           break;
1190         }
1191       }
1192       $script = stream_get_contents($fp);
1193       // Pop off the first two arguments, the
1194       // command (php-script) and the path to
1195       // the script to execute, as a service
1196       // to the script.
1197       eval($first_script_line . $script);
1198       $found = TRUE;
1199     }
1200     fclose($fp);
1201   }
1202   return $found;
1203 }
1204
1205 /**
1206  * Command callback. Process sets from the specified batch.
1207  *
1208  * This is the default batch processor that will be used if the $command parameter
1209  * to drush_backend_batch_process() has not been specified.
1210  */
1211 function drush_core_batch_process($id) {
1212   drush_batch_command($id);
1213 }
1214
1215 /**
1216  * Command callback. Process outstanding updates during updatedb.
1217  *
1218  * This is a batch processing command that makes use of the drush_backend_invoke
1219  * api.
1220  *
1221  * This command includes the version specific update engine, which correctly
1222  * initialises the environment to be able to successfully handle minor and major
1223  * upgrades.
1224  */
1225 function drush_core_updatedb_batch_process($id) {
1226   drush_include_engine('drupal', 'update');
1227   _update_batch_command($id);
1228 }
1229
1230 /**
1231  * Given a target (e.g. @site:%modules), return the evaluated directory path.
1232  *
1233  * @param $target
1234  *   The target to evaluate.  Can be @site or /path or @site:path
1235  *   or @site:%pathalias, etc. (just like rsync parameters)
1236  * @param $component
1237  *   The portion of the evaluated path to return.  Possible values:
1238  *   'path' - the full path to the target (default)
1239  *   'name' - the name of the site from the path (e.g. @site1)
1240  *   'user-path' - the part after the ':' (e.g. %modules)
1241  *   'root' & 'uri' - the Drupal root and URI of the site from the path
1242  *   'path-component' - The ':' and the path
1243  */
1244 function _drush_core_directory($target = 'root', $component = 'path', $local_only = FALSE) {
1245   // Normalize to a sitealias in the target.
1246   $normalized_target = $target;
1247   if (strpos($target, ':') === FALSE) {
1248     if (substr($target, 0, 1) != '@') {
1249       // drush_sitealias_evaluate_path() requires bootstrap to database.
1250       if (!drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_DATABASE)) {
1251         return drush_set_error('DRUPAL_SITE_NOT_FOUND', dt('You need to specify an alias or run this command within a drupal site.'));
1252       }
1253       $normalized_target = '@self:';
1254       if (substr($target, 0, 1) != '%') {
1255         $normalized_target .= '%';
1256       }
1257       $normalized_target .= $target;
1258     }
1259   }
1260   $additional_options = array();
1261   $values = drush_sitealias_evaluate_path($normalized_target, $additional_options, $local_only);
1262   if (isset($values[$component])) {
1263     // Hurray, we found the destination.
1264     return $values[$component];
1265   }
1266 }
1267
1268 /**
1269  * Command callback.
1270  */
1271 function drush_core_drupal_directory($target = 'root') {
1272   $path = _drush_core_directory($target, drush_get_option('component', 'path'), drush_get_option('local-only', FALSE));
1273
1274   // If _drush_core_directory is working right, it will turn
1275   // %blah into the path to the item referred to by the key 'blah'.
1276   // If there is no such key, then no replacement is done.  In the
1277   // case of the dd command, we will consider it an error if
1278   // any keys are -not- replaced in _drush_core_directory.
1279   if ($path && (strpos($path, '%') === FALSE)) {
1280     return $path;
1281   }
1282   else {
1283     return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt("Target '!target' not found.", array('!target' => $target)));
1284   }
1285 }
1286
1287 /**
1288  * Called for `drush version` or `drush --version`
1289  */
1290 function drush_core_version() {
1291   return DRUSH_VERSION;
1292 }
1293
1294 /**
1295  * Command callback. Execute specified shell code. Often used by shell aliases
1296  * that start with !.
1297  */
1298 function drush_core_execute() {
1299   $result = TRUE;
1300   $escape = drush_get_option('escape', TRUE);
1301   // Get all of the args and options that appear after the command name.
1302   $args = drush_get_original_cli_args_and_options();
1303   if ($escape) {
1304     for ($x = 0; $x < count($args); $x++) {
1305       // escape all args except for command separators.
1306       if (!in_array($args[$x], array('&&', '||', ';'))) {
1307         $args[$x] = drush_escapeshellarg($args[$x]);
1308       }
1309     }
1310   }
1311   $cmd = implode(' ', $args);
1312   // If we selected a Drupal site, then cwd to the site root prior to exec
1313   $cwd = FALSE;
1314   if ($selected_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT')) {
1315     if (is_dir($selected_root)) {
1316       $cwd = getcwd();
1317       drush_op('chdir', $selected_root);
1318     }
1319   }
1320   if ($alias = drush_get_context('DRUSH_TARGET_SITE_ALIAS')) {
1321     $site = drush_sitealias_get_record($alias);
1322     if (!empty($site['site-list'])) {
1323       $sites = drush_sitealias_resolve_sitelist($site);
1324       foreach ($sites as $site_name => $site_spec) {
1325         $result = _drush_core_execute_cmd($site_spec, $cmd);
1326         if (!$result) {
1327           break;
1328         }
1329       }
1330     }
1331     else {
1332       $result = _drush_core_execute_cmd($site, $cmd);
1333     }
1334   }
1335   else {
1336     // Must be a local command.
1337     $result = (drush_shell_proc_open($cmd) == 0);
1338   }
1339   // Restore the cwd if we changed it
1340   if ($cwd) {
1341     drush_op('chdir', $selected_root);
1342   }
1343   if (!$result) {
1344     return drush_set_error('CORE_EXECUTE_FAILED', dt("Command !command failed.", array('!command' => $cmd)));
1345   }
1346   return $result;
1347 }
1348
1349 function drush_core_twig_compile() {
1350   require_once DRUSH_DRUPAL_CORE . "/themes/engines/twig/twig.engine";
1351   // Scan all enabled modules and themes.
1352   // @todo refactor since \Drush\Boot\DrupalBoot::commandfile_searchpaths is similar.
1353   $ignored_modules = drush_get_option_list('ignored-modules', array());
1354   $cid = drush_cid_install_profile();
1355   if ($cached = drush_cache_get($cid)) {
1356     $ignored_modules[] = $cached->data;
1357   }
1358   foreach (array_diff(drush_module_list(), $ignored_modules) as $module) {
1359     $searchpaths[] = drupal_get_path('module', $module);
1360   }
1361
1362   $themes = drush_theme_list();
1363   foreach ($themes as $name => $theme) {
1364     $searchpaths[] = $theme->getPath();
1365   }
1366
1367   foreach ($searchpaths as $searchpath) {
1368     foreach ($file = drush_scan_directory($searchpath, '/\.html.twig/', array('tests')) as $file) {
1369       $relative = str_replace(drush_get_context('DRUSH_DRUPAL_ROOT'). '/', '', $file->filename);
1370       // @todo Dynamically disable twig debugging since there is no good info there anyway.
1371       twig_render_template($relative, array('theme_hook_original' => ''));
1372       drush_log(dt('Compiled twig template !path', array('!path' => $relative)), LogLevel::NOTICE);
1373     }
1374   }
1375 }
1376
1377 /**
1378  * Helper function for drush_core_execute: run one shell command
1379  */
1380 function _drush_core_execute_cmd($site, $cmd) {
1381   if (!empty($site['remote-host'])) {
1382     // Remote, so execute an ssh command with a bash fragment at the end.
1383     $exec = drush_shell_proc_build($site, $cmd, TRUE);
1384     return (drush_shell_proc_open($exec) == 0);
1385   }
1386   elseif (!empty($site['root']) && is_dir($site['root'])) {
1387     return (drush_shell_proc_open('cd ' . drush_escapeshellarg($site['root']) . ' && ' . $cmd) == 0);
1388   }
1389   return (drush_shell_proc_open($cmd) == 0);
1390 }