Projet

Général

Profil

Paste
Télécharger (31,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / drush / ctools.drush.inc @ c2ac6d1d

1
<?php
2

    
3
/**
4
 * @file
5
 * CTools Drush commands.
6
 */
7

    
8
/**
9
 * Implements hook_drush_command().
10
 */
11
function ctools_drush_command() {
12
  $items = array();
13

    
14
  $module_text = 'Filter the list of exportables by module. This will come from the \'export_module\' key on the exportable.';
15
  $all_text = 'Perform this operation all CTools exportables available on the system (all tables).';
16

    
17
  $items['ctools-export'] = array(
18
    'aliases' => array('ctex'),
19
    'callback' => 'ctools_drush_export',
20
    'description' => 'Export multiple CTools exportable objects directly to code.',
21
    'arguments' => array(
22
      'module'    => 'Name of your module.',
23
    ),
24
    'options' => array(
25
      'subdir' => 'The name of the sub directory to create the module in. Defaults to ctools_export which will be placed into sites/all/modules.',
26
      'remove' => 'Remove existing files before writing, except the .module file.',
27
      'filter' => 'Filter the list of exportables by status. Available options are enabled, disabled, overridden, database, code and all. Defaults to enabled.',
28
      'tables' => 'Comma separated list of exportable table names to filter by.',
29
    ),
30
    'examples' => array(
31
      'drush ctex export_module' => 'Export CTools exportables to a module called "export_module".',
32
      'drush ctex export_module --subdir=exports' => 'Same as above, but into the sites/all/modules/exports directory.',
33
      'drush ctex export_module --subdir=exports --remove' => 'Same as above, but automatically removing all files, except for the .module file.',
34
      'drush ctex --filter="views_view"' => 'Filter export selection to the views_view table only.',
35
    ),
36
  );
37

    
38
  $items['ctools-export-info'] = array(
39
    'aliases' => array('ctei'),
40
    'callback' => 'ctools_drush_export_info',
41
    'description' => 'Show available CTools exportable objects.',
42
    'arguments' => array(),
43
    'options' => array(
44
      'format' => 'Display exportables info in a different format such as print_r, json, export. The default is to show in a tabular format.',
45
      'tables-only' => 'Only show list of exportable types/table names and not available objects.',
46
      'filter' => 'Filter the list of exportables by status. Available options are enabled, disabled, overridden, database, and code.',
47
      'module' => $module_text,
48
    ),
49
    'examples' => array(
50
      'drush ctools-export-info' => 'View export info on all exportables.',
51
      'drush ctools-export-info views_view variable' => 'View export info for views_view and variable exportable types only.',
52
      'drush ctei --filter=enabled' => 'Show all enabled exportables.',
53
      'drush ctei views_view --filter=disabled' => 'Show all enabled exportables.',
54
      'drush ctei views_view --module=node' => 'Show all exportables provided by/on behalf of the node module.',
55
    ),
56
  );
57

    
58
  $items['ctools-export-view'] = array(
59
    'aliases' => array('ctev'),
60
    'callback' => 'ctools_drush_export_op_command',
61
    'description' => 'View CTools exportable object code output.',
62
    'arguments' => array(
63
      'table name' => 'Base table of the exportable you want to view.',
64
      'machine names' => 'Space separated list of exportables you want to view.',
65
    ),
66
    'options' => array(
67
      'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
68
      'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
69
      'module' => $module_text,
70
      'all' => $all_text,
71
    ),
72
    'examples' => array(
73
      'drush ctools-export-view views_view' => 'View all views exportable objects.',
74
      'drush ctools-export-view views_view archive' => 'View default views archive view.',
75
    ),
76
  );
77

    
78
  $items['ctools-export-revert'] = array(
79
    'aliases' => array('cter'),
80
    'callback' => 'ctools_drush_export_op_command',
81
    'description' => 'Revert CTools exportables from changes overridden in the database.',
82
    'arguments' => array(
83
      'table name' => 'Base table of the exportable you want to revert.',
84
      'machine names' => 'Space separated list of exportables you want to revert.',
85
    ),
86
    'options' => array(
87
      'module' => $module_text,
88
      'all' => $all_text,
89
    ),
90
    'examples' => array(
91
      'drush ctools-export-revert views_view' => 'Revert all overridden views exportable objects.',
92
      'drush ctools-export-revert views_view archive' => 'Revert overridden default views archive view.',
93
      'drush ctools-export-revert --all' => 'Revert all exportables on the system.',
94
    ),
95
  );
96

    
97
  $items['ctools-export-enable'] = array(
98
    'aliases' => array('ctee'),
99
    'callback' => 'ctools_drush_export_op_command',
100
    'description' => 'Enable CTools exportables.',
101
    'arguments' => array(
102
      'table name' => 'Base table of the exportable you want to enable.',
103
      'machine names' => 'Space separated list of exportables you want to enable.',
104
    ),
105
    'options' => array(
106
      'module' => $module_text,
107
      'all' => $all_text,
108
    ),
109
    'examples' => array(
110
      'drush ctools-export-enable views_view' => 'Enable all overridden views exportable objects.',
111
      'drush ctools-export-enable views_view archive' => 'Enable overridden default views archive view.',
112
    ),
113
  );
114

    
115
  $items['ctools-export-disable'] = array(
116
    'aliases' => array('cted'),
117
    'callback' => 'ctools_drush_export_op_command',
118
    'description' => 'Disable CTools exportables.',
119
    'arguments' => array(
120
      'table name' => 'Base table of the exportable you want to disable.',
121
      'machine names' => 'Space separated list of exportables you want to disable.',
122
    ),
123
    'options' => array(
124
      'module' => $module_text,
125
      'all' => $all_text,
126
    ),
127
    'examples' => array(
128
      'drush ctools-export-disable views_view' => 'Disable all overridden views exportable objects.',
129
      'drush ctools-export-disable views_view archive' => 'Disable overridden default views archive view.',
130
    ),
131
  );
132

    
133
  return $items;
134
}
135

    
136
/**
137
 * Implementation of hook_drush_help().
138
 */
139
function ctools_drush_help($section) {
140
  switch ($section) {
141
    case 'meta:ctools:title':
142
      return dt('CTools commands');
143

    
144
    case 'meta:entity:summary':
145
      return dt('CTools drush commands.');
146
  }
147
}
148

    
149
/**
150
 * Drush callback: export.
151
 */
152
function ctools_drush_export($module = 'foo') {
153
  $error = FALSE;
154
  if (preg_match('@[^a-z_]+@', $module)) {
155
    $error = dt('The name of the module must contain only lowercase letters and underscores') . '.';
156
    drush_log($error, 'error');
157
    return;
158
  }
159

    
160
  // Filter by tables.
161
  $tables = _ctools_drush_explode_options('tables');
162

    
163
  // Check status.
164
  $filter = drush_get_option('filter', FALSE);
165
  if (empty($filter)) {
166
    drush_set_option('filter', 'enabled');
167
  }
168

    
169
  // Selection.
170
  $options = array('all' => dt('Export everything'), 'select' => dt('Make selection'));
171
  $selection = drush_choice($options, dt('Select to proceed'));
172

    
173
  if (!$selection) {
174
    return;
175
  }
176

    
177
  // Present the selection screens.
178
  if ($selection == 'select') {
179
    $selections = _ctools_drush_selection_screen($tables);
180
  }
181
  else {
182
    $info = _ctools_drush_export_info($tables, TRUE);
183
    $selections = $info['exportables'];
184
  }
185

    
186
  // Subdirectory.
187
  $dest_exists = FALSE;
188
  $subdir = drush_get_option('subdir', 'ctools_export');
189
  $dest = 'sites/all/modules/' . $subdir . '/' . $module;
190

    
191
  // Overwriting files can be set with 'remove' argument.
192
  $remove = drush_get_option('remove', FALSE);
193

    
194
  // Check if folder exists.
195
  if (file_exists($dest)) {
196
    $dest_exists = TRUE;
197
    if ($remove) {
198
      if (drush_confirm(dt('All files except for the .info and .module files in !module will be removed. You can choose later if you want to overwrite these files as well. Are you sure you want to proceed ?', array('!module' => $module)))) {
199
        $remove = TRUE;
200
        drush_log(dt('Files will be removed'), 'success');
201
      }
202
      else {
203
        drush_log(dt('Export aborted.'), 'success');
204
        return;
205
      }
206
    }
207
  }
208

    
209
  // Remove files (except for the .module file) if the destination folder exists.
210
  if ($remove && $dest_exists) {
211
    _ctools_drush_file_delete($dest);
212
  }
213

    
214
  // Create new dir if needed.
215
  if (!$dest_exists) {
216
    if (!file_exists('sites/all/modules/' . $subdir)) {
217
      drush_mkdir('sites/all/modules/' . $subdir);
218
    }
219
  }
220

    
221
  // Create destination directory.
222
  drush_mkdir($dest);
223

    
224
  // Load bulk export module.
225
  module_load_include('module', 'bulk_export');
226

    
227
  // Create options and call Bulk export function.
228
  // We create an array, because maybe in the future we can pass in more
229
  // options to the export function (pre-selected modules and/or exportables).
230
  $options = array(
231
    'name' => $module,
232
    'selections' => $selections,
233
  );
234
  $files = bulk_export_export(TRUE, $options);
235

    
236
  $alter = array(
237
    'module' => $module,
238
    'files' => $files,
239
  );
240
  // Let other drush commands alter the files.
241
  drush_command_invoke_all_ref('drush_ctex_files_alter', $alter);
242
  $files = $alter['files'];
243

    
244
  // Start writing.
245
  if (is_array($files)) {
246
    foreach ($files as $base_file => $data) {
247
      $filename = $dest . '/' . $base_file;
248
      // Extra check for .module file.
249
      if ($base_file == ($module . '.module' || $module . '.info') && file_exists($filename)) {
250
        if (!drush_confirm(dt('Do you want to overwrite !module_file', array('!module_file' => $base_file)))) {
251
          drush_log(dt('Writing of !filename skipped. This is the code that was supposed to be written:', array('!filename' => $filename)), 'success');
252
          drush_print('---------');
253
          drush_print(shellColours::getColouredOutput("\n$data", 'light_green'));
254
          drush_print('---------');
255
          continue;
256
        }
257
      }
258
      if (file_put_contents($filename, $data)) {
259
        drush_log(dt('Succesfully written !filename', array('!filename' => $filename)), 'success');
260
      }
261
      else {
262
        drush_log(dt('Error writing !filename', array('!filename' => $filename)), 'error');
263
      }
264
    }
265
  }
266
  else {
267
    drush_log(dt('No files were found to be written.'), 'error');
268
  }
269
}
270

    
271
/**
272
 * Helper function to select the exportables. By default, all exportables
273
 * will be selected, so it will be easier to deselect them.
274
 *
275
 * @param $tables
276
 */
277
function _ctools_drush_selection_screen(array $tables = array()) {
278
  $selections = $build = array();
279
  $files = system_rebuild_module_data();
280

    
281
  $selection_number = 0;
282

    
283
  $info = _ctools_drush_export_info($tables, TRUE);
284
  $exportables = $info['exportables'];
285
  $schemas = $info['schemas'];
286

    
287
  $export_tables = array();
288

    
289
  foreach (array_keys($exportables) as $table) {
290
    natcasesort($exportables[$table]);
291
    $export_tables[$table] = $files[$schemas[$table]['module']]->info['name'] . ' (' . $table . ')';
292
  }
293

    
294
  foreach ($export_tables as $table => $table_title) {
295
    if (!empty($exportables[$table])) {
296
      $table_count = count($exportables[$table]);
297
      $selection_number += $table_count;
298
      foreach ($exportables[$table] as $key => $title) {
299
        $build[$table]['title'] = $table_title;
300
        $build[$table]['items'][$key] = $title;
301
        $build[$table]['count'] = $table_count;
302
        $selections[$table][$key] = $key;
303
      }
304
    }
305
  }
306

    
307
  drush_print(dt('Number of exportables selected: !number', array('!number' => $selection_number)));
308
  drush_print(dt('By default all exportables are selected. Select a table to deselect exportables. Select "cancel" to start writing the files.'));
309

    
310
  // Let's go into a loop.
311
  $return = FALSE;
312
  while (!$return) {
313

    
314
    // Present the tables choice.
315
    $table_rows = array();
316
    foreach ($build as $table => $info) {
317
      $table_rows[$table] = $info['title'] . ' (' . $info['count'] . ')';
318
    }
319
    $table_choice = drush_choice($table_rows, dt('Select a table. Select cancel to start writing files.'));
320

    
321
    // Bail out.
322
    if (!$table_choice) {
323
      drush_log(dt('Selection mode done, starting to write the files.'), 'notice');
324
      $return = TRUE;
325
      return $selections;
326
    }
327

    
328
    // Present the exportables choice, using the drush_choice_multiple.
329
    $max = count($build[$table_choice]['items']);
330
    $exportable_rows = array();
331
    foreach ($build[$table_choice]['items'] as $key => $title) {
332
      $exportable_rows[$key] = $title;
333
    }
334
    drush_print(dt('Exportables from !table', array('!table' => $build[$table_choice]['title'])));
335
    $multi_select = drush_choice_multiple($exportable_rows, $selections[$table_choice], dt('Select exportables.'), '!value', '!value (selected)', 0, $max);
336

    
337
    // Update selections.
338
    if (is_array($multi_select)) {
339
      $build[$table_choice]['count'] = count($multi_select);
340
      $selections[$table_choice] = array();
341
      foreach ($multi_select as $key) {
342
        $selections[$table_choice][$key] = $key;
343
      }
344
    }
345
  }
346
}
347

    
348
/**
349
 * Delete files in a directory, keeping the .module  and .info files.
350
 *
351
 * @param $path
352
 *   Path to directory in which to remove files.
353
 */
354
function _ctools_drush_file_delete($path) {
355
  if (is_dir($path)) {
356
    $files = new DirectoryIterator($path);
357
    foreach ($files as $fileInfo) {
358
      if (!$fileInfo->isDot() && !in_array($fileInfo->getExtension(), array('module', 'info'))) {
359
        unlink($fileInfo->getPathname());
360
      }
361
    }
362
  }
363
}
364

    
365
/**
366
 * Drush callback: Export info.
367
 *
368
 * @params $table_names
369
 *   Each argument will be taken as a CTools exportable table name.
370
 */
371
function ctools_drush_export_info() {
372
  // Collect array of table names from args.
373
  $table_names = func_get_args();
374

    
375
  // Get format option to allow for alternative output.
376
  $format = drush_get_option('format', FALSE);
377
  $tables_only = drush_get_option('tables-only', FALSE);
378
  $filter = drush_get_option('filter', FALSE);
379
  $export_module = drush_get_option('module', FALSE);
380

    
381
  $load = (bool) $filter || $export_module;
382

    
383
  // Get info on these tables, or all tables if none specified.
384
  $info = _ctools_drush_export_info($table_names, $load);
385
  $schemas = $info['schemas'];
386
  $exportables = $info['exportables'];
387

    
388
  if (empty($exportables)) {
389
    drush_log(dt('There are no exportables available.'), 'warning');
390
    return;
391
  }
392

    
393
  // Filter by export module.
394
  if (is_string($export_module)) {
395
    $exportables = _ctools_drush_export_module_filter($exportables, $export_module);
396
  }
397

    
398
  if (empty($exportables)) {
399
    drush_log(dt('There are no exportables matching this criteria.'), 'notice');
400
    return;
401
  }
402

    
403
  $exportable_counts = _ctools_drush_count_exportables($exportables);
404

    
405
  // Only use array keys if --tables-only option is set.
406
  if ($tables_only) {
407
    $exportables = array_keys($exportables);
408
  }
409

    
410
  // Use format from --format option if it's present, and send to drush_format.
411
  if ($format) {
412
    // Create array with all exportable info and counts in one.
413
    $output = array(
414
      'exportables' => $exportables,
415
      'count' => $exportable_counts,
416
    );
417
    drush_print(drush_format($output, NULL, $format));
418
  }
419
  // Build a tabular output as default.
420
  else {
421
    $header = $tables_only ? array() : array(dt('Module'), dt('Base table'), dt('Exportables'));
422
    $rows = array();
423
    foreach ($exportables as $table => $info) {
424
      if (is_array($info)) {
425
        $row = array(
426
          $schemas[$table]['module'],
427
          $table,
428
          // Machine name is better for this?
429
          shellColours::getColouredOutput(implode("\n", array_keys($info)), 'light_green') . "\n",
430
        );
431
        $rows[] = $row;
432
      }
433
      else {
434
        $rows[] = array($info);
435
      }
436
    }
437
    if (!empty($rows)) {
438
      drush_print("\n");
439
      array_unshift($rows, $header);
440
      drush_print_table($rows, TRUE, array(20, 20));
441
      drush_print(dt('Total exportables found: !total', array('!total' => $exportable_counts['total'])));
442
      foreach ($exportable_counts['exportables'] as $table_name => $count) {
443
        drush_print(dt('!table_name (!count)', array('!table_name' => $table_name, '!count' => $count)), 2);
444
      }
445
      drush_print("\n");
446
    }
447
  }
448
}
449

    
450
/**
451
 * Drush callback: Acts as the hub for all op commands to keep
452
 * all arg handling etc in one place.
453
 */
454
function ctools_drush_export_op_command() {
455
  $args = func_get_args();
456
  // Get all info for the current drush command.
457
  $command = drush_get_command();
458
  $op = '';
459

    
460
  switch ($command['command']) {
461
    case 'ctools-export-view':
462
      $op = 'view';
463
      break;
464

    
465
    case 'ctools-export-revert':
466
      // Revert is same as deleting. As any objects in the db are deleted.
467
      $op = 'delete';
468
      break;
469

    
470
    case 'ctools-export-enable':
471
      $op = 'enable';
472
      break;
473

    
474
    case 'ctools-export-disable':
475
      $op = 'disable';
476
      break;
477
  }
478

    
479
  if (!$op) {
480
    return;
481
  }
482

    
483
  if (drush_get_option('all', FALSE)) {
484
    $info = _ctools_drush_export_info(array(), TRUE);
485
    $exportable_info = $info['exportables'];
486

    
487
    $all = drush_confirm(dt('Are you sure you would like to !op all exportables on the system?',
488
      array('!op' => _ctools_drush_export_op_alias($op))));
489

    
490
    if ($all && $exportable_info) {
491
      foreach ($exportable_info as $table => $exportables) {
492
        if (!empty($exportables)) {
493
          ctools_drush_export_op($op, $table, $exportables);
494
        }
495
      }
496
    }
497
  }
498
  else {
499
    // Table name should always be first arg...
500
    $table_name = array_shift($args);
501
    // Any additional args are assumed to be exportable names.
502
    $object_names = $args;
503

    
504
    // Return any exportables based on table name, object names, options.
505
    $exportables = _ctools_drush_export_op_command_logic($op, $table_name, $object_names);
506

    
507
    if ($exportables) {
508
      ctools_drush_export_op($op, $table_name, $exportables);
509
    }
510
  }
511
}
512

    
513
/**
514
 * Iterate through exportable object names, load them, and pass each
515
 * object to the correct op function.
516
 *
517
 * @param $op
518
 * @param $table_name
519
 * @param $exportables
520
 */
521
function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL) {
522
  $objects = ctools_export_crud_load_multiple($table_name, array_keys($exportables));
523

    
524
  $function = '_ctools_drush_export_' . $op;
525
  if (function_exists($function)) {
526
    foreach ($objects as $object) {
527
      $function($table_name, $object);
528
    }
529
  }
530
  else {
531
    drush_log(dt('CTools CRUD function !function doesn\'t exist.',
532
      array('!function' => $function)), 'error');
533
  }
534
}
535

    
536
/**
537
 * Helper function to abstract logic for selecting exportable types/objects
538
 * from individual commands as they will all share this same error
539
 * handling/arguments for returning list of exportables.
540
 *
541
 * @param $table_name
542
 * @param $object_names
543
 *
544
 * @return
545
 *   Array of exportable objects (filtered if necessary, by name etc..) or FALSE if not.
546
 */
547
function _ctools_drush_export_op_command_logic($op = '', $table_name = NULL, array $object_names = array()) {
548
  if (!$table_name) {
549
    drush_log(dt('Exportable table name empty. Use the --all command if you want to perform this operation on all tables.'), 'error');
550
    return FALSE;
551
  }
552

    
553
  // Get export info based on table name.
554
  $info = _ctools_drush_export_info(array($table_name), TRUE);
555

    
556
  if (!isset($info['exportables'][$table_name])) {
557
    drush_log(dt('Exportable table name not found.'), 'error');
558
    return FALSE;
559
  }
560

    
561
  $exportables = &$info['exportables'];
562

    
563
  if (empty($object_names)) {
564
    $all = drush_confirm(dt('No object names entered. Would you like to try and !op all exportables of type !type',
565
      array('!op' => _ctools_drush_export_op_alias($op), '!type' => $table_name)));
566
    if (!$all) {
567
      drush_log(dt('Command cancelled'), 'success');
568
      return FALSE;
569
    }
570
  }
571
  else {
572
    // Iterate through object names and check they exist in exportables array.
573
    // Log error and unset them if they don't.
574
    foreach ($object_names as $object_name) {
575
      if (!isset($exportables[$table_name][$object_name])) {
576
        drush_log(dt('Invalid exportable: !exportable', array('!exportable' => $object_name)), 'error');
577
        unset($object_names[$table_name][$object_name]);
578
      }
579
    }
580
    // Iterate through exportables to get just a list of selected ones.
581
    foreach (array_keys($exportables[$table_name]) as $exportable) {
582
      if (!in_array($exportable, $object_names)) {
583
        unset($exportables[$table_name][$exportable]);
584
      }
585
    }
586
  }
587

    
588
  $export_module = drush_get_option('module', FALSE);
589

    
590
  if (is_string($export_module)) {
591
    $exportables = _ctools_drush_export_module_filter($exportables, $export_module);
592
  }
593

    
594
  return $exportables[$table_name];
595
}
596

    
597
/**
598
 * Return array of CTools exportable info based on available tables returned from
599
 * ctools_export_get_schemas().
600
 *
601
 * @param $table_names
602
 *   Array of table names to return.
603
 * @param $load
604
 *   (bool) should ctools exportable objects be loaded for each type.
605
 *   The default behaviour will load just a list of exportable names.
606
 *
607
 * @return
608
 *   Nested arrays of available exportables, keyed by table name.
609
 */
610
function _ctools_drush_export_info(array $table_names = array(), $load = FALSE) {
611
  ctools_include('export');
612
  // Get available schemas that declare exports.
613
  $schemas = ctools_export_get_schemas(TRUE);
614
  $exportables = array();
615

    
616
  if (!empty($schemas)) {
617
    // Remove types we don't want, if any.
618
    if (!empty($table_names)) {
619
      foreach (array_keys($schemas) as $table_name) {
620
        if (!in_array($table_name, $table_names)) {
621
          unset($schemas[$table_name]);
622
        }
623
      }
624
    }
625
    // Load array of available exportables for each schema.
626
    foreach ($schemas as $table_name => $schema) {
627
      // Load all objects.
628
      if ($load) {
629
        $exportables[$table_name] = ctools_export_crud_load_all($table_name);
630
      }
631
      // Get a list of exportable names.
632
      else {
633
        if (!empty($schema['export']['list callback']) && function_exists($schema['export']['list callback'])) {
634
          $exportables[$table_name] = $schema['export']['list callback']();
635
        }
636
        else {
637
          $exportables[$table_name] = ctools_export_default_list($table_name, $schema);
638
        }
639
      }
640
    }
641
  }
642

    
643
  if ($load) {
644
    $filter = drush_get_option('filter', FALSE);
645
    $exportables = _ctools_drush_filter_exportables($exportables, $filter);
646
  }
647

    
648
  return array('exportables' => $exportables, 'schemas' => $schemas);
649
}
650

    
651
/**
652
 * View a single object.
653
 *
654
 * @param $table_name
655
 * @param $object
656
 */
657
function _ctools_drush_export_view($table_name, $object) {
658
  $indent = drush_get_option('indent', '');
659
  $no_colour = drush_get_option('no-colour', FALSE);
660
  $export = ctools_export_crud_export($table_name, $object, $indent);
661
  if ($no_colour) {
662
    drush_print("\n$export");
663
  }
664
  else {
665
    drush_print(shellColours::getColouredOutput("\n$export", 'light_green'));
666
  }
667
}
668

    
669
/**
670
 * Revert a single object.
671
 *
672
 * @param $table_name
673
 * @param $object
674
 */
675
function _ctools_drush_export_delete($table_name, $object) {
676
  $name = _ctools_drush_get_export_name($table_name, $object);
677

    
678
  if (_ctools_drush_object_is_overridden($object)) {
679
    // Remove from db.
680
    ctools_export_crud_delete($table_name, $object);
681
    drush_log("Reverted object: $name", 'success');
682
  }
683
  else {
684
    drush_log("Nothing to revert for: $name", 'notice');
685
  }
686
}
687

    
688
/**
689
 * Enable a single object.
690
 *
691
 * @param $table_name
692
 * @param $object
693
 */
694
function _ctools_drush_export_enable($table_name, $object) {
695
  $name = _ctools_drush_get_export_name($table_name, $object);
696

    
697
  if (_ctools_drush_object_is_disabled($object)) {
698

    
699
    // Enable object.
700
    ctools_export_crud_enable($table_name, $object);
701
    drush_log("Enabled object: $name", 'success');
702
  }
703
  else {
704
    drush_log("$name is already Enabled", 'notice');
705
  }
706
}
707

    
708
/**
709
 * Disable a single object.
710
 *
711
 * @param $table_name
712
 * @param $object
713
 */
714
function _ctools_drush_export_disable($table_name, $object) {
715
  $name = _ctools_drush_get_export_name($table_name, $object);
716

    
717
  if (!_ctools_drush_object_is_disabled($object)) {
718
    // Disable object.
719
    ctools_export_crud_disable($table_name, $object);
720
    drush_log("Disabled object: $name", 'success');
721
  }
722
  else {
723
    drush_log("$name is already disabled", 'notice');
724
  }
725
}
726

    
727
/**
728
 * Filter a nested array of exportables by export module.
729
 *
730
 * @param array $exportables
731
 *   Passed by reference. A nested array of exportables, keyed by table name.
732
 * @param string $export_module
733
 *   The name of the export module providing the exportable.
734
 */
735
function _ctools_drush_export_module_filter($exportables, $export_module) {
736
  $module_list = module_list();
737

    
738
  if (!isset($module_list[$export_module])) {
739
    drush_log(dt('Invalid export module: !export_module', array('!export_module' => $export_module)), 'error');
740
  }
741

    
742
  foreach ($exportables as $table => $objects) {
743
    foreach ($objects as $key => $object) {
744
      if (empty($object->export_module) || ($object->export_module !== $export_module)) {
745
        unset($exportables[$table][$key]);
746
      }
747
    }
748
  }
749

    
750
  return array_filter($exportables);
751
}
752

    
753
/**
754
 * Gets the key for an exportable type.
755
 *
756
 * @param $table_name
757
 *   The exportable table name.
758
 * @param $object
759
 *   The exportable object.
760
 *
761
 * @return string
762
 *   The key defined in the export schema data.
763
 */
764
function _ctools_drush_get_export_name($table_name, $object) {
765
  $info = _ctools_drush_export_info(array($table_name));
766
  $key = $info['schemas'][$table_name]['export']['key'];
767
  return $object->{$key};
768
}
769

    
770
/**
771
 * Determine if an object is disabled.
772
 *
773
 * @param $object
774
 *   Loaded CTools exportable object.
775
 *
776
 * @return TRUE or FALSE
777
 */
778
function _ctools_drush_object_is_disabled($object) {
779
  return (isset($object->disabled) && ($object->disabled == TRUE)) ? TRUE : FALSE;
780
}
781

    
782
/**
783
 * Determine if an object is enabled.
784
 *
785
 * @see _ctools_drush_object_is_disabled()
786
 */
787
function _ctools_drush_object_is_enabled($object) {
788
  return (empty($object->disabled)) ? TRUE : FALSE;
789
}
790

    
791
/**
792
 * Determine if an object is overridden.
793
 */
794
function _ctools_drush_object_is_overridden($object) {
795
  $status = EXPORT_IN_CODE + EXPORT_IN_DATABASE;
796
  return ($object->export_type == $status) ? TRUE : FALSE;
797
}
798

    
799
/**
800
 * Determine if an object is not overridden.
801
 */
802
function _ctools_drush_object_is_not_overridden($object) {
803
  $status = EXPORT_IN_CODE + EXPORT_IN_DATABASE;
804
  return ($object->export_type == $status) ? FALSE : TRUE;
805
}
806

    
807
/**
808
 * Determine if an object is only in the db.
809
 */
810
function _ctools_drush_object_is_db_only($object) {
811
  return ($object->export_type == EXPORT_IN_DATABASE) ? TRUE : FALSE;
812
}
813

    
814
/**
815
 * Determine if an object is not in the db.
816
 */
817
function _ctools_drush_object_is_not_db_only($object) {
818
  return ($object->export_type == EXPORT_IN_DATABASE) ? FALSE : TRUE;
819
}
820

    
821
/**
822
 * Determine if an object is a code only default.
823
 */
824
function _ctools_drush_object_is_code_only($object) {
825
  return ($object->export_type == EXPORT_IN_CODE) ? TRUE : FALSE;
826
}
827

    
828
/**
829
 * Determine if an object is not a code only default.
830
 */
831
function _ctools_drush_object_is_not_code_only($object) {
832
  return ($object->export_type == EXPORT_IN_CODE) ? FALSE : TRUE;
833
}
834

    
835
/**
836
 * Return an array of count information based on exportables array.
837
 *
838
 * @param $exportables
839
 *   Array of exportables to count.
840
 *
841
 * @return
842
 *   Array of count data containing the following:
843
 *     'total' - A total count of all exportables.
844
 *     'exportables' - An array of exportable counts per table.
845
 */
846
function _ctools_drush_count_exportables($exportables) {
847
  $count = array('exportables' => array());
848

    
849
  foreach ($exportables as $table => $objects) {
850
    // Add the object count for each table.
851
    $count['exportables'][$table] = count($objects);
852
  }
853

    
854
  // Once all tables have been counted, total these up.
855
  $count['total'] = array_sum($count['exportables']);
856

    
857
  return $count;
858
}
859

    
860
/**
861
 * Filters a collection of exportables based on filters.
862
 *
863
 * @param $exportables
864
 * @param $filter
865
 */
866
function _ctools_drush_filter_exportables($exportables, $filter) {
867
  $eval = FALSE;
868

    
869
  if (is_string($filter)) {
870
    switch ($filter) {
871
      // Show enabled exportables only.
872
      case 'enabled':
873
        $eval = '_ctools_drush_object_is_disabled';
874
        break;
875

    
876
      // Show disabled exportables only.
877
      case 'disabled':
878
        $eval = '_ctools_drush_object_is_enabled';
879
        break;
880

    
881
      // Show overridden exportables only.
882
      case 'overridden':
883
        $eval = '_ctools_drush_object_is_not_overridden';
884
        break;
885

    
886
      // Show database only exportables.
887
      case 'database':
888
        $eval = '_ctools_drush_object_is_not_db_only';
889
        break;
890

    
891
      // Show code only exportables.
892
      case 'code':
893
        $eval = '_ctools_drush_object_is_not_code_only';
894
        break;
895

    
896
      // Do nothing.
897
      case 'all':
898
        break;
899

    
900
      default:
901
        drush_log(dt('Invalid filter option. Available options are: enabled, disabled, overridden, database, and code.'), 'error');
902
        return;
903
    }
904

    
905
    if ($eval) {
906
      foreach ($exportables as $table => $objects) {
907
        foreach ($objects as $key => $object) {
908
          if ($eval($object)) {
909
            unset($exportables[$table][$key]);
910
          }
911
        }
912
      }
913
    }
914
  }
915

    
916
  return array_filter($exportables);
917
}
918

    
919
/**
920
 * Return an alias for an op, that will be used to show as output.
921
 * For now, this is mainly necessary for delete => revert alias.
922
 *
923
 * @param $op
924
 *   The op name. Such as 'enable', 'disable', or 'delete'.
925
 *
926
 * @return
927
 *   The matched alias value or the original $op passed in if not found.
928
 */
929
function _ctools_drush_export_op_alias($op) {
930
  $aliases = array(
931
    'delete' => 'revert',
932
  );
933

    
934
  if (isset($aliases[$op])) {
935
    return $aliases[$op];
936
  }
937

    
938
  return $op;
939
}
940

    
941
/**
942
 * Convert the drush options from a csv list into an array.
943
 *
944
 * @param $drush_option
945
 *   The drush option name to invoke.
946
 *
947
 * @return
948
 *   Exploded array of options.
949
 */
950
function _ctools_drush_explode_options($drush_option) {
951
  $options = drush_get_option($drush_option, array());
952
  if (!empty($options)) {
953
    $options = explode(',', $options);
954
    return array_map('trim', $options);
955
  }
956

    
957
  return $options;
958
}
959

    
960
/**
961
 * Class to deal with wrapping output strings with
962
 * colour formatting for the shell.
963
 */
964
class shellColours {
965

    
966
  private static $foreground_colours = array(
967
    'black' => '0;30',
968
    'dark_gray' => '1;30',
969
    'blue' => '0;34',
970
    'light_blue' => '1;34',
971
    'green' => '0;32',
972
    'light_green' => '1;32',
973
    'cyan' => '0;36',
974
    'light_cyan' => '1;36',
975
    'red' => '0;31',
976
    'light_red' => '1;31',
977
    'purple' => '0;35',
978
    'light_purple' => '1;35',
979
    'brown' => '0;33',
980
    'yellow' => '1;33',
981
    'light_gray' => '0;37',
982
    'white' => '1;37',
983
  );
984

    
985
  private static $background_colours = array(
986
    'black' => '40',
987
    'red' => '41',
988
    'green' => '42',
989
    'yellow' => '43',
990
    'blue' => '44',
991
    'magenta' => '45',
992
    'cyan' => '46',
993
    'light_gray' => '47',
994
  );
995

    
996
  /**
997
   * shellColours constructor.
998
   */
999
  private function __construct() {}
1000

    
1001
  /**
1002
   * Returns coloured string.
1003
   */
1004
  public static function getColouredOutput($string, $foreground_colour = NULL, $background_colour = NULL) {
1005
    $coloured_string = "";
1006

    
1007
    // Check if given foreground colour found.
1008
    if ($foreground_colour) {
1009
      $coloured_string .= "\033[" . self::$foreground_colours[$foreground_colour] . "m";
1010
    }
1011
    // Check if given background colour found.
1012
    if ($background_colour) {
1013
      $coloured_string .= "\033[" . self::$background_colours[$background_colour] . "m";
1014
    }
1015

    
1016
    // Add string and end colouring.
1017
    $coloured_string .= $string . "\033[0m";
1018

    
1019
    return $coloured_string;
1020
  }
1021

    
1022
  /**
1023
   * Returns all foreground colour names.
1024
   */
1025
  public static function getForegroundColours() {
1026
    return array_keys(self::$foreground_colours);
1027
  }
1028

    
1029
  /**
1030
   * Returns all background colour names.
1031
   */
1032
  public static function getBackgroundColours() {
1033
    return array_keys(self::$background_colours);
1034
  }
1035

    
1036
} // shellColours