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 chance of us being able to reproduce your issue will be much higher if you
share your `composer.json` with us. 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 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 ### [1.7.3] 2018-11-01
* Fixed handling of replace/conflict rules. This may affect dependency resolution in some edge cases. * Fixed handling of replace/conflict rules. This may affect dependency resolution in some edge cases.
@ -696,6 +709,7 @@
* Initial release * 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.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.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]: https://github.com/composer/composer/compare/1.7.0...1.7.1

@ -1,7 +1,7 @@
#!/usr/bin/env php #!/usr/bin/env php
<?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; echo 'Warning: Composer should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
} }

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

102
composer.lock generated

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

@ -243,6 +243,7 @@ Support information includes the following:
* **source:** URL to browse or download the sources. * **source:** URL to browse or download the sources.
* **docs:** URL to the documentation. * **docs:** URL to the documentation.
* **rss:** URL to the RSS feed. * **rss:** URL to the RSS feed.
* **chat:** URL to the chat channel.
An example: 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 ## Calling Composer commands
To call Composer commands, you can use `@composer` which will automatically To call Composer commands, you can use `@composer` which will automatically

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

@ -22,6 +22,7 @@ use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
use Composer\Repository\RepositorySet; use Composer\Repository\RepositorySet;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; 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); $name = strtolower($name);
} else { } 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( 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_.-]+' '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; 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( 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_.-]+' '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; 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) { if ($requires) {
$requires = $this->normalizeRequirements($requires); $requires = $this->normalizeRequirements($requires);
@ -404,7 +410,7 @@ EOT
)); ));
} else { } else {
// check that the specified version/constraint exists before we proceed // 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 // replace package name from packagist.org
$requirement['name'] = $name; $requirement['name'] = $name;
@ -767,4 +773,23 @@ EOT
return array_keys(array_slice($similarPackages, 0, 5)); 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\InputOption;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Composer\Package\BasePackage;
/** /**
* @author Pierre du Plessis <pdples@gmail.com> * @author Pierre du Plessis <pdples@gmail.com>
@ -94,12 +95,25 @@ EOT
if (isset($composer[$type][$package])) { if (isset($composer[$type][$package])) {
$json->removeLink($type, $composer[$type][$package]); $json->removeLink($type, $composer[$type][$package]);
} elseif (isset($composer[$altType][$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->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]); $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 { } else {
$io->writeError('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>'); $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 <<<EOT
The require command adds required packages to your composer.json and installs them. 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. matches to require.
If you do not specify a version constraint, composer will choose a suitable one based on the available package versions. 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(); $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'; $requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev'; $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`.'; $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')) { if ($input->getOption('with-dependencies')) {
$localRepo = $composer->getRepositoryManager()->getLocalRepository(); $localRepo = $composer->getRepositoryManager()->getLocalRepository();
@ -108,7 +109,7 @@ EOT
list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll); list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
$this->outputResult($io, $package->getPrettyName(), $errors, $warnings, $checkPublish, $publishErrors); $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); $exitCode = max($depCode, $exitCode);
} }
} }
@ -121,7 +122,7 @@ EOT
return $exitCode; 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) { if (!$errors && !$publishErrors && !$warnings) {
$io->write('<info>' . $name . ' is valid</info>'); $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 // 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) { if ($checkPublish) {
$errors = array_merge($errors, $publishErrors); $errors = array_merge($errors, $publishErrors);
} else { } elseif (!$isStrict) {
$warnings = array_merge($warnings, $publishErrors); $warnings = array_merge($warnings, $publishErrors);
} }
// If checking lock errors, display them as errors, otherwise just show them as warnings // 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) { if ($checkLock) {
$errors = array_merge($errors, $lockErrors); $errors = array_merge($errors, $lockErrors);
} else { } elseif (!$isStrict) {
$warnings = array_merge($warnings, $lockErrors); $warnings = array_merge($warnings, $lockErrors);
} }

@ -176,8 +176,12 @@ class EventDispatcher
$return = false === call_user_func($callable, $event) ? 1 : 0; $return = false === call_user_func($callable, $event) ? 1 : 0;
} elseif ($this->isComposerScript($callable)) { } elseif ($this->isComposerScript($callable)) {
$this->io->writeError(sprintf('> %s: %s', $event->getName(), $callable), true, IOInterface::VERBOSE); $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(); $flags = $event->getFlags();
if (substr($callable, 0, 10) === '@composer ') { if (substr($callable, 0, 10) === '@composer ') {
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($callable, 9); $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($callable, 9);
@ -262,16 +266,17 @@ class EventDispatcher
protected function getPhpExecCommand() protected function getPhpExecCommand()
{ {
$finder = new PhpExecutableFinder(); $finder = new PhpExecutableFinder();
$phpPath = $finder->find(); $phpPath = $finder->find(false);
if (!$phpPath) { if (!$phpPath) {
throw new \RuntimeException('Failed to locate PHP binary to execute '.$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')); $allowUrlFOpenFlag = ' -d allow_url_fopen=' . ProcessExecutor::escape(ini_get('allow_url_fopen'));
$disableFunctionsFlag = ' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions')); $disableFunctionsFlag = ' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions'));
$memoryLimitFlag = ' -d memory_limit=' . ProcessExecutor::escape(ini_get('memory_limit')); $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\Installer\SuggestedPackagesReporter;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\CompletePackage; use Composer\Package\CompletePackage;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
@ -1247,7 +1248,7 @@ class Installer
} }
foreach ($this->updateWhitelist as $whiteListedPattern => $void) { foreach ($this->updateWhitelist as $whiteListedPattern => $void) {
$patternRegexp = $this->packageNameToRegexp($whiteListedPattern); $patternRegexp = BasePackage::packageNameToRegexp($whiteListedPattern);
if (preg_match($patternRegexp, $package->getName())) { if (preg_match($patternRegexp, $package->getName())) {
return true; return true;
} }
@ -1256,19 +1257,6 @@ class Installer
return false; 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 * @param array $links
* @return array * @return array
@ -1334,7 +1322,7 @@ class Installer
// check if the name is a glob pattern that did not match directly // check if the name is a glob pattern that did not match directly
if (!$nameMatchesRequiredPackage) { if (!$nameMatchesRequiredPackage) {
$whitelistPatternRegexp = $this->packageNameToRegexp($packageName); $whitelistPatternRegexp = BasePackage::packageNameToRegexp($packageName);
foreach ($rootRequiredPackageNames as $rootRequiredPackageName) { foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) { if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) {
$nameMatchesRequiredPackage = true; $nameMatchesRequiredPackage = true;

@ -234,4 +234,17 @@ abstract class BasePackage implements PackageInterface
$this->repository = null; $this->repository = null;
$this->id = -1; $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'])) { 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])) { if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
$this->errors[] = 'support.'.$key.' : invalid value, must be a string'; $this->errors[] = 'support.'.$key.' : invalid value, must be a string';
unset($this->config['support'][$key]); unset($this->config['support'][$key]);
@ -178,7 +178,7 @@ class ValidatingArrayLoader implements LoaderInterface
unset($this->config['support']['irc']); 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])) { 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'; $this->warnings[] = 'support.'.$key.' : invalid value ('.$this->config['support'][$key].'), must be an http/https URL';
unset($this->config['support'][$key]); unset($this->config['support'][$key]);

@ -157,6 +157,13 @@ class PlatformRepository extends ArrayRepository
break; 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': case 'libxml':
$prettyVersion = LIBXML_DOTTED_VERSION; $prettyVersion = LIBXML_DOTTED_VERSION;
break; break;

@ -40,7 +40,7 @@ final class StreamContextFactory
)); ));
// Handle HTTP_PROXY/http_proxy on CLI only for security reasons // 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']); $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\Event;
use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventDispatcher;
use Composer\EventDispatcher\ScriptExecutionException;
use Composer\Installer\InstallerEvents; use Composer\Installer\InstallerEvents;
use Composer\Config; use Composer\Config;
use Composer\Composer; use Composer\Composer;
@ -251,6 +252,45 @@ class EventDispatcherTest extends TestCase
$this->assertEquals($expected, $io->getOutput()); $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 * @expectedException RuntimeException
*/ */

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

Loading…
Cancel
Save