| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911 | 
							- <?php
 
- /**
 
-  * @file
 
-  * Features module drush integration.
 
-  */
 
- use Drupal\features\ConfigurationItem;
 
- use Drupal\features\FeaturesManagerInterface;
 
- use Drupal\features\Plugin\FeaturesGeneration\FeaturesGenerationWrite;
 
- use Drupal\Component\Diff\DiffFormatter;
 
- /**
 
-  * Implements hook_drush_command().
 
-  */
 
- function features_drush_command() {
 
-   $items = array();
 
-   $items['features-status'] = array(
 
-     'description' => 'Display current Features settings.',
 
-     'aliases' => array('fs'),
 
-   );
 
-   $items['features-list-packages'] = array(
 
-     'description' => 'Display a list of all existing features and packages available to be generated.  If a package name is provided as an argument, then all of the configuration objects assigned to that package will be listed.',
 
-     'examples' => array(
 
-       "drush features-list-packages" => 'Display a list of all existing featurea and packages available to be generated.',
 
-       "drush features-list-packages 'example_article'" => "Display a list of all configuration objects assigned to the 'example_article' package.",
 
-     ),
 
-     'arguments' => array(
 
-       'package' => 'The package to list. Optional; if specified, lists all configuration objects assigned to that package. If no package is specified, lists all of the features.',
 
-     ),
 
-     'outputformat' => array(
 
-       'default' => 'table',
 
-       'pipe-format' => 'list',
 
-       'field-labels' => array(
 
-         'name' => 'Name',
 
-         'machine_name' => 'Machine name',
 
-         'status' => 'Status',
 
-         'version' => 'Version',
 
-         'state' => 'State',
 
-         'object' => 'Configuration object',
 
-       ),
 
-       'output-data-type' => 'format-table',
 
-     ),
 
-     'aliases' => array('fl'),
 
-   );
 
-   $items['features-import-all'] = array(
 
-     'description' => 'Import module config from all installed features.',
 
-     'examples' => array(
 
-       "drush features-import-all" => 'Import module config from all installed features.',
 
-     ),
 
-     'aliases' => array('fra', 'fia', 'fim-all'),
 
-   );
 
-   $items['features-export'] = array(
 
-     'description' => "Export the configuration on your site into a custom module.",
 
-     'arguments' => array(
 
-       'package' => 'A space delimited list of features to export.',
 
-     ),
 
-     'options' => array(
 
-       'add-profile' => 'Package features into an install profile.',
 
-     ),
 
-     'examples' => array(
 
-       "drush features-export" => 'Export all available packages.',
 
-       "drush features-export example_article example_page" => "Export the example_article and example_page packages.",
 
-       "drush features-export --add-profile" => "Export all available packages and add them to an install profile.",
 
-     ),
 
-     // Add previous "fu" alias for compatibility.
 
-     'aliases' => array('fex', 'fu', 'fua', 'fu-all'),
 
-   );
 
-   $items['features-add'] = array(
 
-     'description' => "Add a config item to a feature package.",
 
-     'arguments' => array(
 
-       'feature' => 'Feature package to export and add config to.',
 
-       'components' => 'Patterns of config to add, see features-components for the format of patterns.',
 
-     ),
 
-     'aliases' => array('fa', 'fe'),
 
-   );
 
-   $items['features-components'] = array(
 
-     'description' => 'List features components.',
 
-     'arguments' => array(
 
-       'patterns' => 'The features components type to list. Omit this argument to list all components.',
 
-     ),
 
-     'options' => array(
 
-       'exported' => array(
 
-         'description' => 'Show only components that have been exported.',
 
-       ),
 
-       'not-exported' => array(
 
-         'description' => 'Show only components that have not been exported.',
 
-       ),
 
-     ),
 
-     'aliases' => array('fc'),
 
-   );
 
-   $items['features-diff'] = array(
 
-     'description' => "Show the difference between the active config and the default config stored in a feature package.",
 
-     'arguments' => array(
 
-       'feature' => 'The feature in question.',
 
-     ),
 
-     'options' => array(
 
-       'ctypes' => 'Comma separated list of component types to limit the output to. Defaults to all types.',
 
-       'lines' => 'Generate diffs with <n> lines of context instead of the usual two.',
 
-     ),
 
-     'aliases' => array('fd'),
 
-   );
 
-   $items['features-import'] = array(
 
-     'description' => "Import a module config into your site.",
 
-     'arguments' => array(
 
-       'feature' => 'A space delimited list of features or feature:component pairs to import.',
 
-     ),
 
-     'options' => array(
 
-       'force' => "Force import even if config is not overridden.",
 
-     ),
 
-     'examples' => array(
 
-       'drush features-import foo:node.type.page foo:taxonomy.vocabulary.tags bar' => 'Import node and taxonomy config of feature "foo". Import all config of feature "bar".',
 
-     ),
 
-     'aliases' => array('fim', 'fr'),
 
-   );
 
-   foreach ($items as $name => &$item) {
 
-     $item['options']['bundle'] = array(
 
-       'description' => 'Use a specific bundle namespace.',
 
-     );
 
-   }
 
-   return $items;
 
- }
 
- /**
 
-  * Applies global options for Features drush commands.
 
-  *
 
-  * The option --name="bundle_name" sets the bundle namespace.
 
-  *
 
-  * @return \Drupal\features\FeaturesAssignerInterface
 
- */
 
- function _drush_features_options() {
 
-   /** @var \Drupal\features\FeaturesAssignerInterface $assigner */
 
-   $assigner = \Drupal::service('features_assigner');
 
-   $bundle_name = drush_get_option('bundle');
 
-   if (!empty($bundle_name)) {
 
-     $bundle = $assigner->applyBundle($bundle_name);
 
-     if ($bundle->getMachineName() != $bundle_name) {
 
-       drush_log(dt('Bundle @name not found. Using default.', array('@name' => $bundle_name)), 'warning');
 
-     }
 
-   }
 
-   else {
 
-     $assigner->assignConfigPackages();
 
-   }
 
-   return $assigner;
 
- }
 
- /**
 
-  * Provides Drush command callback for features-status.
 
-  */
 
- function drush_features_status() {
 
-   $args = func_get_args();
 
-   $assigner = _drush_features_options();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   $current_bundle = $assigner->getBundle();
 
-   $export_settings = $manager->getExportSettings();
 
-   $methods = $assigner->getEnabledAssigners();
 
-   if ($current_bundle->isDefault()) {
 
-     drush_print(dt('Current bundle: none'));
 
-   }
 
-   else {
 
-     drush_print(dt('Current bundle: @name (@machine_name)',
 
-       array(
 
-         '@name' => $current_bundle->getName(),
 
-         '@machine_name' => $current_bundle->getMachineName(),
 
-       )));
 
-   }
 
-   drush_print(dt('Export folder: @folder', array('@folder' => $export_settings['folder'])));
 
-   $dt_args = array('@methods' => implode(', ', array_keys($methods)));
 
-   drush_print(dt('The following assignment methods are enabled:'));
 
-   drush_print(dt('  @methods', $dt_args));
 
-   if (!empty($args)) {
 
-     $config = $manager->getConfigCollection();
 
-     if (count($args) > 1) {
 
-       print_r(array_keys($config));
 
-     }
 
-     else {
 
-       print_r($config[$args[0]]);
 
-     }
 
-   }
 
- }
 
- /**
 
-  * Drush command callback for features-list-packages.
 
-  *
 
-  * @param string $package_name
 
-  *   (optional) The package name.
 
-  *
 
-  * @return array|bool
 
-  */
 
- function drush_features_list_packages($package_name = '') {
 
-   $assigner = _drush_features_options();
 
-   $current_bundle = $assigner->getBundle();
 
-   $namespace = $current_bundle->isDefault() ? '' : $current_bundle->getMachineName();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   $packages = $manager->getPackages();
 
-   $packages = $manager->filterPackages($packages, $namespace);
 
-   $result = array();
 
-   // If no package was specified, list all packages.
 
-   if (empty($package_name)) {
 
-     drush_hide_output_fields(array('object'));
 
-     foreach ($packages as $package) {
 
-       $overrides = $manager->detectOverrides($package);
 
-       $state = $package->getState();
 
-       if (!empty($overrides) && ($package->getStatus() != FeaturesManagerInterface::STATUS_NO_EXPORT)) {
 
-         $state = FeaturesManagerInterface::STATE_OVERRIDDEN;
 
-       }
 
-       $result[$package->getMachineName()] = array(
 
-         'name' => $package->getName(),
 
-         'machine_name' => $package->getMachineName(),
 
-         'status' => $manager->statusLabel($package->getStatus()),
 
-         'version' => $package->getVersion(),
 
-         'state' => ($state != FeaturesManagerInterface::STATE_DEFAULT)
 
-           ? $manager->stateLabel($state)
 
-           : '',
 
-       );
 
-     }
 
-     return $result;
 
-   }
 
-   // If a valid package was listed, list its configuration.
 
-   else {
 
-     foreach ($packages as $package) {
 
-       if ($package->getMachineName() == $package_name) {
 
-         drush_hide_output_fields(array(
 
-           'machine_name',
 
-           'name',
 
-           'status',
 
-           'version',
 
-           'state',
 
-         ));
 
-         foreach ($package->getConfig() as $item_name) {
 
-           $result[$item_name] = array(
 
-             'object' => $item_name,
 
-           );
 
-         }
 
-         return $result;
 
-       }
 
-     }
 
-   }
 
-   // If no matching package found, return an error.
 
-   drush_log(dt('Package "@package" not found.', array('@package' => $package_name)), 'warning');
 
-   return FALSE;
 
- }
 
- /**
 
-  * Drush command callback for features-import-all.
 
-  *
 
-  */
 
- function drush_features_import_all() {
 
-   $assigner = _drush_features_options();
 
-   $current_bundle = $assigner->getBundle();
 
-   $namespace = $current_bundle->isDefault() ? '' : $current_bundle->getMachineName();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   $packages = $manager->getPackages();
 
-   $packages = $manager->filterPackages($packages, $namespace);
 
-   $overridden = array();
 
-   foreach ($packages as $package) {
 
-     $overrides = $manager->detectOverrides($package);
 
-     $missing = $manager->detectMissing($package);
 
-     if ((!empty($missing) || !empty($overrides)) && ($package->getStatus() == FeaturesManagerInterface::STATUS_INSTALLED)) {
 
-       $overridden[] = $package->getMachineName();
 
-     }
 
-   }
 
-   if (!empty($overridden)) {
 
-     call_user_func_array('drush_features_import', $overridden);
 
-   }
 
-   else {
 
-     drush_log(dt('Current state already matches active config, aborting.'), 'ok');
 
-   }
 
- }
 
- /**
 
-  * Provides Drush command callback for features-export.
 
-  */
 
- function drush_features_export($packages = NULL) {
 
-   $packages = func_get_args();
 
-   $assigner = _drush_features_options();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   /** @var \Drupal\features\FeaturesGeneratorInterface $generator */
 
-   $generator = \Drupal::service('features_generator');
 
-   $current_bundle = $assigner->getBundle();
 
-   if (drush_get_option('add-profile')) {
 
-     if ($current_bundle->isDefault) {
 
-       return drush_set_error('', dt("Must specify a profile name with --name"));
 
-     }
 
-     $current_bundle->setIsProfile(TRUE);
 
-   }
 
-   $all_packages = $manager->getPackages();
 
-   foreach ($packages as $name) {
 
-     if (!isset($all_packages[$name])) {
 
-       return drush_set_error('', dt("The package @name does not exist.", array('@name' => $name)));
 
-     }
 
-   }
 
-   if (empty($packages)) {
 
-     $packages = $all_packages;
 
-     $dt_args = array('@modules' => implode(', ', array_keys($packages)));
 
-     drush_print(dt('The following extensions will be exported: @modules', $dt_args));
 
-     if (!drush_confirm(dt('Do you really want to continue?'))) {
 
-       return drush_user_abort('Aborting.');
 
-     }
 
-   }
 
-   // If any packages exist, confirm before overwriting.
 
-   if ($existing_packages = $manager->listPackageDirectories($packages, $current_bundle)) {
 
-     foreach ($existing_packages as $name => $directory) {
 
-       drush_print(dt("The extension @name already exists at @directory.", array('@name' => $name, '@directory' => $directory)));
 
-     }
 
-     // Apparently, format_plural is not always available.
 
-     if (count($existing_packages) == 1) {
 
-       $message = dt('Would you like to overwrite it?');
 
-     }
 
-     else {
 
-       $message = dt('Would you like to overwrite them?');
 
-     }
 
-     if (!drush_confirm($message)) {
 
-       return drush_user_abort();
 
-     }
 
-   }
 
-   // Use the write generation method.
 
-   $method_id = FeaturesGenerationWrite::METHOD_ID;
 
-   $result = $generator->generatePackages($method_id, $current_bundle, $packages);
 
-   foreach ($result as $message) {
 
-     $type = $message['success'] ? 'success' : 'error';
 
-     drush_log($message['message'], $message['variables'], $type);
 
-   }
 
- }
 
- /**
 
-  * Adds a component to a features module.
 
-  *
 
-  * @param
 
-  *   The selected components.
 
-  */
 
- function drush_features_add() {
 
-   if ($args = func_get_args()) {
 
-     $assigner = _drush_features_options();
 
-     /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-     $manager = \Drupal::service('features.manager');
 
-     /** @var \Drupal\features\FeaturesGeneratorInterface $generator */
 
-     $generator = \Drupal::service('features_generator');
 
-     $current_bundle = $assigner->getBundle();
 
-     $module = array_shift($args);
 
-     if (empty($args)) {
 
-       return drush_set_error('', 'No components supplied.');
 
-     }
 
-     $components = _drush_features_component_list();
 
-     $options = array(
 
-       'exported' => FALSE,
 
-     );
 
-     $filtered_components = _drush_features_component_filter($components, $args, $options);
 
-     $items = $filtered_components['components'];
 
-     if (empty($items)) {
 
-       return drush_set_error('', 'No components to add.');
 
-     }
 
-     $packages = array($module);
 
-     // If any packages exist, confirm before overwriting.
 
-     if ($existing_packages = $manager->listPackageDirectories($packages)) {
 
-       foreach ($existing_packages as $name => $directory) {
 
-         drush_print(dt("The extension @name already exists at @directory.", array('@name' => $name, '@directory' => $directory)));
 
-       }
 
-       // Apparently, format_plural is not always available.
 
-       if (count($existing_packages) == 1) {
 
-         $message = dt('Would you like to overwrite it?');
 
-       }
 
-       else {
 
-         $message = dt('Would you like to overwrite them?');
 
-       }
 
-       if (!drush_confirm($message)) {
 
-         return drush_user_abort();
 
-       }
 
-     }
 
-     else {
 
-       $package = $manager->initPackage($module, NULL, '', 'module', $current_bundle);
 
-       list($full_name, $path) = $manager->getExportInfo($package, $current_bundle);
 
-       drush_print(dt('Will create a new extension @name in @directory', array('@name' => $full_name, '@directory' => $path)));
 
-       if (!drush_confirm(dt('Do you really want to continue?'))) {
 
-         drush_die('Aborting.');
 
-       }
 
-     }
 
-     $config = _drush_features_build_config($items);
 
-     $manager->assignConfigPackage($module, $config);
 
-     // Use the write generation method.
 
-     $method_id = FeaturesGenerationWrite::METHOD_ID;
 
-     $result = $generator->generatePackages($method_id, $current_bundle, $packages);
 
-     foreach ($result as $message) {
 
-       $type = $message['success'] ? 'success' : 'error';
 
-       drush_log($message['message'], $message['variables'], $type);
 
-     }
 
-   }
 
-   else {
 
-     return drush_set_error('', 'No feature name given.');
 
-   }
 
- }
 
- /**
 
-  * Lists components, with pattern matching.
 
-  */
 
- function drush_features_components() {
 
-   $args = func_get_args();
 
-   _drush_features_options();
 
-   $components = _drush_features_component_list();
 
-   ksort($components);
 
-   // If no args supplied, prompt with a list.
 
-   if (empty($args)) {
 
-     $types = array_keys($components);
 
-     array_unshift($types, 'all');
 
-     $choice = drush_choice($types, 'Enter a number to choose which component type to list.');
 
-     if ($choice === FALSE) {
 
-       return;
 
-     }
 
-     $args = ($choice == 0) ? array('*') : array($types[$choice]);
 
-   }
 
-   $options = array(
 
-     'provided by' => TRUE,
 
-   );
 
-   if (drush_get_option(array('exported', 'e'), NULL)) {
 
-     $options['not exported'] = FALSE;
 
-   }
 
-   elseif (drush_get_option(array('not-exported', 'o'), NULL)) {
 
-     $options['exported'] = FALSE;
 
-   }
 
-   $filtered_components = _drush_features_component_filter($components, $args, $options);
 
-   if ($filtered_components) {
 
-     _drush_features_component_print($filtered_components);
 
-   }
 
- }
 
- /**
 
-  * Lists the differences in the package config vs the active store.
 
-  *
 
-  * @param string $package
 
-  *   The machine name of a package.
 
-  */
 
- function drush_features_diff() {
 
-   if (!$args = func_get_args()) {
 
-     drush_print_table(drush_features_list_packages());
 
-     return;
 
-   }
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   /** @var \Drupal\features\FeaturesAssignerInterface $assigner */
 
-   $assigner = \Drupal::service('features_assigner');
 
-   $assigner->assignConfigPackages();
 
-   $module = $args[0];
 
-   $filter_ctypes = drush_get_option("ctypes");
 
-   if ($filter_ctypes) {
 
-     $filter_ctypes = explode(',', $filter_ctypes);
 
-   }
 
-   $feature = $manager->loadPackage($module, TRUE);
 
-   if (empty($feature)) {
 
-     drush_log(dt('No such feature is available: @module', array('@module' => $module)), 'error');
 
-     return;
 
-   }
 
-   $lines = drush_get_option('lines');
 
-   $lines = isset($lines) ? $lines : 2;
 
-   $formatter = new DiffFormatter();
 
-   $formatter->leading_context_lines = $lines;
 
-   $formatter->trailing_context_lines = $lines;
 
-   $formatter->show_header = FALSE;
 
-   if (drush_get_context('DRUSH_NOCOLOR')) {
 
-     $red = $green = "%s";
 
-   }
 
-   else {
 
-     $red = "\033[31;40m\033[1m%s\033[0m";
 
-     $green = "\033[0;32;40m\033[1m%s\033[0m";
 
-   }
 
-   $overrides = $manager->detectOverrides($feature);
 
-   $missing = $manager->reorderMissing($manager->detectMissing($feature));
 
-   $overrides = array_merge($overrides, $missing);
 
-   if (empty($overrides)) {
 
-     drush_print(dt('Active config matches stored config for @module.', array('@module' => $module)));
 
-   }
 
-   else {
 
-     /** @var \Drupal\config_update\ConfigDiffInterface $config_diff */
 
-     $config_diff = \Drupal::service('config_update.config_diff');
 
-     /** @var \Drupal\Core\Config\StorageInterface $active_storage */
 
-     $active_storage = \Drupal::service('config.storage');
 
-     // Print key for colors.
 
-     drush_print(dt('Legend: '));
 
-     drush_print(sprintf($red, dt('Code:    drush features-import will replace the active config with the displayed code.')));
 
-     drush_print(sprintf($green, dt('Active:  drush features-export will update the exported feature with the displayed active config')));
 
-     foreach ($overrides as $name) {
 
-       $message = '';
 
-       if (in_array($name, $missing)) {
 
-         $message = sprintf($red, t('(missing from active)'));
 
-         $extension = array();
 
-       }
 
-       else {
 
-         $active = $manager->getActiveStorage()->read($name);
 
-         $extension = $manager->getExtensionStorages()->read($name);
 
-         if (empty($extension)) {
 
-           $extension = array();
 
-           $message = sprintf($green, t('(not exported)'));
 
-         }
 
-         $diff = $config_diff->diff($extension, $active);
 
-         $rows = explode("\n", $formatter->format($diff));
 
-       }
 
-       drush_print();
 
-       drush_print(dt("Config @name @message", array('@name' => $name, '@message' => $message)));
 
-       if (!empty($extension)) {
 
-         foreach ($rows as $row) {
 
-           if (strpos($row, '>') === 0) {
 
-             drush_print(sprintf($green, $row));
 
-           }
 
-           elseif (strpos($row, '<') === 0) {
 
-             drush_print(sprintf($red, $row));
 
-           }
 
-           else {
 
-             drush_print($row);
 
-           }
 
-         }
 
-       }
 
-     }
 
-   }
 
- }
 
- /**
 
-  * Imports module config into the active store.
 
-  *
 
-  * Same as the old "revert" functionality.
 
-  */
 
- function drush_features_import() {
 
-   if ($args = func_get_args()) {
 
-     _drush_features_options();
 
-     // Determine if revert should be forced.
 
-     $force = drush_get_option('force');
 
-     // Determine if -y was supplied. If so, we can filter out needless output
 
-     // from this command.
 
-     $skip_confirmation = drush_get_context('DRUSH_AFFIRMATIVE');
 
-     /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-     $manager = \Drupal::service('features.manager');
 
-     // Parse list of arguments.
 
-     $modules = array();
 
-     foreach ($args as $arg) {
 
-       $arg = explode(':', $arg);
 
-       $module = array_shift($arg);
 
-       $component = array_shift($arg);
 
-       if (isset($module)) {
 
-         if (empty($component)) {
 
-           // If we received just a feature name, this means that we need all of
 
-           // its components.
 
-           $modules[$module] = TRUE;
 
-         }
 
-         elseif ($modules[$module] !== TRUE) {
 
-           if (!isset($modules[$module])) {
 
-             $modules[$module] = array();
 
-           }
 
-           $modules[$module][] = $component;
 
-         }
 
-       }
 
-     }
 
-     // Process modules.
 
-     foreach ($modules as $module => $components_needed) {
 
-       $dt_args['@module'] = $module;
 
-       /** @var \Drupal\features\Package $feature */
 
-       $feature = $manager->loadPackage($module, TRUE);
 
-       if (empty($feature)) {
 
-         drush_log(dt('No such feature is available: @module', $dt_args), 'error');
 
-         return;
 
-       }
 
-       if ($feature->getStatus() != FeaturesManagerInterface::STATUS_INSTALLED) {
 
-         drush_log(dt('No such feature is installed: @module', $dt_args), 'error');
 
-         return;
 
-       }
 
-       // Forcefully revert all components of a feature.
 
-       if ($force) {
 
-         $components = $feature->getConfigOrig();
 
-       }
 
-       // Only revert components that are detected to be Overridden.
 
-       else {
 
-         $components = $manager->detectOverrides($feature);
 
-         $missing = $manager->reorderMissing($manager->detectMissing($feature));
 
-         // Be sure to import missing components first.
 
-         $components = array_merge($missing, $components);
 
-       }
 
-       if (!empty($components_needed) && is_array($components_needed)) {
 
-         $components = array_intersect($components, $components_needed);
 
-       }
 
-       if (empty($components)) {
 
-         drush_log(dt('Current state already matches active config, aborting.'), 'ok');
 
-       }
 
-       else {
 
-         // Determine which config the user wants to import/revert.
 
-         $config_to_create = [];
 
-         foreach ($components as $component) {
 
-           $dt_args['@component'] = $component;
 
-           $confirmation_message = 'Do you really want to import @module : @component?';
 
-           if ($skip_confirmation || drush_confirm(dt($confirmation_message, $dt_args))) {
 
-             $config_to_create[$component] = '';
 
-           }
 
-         }
 
-         // Perform the import/revert.
 
-         $config_imported = $manager->createConfiguration($config_to_create);
 
-         // List the results.
 
-         foreach ($components as $component) {
 
-           $dt_args['@component'] = $component;
 
-           if (isset($config_imported['new'][$component])) {
 
-             drush_log(dt('Imported @module : @component.', $dt_args), 'ok');
 
-           }
 
-           elseif (isset($config_imported['updated'][$component])) {
 
-             drush_log(dt('Reverted @module : @component.', $dt_args), 'ok');
 
-           }
 
-           elseif (!isset($config_to_create[$component])) {
 
-             drush_log(dt('Skipping @module : @component.', $dt_args), 'ok');
 
-           }
 
-           else {
 
-             drush_log(dt('Error importing @module : @component.', $dt_args), 'error');
 
-           }
 
-         }
 
-       }
 
-     }
 
-   }
 
-   else {
 
-     drush_print_table(drush_features_list_packages());
 
-     return;
 
-   }
 
- }
 
- /**
 
-  * Returns an array of full config names given a array[$type][$component].
 
-  *
 
-  * @param array $items
 
-  *   The items to return data for.
 
-  */
 
- function _drush_features_build_config(array $items) {
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   $result = array();
 
-   foreach ($items as $config_type => $item) {
 
-     foreach ($item as $item_name => $title) {
 
-       $result[] = $manager->getFullName($config_type, $item_name);
 
-     }
 
-   }
 
-   return $result;
 
- }
 
- /**
 
-  * Returns a listing of all known components, indexed by source.
 
-  */
 
- function _drush_features_component_list() {
 
-   $result = array();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   $config = $manager->getConfigCollection();
 
-   foreach ($config as $item_name => $item) {
 
-     $result[$item->getType()][$item->getShortName()] = $item->getLabel();
 
-   }
 
-   return $result;
 
- }
 
- /**
 
-  * Filters components by patterns.
 
-  */
 
- function _drush_features_component_filter($all_components, $patterns = array(), $options = array()) {
 
-   $options += array(
 
-     'exported' => TRUE,
 
-     'not exported' => TRUE,
 
-     'provided by' => FALSE,
 
-   );
 
-   $pool = array();
 
-   // Maps exported components to feature modules.
 
-   $components_map = _drush_features_get_component_map();
 
-   // First filter on exported state.
 
-   foreach ($all_components as $source => $components) {
 
-     foreach ($components as $name => $title) {
 
-       $exported = count($components_map[$source][$name]) > 0;
 
-       if ($exported) {
 
-         if ($options['exported']) {
 
-           $pool[$source][$name] = $title;
 
-         }
 
-       }
 
-       else {
 
-         if ($options['not exported']) {
 
-           $pool[$source][$name] = $title;
 
-         }
 
-       }
 
-     }
 
-   }
 
-   $state_string = '';
 
-   if (!$options['exported']) {
 
-     $state_string = 'unexported';
 
-   }
 
-   elseif (!$options['not exported']) {
 
-     $state_string = 'exported';
 
-   }
 
-   $selected = array();
 
-   foreach ($patterns as $pattern) {
 
-     // Rewrite * to %. Let users use both as wildcard.
 
-     $pattern = strtr($pattern, array('*' => '%'));
 
-     $sources = array();
 
-     list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
 
-     // If source is empty, use a pattern.
 
-     if ($source_pattern == '') {
 
-       $source_pattern = '%';
 
-     }
 
-     if ($component_pattern == '') {
 
-       $component_pattern = '%';
 
-     }
 
-     $preg_source_pattern = strtr(preg_quote($source_pattern, '/'), array('%' => '.*'));
 
-     $preg_component_pattern = strtr(preg_quote($component_pattern, '/'), array('%' => '.*'));
 
-     // If it isn't a pattern, but a simple string, we don't anchor the
 
-     // pattern. This allows for abbreviating. Otherwise, we do, as this seems
 
-     // more natural for patterns.
 
-     if (strpos($source_pattern, '%') !== FALSE) {
 
-       $preg_source_pattern = '^' . $preg_source_pattern . '$';
 
-     }
 
-     if (strpos($component_pattern, '%') !== FALSE) {
 
-       $preg_component_pattern = '^' . $preg_component_pattern . '$';
 
-     }
 
-     $matches = array();
 
-     // Find the sources.
 
-     $all_sources = array_keys($pool);
 
-     $matches = preg_grep('/' . $preg_source_pattern . '/', $all_sources);
 
-     if (count($matches) > 0) {
 
-       // If we have multiple matches and the source string wasn't a
 
-       // pattern, check if one of the matches is equal to the pattern, and
 
-       // use that, or error out.
 
-       if (count($matches) > 1 and $preg_source_pattern[0] != '^') {
 
-         if (in_array($source_pattern, $matches)) {
 
-           $matches = array($source_pattern);
 
-         }
 
-         else {
 
-           return drush_set_error('', dt('Ambiguous source "@source", matches @matches', array(
 
-             '@source' => $source_pattern,
 
-             '@matches' => implode(', ', $matches),
 
-           )));
 
-         }
 
-       }
 
-       // Loose the indexes preg_grep preserved.
 
-       $sources = array_values($matches);
 
-     }
 
-     else {
 
-       return drush_set_error('', dt('No @state sources match "@source"', array('@state' => $state_string, '@source' => $source_pattern)));
 
-     }
 
-     // Now find the components.
 
-     foreach ($sources as $source) {
 
-       // Find the components.
 
-       $all_components = array_keys($pool[$source]);
 
-       // See if there's any matches.
 
-       $matches = preg_grep('/' . $preg_component_pattern . '/', $all_components);
 
-       if (count($matches) > 0) {
 
-         // If we have multiple matches and the components string wasn't a
 
-         // pattern, check if one of the matches is equal to the pattern, and
 
-         // use that, or error out.
 
-         if (count($matches) > 1 and $preg_component_pattern[0] != '^') {
 
-           if (in_array($component_pattern, $matches)) {
 
-             $matches = array($component_pattern);
 
-           }
 
-           else {
 
-             return drush_set_error('', dt('Ambiguous component "@component", matches @matches', array(
 
-               '@component' => $component_pattern,
 
-               '@matches' => implode(', ', $matches),
 
-             )));
 
-           }
 
-         }
 
-         if (!is_array($selected[$source])) {
 
-           $selected[$source] = array();
 
-         }
 
-         $selected[$source] += array_intersect_key($pool[$source], array_flip($matches));
 
-       }
 
-       else {
 
-         // No matches. If the source was a pattern, just carry on, else
 
-         // error out. Allows for patterns like :*field*
 
-         if ($preg_source_pattern[0] != '^') {
 
-           return drush_set_error('', dt('No @state @source components match "@component"', array(
 
-             '@state' => $state_string,
 
-             '@component' => $component_pattern,
 
-             '@source' => $source,
 
-           )));
 
-         }
 
-       }
 
-     }
 
-   }
 
-   // Lastly, provide feature module information on the selected components, if
 
-   // requested.
 
-   $provided_by = array();
 
-   if ($options['provided by'] && $options['exported']) {
 
-     foreach ($selected as $source => $components) {
 
-       foreach ($components as $name => $title) {
 
-         $exported = count($components_map[$source][$name]) > 0;
 
-         if ($exported) {
 
-           $provided_by[$source . ':' . $name] = implode(', ', $components_map[$source][$name]);
 
-         }
 
-       }
 
-     }
 
-   }
 
-   return array(
 
-     'components' => $selected,
 
-     'sources' => $provided_by,
 
-   );
 
- }
 
- /**
 
-  * Provides a component to feature map (port of features_get_component_map).
 
-  */
 
- function _drush_features_get_component_map() {
 
-   $result = array();
 
-   /** @var \Drupal\features\FeaturesManagerInterface $manager */
 
-   $manager = \Drupal::service('features.manager');
 
-   // Recalc full config list without running assignments.
 
-   $config = $manager->getConfigCollection();
 
-   $packages = $manager->getPackages();
 
-   foreach ($config as $item_name => $item) {
 
-     $type = $item->getType();
 
-     $short_name = $item->getShortName();
 
-     $name = $item->getName();
 
-     if (!isset($result[$type][$short_name])) {
 
-       $result[$type][$short_name] = array();
 
-     }
 
-     if (!empty($item->getPackage())) {
 
-       $package = $packages[$item->getPackage()];
 
-       $result[$type][$short_name][] = $package->getMachineName();
 
-     }
 
-   }
 
-   return $result;
 
- }
 
- /**
 
-  * Prints a list of filtered components.
 
-  */
 
- function _drush_features_component_print($filtered_components) {
 
-   $rows = array(array(dt('Available sources')));
 
-   foreach ($filtered_components['components'] as $source => $components) {
 
-     foreach ($components as $name => $value) {
 
-       $row = array($source . ':' . $name);
 
-       if (isset($filtered_components['sources'][$source . ':' . $name])) {
 
-         $row[] = dt('Provided by') . ': ' . $filtered_components['sources'][$source . ':' . $name];
 
-       }
 
-       $rows[] = $row;
 
-     }
 
-   }
 
-   drush_print_table($rows, TRUE);
 
- }
 
 
  |