X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fdrush%2Fdrush%2Fincludes%2Fengines.inc;fp=vendor%2Fdrush%2Fdrush%2Fincludes%2Fengines.inc;h=56a2b41f34dc5cc37c1c53af5494d2f2f931dc18;hp=0000000000000000000000000000000000000000;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad diff --git a/vendor/drush/drush/includes/engines.inc b/vendor/drush/drush/includes/engines.inc new file mode 100644 index 000000000..56a2b41f3 --- /dev/null +++ b/vendor/drush/drush/includes/engines.inc @@ -0,0 +1,567 @@ + $data) { + $info[$type] += array( + 'description' => '', + 'option' => FALSE, + 'default' => NULL, + 'options' => array(), + 'sub-options' => array(), + 'config-aliases' => array(), + 'add-options-to-command' => FALSE, + 'combine-help' => FALSE, + ); + } + + return $info; +} + +/** + * Return a structured array of engines of a specific type. + * + * Engines are pluggable subsystems. Each engine of a specific type will + * implement the same set of API functions and perform the same high-level + * task using a different backend or approach. + * + * This function/hook is useful when you have a selection of several mutually + * exclusive options to present to a user to select from. + * + * Other commands are able to extend this list and provide their own engines. + * The hook can return useful information to help users decide which engine + * they need, such as description or list of available engine options. + * + * The engine path element will automatically default to a subdirectory (within + * the directory of the commandfile that implemented the hook) with the name of + * the type of engine - e.g. an engine "wget" of type "handler" provided by + * the "pm" commandfile would automatically be found if the file + * "pm/handler/wget.inc" exists and a specific path is not provided. + * + * @param $engine_type + * The type of engine. + * + * @return + * A structured array of engines. + */ +function drush_get_engines($engine_type) { + $info = drush_get_engine_types_info(); + if (!isset($info[$engine_type])) { + return drush_set_error('DRUSH_UNKNOWN_ENGINE_TYPE', dt('Unknown engine type !engine_type', array('!engine_type' => $engine_type))); + } + + $engines = array( + 'info' => $info[$engine_type], + 'engines' => array(), + ); + $list = drush_commandfile_list(); + $hook = 'drush_engine_' . str_replace('-', '_', $engine_type); + foreach ($list as $commandfile => $path) { + if (drush_command_hook($commandfile, $hook)) { + $function = $commandfile . '_' . $hook; + $result = $function(); + foreach ($result as $engine_name => $engine) { + // Add some defaults. + $engine += array( + 'commandfile' => $commandfile, + 'options' => array(), + 'sub-options' => array(), + 'drupal dependencies' => array(), + ); + + // Legacy engines live in a subdirectory + // of the commandfile that declared them. + $engine_path = sprintf("%s/%s", dirname($path), $engine_type); + if (file_exists($engine_path)) { + $engine['path'] = $engine_path; + } + // Build engine class name, in case the engine doesn't provide it. + // The class name is based on the engine type and name, converted + // from snake_case to CamelCase. + // For example for type 'package_handler' and engine 'git_drupalorg' + // the class is \Drush\PackageHandler\GitDrupalorg + elseif (!isset($engine['class'])) { + $parts = array(); + $parts[] = '\Drush'; + $parts[] = str_replace(' ', '', ucwords(strtr($engine_type, '_', ' '))); + $parts[] = str_replace(' ', '', ucwords(strtr($engine_name, '_', ' '))); + $engine['class'] = implode('\\', $parts); + } + + $engines['engines'][$engine_name] = $engine; + } + } + } + + return $engines; +} + +/** + * Take a look at all of the available engines, + * and create topic commands for each one that + * declares a topic. + */ +function drush_get_engine_topics() { + $items = array(); + $info = drush_get_engine_types_info(); + foreach ($info as $engine => $data) { + if (array_key_exists('topic', $data)) { + $items[$data['topic']] = array( + 'description' => $data['description'], + 'hidden' => TRUE, + 'topic' => TRUE, + 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, + 'callback' => 'drush_engine_topic_command', + 'callback arguments' => array($engine), + ); + } + } + return $items; +} + +/** + * Include, instantiate and validate command engines. + * + * @return FALSE if a engine doesn't validate. + */ +function drush_load_command_engines($command) { + $result = TRUE; + foreach ($command['engines'] as $engine_type => $config) { + $result = drush_load_command_engine($command, $engine_type); + // Stop loading engines if any of them fails. + if ($result === FALSE) { + break; + } + } + return $result; +} + +/** + * Returns engine config supplied in the command definition. + */ +function drush_get_command_engine_config($command, $engine_type, $metadata = array()) { + if (isset($command['engines'][$engine_type])) { + $metadata = array_merge($metadata, $command['engines'][$engine_type]); + } + return $metadata; +} + +/** + * Selects and loads an engine implementing the given type. + * + * Loaded engines are stored as a context. + */ +function drush_load_command_engine($command, $engine_type, $metadata = array()) { + drush_log(dt("Loading !engine engine.", array('!engine' => $engine_type), LogLevel::BOOTSTRAP)); + + $config = drush_get_command_engine_config($command, $engine_type, $metadata); + $engine_info = drush_get_engines($engine_type); + $engine = drush_select_engine($config, $engine_info); + $version = drush_drupal_major_version(); + + $context = $engine_type . '_engine_' . $engine . '_' . $version; + $instance = drush_get_context($context, FALSE); + if ($instance != FALSE) { + drush_set_engine($engine_type, $instance); + } + else { + $instance = drush_load_engine($engine_type, $engine, $config); + if ($instance == FALSE) { + return FALSE; + } + drush_set_context($context, $instance); + } + return $instance; +} + +/** + * Add command structure info from each engine type back into the command. + */ +function drush_merge_engine_data(&$command) { + // First remap engine data from the shortcut location + // ($command['engine_type']) to the standard location + // ($command['engines']['engine_type']) + $info = drush_get_engine_types_info(); + foreach ($info as $engine_type => $info) { + if (isset($command[$engine_type])) { + $config = $command[$engine_type]; + foreach ($info['config-aliases'] as $engine_option_alias_name => $engine_option_standard_name) { + if (array_key_exists($engine_option_alias_name, $config)) { + $config[$engine_option_standard_name] = $config[$engine_option_alias_name]; + unset($config[$engine_option_alias_name]); + } + } + // Convert single string values of 'require-engine-capability' to an array. + if (isset($config['require-engine-capability']) && is_string($config['require-engine-capability'])) { + $config['require-engine-capability'] = array($config['require-engine-capability']); + } + $command['engines'][$engine_type] = $config; + } + } + + foreach ($command['engines'] as $engine_type => $config) { + // Normalize engines structure. + if (!is_array($config)) { + unset($command['engines'][$engine_type]); + $command['engines'][$config] = array(); + $engine_type = $config; + } + + // Get all implementations for this engine type. + $engine_info = drush_get_engines($engine_type); + if ($engine_info === FALSE) { + return FALSE; + } + + // Complete command-declared engine type with default info. + $command['engines'][$engine_type] += $engine_info['info']; + $config = $command['engines'][$engine_type]; + + $engine_data = array(); + + // If there's a single implementation for this engine type, it will be + // loaded by default, and makes no sense to provide a command line option + // to select the only flavor (ie. --release_info=updatexml), so we won't + // add an option in this case. + // Additionally, depending on the command, it may be convenient to extend + // the command with the engine options. + if (count($engine_info['engines']) == 1) { + if ($config['add-options-to-command'] !== FALSE) { + // Add options and suboptions of the engine type and + // the sole implementation. + $engine = key($engine_info['engines']); + $data = $engine_info['engines'][$engine]; + $engine_data += array( + 'options' => $config['options'] + $data['options'], + 'sub-options' => $config['sub-options'] + $data['sub-options'], + ); + } + } + // Otherwise, provide a command option to choose between engines and add + // the engine options and sub-options. + else { + // Add engine type global options and suboptions. + $engine_data += array( + 'options' => $config['options'], + 'sub-options' => $config['sub-options'], + ); + + // If the 'combine-help' flag is set in the engine config, + // then we will combine all of the help items into the help + // text for $config['option']. + $combine_help = $config['combine-help']; + $combine_help_data = array(); + + // Process engines in order. First the default engine, the rest alphabetically. + $default = drush_select_engine($config, $engine_info); + $engines = array_keys($engine_info['engines']); + asort($engines); + array_unshift($engines, $default); + $engines = array_unique($engines); + foreach ($engines as $engine) { + $data = $engine_info['engines'][$engine]; + // Check to see if the command requires any particular + // capabilities. If no capabilities are required, then + // all engines are acceptable. + $engine_is_usable = TRUE; + if (array_key_exists('require-engine-capability', $config)) { + // See if the engine declares that it provides any + // capabilities. If no capabilities are listed, then + // it is assumed that the engine can satisfy all requirements. + if (array_key_exists('engine-capabilities', $data)) { + $engine_is_usable = FALSE; + // If 'require-engine-capability' is TRUE instead of an array, + // then only engines that are universal (do not declare any + // particular capabilities) are usable. + if (is_array($config['require-engine-capability'])) { + foreach ($config['require-engine-capability'] as $required) { + // We need an engine that provides any one of the requirements. + if (in_array($required, $data['engine-capabilities'])) { + $engine_is_usable = TRUE; + } + } + } + } + } + if ($engine_is_usable) { + $command['engines'][$engine_type]['usable'][] = $engine; + if (!isset($data['hidden'])) { + $option = $config['option'] . '=' . $engine; + $engine_data['options'][$option]['description'] = array_key_exists('description', $data) ? $data['description'] : NULL; + if ($combine_help) { + $engine_data['options'][$option]['hidden'] = TRUE; + if (drush_get_context('DRUSH_VERBOSE') || ($default == $engine) || !isset($data['verbose-only'])) { + $combine_help_data[$engine] = $engine . ': ' . $data['description']; + } + } + if (isset($data['options'])) { + $engine_data['sub-options'][$option] = $data['options']; + } + if (isset($data['sub-options'])) { + $engine_data['sub-options'] += $data['sub-options']; + } + } + } + } + if (!empty($combine_help_data)) { + $engine_selection_option = $config['option']; + if (!is_array($engine_data['options'][$engine_selection_option])) { + $engine_data['options'][$engine_selection_option] = array('description' => $config['options'][$engine_selection_option]); + } + if (drush_get_context('DRUSH_VERBOSE')) { + $engine_data['options'][$engine_selection_option]['description'] .= "\n" . dt("All available values are:") . "\n - " . implode("\n - ", $combine_help_data) . "\n"; + } + else { + $engine_data['options'][$engine_selection_option]['description'] .= " " . dt("Available: ") . implode(', ', array_keys($combine_help_data)) . ". "; + } + $engine_data['options'][$engine_selection_option]['description'] .= dt("Default is !default.", array('!default' => $default)); + } + else { + // If the help options are not combined, then extend the + // default engine description. + $desc = $engine_info['engines'][$default]['description']; + $engine_info['engines'][$default]['description'] = dt('Default !type engine.', array('!type' => $engine_type)) . ' ' . $desc; + } + } + // This was simply array_merge_recursive($command, $engine_data), but this + // function has an undesirable behavior when merging primative types. + // If there is a 'key' => 'value' in $command, and the same 'key' => 'value' + // exists in $engine data, then the result will be 'key' => array('value', 'value');. + // This is NOT what we want, so we provide our own 'overlay' function instead. + $command = _drush_array_overlay_recursive($command, $engine_data); + } +} + +// Works like array_merge_recursive(), but does not convert primative +// types into arrays. Ever. +function _drush_array_overlay_recursive($a, $b) { + foreach ($b as $key => $value) { + if (!isset($a[$key]) || !is_array($a[$key])) { + $a[$key] = $b[$key]; + } + else { + $a[$key] = _drush_array_overlay_recursive($a[$key], $b[$key]); + } + } + return $a; +} + +/** + * Implementation of command hook for docs-output-formats + */ +function drush_engine_topic_command($engine) { + $engine_instances = drush_get_engines($engine); + $option = $engine_instances['info']['option']; + + if (isset($engine_instances['info']['topic-file'])) { + // To do: put this file next to the commandfile that defines the + // engine type, not in the core docs directory. + $docs_dir = drush_get_context('DOC_PREFIX', DRUSH_BASE_PATH); + $path = $engine_instances['info']['topic-file']; + $docs_file = (drush_is_absolute_path($path) ? '' : $docs_dir . '/') . $path; + $doc_text = drush_html_to_text(file_get_contents($docs_file)); + } + elseif (isset($engine_instances['info']['topic-text'])) { + $doc_text = $engine_instances['info']['topic-text']; + } + else { + return drush_set_error('DRUSH_BAD_ENGINE_TOPIC', dt("The engine !engine did not define its topic command correctly.", array('!engine' => $engine))); + } + + // Look at each instance of the engine; if it has an html + // file in the the 'topics' folder named after itself, then + // include the file contents in the engine topic text. + $instances = $engine_instances['engines']; + ksort($instances); + foreach ($instances as $instance => $config) { + if (isset($config['description'])) { + $doc_text .= "\n\n::: --$option=$instance :::\n" . $config['description']; + $path = $config['path'] . '/topics/' . $instance . '.html'; + if (file_exists($path)) { + $doc_text .= "\n" . drush_html_to_text(file_get_contents($path)); + } + $additional_topic_text = drush_command_invoke_all('drush_engine_topic_additional_text', $engine, $instance, $config); + if (!empty($additional_topic_text)) { + $doc_text .= "\n\n" . implode("\n\n", $additional_topic_text); + } + } + } + + // Write the topic text to a file so that is can be paged + $file = drush_save_data_to_temp_file($doc_text); + drush_print_file($file); +} + +/** + * Selects an engine between the available ones. + * + * Precedence: + * + * - preferred engine, if available. + * - user supplied engine via cli. + * - default engine from engine type / command declaration. + * - the first engine available. + * + * @param array $config + * Engine type configuration. My be overridden in command declaration. + * @param array $engine_info + * Engine type declaration. + * @param string $default + * Preferred engine. + * + * @return string + * Selected engine. + */ +function drush_select_engine($config, $engine_info, $preferred = NULL) { + $engines = array_keys($engine_info['engines']); + + if (in_array($preferred, $engines)) { + return $preferred; + } + + if (!empty($config['option'])) { + $engine = drush_get_option($config['option'], FALSE); + if ($engine && in_array($engine, $engines)) { + return $engine; + } + } + + if (isset($config['default']) && in_array($config['default'], $engines)) { + return $config['default']; + } + + return current($engines); +} + +/** + * Loads and validate an engine of the given type. + * + * @param string $type + * Engine type. + * @param string $engine + * Engine name. + * @param array $config + * Engine configuration. Tipically it comes from a command declaration. + * + * @return + * TRUE or instanced object of available class on success. FALSE on fail. + */ +function drush_load_engine($type, $engine, $config = array()) { + $engine_info = drush_get_engines($type); + $engine = drush_select_engine($config, $engine_info, $engine); + $config['engine-info'] = $engine_info['engines'][$engine]; + + // Check engine dependency on drupal modules before include. + $dependencies = $config['engine-info']['drupal dependencies']; + foreach ($dependencies as $dependency) { + if (!drush_module_exists($dependency)) { + return drush_set_error('DRUSH_ENGINE_DEPENDENCY_ERROR', dt('!engine_type: !engine engine needs the following modules installed/enabled to run: !dependencies.', array('!engine_type' => $type, '!engine' => $engine, '!dependencies' => implode(', ', $dependencies)))); + } + } + + $result = drush_include_engine($type, $engine, $config); + if (is_object($result)) { + $valid = method_exists($result, 'validate') ? $result->validate() : TRUE; + if ($valid) { + drush_set_engine($type, $result); + } + } + else { + $function = strtr($type, '-', '_') . '_validate'; + $valid = function_exists($function) ? call_user_func($function) : TRUE; + } + if (!$valid) { + return FALSE; + } + return $result; +} + +/** + * Include the engine code for a specific named engine of a certain type. + * + * If the engine type has implemented hook_drush_engine_$type the path to the + * engine specified in the array will be used. + * + * If a class named in the form drush_$type_$engine exists, it will return an + * instance of the class. + * + * @param string $type + * The type of engine. + * @param string $engine + * The name for the engine to include. + * @param array $config + * Parameters for the engine class constructor. + * + * @return + * TRUE or instanced object of available class on success. FALSE on fail. + */ +function drush_include_engine($type, $engine, $config = NULL) { + $engine_info = drush_get_engines($type); + + // Pick the engine name that actually implements the requested engine. + $engine = isset($engine_info['engines'][$engine]['implemented-by']) ? $engine_info['engines'][$engine]['implemented-by'] : $engine; + + // Legacy engines live in a subdirectory of the commandfile + // that declares them. We need to explicitly include the file. + if (isset($engine_info['engines'][$engine]['path'])) { + $path = $engine_info['engines'][$engine]['path']; + if (!drush_include($path, $engine)) { + return drush_set_error('DRUSH_ENGINE_INCLUDE_FAILED', dt('Unable to include the !type engine !engine from !path.' , array('!path' => $path, '!type' => $type, '!engine' => $engine))); + } + // Legacy engines may be implemented in a magic class name. + $class = 'drush_' . $type . '_' . str_replace('-', '_', $engine); + if (class_exists($class)) { + $instance = new $class($config); + $instance->engine_type = $type; + $instance->engine = $engine; + return $instance; + } + + return TRUE; + } + + return drush_get_class($engine_info['engines'][$engine]['class'], array($type, $engine, $config)); +} + +/** + * Return the engine of the specified type that was loaded by the Drush command. + */ +function drush_get_engine($type) { + return drush_get_context($type . '_engine', FALSE); +} + +/** + * Called by the Drush command (@see _drush_load_command_engines()) + * to cache the active engine instance. + */ +function drush_set_engine($type, $instance) { + drush_set_context($type . '_engine', $instance); +} + +/** + * Add engine topics to the command topics, if any. + */ +function drush_engine_add_help_topics(&$command) { + $engine_types = drush_get_engine_types_info(); + foreach ($command['engines'] as $engine_type => $config) { + $info = $engine_types[$engine_type]; + if (isset($info['topics'])) { + $command['topics'] = array_merge($command['topics'], $info['topics']); + } + if (isset($info['topic'])) { + $command['topics'][] = $info['topic']; + } + } +}