Merge remote-tracking branch 'upstream/master'
commit
25b2748101
|
@ -52,5 +52,5 @@ jobs:
|
||||||
- name: Run PHPStan
|
- name: Run PHPStan
|
||||||
# Locked to phpunit 7.5 here as newer ones have void return types which break inheritance
|
# Locked to phpunit 7.5 here as newer ones have void return types which break inheritance
|
||||||
run: |
|
run: |
|
||||||
bin/composer require --dev phpstan/phpstan:^0.12.42 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }}
|
bin/composer require --dev phpstan/phpstan:^0.12.69 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }}
|
||||||
vendor/bin/phpstan analyse --configuration=phpstan/config.neon
|
vendor/bin/phpstan analyse --configuration=phpstan/config.neon
|
||||||
|
|
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -1,3 +1,17 @@
|
||||||
|
### [2.0.9] 2021-01-27
|
||||||
|
|
||||||
|
* Added warning if the curl extension is not enabled as it significantly degrades performance
|
||||||
|
* Fixed InstalledVersions to report all packages when several vendor dirs are present in the same runtime
|
||||||
|
* Fixed download speed when downloading large files
|
||||||
|
* Fixed `archive` and path repo copies mishandling some .gitignore paths
|
||||||
|
* Fixed root package classes not being available to the plugins/scripts during the initial install
|
||||||
|
* Fixed cache writes to be atomic and better support multiple Composer processes running in parallel
|
||||||
|
* Fixed preg jit issues when `config` or `require` modifies large composer.json files
|
||||||
|
* Fixed compatibility with envs having open_basedir restrictions
|
||||||
|
* Fixed exclude-from-classmap causing regex issues when having too many paths
|
||||||
|
* Fixed compatibility issue with Symfony 4/5
|
||||||
|
* Several small performance and debug output improvements
|
||||||
|
|
||||||
### [2.0.8] 2020-12-03
|
### [2.0.8] 2020-12-03
|
||||||
|
|
||||||
* Fixed packages with aliases not matching conflicts which match the alias
|
* Fixed packages with aliases not matching conflicts which match the alias
|
||||||
|
@ -150,6 +164,11 @@
|
||||||
* Fixed suggest output being very spammy, it now is only one line long and shows more rarely
|
* Fixed suggest output being very spammy, it now is only one line long and shows more rarely
|
||||||
* Fixed conflict rules like e.g. >=5 from matching dev-master, as it is not normalized to 9999999-dev internally anymore
|
* Fixed conflict rules like e.g. >=5 from matching dev-master, as it is not normalized to 9999999-dev internally anymore
|
||||||
|
|
||||||
|
### [1.10.20] 2021-01-27
|
||||||
|
|
||||||
|
* Fixed exclude-from-classmap causing regex issues when having too many paths
|
||||||
|
* Fixed compatibility issue with Symfony 4/5
|
||||||
|
|
||||||
### [1.10.19] 2020-12-04
|
### [1.10.19] 2020-12-04
|
||||||
|
|
||||||
* Fixed regression on PHP 8.0
|
* Fixed regression on PHP 8.0
|
||||||
|
@ -1076,6 +1095,7 @@
|
||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
|
[2.0.9]: https://github.com/composer/composer/compare/2.0.8...2.0.9
|
||||||
[2.0.8]: https://github.com/composer/composer/compare/2.0.7...2.0.8
|
[2.0.8]: https://github.com/composer/composer/compare/2.0.7...2.0.8
|
||||||
[2.0.7]: https://github.com/composer/composer/compare/2.0.6...2.0.7
|
[2.0.7]: https://github.com/composer/composer/compare/2.0.6...2.0.7
|
||||||
[2.0.6]: https://github.com/composer/composer/compare/2.0.5...2.0.6
|
[2.0.6]: https://github.com/composer/composer/compare/2.0.5...2.0.6
|
||||||
|
@ -1090,6 +1110,7 @@
|
||||||
[2.0.0-alpha3]: https://github.com/composer/composer/compare/2.0.0-alpha2...2.0.0-alpha3
|
[2.0.0-alpha3]: https://github.com/composer/composer/compare/2.0.0-alpha2...2.0.0-alpha3
|
||||||
[2.0.0-alpha2]: https://github.com/composer/composer/compare/2.0.0-alpha1...2.0.0-alpha2
|
[2.0.0-alpha2]: https://github.com/composer/composer/compare/2.0.0-alpha1...2.0.0-alpha2
|
||||||
[2.0.0-alpha1]: https://github.com/composer/composer/compare/1.10.7...2.0.0-alpha1
|
[2.0.0-alpha1]: https://github.com/composer/composer/compare/1.10.7...2.0.0-alpha1
|
||||||
|
[1.10.20]: https://github.com/composer/composer/compare/1.10.19...1.10.20
|
||||||
[1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19
|
[1.10.19]: https://github.com/composer/composer/compare/1.10.18...1.10.19
|
||||||
[1.10.18]: https://github.com/composer/composer/compare/1.10.17...1.10.18
|
[1.10.18]: https://github.com/composer/composer/compare/1.10.17...1.10.18
|
||||||
[1.10.17]: https://github.com/composer/composer/compare/1.10.16...1.10.17
|
[1.10.17]: https://github.com/composer/composer/compare/1.10.16...1.10.17
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "composer/ca-bundle",
|
"name": "composer/ca-bundle",
|
||||||
"version": "1.2.8",
|
"version": "1.2.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/composer/ca-bundle.git",
|
"url": "https://github.com/composer/ca-bundle.git",
|
||||||
"reference": "8a7ecad675253e4654ea05505233285377405215"
|
"reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215",
|
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5",
|
||||||
"reference": "8a7ecad675253e4654ea05505233285377405215",
|
"reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -26,14 +26,15 @@
|
||||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
|
"phpstan/phpstan": "^0.12.55",
|
||||||
"psr/log": "^1.0",
|
"psr/log": "^1.0",
|
||||||
|
"symfony/phpunit-bridge": "^4.2 || ^5",
|
||||||
"symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
|
"symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.x-dev"
|
"dev-main": "1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -63,7 +64,7 @@
|
||||||
"support": {
|
"support": {
|
||||||
"irc": "irc://irc.freenode.org/composer",
|
"irc": "irc://irc.freenode.org/composer",
|
||||||
"issues": "https://github.com/composer/ca-bundle/issues",
|
"issues": "https://github.com/composer/ca-bundle/issues",
|
||||||
"source": "https://github.com/composer/ca-bundle/tree/1.2.8"
|
"source": "https://github.com/composer/ca-bundle/tree/1.2.9"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -79,7 +80,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-08-23T12:54:47+00:00"
|
"time": "2021-01-12T12:10:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "composer/semver",
|
"name": "composer/semver",
|
||||||
|
|
|
@ -943,6 +943,8 @@ The `COMPOSER_HOME` var allows you to change the Composer home directory. This
|
||||||
is a hidden, global (per-user on the machine) directory that is shared between
|
is a hidden, global (per-user on the machine) directory that is shared between
|
||||||
all projects.
|
all projects.
|
||||||
|
|
||||||
|
Use `composer config --global home` to see the location of the home directory.
|
||||||
|
|
||||||
By default, it points to `C:\Users\<user>\AppData\Roaming\Composer` on Windows
|
By default, it points to `C:\Users\<user>\AppData\Roaming\Composer` on Windows
|
||||||
and `/Users/<user>/.composer` on macOS. On \*nix systems that follow the [XDG Base
|
and `/Users/<user>/.composer` on macOS. On \*nix systems that follow the [XDG Base
|
||||||
Directory Specifications](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html),
|
Directory Specifications](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html),
|
||||||
|
@ -1012,6 +1014,13 @@ similar use case), and need to support proxies, please provide the `CGI_HTTP_PRO
|
||||||
environment variable instead. See [httpoxy.org](https://httpoxy.org/) for further
|
environment variable instead. See [httpoxy.org](https://httpoxy.org/) for further
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
### COMPOSER_MAX_PARALLEL_HTTP
|
||||||
|
|
||||||
|
Set to an integer to configure how many files can be downloaded in parallel. This
|
||||||
|
defaults to 12 and must be between 1 and 50. If your proxy has issues with
|
||||||
|
concurrency maybe you want to lower this. Increasing it should generally not result
|
||||||
|
in performance gains.
|
||||||
|
|
||||||
### HTTP_PROXY_REQUEST_FULLURI
|
### HTTP_PROXY_REQUEST_FULLURI
|
||||||
|
|
||||||
If you use a proxy, but it does not support the request_fulluri flag, then you
|
If you use a proxy, but it does not support the request_fulluri flag, then you
|
||||||
|
|
|
@ -401,19 +401,19 @@ Example:
|
||||||
|
|
||||||
#### require
|
#### require
|
||||||
|
|
||||||
Lists packages required by this package. The package will not be installed
|
Map of packages required by this package. The package will not be installed
|
||||||
unless those requirements can be met.
|
unless those requirements can be met.
|
||||||
|
|
||||||
#### require-dev <span>([root-only](04-schema.md#root-package))</span>
|
#### require-dev <span>([root-only](04-schema.md#root-package))</span>
|
||||||
|
|
||||||
Lists packages required for developing this package, or running
|
Map of packages required for developing this package, or running
|
||||||
tests, etc. The dev requirements of the root package are installed by default.
|
tests, etc. The dev requirements of the root package are installed by default.
|
||||||
Both `install` or `update` support the `--no-dev` option that prevents dev
|
Both `install` or `update` support the `--no-dev` option that prevents dev
|
||||||
dependencies from being installed.
|
dependencies from being installed.
|
||||||
|
|
||||||
#### conflict
|
#### conflict
|
||||||
|
|
||||||
Lists packages that conflict with this version of this package. They
|
Map of packages that conflict with this version of this package. They
|
||||||
will not be allowed to be installed together with your package.
|
will not be allowed to be installed together with your package.
|
||||||
|
|
||||||
Note that when specifying ranges like `<1.0 >=1.1` in a `conflict` link,
|
Note that when specifying ranges like `<1.0 >=1.1` in a `conflict` link,
|
||||||
|
@ -423,7 +423,7 @@ probably want to go for `<1.0 || >=1.1` in this case.
|
||||||
|
|
||||||
#### replace
|
#### replace
|
||||||
|
|
||||||
Lists packages that are replaced by this package. This allows you to fork a
|
Map of packages that are replaced by this package. This allows you to fork a
|
||||||
package, publish it under a different name with its own version numbers, while
|
package, publish it under a different name with its own version numbers, while
|
||||||
packages requiring the original package continue to work with your fork because
|
packages requiring the original package continue to work with your fork because
|
||||||
it replaces the original package.
|
it replaces the original package.
|
||||||
|
@ -441,10 +441,12 @@ that exact version, and not any other version, which would be incorrect.
|
||||||
|
|
||||||
#### provide
|
#### provide
|
||||||
|
|
||||||
List of other packages that are provided by this package. This is mostly
|
Map of packages that are provided by this package. This is mostly
|
||||||
useful for implementations of common interfaces. A package could depend on
|
useful for implementations of common interfaces. A package could depend on
|
||||||
some virtual `logger-implementation` package, any library that implements
|
some virtual package e.g. `psr/logger-implementation`, any library that implements
|
||||||
this logger interface would list it in `provide`.
|
this logger interface would list it in `provide`. Implementors can then
|
||||||
|
be [found on Packagist.org](https://packagist.org/providers/psr/log-implementation).
|
||||||
|
|
||||||
Using `provide` with the name of an actual package rather than a virtual one
|
Using `provide` with the name of an actual package rather than a virtual one
|
||||||
implies that the code of that package is also shipped, in which case `replace`
|
implies that the code of that package is also shipped, in which case `replace`
|
||||||
is generally a better choice. A common convention for packages providing an
|
is generally a better choice. A common convention for packages providing an
|
||||||
|
|
|
@ -576,15 +576,24 @@ the branch or tag that is currently checked out. Otherwise, the version should
|
||||||
be explicitly defined in the package's `composer.json` file. If the version
|
be explicitly defined in the package's `composer.json` file. If the version
|
||||||
cannot be resolved by these means, it is assumed to be `dev-master`.
|
cannot be resolved by these means, it is assumed to be `dev-master`.
|
||||||
|
|
||||||
When the version cannot be inferred from the local VCS repository, you should use
|
When the version cannot be inferred from the local VCS repository, or when you
|
||||||
the special `branch-version` entry under `extra` instead of `version`:
|
want to override the version, you can use the `versions` option when declaring
|
||||||
|
the repository:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"extra": {
|
"repositories": [
|
||||||
"branch-version": "4.2-dev"
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "../../packages/my-package",
|
||||||
|
"options": {
|
||||||
|
"versions": {
|
||||||
|
"my/package": "4.2-dev"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The local package will be symlinked if possible, in which case the output in
|
The local package will be symlinked if possible, in which case the output in
|
||||||
|
|
|
@ -87,7 +87,7 @@ possible for safety.
|
||||||
----
|
----
|
||||||
|
|
||||||
A few other methods are available for more complex usages, please refer to the
|
A few other methods are available for more complex usages, please refer to the
|
||||||
source/docblocks of the class itself.
|
source/docblocks of [the class itself](https://github.com/composer/composer/blob/master/src/Composer/InstalledVersions.php).
|
||||||
|
|
||||||
## Platform check
|
## Platform check
|
||||||
|
|
||||||
|
|
|
@ -80,10 +80,9 @@ To fix this you need to open the file in an editor and fix the error. To find th
|
||||||
your global `auth.json`, execute:
|
your global `auth.json`, execute:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
composer config --global --list
|
composer config --global home
|
||||||
```
|
```
|
||||||
|
|
||||||
And look for the `[home]` section. (It is by default `~/.composer` or `%APPDATA%/Composer` on Windows)
|
|
||||||
The folder will contain your global `auth.json` if it exists.
|
The folder will contain your global `auth.json` if it exists.
|
||||||
|
|
||||||
You can open this file in your favorite editor and fix the error.
|
You can open this file in your favorite editor and fix the error.
|
||||||
|
@ -107,7 +106,7 @@ section or directly in the repository definition.
|
||||||
|
|
||||||
The final option to supply Composer with credentials is to use the `COMPOSER_AUTH` environment variable.
|
The final option to supply Composer with credentials is to use the `COMPOSER_AUTH` environment variable.
|
||||||
These variables can be either passed as command line variables or set in actual environment variables.
|
These variables can be either passed as command line variables or set in actual environment variables.
|
||||||
Read more about the usage of this environment variable [here](../03-cli.md#COMPOSER_AUTH).
|
Read more about the usage of this environment variable [here](../03-cli.md#composer-auth).
|
||||||
|
|
||||||
# Authentication methods
|
# Authentication methods
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,19 @@ In the above example, if you wanted to check out the `my-feature` branch, you wo
|
||||||
|
|
||||||
When branch names look like versions, we have to clarify for composer that we're trying to check out a branch and not a tag. In the above example, we have two version branches: `v1` and `v2`. To get Composer to check out one of these branches, you must specify a version constraint that looks like this: `v1.x-dev`. The `.x` is an arbitrary string that Composer requires to tell it that we're talking about the `v1` branch and not a `v1` tag (alternatively, you can name the branch `v1.x` instead of `v1`). In the case of a branch with a version-like name (`v1`, in this case), you append `-dev` as a suffix, rather than using `dev-` as a prefix.
|
When branch names look like versions, we have to clarify for composer that we're trying to check out a branch and not a tag. In the above example, we have two version branches: `v1` and `v2`. To get Composer to check out one of these branches, you must specify a version constraint that looks like this: `v1.x-dev`. The `.x` is an arbitrary string that Composer requires to tell it that we're talking about the `v1` branch and not a `v1` tag (alternatively, you can name the branch `v1.x` instead of `v1`). In the case of a branch with a version-like name (`v1`, in this case), you append `-dev` as a suffix, rather than using `dev-` as a prefix.
|
||||||
|
|
||||||
|
### Stabilities
|
||||||
|
|
||||||
|
Composer recognizes the following stabilities (in order of stability): dev,
|
||||||
|
alpha, beta, RC, and stable where RC stands for release candidate. The stability
|
||||||
|
of a version is defined by its suffix e.g version `v1.1-BETA` has a stability of
|
||||||
|
`beta` and `v1.1-RC1` has a stability of `RC`. If such a suffix is missing
|
||||||
|
e.g. version `v1.1` then Composer considers that version `stable`. In addition
|
||||||
|
to that Composer automatically adds a `-dev` suffix to all numeric branches and
|
||||||
|
prefixes all other branches imported from a VCS repository with `dev-`. In both
|
||||||
|
cases the stability `dev` gets assigned.
|
||||||
|
|
||||||
|
Keeping this in mind will help you in the next section.
|
||||||
|
|
||||||
### Minimum Stability
|
### Minimum Stability
|
||||||
|
|
||||||
There's one more thing that will affect which files are checked out of a library's VCS and added to your project: Composer allows you to specify stability constraints to limit which tags are considered valid. In the above example, note that the library released a beta and two release candidates for version `1.1` before the final official release. To receive these versions when running `composer install` or `composer update`, we have to explicitly tell Composer that we are ok with release candidates and beta releases (and alpha releases, if we want those). This can be done using either a project-wide `minimum-stability` value in `composer.json` or using "stability flags" in version constraints. Read more on the [schema page](../04-schema.md#minimum-stability).
|
There's one more thing that will affect which files are checked out of a library's VCS and added to your project: Composer allows you to specify stability constraints to limit which tags are considered valid. In the above example, note that the library released a beta and two release candidates for version `1.1` before the final official release. To receive these versions when running `composer install` or `composer update`, we have to explicitly tell Composer that we are ok with release candidates and beta releases (and alpha releases, if we want those). This can be done using either a project-wide `minimum-stability` value in `composer.json` or using "stability flags" in version constraints. Read more on the [schema page](../04-schema.md#minimum-stability).
|
||||||
|
|
|
@ -9,7 +9,7 @@ An alternative is to use this script which only works with UNIX utilities:
|
||||||
```bash
|
```bash
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)"
|
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||||
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,7 @@ EOF;
|
||||||
|
|
||||||
$excluded = null;
|
$excluded = null;
|
||||||
if (!empty($autoloads['exclude-from-classmap'])) {
|
if (!empty($autoloads['exclude-from-classmap'])) {
|
||||||
$excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}';
|
$excluded = $autoloads['exclude-from-classmap'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$classMap = array();
|
$classMap = array();
|
||||||
|
@ -398,8 +398,31 @@ EOF;
|
||||||
return $classMap;
|
return $classMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ?array $excluded
|
||||||
|
*/
|
||||||
private function generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, $showAmbiguousWarning, array &$scannedFiles)
|
private function generateClassMap($dir, $excluded, $namespaceFilter, $autoloadType, $showAmbiguousWarning, array &$scannedFiles)
|
||||||
{
|
{
|
||||||
|
if ($excluded) {
|
||||||
|
// filter excluded patterns here to only use those matching $dir
|
||||||
|
// exclude-from-classmap patterns are all realpath'd so we can only filter them if $dir exists so that realpath($dir) will work
|
||||||
|
// if $dir does not exist, it should anyway not find anything there so no trouble
|
||||||
|
if (file_exists($dir)) {
|
||||||
|
// transform $dir in the same way that exclude-from-classmap patterns are transformed so we can match them against each other
|
||||||
|
$dirMatch = preg_quote(strtr(realpath($dir), '\\', '/'));
|
||||||
|
foreach ($excluded as $index => $pattern) {
|
||||||
|
// extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character
|
||||||
|
$pattern = preg_replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern);
|
||||||
|
// if the pattern is not a subset or superset of $dir, it is unrelated and we skip it
|
||||||
|
if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) {
|
||||||
|
unset($excluded[$index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$excluded = $excluded ? '{(' . implode('|', $excluded) . ')}' : null;
|
||||||
|
}
|
||||||
|
|
||||||
return ClassMapGenerator::createMap($dir, $excluded, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType, $scannedFiles);
|
return ClassMapGenerator::createMap($dir, $excluded, $showAmbiguousWarning ? $this->io : null, $namespaceFilter, $autoloadType, $scannedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +536,7 @@ EOF;
|
||||||
if (isset($autoloads['classmap'])) {
|
if (isset($autoloads['classmap'])) {
|
||||||
$excluded = null;
|
$excluded = null;
|
||||||
if (!empty($autoloads['exclude-from-classmap'])) {
|
if (!empty($autoloads['exclude-from-classmap'])) {
|
||||||
$excluded = '{(' . implode('|', $autoloads['exclude-from-classmap']) . ')}';
|
$excluded = $autoloads['exclude-from-classmap'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$scannedFiles = array();
|
$scannedFiles = array();
|
||||||
|
@ -838,7 +861,7 @@ PLATFORM_CHECK;
|
||||||
|
|
||||||
$file .= <<<CLASSLOADER_INIT
|
$file .= <<<CLASSLOADER_INIT
|
||||||
spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'), true, $prependAutoloader);
|
spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'), true, $prependAutoloader);
|
||||||
self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader();
|
self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader(\\dirname(\\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Composer\Autoload;
|
||||||
*/
|
*/
|
||||||
class ClassLoader
|
class ClassLoader
|
||||||
{
|
{
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
// PSR-4
|
// PSR-4
|
||||||
private $prefixLengthsPsr4 = array();
|
private $prefixLengthsPsr4 = array();
|
||||||
private $prefixDirsPsr4 = array();
|
private $prefixDirsPsr4 = array();
|
||||||
|
@ -57,6 +59,13 @@ class ClassLoader
|
||||||
private $missingClasses = array();
|
private $missingClasses = array();
|
||||||
private $apcuPrefix;
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
}
|
||||||
|
|
||||||
public function getPrefixes()
|
public function getPrefixes()
|
||||||
{
|
{
|
||||||
if (!empty($this->prefixesPsr0)) {
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
@ -300,6 +309,17 @@ class ClassLoader
|
||||||
public function register($prepend = false)
|
public function register($prepend = false)
|
||||||
{
|
{
|
||||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,6 +328,10 @@ class ClassLoader
|
||||||
public function unregister()
|
public function unregister()
|
||||||
{
|
{
|
||||||
spl_autoload_unregister(array($this, 'loadClass'));
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -367,6 +391,16 @@ class ClassLoader
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return self[]
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
private function findFileWithExtension($class, $ext)
|
private function findFileWithExtension($class, $ext)
|
||||||
{
|
{
|
||||||
// PSR-4 lookup
|
// PSR-4 lookup
|
||||||
|
|
|
@ -51,7 +51,7 @@ class ClassMapGenerator
|
||||||
* Iterate over all files in the given directory searching for classes
|
* Iterate over all files in the given directory searching for classes
|
||||||
*
|
*
|
||||||
* @param \Iterator|string $path The path to search in or an iterator
|
* @param \Iterator|string $path The path to search in or an iterator
|
||||||
* @param string $excluded Regex that matches against the file path that exclude from the classmap.
|
* @param string $excluded Regex that matches file paths to be excluded from the classmap
|
||||||
* @param IOInterface $io IO object
|
* @param IOInterface $io IO object
|
||||||
* @param string $namespace Optional namespace prefix to filter by
|
* @param string $namespace Optional namespace prefix to filter by
|
||||||
* @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules
|
* @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules
|
||||||
|
|
|
@ -114,20 +114,21 @@ class Cache
|
||||||
|
|
||||||
$this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG);
|
$this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG);
|
||||||
|
|
||||||
|
$tempFileName = $this->root . $file . uniqid('.', true) . '.tmp';
|
||||||
try {
|
try {
|
||||||
return file_put_contents($this->root . $file.'.tmp', $contents) !== false && rename($this->root . $file . '.tmp', $this->root . $file);
|
return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file);
|
||||||
} catch (\ErrorException $e) {
|
} catch (\ErrorException $e) {
|
||||||
$this->io->writeError('<warning>Failed to write into cache: '.$e->getMessage().'</warning>', true, IOInterface::DEBUG);
|
$this->io->writeError('<warning>Failed to write into cache: '.$e->getMessage().'</warning>', true, IOInterface::DEBUG);
|
||||||
if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
|
if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
|
||||||
// Remove partial file.
|
// Remove partial file.
|
||||||
unlink($this->root . $file);
|
unlink($tempFileName);
|
||||||
|
|
||||||
$message = sprintf(
|
$message = sprintf(
|
||||||
'<warning>Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available</warning>',
|
'<warning>Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available</warning>',
|
||||||
$this->root . $file,
|
$tempFileName,
|
||||||
$m[1],
|
$m[1],
|
||||||
$m[2],
|
$m[2],
|
||||||
@disk_free_space($this->root . dirname($file))
|
@disk_free_space(dirname($tempFileName))
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->io->writeError($message);
|
$this->io->writeError($message);
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Composer\Command;
|
||||||
use Composer\Installer;
|
use Composer\Installer;
|
||||||
use Composer\Plugin\CommandEvent;
|
use Composer\Plugin\CommandEvent;
|
||||||
use Composer\Plugin\PluginEvents;
|
use Composer\Plugin\PluginEvents;
|
||||||
|
use Composer\Util\HttpDownloader;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
@ -93,6 +94,10 @@ EOT
|
||||||
|
|
||||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||||
|
|
||||||
|
if ((!$composer->getLocker() || !$composer->getLocker()->isLocked()) && !HttpDownloader::isCurlEnabled()) {
|
||||||
|
$io->writeError('<warning>Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.</warning>');
|
||||||
|
}
|
||||||
|
|
||||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
|
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
|
||||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ EOT
|
||||||
$composeUser = posix_getpwuid(posix_geteuid());
|
$composeUser = posix_getpwuid(posix_geteuid());
|
||||||
$homeOwner = posix_getpwuid(fileowner($home));
|
$homeOwner = posix_getpwuid(fileowner($home));
|
||||||
if (isset($composeUser['name'], $homeOwner['name']) && $composeUser['name'] !== $homeOwner['name']) {
|
if (isset($composeUser['name'], $homeOwner['name']) && $composeUser['name'] !== $homeOwner['name']) {
|
||||||
$io->writeError('<warning>You are running composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"</warning>');
|
$io->writeError('<warning>You are running Composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"</warning>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ EOT
|
||||||
if (Composer::VERSION === $updateVersion) {
|
if (Composer::VERSION === $updateVersion) {
|
||||||
$io->writeError(
|
$io->writeError(
|
||||||
sprintf(
|
sprintf(
|
||||||
'<info>You are already using composer version %s (%s channel).</info>',
|
'<info>You are already using the latest available Composer version %s (%s channel).</info>',
|
||||||
$updateVersion,
|
$updateVersion,
|
||||||
$channelString
|
$channelString
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,6 +19,7 @@ use Composer\IO\IOInterface;
|
||||||
use Composer\Plugin\CommandEvent;
|
use Composer\Plugin\CommandEvent;
|
||||||
use Composer\Plugin\PluginEvents;
|
use Composer\Plugin\PluginEvents;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
|
use Composer\Util\HttpDownloader;
|
||||||
use Composer\Semver\Constraint\MultiConstraint;
|
use Composer\Semver\Constraint\MultiConstraint;
|
||||||
use Composer\Package\Link;
|
use Composer\Package\Link;
|
||||||
use Symfony\Component\Console\Helper\Table;
|
use Symfony\Component\Console\Helper\Table;
|
||||||
|
@ -114,6 +115,10 @@ EOT
|
||||||
|
|
||||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||||
|
|
||||||
|
if (!HttpDownloader::isCurlEnabled()) {
|
||||||
|
$io->writeError('<warning>Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.</warning>');
|
||||||
|
}
|
||||||
|
|
||||||
$packages = $input->getArgument('packages');
|
$packages = $input->getArgument('packages');
|
||||||
$reqs = $this->formatRequirements($input->getOption('with'));
|
$reqs = $this->formatRequirements($input->getOption('with'));
|
||||||
|
|
||||||
|
|
|
@ -78,8 +78,7 @@ class Config
|
||||||
public static $defaultRepositories = array(
|
public static $defaultRepositories = array(
|
||||||
'packagist.org' => array(
|
'packagist.org' => array(
|
||||||
'type' => 'composer',
|
'type' => 'composer',
|
||||||
'url' => 'https?://repo.packagist.org',
|
'url' => 'https://repo.packagist.org',
|
||||||
'allow_ssl_downgrade' => true,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -180,6 +179,11 @@ class Config
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auto-deactivate the default packagist.org repo if it gets redefined
|
||||||
|
if (isset($repository['type'], $repository['url']) && $repository['type'] === 'composer' && preg_match('{^https?://(?:[a-z0-9-.]+\.)?packagist.org(/|$)}', $repository['url'])) {
|
||||||
|
$this->disableRepoByName('packagist.org');
|
||||||
|
}
|
||||||
|
|
||||||
// store repo
|
// store repo
|
||||||
if (is_int($name)) {
|
if (is_int($name)) {
|
||||||
$this->repositories[] = $repository;
|
$this->repositories[] = $repository;
|
||||||
|
|
|
@ -237,11 +237,11 @@ class Application extends BaseApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) {
|
if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) {
|
||||||
$io->writeError('<warning>You are running composer with Xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug</warning>');
|
$io->writeError('<warning>Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug</warning>');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) {
|
if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) {
|
||||||
$io->writeError(sprintf('<warning>Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
|
$io->writeError(sprintf('<warning>Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -309,8 +309,9 @@ class Application extends BaseApplication
|
||||||
|
|
||||||
$result = parent::doRun($input, $output);
|
$result = parent::doRun($input, $output);
|
||||||
|
|
||||||
|
// chdir back to $oldWorkingDir if set
|
||||||
if (isset($oldWorkingDir)) {
|
if (isset($oldWorkingDir)) {
|
||||||
chdir($oldWorkingDir);
|
Silencer::call('chdir', $oldWorkingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($startTime)) {
|
if (isset($startTime)) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ class SolverProblemsException extends \RuntimeException
|
||||||
$hints[] = $this->createExtensionHint();
|
$hints[] = $this->createExtensionHint();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isCausedByLock && !$isDevExtraction) {
|
if ($isCausedByLock && !$isDevExtraction && !$request->getUpdateAllowTransitiveRootDependencies()) {
|
||||||
$hints[] = "Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.";
|
$hints[] = "Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Config;
|
||||||
use Composer\Cache;
|
use Composer\Cache;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\IO\NullIO;
|
use Composer\IO\NullIO;
|
||||||
|
use Composer\Exception\IrrecoverableDownloadException;
|
||||||
use Composer\Package\Comparer\Comparer;
|
use Composer\Package\Comparer\Comparer;
|
||||||
use Composer\DependencyResolver\Operation\UpdateOperation;
|
use Composer\DependencyResolver\Operation\UpdateOperation;
|
||||||
use Composer\DependencyResolver\Operation\InstallOperation;
|
use Composer\DependencyResolver\Operation\InstallOperation;
|
||||||
|
@ -219,6 +220,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
|
||||||
}
|
}
|
||||||
$self->clearLastCacheWrite($package);
|
$self->clearLastCacheWrite($package);
|
||||||
|
|
||||||
|
if ($e instanceof IrrecoverableDownloadException) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
if ($e instanceof TransportException) {
|
if ($e instanceof TransportException) {
|
||||||
// if we got an http response with a proper code, then requesting again will probably not help, abort
|
// if we got an http response with a proper code, then requesting again will probably not help, abort
|
||||||
if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) {
|
if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) {
|
||||||
|
|
|
@ -71,6 +71,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
|
||||||
if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref) && is_dir($cachePath)) {
|
if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref) && is_dir($cachePath)) {
|
||||||
$this->cachedPackages[$package->getId()][$ref] = true;
|
$this->cachedPackages[$package->getId()][$ref] = true;
|
||||||
}
|
}
|
||||||
|
} elseif (null === $gitVersion) {
|
||||||
|
throw new \RuntimeException('git was not found in your PATH, skipping source download');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,15 +456,12 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
|
||||||
|
|
||||||
$command = sprintf('git checkout %s --', ProcessExecutor::escape($branch));
|
$command = sprintf('git checkout %s --', ProcessExecutor::escape($branch));
|
||||||
$fallbackCommand = sprintf('git checkout '.$force.'-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
|
$fallbackCommand = sprintf('git checkout '.$force.'-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
|
||||||
if (0 === $this->process->execute($command, $output, $path)
|
$resetCommand = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference));
|
||||||
|| 0 === $this->process->execute($fallbackCommand, $output, $path)
|
|
||||||
) {
|
if (0 === $this->process->execute("($command || $fallbackCommand) && $resetCommand", $output, $path)) {
|
||||||
$command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference));
|
|
||||||
if (0 === $this->process->execute($command, $output, $path)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$command = sprintf($template, ProcessExecutor::escape($gitRef));
|
$command = sprintf($template, ProcessExecutor::escape($gitRef));
|
||||||
if (0 === $this->process->execute($command, $output, $path)) {
|
if (0 === $this->process->execute($command, $output, $path)) {
|
||||||
|
|
|
@ -26,6 +26,9 @@ class HgDownloader extends VcsDownloader
|
||||||
*/
|
*/
|
||||||
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
|
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
|
||||||
{
|
{
|
||||||
|
if (null === HgUtils::getVersion($this->process)) {
|
||||||
|
throw new \RuntimeException('hg was not found in your PATH, skipping source download');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,11 @@ class SvnDownloader extends VcsDownloader
|
||||||
*/
|
*/
|
||||||
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
|
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
|
||||||
{
|
{
|
||||||
|
SvnUtil::cleanEnv();
|
||||||
|
$util = new SvnUtil($url, $this->io, $this->config, $this->process);
|
||||||
|
if (null === $util->binaryVersion()) {
|
||||||
|
throw new \RuntimeException('svn was not found in your PATH, skipping source download');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ class TransportException extends \RuntimeException
|
||||||
protected $headers;
|
protected $headers;
|
||||||
protected $response;
|
protected $response;
|
||||||
protected $statusCode;
|
protected $statusCode;
|
||||||
|
protected $responseInfo = array();
|
||||||
|
|
||||||
public function setHeaders($headers)
|
public function setHeaders($headers)
|
||||||
{
|
{
|
||||||
|
@ -50,4 +51,20 @@ class TransportException extends \RuntimeException
|
||||||
{
|
{
|
||||||
return $this->statusCode;
|
return $this->statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseInfo()
|
||||||
|
{
|
||||||
|
return $this->responseInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $responseInfo
|
||||||
|
*/
|
||||||
|
public function setResponseInfo(array $responseInfo)
|
||||||
|
{
|
||||||
|
$this->responseInfo = $responseInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,8 @@ class EventDispatcher
|
||||||
|
|
||||||
if (strpos($exec, '@putenv ') === 0) {
|
if (strpos($exec, '@putenv ') === 0) {
|
||||||
putenv(substr($exec, 8));
|
putenv(substr($exec, 8));
|
||||||
|
list($var, $value) = explode('=', substr($exec, 8), 2);
|
||||||
|
$_SERVER[$var] = $value;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
namespace Composer;
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
use Composer\Semver\VersionParser;
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +23,8 @@ use Composer\Semver\VersionParser;
|
||||||
class InstalledVersions
|
class InstalledVersions
|
||||||
{
|
{
|
||||||
private static $installed;
|
private static $installed;
|
||||||
|
private static $canGetVendors;
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
@ -31,7 +34,17 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function getInstalledPackages()
|
public static function getInstalledPackages()
|
||||||
{
|
{
|
||||||
return array_keys(self::$installed['versions']);
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,7 +57,13 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function isInstalled($packageName)
|
public static function isInstalled($packageName)
|
||||||
{
|
{
|
||||||
return isset(self::$installed['versions'][$packageName]);
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,42 +98,50 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function getVersionRanges($packageName)
|
public static function getVersionRanges($packageName)
|
||||||
{
|
{
|
||||||
if (!isset(self::$installed['versions'][$packageName])) {
|
foreach (self::getInstalled() as $installed) {
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$ranges = array();
|
$ranges = array();
|
||||||
if (isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
$ranges[] = self::$installed['versions'][$packageName]['pretty_version'];
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
}
|
}
|
||||||
if (array_key_exists('aliases', self::$installed['versions'][$packageName])) {
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']);
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
}
|
}
|
||||||
if (array_key_exists('replaced', self::$installed['versions'][$packageName])) {
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']);
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
}
|
}
|
||||||
if (array_key_exists('provided', self::$installed['versions'][$packageName])) {
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']);
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode(' || ', $ranges);
|
return implode(' || ', $ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $packageName
|
* @param string $packageName
|
||||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
*/
|
*/
|
||||||
public static function getVersion($packageName)
|
public static function getVersion($packageName)
|
||||||
{
|
{
|
||||||
if (!isset(self::$installed['versions'][$packageName])) {
|
foreach (self::getInstalled() as $installed) {
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset(self::$installed['versions'][$packageName]['version'])) {
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$installed['versions'][$packageName]['version'];
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,15 +150,19 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function getPrettyVersion($packageName)
|
public static function getPrettyVersion($packageName)
|
||||||
{
|
{
|
||||||
if (!isset(self::$installed['versions'][$packageName])) {
|
foreach (self::getInstalled() as $installed) {
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$installed['versions'][$packageName]['pretty_version'];
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,15 +171,19 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function getReference($packageName)
|
public static function getReference($packageName)
|
||||||
{
|
{
|
||||||
if (!isset(self::$installed['versions'][$packageName])) {
|
foreach (self::getInstalled() as $installed) {
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset(self::$installed['versions'][$packageName]['reference'])) {
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$installed['versions'][$packageName]['reference'];
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,7 +192,9 @@ class InstalledVersions
|
||||||
*/
|
*/
|
||||||
public static function getRootPackage()
|
public static function getRootPackage()
|
||||||
{
|
{
|
||||||
return self::$installed['root'];
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,5 +229,32 @@ class InstalledVersions
|
||||||
public static function reload($data)
|
public static function reload($data)
|
||||||
{
|
{
|
||||||
self::$installed = $data;
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
|
||||||
|
return $installed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,14 @@ use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Package\Package;
|
use Composer\Package\Package;
|
||||||
use Composer\Repository\ArrayRepository;
|
use Composer\Repository\ArrayRepository;
|
||||||
use Composer\Repository\RepositorySet;
|
use Composer\Repository\RepositorySet;
|
||||||
|
use Composer\Repository\CompositeRepository;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use Composer\Package\Locker;
|
use Composer\Package\Locker;
|
||||||
use Composer\Package\RootPackageInterface;
|
use Composer\Package\RootPackageInterface;
|
||||||
use Composer\Repository\InstalledArrayRepository;
|
use Composer\Repository\InstalledArrayRepository;
|
||||||
use Composer\Repository\InstalledRepositoryInterface;
|
use Composer\Repository\InstalledRepositoryInterface;
|
||||||
use Composer\Repository\InstalledRepository;
|
use Composer\Repository\InstalledRepository;
|
||||||
|
use Composer\Repository\FilterRepository;
|
||||||
use Composer\Repository\RootPackageRepository;
|
use Composer\Repository\RootPackageRepository;
|
||||||
use Composer\Repository\PlatformRepository;
|
use Composer\Repository\PlatformRepository;
|
||||||
use Composer\Repository\RepositoryInterface;
|
use Composer\Repository\RepositoryInterface;
|
||||||
|
@ -706,7 +708,7 @@ class Installer
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createPlatformRepo($forUpdate)
|
protected function createPlatformRepo($forUpdate)
|
||||||
{
|
{
|
||||||
if ($forUpdate) {
|
if ($forUpdate) {
|
||||||
$platformOverrides = $this->config->get('platform') ?: array();
|
$platformOverrides = $this->config->get('platform') ?: array();
|
||||||
|
@ -766,6 +768,21 @@ class Installer
|
||||||
$repositorySet->addRepository(new RootPackageRepository($this->fixedRootPackage));
|
$repositorySet->addRepository(new RootPackageRepository($this->fixedRootPackage));
|
||||||
$repositorySet->addRepository($platformRepo);
|
$repositorySet->addRepository($platformRepo);
|
||||||
if ($this->additionalFixedRepository) {
|
if ($this->additionalFixedRepository) {
|
||||||
|
// allow using installed repos if needed to avoid warnings about installed repositories being used in the RepositorySet
|
||||||
|
// see https://github.com/composer/composer/pull/9574
|
||||||
|
$additionalFixedRepositories = $this->additionalFixedRepository;
|
||||||
|
if ($additionalFixedRepositories instanceof CompositeRepository) {
|
||||||
|
$additionalFixedRepositories = $additionalFixedRepositories->getRepositories();
|
||||||
|
} else {
|
||||||
|
$additionalFixedRepositories = array($additionalFixedRepositories);
|
||||||
|
}
|
||||||
|
foreach ($additionalFixedRepositories as $additionalFixedRepository) {
|
||||||
|
if ($additionalFixedRepository instanceof InstalledRepository || $additionalFixedRepository instanceof InstalledRepositoryInterface) {
|
||||||
|
$repositorySet->allowInstalledRepositories();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$repositorySet->addRepository($this->additionalFixedRepository);
|
$repositorySet->addRepository($this->additionalFixedRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -492,9 +492,15 @@ class InstallationManager
|
||||||
$promise = $installer->update($repo, $initial, $target);
|
$promise = $installer->update($repo, $initial, $target);
|
||||||
$this->markForNotification($target);
|
$this->markForNotification($target);
|
||||||
} else {
|
} else {
|
||||||
$this->getInstaller($initialType)->uninstall($repo, $initial);
|
$promise = $this->getInstaller($initialType)->uninstall($repo, $initial);
|
||||||
|
if (!$promise instanceof PromiseInterface) {
|
||||||
|
$promise = \React\Promise\resolve();
|
||||||
|
}
|
||||||
|
|
||||||
$installer = $this->getInstaller($targetType);
|
$installer = $this->getInstaller($targetType);
|
||||||
$promise = $installer->install($repo, $target);
|
$promise->then(function () use ($installer, $repo, $target) {
|
||||||
|
return $installer->install($repo, $target);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $promise;
|
return $promise;
|
||||||
|
|
|
@ -80,6 +80,7 @@ class JsonFile
|
||||||
/**
|
/**
|
||||||
* Reads json file.
|
* Reads json file.
|
||||||
*
|
*
|
||||||
|
* @throws ParsingException
|
||||||
* @throws \RuntimeException
|
* @throws \RuntimeException
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
@ -172,6 +173,7 @@ class JsonFile
|
||||||
* @param int $schema a JsonFile::*_SCHEMA constant
|
* @param int $schema a JsonFile::*_SCHEMA constant
|
||||||
* @param string|null $schemaFile a path to the schema file
|
* @param string|null $schemaFile a path to the schema file
|
||||||
* @throws JsonValidationException
|
* @throws JsonValidationException
|
||||||
|
* @throws ParsingException
|
||||||
* @return bool true on success
|
* @return bool true on success
|
||||||
*/
|
*/
|
||||||
public function validateSchema($schema = self::STRICT_SCHEMA, $schemaFile = null)
|
public function validateSchema($schema = self::STRICT_SCHEMA, $schemaFile = null)
|
||||||
|
@ -289,6 +291,7 @@ class JsonFile
|
||||||
* @param string $json json string
|
* @param string $json json string
|
||||||
* @param string $file the json file
|
* @param string $file the json file
|
||||||
*
|
*
|
||||||
|
* @throws ParsingException
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function parseJson($json, $file = null)
|
public static function parseJson($json, $file = null)
|
||||||
|
|
|
@ -20,13 +20,13 @@ use Composer\Repository\PlatformRepository;
|
||||||
class JsonManipulator
|
class JsonManipulator
|
||||||
{
|
{
|
||||||
private static $DEFINES = '(?(DEFINE)
|
private static $DEFINES = '(?(DEFINE)
|
||||||
(?<number> -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
|
(?<number> -? (?= [1-9]|0(?!\d) ) \d++ (\.\d++)? ([eE] [+-]?+ \d++)? )
|
||||||
(?<boolean> true | false | null )
|
(?<boolean> true | false | null )
|
||||||
(?<string> " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " )
|
(?<string> " ([^"\\\\]*+ | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " )
|
||||||
(?<array> \[ (?: (?&json) \s* (?: , (?&json) \s* )* )? \s* \] )
|
(?<array> \[ (?: (?&json) \s*+ (?: , (?&json) \s*+ )*+ )?+ \s*+ \] )
|
||||||
(?<pair> \s* (?&string) \s* : (?&json) \s* )
|
(?<pair> \s*+ (?&string) \s*+ : (?&json) \s*+ )
|
||||||
(?<object> \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} )
|
(?<object> \{ (?: (?&pair) (?: , (?&pair) )*+ )?+ \s*+ \} )
|
||||||
(?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) )
|
(?<json> \s*+ (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) )
|
||||||
)';
|
)';
|
||||||
|
|
||||||
private $contents;
|
private $contents;
|
||||||
|
|
|
@ -123,26 +123,25 @@ abstract class BaseExcludeFilter
|
||||||
protected function generatePattern($rule)
|
protected function generatePattern($rule)
|
||||||
{
|
{
|
||||||
$negate = false;
|
$negate = false;
|
||||||
$pattern = '{';
|
$pattern = '';
|
||||||
|
|
||||||
if (strlen($rule) && $rule[0] === '!') {
|
if ($rule !== '' && $rule[0] === '!') {
|
||||||
$negate = true;
|
$negate = true;
|
||||||
$rule = substr($rule, 1);
|
$rule = ltrim($rule, '!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($rule) && $rule[0] === '/') {
|
$firstSlashPosition = strpos($rule, '/');
|
||||||
$pattern .= '^/';
|
if (0 === $firstSlashPosition) {
|
||||||
$rule = substr($rule, 1);
|
$pattern = '^/';
|
||||||
} elseif (strlen($rule) - 1 === strpos($rule, '/')) {
|
} elseif (false === $firstSlashPosition || strlen($rule) - 1 === $firstSlashPosition) {
|
||||||
$pattern .= '/';
|
$pattern = '/';
|
||||||
$rule = substr($rule, 0, -1);
|
|
||||||
} elseif (false === strpos($rule, '/')) {
|
|
||||||
$pattern .= '/';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rule = trim($rule, '/');
|
||||||
|
|
||||||
// remove delimiters as well as caret (^) and dollar sign ($) from the regex
|
// remove delimiters as well as caret (^) and dollar sign ($) from the regex
|
||||||
$pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)';
|
$rule = substr(Finder\Glob::toRegex($rule), 2, -2);
|
||||||
|
|
||||||
return array($pattern . '}', $negate, false);
|
return array('{'.$pattern.$rule.'(?=$|/)}', $negate, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,10 +74,8 @@ class RootPackageLoader extends ArrayLoader
|
||||||
if (!isset($config['version'])) {
|
if (!isset($config['version'])) {
|
||||||
$commit = null;
|
$commit = null;
|
||||||
|
|
||||||
if (isset($config['extra']['branch-version'])) {
|
|
||||||
$config['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $config['extra']['branch-version']).'.x-dev';
|
|
||||||
} elseif (getenv('COMPOSER_ROOT_VERSION')) {
|
|
||||||
// override with env var if available
|
// override with env var if available
|
||||||
|
if (getenv('COMPOSER_ROOT_VERSION')) {
|
||||||
$config['version'] = getenv('COMPOSER_ROOT_VERSION');
|
$config['version'] = getenv('COMPOSER_ROOT_VERSION');
|
||||||
} else {
|
} else {
|
||||||
$versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
|
$versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
|
||||||
|
|
|
@ -21,7 +21,9 @@ use Composer\Package\RootPackage;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Repository\RepositoryInterface;
|
use Composer\Repository\RepositoryInterface;
|
||||||
use Composer\Repository\InstalledRepository;
|
use Composer\Repository\InstalledRepository;
|
||||||
|
use Composer\Repository\RootPackageRepository;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\RootPackageInterface;
|
||||||
use Composer\Package\Link;
|
use Composer\Package\Link;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use Composer\Plugin\Capability\Capability;
|
use Composer\Plugin\Capability\Capability;
|
||||||
|
@ -174,7 +176,9 @@ class PluginManager
|
||||||
$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||||
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
||||||
|
|
||||||
$installedRepo = new InstalledRepository(array($localRepo));
|
$rootPackage = clone $this->composer->getPackage();
|
||||||
|
$rootPackageRepo = new RootPackageRepository($rootPackage);
|
||||||
|
$installedRepo = new InstalledRepository(array($localRepo, $rootPackageRepo));
|
||||||
if ($globalRepo) {
|
if ($globalRepo) {
|
||||||
$installedRepo->addRepository($globalRepo);
|
$installedRepo->addRepository($globalRepo);
|
||||||
}
|
}
|
||||||
|
@ -183,13 +187,17 @@ class PluginManager
|
||||||
$autoloadPackages = $this->collectDependencies($installedRepo, $autoloadPackages, $package);
|
$autoloadPackages = $this->collectDependencies($installedRepo, $autoloadPackages, $package);
|
||||||
|
|
||||||
$generator = $this->composer->getAutoloadGenerator();
|
$generator = $this->composer->getAutoloadGenerator();
|
||||||
$autoloads = array();
|
$autoloads = array(array($rootPackage, ''));
|
||||||
foreach ($autoloadPackages as $autoloadPackage) {
|
foreach ($autoloadPackages as $autoloadPackage) {
|
||||||
|
if ($autoloadPackage === $rootPackage) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage));
|
$downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage));
|
||||||
$autoloads[] = array($autoloadPackage, $downloadPath);
|
$autoloads[] = array($autoloadPackage, $downloadPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
$map = $generator->parseAutoloads($autoloads, new RootPackage('dummy/root-package', '1.0.0.0', '1.0.0'));
|
$map = $generator->parseAutoloads($autoloads, $rootPackage);
|
||||||
$classLoader = $generator->createLoader($map);
|
$classLoader = $generator->createLoader($map);
|
||||||
$classLoader->register();
|
$classLoader->register();
|
||||||
|
|
||||||
|
@ -403,12 +411,7 @@ class PluginManager
|
||||||
*/
|
*/
|
||||||
private function collectDependencies(InstalledRepository $installedRepo, array $collected, PackageInterface $package)
|
private function collectDependencies(InstalledRepository $installedRepo, array $collected, PackageInterface $package)
|
||||||
{
|
{
|
||||||
$requires = array_merge(
|
foreach ($package->getRequires() as $requireLink) {
|
||||||
$package->getRequires(),
|
|
||||||
$package->getDevRequires()
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($requires as $requireLink) {
|
|
||||||
foreach ($installedRepo->findPackagesWithReplacersAndProviders($requireLink->getTarget()) as $requiredPackage) {
|
foreach ($installedRepo->findPackagesWithReplacersAndProviders($requireLink->getTarget()) as $requiredPackage) {
|
||||||
if (!isset($collected[$requiredPackage->getName()])) {
|
if (!isset($collected[$requiredPackage->getName()])) {
|
||||||
$collected[$requiredPackage->getName()] = $requiredPackage;
|
$collected[$requiredPackage->getName()] = $requiredPackage;
|
||||||
|
|
|
@ -532,6 +532,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
*/
|
*/
|
||||||
private function whatProvides($name, array $acceptableStabilities = null, array $stabilityFlags = null, array $alreadyLoaded = array())
|
private function whatProvides($name, array $acceptableStabilities = null, array $stabilityFlags = null, array $alreadyLoaded = array())
|
||||||
{
|
{
|
||||||
|
$packagesSource = null;
|
||||||
if (!$this->hasPartialPackages() || !isset($this->partialPackagesByName[$name])) {
|
if (!$this->hasPartialPackages() || !isset($this->partialPackagesByName[$name])) {
|
||||||
// skip platform packages, root package and composer-plugin-api
|
// skip platform packages, root package and composer-plugin-api
|
||||||
if (PlatformRepository::isPlatformPackage($name) || '__root__' === $name) {
|
if (PlatformRepository::isPlatformPackage($name) || '__root__' === $name) {
|
||||||
|
@ -565,15 +566,18 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
if ($cacheKey) {
|
if ($cacheKey) {
|
||||||
if (!$useLastModifiedCheck && $hash && $this->cache->sha256($cacheKey) === $hash) {
|
if (!$useLastModifiedCheck && $hash && $this->cache->sha256($cacheKey) === $hash) {
|
||||||
$packages = json_decode($this->cache->read($cacheKey), true);
|
$packages = json_decode($this->cache->read($cacheKey), true);
|
||||||
|
$packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')';
|
||||||
} elseif ($useLastModifiedCheck) {
|
} elseif ($useLastModifiedCheck) {
|
||||||
if ($contents = $this->cache->read($cacheKey)) {
|
if ($contents = $this->cache->read($cacheKey)) {
|
||||||
$contents = json_decode($contents, true);
|
$contents = json_decode($contents, true);
|
||||||
// we already loaded some packages from this file, so assume it is fresh and avoid fetching it again
|
// we already loaded some packages from this file, so assume it is fresh and avoid fetching it again
|
||||||
if (isset($alreadyLoaded[$name])) {
|
if (isset($alreadyLoaded[$name])) {
|
||||||
$packages = $contents;
|
$packages = $contents;
|
||||||
|
$packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')';
|
||||||
} elseif (isset($contents['last-modified'])) {
|
} elseif (isset($contents['last-modified'])) {
|
||||||
$response = $this->fetchFileIfLastModified($url, $cacheKey, $contents['last-modified']);
|
$response = $this->fetchFileIfLastModified($url, $cacheKey, $contents['last-modified']);
|
||||||
$packages = true === $response ? $contents : $response;
|
$packages = true === $response ? $contents : $response;
|
||||||
|
$packagesSource = true === $response ? 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')' : 'downloaded file ('.Url::sanitize($url).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -582,10 +586,12 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
if (!$packages) {
|
if (!$packages) {
|
||||||
try {
|
try {
|
||||||
$packages = $this->fetchFile($url, $cacheKey, $hash, $useLastModifiedCheck);
|
$packages = $this->fetchFile($url, $cacheKey, $hash, $useLastModifiedCheck);
|
||||||
|
$packagesSource = 'downloaded file ('.Url::sanitize($url).')';
|
||||||
} catch (TransportException $e) {
|
} catch (TransportException $e) {
|
||||||
// 404s are acceptable for lazy provider repos
|
// 404s are acceptable for lazy provider repos
|
||||||
if ($this->lazyProvidersUrl && in_array($e->getStatusCode(), array(404, 499), true)) {
|
if ($this->lazyProvidersUrl && in_array($e->getStatusCode(), array(404, 499), true)) {
|
||||||
$packages = array('packages' => array());
|
$packages = array('packages' => array());
|
||||||
|
$packagesSource = 'not-found file ('.Url::sanitize($url).')';
|
||||||
if ($e->getStatusCode() === 499) {
|
if ($e->getStatusCode() === 499) {
|
||||||
$this->io->error('<warning>' . $e->getMessage() . '</warning>');
|
$this->io->error('<warning>' . $e->getMessage() . '</warning>');
|
||||||
}
|
}
|
||||||
|
@ -598,6 +604,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
$loadingPartialPackage = false;
|
$loadingPartialPackage = false;
|
||||||
} else {
|
} else {
|
||||||
$packages = array('packages' => array('versions' => $this->partialPackagesByName[$name]));
|
$packages = array('packages' => array('versions' => $this->partialPackagesByName[$name]));
|
||||||
|
$packagesSource = 'root file ('.Url::sanitize($this->getPackagesJsonUrl()).')';
|
||||||
$loadingPartialPackage = true;
|
$loadingPartialPackage = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +644,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
// load acceptable packages in the providers
|
// load acceptable packages in the providers
|
||||||
$loadedPackages = $this->createPackages($versionsToLoad);
|
$loadedPackages = $this->createPackages($versionsToLoad, $packagesSource);
|
||||||
$uids = array_keys($versionsToLoad);
|
$uids = array_keys($versionsToLoad);
|
||||||
|
|
||||||
foreach ($loadedPackages as $index => $package) {
|
foreach ($loadedPackages as $index => $package) {
|
||||||
|
@ -667,7 +674,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
|
|
||||||
$repoData = $this->loadDataFromServer();
|
$repoData = $this->loadDataFromServer();
|
||||||
|
|
||||||
foreach ($this->createPackages($repoData) as $package) {
|
foreach ($this->createPackages($repoData, 'root file ('.Url::sanitize($this->getPackagesJsonUrl()).')') as $package) {
|
||||||
$this->addPackage($package);
|
$this->addPackage($package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -729,8 +736,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
$promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
|
$promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
|
||||||
->then(function ($response) use (&$packages, &$namesFound, $contents, $realName, $constraint, $repo, $acceptableStabilities, $stabilityFlags, $alreadyLoaded) {
|
->then(function ($response) use (&$packages, &$namesFound, $url, $cacheKey, $contents, $realName, $constraint, $repo, $acceptableStabilities, $stabilityFlags, $alreadyLoaded) {
|
||||||
|
$packagesSource = 'downloaded file ('.Url::sanitize($url).')';
|
||||||
|
|
||||||
if (true === $response) {
|
if (true === $response) {
|
||||||
|
$packagesSource = 'cached file ('.$cacheKey.' originating from '.Url::sanitize($url).')';
|
||||||
$response = $contents;
|
$response = $contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,7 +774,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$loadedPackages = $repo->createPackages($versionsToLoad);
|
$loadedPackages = $repo->createPackages($versionsToLoad, $packagesSource);
|
||||||
foreach ($loadedPackages as $package) {
|
foreach ($loadedPackages as $package) {
|
||||||
$package->setRepository($repo);
|
$package->setRepository($repo);
|
||||||
$packages[spl_object_hash($package)] = $package;
|
$packages[spl_object_hash($package)] = $package;
|
||||||
|
@ -812,6 +822,17 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPackagesJsonUrl()
|
||||||
|
{
|
||||||
|
$jsonUrlParts = parse_url($this->url);
|
||||||
|
|
||||||
|
if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->url . '/packages.json';
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadRootServerFile()
|
protected function loadRootServerFile()
|
||||||
{
|
{
|
||||||
if (null !== $this->rootData) {
|
if (null !== $this->rootData) {
|
||||||
|
@ -822,15 +843,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
|
throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
|
||||||
}
|
}
|
||||||
|
|
||||||
$jsonUrlParts = parse_url($this->url);
|
$data = $this->fetchFile($this->getPackagesJsonUrl(), 'packages.json');
|
||||||
|
|
||||||
if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
|
|
||||||
$jsonUrl = $this->url;
|
|
||||||
} else {
|
|
||||||
$jsonUrl = $this->url . '/packages.json';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->fetchFile($jsonUrl, 'packages.json');
|
|
||||||
|
|
||||||
if (!empty($data['notify-batch'])) {
|
if (!empty($data['notify-batch'])) {
|
||||||
$this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']);
|
$this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']);
|
||||||
|
@ -1027,7 +1040,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
public function createPackages(array $packages, $class = 'Composer\Package\CompletePackage')
|
public function createPackages(array $packages, $source = null)
|
||||||
{
|
{
|
||||||
if (!$packages) {
|
if (!$packages) {
|
||||||
return array();
|
return array();
|
||||||
|
@ -1040,7 +1053,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$packages = $this->loader->loadPackages($packages, $class);
|
$packages = $this->loader->loadPackages($packages, 'Composer\Package\CompletePackage');
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
foreach ($packages as $package) {
|
||||||
if (isset($this->sourceMirrors[$package->getSourceType()])) {
|
if (isset($this->sourceMirrors[$package->getSourceType()])) {
|
||||||
|
@ -1052,7 +1065,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
|
|
||||||
return $packages;
|
return $packages;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException('Could not load packages '.(isset($packages[0]['name']) ? $packages[0]['name'] : json_encode($packages)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('Could not load packages '.(isset($packages[0]['name']) ? $packages[0]['name'] : json_encode($packages)).' in '.$this->getRepoName().($source ? ' from '.$source : '').': ['.get_class($e).'] '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,6 +204,9 @@ class FilesystemRepository extends WritableArrayRepository
|
||||||
|
|
||||||
$fs->filePutContentsIfModified($repoDir.'/installed.php', '<?php return '.var_export($versions, true).';'."\n");
|
$fs->filePutContentsIfModified($repoDir.'/installed.php', '<?php return '.var_export($versions, true).';'."\n");
|
||||||
$installedVersionsClass = file_get_contents(__DIR__.'/../InstalledVersions.php');
|
$installedVersionsClass = file_get_contents(__DIR__.'/../InstalledVersions.php');
|
||||||
|
// while not strictly needed since https://github.com/composer/composer/pull/9635 - we keep this for BC
|
||||||
|
// and overall broader compatibility with people that may not use Composer's ClassLoader. They can
|
||||||
|
// simply include InstalledVersions.php manually and have it working in a basic way.
|
||||||
$installedVersionsClass = str_replace('private static $installed;', 'private static $installed = '.var_export($versions, true).';', $installedVersionsClass);
|
$installedVersionsClass = str_replace('private static $installed;', 'private static $installed = '.var_export($versions, true).';', $installedVersionsClass);
|
||||||
$fs->filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass);
|
$fs->filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass);
|
||||||
|
|
||||||
|
|
|
@ -170,10 +170,11 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn
|
||||||
'reference' => sha1($json . serialize($this->options)),
|
'reference' => sha1($json . serialize($this->options)),
|
||||||
);
|
);
|
||||||
$package['transport-options'] = $this->options;
|
$package['transport-options'] = $this->options;
|
||||||
|
unset($package['transport-options']['versions']);
|
||||||
|
|
||||||
// use the branch-version as the package version if available
|
// use the version provided as option if available
|
||||||
if (!isset($package['version']) && isset($package['extra']['branch-version'])) {
|
if (isset($package['name'], $this->options['versions'][$package['name']])) {
|
||||||
$package['version'] = preg_replace('{(\.x)?(-dev)?$}', '', $package['extra']['branch-version']).'.x-dev';
|
$package['version'] = $this->options['versions'][$package['name']];
|
||||||
}
|
}
|
||||||
|
|
||||||
// carry over the root package version if this path repo is in the same git repository as root package
|
// carry over the root package version if this path repo is in the same git repository as root package
|
||||||
|
|
|
@ -37,6 +37,9 @@ class GitDriver extends VcsDriver
|
||||||
{
|
{
|
||||||
if (Filesystem::isLocalPath($this->url)) {
|
if (Filesystem::isLocalPath($this->url)) {
|
||||||
$this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
|
$this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
|
||||||
|
if (!is_dir($this->url)) {
|
||||||
|
throw new \RuntimeException('Failed to read package information from '.$this->url.' as the path does not exist');
|
||||||
|
}
|
||||||
$this->repoDir = $this->url;
|
$this->repoDir = $this->url;
|
||||||
$cacheUrl = realpath($this->url);
|
$cacheUrl = realpath($this->url);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Filesystem
|
||||||
|
|
||||||
public function emptyDirectory($dir, $ensureDirectoryExists = true)
|
public function emptyDirectory($dir, $ensureDirectoryExists = true)
|
||||||
{
|
{
|
||||||
if (file_exists($dir) && is_link($dir)) {
|
if (is_link($dir) && file_exists($dir)) {
|
||||||
$this->unlink($dir);
|
$this->unlink($dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ class Filesystem
|
||||||
return unlink($directory);
|
return unlink($directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists($directory) || !is_dir($directory)) {
|
if (!is_dir($directory) || !file_exists($directory)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ class Filesystem
|
||||||
// clear stat cache because external processes aren't tracked by the php stat cache
|
// clear stat cache because external processes aren't tracked by the php stat cache
|
||||||
clearstatcache();
|
clearstatcache();
|
||||||
|
|
||||||
if ($result && !file_exists($directory)) {
|
if ($result && !is_dir($directory)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ class Git
|
||||||
$errorMsg = $this->process->getErrorOutput();
|
$errorMsg = $this->process->getErrorOutput();
|
||||||
// private github repository without ssh key access, try https with auth
|
// private github repository without ssh key access, try https with auth
|
||||||
if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match)
|
if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match)
|
||||||
|| preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)
|
|| preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match)
|
||||||
) {
|
) {
|
||||||
if (!$this->io->hasAuthentication($match[1])) {
|
if (!$this->io->hasAuthentication($match[1])) {
|
||||||
$gitHubUtil = new GitHub($this->io, $this->config, $this->process);
|
$gitHubUtil = new GitHub($this->io, $this->config, $this->process);
|
||||||
|
@ -122,7 +122,7 @@ class Git
|
||||||
|
|
||||||
$errorMsg = $this->process->getErrorOutput();
|
$errorMsg = $this->process->getErrorOutput();
|
||||||
}
|
}
|
||||||
} elseif (preg_match('{^https://(bitbucket\.org)/(.*)(\.git)?$}U', $url, $match)) { //bitbucket oauth
|
} elseif (preg_match('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth
|
||||||
$bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process);
|
$bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process);
|
||||||
|
|
||||||
if (!$this->io->hasAuthentication($match[1])) {
|
if (!$this->io->hasAuthentication($match[1])) {
|
||||||
|
@ -167,7 +167,7 @@ class Git
|
||||||
}
|
}
|
||||||
} elseif (
|
} elseif (
|
||||||
preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match)
|
preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match)
|
||||||
|| preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}', $url, $match)
|
|| preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match)
|
||||||
) {
|
) {
|
||||||
if ($match[1] === 'git') {
|
if ($match[1] === 'git') {
|
||||||
$match[1] = 'https';
|
$match[1] = 'https';
|
||||||
|
@ -354,7 +354,7 @@ class Git
|
||||||
// added in git 1.7.1, prevents prompting the user for username/password
|
// added in git 1.7.1, prevents prompting the user for username/password
|
||||||
if (getenv('GIT_ASKPASS') !== 'echo') {
|
if (getenv('GIT_ASKPASS') !== 'echo') {
|
||||||
putenv('GIT_ASKPASS=echo');
|
putenv('GIT_ASKPASS=echo');
|
||||||
unset($_SERVER['GIT_ASKPASS']);
|
$_SERVER['GIT_ASKPASS'] = 'echo';
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up rogue git env vars in case this is running in a git hook
|
// clean up rogue git env vars in case this is running in a git hook
|
||||||
|
@ -370,6 +370,7 @@ class Git
|
||||||
// Run processes with predictable LANGUAGE
|
// Run processes with predictable LANGUAGE
|
||||||
if (getenv('LANGUAGE') !== 'C') {
|
if (getenv('LANGUAGE') !== 'C') {
|
||||||
putenv('LANGUAGE=C');
|
putenv('LANGUAGE=C');
|
||||||
|
$_SERVER['LANGUAGE'] = 'C';
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940
|
// clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940
|
||||||
|
@ -402,15 +403,12 @@ class Git
|
||||||
/**
|
/**
|
||||||
* Retrieves the current git version.
|
* Retrieves the current git version.
|
||||||
*
|
*
|
||||||
* @return string|null The git version number.
|
* @return string|null The git version number, if present.
|
||||||
*/
|
*/
|
||||||
public static function getVersion(ProcessExecutor $process)
|
public static function getVersion(ProcessExecutor $process)
|
||||||
{
|
{
|
||||||
if (false === self::$version) {
|
if (false === self::$version) {
|
||||||
self::$version = null;
|
self::$version = null;
|
||||||
if (!$process) {
|
|
||||||
$process = new ProcessExecutor;
|
|
||||||
}
|
|
||||||
if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) {
|
if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) {
|
||||||
self::$version = $matches[1];
|
self::$version = $matches[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ use Composer\IO\IOInterface;
|
||||||
*/
|
*/
|
||||||
class Hg
|
class Hg
|
||||||
{
|
{
|
||||||
|
private static $version = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Composer\IO\IOInterface
|
* @var \Composer\IO\IOInterface
|
||||||
*/
|
*/
|
||||||
|
@ -74,10 +76,27 @@ class Hg
|
||||||
|
|
||||||
private function throwException($message, $url)
|
private function throwException($message, $url)
|
||||||
{
|
{
|
||||||
if (0 !== $this->process->execute('hg --version', $ignoredOutput)) {
|
if (null === self::getVersion($this->process)) {
|
||||||
throw new \RuntimeException(Url::sanitize('Failed to clone ' . $url . ', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()));
|
throw new \RuntimeException(Url::sanitize('Failed to clone ' . $url . ', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \RuntimeException(Url::sanitize($message));
|
throw new \RuntimeException(Url::sanitize($message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current hg version.
|
||||||
|
*
|
||||||
|
* @return string|null The hg version number, if present.
|
||||||
|
*/
|
||||||
|
public static function getVersion(ProcessExecutor $process)
|
||||||
|
{
|
||||||
|
if (false === self::$version) {
|
||||||
|
self::$version = null;
|
||||||
|
if (0 === $process->execute('hg --version', $output) && preg_match('/version (\d+(?:\.\d+)+)/m', $output, $matches)) {
|
||||||
|
self::$version = $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$version;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,12 +321,12 @@ class CurlDownloader
|
||||||
rewind($job['bodyHandle']);
|
rewind($job['bodyHandle']);
|
||||||
$contents = stream_get_contents($job['bodyHandle']);
|
$contents = stream_get_contents($job['bodyHandle']);
|
||||||
}
|
}
|
||||||
$response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents);
|
$response = new CurlResponse(array('url' => $progress['url']), $statusCode, $headers, $contents, $progress);
|
||||||
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG);
|
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG);
|
||||||
} else {
|
} else {
|
||||||
rewind($job['bodyHandle']);
|
rewind($job['bodyHandle']);
|
||||||
$contents = stream_get_contents($job['bodyHandle']);
|
$contents = stream_get_contents($job['bodyHandle']);
|
||||||
$response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents);
|
$response = new CurlResponse(array('url' => $progress['url']), $statusCode, $headers, $contents, $progress);
|
||||||
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG);
|
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG);
|
||||||
}
|
}
|
||||||
fclose($job['bodyHandle']);
|
fclose($job['bodyHandle']);
|
||||||
|
@ -374,6 +374,9 @@ class CurlDownloader
|
||||||
if ($e instanceof TransportException && $response) {
|
if ($e instanceof TransportException && $response) {
|
||||||
$e->setResponse($response->getBody());
|
$e->setResponse($response->getBody());
|
||||||
}
|
}
|
||||||
|
if ($e instanceof TransportException && $progress) {
|
||||||
|
$e->setResponseInfo($progress);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_resource($job['headerHandle'])) {
|
if (is_resource($job['headerHandle'])) {
|
||||||
fclose($job['headerHandle']);
|
fclose($job['headerHandle']);
|
||||||
|
@ -511,7 +514,12 @@ class CurlDownloader
|
||||||
@unlink($job['filename'].'~');
|
@unlink($job['filename'].'~');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TransportException('The "'.$job['url'].'" file could not be downloaded ('.$errorMessage.')', $response->getStatusCode());
|
$details = '';
|
||||||
|
if ($response->getHeader('content-type') === 'application/json') {
|
||||||
|
$details = ':'.PHP_EOL.substr($response->getBody(), 0, 200).(strlen($response->getBody()) > 200 ? '...' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TransportException('The "'.$job['url'].'" file could not be downloaded ('.$errorMessage.')' . $details, $response->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkCurlResult($code)
|
private function checkCurlResult($code)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Util\Http;
|
||||||
|
|
||||||
|
class CurlResponse extends Response
|
||||||
|
{
|
||||||
|
private $curlInfo;
|
||||||
|
|
||||||
|
public function __construct(array $request, $code, array $headers, $body, array $curlInfo)
|
||||||
|
{
|
||||||
|
parent::__construct($request, $code, $headers, $body);
|
||||||
|
$this->curlInfo = $curlInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCurlInfo()
|
||||||
|
{
|
||||||
|
return $this->curlInfo;
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ class ProxyManager
|
||||||
$options = array();
|
$options = array();
|
||||||
$formattedProxyUrl = '';
|
$formattedProxyUrl = '';
|
||||||
|
|
||||||
if ($this->hasProxy && $this->fullProxy[$scheme]) {
|
if ($this->hasProxy && in_array($scheme, array('http', 'https'), true) && $this->fullProxy[$scheme]) {
|
||||||
if ($this->noProxy($requestUrl)) {
|
if ($this->noProxy($requestUrl)) {
|
||||||
$formattedProxyUrl = 'excluded by no_proxy';
|
$formattedProxyUrl = 'excluded by no_proxy';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,6 +19,7 @@ use Composer\Util\Http\Response;
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
|
use Composer\Exception\IrrecoverableDownloadException;
|
||||||
use React\Promise\Promise;
|
use React\Promise\Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +38,7 @@ class HttpDownloader
|
||||||
private $jobs = array();
|
private $jobs = array();
|
||||||
private $options = array();
|
private $options = array();
|
||||||
private $runningJobs = 0;
|
private $runningJobs = 0;
|
||||||
private $maxJobs = 10;
|
private $maxJobs = 12;
|
||||||
private $curl;
|
private $curl;
|
||||||
private $rfs;
|
private $rfs;
|
||||||
private $idGen = 0;
|
private $idGen = 0;
|
||||||
|
@ -71,6 +72,10 @@ class HttpDownloader
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rfs = new RemoteFilesystem($io, $config, $options, $disableTls);
|
$this->rfs = new RemoteFilesystem($io, $config, $options, $disableTls);
|
||||||
|
|
||||||
|
if (is_numeric($maxJobs = getenv('COMPOSER_MAX_PARALLEL_HTTP'))) {
|
||||||
|
$this->maxJobs = max(1, min(50, (int) $maxJobs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,10 +258,11 @@ class HttpDownloader
|
||||||
if (isset($job['curl_id'])) {
|
if (isset($job['curl_id'])) {
|
||||||
$curl->abortRequest($job['curl_id']);
|
$curl->abortRequest($job['curl_id']);
|
||||||
}
|
}
|
||||||
|
throw new IrrecoverableDownloadException('Download of ' . Url::sanitize($job['request']['url']) . ' canceled');
|
||||||
};
|
};
|
||||||
|
|
||||||
$promise = new Promise($resolver, $canceler);
|
$promise = new Promise($resolver, $canceler);
|
||||||
$promise->then(function ($response) use (&$job, $downloader) {
|
$promise = $promise->then(function ($response) use (&$job, $downloader) {
|
||||||
$job['status'] = HttpDownloader::STATUS_COMPLETED;
|
$job['status'] = HttpDownloader::STATUS_COMPLETED;
|
||||||
$job['response'] = $response;
|
$job['response'] = $response;
|
||||||
|
|
||||||
|
@ -302,7 +308,7 @@ class HttpDownloader
|
||||||
if (isset($job['request']['options']['http']['header']) && false !== stripos(implode('', $job['request']['options']['http']['header']), 'if-modified-since')) {
|
if (isset($job['request']['options']['http']['header']) && false !== stripos(implode('', $job['request']['options']['http']['header']), 'if-modified-since')) {
|
||||||
$resolve(new Response(array('url' => $url), 304, array(), ''));
|
$resolve(new Response(array('url' => $url), 304, array(), ''));
|
||||||
} else {
|
} else {
|
||||||
$e = new TransportException('Network disabled, request canceled: '.$url, 499);
|
$e = new TransportException('Network disabled, request canceled: '.Url::sanitize($url), 499);
|
||||||
$e->setStatusCode(499);
|
$e->setStatusCode(499);
|
||||||
$reject($e);
|
$reject($e);
|
||||||
}
|
}
|
||||||
|
@ -336,13 +342,9 @@ class HttpDownloader
|
||||||
*/
|
*/
|
||||||
public function wait($index = null)
|
public function wait($index = null)
|
||||||
{
|
{
|
||||||
while (true) {
|
do {
|
||||||
if (!$this->countActiveJobs($index)) {
|
$jobCount = $this->countActiveJobs($index);
|
||||||
return;
|
} while ($jobCount);
|
||||||
}
|
|
||||||
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -429,7 +431,7 @@ class HttpDownloader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].'</'.$type.'>');
|
$io->writeError('<'.$type.'>'.ucfirst($type).' from '.Url::sanitize($url).': '.$data[$type].'</'.$type.'>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ class Loop
|
||||||
$progress->start($totalJobs);
|
$progress->start($totalJobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$lastUpdate = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
$activeJobs = 0;
|
$activeJobs = 0;
|
||||||
|
|
||||||
|
@ -95,15 +96,19 @@ class Loop
|
||||||
$activeJobs += $this->processExecutor->countActiveJobs();
|
$activeJobs += $this->processExecutor->countActiveJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($progress) {
|
if ($progress && microtime(true) - $lastUpdate > 0.1) {
|
||||||
|
$lastUpdate = microtime(true);
|
||||||
$progress->setProgress($progress->getMaxSteps() - $activeJobs);
|
$progress->setProgress($progress->getMaxSteps() - $activeJobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$activeJobs) {
|
if (!$activeJobs) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
usleep(5000);
|
// as we skip progress updates if they are too quick, make sure we do one last one here at 100%
|
||||||
|
if ($progress) {
|
||||||
|
$progress->setProgress($progress->getMaxSteps());
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($this->currentPromises[$waitIndex]);
|
unset($this->currentPromises[$waitIndex]);
|
||||||
|
|
|
@ -98,11 +98,15 @@ class ProcessExecutor
|
||||||
$this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
|
$this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO in 2.2, these two checks can be dropped as Symfony 4+ supports them out of the box
|
||||||
// make sure that null translate to the proper directory in case the dir is a symlink
|
// make sure that null translate to the proper directory in case the dir is a symlink
|
||||||
// and we call a git command, because msysgit does not handle symlinks properly
|
// and we call a git command, because msysgit does not handle symlinks properly
|
||||||
if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
|
if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
|
||||||
$cwd = realpath(getcwd());
|
$cwd = realpath(getcwd());
|
||||||
}
|
}
|
||||||
|
if (null !== $cwd && !is_dir($cwd)) {
|
||||||
|
throw new \RuntimeException('The given CWD for the process does not exist: '.$cwd);
|
||||||
|
}
|
||||||
|
|
||||||
$this->captureOutput = func_num_args() > 3;
|
$this->captureOutput = func_num_args() > 3;
|
||||||
$this->errorOutput = null;
|
$this->errorOutput = null;
|
||||||
|
@ -177,6 +181,8 @@ class ProcessExecutor
|
||||||
// signal can throw in various conditions, but we don't care if it fails
|
// signal can throw in various conditions, but we don't care if it fails
|
||||||
}
|
}
|
||||||
$job['process']->stop(1);
|
$job['process']->stop(1);
|
||||||
|
|
||||||
|
throw new \RuntimeException('Aborted process');
|
||||||
};
|
};
|
||||||
|
|
||||||
$promise = new Promise($resolver, $canceler);
|
$promise = new Promise($resolver, $canceler);
|
||||||
|
@ -233,11 +239,15 @@ class ProcessExecutor
|
||||||
$this->io->writeError('Executing async command ('.($cwd ?: 'CWD').'): '.$safeCommand);
|
$this->io->writeError('Executing async command ('.($cwd ?: 'CWD').'): '.$safeCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO in 2.2, these two checks can be dropped as Symfony 4+ supports them out of the box
|
||||||
// make sure that null translate to the proper directory in case the dir is a symlink
|
// make sure that null translate to the proper directory in case the dir is a symlink
|
||||||
// and we call a git command, because msysgit does not handle symlinks properly
|
// and we call a git command, because msysgit does not handle symlinks properly
|
||||||
if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
|
if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
|
||||||
$cwd = realpath(getcwd());
|
$cwd = realpath(getcwd());
|
||||||
}
|
}
|
||||||
|
if (null !== $cwd && !is_dir($cwd)) {
|
||||||
|
throw new \RuntimeException('The given CWD for the process does not exist: '.$cwd);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO in v3, commands should be passed in as arrays of cmd + args
|
// TODO in v3, commands should be passed in as arrays of cmd + args
|
||||||
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
|
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
|
||||||
|
|
|
@ -85,7 +85,7 @@ class AllFunctionalTest extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$proc = new Process('php '.escapeshellarg('./bin/compile'), $target);
|
$proc = new Process('php -dphar.readonly=0 '.escapeshellarg('./bin/compile'), $target);
|
||||||
$exitcode = $proc->run();
|
$exitcode = $proc->run();
|
||||||
|
|
||||||
if ($exitcode !== 0 || trim($proc->getOutput())) {
|
if ($exitcode !== 0 || trim($proc->getOutput())) {
|
||||||
|
@ -102,26 +102,73 @@ class AllFunctionalTest extends TestCase
|
||||||
public function testIntegration($testFile)
|
public function testIntegration($testFile)
|
||||||
{
|
{
|
||||||
$testData = $this->parseTestFile($testFile);
|
$testData = $this->parseTestFile($testFile);
|
||||||
|
$this->testDir = self::getUniqueTmpDirectory();
|
||||||
|
|
||||||
|
// if a dir is present with the name of the .test file (without .test), we
|
||||||
|
// copy all its contents in the $testDir to be used to run the test with
|
||||||
|
$testFileSetupDir = substr($testFile, 0, -5);
|
||||||
|
if (is_dir($testFileSetupDir)) {
|
||||||
|
$fs = new Filesystem();
|
||||||
|
$fs->copy($testFileSetupDir, $this->testDir);
|
||||||
|
}
|
||||||
|
|
||||||
$this->oldenv = getenv('COMPOSER_HOME');
|
$this->oldenv = getenv('COMPOSER_HOME');
|
||||||
$_SERVER['COMPOSER_HOME'] = $this->testDir.'home';
|
$_SERVER['COMPOSER_HOME'] = $this->testDir.'home';
|
||||||
putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']);
|
putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']);
|
||||||
|
|
||||||
$cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN'];
|
$cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN'];
|
||||||
$proc = new Process($cmd, __DIR__.'/Fixtures/functional', null, null, 300);
|
$proc = new Process($cmd, $this->testDir, null, null, 300);
|
||||||
$exitcode = $proc->run();
|
$output = '';
|
||||||
|
|
||||||
|
$exitcode = $proc->run(function ($type, $buffer) use (&$output) {
|
||||||
|
$output .= $buffer;
|
||||||
|
});
|
||||||
|
|
||||||
if (isset($testData['EXPECT'])) {
|
if (isset($testData['EXPECT'])) {
|
||||||
$this->assertEquals($testData['EXPECT'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput());
|
$output = trim($this->cleanOutput($output));
|
||||||
|
$expected = $testData['EXPECT'];
|
||||||
|
|
||||||
|
$line = 1;
|
||||||
|
for ($i = 0, $j = 0; $i < strlen($expected); ) {
|
||||||
|
if ($expected[$i] === "\n") {
|
||||||
|
$line++;
|
||||||
|
}
|
||||||
|
if ($expected[$i] === '%') {
|
||||||
|
preg_match('{%(.+?)%}', substr($expected, $i), $match);
|
||||||
|
$regex = $match[1];
|
||||||
|
|
||||||
|
if (preg_match('{'.$regex.'}', substr($output, $j), $match)) {
|
||||||
|
$i += strlen($regex) + 2;
|
||||||
|
$j += strlen($match[0]);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$this->fail(
|
||||||
|
'Failed to match pattern '.$regex.' at line '.$line.' / abs offset '.$i.': '
|
||||||
|
.substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL.
|
||||||
|
'Output:'.PHP_EOL.$output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($expected[$i] !== $output[$j]) {
|
||||||
|
$this->fail(
|
||||||
|
'Output does not match expectation at line '.$line.' / abs offset '.$i.': '.PHP_EOL
|
||||||
|
.'-'.substr($expected, $i, min(strpos($expected, "\n", $i)-$i, 100)).PHP_EOL
|
||||||
|
.'+'.substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL
|
||||||
|
.'Output:'.PHP_EOL.$output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
$j++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isset($testData['EXPECT-REGEX'])) {
|
if (isset($testData['EXPECT-REGEX'])) {
|
||||||
$this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput());
|
$this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($output));
|
||||||
}
|
}
|
||||||
if (isset($testData['EXPECT-ERROR'])) {
|
if (isset($testData['EXPECT-REGEXES'])) {
|
||||||
$this->assertEquals($testData['EXPECT-ERROR'], $this->cleanOutput($proc->getErrorOutput()));
|
$cleanOutput = $this->cleanOutput($output);
|
||||||
|
foreach (explode("\n", $testData['EXPECT-REGEXES']) as $regex) {
|
||||||
|
$this->assertRegExp($regex, $cleanOutput, 'Output: '.$output);
|
||||||
}
|
}
|
||||||
if (isset($testData['EXPECT-ERROR-REGEX'])) {
|
|
||||||
$this->assertRegExp($testData['EXPECT-ERROR-REGEX'], $this->cleanOutput($proc->getErrorOutput()));
|
|
||||||
}
|
}
|
||||||
if (isset($testData['EXPECT-EXIT-CODE'])) {
|
if (isset($testData['EXPECT-EXIT-CODE'])) {
|
||||||
$this->assertSame($testData['EXPECT-EXIT-CODE'], $exitcode);
|
$this->assertSame($testData['EXPECT-EXIT-CODE'], $exitcode);
|
||||||
|
@ -132,7 +179,7 @@ class AllFunctionalTest extends TestCase
|
||||||
{
|
{
|
||||||
$tests = array();
|
$tests = array();
|
||||||
foreach (Finder::create()->in(__DIR__.'/Fixtures/functional')->name('*.test')->files() as $file) {
|
foreach (Finder::create()->in(__DIR__.'/Fixtures/functional')->name('*.test')->files() as $file) {
|
||||||
$tests[] = array($file->getRealPath());
|
$tests[basename($file)] = array($file->getRealPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $tests;
|
return $tests;
|
||||||
|
@ -144,23 +191,6 @@ class AllFunctionalTest extends TestCase
|
||||||
$data = array();
|
$data = array();
|
||||||
$section = null;
|
$section = null;
|
||||||
|
|
||||||
$testDir = self::getUniqueTmpDirectory();
|
|
||||||
$this->testDir = $testDir;
|
|
||||||
$varRegex = '#%([a-zA-Z_-]+)%#';
|
|
||||||
$variableReplacer = function ($match) use (&$data, $testDir) {
|
|
||||||
list(, $var) = $match;
|
|
||||||
|
|
||||||
switch ($var) {
|
|
||||||
case 'testDir':
|
|
||||||
$data['test_dir'] = $testDir;
|
|
||||||
|
|
||||||
return $testDir;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new \InvalidArgumentException(sprintf('Unknown variable "%s". Supported variables: "testDir"', $var));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach ($tokens as $token) {
|
foreach ($tokens as $token) {
|
||||||
if ('' === $token && null === $section) {
|
if ('' === $token && null === $section) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -176,24 +206,20 @@ class AllFunctionalTest extends TestCase
|
||||||
|
|
||||||
// Allow sections to validate, or modify their section data.
|
// Allow sections to validate, or modify their section data.
|
||||||
switch ($section) {
|
switch ($section) {
|
||||||
case 'RUN':
|
|
||||||
$sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'EXPECT-EXIT-CODE':
|
case 'EXPECT-EXIT-CODE':
|
||||||
$sectionData = (int) $sectionData;
|
$sectionData = (int) $sectionData;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'RUN':
|
||||||
case 'EXPECT':
|
case 'EXPECT':
|
||||||
case 'EXPECT-REGEX':
|
case 'EXPECT-REGEX':
|
||||||
case 'EXPECT-ERROR':
|
case 'EXPECT-REGEXES':
|
||||||
case 'EXPECT-ERROR-REGEX':
|
$sectionData = trim($sectionData);
|
||||||
$sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \RuntimeException(sprintf(
|
throw new \RuntimeException(sprintf(
|
||||||
'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-ERROR", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-ERROR-REGEX". '
|
'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-REGEXES". '
|
||||||
.'Section headers must be written as "--HEADER_NAME--".',
|
.'Section headers must be written as "--HEADER_NAME--".',
|
||||||
$section
|
$section
|
||||||
));
|
));
|
||||||
|
@ -207,8 +233,8 @@ class AllFunctionalTest extends TestCase
|
||||||
if (!isset($data['RUN'])) {
|
if (!isset($data['RUN'])) {
|
||||||
throw new \RuntimeException('The test file must have a section named "RUN".');
|
throw new \RuntimeException('The test file must have a section named "RUN".');
|
||||||
}
|
}
|
||||||
if (!isset($data['EXPECT']) && !isset($data['EXPECT-ERROR']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-ERROR-REGEX'])) {
|
if (!isset($data['EXPECT']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-REGEXES'])) {
|
||||||
throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-ERROR", "EXPECT-REGEX", or "EXPECT-ERROR-REGEX".');
|
throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-REGEX", or "EXPECT-REGEXES".');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
@ -61,7 +61,7 @@ class ApplicationTest extends TestCase
|
||||||
|
|
||||||
$outputMock->expects($this->at($index++))
|
$outputMock->expects($this->at($index++))
|
||||||
->method("write")
|
->method("write")
|
||||||
->with($this->equalTo('<warning>You are running composer with Xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug</warning>'));
|
->with($this->equalTo('<warning>Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug</warning>'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$outputMock->expects($this->at($index++))
|
$outputMock->expects($this->at($index++))
|
||||||
|
@ -70,7 +70,7 @@ class ApplicationTest extends TestCase
|
||||||
|
|
||||||
$outputMock->expects($this->at($index++))
|
$outputMock->expects($this->at($index++))
|
||||||
->method("write")
|
->method("write")
|
||||||
->with($this->equalTo(sprintf('<warning>Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF'])));
|
->with($this->equalTo(sprintf('<warning>Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF'])));
|
||||||
|
|
||||||
if (!defined('COMPOSER_DEV_WARNING_TIME')) {
|
if (!defined('COMPOSER_DEV_WARNING_TIME')) {
|
||||||
define('COMPOSER_DEV_WARNING_TIME', time() - 1);
|
define('COMPOSER_DEV_WARNING_TIME', time() - 1);
|
||||||
|
|
|
@ -1447,9 +1447,9 @@ EOF;
|
||||||
$package->setAutoload(array(
|
$package->setAutoload(array(
|
||||||
'psr-0' => array('Foo' => '../path/../src'),
|
'psr-0' => array('Foo' => '../path/../src'),
|
||||||
'psr-4' => array('Acme\Foo\\' => '../path/../src-psr4'),
|
'psr-4' => array('Acme\Foo\\' => '../path/../src-psr4'),
|
||||||
'classmap' => array('../classmap'),
|
'classmap' => array('../classmap', '../classmap2/subdir', 'classmap3', 'classmap4'),
|
||||||
'files' => array('../test.php'),
|
'files' => array('../test.php'),
|
||||||
'exclude-from-classmap' => array('./../classmap/excluded'),
|
'exclude-from-classmap' => array('./../classmap/excluded', '../classmap2', 'classmap3/classes.php', 'classmap4/*/classes.php'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->repository->expects($this->once())
|
$this->repository->expects($this->once())
|
||||||
|
@ -1458,9 +1458,15 @@ EOF;
|
||||||
|
|
||||||
$this->fs->ensureDirectoryExists($this->workingDir.'/src/Foo');
|
$this->fs->ensureDirectoryExists($this->workingDir.'/src/Foo');
|
||||||
$this->fs->ensureDirectoryExists($this->workingDir.'/classmap/excluded');
|
$this->fs->ensureDirectoryExists($this->workingDir.'/classmap/excluded');
|
||||||
|
$this->fs->ensureDirectoryExists($this->workingDir.'/classmap2/subdir');
|
||||||
|
$this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap3');
|
||||||
|
$this->fs->ensureDirectoryExists($this->workingDir.'/working-dir/classmap4/foo/');
|
||||||
file_put_contents($this->workingDir.'/src/Foo/Bar.php', '<?php namespace Foo; class Bar {}');
|
file_put_contents($this->workingDir.'/src/Foo/Bar.php', '<?php namespace Foo; class Bar {}');
|
||||||
file_put_contents($this->workingDir.'/classmap/classes.php', '<?php namespace Foo; class Foo {}');
|
file_put_contents($this->workingDir.'/classmap/classes.php', '<?php namespace Foo; class Foo {}');
|
||||||
file_put_contents($this->workingDir.'/classmap/excluded/classes.php', '<?php namespace Foo; class Boo {}');
|
file_put_contents($this->workingDir.'/classmap/excluded/classes.php', '<?php namespace Foo; class Boo {}');
|
||||||
|
file_put_contents($this->workingDir.'/classmap2/subdir/classes.php', '<?php namespace Foo; class Boo2 {}');
|
||||||
|
file_put_contents($this->workingDir.'/working-dir/classmap3/classes.php', '<?php namespace Foo; class Boo3 {}');
|
||||||
|
file_put_contents($this->workingDir.'/working-dir/classmap4/foo/classes.php', '<?php namespace Foo; class Boo4 {}');
|
||||||
file_put_contents($this->workingDir.'/test.php', '<?php class Foo {}');
|
file_put_contents($this->workingDir.'/test.php', '<?php class Foo {}');
|
||||||
|
|
||||||
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_14');
|
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_14');
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoloadOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoloadOrder', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
||||||
|
|
||||||
$includePaths = require __DIR__ . '/include_paths.php';
|
$includePaths = require __DIR__ . '/include_paths.php';
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitFilesAutoload
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitFilesAutoload', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitIncludePath
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitIncludePath', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ComposerAutoloaderInitTargetDir
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInitTargetDir', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ConfigTest extends TestCase
|
||||||
$data = array();
|
$data = array();
|
||||||
$data['local config inherits system defaults'] = array(
|
$data['local config inherits system defaults'] = array(
|
||||||
array(
|
array(
|
||||||
'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true),
|
'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
),
|
),
|
||||||
array(),
|
array(),
|
||||||
);
|
);
|
||||||
|
@ -58,7 +58,7 @@ class ConfigTest extends TestCase
|
||||||
array(
|
array(
|
||||||
1 => array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
1 => array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
||||||
0 => array('type' => 'pear', 'url' => 'http://pear.composer.org'),
|
0 => array('type' => 'pear', 'url' => 'http://pear.composer.org'),
|
||||||
'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true),
|
'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'),
|
||||||
|
@ -69,7 +69,7 @@ class ConfigTest extends TestCase
|
||||||
$data['system config adds above core defaults'] = array(
|
$data['system config adds above core defaults'] = array(
|
||||||
array(
|
array(
|
||||||
'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
|
'example.com' => array('type' => 'composer', 'url' => 'http://example.com'),
|
||||||
'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true),
|
'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
),
|
),
|
||||||
array(),
|
array(),
|
||||||
array(
|
array(
|
||||||
|
@ -104,9 +104,27 @@ class ConfigTest extends TestCase
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$data['local config redefining packagist.org by URL override it if no named keys are used'] = array(
|
||||||
|
array(
|
||||||
|
array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$data['local config redefining packagist.org by URL override it also with named keys'] = array(
|
||||||
|
array(
|
||||||
|
'example' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'example' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
$data['incorrect local config does not cause ErrorException'] = array(
|
$data['incorrect local config does not cause ErrorException'] = array(
|
||||||
array(
|
array(
|
||||||
'packagist.org' => array('type' => 'composer', 'url' => 'https?://repo.packagist.org', 'allow_ssl_downgrade' => true),
|
'packagist.org' => array('type' => 'composer', 'url' => 'https://repo.packagist.org'),
|
||||||
'type' => 'vcs',
|
'type' => 'vcs',
|
||||||
'url' => 'http://example.com',
|
'url' => 'http://example.com',
|
||||||
),
|
),
|
||||||
|
|
|
@ -122,12 +122,7 @@ class GitDownloaderTest extends TestCase
|
||||||
|
|
||||||
$processExecutor->expects($this->at(2))
|
$processExecutor->expects($this->at(2))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
||||||
->will($this->returnValue(0));
|
|
||||||
|
|
||||||
$processExecutor->expects($this->at(3))
|
|
||||||
->method('execute')
|
|
||||||
->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
|
||||||
->will($this->returnValue(0));
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
|
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
|
||||||
|
@ -198,12 +193,7 @@ class GitDownloaderTest extends TestCase
|
||||||
|
|
||||||
$processExecutor->expects($this->at(5))
|
$processExecutor->expects($this->at(5))
|
||||||
->method('execute')
|
->method('execute')
|
||||||
->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
||||||
->will($this->returnValue(0));
|
|
||||||
|
|
||||||
$processExecutor->expects($this->at(6))
|
|
||||||
->method('execute')
|
|
||||||
->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
|
|
||||||
->will($this->returnValue(0));
|
->will($this->returnValue(0));
|
||||||
|
|
||||||
$downloader = $this->getDownloaderMock(null, $config, $processExecutor);
|
$downloader = $this->getDownloaderMock(null, $config, $processExecutor);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
--RUN--
|
--RUN--
|
||||||
create-project seld/jsonlint %testDir% 1.0.0 --prefer-source -n
|
create-project seld/jsonlint foo 1.0.0 --prefer-source -n
|
||||||
--EXPECT-ERROR-REGEX--
|
--EXPECT-REGEX--
|
||||||
{Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?}
|
{- Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
--RUN--
|
--RUN--
|
||||||
create-project --repository=packages.json -v seld/jsonlint %testDir% dev-master
|
create-project --repository=packages.json -v seld/jsonlint foo dev-main
|
||||||
--EXPECT-ERROR-REGEX--
|
--EXPECT-REGEX--
|
||||||
{^Installing seld/jsonlint \(dev-master [a-f0-9]{40}\)}m
|
{^Installing seld/jsonlint \(dev-main [a-f0-9]{40}\)}m
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
"validator"
|
"validator"
|
||||||
],
|
],
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
"version": "dev-master",
|
"version": "dev-main",
|
||||||
"version_normalized": "9999999-dev",
|
"version_normalized": "dev-main",
|
||||||
|
"default-branch": true,
|
||||||
"license": [
|
"license": [
|
||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
|
@ -0,0 +1,50 @@
|
||||||
|
--TEST--
|
||||||
|
Verify that a conflict with all dependencies option enabled don't recommend to use the option
|
||||||
|
--COMPOSER--
|
||||||
|
{
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": [
|
||||||
|
{ "name": "locked/pkg", "version": "dev-master", "require": {"locked/dependency": "1.0.0"}, "default-branch": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"locked/pkg": "*@dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--LOCK--
|
||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{ "name": "locked/pkg", "version": "dev-master", "require": {"locked/dependency": "1.0.0"}, "default-branch": true },
|
||||||
|
{ "name": "locked/dependency", "version": "1.0.0" }
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": []
|
||||||
|
}
|
||||||
|
|
||||||
|
--RUN--
|
||||||
|
update locked/dependency --with-all-dependencies
|
||||||
|
|
||||||
|
--EXPECT-EXIT-CODE--
|
||||||
|
2
|
||||||
|
|
||||||
|
--EXPECT-OUTPUT--
|
||||||
|
Loading composer repositories with package information
|
||||||
|
Updating dependencies
|
||||||
|
Your requirements could not be resolved to an installable set of packages.
|
||||||
|
|
||||||
|
Problem 1
|
||||||
|
- locked/pkg dev-master requires locked/dependency 1.0.0 -> found locked/dependency[1.0.0] in lock file but not in remote repositories, make sure you avoid updating this package to keep the one from lock file.
|
||||||
|
- locked/pkg is locked to version dev-master and an update of this package was not requested.
|
||||||
|
|
||||||
|
--EXPECT--
|
||||||
|
|
|
@ -17,6 +17,20 @@ use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
class InstalledVersionsTest extends TestCase
|
class InstalledVersionsTest extends TestCase
|
||||||
{
|
{
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
// disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no
|
||||||
|
// class loaders are registered
|
||||||
|
$prop = new \ReflectionProperty('Composer\Autoload\ClassLoader', 'registeredLoaders');
|
||||||
|
$prop->setAccessible(true);
|
||||||
|
$prop->setValue(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass()
|
||||||
|
{
|
||||||
|
self::setUpBeforeClass();
|
||||||
|
}
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php');
|
InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php');
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,20 +18,44 @@ use Composer\Package\Archiver\ZipArchiver;
|
||||||
|
|
||||||
class ZipArchiverTest extends ArchiverTest
|
class ZipArchiverTest extends ArchiverTest
|
||||||
{
|
{
|
||||||
public function testZipArchive()
|
/**
|
||||||
|
* @param string $include
|
||||||
|
*
|
||||||
|
* @dataProvider provideGitignoreExcludeNegationTestCases
|
||||||
|
*/
|
||||||
|
public function testGitignoreExcludeNegation($include)
|
||||||
|
{
|
||||||
|
$this->testZipArchive(array(
|
||||||
|
'docs/README.md' => '# The doc',
|
||||||
|
'.gitignore' => "/*\n.*\n!.git*\n$include",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideGitignoreExcludeNegationTestCases()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('!/docs'),
|
||||||
|
array('!/docs/'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testZipArchive(array $files = array())
|
||||||
{
|
{
|
||||||
if (!class_exists('ZipArchive')) {
|
if (!class_exists('ZipArchive')) {
|
||||||
$this->markTestSkipped('Cannot run ZipArchiverTest, missing class "ZipArchive".');
|
$this->markTestSkipped('Cannot run ZipArchiverTest, missing class "ZipArchive".');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty($files)) {
|
||||||
$files = array(
|
$files = array(
|
||||||
'file.txt',
|
'file.txt' => NULL,
|
||||||
'foo/bar/baz',
|
'foo/bar/baz' => NULL,
|
||||||
'x/baz',
|
'x/baz' => NULL,
|
||||||
'x/includeme',
|
'x/includeme' => NULL,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!Platform::isWindows()) {
|
if (!Platform::isWindows()) {
|
||||||
$files[] = 'foo' . getcwd() . '/file.txt';
|
$files['foo' . getcwd() . '/file.txt'] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Set up repository
|
// Set up repository
|
||||||
$this->setupDummyRepo($files);
|
$this->setupDummyRepo($files);
|
||||||
|
@ -41,12 +65,12 @@ class ZipArchiverTest extends ArchiverTest
|
||||||
// Test archive
|
// Test archive
|
||||||
$archiver = new ZipArchiver();
|
$archiver = new ZipArchiver();
|
||||||
$archiver->archive($package->getSourceUrl(), $target, 'zip');
|
$archiver->archive($package->getSourceUrl(), $target, 'zip');
|
||||||
$this->assertFileExists($target);
|
static::assertFileExists($target);
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
$res = $zip->open($target);
|
$res = $zip->open($target);
|
||||||
self::assertTrue($res, 'Failed asserting that Zip file can be opened');
|
static::assertTrue($res, 'Failed asserting that Zip file can be opened');
|
||||||
foreach ($files as $file) {
|
foreach ($files as $path => $content) {
|
||||||
$this->assertSame('content', $zip->getFromName($file), 'Failed asserting that Zip contains ' . $file);
|
static::assertSame($content, $zip->getFromName($path), 'Failed asserting that Zip contains ' . $path);
|
||||||
}
|
}
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
|
@ -57,12 +81,15 @@ class ZipArchiverTest extends ArchiverTest
|
||||||
* Create a local dummy repository to run tests against!
|
* Create a local dummy repository to run tests against!
|
||||||
* @param array $files
|
* @param array $files
|
||||||
*/
|
*/
|
||||||
protected function setupDummyRepo($files)
|
protected function setupDummyRepo(array &$files)
|
||||||
{
|
{
|
||||||
$currentWorkDir = getcwd();
|
$currentWorkDir = getcwd();
|
||||||
chdir($this->testDir);
|
chdir($this->testDir);
|
||||||
foreach ($files as $file) {
|
foreach ($files as $path => $content) {
|
||||||
$this->writeFile($file, 'content', $currentWorkDir);
|
if ($files[$path] === NULL) {
|
||||||
|
$files[$path] = 'content';
|
||||||
|
}
|
||||||
|
$this->writeFile($path, $files[$path], $currentWorkDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
chdir($currentWorkDir);
|
chdir($currentWorkDir);
|
||||||
|
|
|
@ -202,28 +202,4 @@ class RootPackageLoaderTest extends TestCase
|
||||||
|
|
||||||
$this->assertEquals("dev-latest-production", $package->getPrettyVersion());
|
$this->assertEquals("dev-latest-production", $package->getPrettyVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideExtraBranchVersion
|
|
||||||
*/
|
|
||||||
public function testLoadExtraBranchVersion($branchVersion)
|
|
||||||
{
|
|
||||||
$package = $this->loadPackage(array(
|
|
||||||
'extra' => array(
|
|
||||||
'branch-version' => $branchVersion,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->assertEquals('1.2.x-dev', $package->getPrettyVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideExtraBranchVersion()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
array('1.2'),
|
|
||||||
array('1.2.x'),
|
|
||||||
array('1.2-dev'),
|
|
||||||
array('1.2.x-dev'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use Composer\Installer\PluginInstaller;
|
||||||
use Composer\Package\CompletePackage;
|
use Composer\Package\CompletePackage;
|
||||||
use Composer\Package\Loader\JsonLoader;
|
use Composer\Package\Loader\JsonLoader;
|
||||||
use Composer\Package\Loader\ArrayLoader;
|
use Composer\Package\Loader\ArrayLoader;
|
||||||
|
use Composer\Package\RootPackage;
|
||||||
use Composer\Plugin\PluginManager;
|
use Composer\Plugin\PluginManager;
|
||||||
use Composer\IO\BufferIO;
|
use Composer\IO\BufferIO;
|
||||||
use Composer\EventDispatcher\EventDispatcher;
|
use Composer\EventDispatcher\EventDispatcher;
|
||||||
|
@ -111,6 +112,7 @@ class PluginInstallerTest extends TestCase
|
||||||
$this->composer->setInstallationManager($im);
|
$this->composer->setInstallationManager($im);
|
||||||
$this->composer->setAutoloadGenerator($this->autoloadGenerator);
|
$this->composer->setAutoloadGenerator($this->autoloadGenerator);
|
||||||
$this->composer->setEventDispatcher(new EventDispatcher($this->composer, $this->io));
|
$this->composer->setEventDispatcher(new EventDispatcher($this->composer, $this->io));
|
||||||
|
$this->composer->setPackage(new RootPackage('dummy/root', '1.0.0.0', '1.0.0'));
|
||||||
|
|
||||||
$this->pm = new PluginManager($this->io, $this->composer);
|
$this->pm = new PluginManager($this->io, $this->composer);
|
||||||
$this->composer->setPluginManager($this->pm);
|
$this->composer->setPluginManager($this->pm);
|
||||||
|
|
|
@ -55,7 +55,7 @@ class ComposerRepositoryTest extends TestCase
|
||||||
$repository
|
$repository
|
||||||
->expects($this->at(2))
|
->expects($this->at(2))
|
||||||
->method('createPackages')
|
->method('createPackages')
|
||||||
->with($this->identicalTo($expected), $this->equalTo('Composer\Package\CompletePackage'))
|
->with($this->identicalTo($expected), $this->equalTo('root file (http://example.org/packages.json)'))
|
||||||
->will($this->returnValue($stubs));
|
->will($this->returnValue($stubs));
|
||||||
|
|
||||||
// Triggers initialization
|
// Triggers initialization
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"name": "test/path-branch-versioned",
|
|
||||||
"extra": {
|
|
||||||
"branch-version": "1.2"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -67,23 +67,6 @@ class PathRepositoryTest extends TestCase
|
||||||
$this->assertNotEmpty($packageVersion);
|
$this->assertNotEmpty($packageVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLoadPackageFromFileSystemWithExtraBranchVersion()
|
|
||||||
{
|
|
||||||
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$config = new \Composer\Config();
|
|
||||||
$versionGuesser = null;
|
|
||||||
|
|
||||||
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'with-branch-version'));
|
|
||||||
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
|
|
||||||
$packages = $repository->getPackages();
|
|
||||||
|
|
||||||
$this->assertEquals(1, $repository->count());
|
|
||||||
|
|
||||||
$this->assertTrue($repository->hasPackage($this->getPackage('test/path-branch-versioned', '1.2.x-dev')));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testLoadPackageFromFileSystemWithWildcard()
|
public function testLoadPackageFromFileSystemWithWildcard()
|
||||||
{
|
{
|
||||||
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
|
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
|
||||||
|
@ -95,16 +78,50 @@ class PathRepositoryTest extends TestCase
|
||||||
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
|
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
|
||||||
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
|
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
|
||||||
$packages = $repository->getPackages();
|
$packages = $repository->getPackages();
|
||||||
$result = array();
|
$names = array();
|
||||||
|
|
||||||
$this->assertGreaterThanOrEqual(3, $repository->count());
|
$this->assertEquals(2, $repository->count());
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
$package = $packages[0];
|
||||||
$result[$package->getName()] = $package->getPrettyVersion();
|
$names[] = $package->getName();
|
||||||
|
|
||||||
|
$package = $packages[1];
|
||||||
|
$names[] = $package->getName();
|
||||||
|
|
||||||
|
sort($names);
|
||||||
|
$this->assertEquals(array('test/path-unversioned', 'test/path-versioned'), $names);
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($result);
|
public function testLoadPackageWithExplicitVersions()
|
||||||
$this->assertSame(array('test/path-branch-versioned' => '1.2.x-dev', 'test/path-unversioned' => $result['test/path-unversioned'], 'test/path-versioned' => '0.0.2'), $result);
|
{
|
||||||
|
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$config = new \Composer\Config();
|
||||||
|
$versionGuesser = null;
|
||||||
|
|
||||||
|
$options = array(
|
||||||
|
'versions' => array(
|
||||||
|
'test/path-unversioned' => '4.3.2.1',
|
||||||
|
'test/path-versioned' => '3.2.1.0',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*'));
|
||||||
|
$repository = new PathRepository(array('url' => $repositoryUrl, 'options' => $options), $ioInterface, $config);
|
||||||
|
$packages = $repository->getPackages();
|
||||||
|
|
||||||
|
$versions = array();
|
||||||
|
|
||||||
|
$this->assertEquals(2, $repository->count());
|
||||||
|
|
||||||
|
$package = $packages[0];
|
||||||
|
$versions[$package->getName()] = $package->getVersion();
|
||||||
|
|
||||||
|
$package = $packages[1];
|
||||||
|
$versions[$package->getName()] = $package->getVersion();
|
||||||
|
|
||||||
|
ksort($versions);
|
||||||
|
$this->assertSame(array('test/path-unversioned' => '4.3.2.1', 'test/path-versioned' => '3.2.1.0'), $versions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue