1
0
Fork 0

Merge branch '2.2' into main

pull/10542/head
Jordi Boggiano 2022-02-16 16:05:05 +01:00
commit 40de07569d
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
6 changed files with 76 additions and 35 deletions

View File

@ -46,7 +46,9 @@ Composer fires the following named events during its execution process:
### Installer Events ### Installer Events
- **pre-operations-exec**: occurs before the install/upgrade/.. operations - **pre-operations-exec**: occurs before the install/upgrade/.. operations
are executed when installing a lock file. are executed when installing a lock file. Plugins that need to hook into
this event will need to be installed globally to be usable, as otherwise
they would not be loaded yet when a fresh install of a project happens.
### Package Events ### Package Events

View File

@ -3,7 +3,9 @@
Certain Composer commands, including `exec`, `install`, and `update` allow third party code to Certain Composer commands, including `exec`, `install`, and `update` allow third party code to
execute on your system. This is from its "plugins" and "scripts" features. Plugins and scripts have execute on your system. This is from its "plugins" and "scripts" features. Plugins and scripts have
full access to the user account which runs Composer. For this reason, it is strongly advised to full access to the user account which runs Composer. For this reason, it is strongly advised to
**avoid running Composer as super-user/root**. **avoid running Composer as super-user/root**. All commands also dispatch events which can be
caught by plugins so unless explicitly disabled installed plugins will be loaded/executed by **every**
Composer command.
You can disable plugins and scripts during package installation or updates with the following You can disable plugins and scripts during package installation or updates with the following
syntax so only Composer's code, and no third party code, will execute: syntax so only Composer's code, and no third party code, will execute:
@ -13,10 +15,11 @@ php composer.phar install --no-plugins --no-scripts ...
php composer.phar update --no-plugins --no-scripts ... php composer.phar update --no-plugins --no-scripts ...
``` ```
The `exec` command will always run third party code as the user which runs `composer`. Depending on the operating system we have seen cases where it is possible to trigger execution
of files in the repository using specially crafted `composer.json`. So in general if you do want
to install untrusted dependencies you should sandbox them completely in a container or equivalent.
In some cases, like in CI systems or such where you want to install untrusted dependencies, the Also note that the `exec` command will always run third party code as the user which runs `composer`.
safest way to do it is to run the above command.
See [Environment variable - COMPOSER_ALLOW_SUPERUSER](../03-cli.md#composer-allow-superuser) See [Environment variable - COMPOSER_ALLOW_SUPERUSER](../03-cli.md#composer-allow-superuser)
for more info on how to disable warning for more info on how to disable warning

View File

@ -95,12 +95,6 @@ trait PackageDiscoveryTrait
$requirement['version'], $requirement['version'],
$requirement['name'] $requirement['name']
)); ));
} else {
// check that the specified version/constraint exists before we proceed
list($name) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed);
// replace package name from packagist.org
$requirement['name'] = $name;
} }
$result[] = $requirement['name'] . ' ' . $requirement['version']; $result[] = $requirement['name'] . ' ' . $requirement['version'];
@ -139,20 +133,8 @@ trait PackageDiscoveryTrait
$matches = array_values($matches); $matches = array_values($matches);
$exactMatch = false; $exactMatch = false;
$choices = array(); foreach ($matches as $match) {
foreach ($matches as $position => $foundPackage) { if ($match['name'] === $package) {
$abandoned = '';
if (isset($foundPackage['abandoned'])) {
if (is_string($foundPackage['abandoned'])) {
$replacement = sprintf('Use %s instead', $foundPackage['abandoned']);
} else {
$replacement = 'No replacement was suggested';
}
$abandoned = sprintf('<warning>Abandoned. %s.</warning>', $replacement);
}
$choices[] = sprintf(' <info>%5s</info> %s %s', "[$position]", $foundPackage['name'], $abandoned);
if ($foundPackage['name'] === $package) {
$exactMatch = true; $exactMatch = true;
break; break;
} }
@ -160,6 +142,26 @@ trait PackageDiscoveryTrait
// no match, prompt which to pick // no match, prompt which to pick
if (!$exactMatch) { if (!$exactMatch) {
$providers = $this->getRepos()->getProviders($package);
if (count($providers) > 0) {
array_unshift($matches, array('name' => $package, 'description' => ''));
}
$choices = array();
foreach ($matches as $position => $foundPackage) {
$abandoned = '';
if (isset($foundPackage['abandoned'])) {
if (is_string($foundPackage['abandoned'])) {
$replacement = sprintf('Use %s instead', $foundPackage['abandoned']);
} else {
$replacement = 'No replacement was suggested';
}
$abandoned = sprintf('<warning>Abandoned. %s.</warning>', $replacement);
}
$choices[] = sprintf(' <info>%5s</info> %s %s', "[$position]", $foundPackage['name'], $abandoned);
}
$io->writeError(array( $io->writeError(array(
'', '',
sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package), sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
@ -257,7 +259,8 @@ trait PackageDiscoveryTrait
$platformRequirementFilter = $this->getPlatformRequirementFilter($input); $platformRequirementFilter = $this->getPlatformRequirementFilter($input);
// find the latest version allowed in this repo set // find the latest version allowed in this repo set
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo); $repoSet = $this->getRepositorySet($input, $minimumStability);
$versionSelector = new VersionSelector($repoSet, $platformRepo);
$effectiveMinimumStability = $minimumStability ?? $this->getMinimumStability($input); $effectiveMinimumStability = $minimumStability ?? $this->getMinimumStability($input);
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter); $package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter);
@ -269,6 +272,22 @@ trait PackageDiscoveryTrait
return array($name, $requiredVersion ?: '*'); return array($name, $requiredVersion ?: '*');
} }
// Check if it is a virtual package provided by others
$providers = $repoSet->getProviders($name);
if (count($providers) > 0) {
$constraint = '*';
if ($input->isInteractive()) {
$constraint = $this->getIO()->askAndValidate('Package "<info>'.$name.'</info>" does not exist but is provided by '.count($providers).' packages. Which version constraint would you like to use? [<info>*</info>] ', function ($value) {
$parser = new VersionParser();
$parser->parseConstraints($value);
return $value;
}, 3, '*');
}
return array($name, $constraint);
}
// Check whether the package requirements were the problem // Check whether the package requirements were the problem
if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && false !== ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) { if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && false !== ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(

View File

@ -20,6 +20,9 @@ use Composer\Util\ComposerMirror;
* Core package definitions that are needed to resolve dependencies and install packages * Core package definitions that are needed to resolve dependencies and install packages
* *
* @author Nils Adermann <naderman@naderman.de> * @author Nils Adermann <naderman@naderman.de>
*
* @phpstan-import-type AutoloadRules from PackageInterface
* @phpstan-import-type DevAutoloadRules from PackageInterface
*/ */
class Package extends BasePackage class Package extends BasePackage
{ {
@ -79,9 +82,15 @@ class Package extends BasePackage
protected $devRequires = array(); protected $devRequires = array();
/** @var array<string, string> */ /** @var array<string, string> */
protected $suggests = array(); protected $suggests = array();
/** @var array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} */ /**
* @var array
* @phpstan-var AutoloadRules
*/
protected $autoload = array(); protected $autoload = array();
/** @var array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} */ /**
* @var array
* @phpstan-var DevAutoloadRules
*/
protected $devAutoload = array(); protected $devAutoload = array();
/** @var string[] */ /** @var string[] */
protected $includePaths = array(); protected $includePaths = array();
@ -598,7 +607,7 @@ class Package extends BasePackage
* *
* @return void * @return void
* *
* @phpstan-param array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} $autoload * @phpstan-param AutoloadRules $autoload
*/ */
public function setAutoload(array $autoload) public function setAutoload(array $autoload)
{ {
@ -620,7 +629,7 @@ class Package extends BasePackage
* *
* @return void * @return void
* *
* @phpstan-param array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} $devAutoload * @phpstan-param DevAutoloadRules $devAutoload
*/ */
public function setDevAutoload(array $devAutoload) public function setDevAutoload(array $devAutoload)
{ {

View File

@ -18,6 +18,9 @@ use Composer\Repository\RepositoryInterface;
* Defines the essential information a package has that is used during solving/installation * Defines the essential information a package has that is used during solving/installation
* *
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*
* @phpstan-type AutoloadRules array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>, exclude-from-classmap?: list<string>}
* @phpstan-type DevAutoloadRules array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>}
*/ */
interface PackageInterface interface PackageInterface
{ {
@ -303,7 +306,7 @@ interface PackageInterface
* directories for autoloading using the type specified. * directories for autoloading using the type specified.
* *
* @return array Mapping of autoloading rules * @return array Mapping of autoloading rules
* @phpstan-return array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} * @phpstan-return AutoloadRules
*/ */
public function getAutoload(); public function getAutoload();
@ -316,7 +319,7 @@ interface PackageInterface
* directories for autoloading using the type specified. * directories for autoloading using the type specified.
* *
* @return array Mapping of dev autoloading rules * @return array Mapping of dev autoloading rules
* @phpstan-return array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} * @phpstan-return DevAutoloadRules
*/ */
public function getDevAutoload(); public function getDevAutoload();

View File

@ -16,6 +16,9 @@ namespace Composer\Package;
* Defines additional fields that are only needed for the root package * Defines additional fields that are only needed for the root package
* *
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*
* @phpstan-import-type AutoloadRules from PackageInterface
* @phpstan-import-type DevAutoloadRules from PackageInterface
*/ */
interface RootPackageInterface extends CompletePackageInterface interface RootPackageInterface extends CompletePackageInterface
{ {
@ -122,7 +125,8 @@ interface RootPackageInterface extends CompletePackageInterface
/** /**
* Set the autoload mapping * Set the autoload mapping
* *
* @param array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} $autoload Mapping of autoloading rules * @param array $autoload Mapping of autoloading rules
* @phpstan-param AutoloadRules $autoload
* *
* @return void * @return void
*/ */
@ -131,7 +135,8 @@ interface RootPackageInterface extends CompletePackageInterface
/** /**
* Set the dev autoload mapping * Set the dev autoload mapping
* *
* @param array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} $devAutoload Mapping of dev autoloading rules * @param array $devAutoload Mapping of dev autoloading rules
* @phpstan-param DevAutoloadRules $devAutoload
* *
* @return void * @return void
*/ */