Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ctools / drush / ctools.drush.inc @ 1e39edcb

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
    case 'meta:entity:summary':
144
      return dt('CTools drush commands.');
145
  }
146
}
147

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

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

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

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

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

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

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

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

    
193
  // Check if folder exists.
194
  if (file_exists($dest)) {
195
    $dest_exists = TRUE;
196
    if ($remove) {
197
      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)))) {
198
        $remove = TRUE;
199
        drush_log(dt('Files will be removed'), 'success');
200
      }
201
      else {
202
        drush_log(dt('Export aborted.'), 'success');
203
        return;
204
      }
205
    }
206
  }
207

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

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

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

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

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

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

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

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

    
280
  $selection_number = 0;
281

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

    
286
  $export_tables = array();
287

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
402
  $exportable_counts = _ctools_drush_count_exportables($exportables);
403

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

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

    
457
  switch ($command['command']) {
458
    case 'ctools-export-view':
459
      $op = 'view';
460
    break;
461
    case 'ctools-export-revert':
462
      // Revert is same as deleting. As any objects in the db are deleted.
463
      $op = 'delete';
464
    break;
465
    case 'ctools-export-enable':
466
      $op = 'enable';
467
    break;
468
    case 'ctools-export-disable':
469
      $op = 'disable';
470
    break;
471
  }
472

    
473
  if (!$op) {
474
    return;
475
  }
476

    
477
  if (drush_get_option('all', FALSE)) {
478
    $info = _ctools_drush_export_info('', TRUE);
479
    $exportable_info = $info['exportables'];
480

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

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

    
499
    // Return any exportables based on table name, object names, options.
500
    $exportables = _ctools_drush_export_op_command_logic($op, $table_name, $object_names);
501

    
502
    if ($exportables) {
503
      ctools_drush_export_op($op, $table_name, $exportables);
504
    }
505
  }
506
}
507

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

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

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

    
549
  // Get export info based on table name.
550
  $info = _ctools_drush_export_info(array($table_name), TRUE);
551

    
552
  if (!isset($info['exportables'][$table_name])) {
553
    drush_log(dt('Exportable table name not found.'), 'error');
554
    return FALSE;
555
  }
556

    
557
  $exportables = &$info['exportables'];
558

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

    
584
  $export_module = drush_get_option('module', FALSE);
585

    
586
  if (is_string($export_module)) {
587
    $exportables = _ctools_drush_export_module_filter($exportables, $export_module);
588
  }
589

    
590
  return $exportables[$table_name];
591
}
592

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

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

    
639
  if ($load) {
640
    $filter = drush_get_option('filter', FALSE);
641
    $exportables = _ctools_drush_filter_exportables($exportables, $filter);
642
  }
643

    
644
  return array('exportables' => $exportables, 'schemas' => $schemas);
645
}
646

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

    
665
/*
666
 * Revert a single object.
667
 *
668
 * @param $table_name
669
 * @param $object
670
 */
671
function _ctools_drush_export_delete($table_name, $object) {
672
  $name = _ctools_drush_get_export_name($table_name, $object);
673

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

    
684
/*
685
 * Enable a single object.
686
 *
687
 * @param $table_name
688
 * @param $object
689
 */
690
function _ctools_drush_export_enable($table_name, $object) {
691
  $name = _ctools_drush_get_export_name($table_name, $object);
692

    
693
  if (_ctools_drush_object_is_disabled($object)) {
694

    
695
    // Enable object.
696
    ctools_export_crud_enable($table_name, $object);
697
    drush_log("Enabled object: $name", 'success');
698
  }
699
  else {
700
    drush_log("$name is already Enabled", 'notice');
701
  }
702
}
703

    
704
/*
705
 * Disable a single object.
706
 *
707
 * @param $table_name
708
 * @param $object
709
 */
710
function _ctools_drush_export_disable($table_name, $object) {
711
  $name = _ctools_drush_get_export_name($table_name, $object);
712

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

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

    
734
  if (!isset($module_list[$export_module])) {
735
    drush_log(dt('Invalid export module: !export_module', array('!export_module' => $export_module)), 'error');
736
  }
737

    
738
  foreach ($exportables as $table => $objects) {
739
    foreach ($objects as $key => $object) {
740
      if (empty($object->export_module) || ($object->export_module !== $export_module)) {
741
        unset($exportables[$table][$key]);
742
      }
743
    }
744
  }
745

    
746
  return array_filter($exportables);
747
}
748

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

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

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

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

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

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

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

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

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

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

    
845
  foreach ($exportables as $table => $objects) {
846
    // Add the object count for each table.
847
    $count['exportables'][$table] = count($objects);
848
  }
849

    
850
  // Once all tables have been counted, total these up.
851
  $count['total'] = array_sum($count['exportables']);
852

    
853
  return $count;
854
}
855

    
856
/**
857
 * Filters a collection of exportables based on filters.
858
 *
859
 * @param $exportables
860
 * @param $filter
861
 */
862
function _ctools_drush_filter_exportables($exportables, $filter) {
863
  $eval = FALSE;
864

    
865
  if (is_string($filter)) {
866
    switch ($filter) {
867
      // Show enabled exportables only.
868
      case 'enabled':
869
        $eval = '_ctools_drush_object_is_disabled';
870
      break;
871
      // Show disabled exportables only.
872
      case 'disabled':
873
        $eval = '_ctools_drush_object_is_enabled';
874
      break;
875
      // Show overridden exportables only.
876
      case 'overridden':
877
        $eval = '_ctools_drush_object_is_not_overridden';
878
      break;
879
      // Show database only exportables.
880
      case 'database':
881
        $eval = '_ctools_drush_object_is_not_db_only';
882
      break;
883
      // Show code only exportables.
884
      case 'code':
885
        $eval = '_ctools_drush_object_is_not_code_only';
886
      break;
887
      // Do nothing.
888
      case 'all':
889
        break;
890
      default:
891
        drush_log(dt('Invalid filter option. Available options are: enabled, disabled, overridden, database, and code.'), 'error');
892
        return;
893
    }
894

    
895
    if ($eval) {
896
      foreach ($exportables as $table => $objects) {
897
        foreach ($objects as $key => $object) {
898
          if ($eval($object)) {
899
            unset($exportables[$table][$key]);
900
          }
901
        }
902
      }
903
    }
904
  }
905

    
906
  return array_filter($exportables);
907
}
908

    
909
/**
910
 * Return an alias for an op, that will be used to show as output.
911
 * For now, this is mainly necessary for delete => revert alias.
912
 *
913
 * @param $op
914
 *   The op name. Such as 'enable', 'disable', or 'delete'.
915
 *
916
 * @return
917
 *   The matched alias value or the original $op passed in if not found.
918
 */
919
function _ctools_drush_export_op_alias($op) {
920
  $aliases = array(
921
    'delete' => 'revert',
922
  );
923

    
924
  if (isset($aliases[$op])) {
925
    return $aliases[$op];
926
  }
927

    
928
  return $op;
929
}
930

    
931
/**
932
 * Convert the drush options from a csv list into an array.
933
 *
934
 * @param $drush_option
935
 *   The drush option name to invoke.
936
 *
937
 * @return
938
 *   Exploded array of options.
939
 */
940
function _ctools_drush_explode_options($drush_option) {
941
  $options = drush_get_option($drush_option, array());
942
  if (!empty($options)) {
943
    $options = explode(',', $options);
944
    return array_map('trim', $options);
945
  }
946

    
947
  return $options;
948
}
949

    
950
/**
951
 * Class to deal with wrapping output strings with
952
 * colour formatting for the shell.
953
 */
954
class shellColours {
955

    
956
  private static $foreground_colours = array(
957
    'black' => '0;30',
958
    'dark_gray' => '1;30',
959
    'blue' => '0;34',
960
    'light_blue' => '1;34',
961
    'green' => '0;32',
962
    'light_green' => '1;32',
963
    'cyan' => '0;36',
964
    'light_cyan' => '1;36',
965
    'red' => '0;31',
966
    'light_red' => '1;31',
967
    'purple' => '0;35',
968
    'light_purple' => '1;35',
969
    'brown' => '0;33',
970
    'yellow' => '1;33',
971
    'light_gray' => '0;37',
972
    'white' => '1;37',
973
  );
974

    
975
  private static $background_colours = array(
976
    'black' => '40',
977
    'red' => '41',
978
    'green' => '42',
979
    'yellow' => '43',
980
    'blue' => '44',
981
    'magenta' => '45',
982
    'cyan' => '46',
983
    'light_gray' => '47',
984
  );
985

    
986
  private function __construct() {}
987

    
988
  // Returns coloured string
989
  public static function getColouredOutput($string, $foreground_colour = NULL, $background_colour = NULL) {
990
    $coloured_string = "";
991

    
992
    // Check if given foreground colour found
993
    if ($foreground_colour) {
994
      $coloured_string .= "\033[" . self::$foreground_colours[$foreground_colour] . "m";
995
    }
996
    // Check if given background colour found
997
    if ($background_colour) {
998
      $coloured_string .= "\033[" . self::$background_colours[$background_colour] . "m";
999
    }
1000

    
1001
    // Add string and end colouring
1002
    $coloured_string .=  $string . "\033[0m";
1003

    
1004
    return $coloured_string;
1005
  }
1006

    
1007
  // Returns all foreground colour names
1008
  public static function getForegroundColours() {
1009
    return array_keys(self::$foreground_colours);
1010
  }
1011

    
1012
  // Returns all background colour names
1013
  public static function getBackgroundColours() {
1014
    return array_keys(self::$background_colours);
1015
  }
1016

    
1017
} // shellColours