Skip to content

Commit

Permalink
Deprecate not-unpacking, fix unpacking
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Aug 24, 2021
1 parent 2a32137 commit e0500e1
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 108 deletions.
17 changes: 6 additions & 11 deletions src/Command/RequireCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ public function __construct(PackageResolver $resolver)
protected function configure()
{
parent::configure();
$this->addOption('no-unpack', null, InputOption::VALUE_NONE, 'Disable unpacking Symfony packs in composer.json.');
$this->addOption('no-unpack', null, InputOption::VALUE_NONE, '[DEPRECATED] Disable unpacking Symfony packs in composer.json.');
$this->addOption('unpack', null, InputOption::VALUE_NONE, '[DEPRECATED] Unpacking is now enabled by default.');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('no-unpack')) {
$this->getIO()->writeError('<warning>The "--unpack" command line option is deprecated; unpacking is now enabled by default.</warning>');
}

if ($input->getOption('unpack')) {
$this->getIO()->writeError('<warning>The "--unpack" command line option is deprecated; unpacking is now enabled by default.</warning>');
}
Expand Down Expand Up @@ -68,16 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
unset($contents, $json, $manipulator);

try {
$ret = parent::execute($input, $output) ?? 0;

if (0 !== $ret || $input->getOption('no-unpack') || $input->getOption('no-update')) {
return $ret;
}

$unpackCommand = new UnpackCommand($this->resolver);
$unpackCommand->setApplication($this->getApplication());

return $unpackCommand->execute($input, $output);
return parent::execute($input, $output) ?? 0;
} finally {
if (null !== $file) {
$manipulator = new JsonManipulator(file_get_contents($file));
Expand Down
7 changes: 6 additions & 1 deletion src/Command/UnpackCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use Symfony\Flex\Unpack\Operation;
use Symfony\Flex\Unpacker;

/**
* @deprecated since Flex 1.4
*/
class UnpackCommand extends BaseCommand
{
private $resolver;
Expand All @@ -38,7 +41,7 @@ protected function configure()
{
$this->setName('symfony:unpack')
->setAliases(['unpack'])
->setDescription('Unpacks a Symfony pack.')
->setDescription('[DEPRECATED] Unpacks a Symfony pack.')
->setDefinition([
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Installed packages to unpack.'),
new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages'),
Expand All @@ -56,6 +59,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$versionParser = new VersionParser();
$dryRun = $input->hasOption('dry-run') && $input->getOption('dry-run');

$io->writeError('<warning>Command "symfony:unpack" is deprecated, Symfony packs are always unpacked now.</>');

$op = new Operation(true, $input->getOption('sort-packages') || $composer->getConfig()->get('sort-packages'));
foreach ($versionParser->parseNameVersionPairs($packages) as $package) {
if (null === $pkg = $installedRepo->findPackage($package['name'], '*')) {
Expand Down
184 changes: 88 additions & 96 deletions src/Flex.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
use Composer\Installer;
use Composer\Installer\InstallerEvent;
use Composer\Installer\InstallerEvents;
use Composer\Installer\NoopInstaller;
use Composer\Installer\PackageEvent;
use Composer\Installer\PackageEvents;
use Composer\Installer\SuggestedPackagesReporter;
Expand Down Expand Up @@ -71,6 +70,10 @@ class Flex implements PluginInterface, EventSubscriberInterface
private $options;
private $configurator;
private $downloader;

/**
* @var Installer
*/
private $installer;
private $postInstallOutput = [''];
private $operations = [];
Expand Down Expand Up @@ -293,8 +296,7 @@ public function configureInstaller()
$backtrace = debug_backtrace();
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Installer) {
$this->installer = \Closure::bind(function () { return $this->update ? $this : null; }, $trace['object'], $trace['object'])();
$trace['object']->setSuggestedPackagesReporter(new SuggestedPackagesReporter(new NullIO()));
$this->installer = $trace['object']->setSuggestedPackagesReporter(new SuggestedPackagesReporter(new NullIO()));
}

if (isset($trace['object']) && $trace['object'] instanceof GlobalCommand) {
Expand Down Expand Up @@ -328,33 +330,21 @@ public function configureProject(Event $event)
@unlink('LICENSE');

// Update composer.json (project is proprietary by default)
$json = new JsonFile(Factory::getComposerFile());
$contents = file_get_contents($json->getPath());
$file = Factory::getComposerFile();
$contents = file_get_contents($file);
$manipulator = new JsonManipulator($contents);
$json = JsonFile::parseJson($contents);

// new projects are most of the time proprietary
$manipulator->addMainKey('license', 'proprietary');

// extra.branch-alias doesn't apply to the project
$manipulator->removeSubNode('extra', 'branch-alias');

// replace unbounded constraints for symfony/* packages by extra.symfony.require
$config = json_decode($contents, true);
if ($symfonyVersion = $config['extra']['symfony']['require'] ?? null) {
$versions = $this->downloader->getVersions();
foreach (['require', 'require-dev'] as $type) {
foreach ($config[$type] ?? [] as $package => $version) {
if ('*' === $version && isset($versions['splits'][$package])) {
$manipulator->addLink($type, $package, $symfonyVersion);
}
}
}
}

// 'name' and 'description' are only required for public packages
// don't use $manipulator->removeProperty() for BC with Composer 1.0
$contents = preg_replace(['{^\s*+"name":.*,$\n}m', '{^\s*+"description":.*,$\n}m'], '', $manipulator->getContents(), 1);
file_put_contents($json->getPath(), $contents);
file_put_contents($file, $contents);

$this->updateComposerLock();
}
Expand All @@ -366,106 +356,49 @@ public function record(PackageEvent $event)
}
}

public function checkForUpdate(PackageEvent $event)
{
if (null === $this->installer || $this->cacheDirPopulated || 'symfony/flex' !== $event->getOperation()->getPackage()->getName()) {
return;
}

$this->update();
$this->cacheDirPopulated = true;
$this->composer->getInstallationManager()->addInstaller(new NoopInstaller());

\Closure::bind(function () {
$this->io = new NullIO();
$this->writeLock = false;
$this->executeOperations = false;
$this->dumpAutoloader = false;
$this->runScripts = false;
}, $this->installer, $this->installer)();
}

public function update(Event $event = null, $operations = [])
public function update(Event $event, $operations = [])
{
if ($operations) {
$this->operations = $operations;
}

$this->install($event);

$jsonPath = Factory::getComposerFile();
$json = file_get_contents($jsonPath);
$manipulator = new JsonManipulator($json);
$json = json_decode($json, true);
$file = Factory::getComposerFile();
$contents = file_get_contents($file);
$json = JsonFile::parseJson($contents);

if (!isset($json['flex-require']) && !isset($json['flex-require'])) {
$this->unpack($event);

if (null === $event) {
// called from checkForUpdate()
} elseif (null === $this->installer || (!isset($json['flex-require']) && !isset($json['flex-require-dev']))) {
return;
} else {
$event->stopPropagation();
}

// merge "flex-require" with "require"
$manipulator = new JsonManipulator($contents);
$sortPackages = $this->composer->getConfig()->get('sort-packages');
$unpackOp = new Operation(true, $sortPackages);

$symfonyVersion = $json['extra']['symfony']['require'] ?? null;
$versions = $symfonyVersion ? $this->downloader->getVersions() : null;
foreach (['require', 'require-dev'] as $type) {
if (isset($json['flex-'.$type])) {
foreach ($json['flex-'.$type] as $package => $constraint) {
$unpackOp->addPackage($package, $constraint, 'require-dev' === $type);
if ($symfonyVersion && '*' === $constraint && isset($versions['splits'][$package])) {
// replace unbounded constraints for symfony/* packages by extra.symfony.require
$constraint = $symfonyVersion;
}
$manipulator->addLink($type, $package, $constraint, $sortPackages);
}

$manipulator->removeMainKey('flex-'.$type);
}
}

file_put_contents($jsonPath, $manipulator->getContents());

$this->cacheDirPopulated = false;
$rm = $this->composer->getRepositoryManager();
$package = Factory::create($this->io)->getPackage();
$this->composer->setPackage($package);
\Closure::bind(function () use ($package, $rm) {
$this->package = $package;
$this->repositoryManager = $rm;
}, $this->installer, $this->installer)();
$this->composer->getEventDispatcher()->__construct($this->composer, $this->io);

$status = $this->installer->run();
if (0 !== $status) {
exit($status);
}

$unpacker = new Unpacker($this->composer, new PackageResolver($this->downloader), $this->dryRun);
$result = $unpacker->unpack($unpackOp);
$unpacker->updateLock($result, $this->io);

$io = new NullIO();
$composer = Factory::create($io, null, true);
$installer = Installer::create($io, $composer);
$installer
->setDevMode($this->dryRun)
->setDumpAutoloader(false)
->setIgnorePlatformRequirements(true)
->setUpdate(true)
->setUpdateAllowList(['php'])
;

if (method_exists($composer->getEventDispatcher(), 'setRunScripts')) {
$composer->getEventDispatcher()->setRunScripts(false);
} else {
$installer->setRunScripts(false);
}

if (method_exists($installer, 'setSkipSuggest')) {
$installer->setSkipSuggest(true);
}
file_put_contents($file, $manipulator->getContents());

$installer->run();
$this->reinstall($event, true);
}

public function install(Event $event = null)
public function install(Event $event)
{
$rootDir = $this->options->get('root-dir');

Expand Down Expand Up @@ -813,7 +746,7 @@ public function fetchRecipes(array $operations): array
];
$packRecipes = [];

foreach ($operations as $i => $operation) {
foreach ($operations as $operation) {
if ($operation instanceof UpdateOperation) {
$package = $operation->getTargetPackage();
} else {
Expand Down Expand Up @@ -992,14 +925,73 @@ private function updateComposerLock()
$lockFile->write($lockData);
}

private function unpack(Event $event)
{
$jsonPath = Factory::getComposerFile();
$json = JsonFile::parseJson(file_get_contents($jsonPath));
$sortPackages = $this->composer->getConfig()->get('sort-packages');
$unpackOp = new Operation(true, $sortPackages);

foreach (['require', 'require-dev'] as $type) {
foreach ($json[$type] ?? [] as $package => $constraint) {
$unpackOp->addPackage($package, $constraint, 'require-dev' === $type);
}
}

$unpacker = new Unpacker($this->composer, new PackageResolver($this->downloader), $this->dryRun);
$result = $unpacker->unpack($unpackOp);

if (!$result->getUnpacked()) {
return;
}

$this->io->writeError('<info>Unpacking Symfony packs</>');
foreach ($result->getUnpacked() as $pkg) {
$this->io->writeError(sprintf(' - Unpacked <info>%s</>', $pkg->getName()));
}

$unpacker->updateLock($result, $this->io);

$this->reinstall($event, false);
}

private function reinstall(Event $event, bool $update)
{
$event->stopPropagation();
$composer = Factory::create($this->io);

$installer = clone $this->installer;
$installer->__construct(
$this->io,
$composer->getConfig(),
$composer->getPackage(),
$composer->getDownloadManager(),
$composer->getRepositoryManager(),
$composer->getLocker(),
$composer->getInstallationManager(),
$composer->getEventDispatcher(),
$composer->getAutoloadGenerator()
);

if (!$update) {
$installer->setUpdateAllowList(['php']);
}

if (method_exists($installer, 'setSkipSuggest')) {
$installer->setSkipSuggest(true);
}

$installer->run();
}

public static function getSubscribedEvents(): array
{
if (!self::$activated) {
return [];
}

$events = [
PackageEvents::POST_PACKAGE_INSTALL => __CLASS__ === self::class ? [['record'], ['checkForUpdate']] : 'record',
PackageEvents::POST_PACKAGE_INSTALL => 'record',
PackageEvents::POST_PACKAGE_UPDATE => [['record'], ['enableThanksReminder']],
PackageEvents::POST_PACKAGE_UNINSTALL => 'record',
ScriptEvents::POST_CREATE_PROJECT_CMD => 'configureProject',
Expand Down

0 comments on commit e0500e1

Please sign in to comment.