From d3adcac0fa1749403b4010f14af73438908c5d4b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 19 Dec 2018 17:47:55 +0100 Subject: [PATCH] Improve sync-recipes --force --- src/Command/SyncRecipesCommand.php | 57 ++++++++++++++++++- src/Flex.php | 2 +- src/Options.php | 19 ++----- .../CopyFromPackageConfiguratorTest.php | 2 +- .../CopyFromRecipeConfiguratorTest.php | 2 +- 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/Command/SyncRecipesCommand.php b/src/Command/SyncRecipesCommand.php index a2712e7e1..b203f2737 100644 --- a/src/Command/SyncRecipesCommand.php +++ b/src/Command/SyncRecipesCommand.php @@ -14,6 +14,7 @@ use Composer\Command\BaseCommand; use Composer\DependencyResolver\Operation\InstallOperation; use Composer\Factory; +use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -23,10 +24,12 @@ class SyncRecipesCommand extends BaseCommand { private $flex; + private $rootDir; - public function __construct(/* cannot be type-hinted */ $flex) + public function __construct(/* cannot be type-hinted */ $flex, string $rootDir) { $this->flex = $flex; + $this->rootDir = $rootDir; parent::__construct(); } @@ -42,8 +45,13 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + $win = '\\' === \DIRECTORY_SEPARATOR; $force = $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 = new Lock(getenv('SYMFONY_LOCKFILE') ?: str_replace('composer.json', 'symfony.lock', Factory::getComposerFile())); $composer = $this->getComposer(); $locker = $composer->getLocker(); @@ -80,6 +88,53 @@ protected function execute(InputInterface $input, OutputInterface $output) $operations[] = new InstallOperation($pkg); } + if ($createEnvLocal = $force && file_exists($this->rootDir.'/.env') && file_exists($this->rootDir.'/.env.dist') && !file_exists($this->rootDir.'/.env.local')) { + rename($this->rootDir.'/.env', $this->rootDir.'/.env.local'); + $pipes = []; + proc_close(proc_open(sprintf('git mv .env.dist .env > %s 2>&1 || %s .env.dist .env', $win ? 'NUL' : '/dev/null', $win ? 'rename' : 'mv'), $pipes, $pipes, $this->rootDir)); + if (file_exists($this->rootDir.'/phpunit.xml.dist')) { + touch($this->rootDir.'/.env.test'); + } + } + $this->flex->update(new UpdateEvent($force), $operations); + + if ($force) { + $output = [ + '', + ' ', + ' Config files are now reset to their initial state. ', + ' ', + '', + ' * Use 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 git add -p and 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 git checkout . to revert the changes.'; + $output[] = ''; + + if ($createEnvLocal) { + $output[] = ' To revert the changes made to .env files, run'; + $output[] = sprintf(' git mv %s.env %1$s.env.dist && %s %1$s.env.local %1$s.env', '.' !== $this->rootDir ? $this->rootDir.'/' : '', $win ? 'rename' : 'mv'); + $output[] = ''; + } + + $output[] = ' New (untracked) files can be inspected using git clean --dry-run'; + $output[] = ' Add the new files you want to keep using git add'; + $output[] = ' then delete the rest using git clean --force'; + $output[] = ''; + + $io->write($output); + } } } diff --git a/src/Flex.php b/src/Flex.php index d343399d3..1162620be 100644 --- a/src/Flex.php +++ b/src/Flex.php @@ -231,7 +231,7 @@ public function activate(Composer $composer, IOInterface $io) $app->add(new Command\UpdateCommand($resolver)); $app->add(new Command\RemoveCommand($resolver)); $app->add(new Command\UnpackCommand($resolver)); - $app->add(new Command\SyncRecipesCommand($this)); + $app->add(new Command\SyncRecipesCommand($this, $this->options->get('root-dir'))); $app->add(new Command\GenerateIdCommand($this)); break; diff --git a/src/Options.php b/src/Options.php index ad2fcb533..c8bd0e079 100644 --- a/src/Options.php +++ b/src/Options.php @@ -61,12 +61,12 @@ public function shouldWriteFile(string $file, bool $overwrite): bool return false; } - if ($this->gitExists()) { - exec('git status --short --ignored -- '.ProcessExecutor::escape($file).' 2>&1', $output, $status); - } else { - $status = 1; + if (!filesize($file)) { + return true; } + exec('git status --short --ignored -- '.ProcessExecutor::escape($file).' 2>&1', $output, $status); + if (0 !== $status) { return (bool) $this->io && $this->io->askConfirmation(\sprintf('Cannot determine the state of the "%s" file, overwrite anyway? [y/N] ', $file), false); } @@ -80,15 +80,4 @@ public function shouldWriteFile(string $file, bool $overwrite): bool return (bool) $this->io && $this->io->askConfirmation(\sprintf('File "%s" has uncommitted changes, overwrite? [y/N] ', $name), false); } - - private function gitExists(): bool - { - static $gitExists; - - if (\is_bool($gitExists)) { - return $gitExists; - } - - return $gitExists = @is_executable(strtok(exec('\\' === \DIRECTORY_SEPARATOR ? 'where git' : 'command -v git'), PHP_EOL)); - } } diff --git a/tests/Configurator/CopyFromPackageConfiguratorTest.php b/tests/Configurator/CopyFromPackageConfiguratorTest.php index 08b856aff..6b27b9574 100644 --- a/tests/Configurator/CopyFromPackageConfiguratorTest.php +++ b/tests/Configurator/CopyFromPackageConfiguratorTest.php @@ -51,7 +51,7 @@ public function testConfigureAndOverwriteFiles() mkdir($this->sourceDirectory); } file_put_contents($this->sourceFile, 'somecontent'); - file_put_contents($this->targetFile, ''); + file_put_contents($this->targetFile, '-'); $this->io->expects($this->at(0))->method('writeError')->with([' Setting configuration and copying files']); $this->io->expects($this->at(2))->method('writeError')->with([' Created "./public/file"']); diff --git a/tests/Configurator/CopyFromRecipeConfiguratorTest.php b/tests/Configurator/CopyFromRecipeConfiguratorTest.php index 036b0bb3a..87251d29f 100644 --- a/tests/Configurator/CopyFromRecipeConfiguratorTest.php +++ b/tests/Configurator/CopyFromRecipeConfiguratorTest.php @@ -44,7 +44,7 @@ public function testConfigureAndOverwriteFiles() if (!file_exists($this->targetDirectory)) { mkdir($this->targetDirectory); } - file_put_contents($this->targetFile, ''); + file_put_contents($this->targetFile, '-'); $this->io->expects($this->at(0))->method('writeError')->with([' Setting configuration and copying files']); $this->io->expects($this->at(2))->method('writeError')->with([' Created "./config/file"']);