Merge branch '2.2' into main

main
Jordi Boggiano 2 years ago
commit 5122bd42fb
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC

@ -13,7 +13,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/stale@v3
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 180

@ -81,14 +81,14 @@ jobs:
# This step requires a secret token with `pull` access to composer/docker. The default
# secrets.GITHUB_TOKEN is scoped to this repository only which is not sufficient.
- name: "Open issue @ Docker repository"
uses: actions/github-script@v2
uses: actions/github-script@v6
with:
github-token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}
script: |
// github.ref value looks like 'refs/tags/TAG', cleanup
const tag = "${{ github.ref }}".replace(/refs\/tags\//, '');
// create new issue on Docker repository
github.issues.create({
github.rest.issues.create({
owner: "${{ github.repository_owner }}",
repo: "docker",
title: `New Composer tag: ${ tag }`,

@ -1,3 +1,11 @@
### [2.2.8] 2022-03-15
* Fixed `files` autoloading sort order to be fully deterministic (#10617)
* Fixed pool optimization pass edge cases (#10579)
* Fixed `require` command failing when `self.version` is used as constraint (#10593)
* Fixed --no-ansi / undecorated output still showing color in repo warnings (#10601)
* Performance improvement in pool optimization step (composer/semver#131)
### [2.2.7] 2022-02-25
* Allow installation together with composer/xdebug-handler ^3 (#10528)
@ -1394,6 +1402,7 @@
* Initial release
[2.2.8]: https://github.com/composer/composer/compare/2.2.7...2.2.8
[2.2.7]: https://github.com/composer/composer/compare/2.2.6...2.2.7
[2.2.6]: https://github.com/composer/composer/compare/2.2.5...2.2.6
[2.2.5]: https://github.com/composer/composer/compare/2.2.4...2.2.5

12
composer.lock generated

@ -224,16 +224,16 @@
},
{
"name": "composer/semver",
"version": "3.2.9",
"version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649"
"reference": "f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649",
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649",
"url": "https://api.github.com/repos/composer/semver/zipball/f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b",
"reference": "f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b",
"shasum": ""
},
"require": {
@ -285,7 +285,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.9"
"source": "https://github.com/composer/semver/tree/3.3.0"
},
"funding": [
{
@ -301,7 +301,7 @@
"type": "tidelift"
}
],
"time": "2022-02-04T13:58:43+00:00"
"time": "2022-03-15T08:35:57+00:00"
},
{
"name": "composer/spdx-licenses",

@ -323,6 +323,13 @@ hint to Composer that the plugin should be installed on its own before proceedin
the rest of the package downloads. This slightly slows down the overall installation
process however, so do not use it in plugins which do not absolutely require it.
## Plugin Autoloading
Due to plugins being loaded by Composer at runtime, and to ensure that plugins which
depend on other packages can function correctly, a runtime autoloader is created whenever
a plugin is loaded. That autoloader is only configured to load with the plugin dependencies,
so you may not have access to all the packages which are installed.
[1]: ../04-schema.md#type
[2]: ../04-schema.md#extra
[3]: https://github.com/composer/composer/blob/main/src/Composer/Plugin/PluginInterface.php

@ -1334,7 +1334,7 @@ INITIALIZER;
/**
* Sorts packages by dependency weight
*
* Packages of equal weight retain the original order
* Packages of equal weight are sorted alphabetically
*
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap
* @return array<int, array{0: PackageInterface, 1: string}>

@ -225,6 +225,9 @@ EOT
return 1;
}
if ($constraint === 'self.version') {
continue;
}
$versionParser->parseConstraints($constraint);
}

@ -110,21 +110,18 @@ class PoolOptimizer
// Extract requested package requirements
foreach ($request->getRequires() as $require => $constraint) {
$constraint = Intervals::compactConstraint($constraint);
$this->requireConstraintsPerPackage[$require][(string) $constraint] = $constraint;
$this->extractRequireConstraintsPerPackage($require, $constraint);
}
// First pass over all packages to extract information and mark package constraints irremovable
foreach ($pool->getPackages() as $package) {
// Extract package requirements
foreach ($package->getRequires() as $link) {
$constraint = Intervals::compactConstraint($link->getConstraint());
$this->requireConstraintsPerPackage[$link->getTarget()][(string) $constraint] = $constraint;
$this->extractRequireConstraintsPerPackage($link->getTarget(), $link->getConstraint());
}
// Extract package conflicts
foreach ($package->getConflicts() as $link) {
$constraint = Intervals::compactConstraint($link->getConstraint());
$this->conflictConstraintsPerPackage[$link->getTarget()][(string) $constraint] = $constraint;
$this->extractConflictConstraintsPerPackage($link->getTarget(), $link->getConstraint());
}
// Keep track of alias packages for every package so if either the alias or aliased is kept
@ -452,4 +449,55 @@ class PoolOptimizer
}
}
}
/**
* Disjunctive require constraints need to be considered in their own group. E.g. "^2.14 || ^3.3" needs to generate
* two require constraint groups in order for us to keep the best matching package for "^2.14" AND "^3.3" as otherwise, we'd
* only keep either one which can cause trouble (e.g. when using --prefer-lowest).
*
* @param string $package
* @param ConstraintInterface $constraint
* @return void
*/
private function extractRequireConstraintsPerPackage($package, ConstraintInterface $constraint)
{
foreach ($this->expandDisjunctiveMultiConstraints($constraint) as $expanded) {
$this->requireConstraintsPerPackage[$package][(string) $expanded] = $expanded;
}
}
/**
* Disjunctive conflict constraints need to be considered in their own group. E.g. "^2.14 || ^3.3" needs to generate
* two conflict constraint groups in order for us to keep the best matching package for "^2.14" AND "^3.3" as otherwise, we'd
* only keep either one which can cause trouble (e.g. when using --prefer-lowest).
*
* @param string $package
* @param ConstraintInterface $constraint
* @return void
*/
private function extractConflictConstraintsPerPackage($package, ConstraintInterface $constraint)
{
foreach ($this->expandDisjunctiveMultiConstraints($constraint) as $expanded) {
$this->conflictConstraintsPerPackage[$package][(string) $expanded] = $expanded;
}
}
/**
*
* @param ConstraintInterface $constraint
* @return ConstraintInterface[]
*/
private function expandDisjunctiveMultiConstraints(ConstraintInterface $constraint)
{
$constraint = Intervals::compactConstraint($constraint);
if ($constraint instanceof MultiConstraint && $constraint->isDisjunctive()) {
// No need to call ourselves recursively here because Intervals::compactConstraint() ensures that there
// are no nested disjunctive MultiConstraint instances possible
return $constraint->getConstraints();
}
// Regular constraints and conjunctive MultiConstraints
return array($constraint);
}
}

@ -473,6 +473,11 @@ class Installer
return $exitCode;
}
// exists as of composer/semver 3.3.0
if (method_exists('Composer\Semver\CompilingMatcher', 'clear')) { // @phpstan-ignore-line
\Composer\Semver\CompilingMatcher::clear();
}
// write lock
$platformReqs = $this->extractPlatformRequirements($this->package->getRequires());
$platformDevReqs = $this->extractPlatformRequirements($this->package->getDevRequires());

@ -428,6 +428,14 @@ class HttpDownloader
*/
public static function outputWarnings(IOInterface $io, string $url, $data): void
{
$cleanMessage = function ($msg) use ($io) {
if (!$io->isDecorated()) {
$msg = Preg::replace('{'.chr(27).'\\[[;\d]*m}u', '', $msg);
}
return $msg;
};
// legacy warning/info keys
foreach (array('warning', 'info') as $type) {
if (empty($data[$type])) {
@ -443,7 +451,7 @@ class HttpDownloader
}
}
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$data[$type].'</'.$type.'>');
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$cleanMessage($data[$type]).'</'.$type.'>');
}
// modern Composer 2.2+ format with support for multiple warning/info messages
@ -461,7 +469,7 @@ class HttpDownloader
continue;
}
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$spec['message'].'</'.$type.'>');
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$cleanMessage($spec['message']).'</'.$type.'>');
}
}
}

@ -13,13 +13,14 @@
namespace Composer\Util;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
class PackageSorter
{
/**
* Sorts packages by dependency weight
*
* Packages of equal weight retain the original order
* Packages of equal weight are sorted alphabetically
*
* @param PackageInterface[] $packages
* @return PackageInterface[] sorted array
@ -29,7 +30,11 @@ class PackageSorter
$usageList = array();
foreach ($packages as $package) {
foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) {
$links = $package->getRequires();
if ($package instanceof RootPackageInterface) {
$links = array_merge($links, $package->getDevRequires());
}
foreach ($links as $link) {
$target = $link->getTarget();
$usageList[$target][] = $package->getName();
}
@ -62,39 +67,26 @@ class PackageSorter
return $weight;
};
$weightList = array();
$weightedPackages = array();
foreach ($packages as $index => $package) {
$weight = $computeImportance($package->getName());
$weightList[$index] = $weight;
$name = $package->getName();
$weight = $computeImportance($name);
$weightedPackages[] = array('name' => $name, 'weight' => $weight, 'index' => $index);
}
$stable_sort = function (&$array): void {
static $transform, $restore;
$i = 0;
if (!$transform) {
$transform = function (&$v, $k) use (&$i): void {
$v = array($v, ++$i, $k, $v);
};
$restore = function (&$v): void {
$v = $v[3];
};
usort($weightedPackages, function (array $a, array $b): int {
if ($a['weight'] !== $b['weight']) {
return $a['weight'] - $b['weight'];
}
array_walk($array, $transform);
asort($array);
array_walk($array, $restore);
};
$stable_sort($weightList);
return strnatcasecmp($a['name'], $b['name']);
});
$sortedPackages = array();
foreach (array_keys($weightList) as $index) {
$sortedPackages[] = $packages[$index];
foreach ($weightedPackages as $pkg) {
$sortedPackages[] = $packages[$pkg['index']];
}
return $sortedPackages;

@ -1010,6 +1010,14 @@ EOF;
$packages[] = $c = new Package('c/lorem', '1.0', '1.0');
$packages[] = $e = new Package('e/e', '1.0', '1.0');
// expected order:
// c requires nothing
// d requires c
// b requires c & d
// e requires c
// z requires c
// (b, e, z ordered alphabetically)
$z->setAutoload(array('files' => array('testA.php')));
$z->setRequires(array('c/lorem' => new Link('z/foo', 'c/lorem', new MatchAllConstraint())));

@ -9,9 +9,9 @@ class ComposerStaticInitFilesAutoloadOrder
public static $files = array (
'bfdd693009729d60c830ff8d79129635' => __DIR__ . '/..' . '/c/lorem/testC.php',
'61e6098c8cafe404d6cf19e59fc2b788' => __DIR__ . '/..' . '/d/d/testD.php',
'8bceec6fdc149a1a6acbf7ad3cfed51c' => __DIR__ . '/..' . '/z/foo/testA.php',
'c5466e580c6c2403f225c43b6a21a96f' => __DIR__ . '/..' . '/b/bar/testB.php',
'69dfc37c40a853a7cbac6c9d2367c5f4' => __DIR__ . '/..' . '/e/e/testE.php',
'8bceec6fdc149a1a6acbf7ad3cfed51c' => __DIR__ . '/..' . '/z/foo/testA.php',
'ab280164f4754f5dfdb0721de84d737f' => __DIR__ . '/../..' . '/root2.php',
);

@ -15,7 +15,7 @@ Test filters irrelevant package "package/b" in version 1.0.0
"name": "package/a",
"version": "1.0.0",
"require": {
"package/b": "^1.0"
"package/b": ">=1.0 <1.1 || ^1.2"
}
},
{
@ -25,6 +25,10 @@ Test filters irrelevant package "package/b" in version 1.0.0
{
"name": "package/b",
"version": "1.0.1"
},
{
"name": "package/b",
"version": "1.2.0"
}
]
@ -41,6 +45,10 @@ Test filters irrelevant package "package/b" in version 1.0.0
{
"name": "package/b",
"version": "1.0.1"
},
{
"name": "package/b",
"version": "1.2.0"
}
]

@ -0,0 +1,55 @@
--TEST--
Test keeps package "package/b" in version 2.2.0 because for prefer-lowest either one might be relevant
--REQUEST--
{
"require": {
"package/a": "^1.0"
},
"preferLowest": true
}
--POOL-BEFORE--
[
{
"name": "package/a",
"version": "1.0.0",
"require": {
"package/b": "^1.0 || ^2.2"
}
},
{
"name": "package/b",
"version": "1.0.0"
},
{
"name": "package/b",
"version": "1.0.1"
},
{
"name": "package/b",
"version": "2.2.0"
}
]
--POOL-AFTER--
[
{
"name": "package/a",
"version": "1.0.0",
"require": {
"package/b": "^1.0"
}
},
{
"name": "package/b",
"version": "1.0.0"
},
{
"name": "package/b",
"version": "2.2.0"
}
]

@ -11,7 +11,7 @@ update
!!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/container","psr/log","psr/log-implementation","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/deprecation-contracts","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-intl-grapheme","symfony/polyfill-intl-normalizer","symfony/polyfill-mbstring","symfony/polyfill-php73","symfony/polyfill-php80","symfony/process","symfony/service-contracts","symfony/string"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
Loading composer repositories with package information
Updating dependencies
%((Info|Warning) from .*\n)?%Updating dependencies
Lock file operations: 6 installs, 0 updates, 0 removals
- Locking plugin/a (1.1.1)
- Locking plugin/b (2.2.2)

@ -17,7 +17,7 @@ update plugin/* symfony/console symfony/filesystem symfony/process
!!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/container","psr/log","psr/log-implementation","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/deprecation-contracts","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-intl-grapheme","symfony/polyfill-intl-normalizer","symfony/polyfill-mbstring","symfony/polyfill-php73","symfony/polyfill-php80","symfony/process","symfony/service-contracts","symfony/string","plugin/a","plugin/b","root/pkg"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
Loading composer repositories with package information
Updating dependencies
%((Info|Warning) from .*\n)?%Updating dependencies
Lock file operations: 0 installs, 5 updates, 0 removals
- Upgrading plugin/a (1.1.1 => 1.1.2)
- Upgrading plugin/b (2.2.2 => 2.2.3)

@ -99,6 +99,34 @@ class PackageSorterTest extends TestCase
'foo/bar6',
),
),
'circular deps sorted alphabetically if weighted equally' => array(
array(
$this->createPackage('foo/bar1', array('circular/part1')),
$this->createPackage('foo/bar2', array('circular/part2')),
$this->createPackage('circular/part1', array('circular/part2')),
$this->createPackage('circular/part2', array('circular/part1')),
),
array(
'circular/part1',
'circular/part2',
'foo/bar1',
'foo/bar2',
),
),
'equal weight sorted alphabetically' => array(
array(
$this->createPackage('foo/bar10', array('foo/dep')),
$this->createPackage('foo/bar2', array('foo/dep')),
$this->createPackage('foo/baz', array('foo/dep')),
$this->createPackage('foo/dep', array()),
),
array(
'foo/dep',
'foo/bar2',
'foo/bar10',
'foo/baz',
),
),
);
}

Loading…
Cancel
Save