Skip to content

Commit da3f21f

Browse files
Merge branch '1.x' into 2.x
* 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
2 parents 809425c + 10e438f commit da3f21f

File tree

9 files changed

+174
-64
lines changed

9 files changed

+174
-64
lines changed

src/Command/DumpEnvCommand.php

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Composer\Command\BaseCommand;
1515
use Composer\Config;
16-
use Composer\Factory;
1716
use Symfony\Component\Console\Input\InputArgument;
1817
use Symfony\Component\Console\Input\InputInterface;
1918
use Symfony\Component\Console\Input\InputOption;
@@ -48,19 +47,22 @@ protected function configure()
4847

4948
protected function execute(InputInterface $input, OutputInterface $output): int
5049
{
51-
if ($env = $input->getArgument('env')) {
52-
$_SERVER['APP_ENV'] = $env;
50+
$runtime = $this->options->get('runtime') ?? [];
51+
$envKey = $runtime['env_var_name'] ?? 'APP_ENV';
52+
53+
if ($env = $input->getArgument('env') ?? $runtime['env'] ?? null) {
54+
$_SERVER[$envKey] = $env;
5355
}
5456

55-
$path = $this->options->get('root-dir').'/.env';
57+
$path = $this->options->get('root-dir').'/'.($runtime['dotenv_path'] ?? '.env');
5658

5759
if (!$env || !$input->getOption('empty')) {
58-
$vars = $this->loadEnv($path, $env);
59-
$env = $vars['APP_ENV'];
60+
$vars = $this->loadEnv($path, $env, $runtime);
61+
$env = $vars[$envKey];
6062
}
6163

6264
if ($input->getOption('empty')) {
63-
$vars = ['APP_ENV' => $env];
65+
$vars = [$envKey => $env];
6466
}
6567

6668
$vars = var_export($vars, true);
@@ -79,7 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7981
return 0;
8082
}
8183

82-
private function loadEnv(string $path, ?string $env): array
84+
private function loadEnv(string $path, ?string $env, array $runtime): array
8385
{
8486
if (!file_exists($autoloadFile = $this->config->get('vendor-dir').'/autoload.php')) {
8587
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
9193
throw new \RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
9294
}
9395

96+
$envKey = $runtime['env_var_name'] ?? 'APP_ENV';
9497
$globalsBackup = [$_SERVER, $_ENV];
95-
unset($_SERVER['APP_ENV']);
96-
$_ENV = ['APP_ENV' => $env];
98+
unset($_SERVER[$envKey]);
99+
$_ENV = [$envKey => $env];
97100
$_SERVER['SYMFONY_DOTENV_VARS'] = implode(',', array_keys($_SERVER));
98101
putenv('SYMFONY_DOTENV_VARS='.$_SERVER['SYMFONY_DOTENV_VARS']);
99102

@@ -105,18 +108,17 @@ private function loadEnv(string $path, ?string $env): array
105108
}
106109

107110
if (!$env && file_exists($p = "$path.local")) {
108-
$env = $_ENV['APP_ENV'] = $dotenv->parse(file_get_contents($p), $p)['APP_ENV'] ?? null;
111+
$env = $_ENV[$envKey] = $dotenv->parse(file_get_contents($p), $p)[$envKey] ?? null;
109112
}
110113

111114
if (!$env) {
112-
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.');
115+
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));
113116
}
114117

115-
$config = @json_decode(file_get_contents(Factory::getComposerFile()), true);
116-
$testEnvs = $config['extra']['runtime']['test_envs'] ?? ['test'];
118+
$testEnvs = $runtime['test_envs'] ?? ['test'];
117119

118120
if (method_exists($dotenv, 'loadEnv')) {
119-
$dotenv->loadEnv($path, 'APP_ENV', 'dev', $testEnvs);
121+
$dotenv->loadEnv($path, $envKey, 'dev', $testEnvs);
120122
} else {
121123
// fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added)
122124
$dotenv->load(file_exists($path) || !file_exists($p = "$path.dist") ? $path : $p);

src/Command/InstallRecipesCommand.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Composer\Command\BaseCommand;
1515
use Composer\DependencyResolver\Operation\InstallOperation;
16+
use Composer\Util\ProcessExecutor;
1617
use Symfony\Component\Console\Exception\RuntimeException;
1718
use Symfony\Component\Console\Input\InputArgument;
1819
use Symfony\Component\Console\Input\InputInterface;
@@ -26,11 +27,13 @@ class InstallRecipesCommand extends BaseCommand
2627
/** @var Flex */
2728
private $flex;
2829
private $rootDir;
30+
private $dotenvPath;
2931

30-
public function __construct(/* cannot be type-hinted */ $flex, string $rootDir)
32+
public function __construct(/* cannot be type-hinted */ $flex, string $rootDir, string $dotenvPath = '.env')
3133
{
3234
$this->flex = $flex;
3335
$this->rootDir = $rootDir;
36+
$this->dotenvPath = $dotenvPath;
3437

3538
parent::__construct();
3639
}
@@ -120,12 +123,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
120123
$operations[] = new InstallOperation($pkg);
121124
}
122125

123-
if ($createEnvLocal = $force && file_exists($this->rootDir.'/.env') && file_exists($this->rootDir.'/.env.dist') && !file_exists($this->rootDir.'/.env.local')) {
124-
rename($this->rootDir.'/.env', $this->rootDir.'/.env.local');
126+
$dotenvFile = $this->dotenvPath;
127+
$dotenvPath = $this->rootDir.'/'.$dotenvFile;
128+
129+
if ($createEnvLocal = $force && file_exists($dotenvPath) && file_exists($dotenvPath.'.dist') && !file_exists($dotenvPath.'.local')) {
130+
rename($dotenvPath, $dotenvPath.'.local');
125131
$pipes = [];
126-
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));
132+
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));
127133
if (file_exists($this->rootDir.'/phpunit.xml.dist')) {
128-
touch($this->rootDir.'/.env.test');
134+
touch($dotenvPath.'.test');
129135
}
130136
}
131137

@@ -156,8 +162,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
156162
$output[] = '';
157163

158164
if ($createEnvLocal) {
165+
$root = '.' !== $this->rootDir ? $this->rootDir.'/' : '';
159166
$output[] = ' To revert the changes made to .env files, run';
160-
$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');
167+
$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'));
161168
$output[] = '';
162169
}
163170

src/Configurator/EnvConfigurator.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function configure(Recipe $recipe, $vars, Lock $lock, array $options = []
2525
$this->write('Adding environment variable defaults');
2626

2727
$this->configureEnvDist($recipe, $vars, $options['force'] ?? false);
28-
if (!file_exists($this->options->get('root-dir').'/.env.test')) {
28+
if (!file_exists($this->options->get('root-dir').'/'.($this->options->get('runtime')['dotenv_path'] ?? '.env').'.test')) {
2929
$this->configurePhpUnit($recipe, $vars, $options['force'] ?? false);
3030
}
3131
}
@@ -49,7 +49,9 @@ public function update(RecipeUpdate $recipeUpdate, array $originalConfig, array
4949

5050
private function configureEnvDist(Recipe $recipe, $vars, bool $update)
5151
{
52-
foreach (['.env.dist', '.env'] as $file) {
52+
$dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env';
53+
54+
foreach ([$dotenvPath.'.dist', $dotenvPath] as $file) {
5355
$env = $this->options->get('root-dir').'/'.$file;
5456
if (!is_file($env)) {
5557
continue;
@@ -133,7 +135,9 @@ private function configurePhpUnit(Recipe $recipe, $vars, bool $update)
133135

134136
private function unconfigureEnvFiles(Recipe $recipe, $vars)
135137
{
136-
foreach (['.env', '.env.dist'] as $file) {
138+
$dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env';
139+
140+
foreach ([$dotenvPath, $dotenvPath.'.dist'] as $file) {
137141
$env = $this->options->get('root-dir').'/'.$file;
138142
if (!file_exists($env)) {
139143
continue;
@@ -200,7 +204,8 @@ private function generateRandomBytes($length = 16)
200204

201205
private function getContentsAfterApplyingRecipe(string $rootDir, Recipe $recipe, array $vars): array
202206
{
203-
$files = ['.env', '.env.dist', 'phpunit.xml.dist', 'phpunit.xml'];
207+
$dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env';
208+
$files = [$dotenvPath, $dotenvPath.'.dist', 'phpunit.xml.dist', 'phpunit.xml'];
204209

205210
if (0 === \count($vars)) {
206211
return array_fill_keys($files, null);
@@ -217,7 +222,7 @@ private function getContentsAfterApplyingRecipe(string $rootDir, Recipe $recipe,
217222
true
218223
);
219224

220-
if (!file_exists($rootDir.'/.env.test')) {
225+
if (!file_exists($rootDir.'/'.$dotenvPath.'.test')) {
221226
$this->configurePhpUnit(
222227
$recipe,
223228
$vars,

src/Configurator/MakefileConfigurator.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ private function configureMakefile(Recipe $recipe, array $definitions, bool $upd
7171
$data = "\n".ltrim($data, "\r\n");
7272

7373
if (!file_exists($makefile)) {
74+
$envKey = $this->options->get('runtime')['env_var_name'] ?? 'APP_ENV';
75+
$dotenvPath = $this->options->get('runtime')['dotenv_path'] ?? '.env';
7476
file_put_contents(
7577
$this->options->get('root-dir').'/Makefile',
7678
<<<EOF
77-
ifndef APP_ENV
78-
include .env
79+
ifndef {$envKey}
80+
include {$dotenvPath}
7981
endif
8082
8183
.DEFAULT_GOAL := help

src/Downloader.php

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ class Downloader
4545
private $degradedMode = false;
4646
private $endpoints;
4747
private $index;
48+
private $conflicts;
4849
private $legacyEndpoint;
4950
private $caFile;
5051
private $enabled = true;
52+
private $composer;
5153

5254
public function __construct(Composer $composer, IoInterface $io, HttpDownloader $rfs)
5355
{
@@ -90,6 +92,7 @@ public function __construct(Composer $composer, IoInterface $io, HttpDownloader
9092
$this->rfs = $rfs;
9193
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/flex');
9294
$this->sess = bin2hex(random_bytes(16));
95+
$this->composer = $composer;
9396
}
9497

9598
public function getSessionId(): string
@@ -130,6 +133,22 @@ public function getRecipes(array $operations): array
130133
{
131134
$this->initialize();
132135

136+
if ($this->conflicts) {
137+
$lockedRepository = $this->composer->getLocker()->getLockedRepository();
138+
foreach ($this->conflicts as $conflicts) {
139+
foreach ($conflicts as $package => $versions) {
140+
foreach ($versions as $version => $conflicts) {
141+
foreach ($conflicts as $conflictingPackage => $constraint) {
142+
if ($lockedRepository->findPackage($conflictingPackage, $constraint)) {
143+
unset($this->index[$package][$version]);
144+
}
145+
}
146+
}
147+
}
148+
}
149+
$this->conflicts = [];
150+
}
151+
133152
$data = [];
134153
$urls = [];
135154
$chunk = '';
@@ -178,32 +197,47 @@ public function getRecipes(array $operations): array
178197
$version = $version[0].'.'.($version[1] ?? '9999999');
179198

180199
foreach (array_reverse($recipeVersions) as $v => $endpoint) {
181-
if (version_compare($version, $v, '>=')) {
182-
$data['locks'][$package->getName()]['version'] = $version;
183-
$data['locks'][$package->getName()]['recipe']['version'] = $v;
200+
if (version_compare($version, $v, '<')) {
201+
continue;
202+
}
184203

185-
if (null !== $recipeRef && isset($this->endpoints[$endpoint]['_links']['archived_recipes_template'])) {
186-
$urls[] = strtr($this->endpoints[$endpoint]['_links']['archived_recipes_template'], [
187-
'{package_dotted}' => str_replace('/', '.', $package->getName()),
188-
'{ref}' => $recipeRef,
189-
]);
204+
$data['locks'][$package->getName()]['version'] = $version;
205+
$data['locks'][$package->getName()]['recipe']['version'] = $v;
206+
$links = $this->endpoints[$endpoint]['_links'];
190207

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

194-
$urls[] = strtr($this->endpoints[$endpoint]['_links']['recipe_template'], [
213+
$urls[] = strtr($links['archived_recipes_template'], [
195214
'{package_dotted}' => str_replace('/', '.', $package->getName()),
196-
'{package}' => $package->getName(),
197-
'{version}' => $v,
215+
'{ref}' => $recipeRef,
198216
]);
199217

200218
break;
201219
}
220+
221+
if (isset($links['recipes_template_relative'])) {
222+
$links['recipes_template'] = preg_replace('{[^/\?]*+(?=\?|$)}', $links['recipes_template_relative'], $endpoint, 1);
223+
}
224+
225+
$urls[] = strtr($links['recipe_template'], [
226+
'{package_dotted}' => str_replace('/', '.', $package->getName()),
227+
'{package}' => $package->getName(),
228+
'{version}' => $v,
229+
]);
230+
231+
break;
202232
}
203233

204234
continue;
205235
}
206236

237+
if (\is_array($recipeVersions)) {
238+
$data['conflicts'][$package->getName()] = true;
239+
}
240+
207241
if (null !== $this->endpoints) {
208242
$data['locks'][$package->getName()]['version'] = $version;
209243
continue;
@@ -298,6 +332,11 @@ private function get(array $urls, bool $isRecipe = false, int $try = 3): array
298332

299333
if (preg_match('{^https?://api\.github\.com/}', $url)) {
300334
$headers[] = 'Accept: application/vnd.github.v3.raw';
335+
} elseif (preg_match('{^https?://raw\.githubusercontent\.com/}', $url) && $this->io->hasAuthentication('github.com')) {
336+
$auth = $this->io->getAuthentication('github.com');
337+
if ('x-oauth-basic' === $auth['password']) {
338+
$headers[] = 'Authorization: token '.$auth['username'];
339+
}
301340
} elseif ($this->legacyEndpoint) {
302341
$headers[] = 'Package-Session: '.$this->sess;
303342
}
@@ -410,9 +449,10 @@ private function initialize()
410449
foreach ($config['recipes'] ?? [] as $package => $versions) {
411450
$this->index[$package] = $this->index[$package] ?? array_fill_keys($versions, $endpoint);
412451
}
452+
$this->conflicts[] = $config['recipe-conflicts'] ?? [];
413453
self::$versions += $config['versions'] ?? [];
414454
self::$aliases += $config['aliases'] ?? [];
415-
unset($config['recipes'], $config['versions'], $config['aliases']);
455+
unset($config['recipes'], $config['recipe-conflicts'], $config['versions'], $config['aliases']);
416456
$this->endpoints[$endpoint] = $config;
417457
}
418458
}

0 commit comments

Comments
 (0)