Bachir Soussi Chiadmi 1bc61b12ad first import
2015-04-08 11:40:19 +02:00

598 lines
19 KiB
PHP

<?php
/**
* @file
* The Drush context API implementation.
*
* This API acts as a storage mechanism for all options, arguments and
* configuration settings that are loaded into drush.
*
* This API also acts as an IPC mechanism between the different drush commands,
* and provides protection from accidentally overriding settings that are
* needed by other parts of the system.
*
* It also avoids the necessity to pass references through the command chain
* and allows the scripts to keep track of whether any settings have changed
* since the previous execution.
*
* This API defines several contexts that are used by default.
*
* Argument contexts :
* These contexts are used by Drush to store information on the command.
* They have their own access functions in the forms of
* drush_set_arguments(), drush_get_arguments(), drush_set_command(),
* drush_get_command().
*
* command : The drush command being executed.
* arguments : Any additional arguments that were specified.
*
* Setting contexts :
* These contexts store options that have been passed to the drush.php
* script, either through the use of any of the config files, directly from
* the command line through --option='value' or through a JSON encoded string
* passed through the STDIN pipe.
*
* These contexts are accessible through the drush_get_option() and
* drush_set_option() functions. See drush_context_names() for a description
* of all of the contexts.
*
* Drush commands may also choose to save settings for a specific context to
* the matching configuration file through the drush_save_config() function.
*/
/**
* Return a list of the valid drush context names.
*
* These context names are carefully ordered from
* highest to lowest priority.
*
* These contexts are evaluated in a certain order, and the highest priority value
* is returned by default from drush_get_option. This allows scripts to check whether
* an option was different before the current execution.
*
* Specified by the script itself :
* process : Generated in the current process.
* cli : Passed as --option=value to the command line.
* stdin : Passed as a JSON encoded string through stdin.
* specific : Defined in a command-specific option record, and
* set in the command context whenever that command is used.
* alias : Defined in an alias record, and set in the
* alias context whenever that alias is used.
*
* Specified by config files :
* custom : Loaded from the config file specified by --config or -c
* site : Loaded from the drushrc.php file in the Drupal site directory.
* drupal : Loaded from the drushrc.php file in the Drupal root directory.
* user : Loaded from the drushrc.php file in the user's home directory.
* home.drush Loaded from the drushrc.php file in the $HOME/.drush directory.
* system : Loaded from the drushrc.php file in the system's $PREFIX/etc/drush directory.
* drush : Loaded from the drushrc.php file in the same directory as drush.php.
*
* Specified by the script, but has the lowest priority :
* default : The script might provide some sensible defaults during init.
*/
function drush_context_names() {
static $contexts = array(
'process', 'cli', 'stdin', 'specific', 'alias',
'custom', 'site', 'drupal', 'user', 'home.drush', 'system',
'drush', 'default');
return $contexts;
}
/**
* Return a list of possible drushrc file locations.
*
* @context
* A valid drush context from drush_context_names().
* @prefix
* Optional. Specify a prefix to prepend to ".drushrc.php" when looking
* for config files. Most likely used by contrib commands.
* @return
* An associative array containing possible config files to load
* The keys are the 'context' of the files, the values are the file
* system locations.
*/
function _drush_config_file($context, $prefix = NULL) {
$configs = array();
$config_file = $prefix ? $prefix . '.' . 'drushrc.php' : 'drushrc.php';
// Did the user explicitly specify a config file?
if ($config = drush_get_option(array('c', 'config'))) {
if (is_dir($config)) {
$config = $config . '/drushrc.php';
}
$configs['custom'] = $config;
}
if ($site_path = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
$configs['site'] = $site_path . "/" . $config_file;
}
if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
$configs['drupal'] = $drupal_root . '/' . $config_file;
}
// in the user home directory
if (!is_null(drush_server_home())) {
$configs['user'] = drush_server_home() . '/.' . $config_file;
}
// in $HOME/.drush directory
if (!is_null(drush_server_home())) {
$configs['home.drush'] = drush_server_home() . '/.drush/' . $config_file;
}
// In the system wide configuration folder.
$configs['system'] = drush_get_context('ETC_PREFIX', '') . '/etc/drush/' . $config_file;
// in the drush installation folder
$configs['drush'] = dirname(__FILE__) . '/../' . $config_file;
return empty($configs[$context]) ? '' : $configs[$context];
}
/**
* Load drushrc files (if available) from several possible locations.
*/
function drush_load_config($context) {
drush_load_config_file($context, _drush_config_file($context));
}
function drush_load_config_file($context, $config) {
if (file_exists($config)) {
$options = $aliases = $command_specific = $override = array();
drush_log(dt('Loading drushrc "!config" into "!context" scope.', array('!config' => realpath($config), '!context' => $context)), 'bootstrap');
$ret = @include_once($config);
if ($ret === FALSE) {
drush_log(dt('Cannot open drushrc "!config", ignoring.', array('!config' => realpath($config))), 'warning');
return FALSE;
}
if (!empty($options) || !empty($aliases) || !empty($command_specific)) {
$options = array_merge(drush_get_context($context), $options);
$options['config-file'] = realpath($config);
//$options['site-aliases'] = array_merge(isset($aliases) ? $aliases : array(), isset($options['site-aliases']) ? $options['site-aliases'] : array());
unset($options['site-aliases']);
$options['command-specific'] = array_merge(isset($command_specific) ? $command_specific : array(), isset($options['command-specific']) ? $options['command-specific'] : array());
drush_set_config_options($context, $options, $override);
}
}
}
function drush_set_config_options($context, $options, $override = array()) {
global $drush_conf_override;
// Only reset $drush_conf_override if the array is not set, otherwise keep old values and append new values to it.
if (!isset($drush_conf_override)) {
$drush_conf_override = array();
}
// Copy 'config-file' into 'context-path', converting to an array to hold multiple values if necessary
if (isset($options['config-file'])) {
if (isset($options['context-path'])) {
$options['context-path'] = array_merge(array($options['config-file']), is_array($options['context-path']) ? $options['context-path'] : array($options['context-path']));
}
else {
$options['context-path'] = $options['config-file'];
}
}
// Take out $aliases and $command_specific options
drush_set_config_special_contexts($options);
drush_set_context($context, $options);
// Instruct core not to store queries since we are not outputting them.
// Don't run poormanscron during drush request (D7+).
$defaults = array(
'dev_query' => FALSE,
'cron_safe_threshold' => 0,
);
foreach ($defaults as $key => $value) {
// This can be overridden by a command or a drushrc file if needed.
if (!isset($drush_conf_override[$key])) {
$drush_conf_override[$key] = $value;
}
}
/**
* Allow the drushrc.php file to override $conf settings.
* This is a separate variable because the $conf array gets
* initialized to an empty array, in the drupal bootstrap process,
* and changes in settings.php would wipe out the drushrc.php settings.
*/
if (!empty($override)) {
$drush_conf_override = array_merge($drush_conf_override, $override);
}
}
/**
* There are certain options such as 'site-aliases' and 'command-specific'
* that must be merged together if defined in multiple drush configuration
* files. If we did not do this merge, then the last configuration file
* that defined any of these properties would overwrite all of the options
* that came before in previously-loaded configuration files. We place
* all of them into their own context so that this does not happen.
*/
function drush_set_config_special_contexts(&$options) {
if (isset($options)) {
$has_command_specific = array_key_exists('command-specific', $options);
// Change the keys of the site aliases from 'alias' to '@alias'
if (array_key_exists('site-aliases', $options)) {
$user_aliases = $options['site-aliases'];
$options['site-aliases'] = array();
foreach ($user_aliases as $alias_name => $alias_value) {
if (substr($alias_name,0,1) != '@') {
$alias_name = "@$alias_name";
}
$options['site-aliases'][$alias_name] = $alias_value;
}
}
// Copy site aliases and command-specific options into their
// appropriate caches.
$special_contexts = drush_get_special_keys();
foreach ($special_contexts as $option_name) {
if (isset($options[$option_name])) {
$cache =& drush_get_context($option_name);
$cache = array_merge($cache, $options[$option_name]);
unset($options[$option_name]);
}
}
// If command-specific options were set and if we already have
// a command, then apply the command-specific options immediately.
if ($has_command_specific) {
drush_command_default_options();
}
}
}
/**
* Set a specific context.
*
* @param context
* Any of the default defined contexts.
* @param value
* The value to store in the context
*
* @return
* An associative array of the settings specified in the request context.
*/
function drush_set_context($context, $value) {
$cache =& drush_get_context($context);
$cache = $value;
return $value;
}
/**
* Return a specific context, or the whole context cache
*
* This function provides a storage mechanism for any information
* the currently running process might need to communicate.
*
* This avoids the use of globals, and constants.
*
* Functions that operate on the context cache, can retrieve a reference
* to the context cache using :
* $cache = &drush_get_context($context);
*
* This is a private function, because it is meant as an internal
* generalized API for writing static cache functions, not as a general
* purpose function to be used inside commands.
*
* Code that modifies the reference directly might have unexpected consequences,
* such as modifying the arguments after they have already been parsed and dispatched
* to the callbacks.
*
* @param context
* Optional. Any of the default defined contexts.
*
* @return
* If context is not supplied, the entire context cache will be returned.
* Otherwise only the requested context will be returned.
* If the context does not exist yet, it will be initialized to an empty array.
*/
function &drush_get_context($context = NULL, $default = NULL) {
static $cache = array();
if (!is_null($context)) {
if (!isset($cache[$context])) {
$default = !is_null($default) ? $default : array();
$cache[$context] = $default;
}
return $cache[$context];
}
return $cache;
}
/**
* Set the arguments passed to the drush.php script.
*
* This function will set the 'arguments' context of the current running script.
*
* When initially called by drush_parse_args, the entire list of arguments will
* be populated. Once the command is dispatched, this will be set to only the remaining
* arguments to the command (i.e. the command name is removed).
*
* @param arguments
* Command line arguments, as an array.
*/
function drush_set_arguments($arguments) {
drush_set_context('arguments', $arguments);
}
/**
* Get the arguments passed to the drush.php script.
*
* When drush_set_arguments is initially called by drush_parse_args,
* the entire list of arguments will be populated.
* Once the command has been dispatched, this will be return only the remaining
* arguments to the command.
*/
function drush_get_arguments() {
return drush_get_context('arguments');
}
/**
* Set the command being executed.
*
* Drush_dispatch will set the correct command based on it's
* matching of the script arguments retrieved from drush_get_arguments
* to the implemented commands specified by drush_get_commands.
*
* @param
* A numerically indexed array of command components.
*/
function drush_set_command($command) {
drush_set_context('command', $command);
}
/**
* Return the command being executed.
*
*
*/
function drush_get_command() {
return drush_get_context('command');
}
/**
* Get the value for an option.
*
* If the first argument is an array, then it checks whether one of the options
* exists and return the value of the first one found. Useful for allowing both
* -h and --host-name
*
* @param option
* The name of the option to get
* @param default
* Optional. The value to return if the option has not been set
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*/
function drush_get_option($option, $default = NULL, $context = NULL) {
$value = NULL;
if ($context) {
// We have a definite context to check for the presence of an option.
$value = _drush_get_option($option, drush_get_context($context));
}
else {
// We are not checking a specific context, so check them in a predefined order of precedence.
$contexts = drush_context_names();
foreach ($contexts as $context) {
$value = _drush_get_option($option, drush_get_context($context));
if ($value !== NULL) {
return $value;
}
}
}
if ($value !== NULL) {
return $value;
}
return $default;
}
/**
* Get the value for an option and return it as a list. If the
* option in question is passed on the command line, its value should
* be a comma-separated list (e.g. --flag=1,2,3). If the option
* was set in a drushrc.php file, then its value may be either a
* comma-separated list or an array of values (e.g. $option['flag'] = array('1', '2', '3')).
*
* @param option
* The name of the option to get
* @param default
* Optional. The value to return if the option has not been set
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*/
function drush_get_option_list($option, $default = array(), $context = NULL) {
$result = drush_get_option($option, $default, $context);
if (!is_array($result)) {
$result = explode(',', $result);
}
return $result;
}
/**
* Get the value for an option, but first checks the provided option overrides.
*
* The feature of drush_get_option that allows a list of option names
* to be passed in an array is NOT supported.
*
* @param option_overrides
* An array to check for values before calling drush_get_option.
* @param option
* The name of the option to get.
* @param default
* Optional. The value to return if the option has not been set.
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*
*/
function drush_get_option_override($option_overrides, $option, $value = NULL, $context = NULL) {
if (array_key_exists($option, $option_overrides)) {
return $option_overrides[$option];
}
else {
return drush_get_option($option, $value, $context);
}
}
/**
* Get all of the values for an option in every context.
*
* @param option
* The name of the option to get
* @return
* An array whose key is the context name and value is
* the specific value for the option in that context.
*/
function drush_get_context_options($option, $flatten = FALSE) {
$result = array();
$contexts = drush_context_names();
foreach ($contexts as $context) {
$value = _drush_get_option($option, drush_get_context($context));
if ($value !== NULL) {
if ($flatten && is_array($value)) {
$result = array_merge($value, $result);
}
else {
$result[$context] = $value;
}
}
}
return $result;
}
/**
* Retrieves a collapsed list of all options
*/
function drush_get_merged_options() {
$contexts = drush_context_names();
$cache = drush_get_context();
$result = array();
foreach (array_reverse($contexts) as $context) {
if (array_key_exists($context, $cache)) {
$result = array_merge($result, $cache[$context]);
}
}
return $result;
}
/**
* Helper function to recurse through possible option names
*/
function _drush_get_option($option, $context) {
if (is_array($option)) {
foreach ($option as $current) {
if (array_key_exists($current, $context)) {
return $context[$current];
}
}
}
elseif (array_key_exists($option, $context)) {
return $context[$option];
}
return NULL;
}
/**
* Set an option in one of the option contexts.
*
* @param option
* The option to set.
* @param value
* The value to set it to.
* @param context
* Optional. Which context to set it in.
* @return
* The value parameter. This allows for neater code such as
* $myvalue = drush_set_option('http_host', $_SERVER['HTTP_HOST']);
* Without having to constantly type out the value parameter.
*/
function drush_set_option($option, $value, $context = 'process') {
$cache =& drush_get_context($context);
$cache[$option] = $value;
return $value;
}
/**
* A small helper function to set the value in the default context
*/
function drush_set_default($option, $value) {
return drush_set_option($option, $value, 'default');
}
/**
* Remove a setting from a specific context.
*
* @param
* Option to be unset
* @param
* Context in which to unset the value in.
*/
function drush_unset_option($option, $context = NULL) {
if ($context != NULL) {
$cache =& drush_get_context($context);
if (array_key_exists($option, $cache)) {
unset($cache[$option]);
}
}
else {
$contexts = drush_context_names();
foreach ($contexts as $context) {
drush_unset_option($option, $context);
}
}
}
/**
* Save the settings in a specific context to the applicable configuration file
* This is useful is you want certain settings to be available automatically the next time a command is executed.
*
* @param $context
* The context to save
*/
function drush_save_config($context) {
$filename = _drush_config_file($context);
if ($filename) {
$cache = drush_get_context($context);
$fp = fopen($filename, "w+");
if (!$fp) {
return drush_set_error('DRUSH_PERM_ERROR', dt('Drushrc (!filename) could not be written', array('!filename' => $filename)));
}
else {
fwrite($fp, "<?php\n");
$timestamp = mktime();
foreach ($cache as $key => $value) {
$line = "\n\$options['$key'] = ". var_export($value, TRUE) .';';
fwrite($fp, $line);
}
fwrite($fp, "\n");
fclose($fp);
drush_log(dt('Drushrc file (!filename) was written successfully', array('!filename' => $filename)));
return TRUE;
}
}
return FALSE;
}