Merge branch '2.0' into solve-without-installed
* 2.0: (101 commits) SVN: hide passwords for debug output Free $solver asap fixes #8179 [minor] Fixed a typo in the CHANGELOG.md. Update deps Update changelog Revert "Allow overriding self-update target file with envvar COMPOSER_SELF_UPDATE_TARGET" Revert "Add docs for COMPOSER_SELF_UPDATE_TARGET, refs #8151" Add docs for COMPOSER_SELF_UPDATE_TARGET, refs #8151 Fix display of HHVM warning appearing when HHVM is not in use, fixes #8138 Read classmap-authoritative and apcu-autoloader from project config when installing via create-project, fixes #8155 Use possessive quantifiers Update xdebug-handler to 1.3.3 fixes #8159 Allow overriding self-update target file with envvar COMPOSER_SELF_UPDATE_TARGET flag should come before script name use full command name, not abbreviated/alias modify text Document the alternatives to disable the default script timeout Anchor pattern Fix URL resolution for Composer repositories ...pull/7936/head
commit
9053d74282
|
@ -10,3 +10,8 @@
|
|||
|
||||
# Exclude non-essential files from dist
|
||||
/tests export-ignore
|
||||
.github export-ignore
|
||||
.php_cs export-ignore
|
||||
.travis.yml export-ignore
|
||||
appveyor.yml export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
|
|
|
@ -25,8 +25,10 @@ matrix:
|
|||
- php: 7.1
|
||||
- php: 7.2
|
||||
- php: 7.3
|
||||
env: PHPSTAN=1
|
||||
- php: 7.3
|
||||
env: deps=high
|
||||
env:
|
||||
- deps=high
|
||||
- php: nightly
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
|
@ -58,6 +60,11 @@ before_script:
|
|||
script:
|
||||
# run test suite directories in parallel using GNU parallel
|
||||
- ls -d tests/Composer/Test/* | grep -v TestCase.php | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml --colors=always {} || (echo -e "\e[41mFAILED\e[0m {}" && exit 1);'
|
||||
# Run PHPStan
|
||||
- if [[ $PHPSTAN == "1" ]]; then
|
||||
composer require --dev phpstan/phpstan-shim:^0.11 --ignore-platform-reqs &&
|
||||
vendor/bin/phpstan.phar analyse src tests --configuration=phpstan/config.neon --autoload-file=phpstan/autoload.php;
|
||||
fi
|
||||
|
||||
before_deploy:
|
||||
- php -d phar.readonly=0 bin/compile
|
||||
|
|
28
CHANGELOG.md
28
CHANGELOG.md
|
@ -1,3 +1,25 @@
|
|||
### [1.8.6] 2019-06-11
|
||||
|
||||
* Fixed handling of backslash-escapes handling in composer.json when using the require command
|
||||
* Fixed create-project not following classmap-authoritative and apcu-autoloader config values
|
||||
* Fixed HHVM version warning showing up in some cases when it was not in use
|
||||
|
||||
### [1.8.5] 2019-04-09
|
||||
|
||||
* HHVM 4.0 is no longer compatible with Composer. Please use PHP instead going forward.
|
||||
* Added forward compatibility with upcoming 2.0 changes
|
||||
* Fixed support for PHP 7.3-style heredoc/nowdoc syntax changes in autoload generation
|
||||
* Fixed require command usage when combined with --ignore-platform-reqs
|
||||
* Fixed and cleaned up various Windows junctions handling issues
|
||||
|
||||
### [1.8.4] 2019-02-11
|
||||
|
||||
* Fixed long standing solver bug leading to odd solving issues in edge cases, see #7946
|
||||
* Fixed HHVM support for upcoming releases
|
||||
* Fixed unix proxy for binaries to be POSIX compatible instead of breaking some shells
|
||||
* Fixed invalid deprecation warning for composer-plugin-api
|
||||
* Fixed edge case issues with Windows junctions when working with path repositories
|
||||
|
||||
### [1.8.3] 2019-01-30
|
||||
|
||||
* Fixed regression when executing partial updates
|
||||
|
@ -729,6 +751,12 @@
|
|||
|
||||
* Initial release
|
||||
|
||||
[1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6
|
||||
[1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5
|
||||
[1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4
|
||||
[1.8.3]: https://github.com/composer/composer/compare/1.8.2...1.8.3
|
||||
[1.8.2]: https://github.com/composer/composer/compare/1.8.1...1.8.2
|
||||
[1.8.1]: https://github.com/composer/composer/compare/1.8.0...1.8.1
|
||||
[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
|
||||
|
|
|
@ -3,7 +3,7 @@ clone_depth: 5
|
|||
|
||||
environment:
|
||||
# This sets the PHP version (from Chocolatey)
|
||||
PHPCI_CHOCO_VERSION: 7.2.9
|
||||
PHPCI_CHOCO_VERSION: 7.3.1
|
||||
PHPCI_CACHE: C:\tools\phpci
|
||||
PHPCI_PHP: C:\tools\phpci\php
|
||||
PHPCI_COMPOSER: C:\tools\phpci\composer
|
||||
|
|
|
@ -18,6 +18,11 @@ $xdebug = new XdebugHandler('Composer', '--ansi');
|
|||
$xdebug->check();
|
||||
unset($xdebug);
|
||||
|
||||
if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '4.0', '>=')) {
|
||||
echo 'HHVM 4.0 has dropped support for Composer, please use PHP instead. Aborting.'.PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (function_exists('ini_set')) {
|
||||
@ini_set('display_errors', 1);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "composer/composer",
|
||||
"type": "library",
|
||||
"description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
|
||||
"description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
|
||||
"keywords": [
|
||||
"package",
|
||||
"dependency",
|
||||
|
@ -56,7 +56,7 @@
|
|||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b078b12b2912d599e0c6904f64def484",
|
||||
"content-hash": "280f5d5184039085b5f22236d267ae82",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
|
@ -64,16 +64,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "1.4.2",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
|
||||
"reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
|
||||
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e",
|
||||
"reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -122,28 +122,27 @@
|
|||
"validation",
|
||||
"versioning"
|
||||
],
|
||||
"time": "2016-08-30T16:08:34+00:00"
|
||||
"time": "2019-03-19T17:25:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/spdx-licenses",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/spdx-licenses.git",
|
||||
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2"
|
||||
"reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
|
||||
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
|
||||
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d",
|
||||
"reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0"
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5",
|
||||
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -183,20 +182,20 @@
|
|||
"spdx",
|
||||
"validator"
|
||||
],
|
||||
"time": "2018-11-01T09:45:54+00:00"
|
||||
"time": "2019-03-26T10:23:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
"version": "1.3.2",
|
||||
"version": "1.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/xdebug-handler.git",
|
||||
"reference": "d17708133b6c276d6e42ef887a877866b909d892"
|
||||
"reference": "46867cbf8ca9fb8d60c506895449eb799db1184f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/d17708133b6c276d6e42ef887a877866b909d892",
|
||||
"reference": "d17708133b6c276d6e42ef887a877866b909d892",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f",
|
||||
"reference": "46867cbf8ca9fb8d60c506895449eb799db1184f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -227,27 +226,27 @@
|
|||
"Xdebug",
|
||||
"performance"
|
||||
],
|
||||
"time": "2019-01-28T20:25:53+00:00"
|
||||
"time": "2019-05-27T17:52:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "justinrainbow/json-schema",
|
||||
"version": "5.2.7",
|
||||
"version": "5.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/justinrainbow/json-schema.git",
|
||||
"reference": "8560d4314577199ba51bf2032f02cd1315587c23"
|
||||
"reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8560d4314577199ba51bf2032f02cd1315587c23",
|
||||
"reference": "8560d4314577199ba51bf2032f02cd1315587c23",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4",
|
||||
"reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.1",
|
||||
"friendsofphp/php-cs-fixer": "~2.2.20",
|
||||
"json-schema/json-schema-test-suite": "1.2.0",
|
||||
"phpunit/phpunit": "^4.8.35"
|
||||
},
|
||||
|
@ -293,7 +292,7 @@
|
|||
"json",
|
||||
"schema"
|
||||
],
|
||||
"time": "2018-02-14T22:26:30+00:00"
|
||||
"time": "2019-01-14T23:55:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
|
@ -481,7 +480,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
|
@ -542,7 +541,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
|
@ -599,7 +598,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
|
@ -649,7 +648,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
|
@ -698,16 +697,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
|
||||
"reference": "82ebae02209c21113908c229e9883c419720738a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
|
||||
"reference": "82ebae02209c21113908c229e9883c419720738a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -719,7 +718,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -752,20 +751,20 @@
|
|||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"time": "2018-08-06T14:22:27+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
|
||||
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -777,7 +776,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -811,11 +810,11 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-09-21T13:07:52+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
|
@ -1780,7 +1779,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.8.48",
|
||||
"version": "v2.8.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
|
|
|
@ -47,7 +47,7 @@ Linux and macOS.
|
|||
### Downloading the Composer Executable
|
||||
|
||||
Composer offers a convenient installer that you can execute directly from the
|
||||
commandline. Feel free to [download this file](https://getcomposer.org/installer)
|
||||
command line. Feel free to [download this file](https://getcomposer.org/installer)
|
||||
or review it on [GitHub](https://github.com/composer/getcomposer.org/blob/master/web/installer)
|
||||
if you wish to know more about the inner workings of the installer. The source
|
||||
is plain PHP.
|
||||
|
@ -82,7 +82,7 @@ Now run `php bin/composer` in order to run Composer.
|
|||
#### Globally
|
||||
|
||||
You can place the Composer PHAR anywhere you wish. If you put it in a directory
|
||||
that is part of your `PATH`, you can access it globally. On unixy systems you
|
||||
that is part of your `PATH`, you can access it globally. On Unix systems you
|
||||
can even make it executable and invoke it without directly using the `php`
|
||||
interpreter.
|
||||
|
||||
|
|
|
@ -920,6 +920,10 @@ If you use a proxy but it does not support the request_fulluri flag for HTTPS
|
|||
requests, then you should set this env var to `false` or `0` to prevent Composer
|
||||
from setting the request_fulluri option.
|
||||
|
||||
### COMPOSER_SELF_UPDATE_TARGET
|
||||
|
||||
If set, makes the self-update command write the new Composer phar file into that path instead of overwriting itself. Useful for updating Composer on read-only filesystem.
|
||||
|
||||
### no_proxy or NO_PROXY
|
||||
|
||||
If you are behind a proxy and would like to disable it for certain domains, you
|
||||
|
|
|
@ -666,6 +666,10 @@ Instead of default fallback strategy you can force to use symlink with
|
|||
mirroring can be useful when deploying or generating package from a
|
||||
monolithic repository.
|
||||
|
||||
> **Note:** On Windows, directory symlinks are implemented using NTFS junctions
|
||||
> because they can be created by non-admin users. Mirroring will always be used
|
||||
> on versions below Windows 7 or if `proc_open` has been disabled.
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
|
|
|
@ -9,6 +9,20 @@ Defaults to `300`. The duration processes like git clones can run before
|
|||
Composer assumes they died out. You may need to make this higher if you have a
|
||||
slow connection or huge vendors.
|
||||
|
||||
To disable the process timeout on a custom command under `scripts`, a static
|
||||
helper is available:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"phpunit"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## use-include-path
|
||||
|
||||
Defaults to `false`. If `true`, the Composer autoloader will also look for classes
|
||||
|
|
|
@ -261,6 +261,11 @@ Now the `custom-plugin-command` is available alongside Composer commands.
|
|||
|
||||
> _Composer commands are based on the [Symfony Console Component][10]._
|
||||
|
||||
## Running plugins manually
|
||||
|
||||
Plugins for an event can be run manually by the `run-script` command. This works the same way as
|
||||
[running scripts manually](scripts.md#running-scripts-manually).
|
||||
|
||||
## Using Plugins
|
||||
|
||||
Plugin packages are automatically loaded as soon as they are installed and will
|
||||
|
|
|
@ -189,7 +189,7 @@ composer run-script [--dev] [--no-dev] script
|
|||
```
|
||||
|
||||
For example `composer run-script post-install-cmd` will run any
|
||||
**post-install-cmd** scripts that have been defined.
|
||||
**post-install-cmd** scripts and [plugins](plugins.md) that have been defined.
|
||||
|
||||
You can also give additional arguments to the script handler by appending `--`
|
||||
followed by the handler arguments. e.g.
|
||||
|
@ -221,6 +221,56 @@ to the `phpunit` script.
|
|||
> are easily accessible. In this example no matter if the `phpunit` binary is
|
||||
> actually in `vendor/bin/phpunit` or `bin/phpunit` it will be found and executed.
|
||||
|
||||
Although Composer is not intended to manage long-running processes and other
|
||||
such aspects of PHP projects, it can sometimes be handy to disable the process
|
||||
timeout on custom commands. This timeout defaults to 300 seconds and can be
|
||||
overridden in a variety of ways depending on the desired effect:
|
||||
|
||||
- disable it for all commands using the config key `process-timeout`,
|
||||
- disable it for the current or future invocations of composer using the
|
||||
environment variable `COMPOSER_PROCESS_TIMEOUT`,
|
||||
- for a specific invocation using the `--timeout` flag of the `run-script` command,
|
||||
- using a static helper for specific scripts.
|
||||
|
||||
To disable the timeout for specific scripts with the static helper directly in
|
||||
composer.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"phpunit"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To disable the timeout for every script on a given project, you can use the
|
||||
composer.json configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"process-timeout": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It's also possible to set the global environment variable to disable the timeout
|
||||
of all following scripts in the current terminal environment:
|
||||
|
||||
```
|
||||
export COMPOSER_PROCESS_TIMEOUT=0
|
||||
```
|
||||
|
||||
To disable the timeout of a single script call, you must use the `run-script` composer
|
||||
command and specify the `--timeout` parameter:
|
||||
|
||||
```
|
||||
composer run-script --timeout=0 test
|
||||
```
|
||||
|
||||
## Referencing scripts
|
||||
|
||||
To enable script re-use and avoid duplicates, you can call a script from another
|
||||
|
|
|
@ -32,7 +32,7 @@ repository:*
|
|||
v1
|
||||
v2
|
||||
my-feature
|
||||
nother-feature
|
||||
another-feature
|
||||
|
||||
~/my-library$ git tag
|
||||
v1.0
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
require_once __DIR__ . '/../src/bootstrap.php';
|
|
@ -0,0 +1,42 @@
|
|||
parameters:
|
||||
level: 0
|
||||
excludes_analyse:
|
||||
- 'tests/Composer/Test/Fixtures'
|
||||
- 'tests/Composer/Test/Autoload/Fixtures'
|
||||
- 'tests/Composer/Test/Plugin/Fixtures'
|
||||
ignoreErrors:
|
||||
# unused parameters
|
||||
- '~^Constructor of class Composer\\Repository\\VcsRepository has an unused parameter \$dispatcher\.$~'
|
||||
- '~^Constructor of class Composer\\Repository\\PearRepository has an unused parameter \$dispatcher\.$~'
|
||||
- '~^Constructor of class Composer\\Util\\Http\\CurlDownloader has an unused parameter \$disableTls\.$~'
|
||||
- '~^Constructor of class Composer\\Util\\Http\\CurlDownloader has an unused parameter \$options\.$~'
|
||||
- '~^Constructor of class Composer\\Repository\\PearRepository has an unused parameter \$config\.$~'
|
||||
|
||||
# unused uses
|
||||
- '~^Anonymous function has an unused use \$io\.$~'
|
||||
- '~^Anonymous function has an unused use \$cache\.$~'
|
||||
- '~^Anonymous function has an unused use \$path\.$~'
|
||||
- '~^Anonymous function has an unused use \$fileName\.$~'
|
||||
|
||||
# ion cube is not installed
|
||||
- '~^Function ioncube_loader_\w+ not found\.$~'
|
||||
# rar is not installed
|
||||
- '~^Call to static method open\(\) on an unknown class RarArchive\.$~'
|
||||
# imagick is not installed
|
||||
- '~^Instantiated class Imagick not found\.$~'
|
||||
|
||||
# variables from global scope
|
||||
- '~^Undefined variable: \$vendorDir$~'
|
||||
- '~^Undefined variable: \$baseDir$~'
|
||||
|
||||
# variable defined in eval
|
||||
- '~^Undefined variable: \$res$~'
|
||||
|
||||
# always checked whether the class exists
|
||||
- '~^Instantiated class Symfony\\Component\\Console\\Terminal not found\.$~'
|
||||
- '~^Class Symfony\\Component\\Console\\Input\\StreamableInputInterface not found\.$~'
|
||||
- '~^Call to an undefined static method Symfony\\Component\\Process\\Process::fromShellCommandline\(\).$~'
|
||||
|
||||
# parent call in test mocks
|
||||
- '~^Composer\\Test\\Mock\\HttpDownloaderMock::__construct\(\) does not call parent constructor from Composer\\Util\\HttpDownloader\.$~'
|
||||
- '~^Composer\\Test\\Mock\\InstallationManagerMock::__construct\(\) does not call parent constructor from Composer\\Installer\\InstallationManager\.$~'
|
|
@ -21,6 +21,7 @@ use Composer\Package\PackageInterface;
|
|||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Util\Filesystem;
|
||||
use Composer\Script\ScriptEvents;
|
||||
use Composer\Util\PackageSorter;
|
||||
|
||||
/**
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
|
@ -545,7 +546,7 @@ EOF;
|
|||
}
|
||||
}
|
||||
|
||||
if (preg_match('/\.phar.+$/', $path)) {
|
||||
if (strpos($path, '.phar') !== false) {
|
||||
$baseDir = "'phar://' . " . $baseDir;
|
||||
}
|
||||
|
||||
|
@ -769,10 +770,14 @@ HEADER;
|
|||
$filesystem = new Filesystem();
|
||||
|
||||
$vendorPathCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/";
|
||||
$vendorPharPathCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true, true) . " . '/";
|
||||
$appBaseDirCode = ' => ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/";
|
||||
$appBaseDirPharCode = ' => \'phar://\' . ' . $filesystem->findShortestPathCode(realpath($targetDir), $basePath, true, true) . " . '/";
|
||||
|
||||
$absoluteVendorPathCode = ' => ' . substr(var_export(rtrim($vendorDir, '\\/') . '/', true), 0, -1);
|
||||
$absoluteVendorPharPathCode = ' => ' . substr(var_export(rtrim('phar://' . $vendorDir, '\\/') . '/', true), 0, -1);
|
||||
$absoluteAppBaseDirCode = ' => ' . substr(var_export(rtrim($baseDir, '\\/') . '/', true), 0, -1);
|
||||
$absoluteAppBaseDirPharCode = ' => ' . substr(var_export(rtrim('phar://' . $baseDir, '\\/') . '/', true), 0, -1);
|
||||
|
||||
$initializer = '';
|
||||
$prefix = "\0Composer\Autoload\ClassLoader\0";
|
||||
|
@ -795,9 +800,15 @@ HEADER;
|
|||
// See https://bugs.php.net/68057
|
||||
$staticPhpVersion = 70000;
|
||||
}
|
||||
$value = var_export($value, true);
|
||||
$value = str_replace($absoluteVendorPathCode, $vendorPathCode, $value);
|
||||
$value = str_replace($absoluteAppBaseDirCode, $appBaseDirCode, $value);
|
||||
$value = strtr(
|
||||
var_export($value, true),
|
||||
array(
|
||||
$absoluteVendorPathCode => $vendorPathCode,
|
||||
$absoluteVendorPharPathCode => $vendorPharPathCode,
|
||||
$absoluteAppBaseDirCode => $appBaseDirCode,
|
||||
$absoluteAppBaseDirPharCode => $appBaseDirPharCode,
|
||||
)
|
||||
);
|
||||
$value = ltrim(preg_replace('/^ */m', ' $0$0', $value));
|
||||
|
||||
$file .= sprintf(" public static $%s = %s;\n\n", $prop, $value);
|
||||
|
@ -963,80 +974,21 @@ INITIALIZER;
|
|||
{
|
||||
$packages = array();
|
||||
$paths = array();
|
||||
$usageList = array();
|
||||
|
||||
foreach ($packageMap as $item) {
|
||||
list($package, $path) = $item;
|
||||
$name = $package->getName();
|
||||
$packages[$name] = $package;
|
||||
$paths[$name] = $path;
|
||||
|
||||
foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) {
|
||||
$target = $link->getTarget();
|
||||
$usageList[$target][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$computing = array();
|
||||
$computed = array();
|
||||
$computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
|
||||
// reusing computed importance
|
||||
if (isset($computed[$name])) {
|
||||
return $computed[$name];
|
||||
}
|
||||
$sortedPackages = PackageSorter::sortPackages($packages);
|
||||
|
||||
// canceling circular dependency
|
||||
if (isset($computing[$name])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$computing[$name] = true;
|
||||
$weight = 0;
|
||||
|
||||
if (isset($usageList[$name])) {
|
||||
foreach ($usageList[$name] as $user) {
|
||||
$weight -= 1 - $computeImportance($user);
|
||||
}
|
||||
}
|
||||
|
||||
unset($computing[$name]);
|
||||
$computed[$name] = $weight;
|
||||
|
||||
return $weight;
|
||||
};
|
||||
|
||||
$weightList = array();
|
||||
|
||||
foreach ($packages as $name => $package) {
|
||||
$weight = $computeImportance($name);
|
||||
$weightList[$name] = $weight;
|
||||
}
|
||||
|
||||
$stable_sort = function (&$array) {
|
||||
static $transform, $restore;
|
||||
|
||||
$i = 0;
|
||||
|
||||
if (!$transform) {
|
||||
$transform = function (&$v, $k) use (&$i) {
|
||||
$v = array($v, ++$i, $k, $v);
|
||||
};
|
||||
|
||||
$restore = function (&$v, $k) {
|
||||
$v = $v[3];
|
||||
};
|
||||
}
|
||||
|
||||
array_walk($array, $transform);
|
||||
asort($array);
|
||||
array_walk($array, $restore);
|
||||
};
|
||||
|
||||
$stable_sort($weightList);
|
||||
|
||||
$sortedPackageMap = array();
|
||||
|
||||
foreach (array_keys($weightList) as $name) {
|
||||
foreach ($sortedPackages as $package) {
|
||||
$name = $package->getName();
|
||||
$sortedPackageMap[] = array($packages[$name], $paths[$name]);
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ class ClassMapGenerator
|
|||
}
|
||||
|
||||
// strip heredocs/nowdocs
|
||||
$contents = preg_replace('{<<<\s*(\'?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\2(?=\r\n|\n|\r|;)}s', 'null', $contents);
|
||||
$contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
|
||||
// strip strings
|
||||
$contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
|
||||
// strip leading non-php code if needed
|
||||
|
|
|
@ -189,7 +189,8 @@ class Cache
|
|||
public function clear()
|
||||
{
|
||||
if ($this->enabled) {
|
||||
return $this->filesystem->removeDirectory($this->root);
|
||||
$this->filesystem->emptyDirectory($this->root);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -57,6 +57,7 @@ package in the specified version and writes it to the specified directory.
|
|||
|
||||
<info>php composer.phar archive [--format=zip] [--dir=/foo] [package [version]]</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#archive
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -27,6 +27,8 @@ use Symfony\Component\Console\Command\Command;
|
|||
/**
|
||||
* Base class for Composer commands
|
||||
*
|
||||
* @method Application getApplication()
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knplabs.com>
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*/
|
||||
|
@ -46,7 +48,7 @@ abstract class BaseCommand extends Command
|
|||
* @param bool $required
|
||||
* @param bool|null $disablePlugins
|
||||
* @throws \RuntimeException
|
||||
* @return Composer
|
||||
* @return Composer|null
|
||||
*/
|
||||
public function getComposer($required = true, $disablePlugins = null)
|
||||
{
|
||||
|
@ -173,7 +175,7 @@ abstract class BaseCommand extends Command
|
|||
|
||||
if ($input->getOption('prefer-source') || $input->getOption('prefer-dist') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'))) {
|
||||
$preferSource = $input->getOption('prefer-source') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'));
|
||||
$preferDist = $input->getOption('prefer-dist');
|
||||
$preferDist = (bool) $input->getOption('prefer-dist');
|
||||
}
|
||||
|
||||
return array($preferSource, $preferDist);
|
||||
|
|
|
@ -32,6 +32,8 @@ class ClearCacheCommand extends BaseCommand
|
|||
<<<EOT
|
||||
The <info>clear-cache</info> deletes all cached packages from composer's
|
||||
cache directory.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#clear-cache-clearcache-
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -125,6 +125,8 @@ You can always pass more than one option. As an example, if you want to edit the
|
|||
global config.json file.
|
||||
|
||||
<comment>%command.full_name% --editor --global</comment>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#config
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -226,7 +228,7 @@ EOT
|
|||
}
|
||||
|
||||
$settingKey = $input->getArgument('setting-key');
|
||||
if (!$settingKey) {
|
||||
if (!$settingKey || !is_string($settingKey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ controlled code by appending the <info>'--prefer-source'</info> flag.
|
|||
To install a package from another repository than the default one you
|
||||
can pass the <info>'--repository=https://myrepository.org'</info> flag.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#create-project
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -183,7 +184,9 @@ EOT
|
|||
->setRunScripts(!$noScripts)
|
||||
->setIgnorePlatformRequirements($ignorePlatformReqs)
|
||||
->setSuggestedPackagesReporter($this->suggestedPackagesReporter)
|
||||
->setOptimizeAutoloader($config->get('optimize-autoloader'));
|
||||
->setOptimizeAutoloader($config->get('optimize-autoloader'))
|
||||
->setClassMapAuthoritative($config->get('classmap-authoritative'))
|
||||
->setApcuAutoloader($config->get('apcu-autoloader'));
|
||||
|
||||
if ($disablePlugins) {
|
||||
$installer->disablePlugins();
|
||||
|
|
|
@ -37,6 +37,7 @@ Displays detailed information about where a package is referenced.
|
|||
|
||||
<info>php composer.phar depends composer/composer</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#depends-why-
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -55,6 +55,7 @@ The <info>diagnose</info> command checks common errors to help debugging problem
|
|||
|
||||
The process exit code will be 1 in case of warnings and 2 for errors.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#diagnose
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -602,20 +603,6 @@ EOT
|
|||
$text .= "Install either of them or recompile php without --disable-iconv";
|
||||
break;
|
||||
|
||||
case 'unicode':
|
||||
$text = PHP_EOL."The detect_unicode setting must be disabled.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
|
||||
$text .= " detect_unicode = Off";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'suhosin':
|
||||
$text = PHP_EOL."The suhosin.executor.include.whitelist setting is incorrect.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):".PHP_EOL;
|
||||
$text .= " suhosin.executor.include.whitelist = phar ".$current;
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
$text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher.";
|
||||
break;
|
||||
|
@ -713,7 +700,7 @@ EOT
|
|||
/**
|
||||
* Check if allow_url_fopen is ON
|
||||
*
|
||||
* @return bool|string
|
||||
* @return true|string
|
||||
*/
|
||||
private function checkConnectivity()
|
||||
{
|
||||
|
|
|
@ -39,6 +39,8 @@ class DumpAutoloadCommand extends BaseCommand
|
|||
->setHelp(
|
||||
<<<EOT
|
||||
<info>php composer.phar dump-autoload</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#dump-autoload-dumpautoload-
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -36,6 +36,13 @@ class ExecCommand extends BaseCommand
|
|||
'Arguments to pass to the binary. Use <info>--</info> to separate from composer arguments'
|
||||
),
|
||||
))
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
Executes a vendored binary/script.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#exec
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ XDG_CONFIG_HOME or default to /home/<user>/.config/composer
|
|||
Note: This path may vary depending on customizations to bin-dir in
|
||||
composer.json or the environmental variable COMPOSER_BIN_DIR.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#global
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -49,6 +49,8 @@ homepage in your default browser.
|
|||
|
||||
To open the homepage by default, use -H or --homepage.
|
||||
To show instead of open the repository or homepage URL, use -s or --show.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#browse-home
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ in the current directory.
|
|||
|
||||
<info>php composer.phar init</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#init
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -694,15 +695,22 @@ EOT
|
|||
{
|
||||
// find the latest version allowed in this repo set
|
||||
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability));
|
||||
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability);
|
||||
$ignorePlatformReqs = $input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs');
|
||||
|
||||
// retry without phpVersion if platform requirements are ignored in case nothing was found
|
||||
if ($input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs')) {
|
||||
// ignore phpVersion if platform requirements are ignored
|
||||
if ($ignorePlatformReqs) {
|
||||
$phpVersion = null;
|
||||
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability);
|
||||
}
|
||||
|
||||
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $phpVersion, $preferredStability);
|
||||
|
||||
if (!$package) {
|
||||
// platform packages can not be found in the pool in versions other than the local platform's has
|
||||
// so if platform reqs are ignored we just take the user's word for it
|
||||
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
|
||||
return array($name, $requiredVersion ?: '*');
|
||||
}
|
||||
|
||||
// Check whether the PHP version was the problem
|
||||
if ($phpVersion && $versionSelector->findBestCandidate($name, $requiredVersion, null, $preferredStability)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
|
|
|
@ -61,6 +61,7 @@ exist it will look for composer.json and do the same.
|
|||
|
||||
<info>php composer.phar install</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#install-i
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -41,6 +41,7 @@ class LicensesCommand extends BaseCommand
|
|||
The license command displays detailed information about the licenses of
|
||||
the installed dependencies.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#licenses
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -50,7 +50,7 @@ The color coding (or signage if you have ANSI colors disabled) for dependency ve
|
|||
may involve work.
|
||||
- <highlight>red</highlight> (!): Dependency has a new version that is semver-compatible and you should upgrade it.
|
||||
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#outdated
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -37,6 +37,7 @@ Displays detailed information about why a package cannot be installed.
|
|||
|
||||
<info>php composer.phar prohibits composer/composer</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#prohibits-why-not-
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -56,6 +56,7 @@ list of installed packages
|
|||
|
||||
<info>php composer.phar remove</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#remove
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -25,6 +25,7 @@ use Composer\Plugin\CommandEvent;
|
|||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
* @author Jérémy Romey <jeremy@free-agent.fr>
|
||||
|
@ -73,6 +74,7 @@ If you do not specify a version constraint, composer will choose a suitable one
|
|||
|
||||
If you do not want to install the new dependencies immediately you can call it with --no-update
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#require
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -159,15 +161,26 @@ EOT
|
|||
if ($input->getOption('no-update')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->doUpdate($input, $output, $io, $requirements);
|
||||
} catch (\Exception $e) {
|
||||
$this->revertComposerFile(false);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements)
|
||||
{
|
||||
// Update packages
|
||||
$this->resetComposer();
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
|
||||
$updateDevMode = !$input->getOption('update-no-dev');
|
||||
$optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
|
||||
$authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
|
||||
$apcu = $input->getOption('apcu-autoloader') || $composer->getConfig()->get('apcu-autoloader');
|
||||
|
||||
// Update packages
|
||||
$this->resetComposer();
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ class RunScriptCommand extends BaseCommand
|
|||
The <info>run-script</info> command runs scripts defined in composer.json:
|
||||
|
||||
<info>php composer.phar run-script post-update-cmd</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#run-script
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -48,6 +48,8 @@ class ScriptAliasCommand extends BaseCommand
|
|||
The <info>run-script</info> command runs scripts defined in composer.json:
|
||||
|
||||
<info>php composer.phar run-script post-update-cmd</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#run-script
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -49,6 +49,7 @@ class SearchCommand extends BaseCommand
|
|||
The search command searches for packages by its name
|
||||
<info>php composer.phar search symfony composer</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#search
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -60,6 +60,7 @@ versions of composer and if found, installs the latest.
|
|||
|
||||
<info>php composer.phar self-update</info>
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#self-update-selfupdate-
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -85,6 +85,7 @@ class ShowCommand extends BaseCommand
|
|||
The show command displays detailed information about a package, or
|
||||
lists all packages available.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#show
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
@ -823,10 +824,10 @@ EOT
|
|||
/**
|
||||
* Display a package tree
|
||||
*
|
||||
* @param PackageInterface|string $package
|
||||
* @param array $packagesInTree
|
||||
* @param string $previousTreeBar
|
||||
* @param int $level
|
||||
* @param array|string $package
|
||||
* @param array $packagesInTree
|
||||
* @param string $previousTreeBar
|
||||
* @param int $level
|
||||
*/
|
||||
protected function displayTree(
|
||||
$package,
|
||||
|
@ -835,7 +836,7 @@ EOT
|
|||
$level = 1
|
||||
) {
|
||||
$previousTreeBar = str_replace('├', '│', $previousTreeBar);
|
||||
if (isset($package['requires'])) {
|
||||
if (is_array($package) && isset($package['requires'])) {
|
||||
$requires = $package['requires'];
|
||||
$treeBar = $previousTreeBar . ' ├';
|
||||
$i = 0;
|
||||
|
@ -968,7 +969,7 @@ EOT
|
|||
* @param string $phpVersion
|
||||
* @param bool $minorOnly
|
||||
*
|
||||
* @return PackageInterface|null
|
||||
* @return PackageInterface|false
|
||||
*/
|
||||
private function findLatestPackage(PackageInterface $package, Composer $composer, $phpVersion, $minorOnly = false)
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@ class StatusCommand extends BaseCommand
|
|||
The status command displays a list of dependencies that have
|
||||
been modified locally.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#status
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -38,11 +38,15 @@ The <info>%command.name%</info> command shows a sorted list of suggested package
|
|||
|
||||
Enabling <info>-v</info> implies <info>--by-package --by-suggestion</info>, showing both lists.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#suggests
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$lock = $this->getComposer()->getLocker()->getLockData();
|
||||
|
@ -117,7 +121,7 @@ EOT
|
|||
$io->write(sprintf('<info>%s</info>', $suggestion));
|
||||
}
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Grouped by package
|
||||
|
|
|
@ -81,6 +81,7 @@ from a specific vendor:
|
|||
|
||||
To select packages names interactively with auto-completion use <info>-i</info>.
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#update-u
|
||||
EOT
|
||||
)
|
||||
;
|
||||
|
|
|
@ -55,6 +55,7 @@ Exit codes in case of errors are:
|
|||
2 validation error(s)
|
||||
3 file unreadable or missing
|
||||
|
||||
Read more at https://getcomposer.org/doc/03-cli.md#validate
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
|
|
@ -194,6 +194,7 @@ class Compiler
|
|||
$content = str_replace('@package_version@', $this->version, $content);
|
||||
$content = str_replace('@package_branch_alias_version@', $this->branchAliasVersion, $content);
|
||||
$content = str_replace('@release_date@', $this->versionDate->format('Y-m-d H:i:s'), $content);
|
||||
$content = preg_replace('{SOURCE_VERSION = \'[^\']+\';}', 'SOURCE_VERSION = \'\';', $content);
|
||||
}
|
||||
|
||||
$phar->addFromString($path, $content);
|
||||
|
|
|
@ -29,10 +29,46 @@ use Composer\Package\Archiver\ArchiveManager;
|
|||
*/
|
||||
class Composer
|
||||
{
|
||||
/*
|
||||
* Examples of the following constants in the various configurations they can be in
|
||||
*
|
||||
* releases (phar):
|
||||
* const VERSION = '1.8.2';
|
||||
* const BRANCH_ALIAS_VERSION = '';
|
||||
* const RELEASE_DATE = '2019-01-29 15:00:53';
|
||||
* const SOURCE_VERSION = '';
|
||||
*
|
||||
* snapshot builds (phar):
|
||||
* const VERSION = 'd3873a05650e168251067d9648845c220c50e2d7';
|
||||
* const BRANCH_ALIAS_VERSION = '1.9-dev';
|
||||
* const RELEASE_DATE = '2019-02-20 07:43:56';
|
||||
* const SOURCE_VERSION = '';
|
||||
*
|
||||
* source (git clone):
|
||||
* const VERSION = '@package_version@';
|
||||
* const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@';
|
||||
* const RELEASE_DATE = '@release_date@';
|
||||
* const SOURCE_VERSION = '1.8-dev+source';
|
||||
*/
|
||||
const VERSION = '@package_version@';
|
||||
const BRANCH_ALIAS_VERSION = '@package_branch_alias_version@';
|
||||
const RELEASE_DATE = '@release_date@';
|
||||
const SOURCE_VERSION = '2.0-source';
|
||||
const SOURCE_VERSION = '2.0-dev+source';
|
||||
|
||||
public static function getVersion()
|
||||
{
|
||||
// no replacement done, this must be a source checkout
|
||||
if (self::VERSION === '@package_version'.'@') {
|
||||
return self::SOURCE_VERSION;
|
||||
}
|
||||
|
||||
// we have a branch alias and version is a commit id, this must be a snapshot build
|
||||
if (self::BRANCH_ALIAS_VERSION !== '' && preg_match('{^[a-f0-9]{40}$}', self::VERSION)) {
|
||||
return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION;
|
||||
}
|
||||
|
||||
return self::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Package\RootPackageInterface
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Config\ConfigSourceInterface;
|
|||
use Composer\Downloader\TransportException;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\Platform;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
|
@ -459,4 +460,20 @@ class Config
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by long-running custom scripts in composer.json
|
||||
*
|
||||
* "scripts": {
|
||||
* "watch": [
|
||||
* "Composer\\Config::disableProcessTimeout",
|
||||
* "vendor/bin/long-running-script --watch"
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
public static function disableProcessTimeout()
|
||||
{
|
||||
// Override global timeout set earlier by environment or config
|
||||
ProcessExecutor::setTimeout(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ interface ConfigSourceInterface
|
|||
* Add a config setting
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param string $value Value
|
||||
* @param string|array $value Value
|
||||
*/
|
||||
public function addConfigSetting($name, $value);
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*
|
||||
* @param array $array
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
* @return int
|
||||
*/
|
||||
private function arrayUnshiftRef(&$array, &$value)
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@ class Application extends BaseApplication
|
|||
|
||||
$this->io = new NullIO();
|
||||
|
||||
parent::__construct('Composer', Composer::VERSION);
|
||||
parent::__construct('Composer', Composer::getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,7 +190,7 @@ class Application extends BaseApplication
|
|||
if (!$isProxyCommand) {
|
||||
$io->writeError(sprintf(
|
||||
'Running %s (%s) with %s on %s',
|
||||
Composer::VERSION,
|
||||
Composer::getVersion(),
|
||||
Composer::RELEASE_DATE,
|
||||
defined('HHVM_VERSION') ? 'HHVM '.HHVM_VERSION : 'PHP '.PHP_VERSION,
|
||||
function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS'
|
||||
|
@ -284,7 +284,7 @@ class Application extends BaseApplication
|
|||
|
||||
return $result;
|
||||
} catch (ScriptExecutionException $e) {
|
||||
return $e->getCode();
|
||||
return (int) $e->getCode();
|
||||
} catch (\Exception $e) {
|
||||
$this->hintCommonErrors($e);
|
||||
restore_error_handler();
|
||||
|
@ -440,7 +440,7 @@ class Application extends BaseApplication
|
|||
*/
|
||||
public function getLongVersion()
|
||||
{
|
||||
if (Composer::BRANCH_ALIAS_VERSION) {
|
||||
if (Composer::BRANCH_ALIAS_VERSION && Composer::BRANCH_ALIAS_VERSION !== '@package_branch_alias_version'.'@') {
|
||||
return sprintf(
|
||||
'<info>%s</info> version <comment>%s (%s)</comment> %s',
|
||||
$this->getName(),
|
||||
|
|
|
@ -23,10 +23,10 @@ class GenericRule extends Rule
|
|||
protected $literals;
|
||||
|
||||
/**
|
||||
* @param array $literals
|
||||
* @param int $reason A RULE_* constant describing the reason for generating this rule
|
||||
* @param Link|PackageInterface $reasonData
|
||||
* @param array $job The job this rule was created from
|
||||
* @param array $literals
|
||||
* @param int|null $reason A RULE_* constant describing the reason for generating this rule
|
||||
* @param Link|PackageInterface|int|null $reasonData
|
||||
* @param array $job The job this rule was created from
|
||||
*/
|
||||
public function __construct(array $literals, $reason, $reasonData, $job = null)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ class PoolBuilder
|
|||
|
||||
public function buildPool(array $repositories, array $rootAliases, Request $request)
|
||||
{
|
||||
$this->pool = new Pool($this->filterRequires);
|
||||
$pool = new Pool($this->filterRequires);
|
||||
$this->rootAliases = $rootAliases;
|
||||
|
||||
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
||||
|
@ -137,13 +137,13 @@ class PoolBuilder
|
|||
}
|
||||
}
|
||||
|
||||
$this->pool->setPackages($this->packages, $this->priorities);
|
||||
$pool->setPackages($this->packages, $this->priorities);
|
||||
|
||||
unset($this->aliasMap);
|
||||
unset($this->loadedNames);
|
||||
unset($this->nameConstraints);
|
||||
|
||||
return $this->pool;
|
||||
return $pool;
|
||||
}
|
||||
|
||||
private function loadPackage(PackageInterface $package, $repoIndex)
|
||||
|
@ -180,12 +180,12 @@ class PoolBuilder
|
|||
if (!isset($this->loadedNames[$require])) {
|
||||
$loadNames[$require] = null;
|
||||
}
|
||||
if ($link->getConstraint()) {
|
||||
if ($linkConstraint = $link->getConstraint()) {
|
||||
if (!array_key_exists($require, $this->nameConstraints)) {
|
||||
$this->nameConstraints[$require] = new MultiConstraint(array($link->getConstraint()), false);
|
||||
$this->nameConstraints[$require] = new MultiConstraint(array($linkConstraint), false);
|
||||
} elseif ($this->nameConstraints[$require]) {
|
||||
// TODO addConstraint function?
|
||||
$this->nameConstraints[$require] = new MultiConstraint(array_merge(array($link->getConstraint()), $this->nameConstraints[$require]->getConstraints()), false);
|
||||
$this->nameConstraints[$require] = new MultiConstraint(array_merge(array($linkConstraint), $this->nameConstraints[$require]->getConstraints()), false);
|
||||
}
|
||||
} else {
|
||||
$this->nameConstraints[$require] = null;
|
||||
|
|
|
@ -79,11 +79,13 @@ class Problem
|
|||
reset($reasons);
|
||||
$reason = current($reasons);
|
||||
|
||||
$rule = $reason['rule'];
|
||||
$job = $reason['job'];
|
||||
|
||||
if (isset($job['constraint'])) {
|
||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||
$packageName = $job['packageName'];
|
||||
$constraint = $job['constraint'];
|
||||
|
||||
if (isset($constraint)) {
|
||||
$packages = $this->pool->whatProvides($packageName, $constraint);
|
||||
} else {
|
||||
$packages = array();
|
||||
}
|
||||
|
@ -91,9 +93,9 @@ class Problem
|
|||
if ($job && $job['cmd'] === 'install' && empty($packages)) {
|
||||
|
||||
// handle php/hhvm
|
||||
if ($job['packageName'] === 'php' || $job['packageName'] === 'php-64bit' || $job['packageName'] === 'hhvm') {
|
||||
if ($packageName === 'php' || $packageName === 'php-64bit' || $packageName === 'hhvm') {
|
||||
$version = phpversion();
|
||||
$available = $this->pool->whatProvides($job['packageName']);
|
||||
$available = $this->pool->whatProvides($packageName);
|
||||
|
||||
if (count($available)) {
|
||||
$firstAvailable = reset($available);
|
||||
|
@ -104,13 +106,13 @@ class Problem
|
|||
}
|
||||
}
|
||||
|
||||
$msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but ';
|
||||
$msg = "\n - This package requires ".$packageName.$this->constraintToText($constraint).' but ';
|
||||
|
||||
if (defined('HHVM_VERSION') || count($available)) {
|
||||
if (defined('HHVM_VERSION') || (count($available) && $packageName === 'hhvm')) {
|
||||
return $msg . 'your HHVM version does not satisfy that requirement.';
|
||||
}
|
||||
|
||||
if ($job['packageName'] === 'hhvm') {
|
||||
if ($packageName === 'hhvm') {
|
||||
return $msg . 'you are running this with PHP and not HHVM.';
|
||||
}
|
||||
|
||||
|
@ -118,43 +120,43 @@ class Problem
|
|||
}
|
||||
|
||||
// handle php extensions
|
||||
if (0 === stripos($job['packageName'], 'ext-')) {
|
||||
if (false !== strpos($job['packageName'], ' ')) {
|
||||
return "\n - The requested PHP extension ".$job['packageName'].' should be required as '.str_replace(' ', '-', $job['packageName']).'.';
|
||||
if (0 === stripos($packageName, 'ext-')) {
|
||||
if (false !== strpos($packageName, ' ')) {
|
||||
return "\n - The requested PHP extension ".$packageName.' should be required as '.str_replace(' ', '-', $packageName).'.';
|
||||
}
|
||||
|
||||
$ext = substr($job['packageName'], 4);
|
||||
$ext = substr($packageName, 4);
|
||||
$error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
|
||||
|
||||
return "\n - The requested PHP extension ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error.'. Install or enable PHP\'s '.$ext.' extension.';
|
||||
return "\n - The requested PHP extension ".$packageName.$this->constraintToText($constraint).' '.$error.'. Install or enable PHP\'s '.$ext.' extension.';
|
||||
}
|
||||
|
||||
// handle linked libs
|
||||
if (0 === stripos($job['packageName'], 'lib-')) {
|
||||
if (strtolower($job['packageName']) === 'lib-icu') {
|
||||
if (0 === stripos($packageName, 'lib-')) {
|
||||
if (strtolower($packageName) === 'lib-icu') {
|
||||
$error = extension_loaded('intl') ? 'has the wrong version installed, try upgrading the intl extension.' : 'is missing from your system, make sure the intl extension is loaded.';
|
||||
|
||||
return "\n - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error;
|
||||
return "\n - The requested linked library ".$packageName.$this->constraintToText($constraint).' '.$error;
|
||||
}
|
||||
|
||||
return "\n - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.';
|
||||
return "\n - The requested linked library ".$packageName.$this->constraintToText($constraint).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.';
|
||||
}
|
||||
|
||||
if (!preg_match('{^[A-Za-z0-9_./-]+$}', $job['packageName'])) {
|
||||
$illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $job['packageName']);
|
||||
if (!preg_match('{^[A-Za-z0-9_./-]+$}', $packageName)) {
|
||||
$illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $packageName);
|
||||
|
||||
return "\n - The requested package ".$job['packageName'].' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.';
|
||||
return "\n - The requested package ".$packageName.' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.';
|
||||
}
|
||||
|
||||
if ($providers = $this->pool->whatProvides($job['packageName'], $job['constraint'], true, true)) {
|
||||
return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' is satisfiable by '.$this->getPackageList($providers).' but these conflict with your requirements or minimum-stability.';
|
||||
if ($providers = $this->pool->whatProvides($packageName, $constraint, true, true)) {
|
||||
return "\n - The requested package ".$packageName.$this->constraintToText($constraint).' is satisfiable by '.$this->getPackageList($providers).' but these conflict with your requirements or minimum-stability.';
|
||||
}
|
||||
|
||||
if ($providers = $this->pool->whatProvides($job['packageName'], null, true, true)) {
|
||||
return "\n - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' exists as '.$this->getPackageList($providers).' but these are rejected by your constraint.';
|
||||
if ($providers = $this->pool->whatProvides($packageName, null, true, true)) {
|
||||
return "\n - The requested package ".$packageName.$this->constraintToText($constraint).' exists as '.$this->getPackageList($providers).' but these are rejected by your constraint.';
|
||||
}
|
||||
|
||||
return "\n - The requested package ".$job['packageName'].' could not be found in any version, there may be a typo in the package name.';
|
||||
return "\n - The requested package ".$packageName.' could not be found in any version, there may be a typo in the package name.';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +182,7 @@ class Problem
|
|||
* Store a reason descriptor but ignore duplicates
|
||||
*
|
||||
* @param string $id A canonical identifier for the reason
|
||||
* @param string $reason The reason descriptor
|
||||
* @param string|array $reason The reason descriptor
|
||||
*/
|
||||
protected function addReason($id, $reason)
|
||||
{
|
||||
|
@ -203,27 +205,29 @@ class Problem
|
|||
*/
|
||||
protected function jobToText($job)
|
||||
{
|
||||
$packageName = $job['packageName'];
|
||||
$constraint = $job['constraint'];
|
||||
switch ($job['cmd']) {
|
||||
case 'install':
|
||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||
$packages = $this->pool->whatProvides($packageName, $constraint);
|
||||
if (!$packages) {
|
||||
return 'No package found to satisfy install request for '.$job['packageName'].$this->constraintToText($job['constraint']);
|
||||
return 'No package found to satisfy install request for '.$packageName.$this->constraintToText($constraint);
|
||||
}
|
||||
|
||||
return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).' -> satisfiable by '.$this->getPackageList($packages).'.';
|
||||
return 'Installation request for '.$packageName.$this->constraintToText($constraint).' -> satisfiable by '.$this->getPackageList($packages).'.';
|
||||
case 'update':
|
||||
return 'Update request for '.$job['packageName'].$this->constraintToText($job['constraint']).'.';
|
||||
return 'Update request for '.$packageName.$this->constraintToText($constraint).'.';
|
||||
case 'remove':
|
||||
return 'Removal request for '.$job['packageName'].$this->constraintToText($job['constraint']).'';
|
||||
return 'Removal request for '.$packageName.$this->constraintToText($constraint).'';
|
||||
}
|
||||
|
||||
if (isset($job['constraint'])) {
|
||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||
if (isset($constraint)) {
|
||||
$packages = $this->pool->whatProvides($packageName, $constraint);
|
||||
} else {
|
||||
$packages = $this->pool->whatProvides($job['packageName'], null);
|
||||
}
|
||||
|
||||
return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])';
|
||||
return 'Job(cmd='.$job['cmd'].', target='.$packageName.', packages=['.$this->getPackageList($packages).'])';
|
||||
}
|
||||
|
||||
protected function getPackageList($packages)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositorySet;
|
||||
|
@ -39,7 +40,7 @@ class Solver
|
|||
protected $watchGraph;
|
||||
/** @var Decisions */
|
||||
protected $decisions;
|
||||
/** @var Package[] */
|
||||
/** @var PackageInterface[] */
|
||||
protected $fixedMap;
|
||||
|
||||
/** @var int */
|
||||
|
@ -659,7 +660,7 @@ class Solver
|
|||
/**
|
||||
* @todo this makes $disableRules always false; determine the rationale and possibly remove dead code?
|
||||
*/
|
||||
$disableRules = array();
|
||||
$disableRules = false;
|
||||
|
||||
$level = 1;
|
||||
$systemLevel = $level + 1;
|
||||
|
|
|
@ -294,9 +294,7 @@ class DownloadManager
|
|||
|
||||
// if downloader type changed, or update failed and user asks for reinstall,
|
||||
// we wipe the dir and do a new install instead of updating it
|
||||
if ($initialDownloader) {
|
||||
$initialDownloader->remove($initial, $targetDir);
|
||||
}
|
||||
$initialDownloader->remove($initial, $targetDir);
|
||||
$this->install($target, $targetDir);
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
|
|||
) {
|
||||
$command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
|
||||
if (0 === $this->process->execute($command, $output, $path)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,14 +380,14 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
|
|||
) {
|
||||
$command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference));
|
||||
if (0 === $this->process->execute($command, $output, $path)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$command = sprintf($template, ProcessExecutor::escape($gitRef));
|
||||
if (0 === $this->process->execute($command, $output, $path)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// reference was not found (prints "fatal: reference is not a tree: $ref")
|
||||
|
|
|
@ -28,6 +28,7 @@ use Composer\IO\IOInterface;
|
|||
*/
|
||||
class GzipDownloader extends ArchiveDownloader
|
||||
{
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
|
||||
public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
|
||||
|
|
|
@ -91,6 +91,12 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
|||
$allowedStrategies = array(self::STRATEGY_MIRROR);
|
||||
}
|
||||
|
||||
// Check we can use junctions safely if we are on Windows
|
||||
if (Platform::isWindows() && self::STRATEGY_SYMLINK === $currentStrategy && !$this->safeJunctions()) {
|
||||
$currentStrategy = self::STRATEGY_MIRROR;
|
||||
$allowedStrategies = array(self::STRATEGY_MIRROR);
|
||||
}
|
||||
|
||||
$fileSystem = new Filesystem();
|
||||
$this->filesystem->removeDirectory($path);
|
||||
|
||||
|
@ -181,4 +187,25 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
|
|||
return $packageVersion['commit'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if junctions can be created and safely used on Windows
|
||||
*
|
||||
* A PHP bug makes junction detection fragile, leading to possible data loss
|
||||
* when removing a package. See https://bugs.php.net/bug.php?id=77552
|
||||
*
|
||||
* For safety we require a minimum version of Windows 7, so we can call the
|
||||
* system rmdir which will preserve target content if given a junction.
|
||||
*
|
||||
* The PHP bug was fixed in 7.2.16 and 7.3.3 (requires at least Windows 7).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function safeJunctions()
|
||||
{
|
||||
// We need to call mklink, and rmdir on Windows 7 (version 6.1)
|
||||
return function_exists('proc_open') &&
|
||||
(PHP_WINDOWS_VERSION_MAJOR > 6 ||
|
||||
(PHP_WINDOWS_VERSION_MAJOR === 6 && PHP_WINDOWS_VERSION_MINOR >= 1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class PerforceDownloader extends VcsDownloader
|
|||
*/
|
||||
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
|
||||
{
|
||||
$this->doDownload($target, $path, $url);
|
||||
$this->doInstall($target, $path, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,7 +88,7 @@ class PerforceDownloader extends VcsDownloader
|
|||
{
|
||||
$this->io->writeError('Perforce driver does not check for local changes before overriding', true);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,6 +32,7 @@ use RarArchive;
|
|||
*/
|
||||
class RarDownloader extends ArchiveDownloader
|
||||
{
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
|
||||
public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
|
||||
|
|
|
@ -28,6 +28,7 @@ use Composer\IO\IOInterface;
|
|||
*/
|
||||
class XzDownloader extends ArchiveDownloader
|
||||
{
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
|
||||
public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
|
||||
|
|
|
@ -33,7 +33,9 @@ class ZipDownloader extends ArchiveDownloader
|
|||
private static $hasZipArchive;
|
||||
private static $isWindows;
|
||||
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
/** @var ZipArchive|null */
|
||||
private $zipArchiveObject;
|
||||
|
||||
public function __construct(IOInterface $io, Config $config, HttpDownloader $downloader, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
|
||||
|
|
|
@ -47,7 +47,7 @@ class EventDispatcher
|
|||
protected $io;
|
||||
protected $loader;
|
||||
protected $process;
|
||||
protected $listeners;
|
||||
protected $listeners = array();
|
||||
private $eventStack;
|
||||
|
||||
/**
|
||||
|
@ -173,6 +173,9 @@ class EventDispatcher
|
|||
|
||||
throw new \RuntimeException('Subscriber '.$className.'::'.$callable[1].' for event '.$event->getName().' is not callable, make sure the function is defined and public');
|
||||
}
|
||||
if (is_array($callable) && (is_string($callable[0]) || is_object($callable[0])) && is_string($callable[1])) {
|
||||
$this->io->writeError(sprintf('> %s: %s', $event->getName(), (is_object($callable[0]) ? get_class($callable[0]) : $callable[0]).'->'.$callable[1] ), true, IOInterface::VERBOSE);
|
||||
}
|
||||
$event = $this->checkListenerExpectedEvent($callable, $event);
|
||||
$return = false === call_user_func($callable, $event) ? 1 : 0;
|
||||
} elseif ($this->isComposerScript($callable)) {
|
||||
|
@ -197,6 +200,7 @@ class EventDispatcher
|
|||
}
|
||||
|
||||
try {
|
||||
/** @var InstallerEvent $event */
|
||||
$return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags));
|
||||
} catch (ScriptExecutionException $e) {
|
||||
$this->io->writeError(sprintf('<error>Script %s was called via %s</error>', $callable, $event->getName()), true, IOInterface::QUIET);
|
||||
|
@ -365,6 +369,22 @@ class EventDispatcher
|
|||
$this->listeners[$eventName][$priority][] = $listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable|object $listener A callable or an object instance for which all listeners should be removed
|
||||
*/
|
||||
public function removeListener($listener)
|
||||
{
|
||||
foreach ($this->listeners as $eventName => $priorities) {
|
||||
foreach ($priorities as $priority => $listeners) {
|
||||
foreach ($listeners as $index => $candidate) {
|
||||
if ($listener === $candidate || (is_array($candidate) && is_object($listener) && $candidate[0] === $listener)) {
|
||||
unset($this->listeners[$eventName][$priority][$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds object methods as listeners for the events in getSubscribedEvents
|
||||
*
|
||||
|
@ -481,7 +501,7 @@ class EventDispatcher
|
|||
*
|
||||
* @param Event $event
|
||||
* @throws \RuntimeException
|
||||
* @return number
|
||||
* @return int
|
||||
*/
|
||||
protected function pushEvent(Event $event)
|
||||
{
|
||||
|
|
|
@ -413,7 +413,7 @@ class Factory
|
|||
/**
|
||||
* @param IOInterface $io IO instance
|
||||
* @param bool $disablePlugins Whether plugins should not be loaded
|
||||
* @return Composer
|
||||
* @return Composer|null
|
||||
*/
|
||||
public static function createGlobal(IOInterface $io, $disablePlugins = false)
|
||||
{
|
||||
|
|
|
@ -14,10 +14,9 @@ namespace Composer\IO;
|
|||
|
||||
use Composer\Config;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
abstract class BaseIO implements IOInterface, LoggerInterface
|
||||
abstract class BaseIO implements IOInterface
|
||||
{
|
||||
protected $authentications = array();
|
||||
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
namespace Composer\IO;
|
||||
|
||||
use Composer\Config;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* The Input/Output helper interface.
|
||||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
*/
|
||||
interface IOInterface
|
||||
interface IOInterface extends LoggerInterface
|
||||
{
|
||||
const QUIET = 1;
|
||||
const NORMAL = 2;
|
||||
|
@ -107,7 +108,7 @@ interface IOInterface
|
|||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @throws \RuntimeException If there is no data to read in the input stream
|
||||
* @return string The user answer
|
||||
* @return string|null The user answer
|
||||
*/
|
||||
public function ask($question, $default = null);
|
||||
|
||||
|
@ -145,7 +146,7 @@ interface IOInterface
|
|||
*
|
||||
* @param string $question The question to ask
|
||||
*
|
||||
* @return string The answer
|
||||
* @return string|null The answer
|
||||
*/
|
||||
public function askAndHideAnswer($question);
|
||||
|
||||
|
@ -160,7 +161,7 @@ interface IOInterface
|
|||
* @param bool $multiselect Select more than one value separated by comma
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return int|string|array The selected value or values (the key of the choices array)
|
||||
* @return int|string|array|bool The selected value or values (the key of the choices array)
|
||||
*/
|
||||
public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false);
|
||||
|
||||
|
|
|
@ -399,6 +399,8 @@ class Installer
|
|||
$solver = new Solver($policy, $pool, $this->io);
|
||||
try {
|
||||
$lockTransaction = $solver->solve($request, $this->ignorePlatformReqs);
|
||||
$ruleSetSize = $solver->getRuleSetSize();
|
||||
$solver = null;
|
||||
} catch (SolverProblemsException $e) {
|
||||
$this->io->writeError('<error>Your requirements could not be resolved to an installable set of packages.</error>', true, IOInterface::QUIET);
|
||||
$this->io->writeError($e->getMessage());
|
||||
|
@ -413,7 +415,7 @@ class Installer
|
|||
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $lockedRepository, $request, $lockTransaction);
|
||||
|
||||
$this->io->writeError("Analyzed ".count($pool)." packages to resolve dependencies", true, IOInterface::VERBOSE);
|
||||
$this->io->writeError("Analyzed ".$solver->getRuleSetSize()." rules to resolve dependencies", true, IOInterface::VERBOSE);
|
||||
$this->io->writeError("Analyzed ".$ruleSetSize." rules to resolve dependencies", true, IOInterface::VERBOSE);
|
||||
|
||||
if (!$lockTransaction->getOperations()) {
|
||||
$this->io->writeError('Nothing to modify in lock file');
|
||||
|
@ -559,6 +561,7 @@ class Installer
|
|||
$solver = new Solver($policy, $pool, $this->io);
|
||||
try {
|
||||
$lockTransaction = $solver->solve($request, $this->ignorePlatformReqs);
|
||||
$solver = null;
|
||||
|
||||
// installing the locked packages on this platfom resulted in lock modifying operations, there wasn't a conflict, but the lock file as-is seems to not work on this system
|
||||
if (0 !== count($lockTransaction->getOperations())) {
|
||||
|
|
|
@ -48,7 +48,7 @@ interface InstallerInterface
|
|||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param PackageInterface $prevPackage previous package instance in case of an update
|
||||
* @return PromiseInterface
|
||||
* @return PromiseInterface|null
|
||||
*/
|
||||
public function download(PackageInterface $package, PackageInterface $prevPackage = null);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
*
|
||||
* @param IOInterface $io
|
||||
* @param Composer $composer
|
||||
* @param string $type
|
||||
* @param string|null $type
|
||||
* @param Filesystem $filesystem
|
||||
* @param BinaryInstaller $binaryInstaller
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,7 @@ class JsonManipulator
|
|||
private static $DEFINES = '(?(DEFINE)
|
||||
(?<number> -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
|
||||
(?<boolean> true | false | null )
|
||||
(?<string> " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " )
|
||||
(?<string> " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " )
|
||||
(?<array> \[ (?: (?&json) \s* (?: , (?&json) \s* )* )? \s* \] )
|
||||
(?<pair> \s* (?&string) \s* : (?&json) \s* )
|
||||
(?<object> \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} )
|
||||
|
|
|
@ -401,4 +401,14 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
|
|||
{
|
||||
return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';
|
||||
}
|
||||
|
||||
public function setDistUrl($url)
|
||||
{
|
||||
return $this->aliasOf->setDistUrl($url);
|
||||
}
|
||||
|
||||
public function setDistType($type)
|
||||
{
|
||||
return $this->aliasOf->setDistType($type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ abstract class BasePackage implements PackageInterface
|
|||
* Build a regexp from a package name, expanding * globs as required
|
||||
*
|
||||
* @param string $whiteListedPattern
|
||||
* @param bool $wrap Wrap the cleaned string by the given string
|
||||
* @param string $wrap Wrap the cleaned string by the given string
|
||||
* @return string
|
||||
*/
|
||||
public static function packageNameToRegexp($whiteListedPattern, $wrap = '{^%s$}i')
|
||||
|
|
|
@ -62,39 +62,16 @@ class ArrayLoader implements LoaderInterface
|
|||
|
||||
public function loadPackages(array $versions, $class)
|
||||
{
|
||||
static $uniqKeys = array('version', 'version_normalized', 'source', 'dist', 'time');
|
||||
|
||||
$packages = array();
|
||||
$linkCache = array();
|
||||
|
||||
foreach ($versions as $version) {
|
||||
if (isset($version['versions'])) {
|
||||
$baseVersion = $version;
|
||||
foreach ($uniqKeys as $key) {
|
||||
unset($baseVersion[$key.'s']);
|
||||
}
|
||||
$package = $this->createObject($version, $class);
|
||||
|
||||
foreach ($version['versions'] as $index => $dummy) {
|
||||
$unpackedVersion = $baseVersion;
|
||||
foreach ($uniqKeys as $key) {
|
||||
$unpackedVersion[$key] = $version[$key.'s'][$index];
|
||||
}
|
||||
$this->configureCachedLinks($linkCache, $package, $version);
|
||||
$package = $this->configureObject($package, $version);
|
||||
|
||||
$package = $this->createObject($unpackedVersion, $class);
|
||||
|
||||
$this->configureCachedLinks($linkCache, $package, $unpackedVersion);
|
||||
$package = $this->configureObject($package, $unpackedVersion);
|
||||
|
||||
$packages[] = $package;
|
||||
}
|
||||
} else {
|
||||
$package = $this->createObject($version, $class);
|
||||
|
||||
$this->configureCachedLinks($linkCache, $package, $version);
|
||||
$package = $this->configureObject($package, $version);
|
||||
|
||||
$packages[] = $package;
|
||||
}
|
||||
$packages[] = $package;
|
||||
}
|
||||
|
||||
return $packages;
|
||||
|
|
|
@ -49,6 +49,10 @@ class ValidatingArrayLoader implements LoaderInterface
|
|||
$this->warnings = array();
|
||||
$this->config = $config;
|
||||
|
||||
if ($err = self::hasPackageNamingError($config['name'])) {
|
||||
$this->warnings[] = 'Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.';
|
||||
}
|
||||
|
||||
if ($this->strictName) {
|
||||
$this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true);
|
||||
} else {
|
||||
|
@ -195,7 +199,9 @@ class ValidatingArrayLoader implements LoaderInterface
|
|||
foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
|
||||
if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
|
||||
foreach ($this->config[$linkType] as $package => $constraint) {
|
||||
if (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) {
|
||||
if ($err = self::hasPackageNamingError($package, true)) {
|
||||
$this->warnings[] = 'Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.';
|
||||
} elseif (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) {
|
||||
$this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]';
|
||||
}
|
||||
if (!is_string($constraint)) {
|
||||
|
|
|
@ -31,13 +31,21 @@ use Seld\JsonLint\ParsingException;
|
|||
*/
|
||||
class Locker
|
||||
{
|
||||
/** @var JsonFile */
|
||||
private $lockFile;
|
||||
/** @var RepositoryManager */
|
||||
private $repositoryManager;
|
||||
/** @var InstallationManager */
|
||||
private $installationManager;
|
||||
/** @var string */
|
||||
private $hash;
|
||||
/** @var string */
|
||||
private $contentHash;
|
||||
/** @var ArrayLoader */
|
||||
private $loader;
|
||||
/** @var ArrayDumper */
|
||||
private $dumper;
|
||||
/** @var ProcessExecutor */
|
||||
private $process;
|
||||
private $lockDataCache;
|
||||
private $virtualFileWritten;
|
||||
|
|
|
@ -76,7 +76,7 @@ interface PackageInterface
|
|||
/**
|
||||
* Returns the package targetDir property
|
||||
*
|
||||
* @return string The package targetDir
|
||||
* @return string|null The package targetDir
|
||||
*/
|
||||
public function getTargetDir();
|
||||
|
||||
|
@ -358,4 +358,32 @@ interface PackageInterface
|
|||
* @return array
|
||||
*/
|
||||
public function getTransportOptions();
|
||||
|
||||
/**
|
||||
* @param string $reference
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSourceReference($reference);
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDistUrl($url);
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDistType($type);
|
||||
|
||||
/**
|
||||
* @param string $reference
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDistReference($reference);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use Composer\Repository\Vcs\HgDriver;
|
|||
use Composer\IO\NullIO;
|
||||
use Composer\Semver\VersionParser as SemverVersionParser;
|
||||
use Composer\Util\Git as GitUtil;
|
||||
use Composer\Util\HttpDownloader;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\Svn as SvnUtil;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class VersionSelector
|
|||
* @param string $targetPackageVersion
|
||||
* @param string $targetPhpVersion
|
||||
* @param string $preferredStability
|
||||
* @return PackageInterface|bool
|
||||
* @return PackageInterface|false
|
||||
*/
|
||||
public function findBestCandidate($packageName, $targetPackageVersion = null, $targetPhpVersion = null, $preferredStability = 'stable')
|
||||
{
|
||||
|
|
|
@ -15,15 +15,16 @@ namespace Composer\Plugin;
|
|||
use Composer\Composer;
|
||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\CompletePackage;
|
||||
use Composer\Package\Package;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Repository\RepositorySet;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Composer\Plugin\Capability\Capability;
|
||||
use Composer\Util\PackageSorter;
|
||||
|
||||
/**
|
||||
* Plugin manager
|
||||
|
@ -253,8 +254,10 @@ class PluginManager
|
|||
*/
|
||||
private function loadRepository(RepositoryInterface $repo)
|
||||
{
|
||||
foreach ($repo->getPackages() as $package) { /** @var PackageInterface $package */
|
||||
if ($package instanceof AliasPackage) {
|
||||
$packages = $repo->getPackages();
|
||||
$sortedPackages = array_reverse(PackageSorter::sortPackages($packages));
|
||||
foreach ($sortedPackages as $package) {
|
||||
if (!($package instanceof CompletePackage)) {
|
||||
continue;
|
||||
}
|
||||
if ('composer-plugin' === $package->getType()) {
|
||||
|
|
|
@ -32,9 +32,11 @@ abstract class BaseRepository implements RepositoryInterface
|
|||
|
||||
$result = array();
|
||||
foreach ($packages as $package) {
|
||||
if (array_key_exists($package->getName(), $packageMap) &&
|
||||
(!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion()))) &&
|
||||
call_user_func($isPackageAcceptableCallable, $package->getNames(), $package->getStability())) {
|
||||
if (
|
||||
array_key_exists($package->getName(), $packageMap)
|
||||
&& (!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion())))
|
||||
&& call_user_func($isPackageAcceptableCallable, $package->getNames(), $package->getStability())
|
||||
) {
|
||||
$result[spl_object_hash($package)] = $package;
|
||||
if ($package instanceof AliasPackage && !isset($result[spl_object_hash($package->getAliasOf())])) {
|
||||
$result[spl_object_hash($package->getAliasOf())] = $package->getAliasOf();
|
||||
|
|
|
@ -19,6 +19,7 @@ use Composer\Package\Version\VersionParser;
|
|||
use Composer\Json\JsonFile;
|
||||
use Composer\Cache;
|
||||
use Composer\Config;
|
||||
use Composer\Composer;
|
||||
use Composer\Factory;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\HttpDownloader;
|
||||
|
@ -103,7 +104,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
|
||||
$this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
|
||||
$this->io = $io;
|
||||
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
|
||||
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$~');
|
||||
$this->versionParser = new VersionParser();
|
||||
$this->loader = new ArrayLoader($this->versionParser);
|
||||
$this->httpDownloader = $httpDownloader;
|
||||
|
@ -139,9 +140,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
return;
|
||||
}
|
||||
|
||||
$packages = $this->loadAsyncPackages(array($name => $constraint), function ($name, $stability) {
|
||||
return true;
|
||||
});
|
||||
$packages = $this->loadAsyncPackages(array($name => $constraint));
|
||||
|
||||
return reset($packages);
|
||||
}
|
||||
|
@ -181,9 +180,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
return array();
|
||||
}
|
||||
|
||||
return $this->loadAsyncPackages(array($name => $constraint ?: new EmptyConstraint()), function ($name, $stability) {
|
||||
return true;
|
||||
});
|
||||
return $this->loadAsyncPackages(array($name => $constraint));
|
||||
}
|
||||
|
||||
if ($hasProviders) {
|
||||
|
@ -241,7 +238,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$packageMap[$name] = new EmptyConstraint();
|
||||
}
|
||||
|
||||
return array_values($this->loadAsyncPackages($packageMap, function ($name, $stability) { return true; }));
|
||||
return array_values($this->loadAsyncPackages($packageMap));
|
||||
}
|
||||
|
||||
throw new \LogicException('Composer repositories that have lazy providers and no available-packages list can not load the complete list of packages, use getProviderNames instead.');
|
||||
|
@ -313,9 +310,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add aliases of matched packages even if they did not match the constraint
|
||||
foreach ($candidates as $candidate) {
|
||||
if ($candidate instanceof AliasPackage) {
|
||||
if (isset($result[spl_object_hash($candidate->getAliasOf())])) {
|
||||
if (isset($matches[spl_object_hash($candidate->getAliasOf())])) {
|
||||
$matches[spl_object_hash($candidate)] = $candidate;
|
||||
}
|
||||
}
|
||||
|
@ -511,11 +510,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
|
||||
if (!isset($versionsToLoad[$version['uid']])) {
|
||||
if ($isPackageAcceptableCallable && !call_user_func($isPackageAcceptableCallable, $normalizedName, VersionParser::parseStability($version['version']))) {
|
||||
continue;
|
||||
if (!isset($version['version_normalized'])) {
|
||||
$version['version_normalized'] = $this->versionParser->normalize($version['version']);
|
||||
}
|
||||
|
||||
$versionsToLoad[$version['uid']] = $version;
|
||||
if ($this->isVersionAcceptable($isPackageAcceptableCallable, null, $normalizedName, $version)) {
|
||||
$versionsToLoad[$version['uid']] = $version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -567,7 +568,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$this->configurePackageTransportOptions($package);
|
||||
}
|
||||
|
||||
private function loadAsyncPackages(array $packageNames, $isPackageAcceptableCallable)
|
||||
/**
|
||||
* @param array $packageNames array of package name => ConstraintInterface|null - if a constraint is provided, only packages matching it will be loaded
|
||||
*/
|
||||
private function loadAsyncPackages(array $packageNames, $isPackageAcceptableCallable = null)
|
||||
{
|
||||
$this->loadRootServerFile();
|
||||
|
||||
|
@ -579,16 +583,24 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
throw new \LogicException('loadAsyncPackages only supports v2 protocol composer repos with a metadata-url');
|
||||
}
|
||||
|
||||
// load ~dev variants as well if present
|
||||
// TODO ideally there should be a flag set from the repositoryset/poolbuilder to know which packages should have the dev packages loaded
|
||||
// so we can optimize away some requests entirely
|
||||
foreach ($packageNames as $name => $constraint) {
|
||||
$packageNames[$name.'~dev'] = $constraint;
|
||||
}
|
||||
|
||||
foreach ($packageNames as $name => $constraint) {
|
||||
$name = strtolower($name);
|
||||
|
||||
$realName = preg_replace('{~dev$}', '', $name);
|
||||
// skip platform packages, root package and composer-plugin-api
|
||||
if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name || 'composer-plugin-api' === $name) {
|
||||
if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $realName) || '__root__' === $realName || 'composer-plugin-api' === $realName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = str_replace('%package%', $name, $this->lazyProvidersUrl);
|
||||
$cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
|
||||
$cacheKey = 'provider-'.strtr($name, '/', '~').'.json';
|
||||
|
||||
$lastModified = null;
|
||||
if ($contents = $this->cache->read($cacheKey)) {
|
||||
|
@ -597,16 +609,16 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
|
||||
$promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
|
||||
->then(function ($response) use (&$packages, $contents, $name, $constraint, $repo, $isPackageAcceptableCallable) {
|
||||
->then(function ($response) use (&$packages, $contents, $realName, $constraint, $repo, $isPackageAcceptableCallable) {
|
||||
if (true === $response) {
|
||||
$response = $contents;
|
||||
}
|
||||
|
||||
if (!isset($response['packages'][$name])) {
|
||||
if (!isset($response['packages'][$realName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$versions = $response['packages'][$name];
|
||||
$versions = $response['packages'][$realName];
|
||||
|
||||
if (isset($response['minified']) && $response['minified'] === 'composer/2.0') {
|
||||
// TODO extract in other method
|
||||
|
@ -635,37 +647,24 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
unset($expanded, $expandedVersion, $versionData);
|
||||
}
|
||||
|
||||
static $uniqKeys = array('version', 'version_normalized', 'source', 'dist', 'time');
|
||||
$versionsToLoad = array();
|
||||
foreach ($versions as $version) {
|
||||
if (isset($version['version_normalizeds'])) {
|
||||
foreach ($version['version_normalizeds'] as $index => $normalizedVersion) {
|
||||
if (!$repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $normalizedVersion)) {
|
||||
foreach ($uniqKeys as $key) {
|
||||
unset($version[$key.'s'][$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($version['version_normalizeds'])) {
|
||||
$versionsToLoad[] = $version;
|
||||
}
|
||||
} else {
|
||||
if (!isset($version['version_normalized'])) {
|
||||
$version['version_normalized'] = $repo->versionParser->normalize($version['version']);
|
||||
}
|
||||
if (!isset($version['version_normalized'])) {
|
||||
$version['version_normalized'] = $repo->versionParser->normalize($version['version']);
|
||||
}
|
||||
|
||||
if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $version['version_normalized'])) {
|
||||
$versionsToLoad[] = $version;
|
||||
}
|
||||
if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version)) {
|
||||
$versionsToLoad[] = $version;
|
||||
}
|
||||
}
|
||||
|
||||
$loadedPackages = $repo->createPackages($versionsToLoad, 'Composer\Package\CompletePackage');
|
||||
foreach ($loadedPackages as $package) {
|
||||
$package->setRepository($repo);
|
||||
|
||||
$packages[spl_object_hash($package)] = $package;
|
||||
|
||||
if ($package instanceof AliasPackage && !isset($packages[spl_object_hash($package->getAliasOf())])) {
|
||||
$package->getAliasOf()->setRepository($repo);
|
||||
$packages[spl_object_hash($package->getAliasOf())] = $package->getAliasOf();
|
||||
}
|
||||
}
|
||||
|
@ -681,19 +680,30 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
/**
|
||||
* TODO v3 should make this private once we can drop PHP 5.3 support
|
||||
*
|
||||
* @param string $name package name (must be lowercased already)
|
||||
* @private
|
||||
*/
|
||||
public function isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $versionNormalized)
|
||||
public function isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $versionData)
|
||||
{
|
||||
if (!call_user_func($isPackageAcceptableCallable, strtolower($name), VersionParser::parseStability($versionNormalized))) {
|
||||
return false;
|
||||
$versions = array($versionData['version_normalized']);
|
||||
|
||||
if ($alias = $this->loader->getBranchAlias($versionData)) {
|
||||
$versions[] = $alias;
|
||||
}
|
||||
|
||||
if ($constraint && !$constraint->matches(new Constraint('==', $versionNormalized))) {
|
||||
return false;
|
||||
foreach ($versions as $version) {
|
||||
if ($isPackageAcceptableCallable && !call_user_func($isPackageAcceptableCallable, $name, VersionParser::parseStability($version))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($constraint && !$constraint->matches(new Constraint('==', $version))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function loadRootServerFile()
|
||||
|
@ -793,7 +803,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
private function canonicalizeUrl($url)
|
||||
{
|
||||
if ('/' === $url[0]) {
|
||||
return preg_replace('{(https?://[^/]+).*}i', '$1' . $url, $this->url);
|
||||
if (preg_match('{^[^:]++://[^/]*+}', $this->url, $matches)) {
|
||||
return $matches[0] . $url;
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
@ -952,12 +966,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
|
||||
$data = $response->decodeJson();
|
||||
if (!empty($data['warning'])) {
|
||||
$this->io->writeError('<warning>Warning from '.$this->url.': '.$data['warning'].'</warning>');
|
||||
}
|
||||
if (!empty($data['info'])) {
|
||||
$this->io->writeError('<info>Info from '.$this->url.': '.$data['info'].'</info>');
|
||||
}
|
||||
HttpDownloader::outputWarnings($this->io, $this->url, $data);
|
||||
|
||||
if ($cacheKey) {
|
||||
if ($storeLastModifiedTime) {
|
||||
|
@ -1031,12 +1040,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
|
||||
$data = $response->decodeJson();
|
||||
if (!empty($data['warning'])) {
|
||||
$this->io->writeError('<warning>Warning from '.$this->url.': '.$data['warning'].'</warning>');
|
||||
}
|
||||
if (!empty($data['info'])) {
|
||||
$this->io->writeError('<info>Info from '.$this->url.': '.$data['info'].'</info>');
|
||||
}
|
||||
HttpDownloader::outputWarnings($this->io, $this->url, $data);
|
||||
|
||||
$lastModifiedDate = $response->getHeader('last-modified');
|
||||
$response->collect();
|
||||
|
@ -1101,12 +1105,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
}
|
||||
|
||||
$data = $response->decodeJson();
|
||||
if (!empty($data['warning'])) {
|
||||
$io->writeError('<warning>Warning from '.$url.': '.$data['warning'].'</warning>');
|
||||
}
|
||||
if (!empty($data['info'])) {
|
||||
$io->writeError('<info>Info from '.$url.': '.$data['info'].'</info>');
|
||||
}
|
||||
HttpDownloader::outputWarnings($io, $url, $data);
|
||||
|
||||
$lastModifiedDate = $response->getHeader('last-modified');
|
||||
$response->collect();
|
||||
|
|
|
@ -51,6 +51,11 @@ class FilesystemRepository extends WritableArrayRepository
|
|||
try {
|
||||
$packages = $this->file->read();
|
||||
|
||||
// forward compatibility for composer v2 installed.json
|
||||
if (isset($packages['packages'])) {
|
||||
$packages = $packages['packages'];
|
||||
}
|
||||
|
||||
if (!is_array($packages)) {
|
||||
throw new \UnexpectedValueException('Could not parse package list from the repository');
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ abstract class BaseChannelReader
|
|||
* @param string $origin server
|
||||
* @param string $path relative path to content
|
||||
* @throws \UnexpectedValueException
|
||||
* @return \SimpleXMLElement
|
||||
* @return string
|
||||
*/
|
||||
protected function requestContent($origin, $path)
|
||||
{
|
||||
|
|
|
@ -150,7 +150,7 @@ class ChannelRest10Reader extends BaseChannelReader
|
|||
* @param string $baseUrl
|
||||
* @param string $packageName
|
||||
* @param string $version
|
||||
* @return DependencyInfo[]
|
||||
* @return DependencyInfo
|
||||
*/
|
||||
private function readPackageReleaseDependencies($baseUrl, $packageName, $version)
|
||||
{
|
||||
|
|
|
@ -97,7 +97,7 @@ class PearRepository extends ArrayRepository implements ConfigurableRepositoryIn
|
|||
*
|
||||
* @param ChannelInfo $channelInfo
|
||||
* @param SemverVersionParser $versionParser
|
||||
* @return CompletePackage
|
||||
* @return CompletePackage[]
|
||||
*/
|
||||
private function buildComposerPackages(ChannelInfo $channelInfo, SemverVersionParser $versionParser)
|
||||
{
|
||||
|
|
|
@ -166,8 +166,14 @@ class PlatformRepository extends ArrayRepository
|
|||
case 'imagick':
|
||||
$imagick = new \Imagick();
|
||||
$imageMagickVersion = $imagick->getVersion();
|
||||
preg_match('/^ImageMagick ([\d.]+)-(\d+)/', $imageMagickVersion['versionString'], $matches);
|
||||
$prettyVersion = "{$matches[1]}.{$matches[2]}";
|
||||
// 6.x: ImageMagick 6.2.9 08/24/06 Q16 http://www.imagemagick.org
|
||||
// 7.x: ImageMagick 7.0.8-34 Q16 x86_64 2019-03-23 https://imagemagick.org
|
||||
preg_match('/^ImageMagick ([\d.]+)(?:-(\d+))?/', $imageMagickVersion['versionString'], $matches);
|
||||
if (isset($matches[2])) {
|
||||
$prettyVersion = "{$matches[1]}.{$matches[2]}";
|
||||
} else {
|
||||
$prettyVersion = $matches[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'libxml':
|
||||
|
|
|
@ -78,8 +78,9 @@ interface RepositoryInterface extends \Countable
|
|||
*
|
||||
* @param string $query search query
|
||||
* @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only
|
||||
* @param string $type The type of package to search for. Defaults to all types of packages
|
||||
*
|
||||
* @return array[] an array of array('name' => '...', 'description' => '...')
|
||||
*/
|
||||
public function search($query, $mode = 0);
|
||||
public function search($query, $mode = 0, $type = null);
|
||||
}
|
||||
|
|
|
@ -125,13 +125,7 @@ class RepositoryManager
|
|||
|
||||
$class = $this->repositoryClasses[$type];
|
||||
|
||||
$reflMethod = new \ReflectionMethod($class, '__construct');
|
||||
$params = $reflMethod->getParameters();
|
||||
if (isset($params[3]) && $params[3]->getClass() && $params[3]->getClass()->getName() === 'Composer\Util\HttpDownloader') {
|
||||
return new $class($config, $this->io, $this->config, $this->httpDownloader, $this->eventDispatcher);
|
||||
}
|
||||
|
||||
return new $class($config, $this->io, $this->config, $this->eventDispatcher);
|
||||
return new $class($config, $this->io, $this->config, $this->httpDownloader, $this->eventDispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -125,50 +125,52 @@ abstract class BitbucketDriver extends VcsDriver
|
|||
|
||||
$composer = $this->getBaseComposerInformation($identifier);
|
||||
|
||||
// specials for bitbucket
|
||||
if (!isset($composer['support']['source'])) {
|
||||
$label = array_search(
|
||||
$identifier,
|
||||
$this->getTags()
|
||||
) ?: array_search(
|
||||
$identifier,
|
||||
$this->getBranches()
|
||||
) ?: $identifier;
|
||||
if ($composer) {
|
||||
// specials for bitbucket
|
||||
if (!isset($composer['support']['source'])) {
|
||||
$label = array_search(
|
||||
$identifier,
|
||||
$this->getTags()
|
||||
) ?: array_search(
|
||||
$identifier,
|
||||
$this->getBranches()
|
||||
) ?: $identifier;
|
||||
|
||||
if (array_key_exists($label, $tags = $this->getTags())) {
|
||||
$hash = $tags[$label];
|
||||
} elseif (array_key_exists($label, $branches = $this->getBranches())) {
|
||||
$hash = $branches[$label];
|
||||
if (array_key_exists($label, $tags = $this->getTags())) {
|
||||
$hash = $tags[$label];
|
||||
} elseif (array_key_exists($label, $branches = $this->getBranches())) {
|
||||
$hash = $branches[$label];
|
||||
}
|
||||
|
||||
if (! isset($hash)) {
|
||||
$composer['support']['source'] = sprintf(
|
||||
'https://%s/%s/%s/src',
|
||||
$this->originUrl,
|
||||
$this->owner,
|
||||
$this->repository
|
||||
);
|
||||
} else {
|
||||
$composer['support']['source'] = sprintf(
|
||||
'https://%s/%s/%s/src/%s/?at=%s',
|
||||
$this->originUrl,
|
||||
$this->owner,
|
||||
$this->repository,
|
||||
$hash,
|
||||
$label
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! isset($hash)) {
|
||||
$composer['support']['source'] = sprintf(
|
||||
'https://%s/%s/%s/src',
|
||||
if (!isset($composer['support']['issues']) && $this->hasIssues) {
|
||||
$composer['support']['issues'] = sprintf(
|
||||
'https://%s/%s/%s/issues',
|
||||
$this->originUrl,
|
||||
$this->owner,
|
||||
$this->repository
|
||||
);
|
||||
} else {
|
||||
$composer['support']['source'] = sprintf(
|
||||
'https://%s/%s/%s/src/%s/?at=%s',
|
||||
$this->originUrl,
|
||||
$this->owner,
|
||||
$this->repository,
|
||||
$hash,
|
||||
$label
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isset($composer['support']['issues']) && $this->hasIssues) {
|
||||
$composer['support']['issues'] = sprintf(
|
||||
'https://%s/%s/%s/issues',
|
||||
$this->originUrl,
|
||||
$this->owner,
|
||||
$this->repository
|
||||
);
|
||||
}
|
||||
if (!isset($composer['homepage'])) {
|
||||
$composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website;
|
||||
if (!isset($composer['homepage'])) {
|
||||
$composer['homepage'] = empty($this->website) ? $this->homeUrl : $this->website;
|
||||
}
|
||||
}
|
||||
|
||||
$this->infoCache[$identifier] = $composer;
|
||||
|
@ -217,6 +219,13 @@ abstract class BitbucketDriver extends VcsDriver
|
|||
return $this->fallbackDriver->getChangeDate($identifier);
|
||||
}
|
||||
|
||||
if (strpos($identifier, '/') !== false) {
|
||||
$branches = $this->getBranches();
|
||||
if (isset($branches[$identifier])) {
|
||||
$identifier = $branches[$identifier];
|
||||
}
|
||||
}
|
||||
|
||||
$resource = sprintf(
|
||||
'https://api.bitbucket.org/2.0/repositories/%s/%s/commit/%s?fields=date',
|
||||
$this->owner,
|
||||
|
|
|
@ -154,8 +154,8 @@ class GitHubDriver extends VcsDriver
|
|||
}
|
||||
|
||||
$composer = $this->getBaseComposerInformation($identifier);
|
||||
if ($composer) {
|
||||
|
||||
if ($composer) {
|
||||
// specials for github
|
||||
if (!isset($composer['support']['source'])) {
|
||||
$label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
|
||||
|
|
|
@ -66,8 +66,9 @@ class HgDriver extends VcsDriver
|
|||
// clean up directory and do a fresh clone into it
|
||||
$fs->removeDirectory($this->repoDir);
|
||||
|
||||
$command = function ($url) {
|
||||
return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($this->repoDir));
|
||||
$repoDir = $this->repoDir;
|
||||
$command = function ($url) use ($repoDir) {
|
||||
return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
|
||||
};
|
||||
|
||||
$hgUtils->runCommand($command, $this->url, $this->repoDir);
|
||||
|
|
|
@ -38,7 +38,7 @@ interface VcsDriverInterface
|
|||
*
|
||||
* @param string $file
|
||||
* @param string $identifier
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFileContent($file, $identifier);
|
||||
|
||||
|
@ -46,7 +46,7 @@ interface VcsDriverInterface
|
|||
* Get the changedate for $identifier.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @return \DateTime
|
||||
* @return \DateTime|null
|
||||
*/
|
||||
public function getChangeDate($identifier);
|
||||
|
||||
|
@ -73,7 +73,7 @@ interface VcsDriverInterface
|
|||
|
||||
/**
|
||||
* @param string $identifier Any identifier to a specific branch/tag/commit
|
||||
* @return array With type, url reference and shasum keys.
|
||||
* @return array|null With type, url reference and shasum keys.
|
||||
*/
|
||||
public function getDist($identifier);
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
{
|
||||
protected $url;
|
||||
protected $packageName;
|
||||
protected $verbose;
|
||||
protected $isVerbose;
|
||||
protected $isVeryVerbose;
|
||||
protected $io;
|
||||
protected $config;
|
||||
protected $versionParser;
|
||||
|
@ -47,6 +48,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
private $driver;
|
||||
/** @var VersionCacheInterface */
|
||||
private $versionCache;
|
||||
private $emptyReferences = array();
|
||||
|
||||
public function __construct(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, EventDispatcher $dispatcher = null, array $drivers = null, VersionCacheInterface $versionCache = null)
|
||||
{
|
||||
|
@ -67,7 +69,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
$this->url = $repoConfig['url'];
|
||||
$this->io = $io;
|
||||
$this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
|
||||
$this->verbose = $io->isVeryVerbose();
|
||||
$this->isVerbose = $io->isVerbose();
|
||||
$this->isVeryVerbose = $io->isVeryVerbose();
|
||||
$this->config = $config;
|
||||
$this->repoConfig = $repoConfig;
|
||||
$this->versionCache = $versionCache;
|
||||
|
@ -123,11 +126,17 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
return $this->branchErrorOccurred;
|
||||
}
|
||||
|
||||
public function getEmptyReferences()
|
||||
{
|
||||
return $this->emptyReferences;
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$verbose = $this->verbose;
|
||||
$isVerbose = $this->isVerbose;
|
||||
$isVeryVerbose = $this->isVeryVerbose;
|
||||
|
||||
$driver = $this->getDriver();
|
||||
if (!$driver) {
|
||||
|
@ -145,31 +154,35 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
$this->packageName = !empty($data['name']) ? $data['name'] : null;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<error>Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().'</error>');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($driver->getTags() as $tag => $identifier) {
|
||||
$msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $tag . '</comment>)';
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError($msg);
|
||||
} else {
|
||||
} elseif ($isVerbose) {
|
||||
$this->io->overwriteError($msg, false);
|
||||
}
|
||||
|
||||
// strip the release- prefix from tags if present
|
||||
$tag = str_replace('release-', '', $tag);
|
||||
|
||||
$cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $verbose);
|
||||
$cachedPackage = $this->getCachedPackageVersion($tag, $identifier, $isVerbose, $isVeryVerbose);
|
||||
if ($cachedPackage) {
|
||||
$this->addPackage($cachedPackage);
|
||||
|
||||
continue;
|
||||
} elseif ($cachedPackage === false) {
|
||||
$this->emptyReferences[] = $identifier;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$parsedTag = $this->validateTag($tag)) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name</warning>');
|
||||
}
|
||||
continue;
|
||||
|
@ -177,9 +190,10 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
|
||||
try {
|
||||
if (!$data = $driver->getComposerInformation($identifier)) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped tag '.$tag.', no composer file</warning>');
|
||||
}
|
||||
$this->emptyReferences[] = $identifier;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -198,7 +212,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
|
||||
// broken package, version doesn't match tag
|
||||
if ($data['version_normalized'] !== $parsedTag) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>');
|
||||
}
|
||||
continue;
|
||||
|
@ -206,47 +220,50 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
|
||||
$tagPackageName = isset($data['name']) ? $data['name'] : $this->packageName;
|
||||
if ($existingPackage = $this->findPackage($tagPackageName, $data['version_normalized'])) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped tag '.$tag.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$data['version_normalized'].' internally</warning>');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('Importing tag '.$tag.' ('.$data['version_normalized'].')');
|
||||
}
|
||||
|
||||
$this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier)));
|
||||
} catch (\Exception $e) {
|
||||
if ($verbose) {
|
||||
if ($e instanceof TransportException && $e->getCode() === 404) {
|
||||
$this->emptyReferences[] = $identifier;
|
||||
}
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).'</warning>');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$verbose) {
|
||||
if (!$isVeryVerbose) {
|
||||
$this->io->overwriteError('', false);
|
||||
}
|
||||
|
||||
$branches = $driver->getBranches();
|
||||
foreach ($branches as $branch => $identifier) {
|
||||
$msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $branch . '</comment>)';
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError($msg);
|
||||
} else {
|
||||
} elseif ($isVerbose) {
|
||||
$this->io->overwriteError($msg, false);
|
||||
}
|
||||
|
||||
if ($branch === 'trunk' && isset($branches['master'])) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped branch '.$branch.', can not parse both master and trunk branches as they both resolve to 9999999-dev internally</warning>');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$parsedBranch = $this->validateBranch($branch)) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped branch '.$branch.', invalid name</warning>');
|
||||
}
|
||||
continue;
|
||||
|
@ -260,18 +277,23 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
$version = $prefix . preg_replace('{(\.9{7})+}', '.x', $parsedBranch);
|
||||
}
|
||||
|
||||
$cachedPackage = $this->getCachedPackageVersion($version, $identifier, $verbose);
|
||||
$cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose);
|
||||
if ($cachedPackage) {
|
||||
$this->addPackage($cachedPackage);
|
||||
|
||||
continue;
|
||||
} elseif ($cachedPackage === false) {
|
||||
$this->emptyReferences[] = $identifier;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$data = $driver->getComposerInformation($identifier)) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped branch '.$branch.', no composer file</warning>');
|
||||
}
|
||||
$this->emptyReferences[] = $identifier;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -279,7 +301,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
$data['version'] = $version;
|
||||
$data['version_normalized'] = $parsedBranch;
|
||||
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('Importing branch '.$branch.' ('.$data['version'].')');
|
||||
}
|
||||
|
||||
|
@ -290,12 +312,15 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
}
|
||||
$this->addPackage($package);
|
||||
} catch (TransportException $e) {
|
||||
if ($verbose) {
|
||||
if ($e->getCode() === 404) {
|
||||
$this->emptyReferences[] = $identifier;
|
||||
}
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped branch '.$branch.', no composer file was found</warning>');
|
||||
}
|
||||
continue;
|
||||
} catch (\Exception $e) {
|
||||
if (!$verbose) {
|
||||
if (!$isVeryVerbose) {
|
||||
$this->io->writeError('');
|
||||
}
|
||||
$this->branchErrorOccurred = true;
|
||||
|
@ -306,7 +331,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
}
|
||||
$driver->cleanup();
|
||||
|
||||
if (!$verbose) {
|
||||
if (!$isVeryVerbose) {
|
||||
$this->io->overwriteError('', false);
|
||||
}
|
||||
|
||||
|
@ -351,23 +376,31 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
|
|||
return false;
|
||||
}
|
||||
|
||||
private function getCachedPackageVersion($version, $identifier, $verbose)
|
||||
private function getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose)
|
||||
{
|
||||
if (!$this->versionCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cachedPackage = $this->versionCache->getVersionPackage($version, $identifier);
|
||||
if ($cachedPackage === false) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped '.$version.', no composer file (cached from ref '.$identifier.')</warning>');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cachedPackage) {
|
||||
$msg = 'Found cached composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $version . '</comment>)';
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError($msg);
|
||||
} else {
|
||||
} elseif ($isVerbose) {
|
||||
$this->io->overwriteError($msg, false);
|
||||
}
|
||||
|
||||
if ($existingPackage = $this->findPackage($cachedPackage['name'], $cachedPackage['version_normalized'])) {
|
||||
if ($verbose) {
|
||||
if ($isVeryVerbose) {
|
||||
$this->io->writeError('<warning>Skipped cached version '.$version.', it conflicts with an another tag ('.$existingPackage->getPrettyVersion().') as both resolve to '.$cachedPackage['version_normalized'].' internally</warning>');
|
||||
}
|
||||
$cachedPackage = null;
|
||||
|
|
|
@ -17,7 +17,7 @@ interface VersionCacheInterface
|
|||
/**
|
||||
* @param string $version
|
||||
* @param string $identifier
|
||||
* @return array Package version data
|
||||
* @return array|null|false Package version data if found, false to indicate the identifier is known but has no package, null for an unknown identifier
|
||||
*/
|
||||
public function getVersionPackage($version, $identifier);
|
||||
}
|
||||
|
|
|
@ -71,12 +71,11 @@ class AuthHelper
|
|||
* @param string $origin
|
||||
* @param int $statusCode HTTP status code that triggered this call
|
||||
* @param string|null $reason a message/description explaining why this was called
|
||||
* @param string $warning an authentication warning returned by the server as {"warning": ".."}, if present
|
||||
* @param string[] $headers
|
||||
* @return array containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be
|
||||
* @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be
|
||||
* retried, if storeAuth is true then on a successful retry the authentication should be persisted to auth.json
|
||||
*/
|
||||
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $warning = null, $headers = array())
|
||||
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array())
|
||||
{
|
||||
$storeAuth = false;
|
||||
$retry = false;
|
||||
|
@ -173,10 +172,6 @@ class AuthHelper
|
|||
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
|
||||
}
|
||||
|
||||
$this->io->overwriteError('');
|
||||
if ($warning) {
|
||||
$this->io->writeError(' <warning>'.$warning.'</warning>');
|
||||
}
|
||||
$this->io->writeError(' Authentication required (<info>'.parse_url($url, PHP_URL_HOST).'</info>):');
|
||||
$username = $this->io->ask(' Username: ');
|
||||
$password = $this->io->askAndHideAnswer(' Password: ');
|
||||
|
|
|
@ -22,11 +22,17 @@ use Composer\Downloader\TransportException;
|
|||
*/
|
||||
class Bitbucket
|
||||
{
|
||||
/** @var IOInterface */
|
||||
private $io;
|
||||
/** @var Config */
|
||||
private $config;
|
||||
/** @var ProcessExecutor */
|
||||
private $process;
|
||||
/** @var HttpDownloader */
|
||||
private $httpDownloader;
|
||||
/** @var array */
|
||||
private $token = array();
|
||||
/** @var int|null */
|
||||
private $time;
|
||||
|
||||
const OAUTH2_ACCESS_TOKEN_URL = 'https://bitbucket.org/site/oauth2/access_token';
|
||||
|
|
|
@ -23,6 +23,7 @@ use Symfony\Component\Finder\Finder;
|
|||
*/
|
||||
class Filesystem
|
||||
{
|
||||
/** @var ProcessExecutor */
|
||||
private $processExecutor;
|
||||
|
||||
public function __construct(ProcessExecutor $executor = null)
|
||||
|
@ -199,9 +200,15 @@ class Filesystem
|
|||
*/
|
||||
public function unlink($path)
|
||||
{
|
||||
if (!@$this->unlinkImplementation($path)) {
|
||||
$unlinked = @$this->unlinkImplementation($path);
|
||||
if (!$unlinked) {
|
||||
// retry after a bit on windows since it tends to be touchy with mass removals
|
||||
if (!Platform::isWindows() || (usleep(350000) && !@$this->unlinkImplementation($path))) {
|
||||
if (Platform::isWindows()) {
|
||||
usleep(350000);
|
||||
$unlinked = @$this->unlinkImplementation($path);
|
||||
}
|
||||
|
||||
if (!$unlinked) {
|
||||
$error = error_get_last();
|
||||
$message = 'Could not delete '.$path.': ' . @$error['message'];
|
||||
if (Platform::isWindows()) {
|
||||
|
@ -224,9 +231,15 @@ class Filesystem
|
|||
*/
|
||||
public function rmdir($path)
|
||||
{
|
||||
if (!@rmdir($path)) {
|
||||
$deleted = @rmdir($path);
|
||||
if (!$deleted) {
|
||||
// retry after a bit on windows since it tends to be touchy with mass removals
|
||||
if (!Platform::isWindows() || (usleep(350000) && !@rmdir($path))) {
|
||||
if (Platform::isWindows()) {
|
||||
usleep(350000);
|
||||
$deleted = @rmdir($path);
|
||||
}
|
||||
|
||||
if (!$deleted) {
|
||||
$error = error_get_last();
|
||||
$message = 'Could not delete '.$path.': ' . @$error['message'];
|
||||
if (Platform::isWindows()) {
|
||||
|
@ -279,6 +292,7 @@ class Filesystem
|
|||
$this->ensureDirectoryExists($target);
|
||||
|
||||
$result = true;
|
||||
/** @var RecursiveDirectoryIterator $ri */
|
||||
foreach ($ri as $file) {
|
||||
$targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
|
||||
if ($file->isDir()) {
|
||||
|
@ -428,7 +442,7 @@ class Filesystem
|
|||
*/
|
||||
public function isAbsolutePath($path)
|
||||
{
|
||||
return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':';
|
||||
return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path, 0, 2) === '\\\\';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,6 +539,9 @@ class Filesystem
|
|||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProcessExecutor
|
||||
*/
|
||||
protected function getProcess()
|
||||
{
|
||||
return $this->processExecutor;
|
||||
|
@ -648,6 +665,20 @@ class Filesystem
|
|||
/**
|
||||
* Returns whether the target directory is a Windows NTFS Junction.
|
||||
*
|
||||
* We test if the path is a directory and not an ordinary link, then check
|
||||
* that the mode value returned from lstat (which gives the status of the
|
||||
* link itself) is not a directory, by replicating the POSIX S_ISDIR test.
|
||||
*
|
||||
* This logic works because PHP does not set the mode value for a junction,
|
||||
* since there is no universal file type flag for it. Unfortunately an
|
||||
* uninitialized variable in PHP prior to 7.2.16 and 7.3.3 may cause a
|
||||
* random value to be returned. See https://bugs.php.net/bug.php?id=77552
|
||||
*
|
||||
* If this random value passes the S_ISDIR test, then a junction will not be
|
||||
* detected and a recursive delete operation could lead to loss of data in
|
||||
* the target directory. Note that Windows rmdir can handle this situation
|
||||
* and will only delete the junction (from Windows 7 onwards).
|
||||
*
|
||||
* @param string $junction Path to check.
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -659,22 +690,13 @@ class Filesystem
|
|||
if (!is_dir($junction) || is_link($junction)) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* According to MSDN at https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx we can detect a junction now
|
||||
* using the 'mode' value from stat: "The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit
|
||||
* is set if path specifies an ordinary file or a device." We have just tested for a directory above, so if
|
||||
* we have a directory that isn't one according to lstat(...) we must have a junction.
|
||||
*
|
||||
* #define _S_IFDIR 0x4000
|
||||
* #define _S_IFREG 0x8000
|
||||
*
|
||||
* Stat cache should be cleared before to avoid accidentally reading wrong information from previous installs.
|
||||
*/
|
||||
|
||||
// Important to clear all caches first
|
||||
clearstatcache(true, $junction);
|
||||
clearstatcache(false);
|
||||
$stat = lstat($junction);
|
||||
|
||||
return !($stat['mode'] & 0xC000);
|
||||
// S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask)
|
||||
return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -692,9 +714,7 @@ class Filesystem
|
|||
if (!$this->isJunction($junction)) {
|
||||
throw new IOException(sprintf('%s is not a junction and thus cannot be removed as one', $junction));
|
||||
}
|
||||
$cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape($junction));
|
||||
clearstatcache(true, $junction);
|
||||
|
||||
return ($this->getProcess()->execute($cmd, $output) === 0);
|
||||
return $this->rmdir($junction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,13 @@ use Composer\Downloader\TransportException;
|
|||
*/
|
||||
class GitHub
|
||||
{
|
||||
/** @var IOInterface */
|
||||
protected $io;
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
/** @var HttpDownloader */
|
||||
protected $httpDownloader;
|
||||
|
||||
/**
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue