From 335e44dd02892fed24d5b4b4afa92b73b9919492 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 15 Feb 2022 17:42:07 +0100 Subject: [PATCH] Fix reading config for symfony/runtime --- src/Command/DumpEnvCommand.php | 32 ++++++++++++----------- src/Command/InstallRecipesCommand.php | 19 +++++++++----- src/Configurator/EnvConfigurator.php | 15 +++++++---- src/Configurator/MakefileConfigurator.php | 6 +++-- src/Flex.php | 9 ++++--- tests/Command/DumpEnvCommandTest.php | 9 +++---- 6 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/Command/DumpEnvCommand.php b/src/Command/DumpEnvCommand.php index d2e837cda..6f7ed6f1f 100644 --- a/src/Command/DumpEnvCommand.php +++ b/src/Command/DumpEnvCommand.php @@ -13,7 +13,6 @@ use Composer\Command\BaseCommand; use Composer\Config; -use Composer\Factory; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -48,19 +47,22 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output): int { - if ($env = $input->getArgument('env')) { - $_SERVER['APP_ENV'] = $env; + $runtime = $this->options->get('runtime') ?? []; + $envKey = $runtime['env_var_name'] ?? 'APP_ENV'; + + if ($env = $input->getArgument('env') ?? $runtime['env'] ?? null) { + $_SERVER[$envKey] = $env; } - $path = $this->options->get('root-dir').'/.env'; + $path = $this->options->get('root-dir').'/'.($runtime['dotenv_path'] ?? '.env'); if (!$env || !$input->getOption('empty')) { - $vars = $this->loadEnv($path, $env); - $env = $vars['APP_ENV']; + $vars = $this->loadEnv($path, $env, $runtime); + $env = $vars[$envKey]; } if ($input->getOption('empty')) { - $vars = ['APP_ENV' => $env]; + $vars = [$envKey => $env]; } $vars = var_export($vars, true); @@ -79,7 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - private function loadEnv(string $path, ?string $env): array + private function loadEnv(string $path, ?string $env, array $runtime): array { if (!file_exists($autoloadFile = $this->config->get('vendor-dir').'/autoload.php')) { throw new \RuntimeException(sprintf('Please run "composer install" before running this command: "%s" not found.', $autoloadFile)); @@ -91,9 +93,10 @@ private function loadEnv(string $path, ?string $env): array throw new \RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); } + $envKey = $runtime['env_var_name'] ?? 'APP_ENV'; $globalsBackup = [$_SERVER, $_ENV]; - unset($_SERVER['APP_ENV']); - $_ENV = ['APP_ENV' => $env]; + unset($_SERVER[$envKey]); + $_ENV = [$envKey => $env]; $_SERVER['SYMFONY_DOTENV_VARS'] = implode(',', array_keys($_SERVER)); putenv('SYMFONY_DOTENV_VARS='.$_SERVER['SYMFONY_DOTENV_VARS']); @@ -105,18 +108,17 @@ private function loadEnv(string $path, ?string $env): array } if (!$env && file_exists($p = "$path.local")) { - $env = $_ENV['APP_ENV'] = $dotenv->parse(file_get_contents($p), $p)['APP_ENV'] ?? null; + $env = $_ENV[$envKey] = $dotenv->parse(file_get_contents($p), $p)[$envKey] ?? null; } if (!$env) { - throw new \RuntimeException('Please provide the name of the environment either by passing it as command line argument or by defining the "APP_ENV" variable in the ".env.local" file.'); + throw new \RuntimeException(sprintf('Please provide the name of the environment either by passing it as command line argument or by defining the "%s" variable in the ".env.local" file.', $envKey)); } - $config = @json_decode(file_get_contents(Factory::getComposerFile()), true); - $testEnvs = $config['extra']['runtime']['test_envs'] ?? ['test']; + $testEnvs = $runtime['test_envs'] ?? ['test']; if (method_exists($dotenv, 'loadEnv')) { - $dotenv->loadEnv($path, 'APP_ENV', 'dev', $testEnvs); + $dotenv->loadEnv($path, $envKey, 'dev', $testEnvs); } else { // fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added) $dotenv->load(file_exists($path) || !file_exists($p = "$path.dist") ? $path : $p); diff --git a/src/Command/InstallRecipesCommand.php b/src/Command/InstallRecipesCommand.php index de6e36f01..d1ae1a4b1 100644 --- a/src/Command/InstallRecipesCommand.php +++ b/src/Command/InstallRecipesCommand.php @@ -13,6 +13,7 @@ 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; @@ -26,11 +27,13 @@ class InstallRecipesCommand extends BaseCommand /** @var Flex */ private $flex; private $rootDir; + private $dotenvPath; - public function __construct(/* cannot be type-hinted */ $flex, string $rootDir) + public function __construct(/* cannot be type-hinted */ $flex, string $rootDir, string $dotenvPath = '.env') { $this->flex = $flex; $this->rootDir = $rootDir; + $this->dotenvPath = $dotenvPath; parent::__construct(); } @@ -120,12 +123,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int $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'); + $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 .env.dist .env > %s 2>&1 || %s .env.dist .env', $win ? 'NUL' : '/dev/null', $win ? 'rename' : 'mv'), $pipes, $pipes, $this->rootDir)); + 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')) { - touch($this->rootDir.'/.env.test'); + touch($dotenvPath.'.test'); } } @@ -156,8 +162,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output[] = ''; if ($createEnvLocal) { + $root = '.' !== $this->rootDir ? $this->rootDir.'/' : ''; $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[] = sprintf(' git mv %s %s && %s %s %1$s', ProcessExecutor::escape($root.$dotenvFile), ProcessExecutor::escape($root.$dotenvFile.'.dist'), $win ? 'rename' : 'mv', ProcessExecutor::escape($root.$dotenvFile.'.local')); $output[] = ''; } diff --git a/src/Configurator/EnvConfigurator.php b/src/Configurator/EnvConfigurator.php index 32f8abcd0..9fd81bd30 100644 --- a/src/Configurator/EnvConfigurator.php +++ b/src/Configurator/EnvConfigurator.php @@ -25,7 +25,7 @@ public function configure(Recipe $recipe, $vars, Lock $lock, array $options = [] $this->write('Adding environment variable defaults'); $this->configureEnvDist($recipe, $vars, $options['force'] ?? false); - if (!file_exists($this->options->get('root-dir').'/.env.test')) { + if (!file_exists($this->options->get('root-dir').'/'.($this->options->get('runtime')['dotenv_path'] ?? '.env').'.test')) { $this->configurePhpUnit($recipe, $vars, $options['force'] ?? false); } } @@ -49,7 +49,9 @@ public function update(RecipeUpdate $recipeUpdate, array $originalConfig, array private function configureEnvDist(Recipe $recipe, $vars, bool $update) { - foreach (['.env.dist', '.env'] as $file) { + $dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env'; + + foreach ([$dotenvPath.'.dist', $dotenvPath] as $file) { $env = $this->options->get('root-dir').'/'.$file; if (!is_file($env)) { continue; @@ -133,7 +135,9 @@ private function configurePhpUnit(Recipe $recipe, $vars, bool $update) private function unconfigureEnvFiles(Recipe $recipe, $vars) { - foreach (['.env', '.env.dist'] as $file) { + $dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env'; + + foreach ([$dotenvPath, $dotenvPath.'.dist'] as $file) { $env = $this->options->get('root-dir').'/'.$file; if (!file_exists($env)) { continue; @@ -200,7 +204,8 @@ private function generateRandomBytes($length = 16) private function getContentsAfterApplyingRecipe(string $rootDir, Recipe $recipe, array $vars): array { - $files = ['.env', '.env.dist', 'phpunit.xml.dist', 'phpunit.xml']; + $dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env'; + $files = [$dotenvPath, $dotenvPath.'.dist', 'phpunit.xml.dist', 'phpunit.xml']; if (0 === \count($vars)) { return array_fill_keys($files, null); @@ -217,7 +222,7 @@ private function getContentsAfterApplyingRecipe(string $rootDir, Recipe $recipe, true ); - if (!file_exists($rootDir.'/.env.test')) { + if (!file_exists($rootDir.'/'.$dotenvPath.'.test')) { $this->configurePhpUnit( $recipe, $vars, diff --git a/src/Configurator/MakefileConfigurator.php b/src/Configurator/MakefileConfigurator.php index 5ab400c5b..5b5abe437 100644 --- a/src/Configurator/MakefileConfigurator.php +++ b/src/Configurator/MakefileConfigurator.php @@ -71,11 +71,13 @@ private function configureMakefile(Recipe $recipe, array $definitions, bool $upd $data = "\n".ltrim($data, "\r\n"); if (!file_exists($makefile)) { + $envKey = $this->options->get('runtime')['env_var_name'] ?? 'APP_ENV'; + $dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env'; file_put_contents( $this->options->get('root-dir').'/Makefile', <<add(new Command\RemoveCommand($resolver)); $app->add(new Command\UnpackCommand($resolver)); $app->add(new Command\RecipesCommand($this, $this->lock, $rfs)); - $app->add(new Command\InstallRecipesCommand($this, $this->options->get('root-dir'))); + $app->add(new Command\InstallRecipesCommand($this, $this->options->get('root-dir'), $this->options->get('runtime')['dotenv_path'] ?? '.env')); $app->add(new Command\UpdateRecipesCommand($this, $this->downloader, $rfs, $this->configurator, $this->options->get('root-dir'))); if (class_exists(Command\GenerateIdCommand::class)) { $app->add(new Command\GenerateIdCommand(null)); @@ -391,9 +391,11 @@ public function update(Event $event, $operations = []) public function install(Event $event) { $rootDir = $this->options->get('root-dir'); + $runtime = $this->options->get('runtime'); + $dotenvPath = $rootDir.'/'.($runtime['dotenv_path'] ?? '.env'); - if (!file_exists("$rootDir/.env") && !file_exists("$rootDir/.env.local") && file_exists("$rootDir/.env.dist") && false === strpos(file_get_contents("$rootDir/.env.dist"), '.env.local')) { - copy($rootDir.'/.env.dist', $rootDir.'/.env'); + if (!file_exists($dotenvPath) && !file_exists($dotenvPath.'.local') && file_exists($dotenvPath.'.dist') && false === strpos(file_get_contents($dotenvPath.'.dist'), '.env.local')) { + copy($dotenvPath.'.dist', $dotenvPath); } // Execute missing recipes @@ -829,6 +831,7 @@ private function initOptions(): Options 'var-dir' => 'var', 'public-dir' => 'public', 'root-dir' => $extra['symfony']['root-dir'] ?? '.', + 'runtime' => $extra['runtime'] ?? [], ], $extra); return new Options($options, $this->io); diff --git a/tests/Command/DumpEnvCommandTest.php b/tests/Command/DumpEnvCommandTest.php index aed761b3d..012745583 100644 --- a/tests/Command/DumpEnvCommandTest.php +++ b/tests/Command/DumpEnvCommandTest.php @@ -174,7 +174,6 @@ public function testLoadLocalEnvWhenTestEnvIsNotEqual() $env = FLEX_TEST_DIR.'/.env'; $envLocal = FLEX_TEST_DIR.'/.env.local'; $envLocalPhp = FLEX_TEST_DIR.'/.env.local.php'; - $composer = FLEX_TEST_DIR.'/composer.json'; @unlink($envLocalPhp); @@ -184,9 +183,8 @@ public function testLoadLocalEnvWhenTestEnvIsNotEqual() APP_SECRET=abcdefgh123456789 EOF ); - file_put_contents(FLEX_TEST_DIR.'/composer.json', '{"extra":{"runtime":{"test_envs":[]}}}'); - $command = $this->createCommandDumpEnv(); + $command = $this->createCommandDumpEnv(['runtime' => ['test_envs' => []]]); $command->execute([ 'env' => 'test', ]); @@ -202,14 +200,13 @@ public function testLoadLocalEnvWhenTestEnvIsNotEqual() unlink($env); unlink($envLocal); unlink($envLocalPhp); - unlink($composer); } - private function createCommandDumpEnv() + private function createCommandDumpEnv(array $options = []) { $command = new DumpEnvCommand( new Config(false, __DIR__.'/../..'), - new Options(['root-dir' => FLEX_TEST_DIR]) + new Options($options + ['root-dir' => FLEX_TEST_DIR]) ); $application = new Application();