Skip to content

Commit

Permalink
bug #867 Fix reading config for symfony/runtime (nicolas-grekas)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.x branch.

Discussion
----------

Fix reading config for symfony/runtime

Fix #855

Commits
-------

335e44d Fix reading config for symfony/runtime
  • Loading branch information
nicolas-grekas committed Feb 16, 2022
2 parents ea2a03c + 335e44d commit 5092ea7
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 37 deletions.
32 changes: 17 additions & 15 deletions src/Command/DumpEnvCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand All @@ -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']);

Expand All @@ -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);
Expand Down
19 changes: 13 additions & 6 deletions src/Command/InstallRecipesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
}
Expand Down Expand Up @@ -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');
}
}

Expand Down Expand Up @@ -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(' <comment>git mv %s.env %1$s.env.dist</> && <comment>%s %1$s.env.local %1$s.env</>', '.' !== $this->rootDir ? $this->rootDir.'/' : '', $win ? 'rename' : 'mv');
$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[] = '';
}

Expand Down
15 changes: 10 additions & 5 deletions src/Configurator/EnvConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src/Configurator/MakefileConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
<<<EOF
ifndef APP_ENV
include .env
ifndef {$envKey}
include {$dotenvPath}
endif

.DEFAULT_GOAL := help
Expand Down
9 changes: 6 additions & 3 deletions src/Flex.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ class_exists(__NAMESPACE__.str_replace('/', '\\', substr($file, \strlen(__DIR__)
$app->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));
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 3 additions & 6 deletions tests/Command/DumpEnvCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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',
]);
Expand All @@ -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();
Expand Down

0 comments on commit 5092ea7

Please sign in to comment.