Merge branch 'master' into 2.0

main
Jordi Boggiano 6 years ago
commit 411dd51f20

@ -21,6 +21,11 @@ If your issue involves installing, updating or resolving dependencies, the
chance of us being able to reproduce your issue will be much higher if you
share your `composer.json` with us.
Coding Style Fixes
------------------
We do not accept CS fixes pull requests. Fixes are done by the project maintainers when appropriate to avoid causing too many unnecessary conflicts between branches and pull requests.
Security Reports
----------------

@ -1,3 +1,16 @@
### [1.8.0] 2018-12-03
* Changed `post-package-install` / `post-package-update` event to be fired *after* the lock file has been updated as opposed to before
* Added support for removing packages using a wildcard with the `remove` command, e.g. `composer remove foo/*`
* Added `chat` to the list of `support` channels you can list in composer.json
* Added signal handling on require command to restore the composer.json in case of abort
* Added `--ignore` to `outdated` command to pass one or more packages that you do not want to be listed
* Added `--no-dev` to `check-platform-reqs` command to skip dev requirements even if they are installed
* Added support for running plugin commands from sub-directories within a project much like other Composer commands
* Added support for running Composer via phpdbg
* Added `lib-imagick` platform package
* Fixed validate command always checking for disabled checks when used with `--strict`
### [1.7.3] 2018-11-01
* Fixed handling of replace/conflict rules. This may affect dependency resolution in some edge cases.
@ -696,6 +709,7 @@
* Initial release
[1.8.0]: https://github.com/composer/composer/compare/1.7.3...1.8.0
[1.7.3]: https://github.com/composer/composer/compare/1.7.2...1.7.3
[1.7.2]: https://github.com/composer/composer/compare/1.7.1...1.7.2
[1.7.1]: https://github.com/composer/composer/compare/1.7.0...1.7.1

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
if (PHP_SAPI !== 'cli') {
if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
echo 'Warning: Composer should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
}

@ -55,7 +55,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {

102
composer.lock generated

@ -126,16 +126,16 @@
},
{
"name": "composer/spdx-licenses",
"version": "1.4.0",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
"reference": "cb17687e9f936acd7e7245ad3890f953770dec1b"
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/cb17687e9f936acd7e7245ad3890f953770dec1b",
"reference": "cb17687e9f936acd7e7245ad3890f953770dec1b",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
"shasum": ""
},
"require": {
@ -183,20 +183,20 @@
"spdx",
"validator"
],
"time": "2018-04-30T10:33:04+00:00"
"time": "2018-11-01T09:45:54+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.3.0",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c"
"reference": "dc523135366eb68f22268d069ea7749486458562"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/b8e9745fb9b06ea6664d8872c4505fb16df4611c",
"reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562",
"reference": "dc523135366eb68f22268d069ea7749486458562",
"shasum": ""
},
"require": {
@ -227,7 +227,7 @@
"Xdebug",
"performance"
],
"time": "2018-08-31T19:20:00+00:00"
"time": "2018-11-29T10:59:02+00:00"
},
{
"name": "justinrainbow/json-schema",
@ -297,16 +297,16 @@
},
{
"name": "psr/log",
"version": "1.0.2",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"shasum": ""
},
"require": {
@ -340,7 +340,7 @@
"psr",
"psr-3"
],
"time": "2016-10-10T12:19:37+00:00"
"time": "2018-11-20T15:27:04+00:00"
},
{
"name": "seld/jsonlint",
@ -437,16 +437,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc"
"reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0c1fcbb9afb5cff992c982ff99c0434f0146dcfc",
"reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc",
"url": "https://api.github.com/repos/symfony/console/zipball/cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
"reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
"shasum": ""
},
"require": {
@ -494,20 +494,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T11:13:39+00:00"
"time": "2018-11-20T15:55:20+00:00"
},
{
"name": "symfony/debug",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "cbb8a5f212148964efbc414838c527229f9951b7"
"reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/cbb8a5f212148964efbc414838c527229f9951b7",
"reference": "cbb8a5f212148964efbc414838c527229f9951b7",
"url": "https://api.github.com/repos/symfony/debug/zipball/74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
"reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
"shasum": ""
},
"require": {
@ -551,20 +551,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-08-03T09:45:57+00:00"
"time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/filesystem",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "0b252f4e25b7da17abb5a98eb60755b71d082c9c"
"reference": "7ae46872dad09dffb7fe1e93a0937097339d0080"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/0b252f4e25b7da17abb5a98eb60755b71d082c9c",
"reference": "0b252f4e25b7da17abb5a98eb60755b71d082c9c",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7ae46872dad09dffb7fe1e93a0937097339d0080",
"reference": "7ae46872dad09dffb7fe1e93a0937097339d0080",
"shasum": ""
},
"require": {
@ -601,20 +601,20 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2018-08-07T09:12:42+00:00"
"time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/finder",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e"
"reference": "1444eac52273e345d9b95129bf914639305a9ba4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/f0de0b51913eb2caab7dfed6413b87e14fca780e",
"reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e",
"url": "https://api.github.com/repos/symfony/finder/zipball/1444eac52273e345d9b95129bf914639305a9ba4",
"reference": "1444eac52273e345d9b95129bf914639305a9ba4",
"shasum": ""
},
"require": {
@ -650,11 +650,11 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T11:13:39+00:00"
"time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.9.0",
"version": "v1.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@ -712,16 +712,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.9.0",
"version": "v1.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
"shasum": ""
},
"require": {
@ -767,20 +767,20 @@
"portable",
"shim"
],
"time": "2018-08-06T14:22:27+00:00"
"time": "2018-09-21T13:07:52+00:00"
},
{
"name": "symfony/process",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "4be278e19064c3492095de50c9e375caae569ae1"
"reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/4be278e19064c3492095de50c9e375caae569ae1",
"reference": "4be278e19064c3492095de50c9e375caae569ae1",
"url": "https://api.github.com/repos/symfony/process/zipball/c3591a09c78639822b0b290d44edb69bf9f05dc8",
"reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8",
"shasum": ""
},
"require": {
@ -816,7 +816,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2018-08-03T09:45:57+00:00"
"time": "2018-11-11T11:18:13+00:00"
}
],
"packages-dev": [
@ -1736,16 +1736,16 @@
},
{
"name": "symfony/yaml",
"version": "v2.8.45",
"version": "v2.8.48",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "fbf876678e29dc634430dcf0096e216eb0004467"
"reference": "02c1859112aa779d9ab394ae4f3381911d84052b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/fbf876678e29dc634430dcf0096e216eb0004467",
"reference": "fbf876678e29dc634430dcf0096e216eb0004467",
"url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b",
"reference": "02c1859112aa779d9ab394ae4f3381911d84052b",
"shasum": ""
},
"require": {
@ -1782,7 +1782,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T09:03:18+00:00"
"time": "2018-11-11T11:18:13+00:00"
}
],
"aliases": [],

@ -243,6 +243,7 @@ Support information includes the following:
* **source:** URL to browse or download the sources.
* **docs:** URL to the documentation.
* **rss:** URL to the RSS feed.
* **chat:** URL to the chat channel.
An example:

@ -238,6 +238,17 @@ one by prefixing the command name with `@`:
}
```
You can also refer a script and pass it new arguments:
```json
{
"scripts": {
"tests": "phpunit",
"testsVerbose": "@tests -vvv"
}
}
```
## Calling Composer commands
To call Composer commands, you can use `@composer` which will automatically

@ -490,6 +490,11 @@
"description": "IRC channel for support, as irc://server/channel.",
"format": "uri"
},
"chat": {
"type": "string",
"description": "URL to the support chat.",
"format": "uri"
},
"source": {
"type": "string",
"description": "URL to browse or download the sources.",

@ -22,6 +22,7 @@ use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory;
use Composer\Repository\RepositorySet;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@ -145,6 +146,11 @@ EOT
}
}
}
$question = 'Would you like to install dependencies now [<comment>yes</comment>]? ';
if ($input->isInteractive() && $this->hasDependencies($options) && $io->askConfirmation($question, true)) {
$this->installDependencies($output);
}
}
/**
@ -208,7 +214,7 @@ EOT
}
$name = strtolower($name);
} else {
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}', $name)) {
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $name)) {
throw new \InvalidArgumentException(
'The package name '.$name.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
);
@ -222,7 +228,7 @@ EOT
return $name;
}
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}', $value)) {
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) {
throw new \InvalidArgumentException(
'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
);
@ -381,7 +387,7 @@ EOT
return $this->repos;
}
protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), $phpVersion = null, $preferredStability = 'stable')
protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), $phpVersion = null, $preferredStability = 'stable', $checkProvidedVersions = true)
{
if ($requires) {
$requires = $this->normalizeRequirements($requires);
@ -404,7 +410,7 @@ EOT
));
} else {
// check that the specified version/constraint exists before we proceed
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $requirement['version'], 'dev');
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev');
// replace package name from packagist.org
$requirement['name'] = $name;
@ -767,4 +773,23 @@ EOT
return array_keys(array_slice($similarPackages, 0, 5));
}
private function installDependencies($output)
{
try {
$installCommand = $this->getApplication()->find('install');
$installCommand->run(new ArrayInput(array()), $output);
} catch (\Exception $e) {
$this->getIO()->writeError('Could not install dependencies. Run `composer install` to see more information.');
}
}
private function hasDependencies($options)
{
$requires = (array) $options['require'];
$devRequires = isset($options['require-dev']) ? (array) $options['require-dev'] : array();
return !empty($requires) || !empty($devRequires);
}
}

@ -22,6 +22,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\Package\BasePackage;
/**
* @author Pierre du Plessis <pdples@gmail.com>
@ -94,12 +95,25 @@ EOT
if (isset($composer[$type][$package])) {
$json->removeLink($type, $composer[$type][$package]);
} elseif (isset($composer[$altType][$package])) {
$io->writeError('<warning>'.$composer[$altType][$package].' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
$io->writeError('<warning>' . $composer[$altType][$package] . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
if ($io->isInteractive()) {
if ($io->askConfirmation('Do you want to remove it from '.$altType.' [<comment>yes</comment>]? ', true)) {
if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
$json->removeLink($altType, $composer[$altType][$package]);
}
}
} elseif (isset($composer[$type]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$type]))) {
foreach ($matches as $matchedPackage) {
$json->removeLink($type, $matchedPackage);
}
} elseif (isset($composer[$altType]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$altType]))) {
foreach ($matches as $matchedPackage) {
$io->writeError('<warning>' . $matchedPackage . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
if ($io->isInteractive()) {
if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
$json->removeLink($altType, $matchedPackage);
}
}
}
} else {
$io->writeError('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
}

@ -66,7 +66,7 @@ class RequireCommand extends InitCommand
<<<EOT
The require command adds required packages to your composer.json and installs them.
If you do not specify a package, composer will prompt you to search for a package, and given results, provide a list of
If you do not specify a package, composer will prompt you to search for a package, and given results, provide a list of
matches to require.
If you do not specify a version constraint, composer will choose a suitable one based on the available package versions.
@ -131,7 +131,7 @@ EOT
}
$phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion();
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability);
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update'));
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev';

@ -95,9 +95,10 @@ EOT
$lockErrors[] = 'The lock file is not up to date with the latest changes in composer.json, it is recommended that you run `composer update`.';
}
$this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true);
$this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true, $isStrict);
$exitCode = $errors || ($publishErrors && $checkPublish) || ($lockErrors && $checkLock) ? 2 : ($isStrict && $warnings ? 1 : 0);
// $errors include publish and lock errors when exists
$exitCode = $errors ? 2 : ($isStrict && $warnings ? 1 : 0);
if ($input->getOption('with-dependencies')) {
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
@ -108,7 +109,7 @@ EOT
list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
$this->outputResult($io, $package->getPrettyName(), $errors, $warnings, $checkPublish, $publishErrors);
$depCode = $errors || ($publishErrors && $checkPublish) ? 2 : ($isStrict && $warnings ? 1 : 0);
$depCode = $errors ? 2 : ($isStrict && $warnings ? 1 : 0);
$exitCode = max($depCode, $exitCode);
}
}
@ -121,7 +122,7 @@ EOT
return $exitCode;
}
private function outputResult($io, $name, &$errors, &$warnings, $checkPublish = false, $publishErrors = array(), $checkLock = false, $lockErrors = array(), $printSchemaUrl = false)
private function outputResult($io, $name, &$errors, &$warnings, $checkPublish = false, $publishErrors = array(), $checkLock = false, $lockErrors = array(), $printSchemaUrl = false, $isStrict = false)
{
if (!$errors && !$publishErrors && !$warnings) {
$io->write('<info>' . $name . ' is valid</info>');
@ -141,16 +142,18 @@ EOT
}
// If checking publish errors, display them as errors, otherwise just show them as warnings
// Skip when it is a strict check and we don't want to check publish errors
if ($checkPublish) {
$errors = array_merge($errors, $publishErrors);
} else {
} elseif (!$isStrict) {
$warnings = array_merge($warnings, $publishErrors);
}
// If checking lock errors, display them as errors, otherwise just show them as warnings
// Skip when it is a strict check and we don't want to check lock errors
if ($checkLock) {
$errors = array_merge($errors, $lockErrors);
} else {
} elseif (!$isStrict) {
$warnings = array_merge($warnings, $lockErrors);
}

@ -176,8 +176,12 @@ class EventDispatcher
$return = false === call_user_func($callable, $event) ? 1 : 0;
} elseif ($this->isComposerScript($callable)) {
$this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE);
$scriptName = substr($callable, 1);
$args = $event->getArguments();
$script = explode(' ', substr($callable, 1));
$scriptName = $script[0];
unset($script[0]);
$args = array_merge($script, $event->getArguments());
$flags = $event->getFlags();
if (substr($callable, 0, 10) === '@composer ') {
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($callable, 9);
@ -262,16 +266,17 @@ class EventDispatcher
protected function getPhpExecCommand()
{
$finder = new PhpExecutableFinder();
$phpPath = $finder->find();
$phpPath = $finder->find(false);
if (!$phpPath) {
throw new \RuntimeException('Failed to locate PHP binary to execute '.$phpPath);
}
$phpArgs = $finder->findArguments();
$phpArgs = $phpArgs ? ' ' . implode(' ', $phpArgs) : '';
$allowUrlFOpenFlag = ' -d allow_url_fopen=' . ProcessExecutor::escape(ini_get('allow_url_fopen'));
$disableFunctionsFlag = ' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions'));
$memoryLimitFlag = ' -d memory_limit=' . ProcessExecutor::escape(ini_get('memory_limit'));
return ProcessExecutor::escape($phpPath) . $allowUrlFOpenFlag . $disableFunctionsFlag . $memoryLimitFlag;
return ProcessExecutor::escape($phpPath) . $phpArgs . $allowUrlFOpenFlag . $disableFunctionsFlag . $memoryLimitFlag;
}
/**

@ -33,6 +33,7 @@ use Composer\Installer\NoopInstaller;
use Composer\Installer\SuggestedPackagesReporter;
use Composer\IO\IOInterface;
use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\CompletePackage;
use Composer\Package\Link;
use Composer\Package\Loader\ArrayLoader;
@ -1247,7 +1248,7 @@ class Installer
}
foreach ($this->updateWhitelist as $whiteListedPattern => $void) {
$patternRegexp = $this->packageNameToRegexp($whiteListedPattern);
$patternRegexp = BasePackage::packageNameToRegexp($whiteListedPattern);
if (preg_match($patternRegexp, $package->getName())) {
return true;
}
@ -1256,19 +1257,6 @@ class Installer
return false;
}
/**
* Build a regexp from a package name, expanding * globs as required
*
* @param string $whiteListedPattern
* @return string
*/
private function packageNameToRegexp($whiteListedPattern)
{
$cleanedWhiteListedPattern = str_replace('\\*', '.*', preg_quote($whiteListedPattern));
return "{^" . $cleanedWhiteListedPattern . "$}i";
}
/**
* @param array $links
* @return array
@ -1334,7 +1322,7 @@ class Installer
// check if the name is a glob pattern that did not match directly
if (!$nameMatchesRequiredPackage) {
$whitelistPatternRegexp = $this->packageNameToRegexp($packageName);
$whitelistPatternRegexp = BasePackage::packageNameToRegexp($packageName);
foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) {
$nameMatchesRequiredPackage = true;

@ -234,4 +234,17 @@ abstract class BasePackage implements PackageInterface
$this->repository = null;
$this->id = -1;
}
/**
* Build a regexp from a package name, expanding * globs as required
*
* @param string $whiteListedPattern
* @return string
*/
public static function packageNameToRegexp($whiteListedPattern)
{
$cleanedWhiteListedPattern = str_replace('\\*', '.*', preg_quote($whiteListedPattern));
return "{^" . $cleanedWhiteListedPattern . "$}i";
}
}

@ -161,7 +161,7 @@ class ValidatingArrayLoader implements LoaderInterface
}
if ($this->validateArray('support') && !empty($this->config['support'])) {
foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc', 'docs', 'rss') as $key) {
foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc', 'docs', 'rss', 'chat') as $key) {
if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
$this->errors[] = 'support.'.$key.' : invalid value, must be a string';
unset($this->config['support'][$key]);
@ -178,7 +178,7 @@ class ValidatingArrayLoader implements LoaderInterface
unset($this->config['support']['irc']);
}
foreach (array('issues', 'forum', 'wiki', 'source', 'docs') as $key) {
foreach (array('issues', 'forum', 'wiki', 'source', 'docs', 'chat') as $key) {
if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) {
$this->warnings[] = 'support.'.$key.' : invalid value ('.$this->config['support'][$key].'), must be an http/https URL';
unset($this->config['support'][$key]);

@ -157,6 +157,13 @@ class PlatformRepository extends ArrayRepository
break;
case 'imagick':
$imagick = new \Imagick();
$imageMagickVersion = $imagick->getVersion();
preg_match('/^ImageMagick ([\d.]+)-(\d+)/', $imageMagickVersion['versionString'], $matches);
$prettyVersion = "{$matches[1]}.{$matches[2]}";
break;
case 'libxml':
$prettyVersion = LIBXML_DOTTED_VERSION;
break;

@ -40,7 +40,7 @@ final class StreamContextFactory
));
// Handle HTTP_PROXY/http_proxy on CLI only for security reasons
if (PHP_SAPI === 'cli' && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
$proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
}

@ -14,6 +14,7 @@ namespace Composer\Test\EventDispatcher;
use Composer\EventDispatcher\Event;
use Composer\EventDispatcher\EventDispatcher;
use Composer\EventDispatcher\ScriptExecutionException;
use Composer\Installer\InstallerEvents;
use Composer\Config;
use Composer\Composer;
@ -251,6 +252,45 @@ class EventDispatcherTest extends TestCase
$this->assertEquals($expected, $io->getOutput());
}
public function testRecursionInScriptsNames()
{
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
->setConstructorArgs(array(
$composer = $this->createComposerInstance(),
$io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE),
$process
))
->setMethods(array(
'getListeners'
))
->getMock();
$process->expects($this->exactly(1))
->method('execute')
->will($this->returnValue(0));
$dispatcher->expects($this->atLeastOnce())
->method('getListeners')
->will($this->returnCallback(function (Event $event) {
if($event->getName() === 'hello') {
return array('echo Hello');
}
if($event->getName() === 'helloWorld') {
return array('@hello World');
}
return array();
}));
$dispatcher->dispatch('helloWorld', new CommandEvent('helloWorld', $composer, $io));
$expected = "> helloWorld: @hello World".PHP_EOL.
"> hello: echo Hello " .escapeshellarg('World').PHP_EOL;
$this->assertEquals($expected, $io->getOutput());
}
/**
* @expectedException RuntimeException
*/

@ -71,6 +71,7 @@ class ValidatingArrayLoaderTest extends TestCase
'source' => 'http://example.org/',
'irc' => 'irc://example.org/example',
'rss' => 'http://example.org/rss',
'chat' => 'http://example.org/chat',
),
'require' => array(
'a/b' => '1.*',
@ -305,6 +306,7 @@ class ValidatingArrayLoaderTest extends TestCase
'forum' => 'foo:bar',
'issues' => 'foo:bar',
'wiki' => 'foo:bar',
'chat' => 'foo:bar',
),
),
array(
@ -312,6 +314,7 @@ class ValidatingArrayLoaderTest extends TestCase
'support.forum : invalid value (foo:bar), must be an http/https URL',
'support.issues : invalid value (foo:bar), must be an http/https URL',
'support.wiki : invalid value (foo:bar), must be an http/https URL',
'support.chat : invalid value (foo:bar), must be an http/https URL',
),
),
array(

Loading…
Cancel
Save