Skip to content

Add support for Drush 9.x #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: 8.x-1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,14 @@
"issues": "https://github.com/previousnext/drush_cmi_tools/issues",
"source": "https://github.com/previousnext/drush_cmi_tools"
},
"require": {}
}
"require": {
"php": ">=5.6.0"
},
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
}
}
}
5 changes: 5 additions & 0 deletions drush.services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
drush_cmi_tools.commands:
class: \Drupal\drush_cmi_tools\Commands\DrushCmiToolsCommands
tags:
- { name: drush.command }
8 changes: 4 additions & 4 deletions drush_cmi_tools.drush.inc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use Drupal\Component\Serialization\Yaml;
use Drupal\config\StorageReplaceDataWrapper;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\StorageComparer;
use Drush\Config\StorageWrapper;
use Drush\Drupal\Commands\config\ConfigCommands;
use Drush\Log\LogLevel;

/**
Expand Down Expand Up @@ -103,7 +103,7 @@ function drush_drush_cmi_tools_config_export_plus($destination = NULL) {
}
}

$result = _drush_config_export($destination, $destination_dir, FALSE);
$result = \Drupal::service('config.export.commands')->doExport($destination, $destination_dir, FALSE);
$file_service = \Drupal::service('file_system');
foreach ($patterns as $pattern) {
foreach (file_scan_directory($destination_dir, $pattern) as $file_url => $file) {
Expand Down Expand Up @@ -194,7 +194,7 @@ function drush_drush_cmi_tools_config_import_plus($destination = NULL) {
foreach ($storage_comparer->getAllCollectionNames() as $collection) {
$change_list[$collection] = $storage_comparer->getChangelist(NULL, $collection);
}
_drush_print_config_changes_table($change_list);
ConfigCommands::configChangesTablePrint($change_list);
}
else {
// Copy active storage to the temporary directory.
Expand All @@ -212,6 +212,6 @@ function drush_drush_cmi_tools_config_import_plus($destination = NULL) {
}

if (drush_confirm(dt('Import the listed configuration changes?'))) {
return drush_op('_drush_config_import', $storage_comparer);
\Drupal::service('config.import.commands')->doImport($storage_comparer);
}
}
5 changes: 5 additions & 0 deletions drush_cmi_tools.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: module
name: 'Drush CMI Tools'
description: 'Provides custom export/import commands.'
core: 8.x
package: 'Drush'
222 changes: 222 additions & 0 deletions src/Commands/DrushCmiToolsCommands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
<?php

namespace Drupal\drush_cmi_tools\Commands;

use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\config\StorageReplaceDataWrapper;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\StorageComparer;
use Drupal\Core\Serialization\Yaml;
use Drush\Commands\DrushCommands;

/**
* A Drush commandfile.
*/
class DrushCmiToolsCommands extends DrushCommands {

/**
* Export configuration to a directory and apply an ignore list.
*
* @param array $options An associative array of options whose values come from cli, aliases, config, etc.
* @option destination
* An arbitrary directory that should receive the exported files. An alternative to label argument.
* @option ignore-list
* Path to YAML file containing config to ignore from exports
* @usage drush config-export-plus --destination=/some/folder --ignore-list=./config-ignore.yml
* Export configuration; Save files in a backup directory named config-export.
*
* @command config:export-plus
* @aliases cexy,config-export-plus
*/
public function exportPlus(array $options = ['destination' => null, 'ignore-list' => null]) {
$this->logger()->debug(dt('Starting export'));

// Do the actual config export operation
// Determine which target directory to use.
if (($target = $options['destination']) && $target !== TRUE) {
$destination_dir = $target;

// Support writing to a destination from the $config_directories specified
// in settings.php
global $config_directories;
if (!empty($config_directories[$destination_dir])) {
$destination_dir = $config_directories[$destination_dir];
}

// It is important to be able to specify a destination directory that
// does not exist yet, for exporting on remote systems
drush_mkdir($destination_dir);
} else {
$this->logger()->error((dt('You must provide a --destination option')));
return;
}
$patterns = [];
if ($ignore_list = $options['ignore-list']) {
if (!is_file($ignore_list)) {
$this->logger()->error(dt('The file specified in --ignore-list option does not exist.'));
return;
}
if ($string = file_get_contents($ignore_list)) {
$ignore_list_error = FALSE;
$parsed = FALSE;
try {
$parsed = Yaml::decode($string);
}
catch (InvalidDataTypeException $e) {
$ignore_list_error = TRUE;
}
if (!isset($parsed['ignore']) || !is_array($parsed['ignore'])) {
$ignore_list_error = TRUE;
}
if ($ignore_list_error) {
$this->logger()->error(dt('The file specified in --ignore-list option is in the wrong format. It must be valid YAML with a top-level ignore key.'));
return;
}
foreach ($parsed['ignore'] as $ignore) {
// Allow for accidental .yml extension.
if (substr($ignore, -4) === '.yml') {
$ignore = substr($ignore, 0, -4);
}
$patterns[] = '/^' . str_replace('\*', '(.*)', preg_quote($ignore)) . '\.yml/';
}
}
}

$drushExportOptions = [
'diff' => FALSE,

];
$result = \Drupal::service('config.export.commands')->doExport($drushExportOptions, $destination_dir, FALSE);
$file_service = \Drupal::service('file_system');
foreach ($patterns as $pattern) {
foreach (file_scan_directory($destination_dir, $pattern) as $file_url => $file) {
$file_service->unlink($file_url);
$this->logger()->notice("Removed $file_url according to ignore list.");
}
}

return $result;
}

/**
* Import config from a config directory resepecting live content and a delete list.
*
* @param array $options An associative array of options whose values come from cli, aliases, config, etc.
* @option preview
* Format for displaying proposed changes. Recognized values: list, diff. Defaults to list.
* @option source
* An arbitrary directory that holds the configuration files.
* @option delete-list
* Path to YAML file containing config to delete before importing. Useful when you need to remove items from active config store before importing.
* @option install
* Directory that holds the files to import once only.
* @usage drush config-import-plus --delete-list=./config-delete.yml --install=/some/install/folder --source=/some/export/folder
* Import configuration; do not enable or disable the devel module, regardless of whether or not it appears in the imported list of enabled modules.
* @validate-module-enabled config
*
* @command config:import-plus
* @aliases cimy,config-import-plus
*/
public function importPlus(array $options = ['preview' => null, 'source' => null, 'delete-list' => null, 'install' => null, 'diff' => null]) {
$this->logger()->debug(dt('Starting import'));
// Determine source directory.
if ($target = $options['source']) {
$source_dir = $target;

// Support reading the source from the $config_directories specified in
// settings.php
global $config_directories;
if (!empty($config_directories[$source_dir])) {
$source_dir = $config_directories[$source_dir];
}
}
else {
$this->logger()->error(dt('You must provide a --source option'));
return;
}
/** @var \Drupal\Core\Config\StorageInterface $active_storage */
$active_storage = \Drupal::service('config.storage');
$source_storage = new StorageReplaceDataWrapper($active_storage);
$file_storage = new FileStorage($source_dir);
foreach ($file_storage->listAll() as $name) {
$data = $file_storage->read($name);
$source_storage->replaceData($name, $data);
}
if ($delete_list = $options['delete-list']) {
if (!is_file($delete_list)) {
$this->logger()->error(dt('The file specified in --delete-list option does not exist.'));
return;
}
if ($string = file_get_contents($delete_list)) {
$delete_list_error = FALSE;
$parsed = FALSE;
try {
$parsed = Yaml::decode($string);
}
catch (InvalidDataTypeException $e) {
$delete_list_error = TRUE;
}
if (!isset($parsed['delete']) || !is_array($parsed['delete'])) {
$delete_list_error = TRUE;
}
if ($delete_list_error) {
$this->logger()->error(dt('The file specified in --delete-list option is in the wrong format. It must be valid YAML with a top-level delete key.'));
return;
}
foreach ($parsed['delete'] as $delete) {
// Allow for accidental .yml extension.
if (substr($delete, -4) === '.yml') {
$delete = substr($delete, 0, -4);
}
if ($source_storage->exists($delete)) {
$source_storage->delete($delete);
$this->logger()->notice("Deleted $delete as per delete list.");
}
else {
$this->logger()->notice("Ignored deleting $delete, does not exist.");
}
}
}
}
if ($install = $options['install']) {
$file_storage = new FileStorage($install);
foreach ($file_storage->listAll() as $name) {
if (!$source_storage->exists($name)) {
$data = $file_storage->read($name);
$source_storage->replaceData($name, $data);
$this->logger()->notice("Installed $name for first time.");
}
}
}

/** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
$config_manager = \Drupal::service('config.manager');
$storage_comparer = new StorageComparer($source_storage, $active_storage, $config_manager);


if (!$storage_comparer->createChangelist()->hasChanges()) {
$this->logger()->notice(dt('There are no changes to import.'));
return;
}

// Copy active storage to the temporary directory.
if ($options['diff']) {
$temp_dir = drush_tempdir();
$temp_storage = new FileStorage($temp_dir);
$source_dir_storage = new FileStorage($source_dir);
foreach ($source_dir_storage->listAll() as $name) {
if ($data = $active_storage->read($name)) {
$temp_storage->write($name, $data);
}
}
drush_shell_exec('diff -x %s -u %s %s', '*.git', $temp_dir, $source_dir);
$output = drush_shell_exec_output();
$this->logger()->notice(implode("\n", $output));
}

if ($this->io()->confirm(dt('Import the listed configuration changes?'))) {
\Drupal::service('config.import.commands')->doImport($storage_comparer);
}
}

}