View source
<?php
function ctools_drush_command() {
$items = array();
$module_text = 'Filter the list of exportables by module. This will come from the \'export_module\' key on the exportable.';
$all_text = 'Perform this operation all CTools exportables available on the system (all tables).';
$items['ctools-export'] = array(
'aliases' => array(
'ctex',
),
'callback' => 'ctools_drush_export',
'description' => 'Export multiple CTools exportable objects directly to code.',
'arguments' => array(
'module' => 'Name of your module.',
),
'options' => array(
'subdir' => 'The name of the sub directory to create the module in. Defaults to ctools_export which will be placed into sites/all/modules.',
'remove' => 'Remove existing files before writing, except the .module file.',
'filter' => 'Filter the list of exportables by status. Available options are enabled, disabled, overridden, database, code and all. Defaults to enabled.',
'tables' => 'Comma separated list of exportable table names to filter by.',
),
'examples' => array(
'drush ctex export_module' => 'Export CTools exportables to a module called "export_module".',
'drush ctex export_module --subdir=exports' => 'Same as above, but into the sites/all/modules/exports directory.',
'drush ctex export_module --subdir=exports --remove' => 'Same as above, but automatically removing all files, except for the .module file.',
'drush ctex --filter="views_view"' => 'Filter export selection to the views_view table only.',
),
);
$items['ctools-export-info'] = array(
'aliases' => array(
'ctei',
),
'callback' => 'ctools_drush_export_info',
'description' => 'Show available CTools exportable objects.',
'arguments' => array(),
'options' => array(
'format' => 'Display exportables info in a different format such as print_r, json, export. The default is to show in a tabular format.',
'tables-only' => 'Only show list of exportable types/table names and not available objects.',
'filter' => 'Filter the list of exportables by status. Available options are enabled, disabled, overridden, database, and code.',
'module' => $module_text,
),
'examples' => array(
'drush ctools-export-info' => 'View export info on all exportables.',
'drush ctools-export-info views_view variable' => 'View export info for views_view and variable exportable types only.',
'drush ctei --filter=enabled' => 'Show all enabled exportables.',
'drush ctei views_view --filter=disabled' => 'Show all enabled exportables.',
'drush ctei views_view --module=node' => 'Show all exportables provided by/on behalf of the node module.',
),
);
$items['ctools-export-view'] = array(
'aliases' => array(
'ctev',
),
'callback' => 'ctools_drush_export_op_command',
'description' => 'View CTools exportable object code output.',
'arguments' => array(
'table name' => 'Base table of the exportable you want to view.',
'machine names' => 'Space separated list of exportables you want to view.',
),
'options' => array(
'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
'module' => $module_text,
'all' => $all_text,
),
'examples' => array(
'drush ctools-export-view views_view' => 'View all views exportable objects.',
'drush ctools-export-view views_view archive' => 'View default views archive view.',
),
);
$items['ctools-export-revert'] = array(
'aliases' => array(
'cter',
),
'callback' => 'ctools_drush_export_op_command',
'description' => 'Revert CTools exportables from changes overridden in the database.',
'arguments' => array(
'table name' => 'Base table of the exportable you want to revert.',
'machine names' => 'Space separated list of exportables you want to revert.',
),
'options' => array(
'module' => $module_text,
'all' => $all_text,
),
'examples' => array(
'drush ctools-export-revert views_view' => 'Revert all overridden views exportable objects.',
'drush ctools-export-revert views_view archive' => 'Revert overridden default views archive view.',
'drush ctools-export-revert --all' => 'Revert all exportables on the system.',
),
);
$items['ctools-export-enable'] = array(
'aliases' => array(
'ctee',
),
'callback' => 'ctools_drush_export_op_command',
'description' => 'Enable CTools exportables.',
'arguments' => array(
'table name' => 'Base table of the exportable you want to enable.',
'machine names' => 'Space separated list of exportables you want to enable.',
),
'options' => array(
'module' => $module_text,
'all' => $all_text,
),
'examples' => array(
'drush ctools-export-enable views_view' => 'Enable all overridden views exportable objects.',
'drush ctools-export-enable views_view archive' => 'Enable overridden default views archive view.',
),
);
$items['ctools-export-disable'] = array(
'aliases' => array(
'cted',
),
'callback' => 'ctools_drush_export_op_command',
'description' => 'Disable CTools exportables.',
'arguments' => array(
'table name' => 'Base table of the exportable you want to disable.',
'machine names' => 'Space separated list of exportables you want to disable.',
),
'options' => array(
'module' => $module_text,
'all' => $all_text,
),
'examples' => array(
'drush ctools-export-disable views_view' => 'Disable all overridden views exportable objects.',
'drush ctools-export-disable views_view archive' => 'Disable overridden default views archive view.',
),
);
return $items;
}
function ctools_drush_help($section) {
switch ($section) {
case 'meta:ctools:title':
return dt('CTools commands');
case 'meta:entity:summary':
return dt('CTools drush commands.');
}
}
function ctools_drush_export($module = 'foo') {
$error = FALSE;
if (preg_match('@[^a-z_]+@', $module)) {
$error = dt('The name of the module must contain only lowercase letters and underscores') . '.';
drush_log($error, 'error');
return;
}
$tables = _ctools_drush_explode_options('tables');
$filter = drush_get_option('filter', FALSE);
if (empty($filter)) {
drush_set_option('filter', 'enabled');
}
$options = array(
'all' => dt('Export everything'),
'select' => dt('Make selection'),
);
$selection = drush_choice($options, dt('Select to proceed'));
if (!$selection) {
return;
}
if ($selection == 'select') {
$selections = _ctools_drush_selection_screen($tables);
}
else {
$info = _ctools_drush_export_info($tables, TRUE);
$selections = $info['exportables'];
}
$dest_exists = FALSE;
$subdir = drush_get_option('subdir', 'ctools_export');
$dest = 'sites/all/modules/' . $subdir . '/' . $module;
$remove = drush_get_option('remove', FALSE);
if (file_exists($dest)) {
$dest_exists = TRUE;
if ($remove) {
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,
)))) {
$remove = TRUE;
drush_log(dt('Files will be removed'), 'success');
}
else {
drush_log(dt('Export aborted.'), 'success');
return;
}
}
}
if ($remove && $dest_exists) {
_ctools_drush_file_delete($dest);
}
if (!$dest_exists) {
if (!file_exists('sites/all/modules/' . $subdir)) {
drush_mkdir('sites/all/modules/' . $subdir);
}
}
drush_mkdir($dest);
module_load_include('module', 'bulk_export');
$options = array(
'name' => $module,
'selections' => $selections,
);
$files = bulk_export_export(TRUE, $options);
$alter = array(
'module' => $module,
'files' => $files,
);
drush_command_invoke_all_ref('drush_ctex_files_alter', $alter);
$files = $alter['files'];
if (is_array($files)) {
foreach ($files as $base_file => $data) {
$filename = $dest . '/' . $base_file;
if ($base_file == ($module . '.module' || $module . '.info') && file_exists($filename)) {
if (!drush_confirm(dt('Do you want to overwrite !module_file', array(
'!module_file' => $base_file,
)))) {
drush_log(dt('Writing of !filename skipped. This is the code that was supposed to be written:', array(
'!filename' => $filename,
)), 'success');
drush_print('---------');
drush_print(shellColours::getColouredOutput("\n{$data}", 'light_green'));
drush_print('---------');
continue;
}
}
if (file_put_contents($filename, $data)) {
drush_log(dt('Succesfully written !filename', array(
'!filename' => $filename,
)), 'success');
}
else {
drush_log(dt('Error writing !filename', array(
'!filename' => $filename,
)), 'error');
}
}
}
else {
drush_log(dt('No files were found to be written.'), 'error');
}
}
function _ctools_drush_selection_screen(array $tables = array()) {
$selections = $build = array();
$files = system_rebuild_module_data();
$selection_number = 0;
$info = _ctools_drush_export_info($tables, TRUE);
$exportables = $info['exportables'];
$schemas = $info['schemas'];
$export_tables = array();
foreach (array_keys($exportables) as $table) {
natcasesort($exportables[$table]);
$export_tables[$table] = $files[$schemas[$table]['module']]->info['name'] . ' (' . $table . ')';
}
foreach ($export_tables as $table => $table_title) {
if (!empty($exportables[$table])) {
$table_count = count($exportables[$table]);
$selection_number += $table_count;
foreach ($exportables[$table] as $key => $title) {
$build[$table]['title'] = $table_title;
$build[$table]['items'][$key] = $title;
$build[$table]['count'] = $table_count;
$selections[$table][$key] = $key;
}
}
}
drush_print(dt('Number of exportables selected: !number', array(
'!number' => $selection_number,
)));
drush_print(dt('By default all exportables are selected. Select a table to deselect exportables. Select "cancel" to start writing the files.'));
$return = FALSE;
while (!$return) {
$table_rows = array();
foreach ($build as $table => $info) {
$table_rows[$table] = $info['title'] . ' (' . $info['count'] . ')';
}
$table_choice = drush_choice($table_rows, dt('Select a table. Select cancel to start writing files.'));
if (!$table_choice) {
drush_log(dt('Selection mode done, starting to write the files.'), 'notice');
$return = TRUE;
return $selections;
}
$max = count($build[$table_choice]['items']);
$exportable_rows = array();
foreach ($build[$table_choice]['items'] as $key => $title) {
$exportable_rows[$key] = $title;
}
drush_print(dt('Exportables from !table', array(
'!table' => $build[$table_choice]['title'],
)));
$multi_select = drush_choice_multiple($exportable_rows, $selections[$table_choice], dt('Select exportables.'), '!value', '!value (selected)', 0, $max);
if (is_array($multi_select)) {
$build[$table_choice]['count'] = count($multi_select);
$selections[$table_choice] = array();
foreach ($multi_select as $key) {
$selections[$table_choice][$key] = $key;
}
}
}
}
function _ctools_drush_file_delete($path) {
if (is_dir($path)) {
$files = new DirectoryIterator($path);
foreach ($files as $fileInfo) {
if (!$fileInfo
->isDot() && !in_array($fileInfo
->getExtension(), array(
'module',
'info',
))) {
unlink($fileInfo
->getPathname());
}
}
}
}
function ctools_drush_export_info() {
$table_names = func_get_args();
$format = drush_get_option('format', FALSE);
$tables_only = drush_get_option('tables-only', FALSE);
$filter = drush_get_option('filter', FALSE);
$export_module = drush_get_option('module', FALSE);
$load = (bool) $filter || $export_module;
$info = _ctools_drush_export_info($table_names, $load);
$schemas = $info['schemas'];
$exportables = $info['exportables'];
if (empty($exportables)) {
drush_log(dt('There are no exportables available.'), 'warning');
return;
}
if (is_string($export_module)) {
$exportables = _ctools_drush_export_module_filter($exportables, $export_module);
}
if (empty($exportables)) {
drush_log(dt('There are no exportables matching this criteria.'), 'notice');
return;
}
$exportable_counts = _ctools_drush_count_exportables($exportables);
if ($tables_only) {
$exportables = array_keys($exportables);
}
if ($format) {
$output = array(
'exportables' => $exportables,
'count' => $exportable_counts,
);
drush_print(drush_format($output, NULL, $format));
}
else {
$header = $tables_only ? array() : array(
dt('Module'),
dt('Base table'),
dt('Exportables'),
);
$rows = array();
foreach ($exportables as $table => $info) {
if (is_array($info)) {
$row = array(
$schemas[$table]['module'],
$table,
shellColours::getColouredOutput(implode("\n", array_keys($info)), 'light_green') . "\n",
);
$rows[] = $row;
}
else {
$rows[] = array(
$info,
);
}
}
if (!empty($rows)) {
drush_print("\n");
array_unshift($rows, $header);
drush_print_table($rows, TRUE, array(
20,
20,
));
drush_print(dt('Total exportables found: !total', array(
'!total' => $exportable_counts['total'],
)));
foreach ($exportable_counts['exportables'] as $table_name => $count) {
drush_print(dt('!table_name (!count)', array(
'!table_name' => $table_name,
'!count' => $count,
)), 2);
}
drush_print("\n");
}
}
}
function ctools_drush_export_op_command() {
$args = func_get_args();
$command = drush_get_command();
$op = '';
switch ($command['command']) {
case 'ctools-export-view':
$op = 'view';
break;
case 'ctools-export-revert':
$op = 'delete';
break;
case 'ctools-export-enable':
$op = 'enable';
break;
case 'ctools-export-disable':
$op = 'disable';
break;
}
if (!$op) {
return;
}
if (drush_get_option('all', FALSE)) {
$info = _ctools_drush_export_info(array(), TRUE);
$exportable_info = $info['exportables'];
$all = drush_confirm(dt('Are you sure you would like to !op all exportables on the system?', array(
'!op' => _ctools_drush_export_op_alias($op),
)));
if ($all && $exportable_info) {
foreach ($exportable_info as $table => $exportables) {
if (!empty($exportables)) {
ctools_drush_export_op($op, $table, $exportables);
}
}
}
}
else {
$table_name = array_shift($args);
$object_names = $args;
$exportables = _ctools_drush_export_op_command_logic($op, $table_name, $object_names);
if ($exportables) {
ctools_drush_export_op($op, $table_name, $exportables);
}
}
}
function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL) {
$objects = ctools_export_crud_load_multiple($table_name, array_keys($exportables));
$function = '_ctools_drush_export_' . $op;
if (function_exists($function)) {
foreach ($objects as $object) {
$function($table_name, $object);
}
}
else {
drush_log(dt('CTools CRUD function !function doesn\'t exist.', array(
'!function' => $function,
)), 'error');
}
}
function _ctools_drush_export_op_command_logic($op = '', $table_name = NULL, array $object_names = array()) {
if (!$table_name) {
drush_log(dt('Exportable table name empty. Use the --all command if you want to perform this operation on all tables.'), 'error');
return FALSE;
}
$info = _ctools_drush_export_info(array(
$table_name,
), TRUE);
if (!isset($info['exportables'][$table_name])) {
drush_log(dt('Exportable table name not found.'), 'error');
return FALSE;
}
$exportables =& $info['exportables'];
if (empty($object_names)) {
$all = drush_confirm(dt('No object names entered. Would you like to try and !op all exportables of type !type', array(
'!op' => _ctools_drush_export_op_alias($op),
'!type' => $table_name,
)));
if (!$all) {
drush_log(dt('Command cancelled'), 'success');
return FALSE;
}
}
else {
foreach ($object_names as $object_name) {
if (!isset($exportables[$table_name][$object_name])) {
drush_log(dt('Invalid exportable: !exportable', array(
'!exportable' => $object_name,
)), 'error');
unset($object_names[$table_name][$object_name]);
}
}
foreach (array_keys($exportables[$table_name]) as $exportable) {
if (!in_array($exportable, $object_names)) {
unset($exportables[$table_name][$exportable]);
}
}
}
$export_module = drush_get_option('module', FALSE);
if (is_string($export_module)) {
$exportables = _ctools_drush_export_module_filter($exportables, $export_module);
}
return $exportables[$table_name];
}
function _ctools_drush_export_info(array $table_names = array(), $load = FALSE) {
ctools_include('export');
$schemas = ctools_export_get_schemas(TRUE);
$exportables = array();
if (!empty($schemas)) {
if (!empty($table_names)) {
foreach (array_keys($schemas) as $table_name) {
if (!in_array($table_name, $table_names)) {
unset($schemas[$table_name]);
}
}
}
foreach ($schemas as $table_name => $schema) {
if ($load) {
$exportables[$table_name] = ctools_export_crud_load_all($table_name);
}
else {
if (!empty($schema['export']['list callback']) && function_exists($schema['export']['list callback'])) {
$exportables[$table_name] = $schema['export']['list callback']();
}
else {
$exportables[$table_name] = ctools_export_default_list($table_name, $schema);
}
}
}
}
if ($load) {
$filter = drush_get_option('filter', FALSE);
$exportables = _ctools_drush_filter_exportables($exportables, $filter);
}
return array(
'exportables' => $exportables,
'schemas' => $schemas,
);
}
function _ctools_drush_export_view($table_name, $object) {
$indent = drush_get_option('indent', '');
$no_colour = drush_get_option('no-colour', FALSE);
$export = ctools_export_crud_export($table_name, $object, $indent);
if ($no_colour) {
drush_print("\n{$export}");
}
else {
drush_print(shellColours::getColouredOutput("\n{$export}", 'light_green'));
}
}
function _ctools_drush_export_delete($table_name, $object) {
$name = _ctools_drush_get_export_name($table_name, $object);
if (_ctools_drush_object_is_overridden($object)) {
ctools_export_crud_delete($table_name, $object);
drush_log("Reverted object: {$name}", 'success');
}
else {
drush_log("Nothing to revert for: {$name}", 'notice');
}
}
function _ctools_drush_export_enable($table_name, $object) {
$name = _ctools_drush_get_export_name($table_name, $object);
if (_ctools_drush_object_is_disabled($object)) {
ctools_export_crud_enable($table_name, $object);
drush_log("Enabled object: {$name}", 'success');
}
else {
drush_log("{$name} is already Enabled", 'notice');
}
}
function _ctools_drush_export_disable($table_name, $object) {
$name = _ctools_drush_get_export_name($table_name, $object);
if (!_ctools_drush_object_is_disabled($object)) {
ctools_export_crud_disable($table_name, $object);
drush_log("Disabled object: {$name}", 'success');
}
else {
drush_log("{$name} is already disabled", 'notice');
}
}
function _ctools_drush_export_module_filter($exportables, $export_module) {
$module_list = module_list();
if (!isset($module_list[$export_module])) {
drush_log(dt('Invalid export module: !export_module', array(
'!export_module' => $export_module,
)), 'error');
}
foreach ($exportables as $table => $objects) {
foreach ($objects as $key => $object) {
if (empty($object->export_module) || $object->export_module !== $export_module) {
unset($exportables[$table][$key]);
}
}
}
return array_filter($exportables);
}
function _ctools_drush_get_export_name($table_name, $object) {
$info = _ctools_drush_export_info(array(
$table_name,
));
$key = $info['schemas'][$table_name]['export']['key'];
return $object->{$key};
}
function _ctools_drush_object_is_disabled($object) {
return isset($object->disabled) && $object->disabled == TRUE ? TRUE : FALSE;
}
function _ctools_drush_object_is_enabled($object) {
return empty($object->disabled) ? TRUE : FALSE;
}
function _ctools_drush_object_is_overridden($object) {
$status = EXPORT_IN_CODE + EXPORT_IN_DATABASE;
return $object->export_type == $status ? TRUE : FALSE;
}
function _ctools_drush_object_is_not_overridden($object) {
$status = EXPORT_IN_CODE + EXPORT_IN_DATABASE;
return $object->export_type == $status ? FALSE : TRUE;
}
function _ctools_drush_object_is_db_only($object) {
return $object->export_type == EXPORT_IN_DATABASE ? TRUE : FALSE;
}
function _ctools_drush_object_is_not_db_only($object) {
return $object->export_type == EXPORT_IN_DATABASE ? FALSE : TRUE;
}
function _ctools_drush_object_is_code_only($object) {
return $object->export_type == EXPORT_IN_CODE ? TRUE : FALSE;
}
function _ctools_drush_object_is_not_code_only($object) {
return $object->export_type == EXPORT_IN_CODE ? FALSE : TRUE;
}
function _ctools_drush_count_exportables($exportables) {
$count = array(
'exportables' => array(),
);
foreach ($exportables as $table => $objects) {
$count['exportables'][$table] = count($objects);
}
$count['total'] = array_sum($count['exportables']);
return $count;
}
function _ctools_drush_filter_exportables($exportables, $filter) {
$eval = FALSE;
if (is_string($filter)) {
switch ($filter) {
case 'enabled':
$eval = '_ctools_drush_object_is_disabled';
break;
case 'disabled':
$eval = '_ctools_drush_object_is_enabled';
break;
case 'overridden':
$eval = '_ctools_drush_object_is_not_overridden';
break;
case 'database':
$eval = '_ctools_drush_object_is_not_db_only';
break;
case 'code':
$eval = '_ctools_drush_object_is_not_code_only';
break;
case 'all':
break;
default:
drush_log(dt('Invalid filter option. Available options are: enabled, disabled, overridden, database, and code.'), 'error');
return;
}
if ($eval) {
foreach ($exportables as $table => $objects) {
foreach ($objects as $key => $object) {
if ($eval($object)) {
unset($exportables[$table][$key]);
}
}
}
}
}
return array_filter($exportables);
}
function _ctools_drush_export_op_alias($op) {
$aliases = array(
'delete' => 'revert',
);
if (isset($aliases[$op])) {
return $aliases[$op];
}
return $op;
}
function _ctools_drush_explode_options($drush_option) {
$options = drush_get_option($drush_option, array());
if (!empty($options)) {
$options = explode(',', $options);
return array_map('trim', $options);
}
return $options;
}
class shellColours {
private static $foreground_colours = array(
'black' => '0;30',
'dark_gray' => '1;30',
'blue' => '0;34',
'light_blue' => '1;34',
'green' => '0;32',
'light_green' => '1;32',
'cyan' => '0;36',
'light_cyan' => '1;36',
'red' => '0;31',
'light_red' => '1;31',
'purple' => '0;35',
'light_purple' => '1;35',
'brown' => '0;33',
'yellow' => '1;33',
'light_gray' => '0;37',
'white' => '1;37',
);
private static $background_colours = array(
'black' => '40',
'red' => '41',
'green' => '42',
'yellow' => '43',
'blue' => '44',
'magenta' => '45',
'cyan' => '46',
'light_gray' => '47',
);
private function __construct() {
}
public static function getColouredOutput($string, $foreground_colour = NULL, $background_colour = NULL) {
$coloured_string = "";
if ($foreground_colour) {
$coloured_string .= "\33[" . self::$foreground_colours[$foreground_colour] . "m";
}
if ($background_colour) {
$coloured_string .= "\33[" . self::$background_colours[$background_colour] . "m";
}
$coloured_string .= $string . "\33[0m";
return $coloured_string;
}
public static function getForegroundColours() {
return array_keys(self::$foreground_colours);
}
public static function getBackgroundColours() {
return array_keys(self::$background_colours);
}
}