Skip to content

Commit ed1626b

Browse files
bug #869 Fix detecting new packages before installing their recipes (nicolas-grekas)
This PR was merged into the 1.x branch. Discussion ---------- Fix detecting new packages before installing their recipes Fix #851 Tracking the transactional changeset from composer.lock leads to the linked issue. Instead, this tracks the changeset by computing it from symfony.lock. Requires the `InstallerEvents::PRE_OPERATIONS_EXEC` event, which is Composer 2-only. Commits ------- 07631cf Fix detecting new packages before installing their recipes
2 parents 5092ea7 + 07631cf commit ed1626b

File tree

4 files changed

+51
-11
lines changed

4 files changed

+51
-11
lines changed

src/Flex.php

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Composer\DependencyResolver\Operation\UninstallOperation;
2020
use Composer\DependencyResolver\Operation\UpdateOperation;
2121
use Composer\DependencyResolver\Pool;
22+
use Composer\DependencyResolver\Transaction;
2223
use Composer\Downloader\FileDownloader;
2324
use Composer\EventDispatcher\EventSubscriberInterface;
2425
use Composer\Factory;
@@ -35,6 +36,7 @@
3536
use Composer\Package\BasePackage;
3637
use Composer\Package\Comparer\Comparer;
3738
use Composer\Package\Locker;
39+
use Composer\Package\Package;
3840
use Composer\Package\PackageInterface;
3941
use Composer\Plugin\PluginEvents;
4042
use Composer\Plugin\PluginInterface;
@@ -45,6 +47,7 @@
4547
use Composer\Repository\RepositoryManager;
4648
use Composer\Script\Event;
4749
use Composer\Script\ScriptEvents;
50+
use Composer\Semver\VersionParser;
4851
use Symfony\Component\Console\Input\ArgvInput;
4952
use Symfony\Component\Filesystem\Filesystem;
5053
use Symfony\Flex\Event\UpdateEvent;
@@ -341,11 +344,34 @@ public function configureProject(Event $event)
341344

342345
public function record(PackageEvent $event)
343346
{
344-
if ($this->shouldRecordOperation($event)) {
347+
if ($this->shouldRecordOperation($event->getOperation(), $event->isDevMode(), $event->getComposer())) {
345348
$this->operations[] = $event->getOperation();
346349
}
347350
}
348351

352+
public function recordOperations(InstallerEvent $event)
353+
{
354+
if (!$event->isExecutingOperations()) {
355+
return;
356+
}
357+
358+
$versionParser = new VersionParser();
359+
$packages = [];
360+
foreach ($this->lock->all() as $name => $info) {
361+
$packages[] = new Package($name, $versionParser->normalize($info['version']), $info['version']);
362+
}
363+
364+
$transation = \Closure::bind(function () use ($packages, $event) {
365+
return new Transaction($packages, $event->getTransaction()->resultPackageMap);
366+
}, null, Transaction::class)();
367+
368+
foreach ($transation->getOperations() as $operation) {
369+
if ($this->shouldRecordOperation($operation, $event->isDevMode(), $event->getComposer())) {
370+
$this->operations[] = $operation;
371+
}
372+
}
373+
}
374+
349375
public function update(Event $event, $operations = [])
350376
{
351377
if ($operations) {
@@ -854,18 +880,21 @@ private function formatOrigin(Recipe $recipe): string
854880
return sprintf('<info>%s</> (<comment>>=%s</>): From %s', $matches[1], $matches[2], 'auto-generated recipe' === $matches[3] ? '<comment>'.$matches[3].'</>' : $matches[3]);
855881
}
856882

857-
private function shouldRecordOperation(PackageEvent $event): bool
883+
private function shouldRecordOperation(OperationInterface $operation, bool $isDevMode, Composer $composer = null): bool
858884
{
859-
$operation = $event->getOperation();
885+
if ($this->dryRun) {
886+
return false;
887+
}
888+
860889
if ($operation instanceof UpdateOperation) {
861890
$package = $operation->getTargetPackage();
862891
} else {
863892
$package = $operation->getPackage();
864893
}
865894

866895
// when Composer runs with --no-dev, ignore uninstall operations on packages from require-dev
867-
if (!$event->isDevMode() && $operation instanceof UninstallOperation) {
868-
foreach ($event->getComposer()->getLocker()->getLockData()['packages-dev'] as $p) {
896+
if (!$isDevMode && $operation instanceof UninstallOperation) {
897+
foreach (($composer ?? $this->composer)->getLocker()->getLockData()['packages-dev'] as $p) {
869898
if ($package->getName() === $p['name']) {
870899
return false;
871900
}
@@ -993,9 +1022,6 @@ public static function getSubscribedEvents(): array
9931022
}
9941023

9951024
$events = [
996-
PackageEvents::POST_PACKAGE_INSTALL => 'record',
997-
PackageEvents::POST_PACKAGE_UPDATE => [['record'], ['enableThanksReminder']],
998-
PackageEvents::POST_PACKAGE_UNINSTALL => 'record',
9991025
ScriptEvents::POST_CREATE_PROJECT_CMD => 'configureProject',
10001026
ScriptEvents::POST_INSTALL_CMD => 'install',
10011027
ScriptEvents::PRE_UPDATE_CMD => 'configureInstaller',
@@ -1005,14 +1031,21 @@ public static function getSubscribedEvents(): array
10051031

10061032
if (version_compare('2.0.0', PluginInterface::PLUGIN_API_VERSION, '>')) {
10071033
$events += [
1034+
PackageEvents::POST_PACKAGE_INSTALL => 'record',
1035+
PackageEvents::POST_PACKAGE_UPDATE => [['record'], ['enableThanksReminder']],
1036+
PackageEvents::POST_PACKAGE_UNINSTALL => 'record',
10081037
InstallerEvents::PRE_DEPENDENCIES_SOLVING => [['populateProvidersCacheDir', \PHP_INT_MAX]],
10091038
InstallerEvents::POST_DEPENDENCIES_SOLVING => [['populateFilesCacheDir', \PHP_INT_MAX]],
10101039
PackageEvents::PRE_PACKAGE_INSTALL => [['populateFilesCacheDir', ~\PHP_INT_MAX]],
10111040
PackageEvents::PRE_PACKAGE_UPDATE => [['populateFilesCacheDir', ~\PHP_INT_MAX]],
10121041
PluginEvents::PRE_FILE_DOWNLOAD => 'onFileDownload',
10131042
];
10141043
} else {
1015-
$events += [PluginEvents::PRE_POOL_CREATE => 'truncatePackages'];
1044+
$events += [
1045+
PackageEvents::POST_PACKAGE_UPDATE => 'enableThanksReminder',
1046+
InstallerEvents::PRE_OPERATIONS_EXEC => 'recordOperations',
1047+
PluginEvents::PRE_POOL_CREATE => 'truncatePackages',
1048+
];
10161049
}
10171050

10181051
return $events;

tests/Command/DumpEnvCommandTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
namespace Symfony\Flex\Tests\Command;
1313

1414
use Composer\Config;
15+
use Composer\Console\Application;
16+
use Composer\IO\NullIO;
1517
use PHPUnit\Framework\TestCase;
16-
use Symfony\Component\Console\Application;
1718
use Symfony\Component\Console\Tester\CommandTester;
1819
use Symfony\Flex\Command\DumpEnvCommand;
1920
use Symfony\Flex\Options;
@@ -210,6 +211,11 @@ private function createCommandDumpEnv(array $options = [])
210211
);
211212

212213
$application = new Application();
214+
215+
\Closure::bind(function () {
216+
$this->io = new NullIO();
217+
}, $application, $application)();
218+
213219
$application->add($command);
214220
$command = $application->find('dump-env');
215221

tests/Command/UpdateRecipesCommandTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111

1212
namespace Symfony\Flex\Tests\Command;
1313

14+
use Composer\Console\Application;
1415
use Composer\Factory;
1516
use Composer\IO\BufferIO;
1617
use Composer\Plugin\PluginInterface;
1718
use Composer\Util\Platform;
1819
use PHPUnit\Framework\TestCase;
19-
use Symfony\Component\Console\Application;
2020
use Symfony\Component\Console\Tester\CommandTester;
2121
use Symfony\Component\Filesystem\Filesystem;
2222
use Symfony\Component\Process\Process;

tests/FlexTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ private function mockPackageEvent(Package $package): PackageEvent
364364
{
365365
$event = $this->getMockBuilder(PackageEvent::class, ['getOperation'])->disableOriginalConstructor()->getMock();
366366
$event->expects($this->any())->method('getOperation')->willReturn(new InstallOperation($package));
367+
$event->expects($this->any())->method('isDevMode')->willReturn(true);
367368

368369
return $event;
369370
}

0 commit comments

Comments
 (0)