File: /var/www/payments-gateway/vendor/symfony/flex/src/Command/InstallRecipesCommand.php
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Flex\Command;
use Composer\Command\BaseCommand;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Flex\Event\UpdateEvent;
use Symfony\Flex\Flex;
class InstallRecipesCommand extends BaseCommand
{
/** @var Flex */
private $flex;
private $rootDir;
private $dotenvPath;
public function __construct(/* cannot be type-hinted */ $flex, string $rootDir, string $dotenvPath = '.env')
{
$this->flex = $flex;
$this->rootDir = $rootDir;
$this->dotenvPath = $dotenvPath;
parent::__construct();
}
protected function configure()
{
$this->setName('symfony:recipes:install')
->setAliases(['recipes:install', 'symfony:sync-recipes', 'sync-recipes', 'fix-recipes'])
->setDescription('Installs or reinstalls recipes for already installed packages.')
->addArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Recipes that should be installed.')
->addOption('force', null, InputOption::VALUE_NONE, 'Overwrite existing files when a new version of a recipe is available')
->addOption('reset', null, InputOption::VALUE_NONE, 'Reset all recipes back to their initial state (should be combined with --force)')
->addOption('yes', null, InputOption::VALUE_NONE, "Answer prompt questions with 'yes' for all questions.")
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$win = '\\' === \DIRECTORY_SEPARATOR;
$force = (bool) $input->getOption('force');
if ($force && !@is_executable(strtok(exec($win ? 'where git' : 'command -v git'), \PHP_EOL))) {
throw new RuntimeException('Cannot run "sync-recipes --force": git not found.');
}
$symfonyLock = $this->flex->getLock();
$composer = $this->getComposer();
$locker = $composer->getLocker();
$lockData = $locker->getLockData();
$packages = [];
$totalPackages = [];
foreach ($lockData['packages'] as $pkg) {
$totalPackages[] = $pkg['name'];
if ($force || !$symfonyLock->has($pkg['name'])) {
$packages[] = $pkg['name'];
}
}
foreach ($lockData['packages-dev'] as $pkg) {
$totalPackages[] = $pkg['name'];
if ($force || !$symfonyLock->has($pkg['name'])) {
$packages[] = $pkg['name'];
}
}
$io = $this->getIO();
if (!$io->isVerbose()) {
$io->writeError([
'Run command with <info>-v</info> to see more details',
'',
]);
}
if ($targetPackages = $input->getArgument('packages')) {
if ($invalidPackages = array_diff($targetPackages, $totalPackages)) {
$io->writeError(\sprintf('<warning>Cannot update: some packages are not installed:</warning> %s', implode(', ', $invalidPackages)));
return 1;
}
if ($packagesRequiringForce = array_diff($targetPackages, $packages)) {
$io->writeError(\sprintf('Recipe(s) already installed for: <info>%s</info>', implode(', ', $packagesRequiringForce)));
$io->writeError('Re-run the command with <info>--force</info> to re-install the recipes.');
$io->writeError('');
}
$packages = array_diff($targetPackages, $packagesRequiringForce);
}
if (!$packages) {
$io->writeError('No recipes to install.');
return 0;
}
$composer = $this->getComposer();
$installedRepo = $composer->getRepositoryManager()->getLocalRepository();
$operations = [];
foreach ($packages as $package) {
if (null === $pkg = $installedRepo->findPackage($package, '*')) {
$io->writeError(\sprintf('<error>Package %s is not installed</>', $package));
return 1;
}
$operations[] = new InstallOperation($pkg);
}
$dotenvFile = $this->dotenvPath;
$dotenvPath = $this->rootDir.'/'.$dotenvFile;
if ($createEnvLocal = $force && file_exists($dotenvPath) && file_exists($dotenvPath.'.dist') && !file_exists($dotenvPath.'.local')) {
rename($dotenvPath, $dotenvPath.'.local');
$pipes = [];
proc_close(proc_open(\sprintf('git mv %s %s > %s 2>&1 || %s %1$s %2$s', ProcessExecutor::escape($dotenvFile.'.dist'), ProcessExecutor::escape($dotenvFile), $win ? 'NUL' : '/dev/null', $win ? 'rename' : 'mv'), $pipes, $pipes, $this->rootDir));
if (file_exists($this->rootDir.'/phpunit.xml.dist') || file_exists($this->rootDir.'/phpunit.dist.xml')) {
touch($dotenvPath.'.test');
}
}
$this->flex->update(new UpdateEvent($force, (bool) $input->getOption('reset'), (bool) $input->getOption('yes')), $operations);
if ($force) {
$output = [
'',
'<bg=blue;fg=white> </>',
'<bg=blue;fg=white> Files have been reset to the latest version of the recipe. </>',
'<bg=blue;fg=white> </>',
'',
' * Use <comment>git diff</> to inspect the changes.',
'',
' Not all of the changes will be relevant to your app: you now',
' need to selectively add or revert them using e.g. a combination',
' of <comment>git add -p</> and <comment>git checkout -p</>',
'',
];
if ($createEnvLocal) {
$output[] = ' Dotenv files have been renamed: .env -> .env.local and .env.dist -> .env';
$output[] = ' See https://symfony.com/doc/current/configuration/dot-env-changes.html';
$output[] = '';
}
$output[] = ' * Use <comment>git checkout .</> to revert the changes.';
$output[] = '';
if ($createEnvLocal) {
$root = '.' !== $this->rootDir ? $this->rootDir.'/' : '';
$output[] = ' To revert the changes made to .env files, run';
$output[] = \sprintf(' <comment>git mv %s %s</> && <comment>%s %s %1$s</>', ProcessExecutor::escape($root.$dotenvFile), ProcessExecutor::escape($root.$dotenvFile.'.dist'), $win ? 'rename' : 'mv', ProcessExecutor::escape($root.$dotenvFile.'.local'));
$output[] = '';
}
$output[] = ' New (untracked) files can be inspected using <comment>git clean --dry-run</>';
$output[] = ' Add the new files you want to keep using <comment>git add</>';
$output[] = ' then delete the rest using <comment>git clean --force</>';
$output[] = '';
$io->write($output);
}
return 0;
}
}