Closed malcomio closed 1 year ago
This would be so nice to have!
Just ran into a situation where this would have been very helpful!
In my case something like:
drush cim --single cookies.cookies_service.etracker cookies.cookies_service.google_analytics
would have been very helpful.
Single should not mean here, that it must be just a single config, but can also be a list of config names, but ONLY these should be imported.
So perhaps there's a better standard name typically used for such things? Perhaps other linux tools give an idea? sftp file transfer by file name or others?
@weitzman would you prefer to use "cim" for this (I'd do) or a separate one like "cims"...
Edit: what about for example:
drush cim --only cookies.cookies_service.etracker cookies.cookies_service.google_analytics
copy the file(s) into a separate directory and use the --partial flag
Thats the recommended way.
Both of those are time-consuming.
Its one cp
. I would not characterize it as "time consuming".
I also landed here looking for a way to import a single file and think this should be reopened.
To say that a single cp
is sufficient because it's not "time consuming" assumes a lot about what is trying to be done and where the command is trying to be run. When trying to run a command against a remote host finding a writeable directory and making a temp directory is quite time consuming. For my current situation I'm trying to correct a tricky order of operations config import bug on Acquia so to do "one cp
" I have to
It's a non trivial amount of work for something that feels like it should already be supported by the --partial flag.
Agree with @ctrladel. The answer given by @weitzman is very assume'ish and also seems to include an uneducated opinion at the tail end stating that it's "just a cp". Assuming that it's "just a cp" is pretty ridiculous when you toss in 21st century hosting methods, git repositories (pull requests and the like), etc. Not every site is hosted on your own machine. Making multiple copies of something just to limp around lack of a required feature can be quite an involved process depending upon the hosting situation.
The correct fix is to actually implement a single config import.
IE: Drupal console has this in the form of config:import:single (alias of cis), drush is lagging behind in a lot of areas compared to drupal console: https://drupalconsole.com/docs/vn/commands/config-import-single
PRs welcome for this.
Until then config:set can replace a whole config object https://www.drush.org/latest/commands/config_set/. Satisfies some use cases.
As far as I am aware, config:set doesnt work with files or does it? I am pretty certain config:set is just a command line only command which has nothing to do with the contents of a config yml file. Am I missing something? Maybe there is some sort of way to get it to load from file, idk. Would be welcome news to me :D Perhaps this might work? drush config:set --input-format=yaml < some_filename.yml I have no idea if that would even work or not.
EDIT: Nope, that didnt work either :/ It still asks for a key argument.
The --partial
flag does work, but I had trouble finding the right command, until I found How to import a specific config files map with drush. It is not clear that you need to supply both --partial
and --source
:
$ drush config:import -h
Import config from a config directory.
Options:
--source=SOURCE An arbitrary directory that holds the configuration files.
--partial Allows for partial config imports from the source directory. Only updates and new configs will be
processed with this flag (missing configs will not be deleted). No config transformation happens.
So the full command which works for me in Lando is:
drush config:import --partial --source=/app/config
With this structure:
drupal10/
├── composer.json
├── composer.lock
├── config
├── vendor
└── web
I added the example from @gitressa to config:import.
As for config:import for a single file without creating a directory, I just added documentation to both config:import and config:set that shows how to do this.
Both these docs improvements are in #5543
The docs in #3343 should work in earlier versions of Drush as well as Drush 12.
Thanks for maintaining Drush @weitzman and @greg-1-anderson, I appreciate it very much. It's an incredible tool.
If anyone else needed a port of drupal console config:import:single in drush :
<?php
namespace Drupal\drush_cis\Drush\Commands;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\config\StorageReplaceDataWrapper;
use Drupal\Core\Config\CachedStorage;
use Drupal\Core\Config\ConfigImporter;
use Drupal\Core\Config\ConfigImporterException;
use Drupal\Core\Config\ConfigManager;
use Drupal\Core\Config\StorageComparer;
use Symfony\Component\Yaml\Parser;
use Webmozart\PathUtil\Path;
/**
* A Drush commandfile.
*
* In addition to this file, you need a drush.services.yml
* in root of your module, and a composer.json file that provides the name
* of the services file to use.
*/
final class DrushCisCommands extends DrushCommands {
/**
* Imports given config file(s).
*/
#[CLI\Command(name: 'drush_cis:config-import-single', aliases: ['cis'])]
#[CLI\Option(name: 'file', description: 'Repeatable. Specify 1 or more paths to files as needed.')]
#[CLI\Usage(name: 'drush cis --file=path/to/config.file.yml', description: 'Imports given config file.')]
public function configImportSingle($options = ['file' => ['default']]) {
$configStorage = \Drupal::service('config.storage');
$sourceStorage = new StorageReplaceDataWrapper($configStorage);
$names = [];
foreach ($options['file'] as $configFile) {
if (!file_exists($configFile)) {
$this->logger()->error(dt('Error : config file does not exist') . " : '$configFile'");
return 1;
}
$name = Path::getFilenameWithoutExtension($configFile);
$ymlFile = new Parser();
$value = $ymlFile->parse(file_get_contents($configFile));
$sourceStorage->replaceData($name, $value);
$names[] = $name;
}
$storageComparer = new StorageComparer(
$sourceStorage,
$configStorage,
\Drupal::service('config.manager')
);
$configImporter = new ConfigImporter(
$storageComparer,
\Drupal::service('event_dispatcher'),
\Drupal::service('config.manager'),
\Drupal::lock(),
\Drupal::service('config.typed'),
\Drupal::moduleHandler(),
\Drupal::service('module_installer'),
\Drupal::service('theme_handler'),
\Drupal::service('string_translation'),
\Drupal::service('extension.list.module')
);
if ($configImporter->alreadyImporting()) {
$this->logger()->warning(dt('Already importing.'));
return 0;
}
try {
if ($configImporter->validate()) {
$sync_steps = $configImporter->initialize();
foreach ($sync_steps as $step) {
$context = [];
do {
$configImporter->doSyncStep($step, $context);
}
while ($context['finished'] < 1);
}
}
}
catch (ConfigImporterException $e) {
$feedback = "Error: unable to import specified config file(s)."
. PHP_EOL
. strip_tags(implode(PHP_EOL, $configImporter->getErrors()))
. PHP_EOL;
$this->logger()->error($feedback);
return 2;
}
catch (\Exception $e) {
$this->logger()->error($e->getMessage());
return 3;
}
$this->logger()->success(
dt('Config file(s) successfully imported. Config names imported :')
. " "
. join(', ', $names)
);
}
}
Just thought I'd throw a friendly note that, if you're running this with --source, you're likely going to have to specify a level down to your config folder because drush is technically executing from docroot.
fin drush config-import --partial --source="../config/migrate/"
As per https://drupal.stackexchange.com/questions/221592/import-a-single-yml-configuration-file, there is not currently a way to import a single configuration file via drush, equivalent to the config:import:single command provided by Drupal Console.
It would be good to have either a flag for the
config:import
command, or a separate command.As far as I'm aware, the other options are:
--partial
flagBoth of those are time-consuming.