annotate sites/all/modules/features/features.drush.inc @ 9:830c812b520f

added smtp module
author root <root@paio.local>
date Mon, 28 Oct 2013 15:34:27 +0000
parents ce11bbd8f642
children
rev   line source
danielebarchiesi@4 1 <?php
danielebarchiesi@4 2
danielebarchiesi@4 3 /**
danielebarchiesi@4 4 * @file
danielebarchiesi@4 5 * Features module drush integration.
danielebarchiesi@4 6 */
danielebarchiesi@4 7
danielebarchiesi@4 8 /**
danielebarchiesi@4 9 * Implements hook_drush_command().
danielebarchiesi@4 10 *
danielebarchiesi@4 11 * @return
danielebarchiesi@4 12 * An associative array describing your command(s).
danielebarchiesi@4 13 *
danielebarchiesi@4 14 * @see drush_parse_command()
danielebarchiesi@4 15 */
danielebarchiesi@4 16 function features_drush_command() {
danielebarchiesi@4 17 $items = array();
danielebarchiesi@4 18
danielebarchiesi@4 19 $items['features-list'] = array(
danielebarchiesi@4 20 'description' => "List all the available features for your site.",
danielebarchiesi@4 21 'options' => array(
danielebarchiesi@4 22 'status' => "Feature status, can be 'enabled', 'disabled' or 'all'",
danielebarchiesi@4 23 ),
danielebarchiesi@4 24 'drupal dependencies' => array('features'),
danielebarchiesi@4 25 'aliases' => array('fl', 'features'),
danielebarchiesi@4 26 );
danielebarchiesi@4 27 $items['features-export'] = array(
danielebarchiesi@4 28 'description' => "Export a feature from your site into a module.",
danielebarchiesi@4 29 'arguments' => array(
danielebarchiesi@4 30 'feature' => 'Feature name to export.',
danielebarchiesi@4 31 'components' => 'Patterns of components to include, see features-components for the format of patterns.'
danielebarchiesi@4 32 ),
danielebarchiesi@4 33 'options' => array(
danielebarchiesi@4 34 'destination' => "Destination path (from Drupal root) of the exported feature. Defaults to 'sites/all/modules/features'",
danielebarchiesi@4 35 'version-set' => "Specify a version number for the feature.",
danielebarchiesi@4 36 'version-increment' => "Increment the feature's version number.",
danielebarchiesi@4 37 ),
danielebarchiesi@4 38 'drupal dependencies' => array('features'),
danielebarchiesi@4 39 'aliases' => array('fe'),
danielebarchiesi@4 40 );
danielebarchiesi@4 41 $items['features-add'] = array(
danielebarchiesi@4 42 'description' => "Add a component to a feature module. (DEPRECATED: use features-export)",
danielebarchiesi@4 43 'arguments' => array(
danielebarchiesi@4 44 'feature' => 'Feature name to add to.',
danielebarchiesi@4 45 'components' => 'List of components to add.',
danielebarchiesi@4 46 ),
danielebarchiesi@4 47 'options' => array(
danielebarchiesi@4 48 'version-set' => "Specify a version number for the feature.",
danielebarchiesi@4 49 'version-increment' => "Increment the feature's version number.",
danielebarchiesi@4 50 ),
danielebarchiesi@4 51 'drupal dependencies' => array('features'),
danielebarchiesi@4 52 'aliases' => array('fa'),
danielebarchiesi@4 53 );
danielebarchiesi@4 54 $items['features-components'] = array(
danielebarchiesi@4 55 'description' => 'List features components.',
danielebarchiesi@4 56 'arguments' => array(
danielebarchiesi@4 57 'patterns' => 'The features components type to list. Omit this argument to list all components.',
danielebarchiesi@4 58 ),
danielebarchiesi@4 59 'options' => array(
danielebarchiesi@4 60 'exported' => array(
danielebarchiesi@4 61 'description' => 'Show only components that have been exported.',
danielebarchiesi@4 62 ),
danielebarchiesi@4 63 'not-exported' => array(
danielebarchiesi@4 64 'description' => 'Show only components that have not been exported.',
danielebarchiesi@4 65 ),
danielebarchiesi@4 66 ),
danielebarchiesi@4 67 'aliases' => array('fc'),
danielebarchiesi@4 68 );
danielebarchiesi@4 69 $items['features-update'] = array(
danielebarchiesi@4 70 'description' => "Update a feature module on your site.",
danielebarchiesi@4 71 'arguments' => array(
danielebarchiesi@4 72 'feature' => 'A space delimited list of features.',
danielebarchiesi@4 73 ),
danielebarchiesi@4 74 'options' => array(
danielebarchiesi@4 75 'version-set' => "Specify a version number for the feature.",
danielebarchiesi@4 76 'version-increment' => "Increment the feature's version number.",
danielebarchiesi@4 77 ),
danielebarchiesi@4 78 'drupal dependencies' => array('features'),
danielebarchiesi@4 79 'aliases' => array('fu'),
danielebarchiesi@4 80 );
danielebarchiesi@4 81 $items['features-update-all'] = array(
danielebarchiesi@4 82 'description' => "Update all feature modules on your site.",
danielebarchiesi@4 83 'arguments' => array(
danielebarchiesi@4 84 'feature_exclude' => 'A space-delimited list of features to exclude from being updated.',
danielebarchiesi@4 85 ),
danielebarchiesi@4 86 'drupal dependencies' => array('features'),
danielebarchiesi@4 87 'aliases' => array('fu-all', 'fua'),
danielebarchiesi@4 88 );
danielebarchiesi@4 89 $items['features-revert'] = array(
danielebarchiesi@4 90 'description' => "Revert a feature module on your site.",
danielebarchiesi@4 91 'arguments' => array(
danielebarchiesi@4 92 'feature' => 'A space delimited list of features or feature.component pairs.',
danielebarchiesi@4 93 ),
danielebarchiesi@4 94 'options' => array(
danielebarchiesi@4 95 'force' => "Force revert even if Features assumes components' state are default.",
danielebarchiesi@4 96 ),
danielebarchiesi@4 97 'examples' => array(
danielebarchiesi@4 98 'drush fr foo.node foo.taxonomy bar' => 'Revert node and taxonomy components of feature "foo", but only if they are overriden. Revert all overriden components of feature "bar".',
danielebarchiesi@4 99 'drush fr foo.node foo.taxonomy bar --force' => 'Revert node and taxonomy components of feature "foo". Revert all components of feature "bar".',
danielebarchiesi@4 100 ),
danielebarchiesi@4 101 'drupal dependencies' => array('features'),
danielebarchiesi@4 102 'aliases' => array('fr'),
danielebarchiesi@4 103 );
danielebarchiesi@4 104 $items['features-revert-all'] = array(
danielebarchiesi@4 105 'description' => "Revert all enabled feature module on your site.",
danielebarchiesi@4 106 'arguments' => array(
danielebarchiesi@4 107 'feature_exclude' => 'A space-delimited list of features to exclude from being reverted.',
danielebarchiesi@4 108 ),
danielebarchiesi@4 109 'options' => array(
danielebarchiesi@4 110 'force' => "Force revert even if Features assumes components' state are default.",
danielebarchiesi@4 111 ),
danielebarchiesi@4 112 'drupal dependencies' => array('features'),
danielebarchiesi@4 113 'aliases' => array('fr-all', 'fra'),
danielebarchiesi@4 114 );
danielebarchiesi@4 115 $items['features-diff'] = array(
danielebarchiesi@4 116 'description' => "Show the difference between the default and overridden state of a feature.",
danielebarchiesi@4 117 'arguments' => array(
danielebarchiesi@4 118 'feature' => 'The feature in question.',
danielebarchiesi@4 119 ),
danielebarchiesi@4 120 'options' => array(
danielebarchiesi@4 121 'lines' => 'Generate diffs with <n> lines of context instead of the usual two.',
danielebarchiesi@4 122 ),
danielebarchiesi@4 123 'drupal dependencies' => array('features', 'diff'),
danielebarchiesi@4 124 'aliases' => array('fd'),
danielebarchiesi@4 125 );
danielebarchiesi@4 126
danielebarchiesi@4 127 return $items;
danielebarchiesi@4 128 }
danielebarchiesi@4 129
danielebarchiesi@4 130 /**
danielebarchiesi@4 131 * Implements hook_drush_help().
danielebarchiesi@4 132 */
danielebarchiesi@4 133 function features_drush_help($section) {
danielebarchiesi@4 134 switch ($section) {
danielebarchiesi@4 135 case 'drush:features':
danielebarchiesi@4 136 return dt("List all the available features for your site.");
danielebarchiesi@4 137 case 'drush:features-export':
danielebarchiesi@4 138 return dt("Export a feature from your site into a module. If called with no arguments, display a list of available components. If called with a single argument, attempt to create a feature including the given component with the same name. The option '--destination=foo' may be used to specify the path (from Drupal root) where the feature should be created. The default destination is 'sites/all/modules/features'. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
danielebarchiesi@4 139 case 'drush:features-components':
danielebarchiesi@4 140 return dt("List feature components matching patterns. The listing may be limited to exported/not-exported components.
danielebarchiesi@4 141
danielebarchiesi@4 142 A component pattern consists of a source, a colon and a component. Both source and component may be a full name (as in \"dependencies\"), a shorthand (for instance \"dep\") or a pattern (like \"%denci%\").
danielebarchiesi@4 143
danielebarchiesi@4 144 Shorthands are unique shortenings of a name. They will only match if exactly one option contains the shorthand. So in a standard installation, \"dep\" will work for dependencies, but \"user\" wont, as it matches both user_permission and user_role.
danielebarchiesi@4 145
danielebarchiesi@4 146 Patterns uses * or % for matching multiple sources/components. Unlike shorthands, patterns must match the whole name, so \"field:%article%\" should be used to select all fields containing \"article\" (which could both be those on the node type article, as well as those fields named article). * and % are equivalent, but the latter doesn't have to be escaped in UNIX shells.
danielebarchiesi@4 147
danielebarchiesi@4 148 Lastly, a pattern without a colon is interpreted as having \":%\" appended, for easy listing of all components of a source.
danielebarchiesi@4 149 ");
danielebarchiesi@4 150 case 'drush:features-update':
danielebarchiesi@4 151 return dt("Update a feature module on your site. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
danielebarchiesi@4 152 case 'drush:features-update-all':
danielebarchiesi@4 153 return dt("Update all feature modules on your site.");
danielebarchiesi@4 154 case 'drush:features-revert':
danielebarchiesi@4 155 return dt("Revert a feature module on your site.");
danielebarchiesi@4 156 case 'drush:features-revert-all':
danielebarchiesi@4 157 return dt("Revert all enabled feature module on your site.");
danielebarchiesi@4 158 case 'drush:features-diff':
danielebarchiesi@4 159 return dt("Show a diff of a feature module.");
danielebarchiesi@4 160 case 'drush:features-add':
danielebarchiesi@4 161 return dt("Add a component to a feature module. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
danielebarchiesi@4 162 }
danielebarchiesi@4 163 }
danielebarchiesi@4 164
danielebarchiesi@4 165 /**
danielebarchiesi@4 166 * Get a list of all feature modules.
danielebarchiesi@4 167 */
danielebarchiesi@4 168 function drush_features_list() {
danielebarchiesi@4 169 $status = drush_get_option('status') ? drush_get_option('status') : 'all';
danielebarchiesi@4 170 if (!in_array($status, array('enabled', 'disabled', 'all'))) {
danielebarchiesi@4 171 return drush_set_error('', dt('!status is not valid', array('!status' => $status)));
danielebarchiesi@4 172 }
danielebarchiesi@4 173
danielebarchiesi@4 174 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 175 $rows = array(array(dt('Name'), dt('Feature'), dt('Status'), dt('Version'), dt('State')));
danielebarchiesi@4 176
danielebarchiesi@4 177 // Sort the Features list before compiling the output.
danielebarchiesi@4 178 $features = features_get_features(NULL, TRUE);
danielebarchiesi@4 179 ksort($features);
danielebarchiesi@4 180
danielebarchiesi@4 181 foreach ($features as $k => $m) {
danielebarchiesi@4 182 switch (features_get_storage($m->name)) {
danielebarchiesi@4 183 case FEATURES_DEFAULT:
danielebarchiesi@4 184 case FEATURES_REBUILDABLE:
danielebarchiesi@4 185 $storage = '';
danielebarchiesi@4 186 break;
danielebarchiesi@4 187 case FEATURES_OVERRIDDEN:
danielebarchiesi@4 188 $storage = dt('Overridden');
danielebarchiesi@4 189 break;
danielebarchiesi@4 190 case FEATURES_NEEDS_REVIEW:
danielebarchiesi@4 191 $storage = dt('Needs review');
danielebarchiesi@4 192 break;
danielebarchiesi@4 193 }
danielebarchiesi@4 194 if (
danielebarchiesi@4 195 ($m->status == 0 && ($status == 'all' || $status == 'disabled')) ||
danielebarchiesi@4 196 ($m->status == 1 && ($status == 'all' || $status == 'enabled'))
danielebarchiesi@4 197 ) {
danielebarchiesi@4 198 $rows[] = array(
danielebarchiesi@4 199 $m->info['name'],
danielebarchiesi@4 200 $m->name,
danielebarchiesi@4 201 $m->status ? dt('Enabled') : dt('Disabled'),
danielebarchiesi@4 202 $m->info['version'],
danielebarchiesi@4 203 $storage
danielebarchiesi@4 204 );
danielebarchiesi@4 205 }
danielebarchiesi@4 206 }
danielebarchiesi@4 207 drush_print_table($rows, TRUE);
danielebarchiesi@4 208 }
danielebarchiesi@4 209
danielebarchiesi@4 210 /**
danielebarchiesi@4 211 * List components, with pattern matching.
danielebarchiesi@4 212 */
danielebarchiesi@4 213 function drush_features_components() {
danielebarchiesi@4 214 $args = func_get_args();
danielebarchiesi@4 215 $components = _drush_features_component_list();
danielebarchiesi@4 216 // If no args supplied, prompt with a list.
danielebarchiesi@4 217 if (empty($args)) {
danielebarchiesi@4 218 $types = array_keys($components);
danielebarchiesi@4 219 array_unshift($types, 'all');
danielebarchiesi@4 220 $choice = drush_choice($types, 'Enter a number to choose which component type to list.');
danielebarchiesi@4 221 if ($choice === FALSE) {
danielebarchiesi@4 222 return;
danielebarchiesi@4 223 }
danielebarchiesi@4 224
danielebarchiesi@4 225 $args = ($choice == 0) ? array('*') : array($types[$choice]);
danielebarchiesi@4 226 }
danielebarchiesi@4 227 $options = array(
danielebarchiesi@4 228 'provided by' => TRUE,
danielebarchiesi@4 229 );
danielebarchiesi@4 230 if (drush_get_option(array('exported', 'e'), NULL)) {
danielebarchiesi@4 231 $options['not exported'] = FALSE;
danielebarchiesi@4 232 }
danielebarchiesi@4 233 elseif (drush_get_option(array('not-exported', 'o'), NULL)) {
danielebarchiesi@4 234 $options['exported'] = FALSE;
danielebarchiesi@4 235 }
danielebarchiesi@4 236
danielebarchiesi@4 237 $filtered_components = _drush_features_component_filter($components, $args, $options);
danielebarchiesi@4 238 if ($filtered_components){
danielebarchiesi@4 239 _drush_features_component_print($filtered_components);
danielebarchiesi@4 240 }
danielebarchiesi@4 241 }
danielebarchiesi@4 242
danielebarchiesi@4 243 /**
danielebarchiesi@4 244 * Returns a listing of all known components, indexed by source.
danielebarchiesi@4 245 */
danielebarchiesi@4 246 function _drush_features_component_list() {
danielebarchiesi@4 247 $components = array();
danielebarchiesi@4 248 foreach (features_get_feature_components() as $source => $info) {
danielebarchiesi@4 249 if ($options = features_invoke($source, 'features_export_options')) {
danielebarchiesi@4 250 foreach ($options as $name => $title) {
danielebarchiesi@4 251 $components[$source][$name] = $title;
danielebarchiesi@4 252 }
danielebarchiesi@4 253 }
danielebarchiesi@4 254 }
danielebarchiesi@4 255 return $components;
danielebarchiesi@4 256 }
danielebarchiesi@4 257
danielebarchiesi@4 258 /**
danielebarchiesi@4 259 * Filters components by patterns.
danielebarchiesi@4 260 */
danielebarchiesi@4 261 function _drush_features_component_filter($all_components, $patterns = array(), $options = array()) {
danielebarchiesi@4 262 $options += array(
danielebarchiesi@4 263 'exported' => TRUE,
danielebarchiesi@4 264 'not exported' => TRUE,
danielebarchiesi@4 265 'provided by' => FALSE,
danielebarchiesi@4 266 );
danielebarchiesi@4 267 $pool = array();
danielebarchiesi@4 268 // Maps exported components to feature modules.
danielebarchiesi@4 269 $components_map = features_get_component_map();
danielebarchiesi@4 270 // First filter on exported state.
danielebarchiesi@4 271 foreach ($all_components as $source => $components) {
danielebarchiesi@4 272 foreach ($components as $name => $title) {
danielebarchiesi@4 273 $exported = sizeof($components_map[$source][$name]) > 0;
danielebarchiesi@4 274 if ($exported) {
danielebarchiesi@4 275 if ($options['exported']) {
danielebarchiesi@4 276 $pool[$source][$name] = $title;
danielebarchiesi@4 277 }
danielebarchiesi@4 278 }
danielebarchiesi@4 279 else {
danielebarchiesi@4 280 if ($options['not exported']) {
danielebarchiesi@4 281 $pool[$source][$name] = $title;
danielebarchiesi@4 282 }
danielebarchiesi@4 283 }
danielebarchiesi@4 284 }
danielebarchiesi@4 285 }
danielebarchiesi@4 286
danielebarchiesi@4 287 $state_string = '';
danielebarchiesi@4 288
danielebarchiesi@4 289 if (!$options['exported']) {
danielebarchiesi@4 290 $state_string = 'unexported';
danielebarchiesi@4 291 }
danielebarchiesi@4 292 elseif (!$options['not exported']) {
danielebarchiesi@4 293 $state_string = 'exported';
danielebarchiesi@4 294 }
danielebarchiesi@4 295
danielebarchiesi@4 296 $selected = array();
danielebarchiesi@4 297 foreach ($patterns as $pattern) {
danielebarchiesi@4 298 // Rewrite * to %. Let users use both as wildcard.
danielebarchiesi@4 299 $pattern = strtr($pattern, array('*' => '%'));
danielebarchiesi@4 300 $sources = array();
danielebarchiesi@4 301 list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
danielebarchiesi@4 302 // If source is empty, use a pattern.
danielebarchiesi@4 303 if ($source_pattern == '') {
danielebarchiesi@4 304 $source_pattern = '%';
danielebarchiesi@4 305 }
danielebarchiesi@4 306 if ($component_pattern == '') {
danielebarchiesi@4 307 $component_pattern = '%';
danielebarchiesi@4 308 }
danielebarchiesi@4 309
danielebarchiesi@4 310 $preg_source_pattern = strtr(preg_quote($source_pattern, '/'), array('%' => '.*'));
danielebarchiesi@4 311 $preg_component_pattern = strtr(preg_quote($component_pattern, '/'), array('%' => '.*'));
danielebarchiesi@4 312 /*
danielebarchiesi@4 313 * If it isn't a pattern, but a simple string, we don't anchor the
danielebarchiesi@4 314 * pattern, this allows for abbreviating. Else, we do, as this seems more
danielebarchiesi@4 315 * natural for patterns.
danielebarchiesi@4 316 */
danielebarchiesi@4 317 if (strpos($source_pattern, '%') !== FALSE) {
danielebarchiesi@4 318 $preg_source_pattern = '^' . $preg_source_pattern . '$';
danielebarchiesi@4 319 }
danielebarchiesi@4 320 if (strpos($component_pattern, '%') !== FALSE) {
danielebarchiesi@4 321 $preg_component_pattern = '^' . $preg_component_pattern . '$';
danielebarchiesi@4 322 }
danielebarchiesi@4 323 $matches = array();
danielebarchiesi@4 324
danielebarchiesi@4 325 // Find the sources.
danielebarchiesi@4 326 $all_sources = array_keys($pool);
danielebarchiesi@4 327 $matches = preg_grep('/' . $preg_source_pattern . '/', $all_sources);
danielebarchiesi@4 328 if (sizeof($matches) > 0) {
danielebarchiesi@4 329 // If we have multiple matches and the source string wasn't a
danielebarchiesi@4 330 // pattern, check if one of the matches is equal to the pattern, and
danielebarchiesi@4 331 // use that, or error out.
danielebarchiesi@4 332 if (sizeof($matches) > 1 and $preg_source_pattern[0] != '^') {
danielebarchiesi@4 333 if (in_array($source_pattern, $matches)) {
danielebarchiesi@4 334 $matches = array($source_pattern);
danielebarchiesi@4 335 }
danielebarchiesi@4 336 else {
danielebarchiesi@4 337 return drush_set_error('', dt('Ambiguous source "!source", matches !matches', array('!source' => $source_pattern, '!matches' => join(', ', $matches))));
danielebarchiesi@4 338 }
danielebarchiesi@4 339 }
danielebarchiesi@4 340 // Loose the indexes preg_grep preserved.
danielebarchiesi@4 341 $sources = array_values($matches);
danielebarchiesi@4 342 }
danielebarchiesi@4 343 else {
danielebarchiesi@4 344 return drush_set_error('', dt('No !state sources match "!source"', array('!state' => $state_string, '!source' => $source_pattern)));
danielebarchiesi@4 345 }
danielebarchiesi@4 346
danielebarchiesi@4 347
danielebarchiesi@4 348 // Now find the components.
danielebarchiesi@4 349 foreach ($sources as $source) {
danielebarchiesi@4 350 // Find the components.
danielebarchiesi@4 351 $all_components = array_keys($pool[$source]);
danielebarchiesi@4 352 // See if there's any matches.
danielebarchiesi@4 353 $matches = preg_grep('/' . $preg_component_pattern . '/', $all_components);
danielebarchiesi@4 354 if (sizeof($matches) > 0) {
danielebarchiesi@4 355 // If we have multiple matches and the components string wasn't a
danielebarchiesi@4 356 // pattern, check if one of the matches is equal to the pattern, and
danielebarchiesi@4 357 // use that, or error out.
danielebarchiesi@4 358 if (sizeof($matches) > 1 and $preg_component_pattern[0] != '^') {
danielebarchiesi@4 359 if (in_array($component_pattern, $matches)) {
danielebarchiesi@4 360 $matches = array($component_pattern);
danielebarchiesi@4 361 }
danielebarchiesi@4 362 else {
danielebarchiesi@4 363 return drush_set_error('', dt('Ambiguous component "!component", matches !matches', array('!component' => $component_pattern, '!matches' => join(', ', $matches))));
danielebarchiesi@4 364 }
danielebarchiesi@4 365 }
danielebarchiesi@4 366 if (!is_array($selected[$source])) {
danielebarchiesi@4 367 $selected[$source] = array();
danielebarchiesi@4 368 }
danielebarchiesi@4 369 $selected[$source] += array_intersect_key($pool[$source], array_flip($matches));
danielebarchiesi@4 370 }
danielebarchiesi@4 371 else {
danielebarchiesi@4 372 // No matches. If the source was a pattern, just carry on, else
danielebarchiesi@4 373 // error out. Allows for patterns like :*field*
danielebarchiesi@4 374 if ($preg_source_pattern[0] != '^') {
danielebarchiesi@4 375 return drush_set_error('', dt('No !state !source components match "!component"', array('!state' => $state_string, '!component' => $component_pattern, '!source' => $source)));
danielebarchiesi@4 376 }
danielebarchiesi@4 377 }
danielebarchiesi@4 378 }
danielebarchiesi@4 379 }
danielebarchiesi@4 380
danielebarchiesi@4 381 // Lastly, provide feature module information on the selected components, if
danielebarchiesi@4 382 // requested.
danielebarchiesi@4 383 $provided_by = array();
danielebarchiesi@4 384 if ($options['provided by'] && $options['exported'] ) {
danielebarchiesi@4 385 foreach ($selected as $source => $components) {
danielebarchiesi@4 386 foreach ($components as $name => $title) {
danielebarchiesi@4 387 $exported = sizeof($components_map[$source][$name]) > 0;
danielebarchiesi@4 388 if ($exported) {
danielebarchiesi@4 389 $provided_by[$source . ':' . $name] = join(', ', $components_map[$source][$name]);
danielebarchiesi@4 390 }
danielebarchiesi@4 391 }
danielebarchiesi@4 392 }
danielebarchiesi@4 393 }
danielebarchiesi@4 394
danielebarchiesi@4 395 return array(
danielebarchiesi@4 396 'components' => $selected,
danielebarchiesi@4 397 'sources' => $provided_by,
danielebarchiesi@4 398 );
danielebarchiesi@4 399 }
danielebarchiesi@4 400
danielebarchiesi@4 401 /**
danielebarchiesi@4 402 * Prints a list of filtered components.
danielebarchiesi@4 403 */
danielebarchiesi@4 404 function _drush_features_component_print($filtered_components) {
danielebarchiesi@4 405 $rows = array(array(dt('Available sources')));
danielebarchiesi@4 406 foreach ($filtered_components['components'] as $source => $components) {
danielebarchiesi@4 407 foreach ($components as $name => $value) {
danielebarchiesi@4 408 $row = array($source .':'. $name);
danielebarchiesi@4 409 if (isset($filtered_components['sources'][$source .':'. $name])) {
danielebarchiesi@4 410 $row[] = dt('Provided by') . ': ' . $filtered_components['sources'][$source .':'. $name];
danielebarchiesi@4 411 }
danielebarchiesi@4 412 $rows[] = $row;
danielebarchiesi@4 413 }
danielebarchiesi@4 414 }
danielebarchiesi@4 415
danielebarchiesi@4 416 drush_print_table($rows, TRUE);
danielebarchiesi@4 417 }
danielebarchiesi@4 418
danielebarchiesi@4 419 /**
danielebarchiesi@4 420 * Add a component to a features module, or create a new module with
danielebarchiesi@4 421 * the selected components.
danielebarchiesi@4 422 */
danielebarchiesi@4 423 function drush_features_export() {
danielebarchiesi@4 424 if ($args = func_get_args()) {
danielebarchiesi@4 425 $module = array_shift($args);
danielebarchiesi@4 426 if (empty($args)) {
danielebarchiesi@4 427 return drush_set_error('', 'No components supplied.');
danielebarchiesi@4 428 }
danielebarchiesi@4 429 $components = _drush_features_component_list();
danielebarchiesi@4 430 $options = array(
danielebarchiesi@4 431 'exported' => FALSE,
danielebarchiesi@4 432 );
danielebarchiesi@4 433
danielebarchiesi@4 434 $filtered_components = _drush_features_component_filter($components, $args, $options);
danielebarchiesi@4 435 $items = $filtered_components['components'];
danielebarchiesi@4 436
danielebarchiesi@4 437 if (empty($items)) {
danielebarchiesi@4 438 return drush_set_error('', 'No components to add.');
danielebarchiesi@4 439 }
danielebarchiesi@4 440
danielebarchiesi@4 441 $items = array_map('array_keys', $items);
danielebarchiesi@4 442
danielebarchiesi@4 443 if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
danielebarchiesi@4 444 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 445 _features_populate($items, $feature->info, $feature->name);
danielebarchiesi@4 446 _drush_features_export($feature->info, $feature->name, dirname($feature->filename));
danielebarchiesi@4 447 }
danielebarchiesi@4 448 elseif ($feature) {
danielebarchiesi@4 449 _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
danielebarchiesi@4 450 }
danielebarchiesi@4 451 else {
danielebarchiesi@4 452 // Same logic as in _drush_features_export. Should be refactored.
danielebarchiesi@4 453 $destination = drush_get_option(array('destination'), 'sites/all/modules/features');
danielebarchiesi@4 454 $directory = isset($directory) ? $directory : $destination . '/' . $module;
danielebarchiesi@4 455 drush_print(dt('Will create a new module in !dir', array('!dir' => $directory)));
danielebarchiesi@4 456 if (!drush_confirm(dt('Do you really want to continue?'))) {
danielebarchiesi@4 457 drush_die('Aborting.');
danielebarchiesi@4 458 }
danielebarchiesi@4 459 $export = _drush_features_generate_export($items, $module);
danielebarchiesi@4 460 _features_populate($items, $export[info], $export[name]);
danielebarchiesi@4 461 _drush_features_export($export['info'], $module, $directory);
danielebarchiesi@4 462 }
danielebarchiesi@4 463 }
danielebarchiesi@4 464 else {
danielebarchiesi@4 465 return drush_set_error('', 'No feature name given.');
danielebarchiesi@4 466 }
danielebarchiesi@4 467 }
danielebarchiesi@4 468
danielebarchiesi@4 469 /**
danielebarchiesi@4 470 * Add a component to a features module
danielebarchiesi@4 471 * the selected components.
danielebarchiesi@4 472 *
danielebarchiesi@4 473 * This is DEPRECATED, but keeping it around for a bit longer for user migration
danielebarchiesi@4 474 */
danielebarchiesi@4 475 function drush_features_add() {
danielebarchiesi@4 476 drush_print(dt('features-add is DEPRECATED.'));
danielebarchiesi@4 477 drush_print(dt('Calling features-export instead.'));
danielebarchiesi@4 478 drush_features_export();
danielebarchiesi@4 479 }
danielebarchiesi@4 480
danielebarchiesi@4 481
danielebarchiesi@4 482 /**
danielebarchiesi@4 483 * Update an existing feature module.
danielebarchiesi@4 484 */
danielebarchiesi@4 485 function drush_features_update() {
danielebarchiesi@4 486 if ($args = func_get_args()) {
danielebarchiesi@4 487 foreach ($args as $module) {
danielebarchiesi@4 488 if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
danielebarchiesi@4 489 _drush_features_export($feature->info, $feature->name, dirname($feature->filename));
danielebarchiesi@4 490 }
danielebarchiesi@4 491 else if ($feature) {
danielebarchiesi@4 492 _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
danielebarchiesi@4 493 }
danielebarchiesi@4 494 else {
danielebarchiesi@4 495 _features_drush_set_error($module);
danielebarchiesi@4 496 }
danielebarchiesi@4 497 }
danielebarchiesi@4 498 }
danielebarchiesi@4 499 else {
danielebarchiesi@4 500 // By default just show contexts that are available.
danielebarchiesi@4 501 $rows = array(array(dt('Available features')));
danielebarchiesi@4 502 foreach (features_get_features(NULL, TRUE) as $name => $info) {
danielebarchiesi@4 503 $rows[] = array($name);
danielebarchiesi@4 504 }
danielebarchiesi@4 505 drush_print_table($rows, TRUE);
danielebarchiesi@4 506 }
danielebarchiesi@4 507 }
danielebarchiesi@4 508
danielebarchiesi@4 509 /**
danielebarchiesi@4 510 * Update all enabled features. Optionally pass in a list of features to
danielebarchiesi@4 511 * exclude from being updated.
danielebarchiesi@4 512 */
danielebarchiesi@4 513 function drush_features_update_all() {
danielebarchiesi@4 514 $features_to_update = array();
danielebarchiesi@4 515 $features_to_exclude = func_get_args();
danielebarchiesi@4 516 foreach (features_get_features() as $module) {
danielebarchiesi@4 517 if ($module->status && !in_array($module->name, $features_to_exclude)) {
danielebarchiesi@4 518 $features_to_update[] = $module->name;
danielebarchiesi@4 519 }
danielebarchiesi@4 520 }
danielebarchiesi@4 521 drush_print(dt('The following modules will be updated: !modules', array('!modules' => implode(', ', $features_to_update))));
danielebarchiesi@4 522 if (drush_confirm(dt('Do you really want to continue?'))) {
danielebarchiesi@4 523 foreach ($features_to_update as $module_name) {
danielebarchiesi@4 524 drush_invoke_process(drush_sitealias_get_record('@self'), 'features-update', array($module_name));
danielebarchiesi@4 525 }
danielebarchiesi@4 526 }
danielebarchiesi@4 527 else {
danielebarchiesi@4 528 drush_die('Aborting.');
danielebarchiesi@4 529 }
danielebarchiesi@4 530 }
danielebarchiesi@4 531
danielebarchiesi@4 532 /**
danielebarchiesi@4 533 * Write a module to the site dir.
danielebarchiesi@4 534 *
danielebarchiesi@4 535 * @param $info
danielebarchiesi@4 536 * The feature info associative array.
danielebarchiesi@4 537 * @param $module_name
danielebarchiesi@4 538 * Optional. The name for the exported module.
danielebarchiesi@4 539 */
danielebarchiesi@4 540 function _drush_features_export($info, $module_name = NULL, $directory = NULL) {
danielebarchiesi@4 541 $root = drush_get_option(array('r', 'root'), drush_locate_root());
danielebarchiesi@4 542 if ($root) {
danielebarchiesi@4 543 $destination = drush_get_option(array('destination'), 'sites/all/modules/features');
danielebarchiesi@4 544 $directory = isset($directory) ? $directory : $destination . '/' . $module_name;
danielebarchiesi@4 545 if (is_dir($directory)) {
danielebarchiesi@4 546 drush_print(dt('Module appears to already exist in !dir', array('!dir' => $directory)));
danielebarchiesi@4 547 if (!drush_confirm(dt('Do you really want to continue?'))) {
danielebarchiesi@4 548 drush_die('Aborting.');
danielebarchiesi@4 549 }
danielebarchiesi@4 550 }
danielebarchiesi@4 551 else {
danielebarchiesi@4 552 drush_op('mkdir', $directory);
danielebarchiesi@4 553 }
danielebarchiesi@4 554 if (is_dir($directory)) {
danielebarchiesi@4 555 drupal_flush_all_caches();
danielebarchiesi@4 556 $export = _drush_features_generate_export($info, $module_name);
danielebarchiesi@4 557 $files = features_export_render($export, $module_name, TRUE);
danielebarchiesi@4 558 foreach ($files as $extension => $file_contents) {
danielebarchiesi@4 559 if (!in_array($extension, array('module', 'info'))) {
danielebarchiesi@4 560 $extension .= '.inc';
danielebarchiesi@4 561 }
danielebarchiesi@4 562 drush_op('file_put_contents', "{$directory}/{$module_name}.$extension", $file_contents);
danielebarchiesi@4 563 }
danielebarchiesi@4 564 drush_log(dt("Created module: !module in !directory", array('!module' => $module_name, '!directory' => $directory)), 'ok');
danielebarchiesi@4 565 }
danielebarchiesi@4 566 else {
danielebarchiesi@4 567 drush_die(dt('Couldn\'t create directory !directory', array('!directory' => $directory)));
danielebarchiesi@4 568 }
danielebarchiesi@4 569 }
danielebarchiesi@4 570 else {
danielebarchiesi@4 571 drush_die(dt('Couldn\'t locate site root'));
danielebarchiesi@4 572 }
danielebarchiesi@4 573 }
danielebarchiesi@4 574
danielebarchiesi@4 575 /**
danielebarchiesi@4 576 * Helper function for _drush_feature_export.
danielebarchiesi@4 577 *
danielebarchiesi@4 578 * @param $info
danielebarchiesi@4 579 * The feature info associative array.
danielebarchiesi@4 580 * @param $module_name
danielebarchiesi@4 581 * Optional. The name for the exported module.
danielebarchiesi@4 582 */
danielebarchiesi@4 583 function _drush_features_generate_export(&$info, &$module_name) {
danielebarchiesi@4 584 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 585 $export = features_populate($info, $module_name);
danielebarchiesi@4 586 if (!features_load_feature($module_name)) {
danielebarchiesi@4 587 $export['name'] = $module_name;
danielebarchiesi@4 588 }
danielebarchiesi@4 589 // Set the feature version if the --version-set or --version-increment option is passed.
danielebarchiesi@4 590 if ($version = drush_get_option(array('version-set'))) {
danielebarchiesi@4 591 preg_match('/^(?P<core>\d+\.x)-(?P<major>\d+)\.(?P<patch>\d+)-?(?P<extra>\w+)?$/', $version, $matches);
danielebarchiesi@4 592 if (!isset($matches['core'], $matches['major'])) {
danielebarchiesi@4 593 drush_die(dt('Please enter a valid version with core and major version number. Example: !example', array('!example' => '7.x-1.0')));
danielebarchiesi@4 594 }
danielebarchiesi@4 595 $export['version'] = $version;
danielebarchiesi@4 596 }
danielebarchiesi@4 597 else if ($version = drush_get_option(array('version-increment'))) {
danielebarchiesi@4 598 // Determine current version and increment it.
danielebarchiesi@4 599 $export_load = features_export_prepare($export, $module_name);
danielebarchiesi@4 600 $version = $export_load['version'];
danielebarchiesi@4 601 $version_explode = explode('.', $version);
danielebarchiesi@4 602 $version_minor = array_pop($version_explode);
danielebarchiesi@4 603 // Increment minor version number if numeric or not a dev release.
danielebarchiesi@4 604 if (is_numeric($version_minor) || strpos($version_minor, 'dev') !== (strlen($version_minor) - 3)) {
danielebarchiesi@4 605 // Check for prefixed versions (alpha, beta, rc).
danielebarchiesi@4 606 if (ctype_digit($version_minor)) {
danielebarchiesi@4 607 ++$version_minor;
danielebarchiesi@4 608 }
danielebarchiesi@4 609 else {
danielebarchiesi@4 610 // Split version number parts.
danielebarchiesi@4 611 $pattern = '/([0-9]-[a-z]+([0-9])+)/';
danielebarchiesi@4 612 $matches = array();
danielebarchiesi@4 613 preg_match($pattern, $version_minor, $matches);
danielebarchiesi@4 614 $number = array_pop($matches);
danielebarchiesi@4 615 ++$number;
danielebarchiesi@4 616 $pattern = '/[0-9]+$/';
danielebarchiesi@4 617 $version_minor = preg_replace($pattern, $number, $version_minor);
danielebarchiesi@4 618 }
danielebarchiesi@4 619 }
danielebarchiesi@4 620 array_push($version_explode, $version_minor);
danielebarchiesi@4 621 // Rebuild version string.
danielebarchiesi@4 622 $version = implode('.', $version_explode);
danielebarchiesi@4 623 $export['version'] = $version;
danielebarchiesi@4 624 }
danielebarchiesi@4 625 return $export;
danielebarchiesi@4 626 }
danielebarchiesi@4 627
danielebarchiesi@4 628 /**
danielebarchiesi@4 629 * Revert a feature to it's code definition.
danielebarchiesi@4 630 * Optionally accept a list of components to revert.
danielebarchiesi@4 631 */
danielebarchiesi@4 632 function drush_features_revert() {
danielebarchiesi@4 633 if ($args = func_get_args()) {
danielebarchiesi@4 634 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 635 features_include();
danielebarchiesi@4 636
danielebarchiesi@4 637 // Determine if revert should be forced.
danielebarchiesi@4 638 $force = drush_get_option('force');
danielebarchiesi@4 639
danielebarchiesi@4 640 // Parse list of arguments.
danielebarchiesi@4 641 $modules = array();
danielebarchiesi@4 642 foreach ($args as $arg) {
danielebarchiesi@4 643 $arg = explode('.', $arg);
danielebarchiesi@4 644 $module = array_shift($arg);
danielebarchiesi@4 645 $component = array_shift($arg);
danielebarchiesi@4 646
danielebarchiesi@4 647 if (isset($module)) {
danielebarchiesi@4 648 if (empty($component)) {
danielebarchiesi@4 649 // If we received just a feature name, this means that we need all of it's components.
danielebarchiesi@4 650 $modules[$module] = TRUE;
danielebarchiesi@4 651 }
danielebarchiesi@4 652 elseif ($modules[$module] !== TRUE) {
danielebarchiesi@4 653 if (!isset($modules[$module])) {
danielebarchiesi@4 654 $modules[$module] = array();
danielebarchiesi@4 655 }
danielebarchiesi@4 656 $modules[$module][] = $component;
danielebarchiesi@4 657 }
danielebarchiesi@4 658 }
danielebarchiesi@4 659 }
danielebarchiesi@4 660
danielebarchiesi@4 661 // Process modules.
danielebarchiesi@4 662 foreach ($modules as $module => $components_needed) {
danielebarchiesi@4 663 if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
danielebarchiesi@4 664
danielebarchiesi@4 665 $components = array();
danielebarchiesi@4 666 // Forcefully revert all components of a feature.
danielebarchiesi@4 667 if ($force) {
danielebarchiesi@4 668 foreach (array_keys($feature->info['features']) as $component) {
danielebarchiesi@4 669 if (features_hook($component, 'features_revert')) {
danielebarchiesi@4 670 $components[] = $component;
danielebarchiesi@4 671 }
danielebarchiesi@4 672 }
danielebarchiesi@4 673 }
danielebarchiesi@4 674 // Only revert components that are detected to be Overridden/Needs review/rebuildable.
danielebarchiesi@4 675 else {
danielebarchiesi@4 676 $states = features_get_component_states(array($feature->name), FALSE);
danielebarchiesi@4 677 foreach ($states[$feature->name] as $component => $state) {
danielebarchiesi@4 678 if (in_array($state, array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW, FEATURES_REBUILDABLE)) && features_hook($component, 'features_revert')) {
danielebarchiesi@4 679 $components[] = $component;
danielebarchiesi@4 680 }
danielebarchiesi@4 681 }
danielebarchiesi@4 682 }
danielebarchiesi@4 683
danielebarchiesi@4 684 if (!empty($components_needed) && is_array($components_needed)) {
danielebarchiesi@4 685 $components = array_intersect($components, $components_needed);
danielebarchiesi@4 686 }
danielebarchiesi@4 687 if (empty($components)) {
danielebarchiesi@4 688 drush_log(dt('Current state already matches defaults, aborting.'), 'ok');
danielebarchiesi@4 689 }
danielebarchiesi@4 690 else {
danielebarchiesi@4 691 foreach ($components as $component) {
danielebarchiesi@4 692 if (drush_confirm(dt('Do you really want to revert @component?', array('@component' => $component)))) {
danielebarchiesi@4 693 features_revert(array($module => array($component)));
danielebarchiesi@4 694 drush_log(dt('Reverted @component.', array('@component' => $component)), 'ok');
danielebarchiesi@4 695 }
danielebarchiesi@4 696 else {
danielebarchiesi@4 697 drush_log(dt('Skipping @component.', array('@component' => $component)), 'ok');
danielebarchiesi@4 698 }
danielebarchiesi@4 699 }
danielebarchiesi@4 700 }
danielebarchiesi@4 701 }
danielebarchiesi@4 702 else if ($feature) {
danielebarchiesi@4 703 _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
danielebarchiesi@4 704 }
danielebarchiesi@4 705 else {
danielebarchiesi@4 706 _features_drush_set_error($module);
danielebarchiesi@4 707 }
danielebarchiesi@4 708 }
danielebarchiesi@4 709 }
danielebarchiesi@4 710 else {
danielebarchiesi@4 711 drush_features_list();
danielebarchiesi@4 712 return;
danielebarchiesi@4 713 }
danielebarchiesi@4 714 }
danielebarchiesi@4 715
danielebarchiesi@4 716 /**
danielebarchiesi@4 717 * Revert all enabled features to their definitions in code.
danielebarchiesi@4 718 *
danielebarchiesi@4 719 * @param ...
danielebarchiesi@4 720 * (Optional) A list of features to exclude from being reverted.
danielebarchiesi@4 721 */
danielebarchiesi@4 722 function drush_features_revert_all() {
danielebarchiesi@4 723 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 724 $force = drush_get_option('force');
danielebarchiesi@4 725 $features_to_exclude = func_get_args();
danielebarchiesi@4 726
danielebarchiesi@4 727 $features_to_revert = array();
danielebarchiesi@4 728 foreach (features_get_features(NULL, TRUE) as $module) {
danielebarchiesi@4 729 if ($module->status && !in_array($module->name, $features_to_exclude)) {
danielebarchiesi@4 730 // If forced, add module regardless of status.
danielebarchiesi@4 731 if ($force) {
danielebarchiesi@4 732 $features_to_revert[] = $module->name;
danielebarchiesi@4 733 }
danielebarchiesi@4 734 else {
danielebarchiesi@4 735 switch (features_get_storage($module->name)) {
danielebarchiesi@4 736 case FEATURES_OVERRIDDEN:
danielebarchiesi@4 737 case FEATURES_NEEDS_REVIEW:
danielebarchiesi@4 738 case FEATURES_REBUILDABLE:
danielebarchiesi@4 739 $features_to_revert[] = $module->name;
danielebarchiesi@4 740 break;
danielebarchiesi@4 741 }
danielebarchiesi@4 742 }
danielebarchiesi@4 743 }
danielebarchiesi@4 744 }
danielebarchiesi@4 745
danielebarchiesi@4 746 if ($features_to_revert) {
danielebarchiesi@4 747 drush_print(dt('The following modules will be reverted: !modules', array('!modules' => implode(', ', $features_to_revert))));
danielebarchiesi@4 748 if (drush_confirm(dt('Do you really want to continue?'))) {
danielebarchiesi@4 749 foreach ($features_to_revert as $module) {
danielebarchiesi@4 750 drush_invoke_process(drush_sitealias_get_record('@self'), 'features-revert', array($module), array('force' => $force, '#integrate' => TRUE));
danielebarchiesi@4 751 }
danielebarchiesi@4 752 }
danielebarchiesi@4 753 else {
danielebarchiesi@4 754 return drush_user_abort('Aborting.');
danielebarchiesi@4 755 }
danielebarchiesi@4 756 }
danielebarchiesi@4 757 else {
danielebarchiesi@4 758 drush_log(dt('Current state already matches defaults, aborting.'), 'ok');
danielebarchiesi@4 759 }
danielebarchiesi@4 760 }
danielebarchiesi@4 761
danielebarchiesi@4 762 /**
danielebarchiesi@4 763 * Show the diff of a feature module.
danielebarchiesi@4 764 */
danielebarchiesi@4 765 function drush_features_diff() {
danielebarchiesi@4 766 if (!$args = func_get_args()) {
danielebarchiesi@4 767 drush_features_list();
danielebarchiesi@4 768 return;
danielebarchiesi@4 769 }
danielebarchiesi@4 770 $module = $args[0];
danielebarchiesi@4 771 $feature = features_load_feature($module);
danielebarchiesi@4 772 if (!module_exists($module)) {
danielebarchiesi@4 773 drush_log(dt('No such feature is enabled: ' . $module), 'error');
danielebarchiesi@4 774 return;
danielebarchiesi@4 775 }
danielebarchiesi@4 776 module_load_include('inc', 'features', 'features.export');
danielebarchiesi@4 777 $overrides = features_detect_overrides($feature);
danielebarchiesi@4 778 if (empty($overrides)) {
danielebarchiesi@4 779 drush_log(dt('Feature is in its default state. No diff needed.'), 'ok');
danielebarchiesi@4 780 return;
danielebarchiesi@4 781 }
danielebarchiesi@4 782 module_load_include('inc', 'diff', 'diff.engine');
danielebarchiesi@4 783
danielebarchiesi@4 784 if (!class_exists('DiffFormatter')) {
danielebarchiesi@4 785 if (drush_confirm(dt('It seems that the Diff module is not available. Would you like to download and enable it?'))) {
danielebarchiesi@4 786 // Download it if it's not already here.
danielebarchiesi@4 787 $project_info = drush_get_projects();
danielebarchiesi@4 788 if (empty($project_info['diff']) && !drush_invoke_process(drush_sitealias_get_record('@self'), 'dl', array('diff'), array('#integrate' => TRUE))) {
danielebarchiesi@4 789 return drush_set_error(dt('Diff module could not be downloaded.'));
danielebarchiesi@4 790 }
danielebarchiesi@4 791
danielebarchiesi@4 792 if (!drush_invoke_process(drush_sitealias_get_record('@self'), 'en', array('diff'), array('#integrate' => TRUE))) {
danielebarchiesi@4 793 return drush_set_error(dt('Diff module could not be enabled.'));
danielebarchiesi@4 794 }
danielebarchiesi@4 795 }
danielebarchiesi@4 796 else {
danielebarchiesi@4 797 return drush_set_error(dt('Diff module is not enabled.'));
danielebarchiesi@4 798 }
danielebarchiesi@4 799 // If we're still here, now we can include the diff.engine again.
danielebarchiesi@4 800 module_load_include('inc', 'diff', 'diff.engine');
danielebarchiesi@4 801 }
danielebarchiesi@4 802
danielebarchiesi@4 803 $lines = (int) drush_get_option('lines');
danielebarchiesi@4 804 $lines = $lines > 0 ? $lines : 2;
danielebarchiesi@4 805
danielebarchiesi@4 806 $formatter = new DiffFormatter();
danielebarchiesi@4 807 $formatter->leading_context_lines = $lines;
danielebarchiesi@4 808 $formatter->trailing_context_lines = $lines;
danielebarchiesi@4 809 $formatter->show_header = FALSE;
danielebarchiesi@4 810
danielebarchiesi@4 811 if (drush_get_context('DRUSH_NOCOLOR')) {
danielebarchiesi@4 812 $red = $green = "%s";
danielebarchiesi@4 813 }
danielebarchiesi@4 814 else {
danielebarchiesi@4 815 $red = "\033[31;40m\033[1m%s\033[0m";
danielebarchiesi@4 816 $green = "\033[0;32;40m\033[1m%s\033[0m";
danielebarchiesi@4 817 }
danielebarchiesi@4 818
danielebarchiesi@4 819 // Print key for colors
danielebarchiesi@4 820 drush_print(dt('Legend: '));
danielebarchiesi@4 821 drush_print(sprintf($red, dt('Code: drush features-revert will remove the overrides.')));
danielebarchiesi@4 822 drush_print(sprintf($green, dt('Overrides: drush features-update will update the exported feature with the displayed overrides')));
danielebarchiesi@4 823 drush_print();
danielebarchiesi@4 824
danielebarchiesi@4 825 foreach ($overrides as $component => $items) {
danielebarchiesi@4 826 $diff = new Diff(explode("\n", $items['default']), explode("\n", $items['normal']));
danielebarchiesi@4 827 drush_print();
danielebarchiesi@4 828 drush_print(dt("Component: !component", array('!component' => $component)));
danielebarchiesi@4 829 $rows = explode("\n", $formatter->format($diff));
danielebarchiesi@4 830 foreach ($rows as $row) {
danielebarchiesi@4 831 if (strpos($row, '>') === 0) {
danielebarchiesi@4 832 drush_print(sprintf($green, $row));
danielebarchiesi@4 833 }
danielebarchiesi@4 834 elseif (strpos($row, '<') === 0) {
danielebarchiesi@4 835 drush_print(sprintf($red, $row));
danielebarchiesi@4 836 }
danielebarchiesi@4 837 else {
danielebarchiesi@4 838 drush_print($row);
danielebarchiesi@4 839 }
danielebarchiesi@4 840 }
danielebarchiesi@4 841 }
danielebarchiesi@4 842 }
danielebarchiesi@4 843
danielebarchiesi@4 844 /**
danielebarchiesi@4 845 * Helper function to call drush_set_error().
danielebarchiesi@4 846 *
danielebarchiesi@4 847 * @param $feature
danielebarchiesi@4 848 * The string name of the feature.
danielebarchiesi@4 849 * @param $error
danielebarchiesi@4 850 * A text string identifying the type of error.
danielebarchiesi@4 851 * @return
danielebarchiesi@4 852 * FALSE. See drush_set_error().
danielebarchiesi@4 853 */
danielebarchiesi@4 854 function _features_drush_set_error($feature, $error = '') {
danielebarchiesi@4 855 $args = array('!feature' => $feature);
danielebarchiesi@4 856
danielebarchiesi@4 857 switch ($error) {
danielebarchiesi@4 858 case 'FEATURES_FEATURE_NOT_ENABLED':
danielebarchiesi@4 859 $message = 'The feature !feature is not enabled.';
danielebarchiesi@4 860 break;
danielebarchiesi@4 861 case 'FEATURES_COMPONENT_NOT_FOUND':
danielebarchiesi@4 862 $message = 'The given component !feature could not be found.';
danielebarchiesi@4 863 break;
danielebarchiesi@4 864 default:
danielebarchiesi@4 865 $error = 'FEATURES_FEATURE_NOT_FOUND';
danielebarchiesi@4 866 $message = 'The feature !feature could not be found.';
danielebarchiesi@4 867 }
danielebarchiesi@4 868
danielebarchiesi@4 869 return drush_set_error($error, dt($message, $args));
danielebarchiesi@4 870 }