UnpackCommandProvider::class];
}
/**
* {@inheritdoc}
*/
public function activate(Composer $composer, IOInterface $io): void {
$this->manager = new UnpackManager($composer, $io);
}
/**
* {@inheritdoc}
*/
public function deactivate(Composer $composer, IOInterface $io): void {
}
/**
* {@inheritdoc}
*/
public function uninstall(Composer $composer, IOInterface $io): void {
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
ScriptEvents::POST_UPDATE_CMD => 'unpackOnRequire',
ScriptEvents::POST_CREATE_PROJECT_CMD => 'unpackOnCreateProject',
];
}
/**
* Post update command event callback.
*/
public function unpackOnRequire(Event $event): void {
if (!$this->manager->unpackOptions->options['on-require']) {
return;
}
// @todo https://www.drupal.org/project/drupal/issues/3523269 Use Composer
// API once it exists.
$backtrace = debug_backtrace();
$composer = $event->getComposer();
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Installer) {
$installer = $trace['object'];
// Get the list of packages being required. This code is largely copied
// from https://github.com/symfony/flex/blob/2.x/src/Flex.php#L218.
$updateAllowList = \Closure::bind(function () {
return $this->updateAllowList ?? [];
}, $installer, $installer)();
// Determine if the --no-install flag has been passed to require.
$isInstalling = \Closure::bind(function () {
return $this->install;
}, $installer, $installer)();
}
// If the command is a require command, populate the list of recipes to
// unpack.
if (isset($trace['object']) && $trace['object'] instanceof RequireCommand && isset($installer, $updateAllowList, $isInstalling)) {
// Determines if a message has been sent about require-dev and recipes.
$devRecipeWarningEmitted = FALSE;
$unpackCollection = new UnpackCollection();
foreach ($updateAllowList as $package_name) {
$packages = $composer->getRepositoryManager()->getLocalRepository()->findPackages($package_name);
$package = reset($packages);
if (!$package instanceof PackageInterface) {
if (!$isInstalling) {
$event->getIO()->write('Recipes are not unpacked when the --no-install option is used.', verbosity: IOInterface::VERBOSE);
return;
}
$event->getIO()->error(sprintf('%s does not resolve to a package.', $package_name));
return;
}
// Only recipes are supported.
if ($package->getType() === self::RECIPE_PACKAGE_TYPE) {
if ($this->manager->unpackOptions->isIgnored($package)) {
$event->getIO()->write(sprintf('%s not unpacked because it is ignored.', $package_name), verbosity: IOInterface::VERBOSE);
}
elseif (UnpackManager::isDevRequirement($package)) {
if (!$devRecipeWarningEmitted) {
$event->getIO()->write('Recipes required as a development dependency are not automatically unpacked.');
$devRecipeWarningEmitted = TRUE;
}
}
else {
$unpackCollection->add($package);
}
}
}
// Unpack any recipes that have been added to the collection.
$this->manager->unpack($unpackCollection);
// The trace has been processed far enough and the $updateAllowList has
// been used.
break;
}
}
}
/**
* Post create-project command event callback.
*/
public function unpackOnCreateProject(Event $event): void {
$composer = $event->getComposer();
$unpackCollection = new UnpackCollection();
foreach ($composer->getRepositoryManager()->getLocalRepository()->getPackages() as $package) {
// Only recipes are supported.
if ($package->getType() === self::RECIPE_PACKAGE_TYPE) {
if ($this->manager->unpackOptions->isIgnored($package)) {
$event->getIO()->write(sprintf('%s not unpacked because it is ignored.', $package->getName()), verbosity: IOInterface::VERBOSE);
}
elseif (UnpackManager::isDevRequirement($package)) {
continue;
}
else {
$unpackCollection->add($package);
}
}
}
// Unpack any recipes that have been registered.
$this->manager->unpack($unpackCollection);
}
}