Merge branch '2.2' into main
commit
5122bd42fb
|
@ -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
|
||||
|
|
|
@ -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…
Reference in New Issue