Skip to content

Commit

Permalink
Merge branch '1.x' into 2.x
Browse files Browse the repository at this point in the history
* 1.x:
  Remove read code
  Use relative URLs when index.json provides them
  Read recipe conflicts from index.json
  Honor --no-scripts
  Fix detecting new packages before installing their recipes
  Fix reading config for symfony/runtime
  Fix BC with upgrading from flex < 1.18
  Pass GitHub access token when accessing raw.githubusercontent.com
  • Loading branch information
nicolas-grekas committed Feb 16, 2022
2 parents 809425c + 10e438f commit da3f21f
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 64 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
66 changes: 53 additions & 13 deletions src/Downloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ class Downloader
private $degradedMode = false;
private $endpoints;
private $index;
private $conflicts;
private $legacyEndpoint;
private $caFile;
private $enabled = true;
private $composer;

public function __construct(Composer $composer, IoInterface $io, HttpDownloader $rfs)
{
Expand Down Expand Up @@ -90,6 +92,7 @@ public function __construct(Composer $composer, IoInterface $io, HttpDownloader
$this->rfs = $rfs;
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/flex');
$this->sess = bin2hex(random_bytes(16));
$this->composer = $composer;
}

public function getSessionId(): string
Expand Down Expand Up @@ -130,6 +133,22 @@ public function getRecipes(array $operations): array
{
$this->initialize();

if ($this->conflicts) {
$lockedRepository = $this->composer->getLocker()->getLockedRepository();
foreach ($this->conflicts as $conflicts) {
foreach ($conflicts as $package => $versions) {
foreach ($versions as $version => $conflicts) {
foreach ($conflicts as $conflictingPackage => $constraint) {
if ($lockedRepository->findPackage($conflictingPackage, $constraint)) {
unset($this->index[$package][$version]);
}
}
}
}
}
$this->conflicts = [];
}

$data = [];
$urls = [];
$chunk = '';
Expand Down Expand Up @@ -178,32 +197,47 @@ public function getRecipes(array $operations): array
$version = $version[0].'.'.($version[1] ?? '9999999');

foreach (array_reverse($recipeVersions) as $v => $endpoint) {
if (version_compare($version, $v, '>=')) {
$data['locks'][$package->getName()]['version'] = $version;
$data['locks'][$package->getName()]['recipe']['version'] = $v;
if (version_compare($version, $v, '<')) {
continue;
}

if (null !== $recipeRef && isset($this->endpoints[$endpoint]['_links']['archived_recipes_template'])) {
$urls[] = strtr($this->endpoints[$endpoint]['_links']['archived_recipes_template'], [
'{package_dotted}' => str_replace('/', '.', $package->getName()),
'{ref}' => $recipeRef,
]);
$data['locks'][$package->getName()]['version'] = $version;
$data['locks'][$package->getName()]['recipe']['version'] = $v;
$links = $this->endpoints[$endpoint]['_links'];

break;
if (null !== $recipeRef && isset($links['archived_recipes_template'])) {
if (isset($links['archived_recipes_template_relative'])) {
$links['archived_recipes_template'] = preg_replace('{[^/\?]*+(?=\?|$)}', $links['archived_recipes_template_relative'], $endpoint, 1);
}

$urls[] = strtr($this->endpoints[$endpoint]['_links']['recipe_template'], [
$urls[] = strtr($links['archived_recipes_template'], [
'{package_dotted}' => str_replace('/', '.', $package->getName()),
'{package}' => $package->getName(),
'{version}' => $v,
'{ref}' => $recipeRef,
]);

break;
}

if (isset($links['recipes_template_relative'])) {
$links['recipes_template'] = preg_replace('{[^/\?]*+(?=\?|$)}', $links['recipes_template_relative'], $endpoint, 1);
}

$urls[] = strtr($links['recipe_template'], [
'{package_dotted}' => str_replace('/', '.', $package->getName()),
'{package}' => $package->getName(),
'{version}' => $v,
]);

break;
}

continue;
}

if (\is_array($recipeVersions)) {
$data['conflicts'][$package->getName()] = true;
}

if (null !== $this->endpoints) {
$data['locks'][$package->getName()]['version'] = $version;
continue;
Expand Down Expand Up @@ -298,6 +332,11 @@ private function get(array $urls, bool $isRecipe = false, int $try = 3): array

if (preg_match('{^https?://api\.github\.com/}', $url)) {
$headers[] = 'Accept: application/vnd.github.v3.raw';
} elseif (preg_match('{^https?://raw\.githubusercontent\.com/}', $url) && $this->io->hasAuthentication('github.com')) {
$auth = $this->io->getAuthentication('github.com');
if ('x-oauth-basic' === $auth['password']) {
$headers[] = 'Authorization: token '.$auth['username'];
}
} elseif ($this->legacyEndpoint) {
$headers[] = 'Package-Session: '.$this->sess;
}
Expand Down Expand Up @@ -410,9 +449,10 @@ private function initialize()
foreach ($config['recipes'] ?? [] as $package => $versions) {
$this->index[$package] = $this->index[$package] ?? array_fill_keys($versions, $endpoint);
}
$this->conflicts[] = $config['recipe-conflicts'] ?? [];
self::$versions += $config['versions'] ?? [];
self::$aliases += $config['aliases'] ?? [];
unset($config['recipes'], $config['versions'], $config['aliases']);
unset($config['recipes'], $config['recipe-conflicts'], $config['versions'], $config['aliases']);
$this->endpoints[$endpoint] = $config;
}
}
Expand Down
Loading

0 comments on commit da3f21f

Please sign in to comment.