1
0
Fork 0

Merge branch 'master' into 2.0

pull/7936/head
Jordi Boggiano 2019-10-30 08:54:44 +01:00
commit bc2a1d762a
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
56 changed files with 416 additions and 122 deletions

View File

@ -1,3 +1,16 @@
### [1.9.0] 2019-08-02
* Breaking: artifact repositories with URLs containing port numbers and requiring authentication now require you to configure http-basic auth for the `host:port` pair explicitly
* Added a `--no-cache` flag available on all commands to run with the cache disabled
* Added PHP_BINARY as env var pointing to the PHP process when executing Composer scripts as shell scripts
* Added a `use-github-api` config option which can set the `no-api` flag on all GitHub VCS repositories declared
* Added a static helper you can preprend to a script to avoid process timeouts, `"Composer\\Config::disableProcessTimeout"`
* Added Event::getOriginatingEvent to retrieve an event's original event when a script handler forwards to another one
* Added support for autoloading directly from a phar file
* Fixed loading order of plugins to always initialize them in order of dependencies
* Fixed various network-mount related issues
* Fixed --ignore-platform-reqs not ignoring conflict rules against platform packages
### [1.8.6] 2019-06-11 ### [1.8.6] 2019-06-11
* Fixed handling of backslash-escapes handling in composer.json when using the require command * Fixed handling of backslash-escapes handling in composer.json when using the require command
@ -751,6 +764,7 @@
* Initial release * Initial release
[1.9.0]: https://github.com/composer/composer/compare/1.8.6...1.9.0
[1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6 [1.8.6]: https://github.com/composer/composer/compare/1.8.5...1.8.6
[1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5 [1.8.5]: https://github.com/composer/composer/compare/1.8.4...1.8.5
[1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4 [1.8.4]: https://github.com/composer/composer/compare/1.8.3...1.8.4

72
composer.lock generated
View File

@ -8,25 +8,25 @@
"packages": [ "packages": [
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
"version": "1.1.4", "version": "1.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/ca-bundle.git", "url": "https://github.com/composer/ca-bundle.git",
"reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d" "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/558f321c52faeb4828c03e7dc0cfe39a09e09a2d", "url": "https://api.github.com/repos/composer/ca-bundle/zipball/10bb96592168a0f8e8f6dcde3532d9fa50b0b527",
"reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d", "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-openssl": "*", "ext-openssl": "*",
"ext-pcre": "*", "ext-pcre": "*",
"php": "^5.3.2 || ^7.0" "php": "^5.3.2 || ^7.0 || ^8.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
"psr/log": "^1.0", "psr/log": "^1.0",
"symfony/process": "^2.5 || ^3.0 || ^4.0" "symfony/process": "^2.5 || ^3.0 || ^4.0"
}, },
@ -60,7 +60,7 @@
"ssl", "ssl",
"tls" "tls"
], ],
"time": "2019-01-28T09:30:10+00:00" "time": "2019-08-30T08:44:50+00:00"
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
@ -126,16 +126,16 @@
}, },
{ {
"name": "composer/spdx-licenses", "name": "composer/spdx-licenses",
"version": "1.5.1", "version": "1.5.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/spdx-licenses.git", "url": "https://github.com/composer/spdx-licenses.git",
"reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d" "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d", "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5",
"reference": "a1aa51cf3ab838b83b0867b14e56fc20fbd55b3d", "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -182,7 +182,7 @@
"spdx", "spdx",
"validator" "validator"
], ],
"time": "2019-03-26T10:23:26+00:00" "time": "2019-07-29T10:31:59+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
@ -697,16 +697,16 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.11.0", "version": "v1.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "82ebae02209c21113908c229e9883c419720738a" "reference": "550ebaac289296ce228a706d0867afc34687e3f4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
"reference": "82ebae02209c21113908c229e9883c419720738a", "reference": "550ebaac289296ce228a706d0867afc34687e3f4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -718,7 +718,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.11-dev" "dev-master": "1.12-dev"
} }
}, },
"autoload": { "autoload": {
@ -734,13 +734,13 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{ {
"name": "Gert de Pagter", "name": "Gert de Pagter",
"email": "BackEndTea@gmail.com" "email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
} }
], ],
"description": "Symfony polyfill for ctype functions", "description": "Symfony polyfill for ctype functions",
@ -751,20 +751,20 @@
"polyfill", "polyfill",
"portable" "portable"
], ],
"time": "2019-02-06T07:57:58+00:00" "time": "2019-08-06T08:03:45+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.11.0", "version": "v1.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609" "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609", "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -776,7 +776,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.11-dev" "dev-master": "1.12-dev"
} }
}, },
"autoload": { "autoload": {
@ -810,7 +810,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2019-02-06T07:57:58+00:00" "time": "2019-08-06T08:03:45+00:00"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
@ -968,22 +968,22 @@
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "1.8.0", "version": "1.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpspec/prophecy.git", "url": "https://github.com/phpspec/prophecy.git",
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.0.2", "doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0", "php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
"sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0" "sebastian/recursion-context": "^1.0|^2.0|^3.0"
}, },
@ -998,8 +998,8 @@
} }
}, },
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Prophecy\\": "src/" "Prophecy\\": "src/Prophecy"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -1027,7 +1027,7 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2018-08-05T17:53:17+00:00" "time": "2019-10-03T11:07:50+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",

View File

@ -106,7 +106,8 @@ Linux distributions.
> `mkdir -p /usr/local/bin`. > `mkdir -p /usr/local/bin`.
> **Note:** For information on changing your PATH, please read the > **Note:** For information on changing your PATH, please read the
> [Wikipedia article](https://en.wikipedia.org/wiki/PATH_(variable)) and/or use Google. > [Wikipedia article](https://en.wikipedia.org/wiki/PATH_(variable)) and/or use
> your search engine of choice.
Now run `composer` in order to run Composer instead of `php composer.phar`. Now run `composer` in order to run Composer instead of `php composer.phar`.
@ -139,7 +140,7 @@ C:\bin>echo @php "%~dp0composer.phar" %*>composer.bat
Add the directory to your PATH environment variable if it isn't already. Add the directory to your PATH environment variable if it isn't already.
For information on changing your PATH variable, please see For information on changing your PATH variable, please see
[this article](https://www.computerhope.com/issues/ch000549.htm) and/or [this article](https://www.computerhope.com/issues/ch000549.htm) and/or
use Google. use your search engine of choice.
Close your current terminal. Test usage with a new terminal: Close your current terminal. Test usage with a new terminal:

View File

@ -296,4 +296,9 @@ Example:
Defaults to `true`. If set to `false`, Composer will not create `.htaccess` files Defaults to `true`. If set to `false`, Composer will not create `.htaccess` files
in the composer home, cache, and data directories. in the composer home, cache, and data directories.
## lock
Defaults to `true`. If set to `false`, Composer will not create a `composer.lock`
file.
← [Repositories](05-repositories.md) | [Community](07-community.md) → ← [Repositories](05-repositories.md) | [Community](07-community.md) →

View File

@ -339,6 +339,9 @@ One limitation of this is that you can not call multiple commands in
a row like `@php install && @php foo`. You must split them up in a a row like `@php install && @php foo`. You must split them up in a
JSON array of commands. JSON array of commands.
You can also call a shell/bash script, which will have the path to
the PHP executable available in it as a `PHP_BINARY` env var.
## Custom descriptions. ## Custom descriptions.
You can set custom script descriptions with the following in your `composer.json`: You can set custom script descriptions with the following in your `composer.json`:

View File

@ -211,6 +211,19 @@ To enable the swap you can use for example:
``` ```
You can make a permanent swap file following this [tutorial](https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04). You can make a permanent swap file following this [tutorial](https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04).
## proc_open(): failed to open stream errors (Windows)
If composer shows proc_open(NUL) errors on Windows:
`proc_open(NUL): failed to open stream: No such file or directory`
This could be happening because you are working in a _OneDrive_ directory and
using a version of PHP that does not support the file system semantics of this
service. The issue was fixed in PHP 7.2.23 and 7.3.10.
Alternatively it could be because the Windows Null Service is not enabled. For
more information, see this [issue](https://github.com/composer/composer/issues/7186#issuecomment-373134916).
## Degraded Mode ## Degraded Mode
Due to some intermittent issues on Travis and other systems, we introduced a Due to some intermittent issues on Travis and other systems, we introduced a

View File

@ -11,7 +11,8 @@
}, },
"type": { "type": {
"description": "Package type, either 'library' for common packages, 'composer-plugin' for plugins, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.", "description": "Package type, either 'library' for common packages, 'composer-plugin' for plugins, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.",
"type": "string" "type": "string",
"pattern": "^[a-z0-9-]+$"
}, },
"target-dir": { "target-dir": {
"description": "DEPRECATED: Forces the package to be installed into the given subdirectory path. This is used for autoloading PSR-0 packages that do not contain their full path. Use forward slashes for cross-platform compatibility.", "description": "DEPRECATED: Forces the package to be installed into the given subdirectory path. This is used for autoloading PSR-0 packages that do not contain their full path. Use forward slashes for cross-platform compatibility.",
@ -39,7 +40,8 @@
}, },
"version": { "version": {
"type": "string", "type": "string",
"description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes." "description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes.",
"pattern": "^v?\\d+(((\\.\\d+)?\\.\\d+)?\\.\\d+)?"
}, },
"time": { "time": {
"type": "string", "type": "string",
@ -290,6 +292,10 @@
"sort-packages": { "sort-packages": {
"type": "boolean", "type": "boolean",
"description": "Defaults to false. If set to true, Composer will sort packages when adding/updating a new dependency." "description": "Defaults to false. If set to true, Composer will sort packages when adding/updating a new dependency."
},
"lock": {
"type": "boolean",
"description": "Defaults to true. If set to false, Composer will not create a composer.lock file."
} }
} }
}, },

View File

@ -592,6 +592,9 @@ class ComposerAutoloaderInit$suffix
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::\$loader) { if (null !== self::\$loader) {

View File

@ -173,7 +173,7 @@ class ClassMapGenerator
} }
} }
// strip non-php blocks in the file // strip non-php blocks in the file
$contents = preg_replace('{\?>.+<\?}s', '?><?', $contents); $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
// strip trailing non-php code if needed // strip trailing non-php code if needed
$pos = strrpos($contents, '?>'); $pos = strrpos($contents, '?>');
if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) { if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {

View File

@ -42,5 +42,7 @@ EOT
See https://getcomposer.org/ for more information.</comment> See https://getcomposer.org/ for more information.</comment>
EOT EOT
); );
return 0;
} }
} }

View File

@ -62,7 +62,7 @@ class BaseDependencyCommand extends BaseCommand
* @param InputInterface $input * @param InputInterface $input
* @param OutputInterface $output * @param OutputInterface $output
* @param bool $inverted Whether to invert matching process (why-not vs why behaviour) * @param bool $inverted Whether to invert matching process (why-not vs why behaviour)
* @return int|null Exit code of the operation. * @return int Exit code of the operation.
*/ */
protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false) protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false)
{ {

View File

@ -70,5 +70,7 @@ EOT
} }
$io->writeError('<info>All caches cleared.</info>'); $io->writeError('<info>All caches cleared.</info>');
return 0;
} }
} }

View File

@ -412,6 +412,7 @@ EOT
), ),
'github-expose-hostname' => array($booleanValidator, $booleanNormalizer), 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer),
'htaccess-protect' => array($booleanValidator, $booleanNormalizer), 'htaccess-protect' => array($booleanValidator, $booleanNormalizer),
'lock' => array($booleanValidator, $booleanNormalizer),
); );
$multiConfigValues = array( $multiConfigValues = array(
'github-protocols' => array( 'github-protocols' => array(
@ -463,13 +464,19 @@ EOT
$this->getIO()->writeError('<info>You are now running Composer with SSL/TLS protection enabled.</info>'); $this->getIO()->writeError('<info>You are now running Composer with SSL/TLS protection enabled.</info>');
} }
return $this->configSource->removeConfigSetting($settingKey); $this->configSource->removeConfigSetting($settingKey);
return 0;
} }
if (isset($uniqueConfigValues[$settingKey])) { if (isset($uniqueConfigValues[$settingKey])) {
return $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting'); $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting');
return 0;
} }
if (isset($multiConfigValues[$settingKey])) { if (isset($multiConfigValues[$settingKey])) {
return $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting'); $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting');
return 0;
} }
// handle properties // handle properties
@ -530,38 +537,51 @@ EOT
throw new \InvalidArgumentException('The '.$settingKey.' property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json'); throw new \InvalidArgumentException('The '.$settingKey.' property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json');
} }
if ($input->getOption('unset') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]))) { if ($input->getOption('unset') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]))) {
return $this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
return 0;
} }
if (isset($uniqueProps[$settingKey])) { if (isset($uniqueProps[$settingKey])) {
return $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty'); $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty');
return 0;
} }
if (isset($multiProps[$settingKey])) { if (isset($multiProps[$settingKey])) {
return $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty'); $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty');
return 0;
} }
// handle repositories // handle repositories
if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
return $this->configSource->removeRepository($matches[1]); $this->configSource->removeRepository($matches[1]);
return 0;
} }
if (2 === count($values)) { if (2 === count($values)) {
return $this->configSource->addRepository($matches[1], array( $this->configSource->addRepository($matches[1], array(
'type' => $values[0], 'type' => $values[0],
'url' => $values[1], 'url' => $values[1],
)); ));
return 0;
} }
if (1 === count($values)) { if (1 === count($values)) {
$value = strtolower($values[0]); $value = strtolower($values[0]);
if (true === $booleanValidator($value)) { if (true === $booleanValidator($value)) {
if (false === $booleanNormalizer($value)) { if (false === $booleanNormalizer($value)) {
return $this->configSource->addRepository($matches[1], false); $this->configSource->addRepository($matches[1], false);
return 0;
} }
} else { } else {
$value = JsonFile::parseJson($values[0]); $value = JsonFile::parseJson($values[0]);
$this->configSource->addRepository($matches[1], $value);
return $this->configSource->addRepository($matches[1], $value); return 0;
} }
} }
@ -571,22 +591,32 @@ EOT
// handle extra // handle extra
if (preg_match('/^extra\.(.+)/', $settingKey, $matches)) { if (preg_match('/^extra\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
return $this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
return 0;
} }
return $this->configSource->addProperty($settingKey, $values[0]); $this->configSource->addProperty($settingKey, $values[0]);
return 0;
} }
// handle platform // handle platform
if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) { if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
return $this->configSource->removeConfigSetting($settingKey); $this->configSource->removeConfigSetting($settingKey);
return 0;
} }
return $this->configSource->addConfigSetting($settingKey, $values[0]); $this->configSource->addConfigSetting($settingKey, $values[0]);
return 0;
} }
if ($settingKey === 'platform' && $input->getOption('unset')) { if ($settingKey === 'platform' && $input->getOption('unset')) {
return $this->configSource->removeConfigSetting($settingKey); $this->configSource->removeConfigSetting($settingKey);
return 0;
} }
// handle auth // handle auth
@ -595,7 +625,7 @@ EOT
$this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]); $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
return; return 0;
} }
if ($matches[1] === 'bitbucket-oauth') { if ($matches[1] === 'bitbucket-oauth') {
@ -618,16 +648,20 @@ EOT
$this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1])); $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1]));
} }
return; return 0;
} }
// handle script // handle script
if (preg_match('/^scripts\.(.+)/', $settingKey, $matches)) { if (preg_match('/^scripts\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
return $this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
return 0;
} }
return $this->configSource->addProperty($settingKey, count($values) > 1 ? $values : $values[0]); $this->configSource->addProperty($settingKey, count($values) > 1 ? $values : $values[0]);
return 0;
} }
throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command'); throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command');

View File

@ -48,7 +48,7 @@ EOT
* *
* @param InputInterface $input * @param InputInterface $input
* @param OutputInterface $output * @param OutputInterface $output
* @return int|null * @return int
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {

View File

@ -84,5 +84,7 @@ EOT
} else { } else {
$this->getIO()->overwriteError('<info>Generated autoload files containing '. $numberOfClasses .' classes</info>'); $this->getIO()->overwriteError('<info>Generated autoload files containing '. $numberOfClasses .' classes</info>');
} }
return 0;
} }
} }

View File

@ -152,6 +152,8 @@ EOT
if ($input->isInteractive() && $this->hasDependencies($options) && $io->askConfirmation($question, true)) { if ($input->isInteractive() && $this->hasDependencies($options) && $io->askConfirmation($question, true)) {
$this->installDependencies($output); $this->installDependencies($output);
} }
return 0;
} }
/** /**
@ -400,7 +402,7 @@ EOT
return $this->repos; return $this->repos;
} }
protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), $phpVersion = null, $preferredStability = 'stable', $checkProvidedVersions = true) final protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), $phpVersion = null, $preferredStability = 'stable', $checkProvidedVersions = true, $fixed = false)
{ {
if ($requires) { if ($requires) {
$requires = $this->normalizeRequirements($requires); $requires = $this->normalizeRequirements($requires);
@ -410,7 +412,7 @@ EOT
foreach ($requires as $requirement) { foreach ($requires as $requirement) {
if (!isset($requirement['version'])) { if (!isset($requirement['version'])) {
// determine the best version automatically // determine the best version automatically
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability); list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, null, null, $fixed);
$requirement['version'] = $version; $requirement['version'] = $version;
// replace package name from packagist.org // replace package name from packagist.org
@ -423,7 +425,7 @@ EOT
)); ));
} else { } else {
// check that the specified version/constraint exists before we proceed // check that the specified version/constraint exists before we proceed
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev'); list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $phpVersion, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed);
// replace package name from packagist.org // replace package name from packagist.org
$requirement['name'] = $name; $requirement['name'] = $name;
@ -700,10 +702,11 @@ EOT
* @param string $preferredStability * @param string $preferredStability
* @param string|null $requiredVersion * @param string|null $requiredVersion
* @param string $minimumStability * @param string $minimumStability
* @param bool $fixed
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @return array name version * @return array name version
*/ */
private function findBestVersionAndNameForPackage(InputInterface $input, $name, $phpVersion, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null) private function findBestVersionAndNameForPackage(InputInterface $input, $name, $phpVersion, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null, $fixed = null)
{ {
// find the latest version allowed in this repo set // find the latest version allowed in this repo set
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability)); $versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability));
@ -777,7 +780,7 @@ EOT
return array( return array(
$package->getPrettyName(), $package->getPrettyName(),
$versionSelector->findRecommendedRequireVersion($package), $fixed ? $package->getPrettyVersion() : $versionSelector->findRecommendedRequireVersion($package),
); );
} }

View File

@ -110,6 +110,8 @@ EOT
default: default:
throw new \RuntimeException(sprintf('Unsupported format "%s". See help for supported formats.', $format)); throw new \RuntimeException(sprintf('Unsupported format "%s". See help for supported formats.', $format));
} }
return 0;
} }
/** /**

View File

@ -59,7 +59,7 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$args = array( $args = array(
'show', 'command' => 'show',
'--latest' => true, '--latest' => true,
); );
if (!$input->getOption('all')) { if (!$input->getOption('all')) {

View File

@ -48,7 +48,7 @@ EOT
* *
* @param InputInterface $input * @param InputInterface $input
* @param OutputInterface $output * @param OutputInterface $output
* @return int|null * @return int
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {

View File

@ -49,6 +49,7 @@ class RequireCommand extends InitCommand
new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'), new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'), new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
new InputOption('fixed', null, InputOption::VALUE_NONE, 'Write fixed version to the composer.json.'),
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'Do not show package suggestions.'), new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'Do not show package suggestions.'),
new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'), new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
@ -99,7 +100,9 @@ EOT
return 1; return 1;
} }
if (!is_readable($this->file)) { // check for readability by reading the file as is_readable can not be trusted on network-mounts
// see https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
if (!is_readable($this->file) && false === Silencer::call('file_get_contents', $this->file)) {
$io->writeError('<error>'.$this->file.' is not readable.</error>'); $io->writeError('<error>'.$this->file.' is not readable.</error>');
return 1; return 1;
@ -120,6 +123,25 @@ EOT
return 1; return 1;
} }
if ($input->getOption('fixed') === true) {
$config = $this->json->read();
$packageType = empty($config['type']) ? 'library' : $config['type'];
/**
* @see https://github.com/composer/composer/pull/8313#issuecomment-532637955
*/
if ($packageType !== 'project') {
$io->writeError('<error>"--fixed" option is allowed for "project" package types only to prevent possible misuses.</error>');
if (empty($config['type'])) {
$io->writeError('<error>If your package is not library, you should explicitly specify "type" parameter in composer.json.</error>');
}
return 1;
}
}
$composer = $this->getComposer(true, $input->getOption('no-plugins')); $composer = $this->getComposer(true, $input->getOption('no-plugins'));
$repos = $composer->getRepositoryManager()->getRepositories(); $repos = $composer->getRepositoryManager()->getRepositories();
@ -137,7 +159,7 @@ EOT
} }
$phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion(); $phpVersion = $this->repos->findPackage('php', '*')->getPrettyVersion();
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update')); $requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $phpVersion, $preferredStability, !$input->getOption('no-update'), $input->getOption('fixed'));
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require'; $requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev'; $removeKey = $input->getOption('dev') ? 'require' : 'require-dev';

View File

@ -79,5 +79,7 @@ EOT
foreach ($results as $result) { foreach ($results as $result) {
$io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
} }
return 0;
} }
} }

View File

@ -254,6 +254,8 @@ TAGSPUBKEY
} else { } else {
$io->writeError('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>'); $io->writeError('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>');
} }
return 0;
} }
protected function fetchKeys(IOInterface $io, Config $config) protected function fetchKeys(IOInterface $io, Config $config)

View File

@ -129,6 +129,12 @@ EOT
return 1; return 1;
} }
if ($input->getOption('tree') && $input->getOption('path')) {
$io->writeError('The --tree (-t) option is not usable in combination with --path (-P)');
return 1;
}
$format = $input->getOption('format'); $format = $input->getOption('format');
if (!in_array($format, array('text', 'json'))) { if (!in_array($format, array('text', 'json'))) {
$io->writeError(sprintf('Unsupported format "%s". See help for supported formats.', $format)); $io->writeError(sprintf('Unsupported format "%s". See help for supported formats.', $format));
@ -586,6 +592,7 @@ EOT
} }
$io->write('<info>type</info> : ' . $package->getType()); $io->write('<info>type</info> : ' . $package->getType());
$this->printLicenses($package); $this->printLicenses($package);
$io->write('<info>homepage</info> : ' . $package->getHomepage());
$io->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference())); $io->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
$io->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference())); $io->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
if ($installedRepo->hasPackage($package)) { if ($installedRepo->hasPackage($package)) {

View File

@ -61,7 +61,7 @@ EOT
/** /**
* @param InputInterface $input * @param InputInterface $input
* @param OutputInterface $output * @param OutputInterface $output
* @return int|null * @return int
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {

View File

@ -93,7 +93,7 @@ EOT
continue; continue;
} }
foreach ($package['suggest'] as $suggestion => $reason) { foreach ($package['suggest'] as $suggestion => $reason) {
if (false === strpos('/', $suggestion) && null !== $platform->findPackage($suggestion, '*')) { if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $suggestion) && null !== $platform->findPackage($suggestion, '*')) {
continue; continue;
} }
if (!isset($installed[$suggestion])) { if (!isset($installed[$suggestion])) {
@ -121,7 +121,7 @@ EOT
$io->write(sprintf('<info>%s</info>', $suggestion)); $io->write(sprintf('<info>%s</info>', $suggestion));
} }
return null; return 0;
} }
// Grouped by package // Grouped by package
@ -151,5 +151,7 @@ EOT
$io->write(''); $io->write('');
} }
} }
return 0;
} }
} }

View File

@ -63,6 +63,7 @@ class Config
'archive-dir' => '.', 'archive-dir' => '.',
'htaccess-protect' => true, 'htaccess-protect' => true,
'use-github-api' => true, 'use-github-api' => true,
'lock' => true,
// valid keys without defaults (auth config stuff): // valid keys without defaults (auth config stuff):
// bitbucket-oauth // bitbucket-oauth
// github-oauth // github-oauth
@ -329,6 +330,8 @@ class Config
return $this->config[$key] !== 'false' && (bool) $this->config[$key]; return $this->config[$key] !== 'false' && (bool) $this->config[$key];
case 'use-github-api': case 'use-github-api':
return $this->config[$key] !== 'false' && (bool) $this->config[$key]; return $this->config[$key] !== 'false' && (bool) $this->config[$key];
case 'lock':
return $this->config[$key] !== 'false' && (bool) $this->config[$key];
default: default:
if (!isset($this->config[$key])) { if (!isset($this->config[$key])) {
return null; return null;

View File

@ -113,6 +113,10 @@ class Application extends BaseApplication
{ {
$this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins'); $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins');
if (getenv('COMPOSER_NO_INTERACTION')) {
$input->setInteractive(false);
}
$io = $this->io = new ConsoleIO($input, $output, new HelperSet(array( $io = $this->io = new ConsoleIO($input, $output, new HelperSet(array(
new QuestionHelper(), new QuestionHelper(),
))); )));
@ -208,11 +212,7 @@ class Application extends BaseApplication
$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 (getenv('COMPOSER_NO_INTERACTION')) { if (!Platform::isWindows() && function_exists('exec') && !getenv('COMPOSER_ALLOW_SUPERUSER') && !file_exists('/.dockerenv')) {
$input->setInteractive(false);
}
if (!Platform::isWindows() && function_exists('exec') && !getenv('COMPOSER_ALLOW_SUPERUSER')) {
if (function_exists('posix_getuid') && posix_getuid() === 0) { if (function_exists('posix_getuid') && posix_getuid() === 0) {
if ($commandName !== 'self-update' && $commandName !== 'selfupdate') { if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
$io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>'); $io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>');

View File

@ -183,7 +183,7 @@ class Decisions implements \Iterator, \Countable
$previousDecision = isset($this->decisionMap[$packageId]) ? $this->decisionMap[$packageId] : null; $previousDecision = isset($this->decisionMap[$packageId]) ? $this->decisionMap[$packageId] : null;
if ($previousDecision != 0) { if ($previousDecision != 0) {
$literalString = $this->pool->literalToString($literal); $literalString = $this->pool->literalToPrettyString($literal, array());
$package = $this->pool->literalToPackage($literal); $package = $this->pool->literalToPackage($literal);
throw new SolverBugException( throw new SolverBugException(
"Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."." "Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."."

View File

@ -119,7 +119,7 @@ class Installer
protected $preferStable = false; protected $preferStable = false;
protected $preferLowest = false; protected $preferLowest = false;
protected $skipSuggest = false; protected $skipSuggest = false;
protected $writeLock = true; protected $writeLock;
protected $executeOperations = true; protected $executeOperations = true;
/** /**
@ -165,6 +165,8 @@ class Installer
$this->installationManager = $installationManager; $this->installationManager = $installationManager;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->autoloadGenerator = $autoloadGenerator; $this->autoloadGenerator = $autoloadGenerator;
$this->writeLock = $config->get('lock');
} }
/** /**

View File

@ -98,6 +98,27 @@ abstract class BaseRepository implements RepositoryInterface
// Replacements are considered valid reasons for a package to be installed during forward resolution // Replacements are considered valid reasons for a package to be installed during forward resolution
if (!$invert) { if (!$invert) {
$links += $package->getReplaces(); $links += $package->getReplaces();
// On forward search, check if any replaced package was required and add the replaced
// packages to the list of needles. Contrary to the cross-reference link check below,
// replaced packages are the target of links.
foreach ($package->getReplaces() as $link) {
foreach ($needles as $needle) {
if ($link->getSource() === $needle) {
if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
// already displayed this node's dependencies, cutting short
if (in_array($link->getTarget(), $packagesInTree)) {
$results[] = array($package, $link, false);
continue;
}
$packagesInTree[] = $link->getTarget();
$dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree) : array();
$results[] = array($package, $link, $dependents);
$needles[] = $link->getTarget();
}
}
}
}
} }
// Require-dev is only relevant for the root package // Require-dev is only relevant for the root package
@ -112,12 +133,12 @@ abstract class BaseRepository implements RepositoryInterface
if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) { if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
// already displayed this node's dependencies, cutting short // already displayed this node's dependencies, cutting short
if (in_array($link->getSource(), $packagesInTree)) { if (in_array($link->getSource(), $packagesInTree)) {
$results[$link->getSource()] = array($package, $link, false); $results[] = array($package, $link, false);
continue; continue;
} }
$packagesInTree[] = $link->getSource(); $packagesInTree[] = $link->getSource();
$dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : array(); $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : array();
$results[$link->getSource()] = array($package, $link, $dependents); $results[] = array($package, $link, $dependents);
} }
} }
} }

View File

@ -125,7 +125,13 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn
{ {
parent::initialize(); parent::initialize();
foreach ($this->getUrlMatches() as $url) { $urlMatches = $this->getUrlMatches();
if (empty($urlMatches)) {
throw new \RuntimeException('The `url` supplied for the path (' . $this->url . ') repository does not exist');
}
foreach ($urlMatches as $url) {
$path = realpath($url) . DIRECTORY_SEPARATOR; $path = realpath($url) . DIRECTORY_SEPARATOR;
$composerFilePath = $path.'composer.json'; $composerFilePath = $path.'composer.json';
@ -155,7 +161,11 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn
if (!isset($package['version'])) { if (!isset($package['version'])) {
$versionData = $this->versionGuesser->guessVersion($package, $path); $versionData = $this->versionGuesser->guessVersion($package, $path);
$package['version'] = $versionData['pretty_version'] ?: 'dev-master'; if (is_array($versionData) && $versionData['pretty_version']) {
$package['version'] = $versionData['pretty_version'];
} else {
$package['version'] = 'dev-master';
}
} }
$output = ''; $output = '';

View File

@ -47,7 +47,7 @@ abstract class BitbucketDriver extends VcsDriver
*/ */
public function initialize() public function initialize()
{ {
preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)$#', $this->url, $match); preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)$#i', $this->url, $match);
$this->owner = $match[1]; $this->owner = $match[1];
$this->repository = $match[2]; $this->repository = $match[2];
$this->originUrl = 'bitbucket.org'; $this->originUrl = 'bitbucket.org';

View File

@ -53,7 +53,7 @@ class GitBitbucketDriver extends BitbucketDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match('#^https?://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url)) { if (!preg_match('#^https?://bitbucket\.org/([^/]+)/(.+?)\.git$#i', $url)) {
return false; return false;
} }

View File

@ -48,10 +48,10 @@ class GitHubDriver extends VcsDriver
*/ */
public function initialize() public function initialize()
{ {
preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match); preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match);
$this->owner = $match[3]; $this->owner = $match[3];
$this->repository = $match[4]; $this->repository = $match[4];
$this->originUrl = !empty($match[1]) ? $match[1] : $match[2]; $this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]);
if ($this->originUrl === 'www.github.com') { if ($this->originUrl === 'www.github.com') {
$this->originUrl = 'github.com'; $this->originUrl = 'github.com';
} }
@ -270,12 +270,12 @@ class GitHubDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) { if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) {
return false; return false;
} }
$originUrl = !empty($matches[2]) ? $matches[2] : $matches[3]; $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
if (!in_array(preg_replace('{^www\.}i', '', $originUrl), $config->get('github-domains'))) { if (!in_array(strtolower(preg_replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) {
return false; return false;
} }

View File

@ -497,6 +497,8 @@ class GitLabDriver extends VcsDriver
*/ */
private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts, $portNumber) private static function determineOrigin(array $configuredDomains, $guessedDomain, array &$urlParts, $portNumber)
{ {
$guessedDomain = strtolower($guessedDomain);
if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array($guessedDomain.':'.$portNumber, $configuredDomains))) { if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array($guessedDomain.':'.$portNumber, $configuredDomains))) {
if ($portNumber) { if ($portNumber) {
return $guessedDomain.':'.$portNumber; return $guessedDomain.':'.$portNumber;

View File

@ -53,7 +53,7 @@ class HgBitbucketDriver extends BitbucketDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url)) { if (!preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+)/?$#i', $url)) {
return false; return false;
} }

View File

@ -71,7 +71,7 @@ class HgDriver extends VcsDriver
return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
}; };
$hgUtils->runCommand($command, $this->url, $this->repoDir); $hgUtils->runCommand($command, $this->url, null);
} }
} }

View File

@ -23,6 +23,7 @@ class AuthHelper
{ {
protected $io; protected $io;
protected $config; protected $config;
private $displayedOriginAuthentications = array();
public function __construct(IOInterface $io, Config $config) public function __construct(IOInterface $io, Config $config)
{ {
@ -172,7 +173,7 @@ class AuthHelper
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode); throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
} }
$this->io->writeError(' Authentication required (<info>'.parse_url($url, PHP_URL_HOST).'</info>):'); $this->io->writeError(' Authentication required (<info>'.$origin.'</info>):');
$username = $this->io->ask(' Username: '); $username = $this->io->ask(' Username: ');
$password = $this->io->askAndHideAnswer(' Password: '); $password = $this->io->askAndHideAnswer(' Password: ');
$this->io->setAuthentication($origin, $username, $password); $this->io->setAuthentication($origin, $username, $password);
@ -193,14 +194,18 @@ class AuthHelper
public function addAuthenticationHeader(array $headers, $origin, $url) public function addAuthenticationHeader(array $headers, $origin, $url)
{ {
if ($this->io->hasAuthentication($origin)) { if ($this->io->hasAuthentication($origin)) {
$authenticationDisplayMessage = null;
$auth = $this->io->getAuthentication($origin); $auth = $this->io->getAuthentication($origin);
if ('github.com' === $origin && 'x-oauth-basic' === $auth['password']) { if ('github.com' === $origin && 'x-oauth-basic' === $auth['password']) {
$headers[] = 'Authorization: token '.$auth['username']; $headers[] = 'Authorization: token '.$auth['username'];
$authenticationDisplayMessage = 'Using GitHub token authentication';
} elseif (in_array($origin, $this->config->get('gitlab-domains'), true)) { } elseif (in_array($origin, $this->config->get('gitlab-domains'), true)) {
if ($auth['password'] === 'oauth2') { if ($auth['password'] === 'oauth2') {
$headers[] = 'Authorization: Bearer '.$auth['username']; $headers[] = 'Authorization: Bearer '.$auth['username'];
$authenticationDisplayMessage = 'Using GitLab OAuth token authentication';
} elseif ($auth['password'] === 'private-token') { } elseif ($auth['password'] === 'private-token') {
$headers[] = 'PRIVATE-TOKEN: '.$auth['username']; $headers[] = 'PRIVATE-TOKEN: '.$auth['username'];
$authenticationDisplayMessage = 'Using GitLab private token authentication';
} }
} elseif ( } elseif (
'bitbucket.org' === $origin 'bitbucket.org' === $origin
@ -209,10 +214,17 @@ class AuthHelper
) { ) {
if (!$this->isPublicBitBucketDownload($url)) { if (!$this->isPublicBitBucketDownload($url)) {
$headers[] = 'Authorization: Bearer ' . $auth['password']; $headers[] = 'Authorization: Bearer ' . $auth['password'];
$authenticationDisplayMessage = 'Using Bitbucket OAuth token authentication';
} }
} else { } else {
$authStr = base64_encode($auth['username'] . ':' . $auth['password']); $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
$headers[] = 'Authorization: Basic '.$authStr; $headers[] = 'Authorization: Basic '.$authStr;
$authenticationDisplayMessage = 'Using HTTP basic authentication with username "' . $auth['username'] . '"';
}
if ($authenticationDisplayMessage && !in_array($origin, $this->displayedOriginAuthentications, true)) {
$this->io->writeError($authenticationDisplayMessage, true, IOInterface::DEBUG);
$this->displayedOriginAuthentications[] = $origin;
} }
} }
@ -243,4 +255,15 @@ class AuthHelper
return count($pathParts) >= 4 && $pathParts[3] == 'downloads'; return count($pathParts) >= 4 && $pathParts[3] == 'downloads';
} }
/**
* @param string $url
* @return string
*/
public function stripCredentialsFromUrl($url)
{
// GitHub repository rename result in redirect locations containing the access_token as GET parameter
// e.g. https://api.github.com/repositories/9999999999?access_token=github_token
return preg_replace('{([&?]access_token=)[^&]+}', '$1***', $url);
}
} }

View File

@ -687,12 +687,14 @@ class Filesystem
if (!Platform::isWindows()) { if (!Platform::isWindows()) {
return false; return false;
} }
// Important to clear all caches first
clearstatcache(true, $junction);
if (!is_dir($junction) || is_link($junction)) { if (!is_dir($junction) || is_link($junction)) {
return false; return false;
} }
// Important to clear all caches first
clearstatcache(true, $junction);
$stat = lstat($junction); $stat = lstat($junction);
// S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask) // S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask)

View File

@ -193,7 +193,7 @@ class Git
} }
} }
$this->io->writeError(' Authentication required (<info>' . parse_url($url, PHP_URL_HOST) . '</info>):'); $this->io->writeError(' Authentication required (<info>' . $match[2] . '</info>):');
$auth = array( $auth = array(
'username' => $this->io->ask(' Username: ', $defaultUsername), 'username' => $this->io->ask(' Username: ', $defaultUsername),
'password' => $this->io->askAndHideAnswer(' Password: '), 'password' => $this->io->askAndHideAnswer(' Password: '),

View File

@ -195,7 +195,7 @@ class CurlDownloader
$usingProxy = !empty($options['http']['proxy']) ? ' using proxy ' . $options['http']['proxy'] : ''; $usingProxy = !empty($options['http']['proxy']) ? ' using proxy ' . $options['http']['proxy'] : '';
$ifModified = false !== strpos(strtolower(implode(',', $options['http']['header'])), 'if-modified-since:') ? ' if modified' : ''; $ifModified = false !== strpos(strtolower(implode(',', $options['http']['header'])), 'if-modified-since:') ? ' if modified' : '';
if ($attributes['redirects'] === 0) { if ($attributes['redirects'] === 0) {
$this->io->writeError('Downloading ' . $url . $usingProxy . $ifModified, true, IOInterface::DEBUG); $this->io->writeError('Downloading ' . $this->authHelper->stripCredentialsFromUrl($url) . $usingProxy . $ifModified, true, IOInterface::DEBUG);
} }
$this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $curlHandle)); $this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $curlHandle));
@ -254,12 +254,12 @@ class CurlDownloader
$contents = stream_get_contents($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']);
} }
$response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents); $response = new Response(array('url' => $progress['url']), $statusCode, $headers, $contents);
$this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); $this->io->writeError('['.$statusCode.'] '.$this->authHelper->stripCredentialsFromUrl($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 Response(array('url' => $progress['url']), $statusCode, $headers, $contents);
$this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); $this->io->writeError('['.$statusCode.'] '.$this->authHelper->stripCredentialsFromUrl($progress['url']), true, IOInterface::DEBUG);
} }
fclose($job['bodyHandle']); fclose($job['bodyHandle']);
@ -362,7 +362,7 @@ class CurlDownloader
} }
if (!empty($targetUrl)) { if (!empty($targetUrl)) {
$this->io->writeError(sprintf('Following redirect (%u) %s', $job['attributes']['redirects'] + 1, $targetUrl), true, IOInterface::DEBUG); $this->io->writeError(sprintf('Following redirect (%u) %s', $job['attributes']['redirects'] + 1, $this->authHelper->stripCredentialsFromUrl($targetUrl)), true, IOInterface::DEBUG);
return $targetUrl; return $targetUrl;
} }

View File

@ -246,7 +246,7 @@ class RemoteFilesystem
$actualContextOptions = stream_context_get_options($ctx); $actualContextOptions = stream_context_get_options($ctx);
$usingProxy = !empty($actualContextOptions['http']['proxy']) ? ' using proxy ' . $actualContextOptions['http']['proxy'] : ''; $usingProxy = !empty($actualContextOptions['http']['proxy']) ? ' using proxy ' . $actualContextOptions['http']['proxy'] : '';
$this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $origFileUrl . $usingProxy, true, IOInterface::DEBUG); $this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $this->authHelper->stripCredentialsFromUrl($origFileUrl) . $usingProxy, true, IOInterface::DEBUG);
unset($origFileUrl, $actualContextOptions); unset($origFileUrl, $actualContextOptions);
// Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256 // Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256
@ -704,7 +704,7 @@ class RemoteFilesystem
$this->redirects++; $this->redirects++;
$this->io->writeError('', true, IOInterface::DEBUG); $this->io->writeError('', true, IOInterface::DEBUG);
$this->io->writeError(sprintf('Following redirect (%u) %s', $this->redirects, $targetUrl), true, IOInterface::DEBUG); $this->io->writeError(sprintf('Following redirect (%u) %s', $this->redirects, $this->authHelper->stripCredentialsFromUrl($targetUrl)), true, IOInterface::DEBUG);
$additionalOptions['redirects'] = $this->redirects; $additionalOptions['redirects'] = $this->redirects;

View File

@ -21,7 +21,6 @@ class Zip
* Gets content of the root composer.json inside a ZIP archive. * Gets content of the root composer.json inside a ZIP archive.
* *
* @param string $pathToZip * @param string $pathToZip
* @param string $filename
* *
* @return string|null * @return string|null
*/ */

View File

@ -25,12 +25,18 @@ class ApplicationTest extends TestCase
$inputMock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(); $inputMock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock();
$outputMock = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock(); $outputMock = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock();
putenv('COMPOSER_NO_INTERACTION=1');
$index = 0; $index = 0;
$inputMock->expects($this->at($index++)) $inputMock->expects($this->at($index++))
->method('hasParameterOption') ->method('hasParameterOption')
->with($this->equalTo('--no-plugins')) ->with($this->equalTo('--no-plugins'))
->will($this->returnValue(true)); ->will($this->returnValue(true));
$inputMock->expects($this->at($index++))
->method('setInteractive')
->with($this->equalTo(false));
$inputMock->expects($this->at($index++)) $inputMock->expects($this->at($index++))
->method('hasParameterOption') ->method('hasParameterOption')
->with($this->equalTo('--no-cache')) ->with($this->equalTo('--no-cache'))
@ -83,12 +89,18 @@ class ApplicationTest extends TestCase
$inputMock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(); $inputMock = $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock();
$outputMock = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock(); $outputMock = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock();
putenv('COMPOSER_NO_INTERACTION=1');
$index = 0; $index = 0;
$inputMock->expects($this->at($index++)) $inputMock->expects($this->at($index++))
->method('hasParameterOption') ->method('hasParameterOption')
->with($this->equalTo('--no-plugins')) ->with($this->equalTo('--no-plugins'))
->will($this->returnValue(true)); ->will($this->returnValue(true));
$inputMock->expects($this->at($index++))
->method('setInteractive')
->with($this->equalTo(false));
$inputMock->expects($this->at($index++)) $inputMock->expects($this->at($index++))
->method('hasParameterOption') ->method('hasParameterOption')
->with($this->equalTo('--no-cache')) ->with($this->equalTo('--no-cache'))

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitFilesAutoloadOrder
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitFilesAutoload
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitFilesAutoload
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitFilesAutoload
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitIncludePath
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInitTargetDir
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -1385,6 +1385,10 @@ namespace Foo;
<?php <?php
class LargeGap class LargeGap
{ {
public function a1380() { var_dump(var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null)); } public function test_double_gap() { var_dump(var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null));
?>
public function a1381() { var_dump(var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null), var_dump(null)); }
<?php
}
} }

View File

@ -0,0 +1,25 @@
--TEST--
Installs from composer.json without writing a lock file
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "a/a", "version": "1.0.0" }
]
}
],
"require": {
"a/a": "1.0.0"
},
"config": {
"lock": "false"
}
}
--RUN--
install
--EXPECT--
Installing a/a (1.0.0)
--EXPECT-LOCK--
false

View File

@ -0,0 +1,25 @@
--TEST--
Updates when no lock file is present without writing a lock file
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "a/a", "version": "1.0.0" }
]
}
],
"require": {
"a/a": "1.0.0"
},
"config": {
"lock": false
}
}
--RUN--
update
--EXPECT--
Installing a/a (1.0.0)
--EXPECT-LOCK--
false

View File

@ -199,6 +199,9 @@ class InstallerTest extends TestCase
// so store value temporarily in reference for later assetion // so store value temporarily in reference for later assetion
$actualLock = $hash; $actualLock = $hash;
})); }));
} elseif ($expectLock === false) {
$lockJsonMock->expects($this->never())
->method('write');
} }
$contents = json_encode($composerConfig); $contents = json_encode($composerConfig);
@ -282,15 +285,15 @@ class InstallerTest extends TestCase
continue; continue;
} }
$testData = $this->readTestFile($file, $fixturesDir);
$installed = array();
$installedDev = array();
$lock = array();
$expectLock = array();
$expectResult = 0;
try { try {
$testData = $this->readTestFile($file, $fixturesDir);
$installed = array();
$installedDev = array();
$lock = array();
$expectLock = array();
$expectResult = 0;
$message = $testData['TEST']; $message = $testData['TEST'];
$condition = !empty($testData['CONDITION']) ? $testData['CONDITION'] : null; $condition = !empty($testData['CONDITION']) ? $testData['CONDITION'] : null;
$composer = JsonFile::parseJson($testData['COMPOSER']); $composer = JsonFile::parseJson($testData['COMPOSER']);
@ -321,7 +324,11 @@ class InstallerTest extends TestCase
} }
$run = $testData['RUN']; $run = $testData['RUN'];
if (!empty($testData['EXPECT-LOCK'])) { if (!empty($testData['EXPECT-LOCK'])) {
$expectLock = JsonFile::parseJson($testData['EXPECT-LOCK']); if ($testData['EXPECT-LOCK'] === 'false') {
$expectLock = false;
} else {
$expectLock = JsonFile::parseJson($testData['EXPECT-LOCK']);
}
} }
$expectOutput = isset($testData['EXPECT-OUTPUT']) ? $testData['EXPECT-OUTPUT'] : null; $expectOutput = isset($testData['EXPECT-OUTPUT']) ? $testData['EXPECT-OUTPUT'] : null;
$expect = $testData['EXPECT']; $expect = $testData['EXPECT'];

View File

@ -19,6 +19,22 @@ use Composer\Package\Version\VersionParser;
class PathRepositoryTest extends TestCase class PathRepositoryTest extends TestCase
{ {
/**
* @expectedException RuntimeException
*/
public function testLoadPackageFromFileSystemWithIncorrectPath()
{
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')
->getMock();
$config = new \Composer\Config();
$repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', 'missing'));
$repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config);
$repository->getPackages();
}
public function testLoadPackageFromFileSystemWithVersion() public function testLoadPackageFromFileSystemWithVersion()
{ {
$ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface')

View File

@ -300,16 +300,16 @@ class FilesystemTest extends TestCase
// Create and detect junction // Create and detect junction
$fs->junction($target, $junction); $fs->junction($target, $junction);
$this->assertTrue($fs->isJunction($junction)); $this->assertTrue($fs->isJunction($junction), $junction . ': is a junction');
$this->assertFalse($fs->isJunction($target)); $this->assertFalse($fs->isJunction($target), $target . ': is not a junction');
$this->assertTrue($fs->isJunction($target . '/../../junction')); $this->assertTrue($fs->isJunction($target . '/../../junction'), $target . '/../../junction: is a junction');
$this->assertFalse($fs->isJunction($junction . '/../real')); $this->assertFalse($fs->isJunction($junction . '/../real'), $junction . '/../real: is not a junction');
$this->assertTrue($fs->isJunction($junction . '/../junction')); $this->assertTrue($fs->isJunction($junction . '/../junction'), $junction . '/../junction: is a junction');
// Remove junction // Remove junction
$this->assertTrue(is_dir($junction)); $this->assertTrue(is_dir($junction), $junction . ' is a directory');
$this->assertTrue($fs->removeJunction($junction)); $this->assertTrue($fs->removeJunction($junction), $junction . ' has been removed');
$this->assertFalse(is_dir($junction)); $this->assertFalse(is_dir($junction), $junction . ' is not a directory');
} }
public function testCopy() public function testCopy()